continuous-gtfs 0.1.0__py3-none-any.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.
Files changed (36) hide show
  1. continuous_gtfs/__init__.py +24 -0
  2. continuous_gtfs/analysis_storage.py +76 -0
  3. continuous_gtfs/builtins/__init__.py +0 -0
  4. continuous_gtfs/builtins/realtime/__init__.py +25 -0
  5. continuous_gtfs/builtins/realtime/transforms.py +637 -0
  6. continuous_gtfs/builtins/schedule/__init__.py +35 -0
  7. continuous_gtfs/builtins/schedule/removals.py +573 -0
  8. continuous_gtfs/builtins/schedule/transforms.py +540 -0
  9. continuous_gtfs/cli.py +1479 -0
  10. continuous_gtfs/context.py +246 -0
  11. continuous_gtfs/executor.py +195 -0
  12. continuous_gtfs/parsers.py +96 -0
  13. continuous_gtfs/pipelines/__init__.py +12 -0
  14. continuous_gtfs/pipelines/realtime.py +106 -0
  15. continuous_gtfs/pipelines/schedule.py +232 -0
  16. continuous_gtfs/prep.py +244 -0
  17. continuous_gtfs/py.typed +0 -0
  18. continuous_gtfs/results.py +44 -0
  19. continuous_gtfs/rt_compare/__init__.py +7 -0
  20. continuous_gtfs/rt_compare/compare.py +656 -0
  21. continuous_gtfs/rt_compare/config.py +26 -0
  22. continuous_gtfs/rt_compare/match.py +144 -0
  23. continuous_gtfs/rt_compare/report.py +147 -0
  24. continuous_gtfs/scanner.py +564 -0
  25. continuous_gtfs/schedule_helpers.py +256 -0
  26. continuous_gtfs/schedule_pairing.py +465 -0
  27. continuous_gtfs/schedule_records.py +477 -0
  28. continuous_gtfs/schedule_semantics.py +550 -0
  29. continuous_gtfs/step.py +333 -0
  30. continuous_gtfs/testing.py +304 -0
  31. continuous_gtfs-0.1.0.dist-info/METADATA +165 -0
  32. continuous_gtfs-0.1.0.dist-info/RECORD +36 -0
  33. continuous_gtfs-0.1.0.dist-info/WHEEL +4 -0
  34. continuous_gtfs-0.1.0.dist-info/entry_points.txt +3 -0
  35. continuous_gtfs-0.1.0.dist-info/licenses/LICENSE +202 -0
  36. continuous_gtfs-0.1.0.dist-info/licenses/NOTICE +5 -0
