Skip to content

Commit

Permalink
fix type annotations for container
Browse files Browse the repository at this point in the history
  • Loading branch information
cleder committed Nov 23, 2023
1 parent 0cf42fa commit b9767c0
Show file tree
Hide file tree
Showing 4 changed files with 404 additions and 208 deletions.
152 changes: 107 additions & 45 deletions fastkml/containers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,35 @@
import logging
import urllib.parse as urlparse
from typing import Dict
from typing import Iterable
from typing import Iterator
from typing import List
from typing import Optional
from typing import Union
from typing import cast

from fastkml import atom
from fastkml import gx
from fastkml.data import ExtendedData
from fastkml.data import Schema
from fastkml.enums import Verbosity
from fastkml.features import Placemark
from fastkml.features import Snippet
from fastkml.features import _Feature
from fastkml.geometry import LinearRing
from fastkml.geometry import LineString
from fastkml.geometry import MultiGeometry
from fastkml.geometry import Point
from fastkml.geometry import Polygon
from fastkml.overlays import _Overlay
from fastkml.styles import Style
from fastkml.styles import StyleMap
from fastkml.styles import StyleUrl
from fastkml.times import TimeSpan
from fastkml.times import TimeStamp
from fastkml.types import Element
from fastkml.views import Camera
from fastkml.views import LookAt
from fastkml.views import Region

logger = logging.getLogger(__name__)

Expand All @@ -45,7 +55,7 @@ class _Container(_Feature):
Folder.
"""

_features = []
_features: Optional[List[_Feature]]

def __init__(
self,
Expand All @@ -54,36 +64,50 @@ def __init__(
id: Optional[str] = None,
target_id: Optional[str] = None,
name: Optional[str] = None,
visibility: Optional[bool] = None,
isopen: Optional[bool] = None,
atom_link: Optional[atom.Link] = None,
atom_author: Optional[atom.Author] = None,
address: Optional[str] = None,
phone_number: Optional[str] = None,
snippet: Optional[Snippet] = None,
description: Optional[str] = None,
view: Optional[Union[Camera, LookAt]] = None,
times: Optional[Union[TimeSpan, TimeStamp]] = None,
style_url: Optional[StyleUrl] = None,
styles: Optional[List[Style]] = None,
style_url: Optional[str] = None,
features: None = None,
region: Optional[Region] = None,
extended_data: Optional[ExtendedData] = None,
# Container specific
features: Optional[List[_Feature]] = None,
) -> None:
super().__init__(
ns=ns,
name_spaces=name_spaces,
id=id,
target_id=target_id,
name=name,
visibility=visibility,
isopen=isopen,
atom_link=atom_link,
atom_author=atom_author,
address=address,
phone_number=phone_number,
snippet=snippet,
description=description,
styles=styles,
view=view,
times=times,
style_url=style_url,
styles=styles,
region=region,
extended_data=extended_data,
)
self._features = features or []

def features(self) -> Iterator[_Feature]:
"""Iterate over features."""
for feature in self._features:
if isinstance(feature, (Folder, Placemark, Document, _Overlay)):
yield feature
else:
msg = (
"Features must be instances of "
"(Folder, Placemark, Document, Overlay)"
)
raise TypeError(
msg,
)
assert self._features is not None
yield from self._features

def etree_element(
self,
Expand All @@ -97,16 +121,11 @@ def etree_element(

def append(self, kmlobj: _Feature) -> None:
"""Append a feature."""
if id(kmlobj) == id(self):
if kmlobj is self:
msg = "Cannot append self"
raise ValueError(msg)
if isinstance(kmlobj, (Folder, Placemark, Document, _Overlay)):
self._features.append(kmlobj)
else:
msg = "Features must be instances of (Folder, Placemark, Document, Overlay)"
raise TypeError(
msg,
)
assert self._features is not None
self._features.append(kmlobj)


class Folder(_Container):
Expand All @@ -117,7 +136,7 @@ class Folder(_Container):

__name__ = "Folder"

def from_element(self, element: Element) -> None:
def from_element(self, element: Element, strict: bool = False) -> None:
super().from_element(element)
folders = element.findall(f"{self.ns}Folder")
for folder in folders:
Expand All @@ -126,12 +145,12 @@ def from_element(self, element: Element) -> None:
self.append(feature)
placemarks = element.findall(f"{self.ns}Placemark")
for placemark in placemarks:
feature = Placemark(self.ns)
feature = Placemark(self.ns) # type: ignore[assignment]
feature.from_element(placemark)
self.append(feature)
documents = element.findall(f"{self.ns}Document")
for document in documents:
feature = Document(self.ns)
feature = Document(self.ns) # type: ignore[assignment]
feature.from_element(document)
self.append(feature)

Expand All @@ -144,20 +163,63 @@ class Document(_Container):
"""

