diff --git a/packages/overture-schema-base-theme/src/overture/schema/base/__init__.py b/packages/overture-schema-base-theme/src/overture/schema/base/__init__.py index 186016dbf..8034c6484 100644 --- a/packages/overture-schema-base-theme/src/overture/schema/base/__init__.py +++ b/packages/overture-schema-base-theme/src/overture/schema/base/__init__.py @@ -11,7 +11,6 @@ Depth, Elevation, Height, - SourcedFromOpenStreetMap, SourceTags, SurfaceMaterial, ) @@ -22,7 +21,6 @@ from .land_use import LandUse, LandUseClass, LandUseSubtype from .water import Water, WaterClass, WaterSubtype -# Only the theme's feature type classes should be available for `import *`. __all__ = [ "Bathymetry", "Depth", @@ -30,14 +28,15 @@ "Height", "Infrastructure", "InfrastructureClass", - "InfrastructureSubType", + "InfrastructureSubtype", "Land", "LandClass", "LandCover", "LandCoverSubtype", "LandSubtype", "LandUse", - "SourcedFromOpenStreetMap", + "LandUseClass", + "LandUseSubtype", "SourceTags", "SurfaceMaterial", "Water", diff --git a/packages/overture-schema-base-theme/tests/bathymetry_baseline_schema.json b/packages/overture-schema-base-theme/tests/bathymetry_baseline_schema.json index a36763e92..c7b14a349 100644 --- a/packages/overture-schema-base-theme/tests/bathymetry_baseline_schema.json +++ b/packages/overture-schema-base-theme/tests/bathymetry_baseline_schema.json @@ -214,7 +214,7 @@ "properties": { "cartography": { "$ref": "#/$defs/CartographicHints", - "title": "cartography" + "description": "Cartographic hints useful when including the feature in maps" }, "depth": { "description": "Depth below surface level of the feature in meters.", diff --git a/packages/overture-schema-base-theme/tests/infrastructure_baseline_schema.json b/packages/overture-schema-base-theme/tests/infrastructure_baseline_schema.json index 625a8fd17..c53570380 100644 --- a/packages/overture-schema-base-theme/tests/infrastructure_baseline_schema.json +++ b/packages/overture-schema-base-theme/tests/infrastructure_baseline_schema.json @@ -630,7 +630,8 @@ "type": "integer" }, "names": { - "$ref": "#/$defs/Names" + "$ref": "#/$defs/Names", + "description": "All known names by which the feature is called" }, "source_tags": { "additionalProperties": true, diff --git a/packages/overture-schema-base-theme/tests/land_baseline_schema.json b/packages/overture-schema-base-theme/tests/land_baseline_schema.json index b6df0a401..be1f6d780 100644 --- a/packages/overture-schema-base-theme/tests/land_baseline_schema.json +++ b/packages/overture-schema-base-theme/tests/land_baseline_schema.json @@ -505,7 +505,8 @@ "type": "integer" }, "names": { - "$ref": "#/$defs/Names" + "$ref": "#/$defs/Names", + "description": "All known names by which the feature is called" }, "source_tags": { "additionalProperties": true, diff --git a/packages/overture-schema-base-theme/tests/land_cover_baseline_schema.json b/packages/overture-schema-base-theme/tests/land_cover_baseline_schema.json index 79dea27fe..a104da44a 100644 --- a/packages/overture-schema-base-theme/tests/land_cover_baseline_schema.json +++ b/packages/overture-schema-base-theme/tests/land_cover_baseline_schema.json @@ -231,7 +231,7 @@ "properties": { "cartography": { "$ref": "#/$defs/CartographicHints", - "title": "cartography" + "description": "Cartographic hints useful when including the feature in maps" }, "sources": { "description": "Information about the source data used to assemble the feature.", diff --git a/packages/overture-schema-base-theme/tests/land_use_baseline_schema.json b/packages/overture-schema-base-theme/tests/land_use_baseline_schema.json index e1d461ece..c1ad6e97f 100644 --- a/packages/overture-schema-base-theme/tests/land_use_baseline_schema.json +++ b/packages/overture-schema-base-theme/tests/land_use_baseline_schema.json @@ -582,7 +582,8 @@ "type": "integer" }, "names": { - "$ref": "#/$defs/Names" + "$ref": "#/$defs/Names", + "description": "All known names by which the feature is called" }, "source_tags": { "additionalProperties": true, diff --git a/packages/overture-schema-base-theme/tests/water_baseline_schema.json b/packages/overture-schema-base-theme/tests/water_baseline_schema.json index b99811f95..fd78c6fb9 100644 --- a/packages/overture-schema-base-theme/tests/water_baseline_schema.json +++ b/packages/overture-schema-base-theme/tests/water_baseline_schema.json @@ -469,7 +469,8 @@ "type": "integer" }, "names": { - "$ref": "#/$defs/Names" + "$ref": "#/$defs/Names", + "description": "All known names by which the feature is called" }, "source_tags": { "additionalProperties": true, diff --git a/packages/overture-schema-buildings-theme/tests/building_baseline_schema.json b/packages/overture-schema-buildings-theme/tests/building_baseline_schema.json index ec4b34d32..31d563883 100644 --- a/packages/overture-schema-buildings-theme/tests/building_baseline_schema.json +++ b/packages/overture-schema-buildings-theme/tests/building_baseline_schema.json @@ -560,7 +560,8 @@ "type": "number" }, "names": { - "$ref": "#/$defs/Names" + "$ref": "#/$defs/Names", + "description": "All known names by which the feature is called" }, "num_floors": { "description": "Number of above-ground floors of the building or part.", diff --git a/packages/overture-schema-buildings-theme/tests/building_part_baseline_schema.json b/packages/overture-schema-buildings-theme/tests/building_part_baseline_schema.json index 0d22d8df2..760f53efd 100644 --- a/packages/overture-schema-buildings-theme/tests/building_part_baseline_schema.json +++ b/packages/overture-schema-buildings-theme/tests/building_part_baseline_schema.json @@ -444,7 +444,8 @@ "type": "number" }, "names": { - "$ref": "#/$defs/Names" + "$ref": "#/$defs/Names", + "description": "All known names by which the feature is called" }, "num_floors": { "description": "Number of above-ground floors of the building or part.", diff --git a/packages/overture-schema-codegen/tests/test_type_placement.py b/packages/overture-schema-codegen/tests/test_type_placement.py index 7e21a6a46..506a2afec 100644 --- a/packages/overture-schema-codegen/tests/test_type_placement.py +++ b/packages/overture-schema-codegen/tests/test_type_placement.py @@ -132,17 +132,6 @@ def test_supplementary_types_nested_under_types(self) -> None: "buildings/types/building_class.md" ) - def test_submodule_supplementary_types_nested_under_types(self) -> None: - """Supplementary types in a feature subdirectory go under types/.""" - specs = flat_specs_from_discovery("divisions") - registry, _ = _build_registry(specs) - - # AreaClass is from overture.schema.divisions.division_area.enums, - # a subdirectory of the divisions feature directory. - assert lookup_by_name(registry, "AreaClass") == PurePosixPath( - "divisions/types/division_area/area_class.md" - ) - def test_shared_types_not_nested(self) -> None: """Core/system supplementary types stay at their module-mirrored path.""" specs = flat_specs_from_discovery("buildings") diff --git a/packages/overture-schema-core/src/overture/schema/core/cartography.py b/packages/overture-schema-core/src/overture/schema/core/cartography.py index 1cc17a158..71cd60dbf 100644 --- a/packages/overture-schema-core/src/overture/schema/core/cartography.py +++ b/packages/overture-schema-core/src/overture/schema/core/cartography.py @@ -106,4 +106,9 @@ class CartographicallyHinted(BaseModel): Properties for adding cartographic hints to a model. """ - cartography: Annotated[CartographicHints | None, Field(title="cartography")] = None + cartography: Annotated[ + CartographicHints | None, + Field( + description="Cartographic hints useful when including the feature in maps" + ), + ] = None diff --git a/packages/overture-schema-core/src/overture/schema/core/names.py b/packages/overture-schema-core/src/overture/schema/core/names.py index aed77d985..631ec2d8d 100644 --- a/packages/overture-schema-core/src/overture/schema/core/names.py +++ b/packages/overture-schema-core/src/overture/schema/core/names.py @@ -224,4 +224,7 @@ class Names(BaseModel): class Named(BaseModel): """Properties defining the names of a model.""" - names: Names | None = None + names: Annotated[ + Names | None, + Field(description="All known names by which the feature is called"), + ] = None diff --git a/packages/overture-schema-divisions-theme/src/overture/schema/divisions/__init__.py b/packages/overture-schema-divisions-theme/src/overture/schema/divisions/__init__.py index ea08ff2e5..00e8cabc6 100644 --- a/packages/overture-schema-divisions-theme/src/overture/schema/divisions/__init__.py +++ b/packages/overture-schema-divisions-theme/src/overture/schema/divisions/__init__.py @@ -6,8 +6,23 @@ __path__ = __import__("pkgutil").extend_path(__path__, __name__) -from .division import Division -from .division_area import DivisionArea -from .division_boundary import DivisionBoundary +from ._common import AdminLevel, DivisionSubtype +from .division import CapitalOfDivisionItem, Division, DivisionClass, Norms +from .division_area import AreaClass, DivisionArea +from .division_boundary import BoundaryClass, DivisionBoundary -__all__ = ["Division", "DivisionArea", "DivisionBoundary"] +# Exclude from `__all__`: internal implementation details, and types that are effectively annotated +# primitives, such as `AdminLevel`, where a person working with one of the feature types likely +# would not need to import that type because they'll just set the field to a Python primitive value +# directly. (e.g., `my_division.admin_level = 4`). +__all__ = [ + "AreaClass", + "BoundaryClass", + "CapitalOfDivisionItem", + "Division", + "DivisionArea", + "DivisionClass", + "DivisionSubtype", + "DivisionBoundary", + "Norms", +] diff --git a/packages/overture-schema-divisions-theme/src/overture/schema/divisions/_common.py b/packages/overture-schema-divisions-theme/src/overture/schema/divisions/_common.py new file mode 100644 index 000000000..a2aaa9da0 --- /dev/null +++ b/packages/overture-schema-divisions-theme/src/overture/schema/divisions/_common.py @@ -0,0 +1,115 @@ +import textwrap +from typing import Annotated, NewType + +from pydantic import Field + +from overture.schema.system.doc import DocumentedEnum +from overture.schema.system.model_constraint import FieldEqCondition +from overture.schema.system.primitive import int32 + +AdminLevel = NewType( + "AdminLevel", + Annotated[ + int32, + Field( + description=textwrap.dedent(""" + Integer representing the division's position in its country's administrative + hierarchy, where lower numbers correspond to higher level administrative units. + """).strip(), + ge=0, + le=16, + ), + ], +) + + +class DivisionSubtype(str, DocumentedEnum): + """ + Category of the division from a finite, hierarchical, ordered list of categories (e.g., country, + region, locality, etc.) similar to a Who's on First placetype. + """ + + COUNTRY = ( + "country", + "Largest unit of independent sovereignty, e.g., the United States, France.", + ) + + DEPENDENCY = ( + "dependency", + textwrap.dedent(""" + A place that is not exactly a sub-region of a country but is dependent on a parent + country for defence, passport control, etc., e.g., Puerto Rico. + """).strip(), + ) + + MACROREGION = ( + "macroregion", + textwrap.dedent(""" + A bundle of regions, e.g., England, Scotland, Île-de-France. These exist mainly in + Europe. + """).strip(), + ) + + REGION = ( + "region", + textwrap.dedent(""" + A state, province, region, etc. Largest sub-country administrative unit in most + countries, except those that have dependencies or macro-regions. + """).strip(), + ) + + MACROCOUNTY = ( + "macrocounty", + "A bundle of counties, e.g. Inverness. These exist mainly in Europe.", + ) + + COUNTY = ( + "county", + textwrap.dedent(""" + Largest sub-region administrative unit in most countries, unless they have + macrocounties. + """).strip(), + ) + + LOCALADMIN = ( + "localadmin", + textwrap.dedent(""" + An administrative unit existing in some parts of the world that contains localities + or populated places, e.g. département de Paris. Often the contained places do not + have independent authority. Often, but not exclusively, found in Europe. + """).strip(), + ) + + LOCALITY = ( + "locality", + "A populated place that may or may not have its own administrative authority.", + ) + + BOROUGH = ( + "borough", + "A local government unit subordinate to a locality.", + ) + + MACROHOOD = ( + "macrohood", + textwrap.dedent(""" + A super-neighborhood that contains smaller divisions of type neighborhood, e.g. + BoCaCa (Boerum Hill, Cobble Hill, and Carroll Gardens). + """).strip(), + ) + + NEIGHBORHOOD = ( + "neighborhood", + textwrap.dedent(""" + A neighborhood. Most neighborhoods will be just this, unless there's enough granular + detail to justify introducing macrohood or microhood divisions. + """).strip(), + ) + + MICROHOOD = ( + "microhood", + "A mini-neighborhood that is contained within a division of type neighborhood.", + ) + + +IS_COUNTRY = FieldEqCondition("subtype", DivisionSubtype.COUNTRY) diff --git a/packages/overture-schema-divisions-theme/src/overture/schema/divisions/division.py b/packages/overture-schema-divisions-theme/src/overture/schema/divisions/division.py new file mode 100644 index 000000000..865caca4c --- /dev/null +++ b/packages/overture-schema-divisions-theme/src/overture/schema/divisions/division.py @@ -0,0 +1,418 @@ +""" +The `Division` feature type model and supporting types. +""" + +from __future__ import annotations + +import textwrap +from typing import Annotated, Literal, NewType + +from pydantic import BaseModel, ConfigDict, Field + +from overture.schema.core import ( + OvertureFeature, +) +from overture.schema.core.cartography import CartographicallyHinted +from overture.schema.core.models import ( + Perspectives, +) +from overture.schema.core.names import CommonNames, Named, Names +from overture.schema.core.scoping.side import Side +from overture.schema.system.doc import DocumentedEnum +from overture.schema.system.field_constraint import ( + UniqueItemsConstraint, +) +from overture.schema.system.model_constraint import ( + FieldEqCondition, + forbid_if, + no_extra_fields, + require_if, +) +from overture.schema.system.primitive import ( + Geometry, + GeometryType, + GeometryTypeConstraint, + int32, +) +from overture.schema.system.ref import Id, Reference, Relationship +from overture.schema.system.string import ( + CountryCodeAlpha2, + RegionCode, + StrippedString, + WikidataId, +) + +from ._common import ( + IS_COUNTRY, + AdminLevel, + DivisionSubtype, +) + + +@no_extra_fields +class Norms(BaseModel): + """Local norms and standards.""" + + # Optional + + driving_side: Annotated[ + Side | None, + Field( + description="Side of the road on which vehicles drive in the division.", + ), + ] = None + + +class DivisionClass(str, DocumentedEnum): + """ + Further classification of a division that is more specific than its `subtype`. + + A division's `class` adds detail to the broad classification found in `DivisionSubtype`. + """ + + MEGACITY = ( + "megacity", + textwrap.dedent(""" + A very large city or metropolitan area, typically having a population of 10 million or + more. Example: Tokyo, Japan. + """).strip(), + ) + + CITY = ( + "city", + "A large, permanent human settlement. Example: Guadalajara, Mexico.", + ) + + TOWN = ( + "town", + textwrap.dedent(""" + A medium-sized permanent human settlement that is smaller than a city, but larger than a + village. Example: Walldürn, Germany. + """).strip(), + ) + + VILLAGE = ( + "village", + textwrap.dedent(""" + A smallish permanent human settlement that is smaller than a town, but larger than a + hamlet. Example: Wadi El Karm, Lebanon. + """).strip(), + ) + + HAMLET = ( + "hamlet", + "A very small, isolated human settlement in a rural area. Example: Tjarnabyggð, Iceland.", + ) + + +@no_extra_fields +class CapitalOfDivisionItem(BaseModel): + """A division of which the owning division is the capital, together with its subtype.""" + + model_config = ConfigDict(frozen=True) + + # Required + + division_id: Annotated[ + Id, + Field(description="ID of the division whose capital is the current division."), + Reference(Relationship.CAPITAL_OF, Division), + ] + subtype: DivisionSubtype + + +@no_extra_fields +class HierarchyItem(BaseModel): + """One division in a hierarchy.""" + + model_config = ConfigDict(frozen=True) + + # Required + + division_id: Annotated[ + Id, + Field( + description=textwrap.dedent(""" + ID of a division that is an ancestor of the current division. + + In the context of division hierarchies, the ancestor divisions of a division include + the division itself, and any other division that is an ancestor of the division's parent. + """).strip() + ), + Reference(Relationship.DESCENDANT_OF, Division), + ] + subtype: DivisionSubtype + name: Annotated[ + StrippedString, Field(min_length=1, description="Primary name of the division") + ] + + +Hierarchy = NewType( + "Hierarchy", + Annotated[ + list[HierarchyItem], + Field( + min_length=1, + description=textwrap.dedent(""" + A hierarchy of divisions, with the first entry being a country; each subsequent + entry, if any, being a division that is a direct child of the previous entry; and + the last entry representing the division that contains the hierarchy. + + For example, a hierarchy for the United States is simply [United States]. A + hierarchy for the U.S. state of New Hampshire would be + [United States, New Hampshire], and a hierarchy for the city of Concord, NH would be + [United States, New Hampshire, Merrimack County, Concord]. + """).strip(), + ), + UniqueItemsConstraint(), + ], +) + + +@forbid_if(["parent_division_id"], IS_COUNTRY) +@require_if(["parent_division_id"], ~IS_COUNTRY) +@require_if(["admin_level"], FieldEqCondition("subtype", DivisionSubtype.COUNTRY)) +@require_if(["admin_level"], FieldEqCondition("subtype", DivisionSubtype.DEPENDENCY)) +@require_if(["admin_level"], FieldEqCondition("subtype", DivisionSubtype.MACROREGION)) +@require_if(["admin_level"], FieldEqCondition("subtype", DivisionSubtype.REGION)) +@require_if(["admin_level"], FieldEqCondition("subtype", DivisionSubtype.MACROCOUNTY)) +@require_if(["admin_level"], FieldEqCondition("subtype", DivisionSubtype.COUNTY)) +class Division( + OvertureFeature[Literal["divisions"], Literal["division"]], + Named, + CartographicallyHinted, +): + """ + Divisions are recognized official or non-official organizations of people as seen from a given + political perspective. + + Examples include countries, provinces, cities, towns, neighborhoods, etc. + """ + + model_config = ConfigDict(title="division") + + # Core + geometry: Annotated[ + Geometry, + GeometryTypeConstraint(GeometryType.POINT), + Field( + description=textwrap.dedent(""" + Approximate location of a position commonly associated with the real-world entity + modeled by the division feature. + """).strip(), + ), + ] + + # Required + + names: Annotated[ + Names, Field(description="All known names by which the division is called") + ] + subtype: Annotated[ + DivisionSubtype, + Field( + description=textwrap.dedent(""" + A broad classification of the division (e.g., country, region, locality, etc.). + """).strip() + ), + ] + country: Annotated[ + CountryCodeAlpha2, + Field( + description=textwrap.dedent(""" + ISO 3166-1 alpha-2 country code of the country or country-like entity, that this + division represents or belongs to. + + If the entity this division represents has a country code, the country property + contains it. If it does not, the country property contains the country code of the + first division encountered by traversing the parent_division_id chain to the root. + + For example: + - The country value for the United States is 'US' + - The country value for New York City is 'US' + - The country value for Puerto Rico, a dependency of the US, is 'PR'. + - The country value for San Juan, Puerto Rico is 'PR'. + + If an entity has an internationally-recognized ISO 3166-1 alpha-2 country code, it + should always be used. In cases where the schema requires the code but no + internationally-recognized code is available, a synthetic code may be used provided + it does not conflict with any internationally-recognized codes. + """).strip(), + ), + ] + hierarchies: Annotated[ + list[Hierarchy], + Field( + min_length=1, + description=textwrap.dedent(""" + Hierarchies in which this division participates. + + Every division participates in at least one hierarchy. Most participate in only one. + Some divisions may participate in more than one hierarchy, for example if they are + claimed by different parent divisions from different political perspectives; or if + there are other real-world reasons why the division or one of its ancestors has + multiple parents. + + The first hierarchy in the list is the default hierarchy, and the second-to-last + entry in the default hierarchy (if there is such an entry) always corresponds to the + `parent_division_id` property. The ordering of hierarchies after the first one is + arbitrary. + """).strip(), + ), + UniqueItemsConstraint(), + ] + parent_division_id: Annotated[ + Id | None, + Field( + description=textwrap.dedent(""" + Division ID of this division's parent division. + + Not allowed for top-level divisions (countries) and required for all other + divisions. + + The default parent division is the parent division as seen from the default + political perspective, if there is one, and is otherwise chosen somewhat + arbitrarily. The hierarchies property can be used to inspect the exhaustive list of + parent divisions. + """).strip() + ), + Reference(Relationship.CHILD_OF, Division), + ] = None + admin_level: AdminLevel | None = None + + # Optional + + class_: Annotated[ + DivisionClass | None, + Field( + alias="class", + description=textwrap.dedent(""" + A more specific classification of the division than is provided by `subtype`. + """).strip(), + ), + ] = None + local_type: Annotated[ + CommonNames | None, + Field( + description=textwrap.dedent(""" + Local name for the subtype property, optionally localized. + + For example, the Canadian province of Quebec has the subtype `"region"`, but in the + local administrative hierarchy it is referred to as a province. Similarly, the + Canadian Yukon territory also has subtype `"region"`, but is locally called a + territory. + + This property is localized using a standard Overture names structure. So for + example, in Switzerland the top-level administrative subdivision corresponding to + subtype 'region' is the canton, which may be translated in each of Switzerland's + official languages as, 'canton' in French, 'kanton' in German, 'cantone' in Italian, + and 'chantun' in Romansh. + """).strip(), + ), + ] = None + region: Annotated[ + RegionCode | None, + Field( + description=textwrap.dedent(""" + ISO 3166-2 principal subdivision code of the subdivision-like entity this division + represents or belongs to. + + If the entity this division represents has a principal subdivision code, the region + property contains it. If it does not, the region property contains the principal + subdivision code of the first division encountered by traversing the + `parent_division_id` chain to the root. + + For example: + - The region value for the United States is omitted. + - The region value for the U.S. state of New York is 'US-NY'. + - The region value for New York City is 'US-NY', which it inherits from the state + of New York. + - The region value for Puerto Rico is 'US-PR'. + """).strip(), + ), + ] = None + perspectives: Annotated[ + Perspectives | None, + Field( + description=textwrap.dedent(""" + Political perspectives from which this division is considered to be an accurate + representation. + + If this property is absent, then this division is not known to be disputed from + any political perspective. Consequently, there is only one division feature + representing the entire real world entity. + + If this property is present, it means the division represents one of several + alternative perspectives on the same real-world entity. + + There are two modes of perspective: + + 1. `accepted_by` means the representation of the division is accepted by the + listed entities and would be included on a map drawn from their perspective. + + 2. `disputed_by` means the representation of the division is disputed by the + listed entities and would be excluded from a map drawn from their perspective. + + When drawing a map from the perspective of a given country, one would start by + gathering all the undisputed divisions (with no `perspectives` property), and then + adding to that first all divisions explicitly accepted by the country, and second + all divisions not explicitly disputed by the country. + """).strip(), + ), + ] = None + # If we decide to include default language, it will go here. But is it really generally-useful information? + norms: Annotated[ + Norms | None, + Field( + description=textwrap.dedent(""" + Collects information about local norms and rules within the division that are + generally useful for mapping and map-related use cases. + + If the norms property or a desired sub-property of the norms property is missing + on a division, but at least one of its ancestor divisions has the norms property + and the desired sub-property, then the value from the nearest ancestor division + may be assumed. + """).strip(), + ), + ] = None + population: Annotated[ + int32 | None, Field(ge=0, description="Population of the division") + ] = None + capital_division_ids: Annotated[ + list[ + Annotated[ + Id, + Reference(Relationship.CAPITALLED_BY, Division), + ] + ] + | None, + Field( + min_length=1, + description=textwrap.dedent(""" + Division IDs of this division's capital divisions. If present, this property will + refer to the division IDs of the capital cities, county seats, etc. of a division. + """).strip(), + ), + UniqueItemsConstraint(), + ] = None + capital_of_divisions: Annotated[ + list[CapitalOfDivisionItem] | None, + Field( + min_length=1, + description="Division IDs and subtypes of divisions this division is a capital of.", + ), + UniqueItemsConstraint(), + ] = None + wikidata: WikidataId | None = None + + +# Materialize forward references to `Division`. +def __materialize_forward_refs(model_class: type[BaseModel]) -> None: + rebuilt: bool | None = model_class.model_rebuild() + assert rebuilt, ( + f"expected `{model_class.__name__}` to be rebuilt to materialize forward references to `{Division.__name__}`, but it wasn't" + ) + + +__materialize_forward_refs(CapitalOfDivisionItem) +__materialize_forward_refs(HierarchyItem) diff --git a/packages/overture-schema-divisions-theme/src/overture/schema/divisions/division/__init__.py b/packages/overture-schema-divisions-theme/src/overture/schema/divisions/division/__init__.py deleted file mode 100644 index e111fa7f8..000000000 --- a/packages/overture-schema-divisions-theme/src/overture/schema/divisions/division/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .models import Division - -__all__ = ["Division"] diff --git a/packages/overture-schema-divisions-theme/src/overture/schema/divisions/division/models.py b/packages/overture-schema-divisions-theme/src/overture/schema/divisions/division/models.py deleted file mode 100644 index a3ad0a5ca..000000000 --- a/packages/overture-schema-divisions-theme/src/overture/schema/divisions/division/models.py +++ /dev/null @@ -1,203 +0,0 @@ -"""Division models for Overture Maps divisions theme.""" - -from typing import Annotated, Literal - -from pydantic import BaseModel, ConfigDict, Field - -from overture.schema.core import ( - OvertureFeature, -) -from overture.schema.core.cartography import CartographicallyHinted -from overture.schema.core.models import ( - Perspectives, -) -from overture.schema.core.names import CommonNames, Named, Names -from overture.schema.core.scoping.side import Side -from overture.schema.system.field_constraint import ( - UniqueItemsConstraint, -) -from overture.schema.system.model_constraint import ( - FieldEqCondition, - forbid_if, - no_extra_fields, - require_if, -) -from overture.schema.system.primitive import ( - Geometry, - GeometryType, - GeometryTypeConstraint, - int32, -) -from overture.schema.system.ref import Id -from overture.schema.system.string import CountryCodeAlpha2, RegionCode, WikidataId - -from ..enums import IS_COUNTRY, DivisionClass, PlaceType -from ..models import CapitalOfDivisionItem -from ..types import AdminLevel, Hierarchy - - -@no_extra_fields -class Norms(BaseModel): - """Local norms and standards.""" - - # Optional - - driving_side: Annotated[ - Side | None, - Field( - description="Side of the road on which vehicles drive in the division.", - ), - ] = None - - -@forbid_if(["parent_division_id"], IS_COUNTRY) -@require_if(["parent_division_id"], ~IS_COUNTRY) -@require_if(["admin_level"], FieldEqCondition("subtype", PlaceType.COUNTRY)) -@require_if(["admin_level"], FieldEqCondition("subtype", PlaceType.DEPENDENCY)) -@require_if(["admin_level"], FieldEqCondition("subtype", PlaceType.MACROREGION)) -@require_if(["admin_level"], FieldEqCondition("subtype", PlaceType.REGION)) -@require_if(["admin_level"], FieldEqCondition("subtype", PlaceType.MACROCOUNTY)) -@require_if(["admin_level"], FieldEqCondition("subtype", PlaceType.COUNTY)) -class Division( - OvertureFeature[Literal["divisions"], Literal["division"]], - Named, - CartographicallyHinted, -): - """Divisions are recognized official or non-official organizations of people as seen - from a given political perspective. - - Examples include countries, provinces, cities, towns, neighborhoods, etc. - """ - - model_config = ConfigDict(title="division") - - # Core - geometry: Annotated[ - Geometry, - GeometryTypeConstraint(GeometryType.POINT), - Field( - description="""Approximate location of a position commonly associated with the real-world entity modeled by the division feature.""", - ), - ] - - # Required - - names: Names - subtype: PlaceType - country: Annotated[ - CountryCodeAlpha2, - Field( - description="""ISO 3166-1 alpha-2 country code of the country or country-like entity, that this division represents or belongs to. - -If the entity this division represents has a country code, the country property contains it. If it does not, the country property contains the country code of the first division encountered by traversing the parent_division_id chain to the root. - -For example: - - The country value for the United States is 'US' - - The country value for New York City is 'US' - - The country value for Puerto Rico, a dependency of the US, - is 'PR'. - - The country value for San Juan, Puerto Rico is 'PR'. - -If an entity has an internationally-recognized ISO 3166-1 alpha-2 country code, it should always be used. In cases where the schema requires the code but no internationally-recognized code is available, a synthetic code may be used provided it does not conflict with any internationally-recognized codes.""", - ), - ] - hierarchies: Annotated[ - list[Hierarchy], - Field( - min_length=1, - description="""Hierarchies in which this division participates. - -Every division participates in at least one hierarchy. Most participate in only one. Some divisions may participate in more than one hierarchy, for example if they are claimed by different parent divisions from different political perspectives; or if there are other real-world reasons why the division or one of its ancestors has multiple parents. - -The first hierarchy in the list is the default hierarchy, and the second-to-last entry in the default hierarchy (if there is such an entry) always corresponds to the `parent_division_id' property. The ordering of hierarchies after the first one is arbitrary.""", - ), - UniqueItemsConstraint(), - ] - parent_division_id: Annotated[ - Id | None, - Field( - min_length=1, - description="""Division ID of this division's parent division. - -Not allowed for top-level divisions (countries) and required for all other divisions. - -The default parent division is the parent division as seen from the default political perspective, if there is one, and is otherwise chosen somewhat arbitrarily. The hierarchies property can be used to inspect the exhaustive list of parent divisions.""", - ), - ] = None - admin_level: AdminLevel | None = None - - # Optional - - class_: Annotated[DivisionClass | None, Field(alias="class")] = None - local_type: Annotated[ - CommonNames | None, - Field( - description="""Local name for the subtype property, optionally localized. - -For example, the Canadian province of Quebec has the subtype 'region', but in the local administrative hierarchy it is referred to as a 'province'. Similarly, the Canadian Yukon territory also has subtype 'region', but is locally called a 'territory'. - -This property is localized using a standard Overture names structure. So for example, in Switzerland the top-level administrative subdivision corresponding to subtype 'region' is the canton, which is may be translated in each of Switzerland's official languages as, 'canton' in French, 'kanton' in German, 'cantone' in Italian, and 'chantun' in Romansh.""", - ), - ] = None - region: Annotated[ - RegionCode | None, - Field( - description="""ISO 3166-2 principal subdivision code of the subdivision-like entity this division represents or belongs to. - -If the entity this division represents has a principal subdivision code, the region property contains it. If it does not, the region property contains the principal subdivision code of the first division encountered by traversing the parent_division_id chain to the root. - -For example: - - The region value for the United States is omitted. - - The region value for the U.S. state of New York is 'US-NY'. - - The region value for New York City is 'US-NY', which it - inherits from the state of New York. - - The region value for Puerto Rico is 'US-PR'.""", - ), - ] = None - perspectives: Annotated[ - Perspectives | None, - Field( - description="""Political perspectives from which this division is considered to be an accurate representation. - -If this property is absent, then this division is not known to be disputed from any political perspective. Consequently, there is only one division feature representing the entire real world entity. - -If this property is present, it means the division represents one of several alternative perspectives on the same real-world entity. - -There are two modes of perspective: - -1. `accepted_by` means the representation of the division is accepted by the listed entities and would be included on a map drawn from their perspective. - -2. `disputed_by` means the representation of the division is disputed by the listed entities and would be excluded from a map drawn from their perspective. - -When drawing a map from the perspective of a given country, one would start by gathering all the undisputed divisions (with no `perspectives` property), and then adding to that first all divisions explicitly accepted by the country, and second all divisions not explicitly disputed by the country.""", - ), - ] = None - # If we decide to include default language, it will go here. But is it really generally-useful information? - norms: Annotated[ - Norms | None, - Field( - description="""Collects information about local norms and rules within the division that are generally useful for mapping and map-related use cases. - -If the norms property or a desired sub-property of the norms property is missing on a division, but at least one of its ancestor divisions has the norms property and the desired sub-property, then the value from the nearest ancestor division may be assumed.""", - ), - ] = None - population: Annotated[ - int32 | None, Field(ge=0, description="Population of the division") - ] = None - capital_division_ids: Annotated[ - list[Id] | None, - Field( - min_length=1, - description="""Division IDs of this division's capital divisions. If present, this property will refer to the division IDs of the capital cities, county seats, etc. of a division.""", - ), - UniqueItemsConstraint(), - ] = None - capital_of_divisions: Annotated[ - list[CapitalOfDivisionItem] | None, - Field( - min_length=1, - description="Division IDs and subtypes of divisions this division is a capital of.", - ), - UniqueItemsConstraint(), - ] = None - wikidata: WikidataId | None = None diff --git a/packages/overture-schema-divisions-theme/src/overture/schema/divisions/division_area.py b/packages/overture-schema-divisions-theme/src/overture/schema/divisions/division_area.py new file mode 100644 index 000000000..677906abb --- /dev/null +++ b/packages/overture-schema-divisions-theme/src/overture/schema/divisions/division_area.py @@ -0,0 +1,156 @@ +"""Division area models for Overture Maps divisions theme.""" + +import textwrap +from typing import Annotated, Literal + +from pydantic import ConfigDict, Field + +from overture.schema.core import ( + OvertureFeature, +) +from overture.schema.core.names import ( + Named, + Names, +) +from overture.schema.system.doc import DocumentedEnum +from overture.schema.system.model_constraint import ( + FieldEqCondition, + radio_group, + require_if, +) +from overture.schema.system.primitive import ( + Geometry, + GeometryType, + GeometryTypeConstraint, +) +from overture.schema.system.ref import Id, Reference, Relationship +from overture.schema.system.string import CountryCodeAlpha2, RegionCode + +from ._common import AdminLevel, DivisionSubtype +from .division import Division + + +class AreaClass(str, DocumentedEnum): + """ + Further classification of a division area that is more specific than its `subtype`. + + A division area's `class` adds detail to the broad classification found in `DivisionSubtype`. + """ + + LAND = ("land", "The area does not extend beyond the coastline.") + MARITIME = ( + "maritime", + textwrap.dedent(""" + The area extends beyond the coastline, in most cases to the extent of the division's + territorial sea, if it has one. + """).strip(), + ) + + +@require_if(["admin_level"], FieldEqCondition("subtype", DivisionSubtype.COUNTRY)) +@require_if(["admin_level"], FieldEqCondition("subtype", DivisionSubtype.DEPENDENCY)) +@require_if(["admin_level"], FieldEqCondition("subtype", DivisionSubtype.MACROREGION)) +@require_if(["admin_level"], FieldEqCondition("subtype", DivisionSubtype.REGION)) +@require_if(["admin_level"], FieldEqCondition("subtype", DivisionSubtype.MACROCOUNTY)) +@require_if(["admin_level"], FieldEqCondition("subtype", DivisionSubtype.COUNTY)) +@radio_group("is_land", "is_territorial") +class DivisionArea( + OvertureFeature[Literal["divisions"], Literal["division_area"]], Named +): + """ + Division areas are polygon features that represent the land or maritime area covered by a + division. + + Each division area belongs to a division which it references by ID, and for which the division + area provides an area polygon. For ease of use, every division area repeats the subtype, names, + country, and region properties of the division it belongs to. + """ + + model_config = ConfigDict(title="division_area") + + # Core + geometry: Annotated[ + Geometry, + GeometryTypeConstraint(GeometryType.POLYGON, GeometryType.MULTI_POLYGON), + Field( + description=textwrap.dedent(""" + The area covered by the division with which this area feature is + associated. + """).strip(), + ), + ] + + # Required + + names: Annotated[ + Names, + Field(description="All known names by which the owning division is called"), + ] + subtype: Annotated[ + DivisionSubtype, + Field( + description=textwrap.dedent(""" + A broad classification of the division this area belongs to (e.g., country, region, + locality, etc.). + + This value is the same as the owning division's `subtype`. + """).strip() + ), + ] + class_: Annotated[ + AreaClass, + Field( + alias="class", + description=textwrap.dedent(""" + A more specific classification of the division area than is provided by `subtype`. + """).strip(), + ), + ] + is_land: Annotated[ + bool | None, + Field( + description=textwrap.dedent(""" + Flag indicating whether or not the feature geometry represents the land-clipped, + non-maritime boundary. The geometry can be used for map rendering, cartographic + display, and similar purposes. + """).strip(), + strict=True, + ), + ] = None + is_territorial: Annotated[ + bool | None, + Field( + description=textwrap.dedent(""" + Flag indicating whether or not the feature geometry represents Overture's best + approximation of the division's territorial boundary. For coastal places, this will + tend to include the water area. The geometry can be used for data processing, + reverse-geocoding, and similar purposes. + """).strip(), + strict=True, + ), + ] = None + division_id: Annotated[ + Id, + Field( + description="Division ID of the division this area belongs to.", + ), + Reference(Relationship.BELONGS_TO, Division), + ] + country: Annotated[ + CountryCodeAlpha2, + Field( + description="ISO 3166-1 alpha-2 country code of the division this area belongs to.", + ), + ] + + # Optional + + region: Annotated[ + RegionCode | None, + Field( + description=textwrap.dedent(""" + ISO 3166-2 principal subdivision code of the division this area belongs to. + """).strip(), + ), + ] = None + admin_level: AdminLevel | None = None diff --git a/packages/overture-schema-divisions-theme/src/overture/schema/divisions/division_area/__init__.py b/packages/overture-schema-divisions-theme/src/overture/schema/divisions/division_area/__init__.py deleted file mode 100644 index e8f19fb17..000000000 --- a/packages/overture-schema-divisions-theme/src/overture/schema/divisions/division_area/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .models import DivisionArea - -__all__ = ["DivisionArea"] diff --git a/packages/overture-schema-divisions-theme/src/overture/schema/divisions/division_area/enums.py b/packages/overture-schema-divisions-theme/src/overture/schema/divisions/division_area/enums.py deleted file mode 100644 index a145d0a96..000000000 --- a/packages/overture-schema-divisions-theme/src/overture/schema/divisions/division_area/enums.py +++ /dev/null @@ -1,8 +0,0 @@ -from enum import Enum - - -class AreaClass(str, Enum): - """Area and boundary class designations.""" - - LAND = "land" # The area does not extend beyond the coastline. - MARITIME = "maritime" # The area extends beyond the coastline, in most cases to the extent of the division's territorial sea, if it has one. diff --git a/packages/overture-schema-divisions-theme/src/overture/schema/divisions/division_area/models.py b/packages/overture-schema-divisions-theme/src/overture/schema/divisions/division_area/models.py deleted file mode 100644 index 06b38bb68..000000000 --- a/packages/overture-schema-divisions-theme/src/overture/schema/divisions/division_area/models.py +++ /dev/null @@ -1,107 +0,0 @@ -"""Division area models for Overture Maps divisions theme.""" - -from typing import Annotated, Literal - -from pydantic import ConfigDict, Field - -from overture.schema.core import ( - OvertureFeature, -) -from overture.schema.core.names import ( - Named, - Names, -) -from overture.schema.system.model_constraint import ( - FieldEqCondition, - radio_group, - require_if, -) -from overture.schema.system.primitive import ( - Geometry, - GeometryType, - GeometryTypeConstraint, -) -from overture.schema.system.ref import Id, Reference, Relationship -from overture.schema.system.string import CountryCodeAlpha2, RegionCode - -from ..division.models import Division -from ..enums import PlaceType -from ..types import AdminLevel -from .enums import AreaClass - - -@require_if(["admin_level"], FieldEqCondition("subtype", PlaceType.COUNTRY)) -@require_if(["admin_level"], FieldEqCondition("subtype", PlaceType.DEPENDENCY)) -@require_if(["admin_level"], FieldEqCondition("subtype", PlaceType.MACROREGION)) -@require_if(["admin_level"], FieldEqCondition("subtype", PlaceType.REGION)) -@require_if(["admin_level"], FieldEqCondition("subtype", PlaceType.MACROCOUNTY)) -@require_if(["admin_level"], FieldEqCondition("subtype", PlaceType.COUNTY)) -@radio_group("is_land", "is_territorial") -class DivisionArea( - OvertureFeature[Literal["divisions"], Literal["division_area"]], Named -): - """Division areas are polygons that represent the land or maritime area covered by a - division. - - Each division area belongs to a division which it references by ID, and for which - the division area provides an area polygon. For ease of use, every division area - repeats the subtype, names, country, and region properties of the division it - belongs to. - """ - - model_config = ConfigDict(title="division_area") - - # Core - geometry: Annotated[ - Geometry, - GeometryTypeConstraint(GeometryType.POLYGON, GeometryType.MULTI_POLYGON), - Field( - description="The area covered by the division with which this area feature is associated", - ), - ] - - # Required - - names: Names - subtype: PlaceType - class_: Annotated[ - AreaClass, - Field(alias="class"), - ] - is_land: Annotated[ - bool | None, - Field( - description="""A boolean to indicate whether or not the feature geometry represents the land-clipped, non-maritime boundary. The geometry can be used for map rendering, cartographic display, and similar purposes.""", - strict=True, - ), - ] = None - is_territorial: Annotated[ - bool | None, - Field( - description="""A boolean to indicate whether or not the feature geometry represents Overture's best approximation of this place's maritime boundary. For coastal places, this would tend to include the water area. The geometry can be used for data processing, reverse-geocoding, and similar purposes.""", - strict=True, - ), - ] = None - division_id: Annotated[ - Id, - Field( - description="Division ID of the division this area belongs to.", - ), - Reference(Relationship.BELONGS_TO, Division), - ] - country: Annotated[ - CountryCodeAlpha2, - Field( - description="ISO 3166-1 alpha-2 country code of the division this area belongs to.", - ), - ] - - # Optional - - region: Annotated[ - RegionCode | None, - Field( - description="ISO 3166-2 principal subdivision code of the division this area belongs to.", - ), - ] = None - admin_level: AdminLevel | None = None diff --git a/packages/overture-schema-divisions-theme/src/overture/schema/divisions/division_boundary.py b/packages/overture-schema-divisions-theme/src/overture/schema/divisions/division_boundary.py new file mode 100644 index 000000000..0fcf751f9 --- /dev/null +++ b/packages/overture-schema-divisions-theme/src/overture/schema/divisions/division_boundary.py @@ -0,0 +1,219 @@ +"""Division boundary models for Overture Maps divisions theme.""" + +import textwrap +from typing import Annotated, Literal + +from pydantic import ConfigDict, Field + +from overture.schema.core import ( + OvertureFeature, +) +from overture.schema.core.models import Perspectives +from overture.schema.system.doc import DocumentedEnum +from overture.schema.system.field_constraint import UniqueItemsConstraint +from overture.schema.system.model_constraint import ( + FieldEqCondition, + forbid_if, + radio_group, + require_if, +) +from overture.schema.system.primitive import ( + Geometry, + GeometryType, + GeometryTypeConstraint, +) +from overture.schema.system.ref import Id, Reference, Relationship +from overture.schema.system.string import CountryCodeAlpha2, RegionCode + +from ._common import IS_COUNTRY, AdminLevel, DivisionSubtype +from .division import Division + + +class BoundaryClass(str, DocumentedEnum): + """ + The kind of boundary: land or maritime. + """ + + LAND = ( + "land", + textwrap.dedent(""" + None of the boundary geometry extends beyond the coastline of either associated + division. + """).strip(), + ) + MARITIME = ( + "maritime", + textwrap.dedent(""" + All the boundary geometry extends beyond the coastline of both associated divisions. + """).strip(), + ) + + +@forbid_if(["country"], IS_COUNTRY) +@require_if(["country"], ~IS_COUNTRY) +@require_if(["admin_level"], FieldEqCondition("subtype", DivisionSubtype.COUNTRY)) +@require_if(["admin_level"], FieldEqCondition("subtype", DivisionSubtype.DEPENDENCY)) +@require_if(["admin_level"], FieldEqCondition("subtype", DivisionSubtype.MACROREGION)) +@require_if(["admin_level"], FieldEqCondition("subtype", DivisionSubtype.REGION)) +@require_if(["admin_level"], FieldEqCondition("subtype", DivisionSubtype.MACROCOUNTY)) +@require_if(["admin_level"], FieldEqCondition("subtype", DivisionSubtype.COUNTY)) +@radio_group("is_land", "is_territorial") +class DivisionBoundary( + OvertureFeature[Literal["divisions"], Literal["division_boundary"]] +): + """ + Boundaries represent borders between divisions of the same subtype. + + Some boundaries may be disputed by the divisions on one or both sides. + """ + + model_config = ConfigDict(title="boundary") + + # Core + geometry: Annotated[ + Geometry, + GeometryTypeConstraint( + GeometryType.LINE_STRING, GeometryType.MULTI_LINE_STRING + ), + Field( + description="Boundary line or lines", + ), + ] + + # Required + + subtype: Annotated[ + DivisionSubtype, + Field( + description=textwrap.dedent(""" + A broad classification of the divisions this boundary separates (e.g., country, + region, locality, etc.). + """).strip() + ), + ] + class_: Annotated[ + BoundaryClass, + Field( + alias="class", + description="The kind of boundary: land or maritime.", + ), + ] + is_land: Annotated[ + bool | None, + Field( + description=textwrap.dedent(""" + Flag indicating whether or not the feature geometry represents the land-clipped, + non-maritime boundary. The geometry can be used for map rendering, cartographic + display, and similar purposes. + """).strip(), + strict=True, + ), + ] = None + is_territorial: Annotated[ + bool | None, + Field( + description=textwrap.dedent(""" + Flag indicating whether or not the feature geometry represents Overture's best + approximation of the division's territorial boundary. For coastal places, this will + tend to include the water area. The geometry can be used for data processing, + reverse-geocoding, and similar purposes. + """).strip(), + strict=True, + ), + ] = None + division_ids: Annotated[ + list[ + Annotated[ + Id, + Reference(Relationship.BOUNDARY_OF, Division), + ] + ], + Field( + min_length=2, + max_length=2, + description=textwrap.dedent(""" + Identifies the two divisions to the left and right, respectively, of the + boundary line. The left- and right-hand sides of the boundary are considered + from the perspective of a person standing on the line facing in the direction + in which the geometry is oriented, i.e. facing toward the end of the line. + + The first array element is the Overture ID of the left division. The second + element is the Overture ID of the right division. + """).strip(), + ), + UniqueItemsConstraint(), + ] + country: Annotated[ + CountryCodeAlpha2 | None, + Field( + description=textwrap.dedent(""" + ISO 3166-1 alpha-2 country code of the country or country-like entity that + both sides of the boundary share. + + This property will be present on boundaries between two regions, counties, + or similar entities within the same country, but will not be present on + boundaries between two countries or country-like entities. + """).strip(), + ), + ] = None + + # Optional + + region: Annotated[ + RegionCode | None, + Field( + description=textwrap.dedent(""" + ISO 3166-2 principal subdivision code of the subdivision-like entity that + both sides of the boundary share. + + This property will be present on boundaries between two counties, localadmins + or similar entities within the same principal subdivision, but will not be + present on boundaries between different principal subdivisions or countries. + """).strip(), + ), + ] = None + admin_level: AdminLevel | None = None + is_disputed: Annotated[ + bool | None, + Field( + description=textwrap.dedent(""" + Flag indicating whether this boundary is either disputed outright or is a "best + guess" in a case where the boundary between two divisions is unclear. + + If the boundary is disputed outright, this flag is true and the entities disputing + it are listed in the `perspectives` property. If the boundary is simply a "best + guess", this flag is true but no disputing entities are listed in `perspectives`. + """).strip(), + strict=True, + ), + ] = None + perspectives: Annotated[ + Perspectives | None, + Field( + description=textwrap.dedent(""" + Political perspectives from which this division boundary is considered to be + an accurate representation. + + If this property is absent, then this boundary is not known to be disputed + from any political perspective. Consequently, there is only one boundary + feature representing the entire real world entity. + + If this property is present, it means the boundary represents one of several + alternative perspectives on the same real-world entity. + + There are two modes of perspective: + + 1. `accepted_by` means the representation of the boundary is accepted by the + listed entities and would be included on a map drawn from their perspective. + + 2. `disputed_by` means the representation of the boundary is disputed by the + listed entities and would be excluded from a map drawn from their + perspective. + + When drawing a map from the perspective of a given country, one would start by + gathering all the undisputed boundaries (those with no `perspectives` value); and + then adding to that: first, all boundaries explicitly accepted by the country, and + second, all boundaries not explicitly disputed by the country. + """).strip(), + ), + ] = None diff --git a/packages/overture-schema-divisions-theme/src/overture/schema/divisions/division_boundary/__init__.py b/packages/overture-schema-divisions-theme/src/overture/schema/divisions/division_boundary/__init__.py deleted file mode 100644 index 877a778af..000000000 --- a/packages/overture-schema-divisions-theme/src/overture/schema/divisions/division_boundary/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .models import DivisionBoundary - -__all__ = ["DivisionBoundary"] diff --git a/packages/overture-schema-divisions-theme/src/overture/schema/divisions/division_boundary/enums.py b/packages/overture-schema-divisions-theme/src/overture/schema/divisions/division_boundary/enums.py deleted file mode 100644 index 08fb0ba14..000000000 --- a/packages/overture-schema-divisions-theme/src/overture/schema/divisions/division_boundary/enums.py +++ /dev/null @@ -1,11 +0,0 @@ -from enum import Enum - - -class BoundaryClass(str, Enum): - # None of the boundary geometry extends beyond the - # coastline of either associated division. - LAND = "land" - - # All the boundary geometry extends beyond the - # coastline of both associated divisions. - MARITIME = "maritime" diff --git a/packages/overture-schema-divisions-theme/src/overture/schema/divisions/division_boundary/models.py b/packages/overture-schema-divisions-theme/src/overture/schema/divisions/division_boundary/models.py deleted file mode 100644 index 86ea6e7cf..000000000 --- a/packages/overture-schema-divisions-theme/src/overture/schema/divisions/division_boundary/models.py +++ /dev/null @@ -1,157 +0,0 @@ -"""Division boundary models for Overture Maps divisions theme.""" - -from typing import Annotated, Literal - -from pydantic import ConfigDict, Field - -from overture.schema.core import ( - OvertureFeature, -) -from overture.schema.core.models import Perspectives -from overture.schema.system.field_constraint import UniqueItemsConstraint -from overture.schema.system.model_constraint import ( - FieldEqCondition, - forbid_if, - radio_group, - require_if, -) -from overture.schema.system.primitive import ( - Geometry, - GeometryType, - GeometryTypeConstraint, -) -from overture.schema.system.ref import Id, Reference, Relationship -from overture.schema.system.string import CountryCodeAlpha2, RegionCode - -from ..division import Division -from ..enums import IS_COUNTRY, PlaceType -from ..types import AdminLevel -from .enums import BoundaryClass - - -@forbid_if(["country"], IS_COUNTRY) -@require_if(["country"], ~IS_COUNTRY) -@require_if(["admin_level"], FieldEqCondition("subtype", PlaceType.COUNTRY)) -@require_if(["admin_level"], FieldEqCondition("subtype", PlaceType.DEPENDENCY)) -@require_if(["admin_level"], FieldEqCondition("subtype", PlaceType.MACROREGION)) -@require_if(["admin_level"], FieldEqCondition("subtype", PlaceType.REGION)) -@require_if(["admin_level"], FieldEqCondition("subtype", PlaceType.MACROCOUNTY)) -@require_if(["admin_level"], FieldEqCondition("subtype", PlaceType.COUNTY)) -@radio_group("is_land", "is_territorial") -class DivisionBoundary( - OvertureFeature[Literal["divisions"], Literal["division_boundary"]] -): - """Boundaries represent borders between divisions of the same subtype. - - Some boundaries may be disputed by the divisions on one or both sides. - """ - - model_config = ConfigDict(title="boundary") - - # Core - geometry: Annotated[ - Geometry, - GeometryTypeConstraint( - GeometryType.LINE_STRING, GeometryType.MULTI_LINE_STRING - ), - Field( - description="Boundary line or lines", - ), - ] - - # Required - - subtype: PlaceType - class_: Annotated[BoundaryClass, Field(alias="class")] - is_land: Annotated[ - bool | None, - Field( - description="""A boolean to indicate whether or not the feature geometry represents the -land-clipped, non-maritime boundary. The geometry can be used for map -rendering, cartographic display, and similar purposes.""", - strict=True, - ), - ] = None - is_territorial: Annotated[ - bool | None, - Field( - description="""A boolean to indicate whether or not the feature geometry represents -Overture's best approximation of this place's maritime boundary. For -coastal places, this would tend to include the water area. The geometry -can be used for data processing, reverse-geocoding, and similar purposes.""", - strict=True, - ), - ] = None - division_ids: Annotated[ - list[ - Annotated[ - Id, - Reference(Relationship.BOUNDARY_OF, Division), - ] - ], - Field( - min_length=2, - max_length=2, - description="""Identifies the two divisions to the left and right, respectively, of the boundary line. The left- and right-hand sides of the boundary are considered from the perspective of a person standing on the line facing in the direction in which the geometry is oriented, i.e. facing toward the end of the line. - -The first array element is the Overture ID of the left division. The second element is the Overture ID of the right division.""", - ), - UniqueItemsConstraint(), - ] - country: Annotated[ - CountryCodeAlpha2 | None, - Field( - description="""ISO 3166-1 alpha-2 country code of the country or country-like -entity that both sides of the boundary share. - -This property will be present on boundaries between two regions, counties, -or similar entities within the same country, but will not be present on boundaries -between two countries or country-like entities.""", - ), - ] = None - - # Optional - - region: Annotated[ - RegionCode | None, - Field( - description="""ISO 3166-2 principal subdivision code of the subdivision-like -entity that both sides of the boundary share. - -This property will be present on boundaries between two counties, localadmins -or similar entities within the same principal subdivision, but will not be -present on boundaries between different principal subdivisions or countries.""", - ), - ] = None - admin_level: AdminLevel | None = None - is_disputed: Annotated[ - bool | None, - Field( - description="""Indicator if there are entities disputing this division boundary. -Information about entities disputing this boundary should be included in perspectives -property. - -This property should also be true if boundary between two entities is unclear -and this is "best guess". So having it true and no perspectives gives map creators -reason not to fully trust the boundary, but use it if they have no other.""", - strict=True, - ), - ] = None - perspectives: Annotated[ - Perspectives | None, - Field( - description="""Political perspectives from which this division boundary is considered to be an accurate representation. - -If this property is absent, then this boundary is not known to be disputed from any political perspective. Consequently, there is only one boundary feature representing the entire real world entity. - -If this property is present, it means the boundary represents one of several alternative perspectives on the same real-world entity. - -There are two modes of perspective: - - 1. `accepted_by` means the representation of the boundary is accepted by the listed entities and would be included on a map drawn from their perspective. - - 2. `disputed_by` means the representation of the boundary is disputed by the listed entities and would be excluded from a map drawn from their perspective. - -When drawing a map from the perspective of a given country, one would start by gathering all the undisputed boundary (with no `perspectives` property), and then adding to that first all boundary explicitly accepted by the country, and second all boundary not explicitly disputed by the country.""", - ), - ] = None diff --git a/packages/overture-schema-divisions-theme/src/overture/schema/divisions/enums.py b/packages/overture-schema-divisions-theme/src/overture/schema/divisions/enums.py deleted file mode 100644 index 8634f0f5c..000000000 --- a/packages/overture-schema-divisions-theme/src/overture/schema/divisions/enums.py +++ /dev/null @@ -1,80 +0,0 @@ -from enum import Enum - -from overture.schema.system.model_constraint import FieldEqCondition - - -class PlaceType(str, Enum): - """ - Category of the division from a finite, hierarchical, ordered list of categories (e.g., country, - region, locality, etc.) similar to a Who's on First placetype. - """ - - # Largest unit of independent sovereignty, e.g. the United States, France. - COUNTRY = "country" - - # A place that is not exactly a sub-region of a country but is dependent on a parent country for - # defence, passport control, etc., e.g. Puerto Rico. - DEPENDENCY = "dependency" - - # A bundle of regions, e.g. England, Scotland, Île-de-France. These exist mainly in Europe. - MACROREGION = "macroregion" - - # A state, province, region, etc. Largest sub-country administrative unit in most countries, - # except those that have dependencies or macro-regions. - REGION = "region" - - # A bundle of counties, e.g. Inverness. These exist mainly in Europe. - MACROCOUNTY = "macrocounty" - - # Largest sub-region administrative unit in most countries, unless they have macrocounties. - COUNTY = "county" - - # An administrative unit existing in some parts of the world that contains localities or - # populated places, e.g. département de Paris. Often the contained places do not have - # independent authority. Often, but not exclusively, found in Europe. - LOCALADMIN = "localadmin" - - # A populated place that may or may not have its own administrative authority. - LOCALITY = "locality" - - # A local government unit subordinate to a locality. - BOROUGH = "borough" - - # A super-neighborhood that contains smaller divisions of type neighborhood, e.g. BoCaCa (Boerum - # Hill, Cobble Hill, and Carroll Gardens). - MACROHOOD = "macrohood" - - # A neighborhood. Most neighborhoods will be just this, unless there's enough granular detail to - # justify incroducing macrohood or microhood divisions. - NEIGHBORHOOD = "neighborhood" - - # A mini-neighborhood that is contained within a division of type neighborhood. - MICROHOOD = "microhood" - - -class DivisionClass(str, Enum): - """Division-specific class designations.""" - - # A extensive, large human settlement. - # Example: Tokyo, Japan. - MEGACITY = "megacity" - - # A relatively large, permanent human settlement. - # Example: Guadalajara, Mexico. - CITY = "city" - - # A medium-sized human settlement that is smaller than a city, but larger than a village. - # Example: Walldürn, Germany. - TOWN = "town" - - # A smaller human settlement that is smaller than a town, but larger than a hamlet. - # Example: Wadi El Karm, Lebanon. - VILLAGE = "village" - - # A small, isolated human settlement in a rural area - # Example: Tjarnabyggð, Iceland. - HAMLET = "hamlet" - - -# TODO - vic - Migrate this into a better home -IS_COUNTRY = FieldEqCondition("subtype", PlaceType.COUNTRY) diff --git a/packages/overture-schema-divisions-theme/src/overture/schema/divisions/models.py b/packages/overture-schema-divisions-theme/src/overture/schema/divisions/models.py deleted file mode 100644 index 4f43e4965..000000000 --- a/packages/overture-schema-divisions-theme/src/overture/schema/divisions/models.py +++ /dev/null @@ -1,39 +0,0 @@ -from typing import Annotated, NewType - -from pydantic import BaseModel, ConfigDict, Field - -from overture.schema.divisions.enums import PlaceType -from overture.schema.system.model_constraint import no_extra_fields -from overture.schema.system.ref import Id -from overture.schema.system.string import StrippedString - -DivisionId = NewType( - "DivisionId", Annotated[Id, Field(min_length=1, description="ID of the division")] -) - - -@no_extra_fields -class HierarchyItem(BaseModel): - """One division in a hierarchy.""" - - model_config = ConfigDict(frozen=True) - - # Required - - division_id: DivisionId - subtype: PlaceType - name: Annotated[ - StrippedString, Field(min_length=1, description="Primary name of the division") - ] - - -@no_extra_fields -class CapitalOfDivisionItem(BaseModel): - """One division that has capital.""" - - model_config = ConfigDict(frozen=True) - - # Required - - division_id: DivisionId - subtype: PlaceType diff --git a/packages/overture-schema-divisions-theme/src/overture/schema/divisions/types.py b/packages/overture-schema-divisions-theme/src/overture/schema/divisions/types.py deleted file mode 100644 index 699bfc9ac..000000000 --- a/packages/overture-schema-divisions-theme/src/overture/schema/divisions/types.py +++ /dev/null @@ -1,34 +0,0 @@ -from typing import Annotated, NewType - -from pydantic import Field - -from overture.schema.system.field_constraint import UniqueItemsConstraint -from overture.schema.system.primitive import int32 - -from .models import HierarchyItem - -AdminLevel = NewType( - "AdminLevel", - Annotated[ - int32, - Field( - description="Integer representing the division's position in its country's administrative hierarchy, where lower numbers correspond to higher level administrative units.", - ge=0, - le=16, - ), - ], -) - -Hierarchy = NewType( - "Hierarchy", - Annotated[ - list[HierarchyItem], - Field( - min_length=1, - description="""A hierarchy of divisions, with the first entry being a country; each subsequent entry, if any, being a division that is a direct child of the previous entry; and the last entry representing the division that contains the hierarchy. - -For example, a hierarchy for the United States is simply [United States]. A hierarchy for the U.S. state of New Hampshire would be [United States, New Hampshire], and a hierarchy for the city of Concord, NH would be [United States, New Hampshire, Merrimack County, Concord].""", - ), - UniqueItemsConstraint(), - ], -) diff --git a/packages/overture-schema-divisions-theme/tests/division_area_baseline_schema.json b/packages/overture-schema-divisions-theme/tests/division_area_baseline_schema.json index a3d2084d0..8f800c551 100644 --- a/packages/overture-schema-divisions-theme/tests/division_area_baseline_schema.json +++ b/packages/overture-schema-divisions-theme/tests/division_area_baseline_schema.json @@ -1,7 +1,7 @@ { "$defs": { "AreaClass": { - "description": "Area and boundary class designations.", + "description": "Further classification of a division area that is more specific than its `subtype`.\n\nA division area's `class` adds detail to the broad classification found in `DivisionSubtype`.", "enum": [ "land", "maritime" @@ -9,6 +9,25 @@ "title": "AreaClass", "type": "string" }, + "DivisionSubtype": { + "description": "Category of the division from a finite, hierarchical, ordered list of categories (e.g., country,\nregion, locality, etc.) similar to a Who's on First placetype.", + "enum": [ + "country", + "dependency", + "macroregion", + "region", + "macrocounty", + "county", + "localadmin", + "locality", + "borough", + "macrohood", + "neighborhood", + "microhood" + ], + "title": "DivisionSubtype", + "type": "string" + }, "NameRule": { "additionalProperties": false, "description": "A rule that can be evaluated to determine the name in advanced scenarios.\n\nName rules are used for cases where the primary name is not sufficient; the common name is not\nthe right fit for the use case and another variant is needed; or where the name only applies in\ncertain specific circumstances.\n\nExamples might include:\n- An official, alternate, or short name.\n- A name that only applies to part of a linear path like a road segment (geometric range\n scoping).\n- A name that only applies to the left or right side of a linear path like a road segment (side\n scoping).\n- A name that is only accepted by some political perspectives.", @@ -149,25 +168,6 @@ "title": "Perspectives", "type": "object" }, - "PlaceType": { - "description": "Category of the division from a finite, hierarchical, ordered list of categories (e.g., country,\nregion, locality, etc.) similar to a Who's on First placetype.", - "enum": [ - "country", - "dependency", - "macroregion", - "region", - "macrocounty", - "county", - "localadmin", - "locality", - "borough", - "macrohood", - "neighborhood", - "microhood" - ], - "title": "PlaceType", - "type": "string" - }, "Side": { "description": "The side, left or right, on which something appears relative to a facing or heading direction\n(*e.g.*, the side of a road relative to the road orientation), or relative to the direction of\ntravel of a person or vehicle.", "enum": [ @@ -237,7 +237,7 @@ } }, "additionalProperties": false, - "description": "Division areas are polygons that represent the land or maritime area covered by a\ndivision.\n\nEach division area belongs to a division which it references by ID, and for which\nthe division area provides an area polygon. For ease of use, every division area\nrepeats the subtype, names, country, and region properties of the division it\nbelongs to.", + "description": "Division areas are polygon features that represent the land or maritime area covered by a\ndivision.\n\nEach division area belongs to a division which it references by ID, and for which the division\narea provides an area polygon. For ease of use, every division area repeats the subtype, names,\ncountry, and region properties of the division it belongs to.", "properties": { "bbox": { "description": "An optional bounding box for the feature", @@ -250,7 +250,7 @@ "type": "array" }, "geometry": { - "description": "The area covered by the division with which this area feature is associated", + "description": "The area covered by the division with which this area feature is\nassociated.", "oneOf": [ { "properties": { @@ -498,14 +498,15 @@ }, "properties": { "admin_level": { - "description": "Integer representing the division's position in its country's administrative hierarchy, where lower numbers correspond to higher level administrative units.", + "description": "Integer representing the division's position in its country's administrative\nhierarchy, where lower numbers correspond to higher level administrative units.", "maximum": 16, "minimum": 0, "title": "Admin Level", "type": "integer" }, "class": { - "$ref": "#/$defs/AreaClass" + "$ref": "#/$defs/AreaClass", + "description": "A more specific classification of the division area than is provided by `subtype`." }, "country": { "description": "ISO 3166-1 alpha-2 country code of the division this area belongs to.", @@ -523,17 +524,18 @@ "type": "string" }, "is_land": { - "description": "A boolean to indicate whether or not the feature geometry represents the land-clipped, non-maritime boundary. The geometry can be used for map rendering, cartographic display, and similar purposes.", + "description": "Flag indicating whether or not the feature geometry represents the land-clipped,\nnon-maritime boundary. The geometry can be used for map rendering, cartographic\ndisplay, and similar purposes.", "title": "Is Land", "type": "boolean" }, "is_territorial": { - "description": "A boolean to indicate whether or not the feature geometry represents Overture's best approximation of this place's maritime boundary. For coastal places, this would tend to include the water area. The geometry can be used for data processing, reverse-geocoding, and similar purposes.", + "description": "Flag indicating whether or not the feature geometry represents Overture's best\napproximation of the division's territorial boundary. For coastal places, this will\ntend to include the water area. The geometry can be used for data processing,\nreverse-geocoding, and similar purposes.", "title": "Is Territorial", "type": "boolean" }, "names": { - "$ref": "#/$defs/Names" + "$ref": "#/$defs/Names", + "description": "All known names by which the owning division is called" }, "region": { "description": "ISO 3166-2 principal subdivision code of the division this area belongs to.", @@ -554,7 +556,8 @@ "uniqueItems": true }, "subtype": { - "$ref": "#/$defs/PlaceType" + "$ref": "#/$defs/DivisionSubtype", + "description": "A broad classification of the division this area belongs to (e.g., country, region,\nlocality, etc.).\n\nThis value is the same as the owning division's `subtype`." }, "theme": { "const": "divisions", diff --git a/packages/overture-schema-divisions-theme/tests/division_baseline_schema.json b/packages/overture-schema-divisions-theme/tests/division_baseline_schema.json index 5c55f88dc..8097ee0df 100644 --- a/packages/overture-schema-divisions-theme/tests/division_baseline_schema.json +++ b/packages/overture-schema-divisions-theme/tests/division_baseline_schema.json @@ -2,17 +2,17 @@ "$defs": { "CapitalOfDivisionItem": { "additionalProperties": false, - "description": "One division that has capital.", + "description": "A division of which the owning division is the capital, together with its subtype.", "properties": { "division_id": { - "description": "ID of the division", + "description": "ID of the division whose capital is the current division.", "minLength": 1, "pattern": "^\\S+$", "title": "Division Id", "type": "string" }, "subtype": { - "$ref": "#/$defs/PlaceType" + "$ref": "#/$defs/DivisionSubtype" } }, "required": [ @@ -59,7 +59,7 @@ "type": "object" }, "DivisionClass": { - "description": "Division-specific class designations.", + "description": "Further classification of a division that is more specific than its `subtype`.\n\nA division's `class` adds detail to the broad classification found in `DivisionSubtype`.", "enum": [ "megacity", "city", @@ -70,12 +70,31 @@ "title": "DivisionClass", "type": "string" }, + "DivisionSubtype": { + "description": "Category of the division from a finite, hierarchical, ordered list of categories (e.g., country,\nregion, locality, etc.) similar to a Who's on First placetype.", + "enum": [ + "country", + "dependency", + "macroregion", + "region", + "macrocounty", + "county", + "localadmin", + "locality", + "borough", + "macrohood", + "neighborhood", + "microhood" + ], + "title": "DivisionSubtype", + "type": "string" + }, "HierarchyItem": { "additionalProperties": false, "description": "One division in a hierarchy.", "properties": { "division_id": { - "description": "ID of the division", + "description": "ID of a division that is an ancestor of the current division.\n\nIn the context of division hierarchies, the ancestor divisions of a division include\nthe division itself, and any other division that is an ancestor of the division's parent.", "minLength": 1, "pattern": "^\\S+$", "title": "Division Id", @@ -89,7 +108,7 @@ "type": "string" }, "subtype": { - "$ref": "#/$defs/PlaceType" + "$ref": "#/$defs/DivisionSubtype" } }, "required": [ @@ -252,25 +271,6 @@ "title": "Perspectives", "type": "object" }, - "PlaceType": { - "description": "Category of the division from a finite, hierarchical, ordered list of categories (e.g., country,\nregion, locality, etc.) similar to a Who's on First placetype.", - "enum": [ - "country", - "dependency", - "macroregion", - "region", - "macrocounty", - "county", - "localadmin", - "locality", - "borough", - "macrohood", - "neighborhood", - "microhood" - ], - "title": "PlaceType", - "type": "string" - }, "Side": { "description": "The side, left or right, on which something appears relative to a facing or heading direction\n(*e.g.*, the side of a road relative to the road orientation), or relative to the direction of\ntravel of a person or vehicle.", "enum": [ @@ -340,7 +340,7 @@ } }, "additionalProperties": false, - "description": "Divisions are recognized official or non-official organizations of people as seen\nfrom a given political perspective.\n\nExamples include countries, provinces, cities, towns, neighborhoods, etc.", + "description": "Divisions are recognized official or non-official organizations of people as seen from a given\npolitical perspective.\n\nExamples include countries, provinces, cities, towns, neighborhoods, etc.", "properties": { "bbox": { "description": "An optional bounding box for the feature", @@ -353,7 +353,7 @@ "type": "array" }, "geometry": { - "description": "Approximate location of a position commonly associated with the real-world entity modeled by the division feature.", + "description": "Approximate location of a position commonly associated with the real-world entity\nmodeled by the division feature.", "properties": { "bbox": { "items": { @@ -579,14 +579,14 @@ }, "properties": { "admin_level": { - "description": "Integer representing the division's position in its country's administrative hierarchy, where lower numbers correspond to higher level administrative units.", + "description": "Integer representing the division's position in its country's administrative\nhierarchy, where lower numbers correspond to higher level administrative units.", "maximum": 16, "minimum": 0, "title": "Admin Level", "type": "integer" }, "capital_division_ids": { - "description": "Division IDs of this division's capital divisions. If present, this property will refer to the division IDs of the capital cities, county seats, etc. of a division.", + "description": "Division IDs of this division's capital divisions. If present, this property will\nrefer to the division IDs of the capital cities, county seats, etc. of a division.", "items": { "description": "A unique identifier", "minLength": 1, @@ -610,13 +610,14 @@ }, "cartography": { "$ref": "#/$defs/CartographicHints", - "title": "cartography" + "description": "Cartographic hints useful when including the feature in maps" }, "class": { - "$ref": "#/$defs/DivisionClass" + "$ref": "#/$defs/DivisionClass", + "description": "A more specific classification of the division than is provided by `subtype`." }, "country": { - "description": "ISO 3166-1 alpha-2 country code of the country or country-like entity, that this division represents or belongs to.\n\nIf the entity this division represents has a country code, the country property contains it. If it does not, the country property contains the country code of the first division encountered by traversing the parent_division_id chain to the root.\n\nFor example:\n - The country value for the United States is 'US'\n - The country value for New York City is 'US'\n - The country value for Puerto Rico, a dependency of the US,\n is 'PR'.\n - The country value for San Juan, Puerto Rico is 'PR'.\n\nIf an entity has an internationally-recognized ISO 3166-1 alpha-2 country code, it should always be used. In cases where the schema requires the code but no internationally-recognized code is available, a synthetic code may be used provided it does not conflict with any internationally-recognized codes.", + "description": "ISO 3166-1 alpha-2 country code of the country or country-like entity, that this\ndivision represents or belongs to.\n\nIf the entity this division represents has a country code, the country property\ncontains it. If it does not, the country property contains the country code of the\nfirst division encountered by traversing the parent_division_id chain to the root.\n\nFor example:\n- The country value for the United States is 'US'\n- The country value for New York City is 'US'\n- The country value for Puerto Rico, a dependency of the US, is 'PR'.\n- The country value for San Juan, Puerto Rico is 'PR'.\n\nIf an entity has an internationally-recognized ISO 3166-1 alpha-2 country code, it\nshould always be used. In cases where the schema requires the code but no\ninternationally-recognized code is available, a synthetic code may be used provided\nit does not conflict with any internationally-recognized codes.", "maxLength": 2, "minLength": 2, "pattern": "^[A-Z]{2}$", @@ -624,9 +625,9 @@ "type": "string" }, "hierarchies": { - "description": "Hierarchies in which this division participates.\n\nEvery division participates in at least one hierarchy. Most participate in only one. Some divisions may participate in more than one hierarchy, for example if they are claimed by different parent divisions from different political perspectives; or if there are other real-world reasons why the division or one of its ancestors has multiple parents.\n\nThe first hierarchy in the list is the default hierarchy, and the second-to-last entry in the default hierarchy (if there is such an entry) always corresponds to the `parent_division_id' property. The ordering of hierarchies after the first one is arbitrary.", + "description": "Hierarchies in which this division participates.\n\nEvery division participates in at least one hierarchy. Most participate in only one.\nSome divisions may participate in more than one hierarchy, for example if they are\nclaimed by different parent divisions from different political perspectives; or if\nthere are other real-world reasons why the division or one of its ancestors has\nmultiple parents.\n\nThe first hierarchy in the list is the default hierarchy, and the second-to-last\nentry in the default hierarchy (if there is such an entry) always corresponds to the\n`parent_division_id` property. The ordering of hierarchies after the first one is\narbitrary.", "items": { - "description": "A hierarchy of divisions, with the first entry being a country; each subsequent entry, if any, being a division that is a direct child of the previous entry; and the last entry representing the division that contains the hierarchy.\n\nFor example, a hierarchy for the United States is simply [United States]. A hierarchy for the U.S. state of New Hampshire would be [United States, New Hampshire], and a hierarchy for the city of Concord, NH would be [United States, New Hampshire, Merrimack County, Concord].", + "description": "A hierarchy of divisions, with the first entry being a country; each subsequent\nentry, if any, being a division that is a direct child of the previous entry; and\nthe last entry representing the division that contains the hierarchy.\n\nFor example, a hierarchy for the United States is simply [United States]. A\nhierarchy for the U.S. state of New Hampshire would be\n[United States, New Hampshire], and a hierarchy for the city of Concord, NH would be\n[United States, New Hampshire, Merrimack County, Concord].", "items": { "$ref": "#/$defs/HierarchyItem" }, @@ -641,7 +642,7 @@ }, "local_type": { "additionalProperties": false, - "description": "Local name for the subtype property, optionally localized.\n\nFor example, the Canadian province of Quebec has the subtype 'region', but in the local administrative hierarchy it is referred to as a 'province'. Similarly, the Canadian Yukon territory also has subtype 'region', but is locally called a 'territory'.\n\nThis property is localized using a standard Overture names structure. So for example, in Switzerland the top-level administrative subdivision corresponding to subtype 'region' is the canton, which is may be translated in each of Switzerland's official languages as, 'canton' in French, 'kanton' in German, 'cantone' in Italian, and 'chantun' in Romansh.", + "description": "Local name for the subtype property, optionally localized.\n\nFor example, the Canadian province of Quebec has the subtype `\"region\"`, but in the\nlocal administrative hierarchy it is referred to as a province. Similarly, the\nCanadian Yukon territory also has subtype `\"region\"`, but is locally called a\nterritory.\n\nThis property is localized using a standard Overture names structure. So for\nexample, in Switzerland the top-level administrative subdivision corresponding to\nsubtype 'region' is the canton, which may be translated in each of Switzerland's\nofficial languages as, 'canton' in French, 'kanton' in German, 'cantone' in Italian,\nand 'chantun' in Romansh.", "patternProperties": { "^(?:(?:[A-Za-z]{2,3}(?:-[A-Za-z]{3}){0,3}?)|(?:[A-Za-z]{4,8}))(?:-[A-Za-z]{4})?(?:-[A-Za-z]{2}|[0-9]{3})?(?:-(?:[A-Za-z0-9]{5,8}|[0-9][A-Za-z0-9]{3}))*(?:-[A-WY-Za-wy-z0-9](?:-[A-Za-z0-9]{2,8})+)*$": { "description": "String with no leading/trailing whitespace", @@ -656,14 +657,15 @@ "type": "object" }, "names": { - "$ref": "#/$defs/Names" + "$ref": "#/$defs/Names", + "description": "All known names by which the division is called" }, "norms": { "$ref": "#/$defs/Norms", - "description": "Collects information about local norms and rules within the division that are generally useful for mapping and map-related use cases.\n\nIf the norms property or a desired sub-property of the norms property is missing on a division, but at least one of its ancestor divisions has the norms property and the desired sub-property, then the value from the nearest ancestor division may be assumed." + "description": "Collects information about local norms and rules within the division that are\ngenerally useful for mapping and map-related use cases.\n\nIf the norms property or a desired sub-property of the norms property is missing\non a division, but at least one of its ancestor divisions has the norms property\nand the desired sub-property, then the value from the nearest ancestor division\nmay be assumed." }, "parent_division_id": { - "description": "Division ID of this division's parent division.\n\nNot allowed for top-level divisions (countries) and required for all other divisions.\n\nThe default parent division is the parent division as seen from the default political perspective, if there is one, and is otherwise chosen somewhat arbitrarily. The hierarchies property can be used to inspect the exhaustive list of parent divisions.", + "description": "Division ID of this division's parent division.\n\nNot allowed for top-level divisions (countries) and required for all other\ndivisions.\n\nThe default parent division is the parent division as seen from the default\npolitical perspective, if there is one, and is otherwise chosen somewhat\narbitrarily. The hierarchies property can be used to inspect the exhaustive list of\nparent divisions.", "minLength": 1, "pattern": "^\\S+$", "title": "Parent Division Id", @@ -671,7 +673,7 @@ }, "perspectives": { "$ref": "#/$defs/Perspectives", - "description": "Political perspectives from which this division is considered to be an accurate representation.\n\nIf this property is absent, then this division is not known to be disputed from any political perspective. Consequently, there is only one division feature representing the entire real world entity.\n\nIf this property is present, it means the division represents one of several alternative perspectives on the same real-world entity.\n\nThere are two modes of perspective:\n\n1. `accepted_by` means the representation of the division is accepted by the listed entities and would be included on a map drawn from their perspective.\n\n2. `disputed_by` means the representation of the division is disputed by the listed entities and would be excluded from a map drawn from their perspective.\n\nWhen drawing a map from the perspective of a given country, one would start by gathering all the undisputed divisions (with no `perspectives` property), and then adding to that first all divisions explicitly accepted by the country, and second all divisions not explicitly disputed by the country." + "description": "Political perspectives from which this division is considered to be an accurate\nrepresentation.\n\nIf this property is absent, then this division is not known to be disputed from\nany political perspective. Consequently, there is only one division feature\nrepresenting the entire real world entity.\n\nIf this property is present, it means the division represents one of several\nalternative perspectives on the same real-world entity.\n\nThere are two modes of perspective:\n\n1. `accepted_by` means the representation of the division is accepted by the\n listed entities and would be included on a map drawn from their perspective.\n\n2. `disputed_by` means the representation of the division is disputed by the\n listed entities and would be excluded from a map drawn from their perspective.\n\nWhen drawing a map from the perspective of a given country, one would start by\ngathering all the undisputed divisions (with no `perspectives` property), and then\nadding to that first all divisions explicitly accepted by the country, and second\nall divisions not explicitly disputed by the country." }, "population": { "description": "Population of the division", @@ -681,7 +683,7 @@ "type": "integer" }, "region": { - "description": "ISO 3166-2 principal subdivision code of the subdivision-like entity this division represents or belongs to.\n\nIf the entity this division represents has a principal subdivision code, the region property contains it. If it does not, the region property contains the principal subdivision code of the first division encountered by traversing the parent_division_id chain to the root.\n\nFor example:\n - The region value for the United States is omitted.\n - The region value for the U.S. state of New York is 'US-NY'.\n - The region value for New York City is 'US-NY', which it\n inherits from the state of New York.\n - The region value for Puerto Rico is 'US-PR'.", + "description": "ISO 3166-2 principal subdivision code of the subdivision-like entity this division\nrepresents or belongs to.\n\nIf the entity this division represents has a principal subdivision code, the region\nproperty contains it. If it does not, the region property contains the principal\nsubdivision code of the first division encountered by traversing the\n`parent_division_id` chain to the root.\n\nFor example:\n- The region value for the United States is omitted.\n- The region value for the U.S. state of New York is 'US-NY'.\n- The region value for New York City is 'US-NY', which it inherits from the state\n of New York.\n- The region value for Puerto Rico is 'US-PR'.", "maxLength": 6, "minLength": 4, "pattern": "^[A-Z]{2}-[A-Z0-9]{1,3}$", @@ -699,7 +701,8 @@ "uniqueItems": true }, "subtype": { - "$ref": "#/$defs/PlaceType" + "$ref": "#/$defs/DivisionSubtype", + "description": "A broad classification of the division (e.g., country, region, locality, etc.)." }, "theme": { "const": "divisions", diff --git a/packages/overture-schema-divisions-theme/tests/division_boundary_baseline_schema.json b/packages/overture-schema-divisions-theme/tests/division_boundary_baseline_schema.json index 4d9efb412..82b9b38b9 100644 --- a/packages/overture-schema-divisions-theme/tests/division_boundary_baseline_schema.json +++ b/packages/overture-schema-divisions-theme/tests/division_boundary_baseline_schema.json @@ -1,6 +1,7 @@ { "$defs": { "BoundaryClass": { + "description": "The kind of boundary: land or maritime.", "enum": [ "land", "maritime" @@ -8,6 +9,25 @@ "title": "BoundaryClass", "type": "string" }, + "DivisionSubtype": { + "description": "Category of the division from a finite, hierarchical, ordered list of categories (e.g., country,\nregion, locality, etc.) similar to a Who's on First placetype.", + "enum": [ + "country", + "dependency", + "macroregion", + "region", + "macrocounty", + "county", + "localadmin", + "locality", + "borough", + "macrohood", + "neighborhood", + "microhood" + ], + "title": "DivisionSubtype", + "type": "string" + }, "PerspectiveMode": { "description": "Perspective mode for disputed names.", "enum": [ @@ -47,25 +67,6 @@ "title": "Perspectives", "type": "object" }, - "PlaceType": { - "description": "Category of the division from a finite, hierarchical, ordered list of categories (e.g., country,\nregion, locality, etc.) similar to a Who's on First placetype.", - "enum": [ - "country", - "dependency", - "macroregion", - "region", - "macrocounty", - "county", - "localadmin", - "locality", - "borough", - "macrohood", - "neighborhood", - "microhood" - ], - "title": "PlaceType", - "type": "string" - }, "SourceItem": { "additionalProperties": false, "description": "Specifies the source of the data used for a feature or one of its properties.", @@ -425,7 +426,7 @@ }, "properties": { "admin_level": { - "description": "Integer representing the division's position in its country's administrative hierarchy, where lower numbers correspond to higher level administrative units.", + "description": "Integer representing the division's position in its country's administrative\nhierarchy, where lower numbers correspond to higher level administrative units.", "maximum": 16, "minimum": 0, "title": "Admin Level", @@ -435,7 +436,7 @@ "$ref": "#/$defs/BoundaryClass" }, "country": { - "description": "ISO 3166-1 alpha-2 country code of the country or country-like\nentity that both sides of the boundary share.\n\nThis property will be present on boundaries between two regions, counties,\nor similar entities within the same country, but will not be present on boundaries\nbetween two countries or country-like entities.", + "description": "ISO 3166-1 alpha-2 country code of the country or country-like entity that\nboth sides of the boundary share.\n\nThis property will be present on boundaries between two regions, counties,\nor similar entities within the same country, but will not be present on\nboundaries between two countries or country-like entities.", "maxLength": 2, "minLength": 2, "pattern": "^[A-Z]{2}$", @@ -443,7 +444,7 @@ "type": "string" }, "division_ids": { - "description": "Identifies the two divisions to the left and right, respectively, of the boundary line. The left- and right-hand sides of the boundary are considered from the perspective of a person standing on the line facing in the direction in which the geometry is oriented, i.e. facing toward the end of the line.\n\nThe first array element is the Overture ID of the left division. The second element is the Overture ID of the right division.", + "description": "Identifies the two divisions to the left and right, respectively, of the\nboundary line. The left- and right-hand sides of the boundary are considered\nfrom the perspective of a person standing on the line facing in the direction\nin which the geometry is oriented, i.e. facing toward the end of the line.\n\nThe first array element is the Overture ID of the left division. The second\nelement is the Overture ID of the right division.", "items": { "description": "A unique identifier", "minLength": 1, @@ -457,26 +458,26 @@ "uniqueItems": true }, "is_disputed": { - "description": "Indicator if there are entities disputing this division boundary.\nInformation about entities disputing this boundary should be included in perspectives\nproperty.\n\nThis property should also be true if boundary between two entities is unclear\nand this is \"best guess\". So having it true and no perspectives gives map creators\nreason not to fully trust the boundary, but use it if they have no other.", + "description": "Flag indicating whether this boundary is either disputed outright or is a \"best\nguess\" in a case where the boundary between two divisions is unclear.\n\nIf the boundary is disputed outright, this flag is true and the entities disputing\nit are listed in the `perspectives` property. If the boundary is simply a \"best\nguess\", this flag is true but no disputing entities are listed in `perspectives`.", "title": "Is Disputed", "type": "boolean" }, "is_land": { - "description": "A boolean to indicate whether or not the feature geometry represents the\nland-clipped, non-maritime boundary. The geometry can be used for map\nrendering, cartographic display, and similar purposes.", + "description": "Flag indicating whether or not the feature geometry represents the land-clipped,\nnon-maritime boundary. The geometry can be used for map rendering, cartographic\ndisplay, and similar purposes.", "title": "Is Land", "type": "boolean" }, "is_territorial": { - "description": "A boolean to indicate whether or not the feature geometry represents\nOverture's best approximation of this place's maritime boundary. For\ncoastal places, this would tend to include the water area. The geometry\ncan be used for data processing, reverse-geocoding, and similar purposes.", + "description": "Flag indicating whether or not the feature geometry represents Overture's best\napproximation of the division's territorial boundary. For coastal places, this will\ntend to include the water area. The geometry can be used for data processing,\nreverse-geocoding, and similar purposes.", "title": "Is Territorial", "type": "boolean" }, "perspectives": { "$ref": "#/$defs/Perspectives", - "description": "Political perspectives from which this division boundary is considered to be an accurate representation.\n\nIf this property is absent, then this boundary is not known to be disputed from any political perspective. Consequently, there is only one boundary feature representing the entire real world entity.\n\nIf this property is present, it means the boundary represents one of several alternative perspectives on the same real-world entity.\n\nThere are two modes of perspective:\n\n 1. `accepted_by` means the representation of the boundary is accepted by the listed entities and would be included on a map drawn from their perspective.\n\n 2. `disputed_by` means the representation of the boundary is disputed by the listed entities and would be excluded from a map drawn from their perspective.\n\nWhen drawing a map from the perspective of a given country, one would start by gathering all the undisputed boundary (with no `perspectives` property), and then adding to that first all boundary explicitly accepted by the country, and second all boundary not explicitly disputed by the country." + "description": "Political perspectives from which this division boundary is considered to be\nan accurate representation.\n\nIf this property is absent, then this boundary is not known to be disputed\nfrom any political perspective. Consequently, there is only one boundary\nfeature representing the entire real world entity.\n\nIf this property is present, it means the boundary represents one of several\nalternative perspectives on the same real-world entity.\n\nThere are two modes of perspective:\n\n1. `accepted_by` means the representation of the boundary is accepted by the\n listed entities and would be included on a map drawn from their perspective.\n\n2. `disputed_by` means the representation of the boundary is disputed by the\n listed entities and would be excluded from a map drawn from their\n perspective.\n\nWhen drawing a map from the perspective of a given country, one would start by\ngathering all the undisputed boundaries (those with no `perspectives` value); and\nthen adding to that: first, all boundaries explicitly accepted by the country, and\nsecond, all boundaries not explicitly disputed by the country." }, "region": { - "description": "ISO 3166-2 principal subdivision code of the subdivision-like\nentity that both sides of the boundary share.\n\nThis property will be present on boundaries between two counties, localadmins\nor similar entities within the same principal subdivision, but will not be\npresent on boundaries between different principal subdivisions or countries.", + "description": "ISO 3166-2 principal subdivision code of the subdivision-like entity that\nboth sides of the boundary share.\n\nThis property will be present on boundaries between two counties, localadmins\nor similar entities within the same principal subdivision, but will not be\npresent on boundaries between different principal subdivisions or countries.", "maxLength": 6, "minLength": 4, "pattern": "^[A-Z]{2}-[A-Z0-9]{1,3}$", @@ -494,7 +495,8 @@ "uniqueItems": true }, "subtype": { - "$ref": "#/$defs/PlaceType" + "$ref": "#/$defs/DivisionSubtype", + "description": "A broad classification of the divisions this boundary separates (e.g., country,\nregion, locality, etc.)." }, "theme": { "const": "divisions", diff --git a/packages/overture-schema-places-theme/tests/place_baseline_schema.json b/packages/overture-schema-places-theme/tests/place_baseline_schema.json index 6f862f4ed..a9e0c3620 100644 --- a/packages/overture-schema-places-theme/tests/place_baseline_schema.json +++ b/packages/overture-schema-places-theme/tests/place_baseline_schema.json @@ -44,7 +44,8 @@ "description": "A brand associated with a place.\n\nA location with multiple brands is modeled as multiple separate places, each with its own brand.", "properties": { "names": { - "$ref": "#/$defs/Names" + "$ref": "#/$defs/Names", + "description": "All known names by which the feature is called" }, "wikidata": { "description": "Wikidata identifier (Q followed by digits)", @@ -450,7 +451,8 @@ "uniqueItems": true }, "names": { - "$ref": "#/$defs/Names" + "$ref": "#/$defs/Names", + "description": "All known names by which the feature is called" }, "operating_status": { "$ref": "#/$defs/OperatingStatus", diff --git a/packages/overture-schema-system/src/overture/schema/system/ref/ref.py b/packages/overture-schema-system/src/overture/schema/system/ref/ref.py index 86c8d19d6..ff712104b 100644 --- a/packages/overture-schema-system/src/overture/schema/system/ref/ref.py +++ b/packages/overture-schema-system/src/overture/schema/system/ref/ref.py @@ -23,7 +23,14 @@ def __init__(self, value: str, doc: str) -> None: BELONGS_TO = "belongs_to", "The relator belongs to the relatee" BOUNDARY_OF = "boundary_of", "The relator is a boundary of the relatee" + CAPITAL_OF = "capital_of", "The relator is a capital of the relatee" + CAPITALLED_BY = "capitalled_by", "The relator has the relatee as its capital" + CHILD_OF = "child_of", "The relator is a child of the relatee" CONNECTS_TO = "connects_to", "The relator connects to the relatee" + DESCENDANT_OF = ( + "descendant_of", + "The relator is a hierarchical descendant of the relatee", + ) @dataclass(frozen=True, slots=True) diff --git a/packages/overture-schema-transportation-theme/tests/segment_baseline_schema.json b/packages/overture-schema-transportation-theme/tests/segment_baseline_schema.json index 1ff6ba934..4ec108313 100644 --- a/packages/overture-schema-transportation-theme/tests/segment_baseline_schema.json +++ b/packages/overture-schema-transportation-theme/tests/segment_baseline_schema.json @@ -619,7 +619,8 @@ "type": "array" }, "names": { - "$ref": "#/$defs/Names" + "$ref": "#/$defs/Names", + "description": "All known names by which the feature is called" }, "rail_flags": { "description": "Set of boolean attributes applicable to railways. May be specified either as a single flag array of flag values, or as an array of flag rules.", @@ -896,7 +897,8 @@ "type": "array" }, "names": { - "$ref": "#/$defs/Names" + "$ref": "#/$defs/Names", + "description": "All known names by which the feature is called" }, "prohibited_transitions": { "description": "Rules preventing transitions from this segment to another segment.", @@ -1625,7 +1627,8 @@ "type": "array" }, "names": { - "$ref": "#/$defs/Names" + "$ref": "#/$defs/Names", + "description": "All known names by which the feature is called" }, "routes": { "description": "Routes this segment belongs to",