Skip to content

[ENHANCEMENT] May schema release v1.17.0#528

Closed
Stephen Epps (stepps00) wants to merge 114 commits into
mainfrom
staging
Closed

[ENHANCEMENT] May schema release v1.17.0#528
Stephen Epps (stepps00) wants to merge 114 commits into
mainfrom
staging

Conversation

@stepps00
Copy link
Copy Markdown
Contributor

@stepps00 Stephen Epps (stepps00) commented May 18, 2026

Fixes #529

For February schema release. Version: v1.17.0

This pull request includes all commits from staging - some of which are currently on the main branch, some of which are not. After merge, this should give staging and main a common history, so that in the future all the merges are clean and any commits map to actual net-new changes.

Changes in these commits:

  • Makes operating_status field optional for Places
  • Various version updates
  • Now testing dep floors via lowest-direct matrix

John McCall (lowlydba) and others added 30 commits May 11, 2026 10:48
Update multiple packages' pyproject.toml files to add a maintainers list, common keywords, and a [project.urls] section (Homepage, Source, Issues). Affects core, system, cli, annex, and all theme packages under packages/overture-schema-*. This centralizes package metadata to improve discoverability, attribution, and tooling integration.
pytest-subtests merged into pytest core as of pytest 9.
Update test imports from pytest_subtests.SubTests to
_pytest.subtests.Subtests.

uv.lock was fully re-resolved, upgrading all transitive
dependencies to current versions. Notable: pytest 8.4→9.0,
mypy 1.18→1.19, pdoc 15→16, ruff 0.14.0→0.14.14.
* Widen `AdminLevel` from `uint8` to `int32` to match divisions data currently being generated.
* Fix Pydantic rebinding self in model constraint validator
Geometry constraint tests: replace full powerset (127 subsets of 7
geometry types) with singletons + pairs + full set (29 subsets).
GeometryTypeConstraint is a set-membership check — combinatorial
testing beyond pairs exercises no additional code paths.

Makefile: run pytest, doctest, ruff, and mypy concurrently via
make -j after a single upfront uv-sync. Added -only variants
(no uv-sync dep) for the parallel invocation; standalone targets
preserved with their original uv-sync dependencies.
* Treat None as absent in model constraint validation

require_any_of, require_if, and forbid_if now treat None as "not
present" for constraint purposes. Fields must be both in
model_fields_set and non-null to satisfy (or violate) a constraint.

- require_any_of: None no longer satisfies "at least one must be set"
- require_if: None no longer satisfies "must be set when condition holds"
- forbid_if: None no longer violates "must not be set when condition holds"

JSON Schema generation updated to emit {"not": {"type": "null"}}
property constraints alongside "required" assertions, via a shared
required_non_null helper in _json_schema.py. Shared predicate
_field_has_non_null_value extracted onto OptionalFieldGroupConstraint
so the check lives in one place. Also fixes a stray backtick in the
require_if error message.

* Use Python None terminology and clarify constraint docs

Use Python terminology (None) instead of null in docstrings, identifiers,
and error messages. Rewrite error messages to describe what's checked
("set to a value other than None") rather than using jargon.
Eliminates duplicated validate() and __get_pydantic_json_schema__()
across CountryCodeAlpha2, HexColor, LanguageTag, NoWhitespace,
SnakeCase, PhoneNumber, RegionCode, and WikidataId constraints.
Each is now a thin __init__-only wrapper calling super().__init__().

PatternConstraint gains optional keyword-only description, min_length,
max_length parameters for JSON Schema annotations. StringConstraint
gains _raise_validation_error() to deduplicate error construction
across PatternConstraint, JsonPointerConstraint, and
StrippedConstraint.
The previous pattern ^(\S.*)?\S$ required at least one non-whitespace
character, rejecting empty string. The validator itself accepts empty
string ("" == "".strip()), so the JSON schema was more restrictive
than the Python validation.

New pattern ^(\S(.*\S)?)?$ matches empty string (outer group optional),
single non-whitespace chars, and strings bookended by non-whitespace.