__name__ = "Document"
_schemata = None
_schemata: Optional[List[Schema]]

def __init__(
self,
ns: Optional[str] = None,
name_spaces: Optional[Dict[str, str]] = None,
id: Optional[str] = None,
target_id: Optional[str] = None,
name: Optional[str] = None,
visibility: Optional[bool] = None,
isopen: Optional[bool] = None,
atom_link: Optional[atom.Link] = None,
atom_author: Optional[atom.Author] = None,
address: Optional[str] = None,
phone_number: Optional[str] = None,
snippet: Optional[Snippet] = None,
description: Optional[str] = None,
view: Optional[Union[Camera, LookAt]] = None,
times: Optional[Union[TimeSpan, TimeStamp]] = None,
style_url: Optional[StyleUrl] = None,
styles: Optional[List[Style]] = None,
region: Optional[Region] = None,
extended_data: Optional[ExtendedData] = None,
features: Optional[List[_Feature]] = None,
schemata: Optional[Iterable[Schema]] = None,
) -> None:
super().__init__(
ns=ns,
name_spaces=name_spaces,
id=id,
target_id=target_id,
name=name,
visibility=visibility,
isopen=isopen,
atom_link=atom_link,
atom_author=atom_author,
address=address,
phone_number=phone_number,
snippet=snippet,
description=description,
view=view,
times=times,
style_url=style_url,
styles=styles,
region=region,
extended_data=extended_data,
features=features,
)
self._schemata = list(schemata) if schemata else []

def schemata(self) -> Iterator["Schema"]:
def schemata(self) -> Iterator[Schema]:
if self._schemata:
yield from self._schemata

def append_schema(self, schema: "Schema") -> None:
if self._schemata is None:
self._schemata = []
if isinstance(schema, Schema):
self._schemata.append(schema)
else:
s = Schema(schema)
self._schemata.append(s)
def append_schema(self, schema: Schema) -> None:
assert self._schemata is not None
self._schemata.append(schema)

def from_element(self, element: Element, strict: bool = False) -> None:
super().from_element(element)
Expand All @@ -168,17 +230,20 @@ def from_element(self, element: Element, strict: bool = False) -> None:
self.append(feature)
folders = element.findall(f"{self.ns}Folder")
for folder in folders:
feature = Folder(self.ns)
feature = Folder(self.ns) # type: ignore[assignment]
feature.from_element(folder)
self.append(feature)
placemarks = element.findall(f"{self.ns}Placemark")
for placemark in placemarks:
feature = Placemark(self.ns)
feature = Placemark(self.ns) # type: ignore[assignment]
feature.from_element(placemark)
self.append(feature)
schemata = element.findall(f"{self.ns}Schema")
for schema in schemata:
s = Schema.class_from_element(ns=self.ns, element=schema, strict=strict)
s = cast(
Schema,
Schema.class_from_element(ns=self.ns, element=schema, strict=strict),
)
self.append_schema(s)

def etree_element(
Expand All @@ -193,8 +258,5 @@ def etree_element(
return element

def get_style_by_url(self, style_url: str) -> Optional[Union[Style, StyleMap]]:
id = urlparse.urlparse(style_url).fragment
for style in self.styles():
if style.id == id:
return style
return None
id_ = urlparse.urlparse(style_url).fragment
return next((style for style in self.styles() if style.id == id_), None)
Loading

0 comments on commit b9767c0

Please sign in to comment.