overture-schema-common 0.1.1.dev0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (24) hide show
  1. overture_schema_common-0.1.1.dev0/PKG-INFO +13 -0
  2. overture_schema_common-0.1.1.dev0/pyproject.toml +41 -0
  3. overture_schema_common-0.1.1.dev0/pyproject.toml.orig +41 -0
  4. overture_schema_common-0.1.1.dev0/src/overture/schema/common/__init__.py +50 -0
  5. overture_schema_common-0.1.1.dev0/src/overture/schema/common/cartography.py +114 -0
  6. overture_schema_common-0.1.1.dev0/src/overture/schema/common/confidence.py +17 -0
  7. overture_schema_common-0.1.1.dev0/src/overture/schema/common/feature.py +103 -0
  8. overture_schema_common-0.1.1.dev0/src/overture/schema/common/level.py +23 -0
  9. overture_schema_common-0.1.1.dev0/src/overture/schema/common/names.py +230 -0
  10. overture_schema_common-0.1.1.dev0/src/overture/schema/common/perspectives.py +40 -0
  11. overture_schema_common-0.1.1.dev0/src/overture/schema/common/py.typed +0 -0
  12. overture_schema_common-0.1.1.dev0/src/overture/schema/common/scoping/__init__.py +394 -0
  13. overture_schema_common-0.1.1.dev0/src/overture/schema/common/scoping/heading.py +14 -0
  14. overture_schema_common-0.1.1.dev0/src/overture/schema/common/scoping/lr.py +105 -0
  15. overture_schema_common-0.1.1.dev0/src/overture/schema/common/scoping/opening_hours.py +21 -0
  16. overture_schema_common-0.1.1.dev0/src/overture/schema/common/scoping/purpose_of_use.py +18 -0
  17. overture_schema_common-0.1.1.dev0/src/overture/schema/common/scoping/recognized_status.py +18 -0
  18. overture_schema_common-0.1.1.dev0/src/overture/schema/common/scoping/scoped.py +495 -0
  19. overture_schema_common-0.1.1.dev0/src/overture/schema/common/scoping/side.py +16 -0
  20. overture_schema_common-0.1.1.dev0/src/overture/schema/common/scoping/travel_mode.py +24 -0
  21. overture_schema_common-0.1.1.dev0/src/overture/schema/common/scoping/vehicle.py +139 -0
  22. overture_schema_common-0.1.1.dev0/src/overture/schema/common/sources.py +139 -0
  23. overture_schema_common-0.1.1.dev0/src/overture/schema/common/tag_providers.py +130 -0
  24. overture_schema_common-0.1.1.dev0/src/overture/schema/common/unit.py +46 -0