Updated all JSON schema baselines and inline expectations.
Replace `len(errors()) > 0` with error message assertions in
hex color and no-whitespace invalid tests. The weak assertions
only checked that validation failed, not that the correct error
was raised.
Replace 16 individual valid/invalid test methods with two parametrized
tests driven by PATTERN_CONSTRAINT_CASES. Covers all 8 PatternConstraint
subclasses: LanguageTag, CountryCodeAlpha2, RegionCode, WikidataId,
PhoneNumber, HexColor, NoWhitespace, SnakeCase.

Moved SnakeCaseConstraint tests from TestErrorHandling (where they were
misplaced) into the parametrized data.

Non-PatternConstraint tests remain as standalone methods: base
PatternConstraint (custom pattern), StrippedConstraint, and
JsonPointerConstraint (empty-string special case).
The dict branch of the Pydantic validator in BBox.__get_pydantic_core_schema__
constructed a BBox from the dict but didn't return it, silently producing
None. Add the missing return statement.

The test parametrize case for dict input covers this path.
Bare triple-quoted strings after NewType assignments are
expression statements that Python never attaches to the
NewType object, leaving __doc__ as None. Convert each to
an explicit __doc__ assignment so codegen and introspection
tools can read them at runtime.

Same pattern DocumentedEnum uses for enum member docs.
- Add -q, --tb=short to `make test` for compact output
- Set verbosity_subtests=0 to suppress per-subtest
  progress characters (the u/,/- markers from pytest's
  built-in subtests support)

Signed-off-by: Seth Fitzsimmons <sethfitz@amazon.com>
OvertureFeature validator error message had two continuation
lines missing the f-prefix, so {self.__class__.__name__} was
rendered literally. Also add missing space before "and".

Signed-off-by: Seth Fitzsimmons <sethfitz@amazon.com>
Also fix "supserset" typo in docstring.

Signed-off-by: Seth Fitzsimmons <sethfitz@amazon.com>
Replace hardcoded discriminator_fields tuple ("type", "theme",
"subtype") in _process_union_member with the discriminator field
name extracted from the union's Annotated metadata.

introspect_union already extracted the discriminator field name
but didn't pass it through to member processing. Now it does,
so unions using any field name as discriminator work correctly.

For nested unions, parent discriminator values are extracted from
nested leaf models to preserve structural tuple classification.

Feature.field_discriminator now attaches _field_name to the
callable, and _extract_discriminator_name reads it. This handles
the Discriminator-wrapping-a-callable case that str(disc) got
wrong silently.

Signed-off-by: Seth Fitzsimmons <sethfitz@amazon.com>
Make _extract_literal_value return str directly instead of object,
eliminating implicit str() conversions at call sites. Add comment
explaining nested union re-indexing under the parent discriminator.

Remove redundant test covered by TestDiscriminatorDiscovery and
debugging print() calls from TestStructuralTuples.

Signed-off-by: Seth Fitzsimmons <sethfitz@amazon.com>
The field holds the entry point value in "module:Class" format, not a
class name. The old name required callers to know this (codegen's cli.py
had a comment explaining it, and assigned to a local `entry_point`
variable to compensate).

Signed-off-by: Seth Fitzsimmons <sethfitz@amazon.com>
Empty package with build config, namespace packages, and
py.typed marker. Declares click, jinja2, tomli, and
overture-schema-core/system as dependencies.

Signed-off-by: Seth Fitzsimmons <sethfitz@amazon.com>
Type analyzer (analyze_type) handles all type unwrapping in a
single iterative function: NewType → Annotated → Union → list →
terminal classification. Constraints accumulate from Annotated
metadata with source tracking via ConstraintSource.

Data structures: TypeInfo (type representation), FieldSpec
(model field), ModelSpec (model), EnumSpec, NewTypeSpec,
PrimitiveSpec.

Type registry maps type names to per-target string
representations via TypeMapping. is_semantic_newtype()
distinguishes meaningful NewTypes from pass-through aliases.

Utilities: case_conversion (snake_case), docstring (cleaning
and custom-docstring detection).