@@ -0,0 +1,24 @@
1
+ """Continuous GTFS transform framework."""
2
+
3
+ from .context import PipelineContext
4
+ from .executor import execute_pipeline
5
+ from .prep import PreparedRun, load_inputs, prepare_pipeline_run
6
+ from .results import ExecutionResult, StepResult
7
+ from .scanner import dag_edges, export_reactflow, resolve_dag, scan_pipeline
8
+ from .step import Step, step
9
+
10
+ __all__ = [
11
+ "Step",
12
+ "step",
13
+ "PipelineContext",
14
+ "StepResult",
15
+ "ExecutionResult",
16
+ "execute_pipeline",
17
+ "scan_pipeline",
18
+ "dag_edges",
19
+ "resolve_dag",
20
+ "export_reactflow",
21
+ "PreparedRun",
22
+ "prepare_pipeline_run",
23
+ "load_inputs",
24
+ ]
@@ -0,0 +1,76 @@
1
+ """GCS customTime stamping for analysis-bucket writes.
2
+
3
+ Every object the pipeline worker writes to the analysis bucket (canonical
4
+ form today; semantic/pairing tables later) must carry the retention
5
+ deadline of the source asset version it derives from, per
6
+ specs/data-retention.md §Analysis bucket. The deadline rides the run
7
+ dispatch (orchestrator's ``retention.ts`` ``dispatchDeadline()``, wired
8
+ onto ``DispatchRequest.deadline``) since the worker has no way to compute
9
+ a retention class itself.
10
+
11
+ Stamping happens at OBJECT CREATION, never as a follow-up metadata patch:
12
+ the pipeline service account holds create-only IAM on the analysis bucket
13
+ (``tf/modules/platform/analysis-storage.tf`` — objectCreator + objectViewer,
14
+ no update/delete), so ``customTime`` must be part of each object's initial
15
+ upload. gcsfs's ``fixed_key_metadata={"custom_time": ...}`` does exactly
16
+ that (see gcsfs.GCSFile — the value is folded into the initial
17
+ simple/resumable upload body, not a PATCH), so the helper here wraps
18
+ whatever filesystem ``gtfs_digester.write_exploded()`` would otherwise
19
+ resolve, injecting that metadata into every file it opens for write. A
20
+ ``None`` deadline (permanent/null-window source version) is a pure
21
+ passthrough: no customTime is ever set, matching "permanent and
22
+ null-window derived objects carry no customTime" in the spec.
23
+ """
24
+
25
+ from __future__ import annotations
26
+
27
+ from datetime import datetime
28
+ from typing import Any
29
+
30
+ import fsspec
31
+
32
+
33
+ class _StampingFilesystem:
34
+ """Wraps an fsspec filesystem so every file opened for write is created
35
+ with a fixed GCS ``customTime``. Wraps rather than subclasses — fsspec
36
+ filesystem instances are commonly cached per URL, and wrapping avoids
37
+ fighting that cache. Delegates every other attribute/method (mkdirs,
38
+ exists, ls, ...) straight through to the wrapped filesystem.
39
+ """
40
+
41
+ def __init__(self, fs: fsspec.AbstractFileSystem, deadline: datetime) -> None:
42
+ self._fs = fs
43
+ self._deadline = deadline
44
+
45
+ def __getattr__(self, name: str) -> Any:
46
+ return getattr(self._fs, name)
47
+
48
+ def open(self, path: str, mode: str = "rb", *args: Any, **kwargs: Any):
49
+ if "w" in mode or "x" in mode:
50
+ fixed = dict(kwargs.pop("fixed_key_metadata", None) or {})
51
+ fixed.setdefault("custom_time", self._deadline.isoformat())
52
+ kwargs["fixed_key_metadata"] = fixed
53
+ return self._fs.open(path, mode, *args, **kwargs)
54
+
55
+
56
+ def stamped_filesystem(
57
+ base_path: str,
58
+ deadline: datetime | None,
59
+ ) -> tuple[fsspec.AbstractFileSystem, str]:
60
+ """Resolve the fsspec filesystem for ``base_path``, wrapped so every
61
+ subsequently-written file is stamped with ``customTime = deadline`` at
62
+ creation. Pass both return values straight through to
63
+ ``gtfs_digester.write_exploded(filesystem=fs, base_path=resolved, ...)``
64
+ — ``write_exploded`` only resolves its own filesystem when ``None`` is
65
+ passed in, so handing it an already-resolved (and already-wrapped) one
66
+ skips that and uses ours for every write.
67
+
68
+ ``deadline=None`` (a permanent/null-window source version) returns the
69
+ plain, unwrapped filesystem: no customTime is ever set, matching
70
+ specs/data-retention.md's "permanent and null-window derived objects
71
+ carry no customTime."
72
+ """
73
+ fs, resolved = fsspec.core.url_to_fs(base_path)
74
+ if deadline is None:
75
+ return fs, resolved
76
+ return _StampingFilesystem(fs, deadline), resolved
File without changes
@@ -0,0 +1,25 @@
1
+ """Realtime transform builtins — parameterized Steps for GTFS-RT protobuf data."""
2
+
3
+ from .transforms import (
4
+ CombineFeeds,
5
+ ConvertScheduledToNew,
6
+ ExpireCancelledTrips,
7
+ FilterStopsByID,
8
+ InsertMissingCancellations,
9
+ PassThrough,
10
+ RenameVehicles,
11
+ TransformTripId,
12
+ UpdateFeedHeader,
13
+ )
14
+
15
+ __all__ = [
16
+ "PassThrough",
17
+ "FilterStopsByID",
18
+ "CombineFeeds",
19
+ "RenameVehicles",
20
+ "UpdateFeedHeader",
21
+ "TransformTripId",
22
+ "ExpireCancelledTrips",
23
+ "InsertMissingCancellations",
24
+ "ConvertScheduledToNew",
25
+ ]