Sinks¶
A sink is where your data ends up: an Arrow table, a DataFrame, a file, or a list of dicts. Sources have sink methods; pipelines are materialized with sink functions. This page shows one short example of each.
Which sink do I want?¶
| Goal | Call |
|---|---|
Get a pyarrow.Table |
src.to_arrow() |
Get a pipeline pyarrow.Table |
pipeline.to_arrow() |
| Get a pandas DataFrame | src.to_pandas() |
| Get a Polars DataFrame | src.to_polars() |
| Write a Parquet file | src.to_parquet(path) |
| Get rows from a pipeline | collect(pipeline) |
| Get a DataFrame from a pipeline | to_pandas(pipeline) |
| Write a pipeline to CSV | to_csv(pipeline, path) |
| Write a pipeline to Parquet | to_parquet(pipeline, path) |
| Free the cached table | src.clear_cache() |
| Free a cached pipeline result | pipeline.clear_cache() |
Ordinary materializing Source and Pipeline sink methods cache their Arrow
result, so repeated calls are cheap. Iteration and memory= streaming consume
the pipeline without creating that cache. A Pipeline keeps its transformed
result separately from the Source cache. Function-style materializing sinks
use the same cache when given a Pipeline.
For DataFrames, pick the library your downstream code already uses:
to_arrow() is the lowest-copy baseline (primitive arrays still copy), while to_pandas() and
to_polars() pay a conversion. For files too large to hold in memory,
skip all of these and stream with iter_record_batches() (see
Streaming).
Pipeline vs Source
Ordinary materializing sinks parse once and cache the result. A Pipeline
caches its transformed table; subsequent sinks reuse it. Iteration reuses
an existing cache but does not create one. Use to_arrow(pipeline),
to_pandas(pipeline), or collect(pipeline) for function-style sinks.
All examples assume:
from crxml import CrystalXMLSource, FilterRows
src = CrystalXMLSource("report.xml", row_tag="Details")
pipeline = src | FilterRows(field="Status", op="==", value="Active")
Source methods¶
to_arrow()¶
The table is cached after the first call, so to_pandas() and friends
reuse it without re-parsing.
to_pandas()¶
Requires pandas.
to_polars()¶
Requires polars.
to_parquet()¶
Extra keyword arguments are passed to pyarrow.parquet.write_table, for
example compression="zstd". See the
reference for the common
options.
clear_cache()¶
Drops the cached Arrow table. The next sink call re-parses the file.
A Source keeps its parsed table in memory so repeated sinks
(to_pandas(), then to_parquet(), ...) do not re-parse. That is great
while you work with one file, but in an ETL flow the table is dead weight
once the file is done. Good practice: after the final sink for a file,
call clear_cache() before moving to the next one.
import glob
from crxml import CrystalXMLSource
for path in sorted(glob.glob("exports/*.xml")):
src = CrystalXMLSource(path, row_tag="Details")
src.to_parquet(path.replace(".xml", ".parquet"))
src.clear_cache() # free the table before the next file
Without the clear_cache() call, each Source in a long-running job holds
its table until it is garbage collected, so peak memory grows with the
number of live Sources. (If your files are large, see
Streaming: processing in batches with
iter_record_batches never holds the whole table at all.)
Pipeline functions¶
Pipelines are streams of row dicts, so you materialize them with the
functions from crxml:
collect()¶
Runs the pipeline and returns all rows as a list of dicts:
from crxml import collect
rows = collect(pipeline)
print(len(rows), rows[0]["Name"]) # 12 Alice Johnson
to_pandas() (function)¶
to_csv()¶
Tip
After a materializing sink creates the cache, later ordinary sinks reuse it.
Iteration and streaming may run again. Call clear_cache() when the result
is no longer needed.
Streaming sinks
To write Parquet or build a DataFrame without holding the whole file in
memory, use iter_record_batches(). See
Streaming.
Recap¶
- Source methods:
.to_arrow(),.to_pandas(),.to_polars(),.to_parquet(path),.clear_cache(). - Pipeline methods:
.to_arrow(),.to_pandas(),.to_polars(),.to_parquet(path),.clear_cache(). - Pipeline functions:
collect(),to_pandas(),to_csv(),to_parquet(). - Source and Pipeline results are cached separately; call
.clear_cache()to release either materialized result. - In ETL loops over many files, call
.clear_cache()after each file's final sink to free its table. - Parameter details live in the Python API reference.
Next: Streaming, processing large files with bounded memory.