Signed-off-by: Seth Fitzsimmons <sethfitz@amazon.com>
Domain-specific extractors that consume analyze_type() and
produce specs:

- model_extraction: extract_model() for Pydantic models with
  MRO-aware field ordering, alias resolution, and recursive
  sub-model expansion via expand_model_tree()
- enum_extraction: extract_enum() for DocumentedEnum classes
- newtype_extraction: extract_newtype() for semantic NewTypes
- primitive_extraction: extract_primitives() for numeric types
  with range and precision introspection
- union_extraction: extract_union() with field merging across
  discriminated union variants

Shared test fixtures in codegen_test_support.py.

Signed-off-by: Seth Fitzsimmons <sethfitz@amazon.com>
Generate prose from extracted constraint data:

- field_constraint_description: describe field-level
  constraints (ranges, patterns, unique items, hex colors)
  as human-readable notes with NewType source attribution
- model_constraint_description: describe model-level
  constraints (@require_any_of, @radio_group, @min_fields_set,
  @require_if, @forbid_if) as prose, with consolidation of
  same-field conditional constraints

Signed-off-by: Seth Fitzsimmons <sethfitz@amazon.com>
Determine what artifacts to generate and where they go:

- module_layout: compute output directories for entry points,
  map Python module paths to filesystem output paths via
  compute_output_dir
- path_assignment: build_placement_registry maps types to
  output file paths. Feature models get {theme}/{slug}/,
  shared types get types/{subsystem}/, theme-local types
  nest under their feature or sit flat at theme level
- type_collection: discover supplementary types (enums,
  NewTypes, sub-models) by walking expanded feature trees
- link_computation: relative_link() computes cross-page
  links, LinkContext holds page path + registry for
  resolving links during rendering

Signed-off-by: Seth Fitzsimmons <sethfitz@amazon.com>
Embed JSON example features in [tool.overture-schema.examples]
sections. Each example is a complete GeoJSON Feature matching
the theme's Pydantic model, used by the codegen example_loader
to render example tables in documentation.

Signed-off-by: Seth Fitzsimmons <sethfitz@amazon.com>
Jinja2 templates and rendering logic for documentation pages:

- markdown_renderer: orchestrates page rendering for features,
  enums, NewTypes, primitives, and geometry. Recursively expands
  MODEL-kind fields inline with dot-notation.
- markdown_type_format: type string formatting with link-aware
  rendering via LinkContext
- example_loader: loads examples from theme pyproject.toml,
  validates against Pydantic models, flattens to dot-notation
- reverse_references: computes "Used By" cross-references
  between types and the features that reference them

Templates: feature, enum, newtype, primitives, geometry pages.
Golden-file snapshot tests verify rendered output stability.

Adds renderer-specific fixtures to conftest.py (cli_runner,
primitives_markdown, geometry_markdown).

Signed-off-by: Seth Fitzsimmons <sethfitz@amazon.com>
Click-based CLI entry point (overture-codegen generate) that
wires discovery → extraction → output layout → rendering:

- Discovers models via discover_models() entry points
- Filters themes, extracts specs, builds placement registry
- Renders markdown pages with field tables, examples, cross-
  references, and sidebar metadata
- Supports --theme filtering and --output-dir targeting

Integration tests verify extraction against real Overture
models (Building, Division, Segment, etc.) to catch schema
drift. CLI tests verify end-to-end generation, output
structure, and link integrity.

Signed-off-by: Seth Fitzsimmons <sethfitz@amazon.com>
Design doc covers the four-layer architecture, analyze_type(),
domain-specific extractors, and extension points for new output
targets.

Walkthrough traces Segment through the full pipeline
module-by-module in dependency order, with FeatureVersion as a
secondary example for constraint provenance in the type analyzer.

README describes the problem (Pydantic flattens domain vocabulary),
the "unwrap once, render many" approach, CLI usage, architecture
overview, and programmatic API.

Signed-off-by: Seth Fitzsimmons <sethfitz@amazon.com>
TypeInfo.literal_value discarded multi-value Literals entirely
(Literal["a", "b"] got None). Renamed to literal_values as a
tuple of all args so consumers decide presentation.

