Jak/stapi v0.2.0#129
Draft
jkeifer wants to merge 25 commits into
Draft
Conversation
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RhnGNojViYvYDevhtz999a
…tion stapi fields
Feature[G, P] from geojson_pydantic types geometry and properties as
optional/nullable. Opportunity never narrowed these, so
model_validate accepted {"geometry": None, ...}, which then skipped
bbox computation in compute_bbox and produced a dump violating the
v0.2.0 spec (geometry and bbox are both REQUIRED, non-null).
Override geometry and properties on Opportunity to use the class's
own bound TypeVars (G, P) as required fields, and drop the
"geometry is not None" guard in compute_bbox now that geometry can
no longer be None.
…yables enforcement
…tives
ConformanceClasses.pattern built a regex without an end anchor, and
callers used re.match (start-anchored only). This let OPPORTUNITIES
("/opportunities") falsely match URIs like ".../opportunities-async",
so a client could report sync-opportunities support against an
async-only server. Adding a trailing "$" to the pattern fixes it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The reference app's RootRouter construction omitted
get_opportunity_search_record_statuses, so the exported OpenAPI spec
was missing the /searches/opportunities/{search_record_id}/statuses
endpoint and OpportunitySearchStatusCollection schema. The mock
backend already existed and was used by the conftest.py fixture
router; this wires the same mock into the application used for
OpenAPI export so the reference app exercises the full conformance
surface.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Removes the OrderPayload, OpportunityPayload, OrderSearchParameters, OrderStatuses, and OpportunitySearchRecords aliases that scaffolded the v0.2.0 migration. Only the spec-aligned names remain: OrderRequest, OpportunityRequest, SearchParameters, OrderStatusCollection, and OpportunitySearchRecordCollection. Breaking change, accepted for this release. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…on tests Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RhnGNojViYvYDevhtz999a
Harvested from unmerged PR #68 (pystapi-schema-generator): the spec intro as the info description, a contact block, per-tag descriptions with externalDocs links into the spec documents, and top-level externalDocs pointing at the rendered documentation site. Links are updated for the current spec repo layout and tag names match the actual router tags. Note openapi_extra is a path-operation parameter, not an application one, so top-level externalDocs is injected via an openapi wrapper. Also drop an inert conformsTo kwarg mistakenly passed to Provider. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Move the generic reference FastAPI app and OpenAPI post-processing logic from scripts/openapi_app.py + scripts/export-openapi into a new stapi_fastapi.reference_app module, exposing create_reference_app(), export_openapi(), and main(). Add an optional "export" extra (pyyaml) and a stapi-fastapi-export-openapi console script so the tool ships with the package. scripts/export-openapi is now a thin shim delegating to the packaged main(). Add tests/test_reference_app.py asserting export invariants (path inventory, no leaked example-product paths, productId param injection, info/externalDocs, key component schemas, determinism) so these run under the normal test/type gates. types-pyyaml added to the root dev group to keep mypy clean on the new module. Verified the export is byte-identical to the committed spec/openapi.yaml before and after. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The framework wheel no longer ships the reference app or a console script. Move the generic reference FastAPI app and OpenAPI export CLI out of stapi-fastapi into a new thin workspace member, pystapi-schema-generator, which realizes the package structure proposed in unmerged PR #68 but wires it against the real stapi_fastapi routers (no forked routers). The package imports pyyaml unconditionally at module scope, since export is its entire purpose, dropping the lazy-import/extra dance stapi-fastapi needed as a general-purpose framework. scripts/export-openapi is now a shim delegating to pystapi_schema_generator.application.main. Wired the new member into the root workspace, dependencies, and mypy file list, and into scripts/run-tests.sh's per-package test loop. Verified the exported openapi.yaml is still byte-identical to the committed stapi-spec artifact. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The spec's Search Parameters Object datetime allows open ends via '..' or an empty string, with only singly-open intervals permitted. Adds OpenDatetimeInterval; OpportunityProperties keeps the closed DatetimeInterval since an opportunity window is concrete. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…nable Spec frames statuses as extensible: providers may support additional statuses through extensions. status_code is now enum-or-string (known codes still validate to the enum), and OrderStatus / OpportunitySearchStatus are generic so implementations can constrain the accepted set with their own StrEnum, e.g. OrderStatus[MyCodes]. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- bbox non-nullable and serialization-required on Order/Opportunity - spec-REQUIRED defaulted fields (type, stapi_type, stapi_version, links, conformsTo, ...) marked required in serialization schemas - Link schema no longer degrades to a bare object in serialization - stored order requests and search parameters round-trip unknown fields - Opportunity id is string-only; collections omit null id - Product.description required per spec - numberMatched available on all collections - clear error for bbox computation on empty geometries Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- products advertise sync/async opportunity classes per actual capability - search records carry rel=monitor links when statuses endpoint exists - landing page uses spec rel search-records - Preference-Applied always sent when a preference was specified - statuses endpoint and conformance gated on async search support - Location headers and correct media types documented in OpenAPI Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- opportunity capability checks consult the product's conformsTo per spec, not the root document - conformance URI patterns anchor the version as a single path segment - enum gains API-level extension classes (order-statuses, searches-opportunity, searches-opportunity-statuses) - fixtures model a spec-compliant server Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- generic deterministic operationIds; no concrete-product leakage - readable component schema names; orphan BaseModel eliminated - conformance URI example on GET /conformance - exported doc verified to carry required-field, Location-header, media-type, and extensible-status fixes from the model/router work - full schema-inventory and subprocess determinism invariant tests - bound stapi-fastapi>=0.9.0; license/authors metadata Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR updates the workspace to STAPI v0.2.0 across the Pydantic models, FastAPI server, and Python client, and adds a new pystapi-schema-generator package to export a clean, generic OpenAPI document.
Changes:
- Bump STAPI versions and align server/client behavior and conformance URI handling for v0.2.0.
- Restructure request/response models (notably
SearchParameters,OrderRequest, async opportunity search records/status collections) and tighten JSON-schema serialization requirements. - Add a standalone schema generator package + script to export a deterministic OpenAPI YAML with cleaned schema names/operationIds.
Reviewed changes
Copilot reviewed 47 out of 49 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| uv.lock | Adds new workspace package and dependency updates (incl. pyyaml/types). |
| stapi-pydantic/tests/test_shared.py | Adds schema/serialization tests for shared models (Link/RootResponse/Conformance). |
| stapi-pydantic/tests/test_search_parameters.py | Adds tests for open-ended datetime intervals and SearchParameters behavior. |
| stapi-pydantic/tests/test_product.py | Adds/updates tests for v0.2.0 product models and required fields. |
| stapi-pydantic/tests/test_order.py | Expands tests for order models (status code extensibility, bbox computation, stored requests). |
| stapi-pydantic/tests/test_opportunity.py | Expands tests for opportunity request/record/status models and bbox/schema requirements. |
| stapi-pydantic/tests/test_filter.py | Adds tests for CQL2 property-name extraction helper. |
| stapi-pydantic/src/stapi_pydantic/shared.py | Introduces reusable NumberMatched annotated field and updates Link serialization behavior. |
| stapi-pydantic/src/stapi_pydantic/search_parameters.py | Adds SearchParameters model shared by Order/Opportunity requests. |
| stapi-pydantic/src/stapi_pydantic/root.py | Forces defaults to be required in serialization schema for RootResponse. |
| stapi-pydantic/src/stapi_pydantic/product.py | Updates Product/ProductsCollection fields to v0.2.0 shape (stapi_type/version, required description, numberMatched). |
| stapi-pydantic/src/stapi_pydantic/order.py | Refactors order request/storage shapes, adds bbox computation, introduces status collections and generic status code handling. |
| stapi-pydantic/src/stapi_pydantic/opportunity.py | Refactors opportunity request/search record/status models; adds bbox computation and collections. |
| stapi-pydantic/src/stapi_pydantic/geometry.py | Adds bbox computation helper used by Order/Opportunity models. |
| stapi-pydantic/src/stapi_pydantic/filter.py | Adds cql2_property_names traversal utility. |
| stapi-pydantic/src/stapi_pydantic/datetime_interval.py | Adds singly-open datetime interval parsing/serialization for SearchParameters. |
| stapi-pydantic/src/stapi_pydantic/constants.py | Bumps STAPI_VERSION to 0.2.0. |
| stapi-pydantic/src/stapi_pydantic/conformance.py | Adjusts conformance model schema requirements for serialization. |
| stapi-pydantic/src/stapi_pydantic/init.py | Re-exports new/renamed models and utilities for v0.2.0. |
| stapi-pydantic/pyproject.toml | Bumps package version and adds typing-extensions dependency. |
| stapi-fastapi/tests/test_product.py | Updates server response assertions to new product collection shape. |
| stapi-fastapi/tests/test_order.py | Updates tests for new order request shape, required-filter enforcement, and status collection responses. |
| stapi-fastapi/tests/test_opportunity.py | Adds test ensuring required queryable predicates are enforced for opportunity search. |
| stapi-fastapi/tests/test_opportunity_async.py | Adds/updates async opportunity search tests (monitor links, statuses collection, conformance behavior, Prefer handling). |
| stapi-fastapi/tests/shared.py | Updates test products’ conformsTo behavior to rely on router-derived conformances. |
| stapi-fastapi/tests/conftest.py | Adjusts fixtures to new opportunity search body shape and stops force-overriding product conformsTo. |
| stapi-fastapi/tests/backends.py | Updates mock backends for new request/record shapes and fixes opportunity geometry reflection. |
| stapi-fastapi/tests/application.py | Wires the async search-record-statuses backend in the test application. |
| stapi-fastapi/src/stapi_fastapi/routers/root_router.py | Renames/extends async-search links, returns collections for statuses/records, and gates statuses endpoint correctly. |
| stapi-fastapi/src/stapi_fastapi/routers/product_router.py | Updates payload models, adds required-queryables validation, and improves OpenAPI response metadata. |
| stapi-fastapi/src/stapi_fastapi/errors.py | Changes QueryablesError to HTTP 400. |
| stapi-fastapi/src/stapi_fastapi/backends/product_backend.py | Updates backend type aliases for new payload/request models. |
| stapi-fastapi/pyproject.toml | Bumps stapi-fastapi version to 0.9.0. |
| scripts/run-tests.sh | Includes pystapi-schema-generator in the test runner loop. |
| scripts/export-openapi | Adds shim script to export OpenAPI YAML via the new generator package. |
| pystapi-schema-generator/tests/test_application.py | Adds snapshot/invariant tests for exported OpenAPI (paths, schemas, determinism, cleanliness). |
| pystapi-schema-generator/src/pystapi_schema_generator/py.typed | Marks package as typed. |
| pystapi-schema-generator/src/pystapi_schema_generator/application.py | Implements reference app + OpenAPI post-processing (clean ids/names, dedup, templated product paths, examples). |
| pystapi-schema-generator/src/pystapi_schema_generator/init.py | Exposes generator entrypoints. |
| pystapi-schema-generator/README.md | Documents CLI usage. |
| pystapi-schema-generator/pyproject.toml | Defines the new package, dependencies, and console script. |
| pystapi-client/tests/test_client.py | Adds tests for updated conformance URI patterns and product-scoped opportunity capability checks. |
| pystapi-client/tests/fixtures/products.json | Updates fixtures for v0.2.0 product shapes and per-product conformsTo inventory. |
| pystapi-client/tests/fixtures/landing_page.json | Updates root conformance URIs to v0.2.0 API-level classes only. |
| pystapi-client/tests/conftest.py | Mocks per-product GET endpoints for product conformance capability checks. |
| pystapi-client/src/pystapi_client/conformance.py | Updates conformance class inventory and tightens URI regex patterns. |
| pystapi-client/src/pystapi_client/client.py | Switches opportunity support checks to product-scoped conformsTo and updates request models. |
| pystapi-client/pyproject.toml | Bumps pystapi-client version to 0.0.2. |
| pyproject.toml | Adds new workspace member/package and updates dev dependencies and mypy file set. |
Comments suppressed due to low confidence (1)
stapi-pydantic/src/stapi_pydantic/order.py:97
- OrderStatus.new currently instantiates OrderStatus directly, which bypasses the calling class's generic parameterization/subclassing (e.g. OrderStatus[NarrowCodes]) and can allow values that should be rejected. Use cls(...) so constraints are applied consistently.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| async def create_order(self, payload: OrderPayload, request: Request, response: Response) -> Order: # type: ignore | ||
| def validate_required_queryables(self, search_parameters: SearchParameters) -> None: | ||
| required = set(self.product.queryables.model_json_schema().get("required", [])) |
| [sys.executable, "-m", "pystapi_schema_generator.application"], | ||
| capture_output=True, | ||
| check=True, | ||
| env={"PYTHONHASHSEED": seed, "PATH": os.environ.get("PATH", "")}, |
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.
What I'm changing
How I did it
Checklist
./scripts/run-tests.shuv run pre-commit run --all-files