gtfs-guru 0.1.0__cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
gtfs_guru/__init__.py
ADDED
|
Binary file
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: gtfs-guru
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Classifier: Development Status :: 4 - Beta
|
|
5
|
+
Classifier: Intended Audience :: Developers
|
|
6
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Rust
|
|
14
|
+
Classifier: Topic :: Scientific/Engineering :: GIS
|
|
15
|
+
Summary: Fast GTFS validator written in Rust
|
|
16
|
+
Keywords: gtfs,transit,validator,public-transit
|
|
17
|
+
License: Apache-2.0
|
|
18
|
+
Requires-Python: >=3.8
|
|
19
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
20
|
+
Project-URL: Homepage, https://github.com/abasis-ltd/gtfs.guru
|
|
21
|
+
Project-URL: Repository, https://github.com/abasis-ltd/gtfs.guru
|
|
22
|
+
|
|
23
|
+
# GTFS Validator Python
|
|
24
|
+
|
|
25
|
+
High-performance GTFS feed validator with Python bindings. Written in Rust, exposed via PyO3.
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pip install gtfs-validator
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### From Source
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
pip install maturin
|
|
37
|
+
maturin build --release
|
|
38
|
+
pip install target/wheels/gtfs_validator-*.whl
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Quick Start
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
import gtfs_validator
|
|
45
|
+
|
|
46
|
+
# Validate a GTFS feed
|
|
47
|
+
result = gtfs_validator.validate("/path/to/gtfs.zip")
|
|
48
|
+
|
|
49
|
+
print(f"Valid: {result.is_valid}")
|
|
50
|
+
print(f"Errors: {result.error_count}")
|
|
51
|
+
print(f"Warnings: {result.warning_count}")
|
|
52
|
+
|
|
53
|
+
# Print errors
|
|
54
|
+
for error in result.errors():
|
|
55
|
+
print(f"{error.code}: {error.message}")
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## API Reference
|
|
59
|
+
|
|
60
|
+
### Functions
|
|
61
|
+
|
|
62
|
+
#### `validate(path, country_code=None, date=None) -> ValidationResult`
|
|
63
|
+
|
|
64
|
+
Validate a GTFS feed.
|
|
65
|
+
|
|
66
|
+
**Parameters:**
|
|
67
|
+
- `path` (str): Path to GTFS zip file or directory
|
|
68
|
+
- `country_code` (str, optional): ISO country code (e.g., "US", "RU")
|
|
69
|
+
- `date` (str, optional): Validation date in YYYY-MM-DD format
|
|
70
|
+
|
|
71
|
+
**Returns:** `ValidationResult` object
|
|
72
|
+
|
|
73
|
+
**Example:**
|
|
74
|
+
```python
|
|
75
|
+
result = gtfs_validator.validate(
|
|
76
|
+
"/path/to/gtfs.zip",
|
|
77
|
+
country_code="US",
|
|
78
|
+
date="2025-01-15"
|
|
79
|
+
)
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
#### `async validate_async(path, country_code=None, date=None, on_progress=None) -> ValidationResult`
|
|
83
|
+
|
|
84
|
+
Validate a GTFS feed asynchronously (non-blocking).
|
|
85
|
+
|
|
86
|
+
**Parameters:**
|
|
87
|
+
- `path` (str): Path to GTFS zip file or directory
|
|
88
|
+
- `country_code` (str, optional): ISO country code
|
|
89
|
+
- `date` (str, optional): Validation date in YYYY-MM-DD format
|
|
90
|
+
- `on_progress` (Callable[[ProgressInfo], None], optional): Callback for progress updates
|
|
91
|
+
|
|
92
|
+
**Example:**
|
|
93
|
+
```python
|
|
94
|
+
import asyncio
|
|
95
|
+
|
|
96
|
+
async def main():
|
|
97
|
+
def on_progress(info):
|
|
98
|
+
print(f"{info.stage}: {info.current}/{info.total}")
|
|
99
|
+
|
|
100
|
+
result = await gtfs_validator.validate_async(
|
|
101
|
+
"/path/to/gtfs.zip",
|
|
102
|
+
on_progress=on_progress
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
asyncio.run(main())
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
#### `version() -> str`
|
|
109
|
+
|
|
110
|
+
Get validator version.
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
>>> gtfs_validator.version()
|
|
114
|
+
'0.1.0'
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
#### `notice_codes() -> list[str]`
|
|
118
|
+
|
|
119
|
+
Get list of all available notice codes.
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
>>> len(gtfs_validator.notice_codes())
|
|
123
|
+
164
|
|
124
|
+
>>> gtfs_validator.notice_codes()[:3]
|
|
125
|
+
['attribution_without_role', 'bidirectional_exit_gate', 'block_trips_with_overlapping_stop_times']
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
#### `notice_schema() -> dict`
|
|
129
|
+
|
|
130
|
+
Get schema for all notice types with descriptions and severity levels.
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
>>> schema = gtfs_validator.notice_schema()
|
|
134
|
+
>>> schema['missing_required_field']
|
|
135
|
+
{'severity': 'ERROR', 'description': '...'}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Classes
|
|
139
|
+
|
|
140
|
+
#### `ValidationResult`
|
|
141
|
+
|
|
142
|
+
Result of GTFS validation.
|
|
143
|
+
|
|
144
|
+
**Attributes:**
|
|
145
|
+
| Attribute | Type | Description |
|
|
146
|
+
|-----------|------|-------------|
|
|
147
|
+
| `is_valid` | `bool` | True if no errors |
|
|
148
|
+
| `error_count` | `int` | Number of errors |
|
|
149
|
+
| `warning_count` | `int` | Number of warnings |
|
|
150
|
+
| `info_count` | `int` | Number of info notices |
|
|
151
|
+
| `validation_time_seconds` | `float` | Validation time in seconds |
|
|
152
|
+
| `notices` | `list[Notice]` | All validation notices |
|
|
153
|
+
|
|
154
|
+
**Methods:**
|
|
155
|
+
|
|
156
|
+
```python
|
|
157
|
+
# Get notices by severity
|
|
158
|
+
errors = result.errors() # List[Notice]
|
|
159
|
+
warnings = result.warnings() # List[Notice]
|
|
160
|
+
infos = result.infos() # List[Notice]
|
|
161
|
+
|
|
162
|
+
# Filter by notice code
|
|
163
|
+
notices = result.by_code("missing_required_field") # List[Notice]
|
|
164
|
+
|
|
165
|
+
# Export
|
|
166
|
+
result.save_json("/path/to/report.json")
|
|
167
|
+
result.save_html("/path/to/report.html")
|
|
168
|
+
json_str = result.to_json() # str
|
|
169
|
+
report = result.to_dict() # dict
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
#### `Notice`
|
|
173
|
+
|
|
174
|
+
A single validation notice.
|
|
175
|
+
|
|
176
|
+
**Attributes:**
|
|
177
|
+
| Attribute | Type | Description |
|
|
178
|
+
|-----------|------|-------------|
|
|
179
|
+
| `code` | `str` | Notice code (e.g., "missing_required_field") |
|
|
180
|
+
| `severity` | `str` | "ERROR", "WARNING", or "INFO" |
|
|
181
|
+
| `message` | `str` | Human-readable message |
|
|
182
|
+
| `file` | `str \| None` | GTFS filename |
|
|
183
|
+
| `row` | `int \| None` | CSV row number |
|
|
184
|
+
| `field` | `str \| None` | Field name |
|
|
185
|
+
|
|
186
|
+
**Methods:**
|
|
187
|
+
|
|
188
|
+
```python
|
|
189
|
+
# Get context field
|
|
190
|
+
value = notice.get("fieldName") # Any | None
|
|
191
|
+
|
|
192
|
+
# Get all context
|
|
193
|
+
ctx = notice.context() # dict[str, Any]
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Examples
|
|
197
|
+
|
|
198
|
+
### Basic Validation
|
|
199
|
+
|
|
200
|
+
```python
|
|
201
|
+
import gtfs_validator
|
|
202
|
+
|
|
203
|
+
result = gtfs_validator.validate("/path/to/gtfs.zip")
|
|
204
|
+
|
|
205
|
+
if result.is_valid:
|
|
206
|
+
print("Feed is valid!")
|
|
207
|
+
else:
|
|
208
|
+
print(f"Found {result.error_count} errors")
|
|
209
|
+
for error in result.errors():
|
|
210
|
+
print(f" - {error.code}: {error.message}")
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Detailed Analysis
|
|
214
|
+
|
|
215
|
+
```python
|
|
216
|
+
from collections import Counter
|
|
217
|
+
|
|
218
|
+
result = gtfs_validator.validate("/path/to/gtfs.zip")
|
|
219
|
+
|
|
220
|
+
# Count notices by code
|
|
221
|
+
error_counts = Counter(e.code for e in result.errors())
|
|
222
|
+
for code, count in error_counts.most_common(10):
|
|
223
|
+
print(f"{code}: {count}")
|
|
224
|
+
|
|
225
|
+
# Find all missing required fields
|
|
226
|
+
for notice in result.by_code("missing_required_field"):
|
|
227
|
+
file = notice.file
|
|
228
|
+
field = notice.get("fieldName")
|
|
229
|
+
row = notice.row
|
|
230
|
+
print(f"{file}:{row} - missing {field}")
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Save Reports
|
|
234
|
+
|
|
235
|
+
```python
|
|
236
|
+
result = gtfs_validator.validate("/path/to/gtfs.zip")
|
|
237
|
+
|
|
238
|
+
# Save JSON report (same format as Java validator)
|
|
239
|
+
result.save_json("report.json")
|
|
240
|
+
|
|
241
|
+
# Save HTML report
|
|
242
|
+
result.save_html("report.html")
|
|
243
|
+
|
|
244
|
+
# Get as Python dict
|
|
245
|
+
report = result.to_dict()
|
|
246
|
+
summary = report["summary"]
|
|
247
|
+
print(f"Agencies: {summary.get('agencies', [])}")
|
|
248
|
+
print(f"Routes: {summary.get('routes', {}).get('count', 0)}")
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### Validation with Options
|
|
252
|
+
|
|
253
|
+
```python
|
|
254
|
+
# Validate for specific country (affects some rules)
|
|
255
|
+
result = gtfs_validator.validate(
|
|
256
|
+
"/path/to/gtfs.zip",
|
|
257
|
+
country_code="DE"
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
# Validate as of specific date
|
|
261
|
+
result = gtfs_validator.validate(
|
|
262
|
+
"/path/to/gtfs.zip",
|
|
263
|
+
date="2025-06-01"
|
|
264
|
+
)
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## Supported Platforms
|
|
268
|
+
|
|
269
|
+
| Platform | Architecture | Python |
|
|
270
|
+
|----------|--------------|--------|
|
|
271
|
+
| macOS | ARM64 (M1/M2) | 3.8+ |
|
|
272
|
+
| macOS | x86_64 (Intel) | 3.8+ |
|
|
273
|
+
| Windows | x86_64 | 3.8+ |
|
|
274
|
+
| Linux | x86_64 | 3.8+ |
|
|
275
|
+
|
|
276
|
+
## Performance
|
|
277
|
+
|
|
278
|
+
Typical validation times (compared to Java validator):
|
|
279
|
+
|
|
280
|
+
| Feed Size | Java | Rust/Python |
|
|
281
|
+
|-----------|------|-------------|
|
|
282
|
+
| Small (<1MB) | ~2s | ~0.05s |
|
|
283
|
+
| Medium (10MB) | ~10s | ~0.5s |
|
|
284
|
+
| Large (100MB) | ~60s | ~3s |
|
|
285
|
+
|
|
286
|
+
## License
|
|
287
|
+
|
|
288
|
+
Apache-2.0
|
|
289
|
+
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
gtfs_guru-0.1.0.dist-info/METADATA,sha256=MkPlXAtIOOQjb_KgMiA_TA6SqTIf5UV1Va8rTLrDNsI,6918
|
|
2
|
+
gtfs_guru-0.1.0.dist-info/WHEEL,sha256=EsgGQg7OBGIn-zS1ipDRPjO8C2qSQ0GRrd2xuL_Pyq0,143
|
|
3
|
+
gtfs_guru/__init__.py,sha256=07pjBrHesbYZsymeW8sWho0cXJ66SJ4urcX9Sjzm8NI,119
|
|
4
|
+
gtfs_guru/gtfs_guru.abi3.so,sha256=F2JTUh5NeS-_bE7Wy1awmA8f0Ffxgrbl3XcnSIIks0I,2271104
|
|
5
|
+
gtfs_guru-0.1.0.dist-info/RECORD,,
|