single_literal_value() preserves its contract: returns the
value for single-arg Literals, None otherwise. Callers
(example_loader, union_extraction) are unchanged.

Multi-value Literals render as pipe-separated quoted values
in markdown tables: `"a"` \| `"b"`.

Signed-off-by: Seth Fitzsimmons <sethfitz@amazon.com>
John McCall (lowlydba) and others added 18 commits May 11, 2026 10:48
Signed-off-by: John McCall <john@overturemaps.org>
Signed-off-by: John McCall <john@overturemaps.org>
Add id-token: write permissions to workflows (.github/workflows/publish-python-packages.yaml and reusable-check-python-package-versions.yaml) so reusable workflows can use OIDC for AWS CodeArtifact authentication. Also add contents: read to the publish job. Update schema-pr-preview.yml to remove the PREVIEW_PATH env var and inline the /schema/pr/${{ github.event.number }} path for S3 sync and CloudFront invalidation to ensure the preview is uploaded and invalidated at the correct location.

Signed-off-by: John McCall <john@overturemaps.org>
Signed-off-by: John McCall <john@overturemaps.org>
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 7.0.0 to 7.0.1.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](actions/upload-artifact@bbbca2d...043fb46)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: 7.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: John McCall <john@overturemaps.org>
Bumps [marocchino/sticky-pull-request-comment](https://github.com/marocchino/sticky-pull-request-comment) from 3.0.3 to 3.0.4.
- [Release notes](https://github.com/marocchino/sticky-pull-request-comment/releases)
- [Commits](marocchino/sticky-pull-request-comment@d4d6b09...0ea0beb)

---
updated-dependencies:
- dependency-name: marocchino/sticky-pull-request-comment
  dependency-version: 3.0.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: John McCall <john@overturemaps.org>
Signed-off-by: John McCall <john@overturemaps.org>
Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 8.0.0 to 8.1.0.
- [Release notes](https://github.com/astral-sh/setup-uv/releases)
- [Commits](astral-sh/setup-uv@cec2083...0880764)

---
updated-dependencies:
- dependency-name: astral-sh/setup-uv
  dependency-version: 8.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps the actions group with 2 updates: [actions/github-script](https://github.com/actions/github-script) and [actions/setup-node](https://github.com/actions/setup-node).


Updates `actions/github-script` from 8.0.0 to 9.0.0
- [Release notes](https://github.com/actions/github-script/releases)
- [Commits](actions/github-script@ed59741...3a2844b)

Updates `actions/setup-node` from 6.3.0 to 6.4.0
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](actions/setup-node@53b8394...48b55a0)

---
updated-dependencies:
- dependency-name: actions/github-script
  dependency-version: 9.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: actions/setup-node
  dependency-version: 6.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
The check-python-code workflow now runs across the supported Python
minor versions (3.10-3.14), and adds a lowest-direct cell that re-
resolves every direct dependency to its declared floor before running
make check. Failures in that cell mean a declared minimum is wrong --
either the code uses a feature newer than the floor admits, or the
pin needs to be raised.

Setting UV_RESOLUTION=lowest-direct causes the existing make uv-sync
to re-resolve from the lockfile rather than follow it, so no separate
lock or constraints file is needed.

The declared floors lie about the actual minimums in several places.
Bump them to what the code requires today:

- pydantic >= 2.12: optionality.py imports
  pydantic.experimental.missing_sentinel, which only exists in 2.12+.
  feature.py imports ModelWrapValidatorHandler at the top level
  (re-exported in 2.10.4) and Tag (added in 2.5).
- ruff >= 0.13: 0.12.x still fires the deprecated UP038 rule under
  select = ["UP"], which the workspace config selects.
- deepdiff >= 8.6: first version shipping a py.typed marker, without
  which mypy errors on import-untyped.

Per-package dev deps that were unpinned (ruff, mypy, pytest in
overture-schema-cli and overture-schema-system; pyyaml, deepdiff in
overture-schema) now match the workspace dev-group floors. uv warns
about unpinned direct deps under lowest-direct resolution; pinning
silences the warnings and makes the floor explicit.

Signed-off-by: Seth Fitzsimmons <seth@mojodna.net>
Signed-off-by: jeffdefacto <jeffdefacto@gmail.com>
Signed-off-by: Seth Fitzsimmons <seth@mojodna.net>
Signed-off-by: Seth Fitzsimmons <seth@mojodna.net>
… staging

# Conflicts:
#	.github/workflows/publish-python-packages.yaml
#	.github/workflows/reusable-check-python-package-versions.yaml
#	.github/workflows/schema-pr-preview-cleanup.yml
#	.github/workflows/schema-pr-preview.yml
#	Makefile
#	PYDANTIC_GUIDE.md
#	README.pydantic.md
#	packages/overture-schema-addresses-theme/pyproject.toml
#	packages/overture-schema-annex/pyproject.toml
#	packages/overture-schema-base-theme/pyproject.toml
#	packages/overture-schema-buildings-theme/pyproject.toml
#	packages/overture-schema-cli/src/overture/schema/cli/commands.py
#	packages/overture-schema-cli/tests/test_resolve_types.py
#	packages/overture-schema-codegen/README.md
#	packages/overture-schema-codegen/docs/design.md
#	packages/overture-schema-codegen/docs/walkthrough.md
#	packages/overture-schema-codegen/pyproject.toml
#	packages/overture-schema-codegen/src/overture/schema/codegen/cli.py
#	packages/overture-schema-codegen/src/overture/schema/codegen/extraction/field_constraints.py
#	packages/overture-schema-codegen/tests/codegen_test_support.py
#	packages/overture-schema-codegen/tests/conftest.py
#	packages/overture-schema-codegen/tests/golden/markdown/venue.md
#	packages/overture-schema-codegen/tests/test_cli.py
#	packages/overture-schema-codegen/tests/test_constraint_description.py
#	packages/overture-schema-codegen/tests/test_integration_real_models.py
#	packages/overture-schema-codegen/tests/test_markdown_renderer.py
#	packages/overture-schema-codegen/tests/test_module_layout.py
#	packages/overture-schema-codegen/tests/test_type_placement.py
#	packages/overture-schema-core/README.md
#	packages/overture-schema-core/pyproject.toml
#	packages/overture-schema-core/src/overture/schema/core/__about__.py
#	packages/overture-schema-core/src/overture/schema/core/discovery.py
#	packages/overture-schema-divisions-theme/pyproject.toml
#	packages/overture-schema-divisions-theme/src/overture/schema/divisions/division.py
#	packages/overture-schema-divisions-theme/src/overture/schema/divisions/division_area.py
#	packages/overture-schema-divisions-theme/src/overture/schema/divisions/division_boundary.py
#	packages/overture-schema-places-theme/pyproject.toml
#	packages/overture-schema-system/README.md
#	packages/overture-schema-system/src/overture/schema/system/field_constraint/string.py
#	packages/overture-schema-system/src/overture/schema/system/ref/ref.py
#	packages/overture-schema-transportation-theme/pyproject.toml
#	packages/overture-schema/pyproject.toml
#	pyproject.toml
#	uv.lock

Signed-off-by: John McCall <john@overturemaps.org>
@github-actions
Copy link
Copy Markdown

🗺️ Schema reference docs preview is live!

🌍 Preview https://staging.overturemaps.org/schema/pr/528/schema/index.html
🕐 Updated May 18, 2026 15:35 UTC
📝 Commit 0345d95
🔧 env SCHEMA_PREVIEW true

Note

♻️ This preview updates automatically with each push to this PR.

@stepps00 Stephen Epps (stepps00) added change type - minor 🤏 Minor schema change. See https://lf-overturemaps.atlassian.net/wiki/x/GgDa release 🚀 labels May 18, 2026
@stepps00
Copy link
Copy Markdown
Contributor Author

Closing in preference of a new pull request that only includes commits with version updates.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

change type - minor 🤏 Minor schema change. See https://lf-overturemaps.atlassian.net/wiki/x/GgDa release 🚀

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Merge staging commits into main

6 participants