How to Mock a Parquet partitionBy Sink in Python
Manually write a DataFrame to partitioned Parquet files, mimicking Spark's partitionBy sink behavior without Spark.
pip install pyarrow pandas
Python code
47 linesimport pyarrow as pa
import pyarrow.parquet as pq
from pathlib import Path
import tempfile
import shutil
def mock_partition_by_sink(data, output_dir, partition_cols):
table = pa.Table.from_pandas(data)
schema = table.schema
unique_combos = table.select(partition_cols).to_pylist()
seen = set()
for combo in unique_combos:
key = tuple(combo[col] for col in partition_cols)
if key in seen:
continue
seen.add(key)
mask = pa.compute.equal(table[partition_cols[0]], combo[partition_cols[0]])
for col in partition_cols[1:]:
mask = pa.compute.and_(mask, pa.compute.equal(table[col], combo[col]))
subset = table.filter(mask)
partition_path = Path(output_dir) / "/".join(
f"{col}={combo[col]}" for col in partition_cols
)
partition_path.mkdir(parents=True, exist_ok=True)
pq.write_table(subset, partition_path / "data.parquet", schema=schema)
if __name__ == "__main__":
import pandas as pd
df = pd.DataFrame({
"year": [2020, 2020, 2021, 2021],
"month": [1, 2, 1, 2],
"value": [10, 20, 30, 40],
})
tmp_dir = tempfile.mkdtemp()
try:
mock_partition_by_sink(df, tmp_dir, ["year", "month"])
result = sorted(
str(p.relative_to(tmp_dir))
for p in Path(tmp_dir).rglob("*.parquet")
)
print(result)
finally:
shutil.rmtree(tmp_dir)
Output
['year=2020/month=1/data.parquet', 'year=2020/month=2/data.parquet', 'year=2021/month=1/data.parquet', 'year=2021/month=2/data.parquet']
How it works
The function extracts unique combinations of partition columns from the input table. For each combination, it builds a boolean mask using pa.compute.equal and pa.compute.and_ to filter the rows that belong to that partition. The filtered subset is then written to a directory path constructed as col=value pairs, mimicking Spark's Hive-style partitioning layout. This approach avoids running a full Spark cluster while still producing partitioned Parquet output for local testing or small-scale workflows. The schema is preserved for each partition write to keep column types consistent.
Common mistakes
- Using `json` or file path strings incorrectly when building partition paths, causing invalid directory structures.
- Forgetting to convert pandas DataFrame to a PyArrow Table before filtering, which breaks arrow-based operations.
- Not deduplicating the unique partition combos, causing duplicate writes or redundant file creation.
Variations
- Use `table.to_pandas().groupby(partition_cols)` and write each group separately with pandas to_parquet.
- Leverage PyArrow's `pq.write_to_dataset` with `partition_cols` parameter to let PyArrow handle partitioning natively.
Real-world use cases
- Replicating Spark's partitionBy logic in unit tests without spinning up a local Spark instance.
- Writing small to medium datasets to partitioned Parquet for downstream tools like Athena or DuckDB.
- Creating partition-on-write example code in a data engineering tutorial for a local dev environment.
Sponsored
More from Big data & Spark
Keep learning
Related tutorials and quizzes for this topic.