feat(dispatcher): catalog-driven MEOS-function dispatcher (step 4 foundation)#6
Open
estebanzimanyi wants to merge 2 commits into
Open
Conversation
Vendor MobilityAPI's read-only copy of MEOS-API's published catalog +
projection artefacts under `vendor/meos-api/`, plus a Makefile target
`make vendor-meos-api` that regenerates them from upstream.
Files added:
vendor/meos-api/
PROVENANCE.json -- per-artefact source URLs + regenerate cmd
README.md -- refresh procedure
meos-idl.json -- 3546 fns / 70 structs / 16 enums
(generated by MEOS-API run.py over
MobilityDB master meos/include headers)
meos-coverage.json -- structural worklist (from open PR MobilityDB#4)
meos-object-model-parity.json -- 29-pair portable-parity (from open PR #10)
The Makefile target clones MEOS-API + MobilityDB shallowly, installs
libclang, runs MEOS-API's `run.py` against MobilityDB's MEOS headers,
and copies the produced JSON artefacts into `vendor/meos-api/`.
Two of the four artefacts (`meos-coverage.json`,
`meos-object-model-parity.json`) currently come from open MEOS-API PR
branches because their generators are not yet on master; PROVENANCE.json
makes that explicit. The Makefile gracefully skips them if absent.
Step 2 of `docs/MEOS_API_INGESTION_PLAN.md`. The drift gate workflow
that fails on stale artefacts is step 3 (separate stacked PR).
…ndation)
Step 4 of docs/MEOS_API_INGESTION_PLAN.md — the catalog-driven
dispatcher that the 5 'REPLACE' resource modules will delegate to in
follow-up PRs.
mobilityapi/dispatcher.py:
- Loads vendor/meos-api/meos-idl.json at construction; honours an
explicit catalog_path= for tests.
- Filters to network.exposable functions only when enrichment fields
are present; otherwise treats every function as exposable.
- FunctionSignature dataclass: name / category / params / return_type
/ decode_per_param / encode_return / description, all populated
from the catalog (enriched or bare).
- dispatch(function_name, params) -> Any:
* validates the parameter set against the catalog signature
(missing or unexpected names raise TypeError)
* resolves the MEOS function via an injected resolver callable
(production: getattr(pymeos.functions, name); tests: stub
registry)
* invokes it with the validated keyword args
* returns the result; the caller owns encoding to JSON / WKB
tests/test_dispatcher.py (12 tests, all passing locally):
- catalog load (default path, explicit path, FileNotFoundError)
- FunctionSignature.from_catalog_entry (basic fields, enriched wire
metadata, fallback when wire absent, non-exposable filtering)
- dispatch contract (resolver invocation, unknown function, missing
param, unexpected param, default stub resolver)
- integration sanity (the 5 MovFeat dispatch candidates named in the
ingestion plan are present in the vendored catalog)
What this PR does NOT change:
- Existing hand-written endpoint modules in resource/* remain
unchanged. The plan's 5 REPLACE candidates migrate to the
dispatcher module-by-module in follow-up PRs:
temporal_geom_seq/, temporal_geom_query/{velocity,acceleration,
distance}, temporal_properties/.
- PyMEOS is not yet a dependency (the dispatcher is resolver-
agnostic; the production resolver lands when the first endpoint
migrates).
Stacks on MobilityDB#4 (vendor MEOS-API artefacts) so vendor/meos-api/meos-idl.json
is in the tree.
9db7952 to
6bf5621
Compare
This was referenced May 20, 2026
estebanzimanyi
added a commit
to estebanzimanyi/MobilityAPI
that referenced
this pull request
May 21, 2026
Adds mobilityapi/app.py + two routers that expose the catalog-driven Dispatcher (PR MobilityDB#6) and WireCodec (PR MobilityDB#7) as HTTP endpoints: - GET /catalog -> list dispatcher-exposable functions - GET /catalog/{name} -> full signature for one function - POST /functions/{name} -> invoke with JSON body, decode/encode opaque MEOS types via the WireCodec The app is built by create_app(dispatcher, codec) — both dependencies are explicit; no global singletons. Production wires both to PyMEOS; tests pass stubs. The POST /functions/{name} flow: 1. Decode opaque-type params via codec.decode(encoding, wire_value). 2. Dispatch via Dispatcher.dispatch(name, params). 3. Encode the result via codec.encode(encoding, value) if the catalog marks the return as serialised. Error mapping: - Unknown function -> 404 - Missing / extra parameters -> 400 - Param encoding has no codec decoder -> 400 - Result encoding has no codec encoder -> 500 tests/test_app.py: 11 HTTP-level tests against a tiny in-test catalog covering scalar, serialised-in / scalar-out, and serialised-in / serialised-out shapes, plus the four error paths. All 38 framework tests pass.
estebanzimanyi
added a commit
to estebanzimanyi/MobilityAPI
that referenced
this pull request
May 21, 2026
Adds mobilityapi/app.py + two routers that expose the catalog-driven Dispatcher (PR MobilityDB#6) and WireCodec (PR MobilityDB#7) as HTTP endpoints: - GET /catalog -> list dispatcher-exposable functions - GET /catalog/{name} -> full signature for one function - POST /functions/{name} -> invoke with JSON body, decode/encode opaque MEOS types via the WireCodec The app is built by create_app(dispatcher, codec) — both dependencies are explicit; no global singletons. Production wires both to PyMEOS; tests pass stubs. The POST /functions/{name} flow: 1. Decode opaque-type params via codec.decode(encoding, wire_value). 2. Dispatch via Dispatcher.dispatch(name, params). 3. Encode the result via codec.encode(encoding, value) if the catalog marks the return as serialised. Error mapping: - Unknown function -> 404 - Missing / extra parameters -> 400 - Param encoding has no codec decoder -> 400 - Result encoding has no codec encoder -> 500 tests/test_app.py: 11 HTTP-level tests against a tiny in-test catalog covering scalar, serialised-in / scalar-out, and serialised-in / serialised-out shapes, plus the four error paths. All 38 framework tests pass.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacks on #4. Step 4 of
docs/MEOS_API_INGESTION_PLAN.md— the catalog-driven dispatcher that the 5 'REPLACE' resource modules will delegate to in follow-up PRs.What it ships
mobilityapi/dispatcher.py:vendor/meos-api/meos-idl.jsonat construction; honours an explicitcatalog_path=for tests.network.exposablefunctions only when enrichment fields are present; otherwise treats every function as exposable.FunctionSignaturedataclass: name / category / params / return_type / decode_per_param / encode_return / description, all populated from the catalog (enriched or bare).dispatch(function_name, params) -> Any:tests/test_dispatcher.py— 12 tests, all passing locally (python3 -m pytest tests/test_dispatcher.py -v):FunctionSignature.from_catalog_entry(basic fields, enriched wire metadata, fallback when wire absent, non-exposable filtering)Resolver pattern
Production wiring lands when the first endpoint migrates:
For tests, a stub registry suffices:
What this PR does NOT change
resource/*are unchanged. The plan's 5 REPLACE candidates migrate to the dispatcher one PR at a time:resource/temporal_geom_seq/(Create, Retrieve) →temporal_from_mfjson/temporal_as_mfjsonresource/temporal_geom_query/velocity.py→tpoint_speedresource/temporal_geom_query/acceleration.py→temporal_derivativeresource/temporal_geom_query/distance.py→tpoint_cumulative_lengthresource/temporal_properties/→temporal_as_mfjsonDependency chain
When #4 lands, this PR's diff narrows to just the new
mobilityapi/+tests/files.