gflights 0.2.1__tar.gz
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.
- gflights-0.2.1/.gitignore +16 -0
- gflights-0.2.1/CHANGELOG.md +135 -0
- gflights-0.2.1/CLAUDE.md +164 -0
- gflights-0.2.1/Cargo.lock +2877 -0
- gflights-0.2.1/Cargo.toml +60 -0
- gflights-0.2.1/LICENSE +21 -0
- gflights-0.2.1/PKG-INFO +13 -0
- gflights-0.2.1/README.md +541 -0
- gflights-0.2.1/benches/parse.rs +108 -0
- gflights-0.2.1/build.rs +23 -0
- gflights-0.2.1/examples/cheapest_dates.rs +96 -0
- gflights-0.2.1/examples/date_grid.rs +62 -0
- gflights-0.2.1/examples/explore.rs +90 -0
- gflights-0.2.1/examples/flights.rs +149 -0
- gflights-0.2.1/examples/graph.rs +72 -0
- gflights-0.2.1/examples/multi_city.rs +57 -0
- gflights-0.2.1/examples/offer.rs +128 -0
- gflights-0.2.1/gflights/__init__.py +57 -0
- gflights-0.2.1/gflights/_gflights.pyi +220 -0
- gflights-0.2.1/gflights/_types.py +12 -0
- gflights-0.2.1/gflights/py.typed +0 -0
- gflights-0.2.1/gflights-py/.gitignore +9 -0
- gflights-0.2.1/gflights-py/Cargo.toml +22 -0
- gflights-0.2.1/gflights-py/src/lib.rs +1146 -0
- gflights-0.2.1/gflights-py/tests/test_errors.py +103 -0
- gflights-0.2.1/gflights-py/tests/test_import.py +103 -0
- gflights-0.2.1/gflights-py/tests/test_live.py +269 -0
- gflights-0.2.1/gflights-py/tests/test_types.py +39 -0
- gflights-0.2.1/gflights-py/uv.lock +7 -0
- gflights-0.2.1/hooks/pre-commit +26 -0
- gflights-0.2.1/pyproject.toml +36 -0
- gflights-0.2.1/src/bin/cli/cheap.rs +154 -0
- gflights-0.2.1/src/bin/cli/date_grid.rs +105 -0
- gflights-0.2.1/src/bin/cli/explore.rs +296 -0
- gflights-0.2.1/src/bin/cli/graph.rs +60 -0
- gflights-0.2.1/src/bin/cli/mod.rs +611 -0
- gflights-0.2.1/src/bin/cli/multi_city.rs +240 -0
- gflights-0.2.1/src/bin/cli/offer.rs +91 -0
- gflights-0.2.1/src/bin/cli/search.rs +223 -0
- gflights-0.2.1/src/bin/main.rs +46 -0
- gflights-0.2.1/src/lib.rs +76 -0
- gflights-0.2.1/src/parsers/common/airline.rs +193 -0
- gflights-0.2.1/src/parsers/common/duration.rs +281 -0
- gflights-0.2.1/src/parsers/common/fixed_flights.rs +156 -0
- gflights-0.2.1/src/parsers/common/location.rs +63 -0
- gflights-0.2.1/src/parsers/common/mod.rs +258 -0
- gflights-0.2.1/src/parsers/common/travelers.rs +138 -0
- gflights-0.2.1/src/parsers/common/types.rs +240 -0
- gflights-0.2.1/src/parsers/constants.rs +12 -0
- gflights-0.2.1/src/parsers/mod.rs +37 -0
- gflights-0.2.1/src/parsers/request/calendar_graph_request.rs +223 -0
- gflights-0.2.1/src/parsers/request/city_request.rs +58 -0
- gflights-0.2.1/src/parsers/request/date_grid_request.rs +242 -0
- gflights-0.2.1/src/parsers/request/explore_request.rs +323 -0
- gflights-0.2.1/src/parsers/request/flight_request.rs +1293 -0
- gflights-0.2.1/src/parsers/request/mod.rs +15 -0
- gflights-0.2.1/src/parsers/response/calendar_graph_response.rs +121 -0
- gflights-0.2.1/src/parsers/response/city_response.rs +179 -0
- gflights-0.2.1/src/parsers/response/date_grid_response.rs +397 -0
- gflights-0.2.1/src/parsers/response/explore_response.rs +317 -0
- gflights-0.2.1/src/parsers/response/flight_response.rs +1383 -0
- gflights-0.2.1/src/parsers/response/mod.rs +17 -0
- gflights-0.2.1/src/parsers/response/offer_response.rs +386 -0
- gflights-0.2.1/src/protos/message.proto +61 -0
- gflights-0.2.1/src/protos/mod.rs +220 -0
- gflights-0.2.1/src/protos/readme.md +7 -0
- gflights-0.2.1/src/requests/api.rs +1213 -0
- gflights-0.2.1/src/requests/config/builder.rs +561 -0
- gflights-0.2.1/src/requests/config/currency.rs +175 -0
- gflights-0.2.1/src/requests/config/explore.rs +337 -0
- gflights-0.2.1/src/requests/config/mod.rs +640 -0
- gflights-0.2.1/src/requests/config/multi_city.rs +539 -0
- gflights-0.2.1/src/requests/mod.rs +2 -0
- gflights-0.2.1/test_files/booking_offer_response.txt +10 -0
- gflights-0.2.1/test_files/error0.txt +1 -0
- gflights-0.2.1/test_files/error1.txt +1 -0
- gflights-0.2.1/test_files/flights.txt +10 -0
- gflights-0.2.1/test_files/flights_new_test.txt +1 -0
- gflights-0.2.1/test_files/graph_response +4 -0
- gflights-0.2.1/test_files/inner_object_test.txt +1 -0
- gflights-0.2.1/test_files/low_price_in_second_line.txt +10 -0
- gflights-0.2.1/test_files/lux_dubai_oneway.txt +1 -0
- gflights-0.2.1/test_files/lux_milan_oneway.txt +1 -0
- gflights-0.2.1/test_files/lux_tokyo_oneway.txt +1 -0
- gflights-0.2.1/test_files/offers_full.txt +10 -0
- gflights-0.2.1/test_files/offers_single_line.txt +1 -0
- gflights-0.2.1/test_files/raw.response +1 -0
- gflights-0.2.1/test_files/raw_gflights.response +1 -0
- gflights-0.2.1/test_files/raw_multiline.txt +14 -0
- gflights-0.2.1/test_files/raw_offer_response.txt +12 -0
- gflights-0.2.1/test_files/response_non_uniform_city_images.txt +1 -0
- gflights-0.2.1/test_files/response_with_first_fixed_full.txt +10 -0
- gflights-0.2.1/test_files/with_28_elements.txt +1 -0
- gflights-0.2.1/tests/live_api.rs +1473 -0
- gflights-0.2.1/tests/negative.rs +405 -0
- gflights-0.2.1/tests/wire.rs +283 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Generated by Cargo
|
|
2
|
+
# will have compiled files and executables
|
|
3
|
+
debug/
|
|
4
|
+
target/
|
|
5
|
+
|
|
6
|
+
# Cargo.lock is committed: this crate ships a binary, so pinning deps matters.
|
|
7
|
+
# https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
|
8
|
+
|
|
9
|
+
# These are backup files generated by rustfmt
|
|
10
|
+
**/*.rs.bk
|
|
11
|
+
|
|
12
|
+
# MSVC Windows builds of rustc generate these, which store debugging information
|
|
13
|
+
*.pdb
|
|
14
|
+
|
|
15
|
+
.cargo/
|
|
16
|
+
.vscode/
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## [0.2.1] — 2026-06-04
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
|
|
16
|
+
- TLS backend switched from native-tls (vendored OpenSSL) to **rustls**. This
|
|
17
|
+
removes the OpenSSL — and its Perl — build dependency, making builds hermetic
|
|
18
|
+
on every platform and fixing portable (manylinux) wheel builds. No API change.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## [0.2.0] — 2026-06-04
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
|
|
26
|
+
#### Core library
|
|
27
|
+
|
|
28
|
+
- **`gflights explore`** — `GetExploreDestinations` endpoint + CLI `explore` subcommand.
|
|
29
|
+
Returns `Vec<ExploreResult>` with destination name, country, airport codes, price, dates,
|
|
30
|
+
airline, CO₂, and accommodation price.
|
|
31
|
+
- `ExploreResult::flight_airport` — actual flight destination airport (may differ from the
|
|
32
|
+
geographic `nearest_airport`; e.g. Verdon Gorge shows MRS, not NCE).
|
|
33
|
+
- `--interest` flag accepts names (`beaches`, `climbing`, …), aliases, or raw Knowledge-Graph
|
|
34
|
+
MIDs (`/m/…`).
|
|
35
|
+
- `--to` flag filters to a destination airport or geographic region (Alps, Northern Europe, …).
|
|
36
|
+
- **`request_cheapest_dates`** — scans a range of months for the cheapest one-way or round-trip
|
|
37
|
+
departure dates; returns `Vec<CheapDate>` sorted by price.
|
|
38
|
+
- **`request_date_grid`** — full departure × return price matrix from `GetCalendarGrid`;
|
|
39
|
+
returns `Vec<DateGridEntry>`. Now runs chunks concurrently (`buffer_unordered(8)`)
|
|
40
|
+
with per-chunk body-read retry on EOF, reducing round-trip scan time from ~10 min to ~30 s.
|
|
41
|
+
- **Multi-city (open-jaw) search** — `MultiCityConfig::builder()` with per-leg
|
|
42
|
+
`max_price`, `carry_on`, `checked_bags` filters.
|
|
43
|
+
- **Up to 7 airports per side** — `departure` / `destination` (and each multi-city
|
|
44
|
+
leg) now accept up to 7 origin/destination airports, matching Google's maximum
|
|
45
|
+
(previously capped at 4).
|
|
46
|
+
- **Arrives-next-day detection** — `Itinerary::arrives_next_day()`, `arrival_date()`,
|
|
47
|
+
`departure_date()` derived from raw date fields.
|
|
48
|
+
- **`max_price` filter** on `Config` and `MultiCityConfig`.
|
|
49
|
+
- **Baggage filter** (`carry_on`, `checked_bags`) on `Config`.
|
|
50
|
+
- **`AirlineFilter`** with `Alliance` variants (OneWorld, SkyTeam, StarAlliance) and
|
|
51
|
+
`FromStr` parsing (`"LX"`, `"ONEWORLD"`, `"star_alliance"`).
|
|
52
|
+
- **`stopover_min`** field on `Config` — minimum layover duration.
|
|
53
|
+
- **`language` / `country`** on `Config` and `ExploreConfig` — removes hard-coded `en-GB`.
|
|
54
|
+
- **`sort_order`** field on `Config` (`SortOrder` enum: Best, Price, Duration,
|
|
55
|
+
DepartureTime, ArrivalTime).
|
|
56
|
+
- **Rate-limiter** (governor token bucket, 10 req/s default) with 429 detection flag and
|
|
57
|
+
`reset_rate_limit()`. Shared across all clones of an `ApiClient`.
|
|
58
|
+
- **Retry logic** (`RetryConfig`) — exponential back-off for 5xx/timeout; configurable via
|
|
59
|
+
`ApiClient::with_retry_config()`. `request_date_grid` also retries body-read errors.
|
|
60
|
+
- **`RateLimitedError`** — downcasting sentinel for HTTP 429.
|
|
61
|
+
- **`Travelers::new()`** — validates ≥1 adult, total ≤9; previously unchecked.
|
|
62
|
+
- **`PlaceType::from(i32)` non-panicking** — unknown discriminants return `Unspecified`
|
|
63
|
+
with a `tracing::warn!` instead of panicking.
|
|
64
|
+
|
|
65
|
+
#### CLI (`gflights` binary)
|
|
66
|
+
|
|
67
|
+
- `search` subcommand: `--airline`, `--exclude-airline`, `--via`, `--min-layover`,
|
|
68
|
+
`--max-layover`, `--lower-emissions`, `--sort`, `--format`.
|
|
69
|
+
- `search --show-co2` — CO₂ kg column in table output.
|
|
70
|
+
- `search --detail` — layover airports (`via ZRH (65 min)`) and `+1` next-day marker.
|
|
71
|
+
- `graph` subcommand.
|
|
72
|
+
- `dgrid` subcommand.
|
|
73
|
+
- `offer` subcommand (booking offers + deep links).
|
|
74
|
+
- `cheap` subcommand (cheapest departure dates, `--trip-days N` for round trips).
|
|
75
|
+
- `explore` subcommand with `--interest`, `--to`, `--duration`, `--month`, `--budget`.
|
|
76
|
+
- `mcity` (multi-city) subcommand.
|
|
77
|
+
- Interactive **REPL** with readline history; `--help` works inside the REPL.
|
|
78
|
+
|
|
79
|
+
#### Python bindings (`gflights-py`)
|
|
80
|
+
|
|
81
|
+
- Async Python bindings via pyo3 + maturin.
|
|
82
|
+
- Wheels use the CPython **abi3** stable ABI: a single wheel per platform works
|
|
83
|
+
on CPython 3.10+.
|
|
84
|
+
- `GFlights` class with methods: `search`, `price_graph`, `date_grid`,
|
|
85
|
+
`multi_city_search`, `explore`, `cheapest_dates`.
|
|
86
|
+
- **`GFlightsError`** — typed exception class; all API errors now raise
|
|
87
|
+
`GFlightsError` (a `Exception` subclass) instead of `RuntimeError`.
|
|
88
|
+
- Full `.pyi` type stubs for IDE support and mypy compatibility.
|
|
89
|
+
- `CheapDate`, `ExploreResult`, `EmissionsInfo`, `LayoverInfo`, `LegInfo` data classes.
|
|
90
|
+
- `rate_limited` flag and `reset_rate_limit()` on `GFlights`.
|
|
91
|
+
|
|
92
|
+
#### Tests
|
|
93
|
+
|
|
94
|
+
- **Wire-protocol tests** (`tests/wire.rs`) — 19 tests feeding captured fixtures through
|
|
95
|
+
parsers and asserting field values.
|
|
96
|
+
- **Negative / error-input tests** (`tests/negative.rs`) — 39 tests covering bad input
|
|
97
|
+
validation, malformed response bodies, and error message content.
|
|
98
|
+
- Live integration tests (`tests/live_api.rs`, gated behind `RUN_LIVE_TESTS=1`).
|
|
99
|
+
- Python offline test suite: `test_import.py`, `test_types.py`, `test_errors.py`.
|
|
100
|
+
|
|
101
|
+
### Fixed
|
|
102
|
+
|
|
103
|
+
- `Travelers::new([0, …])` returned `Ok` with 0 adults; now returns `Err`.
|
|
104
|
+
- `PlaceType::from(i32)` panicked on undocumented values; now logs warning and
|
|
105
|
+
returns `Unspecified`.
|
|
106
|
+
- `explore` CLI ARPT column showed geographic nearest airport (NCE) instead of the
|
|
107
|
+
actual flight destination airport (MRS for Verdon Gorge).
|
|
108
|
+
- REPL `--help` flag triggered `UnknownArgument` error instead of printing help.
|
|
109
|
+
- `_gflights.pyi` had unresolved merge-conflict markers from `feat/multi-city`;
|
|
110
|
+
`explore()`, `cheapest_dates()`, and `multi_city_search(max_price, …)` signatures
|
|
111
|
+
were missing.
|
|
112
|
+
- Date-grid chunking looped without moving the window, producing all-identical requests.
|
|
113
|
+
|
|
114
|
+
### Changed
|
|
115
|
+
|
|
116
|
+
- `request_date_grid` chunks are now dispatched concurrently with `buffer_unordered(8)`.
|
|
117
|
+
- `do_request()` retries 5xx/timeout errors; `request_date_grid_chunk` additionally
|
|
118
|
+
retries body-read errors (EOF from mid-stream connection closure).
|
|
119
|
+
- CI runs on pull requests only (not on every push to master).
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## [0.1.0] — 2026-04-01
|
|
124
|
+
|
|
125
|
+
Initial release.
|
|
126
|
+
|
|
127
|
+
- Flight search (one-way and return).
|
|
128
|
+
- Price graph (`GetCalendarGraph`).
|
|
129
|
+
- Booking offer resolution.
|
|
130
|
+
- City / airport lookup.
|
|
131
|
+
|
|
132
|
+
[Unreleased]: https://github.com/nas-/google-flights-rs/compare/v0.2.1...HEAD
|
|
133
|
+
[0.2.1]: https://github.com/nas-/google-flights-rs/compare/v0.2.0...v0.2.1
|
|
134
|
+
[0.2.0]: https://github.com/nas-/google-flights-rs/compare/v0.1.0...v0.2.0
|
|
135
|
+
[0.1.0]: https://github.com/nas-/google-flights-rs/releases/tag/v0.1.0
|
gflights-0.2.1/CLAUDE.md
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# gflights — Claude instructions
|
|
2
|
+
|
|
3
|
+
## Workspace layout
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
google-flights-rs/
|
|
7
|
+
├── src/ Rust library + CLI
|
|
8
|
+
│ ├── bin/cli/ CLI subcommands
|
|
9
|
+
│ ├── parsers/ Request builders & response parsers
|
|
10
|
+
│ └── requests/ ApiClient, Config, retry logic
|
|
11
|
+
├── gflights-py/ Python bindings (pyo3 + maturin)
|
|
12
|
+
│ ├── src/lib.rs Rust extension (_gflights)
|
|
13
|
+
│ ├── gflights/ Python package (re-exports, stubs, types)
|
|
14
|
+
│ └── tests/ Python test suite
|
|
15
|
+
├── benches/ Criterion benchmarks
|
|
16
|
+
└── tests/ Rust integration / live API tests
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Git workflow
|
|
22
|
+
|
|
23
|
+
- **Never commit directly to `master`** — always use a feature or fix branch.
|
|
24
|
+
- Branch naming: `feat/<topic>`, `fix/<topic>`, `chore/<topic>`.
|
|
25
|
+
- After every feature or fix is complete, run `/verify` to confirm the change works end-to-end at the CLI / Python surface before merging. The `--profile dev` build is sufficient for verification.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Before every commit — run locally first
|
|
30
|
+
|
|
31
|
+
Always verify locally before pushing. CI runs the same checks and failing there wastes time.
|
|
32
|
+
|
|
33
|
+
### Rust crate
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
cargo fmt # format (required — CI blocks on diff)
|
|
37
|
+
cargo clippy --all-targets -- -D warnings # lint (zero warnings policy)
|
|
38
|
+
cargo test --lib # 152 unit tests
|
|
39
|
+
cargo test --bin gflights # 13 CLI tests
|
|
40
|
+
cargo test --doc # doc tests
|
|
41
|
+
cargo build --benches # ensure benchmarks still compile
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Python bindings (run from `gflights-py/`)
|
|
45
|
+
|
|
46
|
+
```sh
|
|
47
|
+
cd gflights-py
|
|
48
|
+
python -m maturin develop # rebuild extension after Rust changes
|
|
49
|
+
.venv/Scripts/pytest.exe tests/test_import.py tests/test_types.py tests/test_errors.py -v
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
All offline tests must pass before pushing.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Live / integration tests
|
|
57
|
+
|
|
58
|
+
These hit the real Google Flights API. They are skipped unless the
|
|
59
|
+
`RUN_LIVE_TESTS` environment variable is set to a non-empty value.
|
|
60
|
+
|
|
61
|
+
### Rust
|
|
62
|
+
```sh
|
|
63
|
+
RUN_LIVE_TESTS=1 cargo test --test live_api
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Python
|
|
67
|
+
```sh
|
|
68
|
+
cd gflights-py
|
|
69
|
+
RUN_LIVE_TESTS=1 .venv/Scripts/pytest.exe tests/test_live.py -v
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Test coverage
|
|
75
|
+
|
|
76
|
+
Keep line coverage **≥ 80%** for the Rust crate.
|
|
77
|
+
|
|
78
|
+
```sh
|
|
79
|
+
cargo install cargo-tarpaulin # one-time
|
|
80
|
+
cargo tarpaulin --out Stdout # check coverage
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Current baseline: **84%** overall (parsers 84–99%; `api.rs` ~26% — network code, accepted).
|
|
84
|
+
If coverage drops below 80%, add tests before merging.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Examples parity rule
|
|
89
|
+
|
|
90
|
+
Every public-facing feature must have a corresponding example in `examples/`.
|
|
91
|
+
|
|
92
|
+
| Feature | Example file |
|
|
93
|
+
|---|---|
|
|
94
|
+
| Flight search + offers + booking URL | `examples/flights.rs` |
|
|
95
|
+
| Price graph | `examples/graph.rs` |
|
|
96
|
+
| Date grid | `examples/date_grid.rs` |
|
|
97
|
+
| Cheapest dates (one-way + round-trip) | `examples/cheapest_dates.rs` |
|
|
98
|
+
| Booking offers + URL resolution | `examples/offer.rs` |
|
|
99
|
+
| Multi-city search | `examples/multi_city.rs` |
|
|
100
|
+
| Explore destinations | `examples/explore.rs` |
|
|
101
|
+
|
|
102
|
+
When adding a new public API method, add or update the relevant example. All examples guard network calls behind `RUN_LIVE=1` so `cargo test --examples` passes offline.
|
|
103
|
+
|
|
104
|
+
```sh
|
|
105
|
+
cargo build --examples # must compile clean
|
|
106
|
+
RUN_LIVE=1 cargo run --example <name> # smoke-test with network
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Python bindings parity rule
|
|
112
|
+
|
|
113
|
+
Whenever `src/` (the Rust crate) changes, update `gflights-py/` to match:
|
|
114
|
+
|
|
115
|
+
| Rust change | Bindings update needed |
|
|
116
|
+
|---|---|
|
|
117
|
+
| New public method / field / type | Expose in `gflights-py/src/lib.rs`; add to `gflights/_gflights.pyi` |
|
|
118
|
+
| Renamed / removed API | Mirror in bindings |
|
|
119
|
+
| New `Config` option or filter | Add parameter to the affected Python method(s) |
|
|
120
|
+
| New response field | Expose on the relevant Python data class |
|
|
121
|
+
| Behaviour change | Update affected Python tests |
|
|
122
|
+
|
|
123
|
+
The Rust crate and Python bindings must stay in sync at all times.
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Building the Python extension
|
|
128
|
+
|
|
129
|
+
```sh
|
|
130
|
+
cd gflights-py
|
|
131
|
+
uv venv --python 3.11 .venv # one-time
|
|
132
|
+
uv pip install maturin pytest pytest-asyncio
|
|
133
|
+
python -m maturin develop # build + install into .venv
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
After any change to `gflights-py/src/lib.rs`, re-run `maturin develop` before running Python tests.
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## Security & dependency hygiene
|
|
141
|
+
|
|
142
|
+
```sh
|
|
143
|
+
cargo audit # check for CVEs (runs in CI)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Zero CVE policy — fix or justify any advisory before merging.
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Benchmarks
|
|
151
|
+
|
|
152
|
+
```sh
|
|
153
|
+
cargo bench # must be run from the project root (test_files/ paths)
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Benchmarks are in `benches/parse.rs`. They use fixtures from `test_files/`.
|
|
157
|
+
Do not move or rename fixtures without updating the benchmark.
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## Publishing (Rust crate)
|
|
162
|
+
|
|
163
|
+
`cargo publish --dry-run` must be clean before tagging a release.
|
|
164
|
+
The crate is live at https://crates.io/crates/gflights.
|