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