gtfs-normalizer 0.0.1.dev1
GTFS cleanup and transformation utilities
Requires Python: >=3.11

# gtfs-tools

GTFS cleanup and transformation utilities for improving feed quality and consistency.

## Features

- **Clean Feed**: Remove problematic Unicode characters (non-breaking spaces, zero-width chars, etc.)
- **Fix Routes**: Convert ALL CAPS route names to Title Case using route descriptions as reference
- **Fix Blocks**: Clear block_id for trips with overlapping stop times (prevent impossible schedules)
- **Round Shapes**: Round geographic coordinates and distances to appropriate precision

## Installation

```bash
pip install .
```

Or with development mode:

```bash
pip install -e .
```

## Usage

### As a Library

```python
from gtfs_normalizer import clean_feed, fix_route_names, fix_overlapping_blocks, round_shapes
from pathlib import Path

feed_dir = Path("feed")

# Clean invisible Unicode whitespace
clean_feed(feed_dir)

# Fix ALL CAPS route names
fix_route_names(feed_dir)

# Fix overlapping block assignments
fix_overlapping_blocks(feed_dir)

# Round geographic/distance values
round_shapes(feed_dir)
```

### As Command-Line Tools

```bash
# Clean feed
gtfs-clean ./feed

# Fix route names
gtfs-fix-routes ./feed

# Fix overlapping blocks
gtfs-fix-blocks ./feed

# Round shapes
gtfs-round-shapes ./feed
```

## Module Details

### clean_feed

Removes problematic whitespace characters:
- U+00A0 (non-breaking space)
- U+200B (zero-width space)
- U+200C (zero-width non-joiner)
- U+200D (zero-width joiner)
- U+FEFF (zero-width no-break space / BOM)

**Usage:**
```python
from gtfs_normalizer import clean_feed
clean_feed("feed")
```

### fix_route_names

Converts ALL CAPS route names to Title Case using `route_desc` as reference:
- Splits route name by " - " separator
- Finds each part in route_desc (case-insensitive)
- Reconstructs with proper casing from description
- Removes `route_desc` when it duplicates `route_long_name`

**Usage:**
```python
from gtfs_normalizer import fix_route_names
fix_route_names("feed")
```

### fix_overlapping_blocks

Clears `block_id` for trips with overlapping stop times in the same block:
- Groups trips by block and service
- Calculates trip start/end times from stop_times
- Detects overlaps (same physical vehicle in two places simultaneously)
- Clears block_id for conflicting trips

**Usage:**
```python
from gtfs_normalizer import fix_overlapping_blocks
fix_overlapping_blocks("feed")
```

### round_shapes

Rounds geographic and distance precision:
- **shapes.txt**: lat/lon to 6 decimals (~1.1m accuracy), distances to 2 decimals
- **stop_times.txt**: distances to 2 decimals

**Usage:**
```python
from gtfs_normalizer import round_shapes
round_shapes("feed")
```

## Requirements

- Python 3.11+
- No external dependencies

## Integration Example

For use in GitHub Actions workflows or local scripts:

```python
import logging
from pathlib import Path
from gtfs_normalizer import clean_feed, fix_route_names, fix_overlapping_blocks, round_shapes

logging.basicConfig(level=logging.INFO)

feed_dir = Path("feed")

# Apply all transformations in sequence
clean_feed(feed_dir)
fix_route_names(feed_dir)
fix_overlapping_blocks(feed_dir)
round_shapes(feed_dir)

print("GTFS feed processing completed")
```

## License

MIT