overturetoosm.objects
Pydantic models needed throughout the project.
1"""Pydantic models needed throughout the project.""" 2 3# ruff: noqa: D415 4 5from enum import Enum 6from typing import Dict, List, Optional, Union 7 8try: 9 from typing import Annotated 10except ImportError: 11 from typing_extensions import Annotated 12 13from pydantic import BaseModel, ConfigDict, Field, RootModel, field_validator 14 15from .resources import places_tags 16 17 18class OvertureBaseModel(BaseModel): 19 """Base model for Overture features.""" 20 21 model_config = ConfigDict(extra="forbid") 22 23 version: int = Field(ge=0) 24 theme: Optional[str] = None 25 type: Optional[str] = None 26 id: Optional[str] = Field(None, pattern=r"^(\S.*)?\S$") 27 28 29class Wikidata(RootModel): 30 """Model for transportation segment wikidata.""" 31 32 root: str = Field(description="Wikidata ID.", pattern=r"^Q\d+") 33 34 35class Sources(BaseModel): 36 """Overture sources model.""" 37 38 property: str 39 dataset: str 40 record_id: Optional[str] = None 41 confidence: Optional[float] = Field(ge=0.0, le=1.0) 42 update_time: Optional[str] = None 43 44 @field_validator("confidence") 45 @classmethod 46 def set_default_if_none(cls, v: float) -> float: 47 """@private""" 48 return v if v is not None else 0.0 49 50 def get_osm_link(self) -> Union[str, None]: 51 """Return the OSM link for the source.""" 52 if ( 53 self.record_id 54 and self.record_id.startswith(("n", "w", "r")) 55 and self.dataset == "OpenStreetMap" 56 ): 57 type_dict = {"n": "node", "w": "way", "r": "relation"} 58 return f"https://www.openstreetmap.org/{type_dict[self.record_id[0]]}/{self.record_id[1:]}" 59 60 61class RulesVariant(str, Enum): 62 """Overture name rules variant model.""" 63 64 alternate = "alternate" 65 common = "common" 66 official = "official" 67 short = "short" 68 69 70class Between(RootModel): 71 """Model for transportation segment between.""" 72 73 root: Annotated[list, Field(float, min_length=2, max_length=2)] 74 75 76class Rules(BaseModel): 77 """Overture name rules model.""" 78 79 variant: RulesVariant 80 language: Optional[str] = None 81 value: str 82 between: Optional[Between] = None 83 side: Optional[str] = None 84 85 86class Names(BaseModel): 87 """Overture names model.""" 88 89 primary: str 90 common: Optional[Dict[str, str]] 91 rules: Optional[List[Rules]] 92 93 94class PlaceAddress(BaseModel): 95 """Overture addresses model.""" 96 97 freeform: Optional[str] 98 locality: Optional[str] 99 postcode: Optional[str] 100 region: Optional[str] 101 country: Optional[str] = Field(pattern=r"^[A-Z]{2}$") 102 103 104class Categories(BaseModel): 105 """Overture categories model.""" 106 107 main: str 108 alternate: Optional[List[str]] 109 110 111class Brand(BaseModel): 112 """Overture brand model.""" 113 114 wikidata: Optional[Wikidata] = None 115 names: Names 116 117 def to_osm(self) -> Dict[str, str]: 118 """Convert brand properties to OSM tags.""" 119 osm = {"brand": self.names.primary} 120 if self.wikidata: 121 osm.update({"brand:wikidata": str(self.wikidata.root)}) 122 return osm 123 124 125class Socials(RootModel): 126 """Overture socials model.""" 127 128 root: List[str] 129 130 def to_osm(self) -> Dict[str, str]: 131 """Convert socials properties to OSM tags.""" 132 new_props = {} 133 for social in self.root: 134 if "facebook" in social: 135 new_props["contact:facebook"] = social 136 elif "twitter" in str(social): 137 new_props["contact:twitter"] = social 138 return new_props 139 140 141class PlaceProps(OvertureBaseModel): 142 """Overture properties model. 143 144 Use this model directly if you want to manipulate the `place` properties yourself. 145 """ 146 147 update_time: str 148 sources: List[Sources] 149 names: Names 150 brand: Optional[Brand] = None 151 categories: Optional[Categories] = None 152 confidence: float = Field(ge=0.0, le=1.0) 153 websites: Optional[List[str]] = None 154 socials: Optional[Socials] = None 155 emails: Optional[List[str]] = None 156 phones: Optional[List[str]] = None 157 addresses: List[PlaceAddress] 158 159 def to_osm( 160 self, confidence: float, region_tag: str, unmatched: str 161 ) -> Dict[str, str]: 162 """Convert Overture's place properties to OSM tags. 163 164 Used internally by the `overturetoosm.process_place` function. 165 """ 166 new_props = {} 167 if self.confidence < confidence: 168 raise ConfidenceError(confidence, self.confidence) 169 170 if self.categories: 171 prim = places_tags.get(self.categories.main) 172 if prim: 173 new_props = {**new_props, **prim} 174 elif unmatched == "force": 175 new_props["type"] = self.categories.main 176 elif unmatched == "error": 177 raise UnmatchedError(self.categories.main) 178 179 if self.names.primary: 180 new_props["name"] = self.names.primary 181 182 if self.phones is not None: 183 new_props["phone"] = self.phones[0] 184 185 if self.websites is not None and self.websites[0]: 186 new_props["website"] = str(self.websites[0]) 187 188 if add := self.addresses[0]: 189 if add.freeform: 190 new_props["addr:street_address"] = add.freeform 191 if add.country: 192 new_props["addr:country"] = add.country 193 if add.postcode: 194 new_props["addr:postcode"] = add.postcode 195 if add.locality: 196 new_props["addr:city"] = add.locality 197 if add.region: 198 new_props[region_tag] = add.region 199 200 if self.sources: 201 new_props["source"] = source_statement(self.sources) 202 203 if self.socials: 204 new_props.update(self.socials.to_osm()) 205 206 if self.brand: 207 new_props.update(self.brand.to_osm()) 208 209 return new_props 210 211 212class ConfidenceError(Exception): 213 """Confidence error exception. 214 215 This exception is raised when the confidence level of an item is below the 216 user-defined level. It contains the original confidence level and the confidence 217 level of the item. 218 219 Attributes: 220 confidence_level (float): The set confidence level. 221 confidence_item (float): The confidence of the item. 222 message (str): The error message. 223 """ 224 225 def __init__( 226 self, 227 confidence_level: float, 228 confidence_item: float, 229 message: str = "Confidence in this item is too low.", 230 ) -> None: 231 """@private""" 232 self.confidence_level = confidence_level 233 self.confidence_item = confidence_item 234 self.message = message 235 super().__init__(message) 236 237 def __str__(self) -> str: 238 """@private""" 239 lev = f"confidence_level={self.confidence_level}" 240 item = f"confidence_item={self.confidence_item}" 241 return f"""{self.message} {lev}, {item}""" 242 243 244class UnmatchedError(Exception): 245 """Unmatched category error. 246 247 This exception is raised when an item's Overture category does not have a 248 corresponding OSM definition. Edit 249 [the OSM Wiki page](https://wiki.openstreetmap.org/wiki/Overture_categories) 250 to add a definition to this category. 251 252 Attributes: 253 category (str): The Overture category that is unmatched. 254 message (str): The error message. 255 """ 256 257 def __init__( 258 self, category: str, message: str = "Overture category is unmatched." 259 ) -> None: 260 """@private""" 261 self.category = category 262 self.message = message 263 super().__init__(message) 264 265 def __str__(self) -> str: 266 """@private""" 267 return f"{self.message} {{category={self.category}}}" 268 269 270class BuildingProps(OvertureBaseModel): 271 """Overture building properties. 272 273 Use this model if you want to manipulate the `building` properties yourself. 274 """ 275 276 has_parts: bool 277 sources: List[Sources] 278 class_: Optional[str] = Field(alias="class", default=None) 279 subtype: Optional[str] = None 280 names: Optional[Names] = None 281 level: Optional[int] = None 282 height: Optional[float] = None 283 is_underground: Optional[bool] = None 284 num_floors: Optional[int] = Field( 285 serialization_alias="building:levels", default=None 286 ) 287 num_floors_underground: Optional[int] = Field( 288 serialization_alias="building:levels:underground", default=None 289 ) 290 min_height: Optional[float] = None 291 min_floor: Optional[int] = Field( 292 serialization_alias="building:min_level", default=None 293 ) 294 facade_color: Optional[str] = Field( 295 serialization_alias="building:colour", default=None 296 ) 297 facade_material: Optional[str] = Field( 298 serialization_alias="building:material", default=None 299 ) 300 roof_material: Optional[str] = Field( 301 serialization_alias="roof:material", default=None 302 ) 303 roof_shape: Optional[str] = Field(serialization_alias="roof:shape", default=None) 304 roof_direction: Optional[str] = Field( 305 serialization_alias="roof:direction", default=None 306 ) 307 roof_orientation: Optional[str] = Field( 308 serialization_alias="roof:orientation", default=None 309 ) 310 roof_color: Optional[str] = Field(serialization_alias="roof:colour", default=None) 311 roof_height: Optional[float] = Field( 312 serialization_alias="roof:height", default=None 313 ) 314 315 def to_osm(self, confidence: float) -> Dict[str, str]: 316 """Convert properties to OSM tags. 317 318 Used internally by`overturetoosm.process_building` function. 319 """ 320 new_props = {} 321 confidences = {source.confidence for source in self.sources} 322 if any(conf and conf < confidence for conf in confidences): 323 raise ConfidenceError(confidence, max({i for i in confidences if i})) 324 325 new_props["building"] = self.class_ if self.class_ else "yes" 326 327 new_props["source"] = source_statement(self.sources) 328 329 prop_obj = self.model_dump(exclude_none=True, by_alias=True).items() 330 new_props.update( 331 {k: v for k, v in prop_obj if k.startswith(("roof", "building"))} 332 ) 333 new_props.update({k: round(v, 2) for k, v in prop_obj if k.endswith("height")}) 334 335 if self.is_underground: 336 new_props["location"] = "underground" 337 if self.names: 338 new_props["name"] = self.names.primary 339 return new_props 340 341 342class AddressLevel(BaseModel): 343 """Overture address level model.""" 344 345 value: str 346 347 348class AddressProps(OvertureBaseModel): 349 """Overture address properties. 350 351 Use this model directly if you want to manipulate the `address` properties yourself. 352 """ 353 354 number: Optional[str] = Field(serialization_alias="addr:housenumber") 355 street: Optional[str] = Field(serialization_alias="addr:street") 356 postcode: Optional[str] = Field(serialization_alias="addr:postcode") 357 country: Optional[str] = Field(serialization_alias="addr:country") 358 address_levels: Optional[ 359 Annotated[List[AddressLevel], Field(min_length=1, max_length=5)] 360 ] = Field(default_factory=list) 361 sources: List[Sources] 362 363 def to_osm(self, style: str) -> Dict[str, str]: 364 """Convert properties to OSM tags. 365 366 Used internally by `overturetoosm.process_address`. 367 """ 368 obj_dict = { 369 k: v 370 for k, v in self.model_dump(exclude_none=True, by_alias=True).items() 371 if k.startswith("addr:") 372 } 373 obj_dict["source"] = source_statement(self.sources) 374 375 if self.address_levels and len(self.address_levels) > 0 and style == "US": 376 obj_dict["addr:state"] = str(self.address_levels[0].value) 377 378 return obj_dict 379 380 381def source_statement(source: List[Sources]) -> str: 382 """Return a source statement from a list of sources.""" 383 return ( 384 ", ".join(sorted({i.dataset.strip(", ") for i in source})) 385 + " via overturetoosm" 386 )
19class OvertureBaseModel(BaseModel): 20 """Base model for Overture features.""" 21 22 model_config = ConfigDict(extra="forbid") 23 24 version: int = Field(ge=0) 25 theme: Optional[str] = None 26 type: Optional[str] = None 27 id: Optional[str] = Field(None, pattern=r"^(\S.*)?\S$")
Base model for Overture features.
Configuration for the model, should be a dictionary conforming to [ConfigDict
][pydantic.config.ConfigDict].
Metadata about the fields defined on the model,
mapping of field names to [FieldInfo
][pydantic.fields.FieldInfo] objects.
This replaces Model.__fields__
from Pydantic V1.
A dictionary of computed field names and their corresponding ComputedFieldInfo
objects.
Inherited Members
- pydantic.main.BaseModel
- BaseModel
- model_extra
- model_fields_set
- model_construct
- model_copy
- model_dump
- model_dump_json
- model_json_schema
- model_parametrized_name
- model_post_init
- model_rebuild
- model_validate
- model_validate_json
- model_validate_strings
- dict
- json
- parse_obj
- parse_raw
- parse_file
- from_orm
- construct
- copy
- schema
- schema_json
- validate
- update_forward_refs
30class Wikidata(RootModel): 31 """Model for transportation segment wikidata.""" 32 33 root: str = Field(description="Wikidata ID.", pattern=r"^Q\d+")
Model for transportation segment wikidata.
Inherited Members
- pydantic.main.BaseModel
- BaseModel
- model_config
- model_fields
- model_computed_fields
- model_extra
- model_fields_set
- model_construct
- model_copy
- model_dump
- model_dump_json
- model_json_schema
- model_parametrized_name
- model_post_init
- model_rebuild
- model_validate
- model_validate_json
- model_validate_strings
- dict
- json
- parse_obj
- parse_raw
- parse_file
- from_orm
- construct
- copy
- schema
- schema_json
- validate
- update_forward_refs
36class Sources(BaseModel): 37 """Overture sources model.""" 38 39 property: str 40 dataset: str 41 record_id: Optional[str] = None 42 confidence: Optional[float] = Field(ge=0.0, le=1.0) 43 update_time: Optional[str] = None 44 45 @field_validator("confidence") 46 @classmethod 47 def set_default_if_none(cls, v: float) -> float: 48 """@private""" 49 return v if v is not None else 0.0 50 51 def get_osm_link(self) -> Union[str, None]: 52 """Return the OSM link for the source.""" 53 if ( 54 self.record_id 55 and self.record_id.startswith(("n", "w", "r")) 56 and self.dataset == "OpenStreetMap" 57 ): 58 type_dict = {"n": "node", "w": "way", "r": "relation"} 59 return f"https://www.openstreetmap.org/{type_dict[self.record_id[0]]}/{self.record_id[1:]}"
Overture sources model.
51 def get_osm_link(self) -> Union[str, None]: 52 """Return the OSM link for the source.""" 53 if ( 54 self.record_id 55 and self.record_id.startswith(("n", "w", "r")) 56 and self.dataset == "OpenStreetMap" 57 ): 58 type_dict = {"n": "node", "w": "way", "r": "relation"} 59 return f"https://www.openstreetmap.org/{type_dict[self.record_id[0]]}/{self.record_id[1:]}"
Return the OSM link for the source.
Configuration for the model, should be a dictionary conforming to [ConfigDict
][pydantic.config.ConfigDict].
Metadata about the fields defined on the model,
mapping of field names to [FieldInfo
][pydantic.fields.FieldInfo] objects.
This replaces Model.__fields__
from Pydantic V1.
A dictionary of computed field names and their corresponding ComputedFieldInfo
objects.
Inherited Members
- pydantic.main.BaseModel
- BaseModel
- model_extra
- model_fields_set
- model_construct
- model_copy
- model_dump
- model_dump_json
- model_json_schema
- model_parametrized_name
- model_post_init
- model_rebuild
- model_validate
- model_validate_json
- model_validate_strings
- dict
- json
- parse_obj
- parse_raw
- parse_file
- from_orm
- construct
- copy
- schema
- schema_json
- validate
- update_forward_refs
62class RulesVariant(str, Enum): 63 """Overture name rules variant model.""" 64 65 alternate = "alternate" 66 common = "common" 67 official = "official" 68 short = "short"
Overture name rules variant model.
Inherited Members
- enum.Enum
- name
- value
- builtins.str
- encode
- replace
- split
- rsplit
- join
- capitalize
- casefold
- title
- center
- count
- expandtabs
- find
- partition
- index
- ljust
- lower
- lstrip
- rfind
- rindex
- rjust
- rstrip
- rpartition
- splitlines
- strip
- swapcase
- translate
- upper
- startswith
- endswith
- removeprefix
- removesuffix
- isascii
- islower
- isupper
- istitle
- isspace
- isdecimal
- isdigit
- isnumeric
- isalpha
- isalnum
- isidentifier
- isprintable
- zfill
- format
- format_map
- maketrans
71class Between(RootModel): 72 """Model for transportation segment between.""" 73 74 root: Annotated[list, Field(float, min_length=2, max_length=2)]
Model for transportation segment between.
Inherited Members
- pydantic.main.BaseModel
- BaseModel
- model_config
- model_fields
- model_computed_fields
- model_extra
- model_fields_set
- model_construct
- model_copy
- model_dump
- model_dump_json
- model_json_schema
- model_parametrized_name
- model_post_init
- model_rebuild
- model_validate
- model_validate_json
- model_validate_strings
- dict
- json
- parse_obj
- parse_raw
- parse_file
- from_orm
- construct
- copy
- schema
- schema_json
- validate
- update_forward_refs
77class Rules(BaseModel): 78 """Overture name rules model.""" 79 80 variant: RulesVariant 81 language: Optional[str] = None 82 value: str 83 between: Optional[Between] = None 84 side: Optional[str] = None
Overture name rules model.
Configuration for the model, should be a dictionary conforming to [ConfigDict
][pydantic.config.ConfigDict].
Metadata about the fields defined on the model,
mapping of field names to [FieldInfo
][pydantic.fields.FieldInfo] objects.
This replaces Model.__fields__
from Pydantic V1.
A dictionary of computed field names and their corresponding ComputedFieldInfo
objects.
Inherited Members
- pydantic.main.BaseModel
- BaseModel
- model_extra
- model_fields_set
- model_construct
- model_copy
- model_dump
- model_dump_json
- model_json_schema
- model_parametrized_name
- model_post_init
- model_rebuild
- model_validate
- model_validate_json
- model_validate_strings
- dict
- json
- parse_obj
- parse_raw
- parse_file
- from_orm
- construct
- copy
- schema
- schema_json
- validate
- update_forward_refs
87class Names(BaseModel): 88 """Overture names model.""" 89 90 primary: str 91 common: Optional[Dict[str, str]] 92 rules: Optional[List[Rules]]
Overture names model.
Configuration for the model, should be a dictionary conforming to [ConfigDict
][pydantic.config.ConfigDict].
Metadata about the fields defined on the model,
mapping of field names to [FieldInfo
][pydantic.fields.FieldInfo] objects.
This replaces Model.__fields__
from Pydantic V1.
A dictionary of computed field names and their corresponding ComputedFieldInfo
objects.
Inherited Members
- pydantic.main.BaseModel
- BaseModel
- model_extra
- model_fields_set
- model_construct
- model_copy
- model_dump
- model_dump_json
- model_json_schema
- model_parametrized_name
- model_post_init
- model_rebuild
- model_validate
- model_validate_json
- model_validate_strings
- dict
- json
- parse_obj
- parse_raw
- parse_file
- from_orm
- construct
- copy
- schema
- schema_json
- validate
- update_forward_refs
95class PlaceAddress(BaseModel): 96 """Overture addresses model.""" 97 98 freeform: Optional[str] 99 locality: Optional[str] 100 postcode: Optional[str] 101 region: Optional[str] 102 country: Optional[str] = Field(pattern=r"^[A-Z]{2}$")
Overture addresses model.
Configuration for the model, should be a dictionary conforming to [ConfigDict
][pydantic.config.ConfigDict].
Metadata about the fields defined on the model,
mapping of field names to [FieldInfo
][pydantic.fields.FieldInfo] objects.
This replaces Model.__fields__
from Pydantic V1.
A dictionary of computed field names and their corresponding ComputedFieldInfo
objects.
Inherited Members
- pydantic.main.BaseModel
- BaseModel
- model_extra
- model_fields_set
- model_construct
- model_copy
- model_dump
- model_dump_json
- model_json_schema
- model_parametrized_name
- model_post_init
- model_rebuild
- model_validate
- model_validate_json
- model_validate_strings
- dict
- json
- parse_obj
- parse_raw
- parse_file
- from_orm
- construct
- copy
- schema
- schema_json
- validate
- update_forward_refs
105class Categories(BaseModel): 106 """Overture categories model.""" 107 108 main: str 109 alternate: Optional[List[str]]
Overture categories model.
Configuration for the model, should be a dictionary conforming to [ConfigDict
][pydantic.config.ConfigDict].
Metadata about the fields defined on the model,
mapping of field names to [FieldInfo
][pydantic.fields.FieldInfo] objects.
This replaces Model.__fields__
from Pydantic V1.
A dictionary of computed field names and their corresponding ComputedFieldInfo
objects.
Inherited Members
- pydantic.main.BaseModel
- BaseModel
- model_extra
- model_fields_set
- model_construct
- model_copy
- model_dump
- model_dump_json
- model_json_schema
- model_parametrized_name
- model_post_init
- model_rebuild
- model_validate
- model_validate_json
- model_validate_strings
- dict
- json
- parse_obj
- parse_raw
- parse_file
- from_orm
- construct
- copy
- schema
- schema_json
- validate
- update_forward_refs
112class Brand(BaseModel): 113 """Overture brand model.""" 114 115 wikidata: Optional[Wikidata] = None 116 names: Names 117 118 def to_osm(self) -> Dict[str, str]: 119 """Convert brand properties to OSM tags.""" 120 osm = {"brand": self.names.primary} 121 if self.wikidata: 122 osm.update({"brand:wikidata": str(self.wikidata.root)}) 123 return osm
Overture brand model.
118 def to_osm(self) -> Dict[str, str]: 119 """Convert brand properties to OSM tags.""" 120 osm = {"brand": self.names.primary} 121 if self.wikidata: 122 osm.update({"brand:wikidata": str(self.wikidata.root)}) 123 return osm
Convert brand properties to OSM tags.
Configuration for the model, should be a dictionary conforming to [ConfigDict
][pydantic.config.ConfigDict].
Metadata about the fields defined on the model,
mapping of field names to [FieldInfo
][pydantic.fields.FieldInfo] objects.
This replaces Model.__fields__
from Pydantic V1.
A dictionary of computed field names and their corresponding ComputedFieldInfo
objects.
Inherited Members
- pydantic.main.BaseModel
- BaseModel
- model_extra
- model_fields_set
- model_construct
- model_copy
- model_dump
- model_dump_json
- model_json_schema
- model_parametrized_name
- model_post_init
- model_rebuild
- model_validate
- model_validate_json
- model_validate_strings
- dict
- json
- parse_obj
- parse_raw
- parse_file
- from_orm
- construct
- copy
- schema
- schema_json
- validate
- update_forward_refs
126class Socials(RootModel): 127 """Overture socials model.""" 128 129 root: List[str] 130 131 def to_osm(self) -> Dict[str, str]: 132 """Convert socials properties to OSM tags.""" 133 new_props = {} 134 for social in self.root: 135 if "facebook" in social: 136 new_props["contact:facebook"] = social 137 elif "twitter" in str(social): 138 new_props["contact:twitter"] = social 139 return new_props
Overture socials model.
131 def to_osm(self) -> Dict[str, str]: 132 """Convert socials properties to OSM tags.""" 133 new_props = {} 134 for social in self.root: 135 if "facebook" in social: 136 new_props["contact:facebook"] = social 137 elif "twitter" in str(social): 138 new_props["contact:twitter"] = social 139 return new_props
Convert socials properties to OSM tags.
Inherited Members
- pydantic.main.BaseModel
- BaseModel
- model_config
- model_fields
- model_computed_fields
- model_extra
- model_fields_set
- model_construct
- model_copy
- model_dump
- model_dump_json
- model_json_schema
- model_parametrized_name
- model_post_init
- model_rebuild
- model_validate
- model_validate_json
- model_validate_strings
- dict
- json
- parse_obj
- parse_raw
- parse_file
- from_orm
- construct
- copy
- schema
- schema_json
- validate
- update_forward_refs
142class PlaceProps(OvertureBaseModel): 143 """Overture properties model. 144 145 Use this model directly if you want to manipulate the `place` properties yourself. 146 """ 147 148 update_time: str 149 sources: List[Sources] 150 names: Names 151 brand: Optional[Brand] = None 152 categories: Optional[Categories] = None 153 confidence: float = Field(ge=0.0, le=1.0) 154 websites: Optional[List[str]] = None 155 socials: Optional[Socials] = None 156 emails: Optional[List[str]] = None 157 phones: Optional[List[str]] = None 158 addresses: List[PlaceAddress] 159 160 def to_osm( 161 self, confidence: float, region_tag: str, unmatched: str 162 ) -> Dict[str, str]: 163 """Convert Overture's place properties to OSM tags. 164 165 Used internally by the `overturetoosm.process_place` function. 166 """ 167 new_props = {} 168 if self.confidence < confidence: 169 raise ConfidenceError(confidence, self.confidence) 170 171 if self.categories: 172 prim = places_tags.get(self.categories.main) 173 if prim: 174 new_props = {**new_props, **prim} 175 elif unmatched == "force": 176 new_props["type"] = self.categories.main 177 elif unmatched == "error": 178 raise UnmatchedError(self.categories.main) 179 180 if self.names.primary: 181 new_props["name"] = self.names.primary 182 183 if self.phones is not None: 184 new_props["phone"] = self.phones[0] 185 186 if self.websites is not None and self.websites[0]: 187 new_props["website"] = str(self.websites[0]) 188 189 if add := self.addresses[0]: 190 if add.freeform: 191 new_props["addr:street_address"] = add.freeform 192 if add.country: 193 new_props["addr:country"] = add.country 194 if add.postcode: 195 new_props["addr:postcode"] = add.postcode 196 if add.locality: 197 new_props["addr:city"] = add.locality 198 if add.region: 199 new_props[region_tag] = add.region 200 201 if self.sources: 202 new_props["source"] = source_statement(self.sources) 203 204 if self.socials: 205 new_props.update(self.socials.to_osm()) 206 207 if self.brand: 208 new_props.update(self.brand.to_osm()) 209 210 return new_props
Overture properties model.
Use this model directly if you want to manipulate the place
properties yourself.
160 def to_osm( 161 self, confidence: float, region_tag: str, unmatched: str 162 ) -> Dict[str, str]: 163 """Convert Overture's place properties to OSM tags. 164 165 Used internally by the `overturetoosm.process_place` function. 166 """ 167 new_props = {} 168 if self.confidence < confidence: 169 raise ConfidenceError(confidence, self.confidence) 170 171 if self.categories: 172 prim = places_tags.get(self.categories.main) 173 if prim: 174 new_props = {**new_props, **prim} 175 elif unmatched == "force": 176 new_props["type"] = self.categories.main 177 elif unmatched == "error": 178 raise UnmatchedError(self.categories.main) 179 180 if self.names.primary: 181 new_props["name"] = self.names.primary 182 183 if self.phones is not None: 184 new_props["phone"] = self.phones[0] 185 186 if self.websites is not None and self.websites[0]: 187 new_props["website"] = str(self.websites[0]) 188 189 if add := self.addresses[0]: 190 if add.freeform: 191 new_props["addr:street_address"] = add.freeform 192 if add.country: 193 new_props["addr:country"] = add.country 194 if add.postcode: 195 new_props["addr:postcode"] = add.postcode 196 if add.locality: 197 new_props["addr:city"] = add.locality 198 if add.region: 199 new_props[region_tag] = add.region 200 201 if self.sources: 202 new_props["source"] = source_statement(self.sources) 203 204 if self.socials: 205 new_props.update(self.socials.to_osm()) 206 207 if self.brand: 208 new_props.update(self.brand.to_osm()) 209 210 return new_props
Convert Overture's place properties to OSM tags.
Used internally by the overturetoosm.process_place
function.
Configuration for the model, should be a dictionary conforming to [ConfigDict
][pydantic.config.ConfigDict].
Metadata about the fields defined on the model,
mapping of field names to [FieldInfo
][pydantic.fields.FieldInfo] objects.
This replaces Model.__fields__
from Pydantic V1.
A dictionary of computed field names and their corresponding ComputedFieldInfo
objects.
Inherited Members
- pydantic.main.BaseModel
- BaseModel
- model_extra
- model_fields_set
- model_construct
- model_copy
- model_dump
- model_dump_json
- model_json_schema
- model_parametrized_name
- model_post_init
- model_rebuild
- model_validate
- model_validate_json
- model_validate_strings
- dict
- json
- parse_obj
- parse_raw
- parse_file
- from_orm
- construct
- copy
- schema
- schema_json
- validate
- update_forward_refs
213class ConfidenceError(Exception): 214 """Confidence error exception. 215 216 This exception is raised when the confidence level of an item is below the 217 user-defined level. It contains the original confidence level and the confidence 218 level of the item. 219 220 Attributes: 221 confidence_level (float): The set confidence level. 222 confidence_item (float): The confidence of the item. 223 message (str): The error message. 224 """ 225 226 def __init__( 227 self, 228 confidence_level: float, 229 confidence_item: float, 230 message: str = "Confidence in this item is too low.", 231 ) -> None: 232 """@private""" 233 self.confidence_level = confidence_level 234 self.confidence_item = confidence_item 235 self.message = message 236 super().__init__(message) 237 238 def __str__(self) -> str: 239 """@private""" 240 lev = f"confidence_level={self.confidence_level}" 241 item = f"confidence_item={self.confidence_item}" 242 return f"""{self.message} {lev}, {item}"""
Confidence error exception.
This exception is raised when the confidence level of an item is below the user-defined level. It contains the original confidence level and the confidence level of the item.
Attributes:
- confidence_level (float): The set confidence level.
- confidence_item (float): The confidence of the item.
- message (str): The error message.
Inherited Members
- builtins.BaseException
- with_traceback
- add_note
- args
245class UnmatchedError(Exception): 246 """Unmatched category error. 247 248 This exception is raised when an item's Overture category does not have a 249 corresponding OSM definition. Edit 250 [the OSM Wiki page](https://wiki.openstreetmap.org/wiki/Overture_categories) 251 to add a definition to this category. 252 253 Attributes: 254 category (str): The Overture category that is unmatched. 255 message (str): The error message. 256 """ 257 258 def __init__( 259 self, category: str, message: str = "Overture category is unmatched." 260 ) -> None: 261 """@private""" 262 self.category = category 263 self.message = message 264 super().__init__(message) 265 266 def __str__(self) -> str: 267 """@private""" 268 return f"{self.message} {{category={self.category}}}"
Unmatched category error.
This exception is raised when an item's Overture category does not have a corresponding OSM definition. Edit the OSM Wiki page to add a definition to this category.
Attributes:
- category (str): The Overture category that is unmatched.
- message (str): The error message.
Inherited Members
- builtins.BaseException
- with_traceback
- add_note
- args
271class BuildingProps(OvertureBaseModel): 272 """Overture building properties. 273 274 Use this model if you want to manipulate the `building` properties yourself. 275 """ 276 277 has_parts: bool 278 sources: List[Sources] 279 class_: Optional[str] = Field(alias="class", default=None) 280 subtype: Optional[str] = None 281 names: Optional[Names] = None 282 level: Optional[int] = None 283 height: Optional[float] = None 284 is_underground: Optional[bool] = None 285 num_floors: Optional[int] = Field( 286 serialization_alias="building:levels", default=None 287 ) 288 num_floors_underground: Optional[int] = Field( 289 serialization_alias="building:levels:underground", default=None 290 ) 291 min_height: Optional[float] = None 292 min_floor: Optional[int] = Field( 293 serialization_alias="building:min_level", default=None 294 ) 295 facade_color: Optional[str] = Field( 296 serialization_alias="building:colour", default=None 297 ) 298 facade_material: Optional[str] = Field( 299 serialization_alias="building:material", default=None 300 ) 301 roof_material: Optional[str] = Field( 302 serialization_alias="roof:material", default=None 303 ) 304 roof_shape: Optional[str] = Field(serialization_alias="roof:shape", default=None) 305 roof_direction: Optional[str] = Field( 306 serialization_alias="roof:direction", default=None 307 ) 308 roof_orientation: Optional[str] = Field( 309 serialization_alias="roof:orientation", default=None 310 ) 311 roof_color: Optional[str] = Field(serialization_alias="roof:colour", default=None) 312 roof_height: Optional[float] = Field( 313 serialization_alias="roof:height", default=None 314 ) 315 316 def to_osm(self, confidence: float) -> Dict[str, str]: 317 """Convert properties to OSM tags. 318 319 Used internally by`overturetoosm.process_building` function. 320 """ 321 new_props = {} 322 confidences = {source.confidence for source in self.sources} 323 if any(conf and conf < confidence for conf in confidences): 324 raise ConfidenceError(confidence, max({i for i in confidences if i})) 325 326 new_props["building"] = self.class_ if self.class_ else "yes" 327 328 new_props["source"] = source_statement(self.sources) 329 330 prop_obj = self.model_dump(exclude_none=True, by_alias=True).items() 331 new_props.update( 332 {k: v for k, v in prop_obj if k.startswith(("roof", "building"))} 333 ) 334 new_props.update({k: round(v, 2) for k, v in prop_obj if k.endswith("height")}) 335 336 if self.is_underground: 337 new_props["location"] = "underground" 338 if self.names: 339 new_props["name"] = self.names.primary 340 return new_props
Overture building properties.
Use this model if you want to manipulate the building
properties yourself.
316 def to_osm(self, confidence: float) -> Dict[str, str]: 317 """Convert properties to OSM tags. 318 319 Used internally by`overturetoosm.process_building` function. 320 """ 321 new_props = {} 322 confidences = {source.confidence for source in self.sources} 323 if any(conf and conf < confidence for conf in confidences): 324 raise ConfidenceError(confidence, max({i for i in confidences if i})) 325 326 new_props["building"] = self.class_ if self.class_ else "yes" 327 328 new_props["source"] = source_statement(self.sources) 329 330 prop_obj = self.model_dump(exclude_none=True, by_alias=True).items() 331 new_props.update( 332 {k: v for k, v in prop_obj if k.startswith(("roof", "building"))} 333 ) 334 new_props.update({k: round(v, 2) for k, v in prop_obj if k.endswith("height")}) 335 336 if self.is_underground: 337 new_props["location"] = "underground" 338 if self.names: 339 new_props["name"] = self.names.primary 340 return new_props
Convert properties to OSM tags.
Used internally byoverturetoosm.process_building
function.
Configuration for the model, should be a dictionary conforming to [ConfigDict
][pydantic.config.ConfigDict].
Metadata about the fields defined on the model,
mapping of field names to [FieldInfo
][pydantic.fields.FieldInfo] objects.
This replaces Model.__fields__
from Pydantic V1.
A dictionary of computed field names and their corresponding ComputedFieldInfo
objects.
Inherited Members
- pydantic.main.BaseModel
- BaseModel
- model_extra
- model_fields_set
- model_construct
- model_copy
- model_dump
- model_dump_json
- model_json_schema
- model_parametrized_name
- model_post_init
- model_rebuild
- model_validate
- model_validate_json
- model_validate_strings
- dict
- json
- parse_obj
- parse_raw
- parse_file
- from_orm
- construct
- copy
- schema
- schema_json
- validate
- update_forward_refs
Overture address level model.
Configuration for the model, should be a dictionary conforming to [ConfigDict
][pydantic.config.ConfigDict].
Metadata about the fields defined on the model,
mapping of field names to [FieldInfo
][pydantic.fields.FieldInfo] objects.
This replaces Model.__fields__
from Pydantic V1.
A dictionary of computed field names and their corresponding ComputedFieldInfo
objects.
Inherited Members
- pydantic.main.BaseModel
- BaseModel
- model_extra
- model_fields_set
- model_construct
- model_copy
- model_dump
- model_dump_json
- model_json_schema
- model_parametrized_name
- model_post_init
- model_rebuild
- model_validate
- model_validate_json
- model_validate_strings
- dict
- json
- parse_obj
- parse_raw
- parse_file
- from_orm
- construct
- copy
- schema
- schema_json
- validate
- update_forward_refs
349class AddressProps(OvertureBaseModel): 350 """Overture address properties. 351 352 Use this model directly if you want to manipulate the `address` properties yourself. 353 """ 354 355 number: Optional[str] = Field(serialization_alias="addr:housenumber") 356 street: Optional[str] = Field(serialization_alias="addr:street") 357 postcode: Optional[str] = Field(serialization_alias="addr:postcode") 358 country: Optional[str] = Field(serialization_alias="addr:country") 359 address_levels: Optional[ 360 Annotated[List[AddressLevel], Field(min_length=1, max_length=5)] 361 ] = Field(default_factory=list) 362 sources: List[Sources] 363 364 def to_osm(self, style: str) -> Dict[str, str]: 365 """Convert properties to OSM tags. 366 367 Used internally by `overturetoosm.process_address`. 368 """ 369 obj_dict = { 370 k: v 371 for k, v in self.model_dump(exclude_none=True, by_alias=True).items() 372 if k.startswith("addr:") 373 } 374 obj_dict["source"] = source_statement(self.sources) 375 376 if self.address_levels and len(self.address_levels) > 0 and style == "US": 377 obj_dict["addr:state"] = str(self.address_levels[0].value) 378 379 return obj_dict
Overture address properties.
Use this model directly if you want to manipulate the address
properties yourself.
364 def to_osm(self, style: str) -> Dict[str, str]: 365 """Convert properties to OSM tags. 366 367 Used internally by `overturetoosm.process_address`. 368 """ 369 obj_dict = { 370 k: v 371 for k, v in self.model_dump(exclude_none=True, by_alias=True).items() 372 if k.startswith("addr:") 373 } 374 obj_dict["source"] = source_statement(self.sources) 375 376 if self.address_levels and len(self.address_levels) > 0 and style == "US": 377 obj_dict["addr:state"] = str(self.address_levels[0].value) 378 379 return obj_dict
Convert properties to OSM tags.
Used internally by overturetoosm.process_address
.
Configuration for the model, should be a dictionary conforming to [ConfigDict
][pydantic.config.ConfigDict].
Metadata about the fields defined on the model,
mapping of field names to [FieldInfo
][pydantic.fields.FieldInfo] objects.
This replaces Model.__fields__
from Pydantic V1.
A dictionary of computed field names and their corresponding ComputedFieldInfo
objects.
Inherited Members
- pydantic.main.BaseModel
- BaseModel
- model_extra
- model_fields_set
- model_construct
- model_copy
- model_dump
- model_dump_json
- model_json_schema
- model_parametrized_name
- model_post_init
- model_rebuild
- model_validate
- model_validate_json
- model_validate_strings
- dict
- json
- parse_obj
- parse_raw
- parse_file
- from_orm
- construct
- copy
- schema
- schema_json
- validate
- update_forward_refs
382def source_statement(source: List[Sources]) -> str: 383 """Return a source statement from a list of sources.""" 384 return ( 385 ", ".join(sorted({i.dataset.strip(", ") for i in source})) 386 + " via overturetoosm" 387 )
Return a source statement from a list of sources.