@@ -0,0 +1,13 @@
1
+ Metadata-Version: 2.4
2
+ Name: overture-schema-common
3
+ Version: 0.1.1.dev0
4
+ Summary: Common components that are shared across Overture theme schemas
5
+ License-Expression: MIT
6
+ Requires-Dist: overture-schema-system>=0.1.1
7
+ Requires-Dist: pydantic>=2.13.0
8
+ Requires-Dist: shapely>=2.1.1
9
+ Maintainer: Overture Maps Schema Working Group
10
+ Requires-Python: >=3.10
11
+ Project-URL: Homepage, https://overturemaps.org
12
+ Project-URL: Source, https://github.com/OvertureMaps/schema
13
+ Project-URL: Issues, https://github.com/OvertureMaps/schema/issues
@@ -0,0 +1,41 @@
1
+ [build-system]
2
+ requires = ["uv_build>=0.11.32,<0.13"]
3
+ build-backend = "uv_build"
4
+
5
+ [project]
6
+ name = "overture-schema-common"
7
+ version = "0.1.1.dev0"
8
+ description = "Common components that are shared across Overture theme schemas"
9
+ requires-python = ">=3.10"
10
+ license = "MIT"
11
+ dependencies = [
12
+ "overture-schema-system>=0.1.1",
13
+ "pydantic>=2.13.0",
14
+ "shapely>=2.1.1",
15
+ ]
16
+
17
+ [[project.maintainers]]
18
+ name = "Overture Maps Schema Working Group"
19
+
20
+ [project.urls]
21
+ Homepage = "https://overturemaps.org"
22
+ Source = "https://github.com/OvertureMaps/schema"
23
+ Issues = "https://github.com/OvertureMaps/schema/issues"
24
+
25
+ [project.entry-points."overture.tag_providers"]
26
+ overture = "overture.schema.common.tag_providers:overture_provider"
27
+ theme = "overture.schema.common.tag_providers:theme_provider"
28
+
29
+ [tool.uv.sources.overture-schema-system]
30
+ workspace = true
31
+
32
+ [tool.uv.build-backend]
33
+ module-name = "overture.schema.common"
34
+
35
+ [dependency-groups]
36
+ dev = [
37
+ "deepdiff>=8.6.0",
38
+ "jsonpath-ng>=1.7.0",
39
+ "types-pyyaml>=6.0.12.20250516",
40
+ "types-shapely>=2.1.0.20250710",
41
+ ]
@@ -0,0 +1,41 @@
1
+ [build-system]
2
+ requires = ["uv_build>=0.11.32,<0.13"]
3
+ build-backend = "uv_build"
4
+
5
+ [project]
6
+ name = "overture-schema-common"
7
+ maintainers = [
8
+ {name = "Overture Maps Schema Working Group"},
9
+ ]
10
+ version = "0.1.1.dev0"
11
+ description = "Common components that are shared across Overture theme schemas"
12
+ requires-python = ">=3.10"
13
+ license = "MIT"
14
+ dependencies = [
15
+ "overture-schema-system>=0.1.1",
16
+ "pydantic>=2.13.0",
17
+ "shapely>=2.1.1",
18
+ ]
19
+
20
+ [project.urls]
21
+ Homepage = "https://overturemaps.org"
22
+ Source = "https://github.com/OvertureMaps/schema"
23
+ Issues = "https://github.com/OvertureMaps/schema/issues"
24
+
25
+ [tool.uv.sources]
26
+ overture-schema-system = { workspace = true }
27
+
28
+ [tool.uv.build-backend]
29
+ module-name = "overture.schema.common"
30
+
31
+ [dependency-groups]
32
+ dev = [
33
+ "deepdiff>=8.6.0",
34
+ "jsonpath-ng>=1.7.0",
35
+ "types-pyyaml>=6.0.12.20250516",
36
+ "types-shapely>=2.1.0.20250710",
37
+ ]
38
+
39
+ [project.entry-points."overture.tag_providers"]
40
+ overture = "overture.schema.common.tag_providers:overture_provider"
41
+ theme = "overture.schema.common.tag_providers:theme_provider"
@@ -0,0 +1,50 @@
1
+ """
2
+ Shared building blocks common to all Overture theme packages.
3
+
4
+ The `OvertureFeature` base class and the reusable feature components — naming, sources,
5
+ cartographic hints, scoping, and more — that theme packages compose to define their
6
+ feature types.
7
+
8
+ Subpackages
9
+ -----------
10
+ - :mod:`cartography <overture.schema.common.cartography>` Cartographic display hints.
11
+ - :mod:`confidence <overture.schema.common.confidence>` The `ConfidenceScore` type.
12
+ - :mod:`feature <overture.schema.common.feature>` The `OvertureFeature` base class and its
13
+ supporting types (`FeatureVersion`, `ThemeT`, `TypeT`).
14
+ - :mod:`level <overture.schema.common.level>` Feature Z-order / stacking (`Level`, `Stacked`).
15
+ - :mod:`names <overture.schema.common.names>` Multilingual naming with variants and rules.
16
+ - :mod:`perspectives <overture.schema.common.perspectives>` Political perspectives on disputed
17
+ data.
18
+ - :mod:`scoping <overture.schema.common.scoping>` Scoped, conditionally-applicable field values.
19
+ - :mod:`sources <overture.schema.common.sources>` Data provenance and source attribution.
20
+ - :mod:`unit <overture.schema.common.unit>` Units of measure.
21
+ """
22
+
23
+ from . import (
24
+ cartography,
25
+ confidence,
26
+ feature,
27
+ level,
28
+ names,
29
+ perspectives,
30
+ scoping,
31
+ sources,
32
+ unit,
33
+ )
34
+ from .feature import FeatureVersion, OvertureFeature, ThemeT, TypeT
35
+
36
+ __all__ = [
37
+ "cartography",
38
+ "confidence",
39
+ "feature",
40
+ "FeatureVersion",
41
+ "level",
42
+ "names",
43
+ "OvertureFeature",
44
+ "perspectives",
45
+ "scoping",
46
+ "sources",
47
+ "ThemeT",
48
+ "TypeT",
49
+ "unit",
50
+ ]
@@ -0,0 +1,114 @@
1
+ """
2
+ Specify cartographic hints for features and fields of features.
3
+ """
4
+
5
+ import textwrap
6
+ from typing import Annotated, NewType
7
+
8
+ from pydantic import BaseModel, Field
9
+
10
+ from overture.schema.system.model_constraint import no_extra_fields
11
+ from overture.schema.system.numeric import int32
12
+
13
+ Prominence = NewType(
14
+ "Prominence",
15
+ Annotated[
16
+ int32,
17
+ Field(
18
+ ge=1,
19
+ le=100,
20
+ description=textwrap.dedent("""
21
+ Subjective scale of feature significance or importance, with 1 being the least, and
22
+ 100 being the most, significant.
23
+
24
+ This value can be used to help drive decisions about how and when to display a
25
+ feature, and how to treat it relative to neighboring features.
26
+
27
+ When populated by Overture, this value is derived from various factors including,
28
+ but not limited to: feature and subtype, population, and capital status.
29
+ """).strip(),
30
+ ),
31
+ ],
32
+ )
33
+
34
+ MinZoom = NewType(
35
+ "MinZoom",
36
+ Annotated[
37
+ int32,
38
+ Field(
39
+ ge=0,
40
+ le=23,
41
+ description=textwrap.dedent("""
42
+ Recommended minimum tile zoom level in which this feature should be displayed.
43
+
44
+ It is recommended that the feature be hidden at zoom levels below this value.
45
+
46
+ Zoom levels follow the Slippy Maps convention, documented in the following
47
+ references:
48
+ - https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames
49
+ - https://www.maptiler.com/google-maps-coordinates-tile-bounds-projection
50
+ """).strip(),
51
+ ),
52
+ ],
53
+ )
54
+
55
+ MaxZoom = NewType(
56
+ "MaxZoom",
57
+ Annotated[
58
+ int32,
59
+ Field(
60
+ ge=0,
61
+ le=23,
62
+ description=textwrap.dedent("""
63
+ Recommended maximum tile zoom level in which this feature should be displayed.
64
+
65
+ It is recommended that the feature be hidden at zoom levels above this value.
66
+
67
+ Zoom levels follow the Slippy Maps convention, documented in the following
68
+ references:
69
+ - https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames
70
+ - https://www.maptiler.com/google-maps-coordinates-tile-bounds-projection
71
+ """).strip(),
72
+ ),
73
+ ],
74
+ )
75
+
76
+ SortKey = NewType(
77
+ "SortKey",
78
+ Annotated[
79
+ int32,
80
+ Field(
81
+ description=textwrap.dedent("""
82
+ Integer indicating the recommended order in which to draw features.
83
+
84
+ Features with a lower number should be drawn "in front" of features with a higher
85
+ number.
86
+ """).strip(),
87
+ ),
88
+ ],
89
+ )
90
+
91
+
92
+ @no_extra_fields
93
+ class CartographicHints(BaseModel):
94
+ """Cartographic hints for optimal use of Overture features in map-making."""
95
+
96
+ # Optional
97
+
98
+ prominence: Prominence | None = None
99
+ min_zoom: MinZoom | None = None
100
+ max_zoom: MaxZoom | None = None
101
+ sort_key: SortKey | None = None
102
+
103
+
104
+ class CartographicallyHinted(BaseModel):
105
+ """
106
+ Properties for adding cartographic hints to a model.
107
+ """
108
+
109
+ cartography: Annotated[
110
+ CartographicHints | None,
111
+ Field(
112
+ description="Cartographic hints useful when including the feature in maps"
113
+ ),
114
+ ] = None
@@ -0,0 +1,17 @@
1
+ """
2
+ Confidence scores for machine-generated or machine-augmented data.
3
+ """
4
+
5
+ from typing import Annotated, NewType
6
+
7
+ from pydantic import Field
8
+
9
+ from overture.schema.system.numeric import float64
10
+
11
+ ConfidenceScore = NewType(
12
+ "ConfidenceScore",
13
+ Annotated[
14
+ float64,
15
+ Field(description="Confidence score between 0.0 and 1.0", ge=0.0, le=1.0),
16
+ ],
17
+ )
@@ -0,0 +1,103 @@
1
+ """
2
+ The Overture feature, an Overture-specific refinement of the base `Feature` type defined in the
3
+ system package.
4
+ """
5
+
6
+ import textwrap
7
+ from typing import Annotated, Generic, NewType, TypeVar
8
+
9
+ from pydantic import (
10
+ ConfigDict,
11
+ Field,
12
+ GetJsonSchemaHandler,
13
+ model_validator,
14
+ )
15
+ from pydantic.json_schema import JsonSchemaValue
16
+ from pydantic_core import core_schema
17
+ from typing_extensions import Self
18
+
19
+ from overture.schema.system.feature import Feature
20
+ from overture.schema.system.numeric import int32
21
+ from overture.schema.system.ref import Id, Identified
22
+
23
+ from .sources import Sources
24
+
25
+ ThemeT = TypeVar("ThemeT", bound=str)
26
+ TypeT = TypeVar("TypeT", bound=str)
27
+
28
+ FeatureVersion = NewType(
29
+ "FeatureVersion", Annotated[int32, Field(ge=0, description="")]
30
+ )
31
+
32
+
33
+ class OvertureFeature(Identified, Feature, Generic[ThemeT, TypeT]):
34
+ """
35
+ Overture feature, the base class for all Overture features types.
36
+
37
+ An `OvertureFeature` extends the fundamental `Feature` type by:
38
+ - Making the basic ``id`` field required instead of optional.
39
+ - Adding required fields ``theme``, ``type``, and ``version``.
40
+ - Adding the optional field ``sources``.
41
+ """
42
+
43
+ # Only used to support `ext_*` fields, which are on a deprecation path.
44
+ model_config = ConfigDict(extra="allow")
45
+
46
+ # Required
47
+
48
+ # Repeating `id` from the superclass `Feature` to make it mandatory: it is optional in the
49
+ # superclass.
50
+ id: Id = Field(
51
+ description="A feature ID. This may be an ID associated with the Global Entity Reference System (GERS) if—and-only-if the feature represents an entity that is part of GERS."
52
+ ) # type: ignore[assignment]
53
+ theme: ThemeT
54
+ type: TypeT
55
+ # Superclass `Feature` provides `geometry` and `bbox`.
56
+ version: FeatureVersion
57
+
58
+ # Optional
59
+
60
+ sources: Sources | None = None
61
+
62
+ @model_validator(mode="after")
63
+ def __validate_ext_fields__(self) -> Self:
64
+ extra = self.model_extra
65
+ invalid_extra_fields = (
66
+ [f for f in extra.keys() if not f.startswith("ext_")] if extra else ()
67
+ )
68
+ if invalid_extra_fields:
69
+ maybe_plural = "s" if len(invalid_extra_fields) > 1 else ""
70
+ raise ValueError(
71
+ f"invalid extra field name{maybe_plural}: {', '.join(invalid_extra_fields)} "
72
+ f"(extra fields are temporarily allowed, but only if their names start with 'ext_', "
73
+ f"but all extra field name support in {self.__class__.__name__} is on a deprecation path "
74
+ f"and will be removed)"
75
+ )
76
+ return self
77
+
78
+ @classmethod
79
+ def __get_pydantic_json_schema__(
80
+ cls,
81
+ schema: core_schema.CoreSchema,
82
+ handler: GetJsonSchemaHandler,
83
+ ) -> JsonSchemaValue:
84
+ # Get the main Feature JSON schema.
85
+ json_schema = super().__get_pydantic_json_schema__(schema, handler)
86
+
87
+ # Explicitly allow `ext_*` properties, but no other properties, in the properties object.
88
+ # This feature only exists to get to initial parity between the hand-written JSON Schema and
89
+ # the Pydantic port. Once Pydantic is the primary, it will be deprecated.
90
+ properties_object_schema = json_schema["properties"]["properties"]
91
+ properties_object_schema["patternProperties"] = {
92
+ "^ext_.*$": {
93
+ "description": textwrap.dedent("""
94
+ Additional top-level properties are allowed if prefixed by `ext_`.
95
+
96
+ This feature is on a deprecation path and will be removed once the schema is
97
+ fully migrated to Pydantic.
98
+ """).strip(),
99
+ }
100
+ }
101
+ properties_object_schema["additionalProperties"] = False
102
+
103
+ return json_schema
@@ -0,0 +1,23 @@
1
+ """
2
+ Z-order stacking.
3
+ """
4
+
5
+ from typing import Annotated, NewType
6
+
7
+ from pydantic import BaseModel, Field
8
+
9
+ from overture.schema.system.numeric import int32
10
+
11
+ Level = NewType(
12
+ "Level",
13
+ Annotated[
14
+ int32,
15
+ Field(description="Z-order of the feature where 0 is visual level"),
16
+ ],
17
+ )
18
+
19
+
20
+ class Stacked(BaseModel):
21
+ """Properties defining feature Z-order, i.e., stacking order."""
22
+
23
+ level: Level | None = 0 # type: ignore[assignment]
@@ -0,0 +1,230 @@
1
+ """
2
+ Names for features and their child attributes.
3
+
4
+ This module includes all Overture's standard naming types. It supports multi-language names,
5
+ multiple name variants, and naming rules for specifying conditional or partial names to things.
6
+
7
+ Examples
8
+ --------
9
+ Create a feature type that can have a name:
10
+
11
+ >>> from typing import Literal
12
+ >>> from overture.schema.common import OvertureFeature
13
+ >>> from overture.schema.system.geometric import Geometry
14
+ >>> class MyFeature(OvertureFeature[Literal["mytheme"], Literal["mytype"]], Named):
15
+ ... pass
16
+ ...
17
+ >>> my_feature = MyFeature(
18
+ ... id='12345678-1234-5678-9abc-123456789012',
19
+ ... geometry=Geometry.from_wkt('POINT(0 0)'),
20
+ ... theme='mytheme',
21
+ ... type='mytype',
22
+ ... version=1,
23
+ ... names=Names(primary='my feature primary name')
24
+ ... )
25
+
26
+ Create an arbitrary Pydantic model that can have a name:
27
+
28
+ >>> from pydantic import BaseModel
29
+ >>> from overture.schema.system.model_constraint import no_extra_fields
30
+ >>> @no_extra_fields
31
+ ... class MyModel(Named):
32
+ ... myfield: int
33
+ ...
34
+ >>> MyModel(names=Names(primary='foo'), myfield=42)
35
+ MyModel(names=Names(primary='foo', common=None, rules=None), myfield=42)
36
+
37
+ Create a simple names structure with names in multiple languages:
38
+
39
+ >>> names = Names(
40
+ ... primary='Le Léman',
41
+ ... common={
42
+ ... 'de': 'Genfersee',
43
+ ... 'en': 'Lake Geneva',
44
+ ... 'fr': 'Le Léman',
45
+ ... }
46
+ ... )
47
+
48
+ Create a name structure with official, alternate, and short names:
49
+
50
+ >>> names = Names(
51
+ ... primary='City of New York',
52
+ ... rules=[
53
+ ... NameRule(value='New York', variant='official', language='en'),
54
+ ... NameRule(value='New York City', variant='alternate', language='en'),
55
+ ... NameRule(value='The Big Apple', variant='alternate', language='en'),
56
+ ... NameRule(value='NYC', variant='alternate'),
57
+ ... ]
58
+ ... )
59
+
60
+ Create a name structure for a street where the name changes based on the side of the street.
61
+
62
+ >>> from overture.schema.common.scoping import Side
63
+ >>> names = Names(
64
+ ... primary='Fir St',
65
+ ... rules=[
66
+ ... NameRule(value='2 Ave', variant='common', between=[0, 0.3], side=Side.LEFT),
67
+ ... NameRule(value='Fir St', variant='common', between=[0.3, 1], side=Side.LEFT),
68
+ ... NameRule(value='Fir St', variant='common', side=Side.RIGHT),
69
+ ... ]
70
+ ... )
71
+ """
72
+
73
+ import textwrap
74
+ from typing import Annotated, NewType
75
+
76
+ from pydantic import BaseModel, Field
77
+
78
+ from overture.schema.common.perspectives import Perspectives
79
+ from overture.schema.common.scoping import Scope, scoped
80
+ from overture.schema.system.doc import DocumentedEnum
81
+ from overture.schema.system.model_constraint import no_extra_fields
82
+ from overture.schema.system.string import (
83
+ LanguageTag,
84
+ StrippedString,
85
+ )
86
+
87
+ CommonNames = NewType(
88
+ "CommonNames",
89
+ Annotated[
90
+ dict[
91
+ Annotated[
92
+ LanguageTag,
93
+ Field(
94
+ description=textwrap.dedent("""
95
+ A mapping from language to the most commonly used or recognized name in that
96
+ language.
97
+
98
+ Each entry consists of a key that is an IETF BCP 47 language tag; and a
99
+ value that reflects the common name in the language represented by the key's
100
+ language tag.
101
+
102
+ The validating regular expression for this property follows the pattern
103
+ described in https://www.rfc-editor.org/rfc/bcp/bcp47.txt with the exception
104
+ that private use tags are not supported.
105
+ """).strip(),
106
+ ),
107
+ ],
108
+ StrippedString,
109
+ ],
110
+ Field(json_schema_extra={"additionalProperties": False}),
111
+ ],
112
+ )
113
+ CommonNames.__doc__ = """A mapping from language to the most commonly used or recognized name in that language."""
114
+
115
+
116
+ class NameVariant(str, DocumentedEnum):
117
+ """
118
+ Name variant used in a `NameRule`.
119
+ """
120
+
121
+ COMMON = (
122
+ "common",
123
+ textwrap.dedent("""
124
+ The most commonly used or recognized name for a feature in the specified language.
125
+
126
+ In a `Names` value, most common names will appear in the `Names.common` field and will
127
+ not need to be specified as `NameRule` values in `Names.rules`. This member of the
128
+ enumeration should only be used to construct a `NameRule` if the common name needs to
129
+ be scoped in some way and therefore cannot be accurately represented in `CommonNames`.
130
+ """).strip(),
131
+ )
132
+ OFFICIAL = (
133
+ "official",
134
+ textwrap.dedent("""
135
+ The legally or administratively recognized name, often used by government agencies or
136
+ official documents.
137
+ """).strip(),
138
+ )
139
+ ALTERNATE = (
140
+ "alternate",
141
+ textwrap.dedent("""
142
+ An alternative name, which may be a historical name, a local colloquial name, or some
143
+ other well-known name is not the common name.
144
+ """).strip(),
145
+ )
146
+ SHORT = (
147
+ "short",
148
+ textwrap.dedent("""
149
+ An abbreviated or shortened version of the name, which may be an acronym or some other
150
+ commonly-used short form. An example is "NYC" for New York City.
151
+ """).strip(),
152
+ )
153
+
154
+
155
+ @no_extra_fields
156
+ @scoped(Scope.GEOMETRIC_RANGE, Scope.SIDE)
157
+ class NameRule(BaseModel):
158
+ """
159
+ A rule that can be evaluated to determine the name in advanced scenarios.
160
+
161
+ Name rules are used for cases where the primary name is not sufficient; the common name is not
162
+ the right fit for the use case and another variant is needed; or where the name only applies in
163
+ certain specific circumstances.
164
+
165
+ Examples might include:
166
+ - An official, alternate, or short name.
167
+ - A name that only applies to part of a linear path like a road segment (geometric range
168
+ scoping).
169
+ - A name that only applies to the left or right side of a linear path like a road segment (side
170
+ scoping).
171
+ - A name that is only accepted by some political perspectives.
172
+ """
173
+
174
+ # Required
175
+
176
+ value: Annotated[
177
+ StrippedString, Field(description="The actual name value.", min_length=1)
178
+ ]
179
+ variant: NameVariant = Field(description="The name variant for this name rule.")
180
+
181
+ # Optional
182
+
183
+ language: Annotated[
184
+ LanguageTag | None,
185
+ Field(
186
+ description=textwrap.dedent("""
187
+ The language in which the name `value` is specified, if known, as an IETF BCP 47
188
+ language tag.
189
+ """).strip()
190
+ ),
191
+ ] = None
192
+ perspectives: (
193
+ Annotated[
194
+ Perspectives,
195
+ Field(
196
+ description="Political perspectives from which a named feature is viewed."
197
+ ),
198
+ ]
199
+ | None
200
+ ) = None
201
+
202
+
203
+ @no_extra_fields
204
+ class Names(BaseModel):
205
+ """Multilingual names container."""
206
+
207
+ # Required
208
+
209
+ primary: Annotated[
210
+ StrippedString, Field(min_length=1, description="The most commonly used name.")
211
+ ]
212
+
213
+ # Optional
214
+
215
+ common: CommonNames | None = None
216
+ rules: Annotated[
217
+ list[NameRule] | None,
218
+ Field(
219
+ description="Rules for names that cannot be specified in the simple common names property. These rules can cover other name variants such as official, alternate, and short; and they can optionally include geometric scoping (linear referencing) and side-of-road scoping for complex cases.",
220
+ ),
221
+ ] = None
222
+
223
+
224
+ class Named(BaseModel):
225
+ """Properties defining the names of a model."""
226
+
227
+ names: Annotated[
228
+ Names | None,
229
+ Field(description="All known names by which the feature is called"),
230
+ ] = None
@@ -0,0 +1,40 @@
1
+ """
2
+ Political perspectives.
3
+ """
4
+
5
+ from enum import Enum
6
+ from typing import Annotated
7
+
8
+ from pydantic import BaseModel, Field
9
+
10
+ from overture.schema.system.field_constraint import UniqueItemsConstraint
11
+ from overture.schema.system.model_constraint import no_extra_fields
12
+ from overture.schema.system.string import CountryCodeAlpha2
13
+
14
+
15
+ class PerspectiveMode(str, Enum):
16
+ """Perspective mode for disputed names."""
17
+
18
+ ACCEPTED_BY = "accepted_by"
19
+ DISPUTED_BY = "disputed_by"
20
+
21
+
22
+ @no_extra_fields
23
+ class Perspectives(BaseModel):
24
+ """Political perspectives container."""
25
+
26
+ # Required
27
+
28
+ mode: Annotated[
29
+ PerspectiveMode,
30
+ Field(
31
+ description="Whether the perspective holder accepts or disputes this name."
32
+ ),
33
+ ]
34
+ countries: Annotated[
35
+ list[CountryCodeAlpha2],
36
+ Field(
37
+ min_length=1, description="Countries holding the given mode of perspective."
38
+ ),
39
+ UniqueItemsConstraint(),
40
+ ]