Metadata-Version: 2.4
Name: gtfs-parquet
Version: 0.3.0
Summary: Parse GTFS feeds to/from Parquet via Polars — fast, compact, typed.
Project-URL: Homepage, https://github.com/GaspardMerten/gtfs-parquet
Project-URL: Repository, https://github.com/GaspardMerten/gtfs-parquet
Project-URL: Issues, https://github.com/GaspardMerten/gtfs-parquet/issues
Author-email: Gaspard Merten <gaspard.mp.work@gmail.com>
License-Expression: MIT
License-File: LICENSE
Keywords: gtfs,parquet,polars,transit,transport
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: GIS
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: httpx>=0.27
Requires-Dist: polars>=1.0
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Description-Content-Type: text/markdown

# gtfs-parquet

Parse [GTFS](https://gtfs.org/) feeds to/from [Parquet](https://parquet.apache.org/) via [Polars](https://pola.rs/) — fast, compact, typed.

## Features

- Parse GTFS from **zip**, **directory**, or **URL**
- Write to **Parquet** (zstd-compressed, sorted for optimal compression) or back to **GTFS**
- Strongly typed schemas with optimised dtypes (Float32 coords, Int16 sequences)
- Built on Polars — zero-copy reads, lazy evaluation ready
- Operations: calendar expansion, network analysis, route stats, stop clustering, trip metrics

## Installation

```bash
pip install gtfs-parquet
```

## Quick start

```python
from gtfs_parquet import parse_gtfs, write_parquet, read_parquet, write_gtfs

# Parse a GTFS zip (local path or URL)
feed = parse_gtfs("gtfs.zip")

# Write to Parquet — directory, .zip, or .tar (auto-detected by extension)
write_parquet(feed, "output/")           # directory of .parquet files
write_parquet(feed, "output.zip")        # zip archive (no extra compression)
write_parquet(feed, "output.tar")        # tar archive (single file, no extra compression)

# Read back (same formats)
feed = read_parquet("output/")
feed = read_parquet("output.zip")
feed = read_parquet("output.tar")

# Convert back to GTFS zip
write_gtfs(feed, "roundtrip.zip")
```

## Compression

Parquet output is **significantly smaller** than the original GTFS zip thanks to
zstd compression, sorted row groups, and optimised column types:

| Feed     | GTFS zip | Parquet |  Saving |
|----------|----------|---------|---------|
| STIB     |  5.5 MB  |  3.2 MB |  42.8 % |
| TEC      | 95.2 MB  | 23.9 MB |  75.0 % |
| De Lijn  | 195 MB   | 55.0 MB |  71.8 % |

## Feed object

`Feed` is a dataclass with one optional `polars.DataFrame` attribute per GTFS
file (e.g. `feed.stops`, `feed.routes`, `feed.stop_times`). Only files present
in the source feed are populated.

## Operations

The operations API is inspired by [gtfs-kit](https://github.com/mrcagney/gtfs_kit),
re-implemented on Polars for significantly better performance.

```python
from gtfs_parquet.ops import calendar, network, routes, stops, trips

# Expand calendar + calendar_dates into per-date service table
services = calendar.dates(feed)

# Route-level statistics
route_stats = routes.stats(feed)

# Stop-level statistics
stop_stats = stops.stats(feed)

# Trip-level metrics
trip_stats = trips.stats(feed)

# Network graph analysis
net_stats = network.stats(feed)
```

### Performance vs gtfs-kit

Benchmarked on the STIB (Brussels) feed (~5.5 MB, ~9 000 trips):

| Operation             | gtfs-kit (pandas) | gtfs-parquet (Polars) | Speedup |
|-----------------------|------------------:|----------------------:|--------:|
| Load feed             |           2.97 s  |              0.40 s   |     7×  |
| `compute_trip_stats`  |          57.46 s  |              0.05 s   |  1149×  |
| `compute_stop_stats`  |           9.67 s  |              0.19 s   |    51×  |
| `compute_route_stats` |           2.12 s  |              0.08 s   |    27×  |
| `compute_busiest_date`|           0.07 s  |              0.06 s   |     1×  |

Peak process memory: **1020 MB** (gtfs-kit) vs **744 MB** (gtfs-parquet).

## License

[MIT](LICENSE)
