From b9767c0df35dac2ee4342caadf56e22fa2f4258b Mon Sep 17 00:00:00 2001 From: Christian Ledermann Date: Thu, 23 Nov 2023 19:41:34 +0000 Subject: [PATCH] fix type annotations for container --- fastkml/containers.py | 152 ++++++++++++++++++-------- fastkml/features.py | 199 ++++++++++++++++++++++------------ fastkml/overlays.py | 236 ++++++++++++++++++++++++++++------------- tests/overlays_test.py | 25 +---- 4 files changed, 404 insertions(+), 208 deletions(-) diff --git a/fastkml/containers.py b/fastkml/containers.py index e467734b..4bf54a55 100644 --- a/fastkml/containers.py +++ b/fastkml/containers.py @@ -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__) @@ -45,7 +55,7 @@ class _Container(_Feature): Folder. """ - _features = [] + _features: Optional[List[_Feature]] def __init__( self, @@ -54,10 +64,22 @@ 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, @@ -65,25 +87,27 @@ def __init__( 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, @@ -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): @@ -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: @@ -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) @@ -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) @@ -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( @@ -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) diff --git a/fastkml/features.py b/fastkml/features.py index 0b224651..be40f1b5 100644 --- a/fastkml/features.py +++ b/fastkml/features.py @@ -291,25 +291,40 @@ def etree_element( ) -> Element: element = super().etree_element(precision=precision, verbosity=verbosity) if self.name: - name = config.etree.SubElement(element, f"{self.ns}name") + name = config.etree.SubElement( # type: ignore[attr-defined] + element, + f"{self.ns}name", + ) name.text = self.name if self.description: - description = config.etree.SubElement(element, f"{self.ns}description") + description = config.etree.SubElement( # type: ignore[attr-defined] + element, + f"{self.ns}description", + ) description.text = self.description if self._view is not None: element.append(self._view.etree_element()) if self.visibility is not None: - visibility = config.etree.SubElement(element, f"{self.ns}visibility") - visibility.text = str(self.visibility) + visibility = config.etree.SubElement( # type: ignore[attr-defined] + element, + f"{self.ns}visibility", + ) + visibility.text = str(int(self.visibility)) if self.isopen: - isopen = config.etree.SubElement(element, f"{self.ns}open") - isopen.text = str(self.isopen) + isopen = config.etree.SubElement( # type: ignore[attr-defined] + element, + f"{self.ns}open", + ) + isopen.text = str(int(self.isopen)) if self._style_url is not None: element.append(self._style_url.etree_element()) for style in self.styles(): element.append(style.etree_element()) if self.snippet: - snippet = config.etree.SubElement(element, f"{self.ns}Snippet") + snippet = config.etree.SubElement( # type: ignore[attr-defined] + element, + f"{self.ns}Snippet", + ) snippet.text = self.snippet.text if self.snippet.max_lines: snippet.set("maxLines", str(self.snippet.max_lines)) @@ -322,10 +337,16 @@ def etree_element( if self.extended_data is not None: element.append(self.extended_data.etree_element()) if self._address is not None: - address = config.etree.SubElement(element, f"{self.ns}address") + address = config.etree.SubElement( # type: ignore[attr-defined] + element, + f"{self.ns}address", + ) address.text = self._address if self._phone_number is not None: - phone_number = config.etree.SubElement(element, f"{self.ns}phoneNumber") + phone_number = config.etree.SubElement( # type: ignore[attr-defined] + element, + f"{self.ns}phoneNumber", + ) phone_number.text = self._phone_number return element @@ -397,26 +418,35 @@ def from_element(self, element: Element, strict: bool = False) -> None: ) atom_link = element.find(f"{atom.NS}link") if atom_link is not None: - self._atom_link = atom.Link.class_from_element( - ns=atom.NS, - name_spaces=self.name_spaces, - element=atom_link, - strict=strict, + self._atom_link = cast( + atom.Link, + atom.Link.class_from_element( + ns=atom.NS, + name_spaces=self.name_spaces, + element=atom_link, + strict=strict, + ), ) atom_author = element.find(f"{atom.NS}author") if atom_author is not None: - self._atom_author = atom.Author.class_from_element( - ns=atom.NS, - name_spaces=self.name_spaces, - element=atom_author, - strict=strict, + self._atom_author = cast( + atom.Author, + atom.Author.class_from_element( + ns=atom.NS, + name_spaces=self.name_spaces, + element=atom_author, + strict=strict, + ), ) extended_data = element.find(f"{self.ns}ExtendedData") if extended_data is not None: - self.extended_data = ExtendedData.class_from_element( - ns=self.ns, - element=extended_data, - strict=strict, + self.extended_data = cast( + ExtendedData, + ExtendedData.class_from_element( + ns=self.ns, + element=extended_data, + strict=strict, + ), ) address = element.find(f"{self.ns}address") if address is not None: @@ -426,17 +456,23 @@ def from_element(self, element: Element, strict: bool = False) -> None: self.phone_number = phone_number.text camera = element.find(f"{self.ns}Camera") if camera is not None: - self._view = Camera.class_from_element( - ns=self.ns, - element=camera, - strict=strict, + self._view = cast( + Camera, + Camera.class_from_element( + ns=self.ns, + element=camera, + strict=strict, + ), ) lookat = element.find(f"{self.ns}LookAt") if lookat is not None: - self._view = LookAt.class_from_element( - ns=self.ns, - element=lookat, - strict=strict, + self._view = cast( + LookAt, + LookAt.class_from_element( + ns=self.ns, + element=lookat, + strict=strict, + ), ) @@ -508,62 +544,86 @@ def from_element(self, element: Element, strict: bool = False) -> None: super().from_element(element) point = element.find(f"{self.ns}Point") if point is not None: - self._geometry = Point.class_from_element( - ns=self.ns, - element=point, - strict=strict, + self._geometry = cast( + Point, + Point.class_from_element( + ns=self.ns, + element=point, + strict=strict, + ), ) return line = element.find(f"{self.ns}LineString") if line is not None: - self._geometry = LineString.class_from_element( - ns=self.ns, - element=line, - strict=strict, + self._geometry = cast( + LineString, + LineString.class_from_element( + ns=self.ns, + element=line, + strict=strict, + ), ) return polygon = element.find(f"{self.ns}Polygon") if polygon is not None: - self._geometry = Polygon.class_from_element( - ns=self.ns, - element=polygon, - strict=strict, + self._geometry = cast( + Polygon, + Polygon.class_from_element( + ns=self.ns, + element=polygon, + strict=strict, + ), ) return linearring = element.find(f"{self.ns}LinearRing") if linearring is not None: - self._geometry = LinearRing.class_from_element( - ns=self.ns, - element=linearring, - strict=strict, + self._geometry = cast( + LinearRing, + LinearRing.class_from_element( + ns=self.ns, + element=linearring, + strict=strict, + ), ) return multigeometry = element.find(f"{self.ns}MultiGeometry") if multigeometry is not None: - self._geometry = MultiGeometry.class_from_element( - ns=self.ns, - element=multigeometry, - strict=strict, + self._geometry = cast( + MultiGeometry, + MultiGeometry.class_from_element( + ns=self.ns, + element=multigeometry, + strict=strict, + ), ) return track = element.find(f"{self.ns}Track") if track is not None: - self._geometry = gx.Track.class_from_element( - ns=config.GXNS, - element=track, - strict=strict, + self._geometry = cast( + gx.Track, + gx.Track.class_from_element( + ns=config.GXNS, + element=track, + strict=strict, + ), ) return multitrack = element.find(f"{self.ns}MultiTrack") if multitrack is not None: - self._geometry = gx.MultiTrack.class_from_element( - ns=config.GXNS, - element=multitrack, - strict=strict, + self._geometry = cast( + gx.MultiTrack, + gx.MultiTrack.class_from_element( + ns=config.GXNS, + element=multitrack, + strict=strict, + ), ) return logger.warning("No geometries found") - logger.debug("Problem with element: %", config.etree.tostring(element)) + logger.debug( + "Problem with element: %", + config.etree.tostring(element), # type: ignore[attr-defined] + ) def etree_element( self, @@ -620,7 +680,7 @@ class NetworkLink(_Feature): refresh_visibility: Optional[bool] fly_to_view: Optional[bool] - link: Optional[Link] + _link: Optional[Link] __name__ = "NetworkLink" @@ -673,7 +733,7 @@ def __init__( ) self.refresh_visibility = refresh_visibility self.fly_to_view = fly_to_view - self.link = link + self._link = link def etree_element( self, @@ -698,7 +758,7 @@ def etree_element( element.append(self.link.etree_element()) return element - def from_element(self, element: Element, strict=False) -> None: + def from_element(self, element: Element, strict: bool = False) -> None: super(_Feature, self).from_element(element) visibility = element.find(f"{self.ns}refreshVisibility") @@ -710,9 +770,12 @@ def from_element(self, element: Element, strict=False) -> None: link = element.find(f"{self.ns}Link") if link is not None: - self.link = Link.class_from_element( - ns=self.ns, - name_spaces=self.name_spaces, - element=link, - strict=strict, + self._link = cast( + Link, + Link.class_from_element( + ns=self.ns, + name_spaces=self.name_spaces, + element=link, + strict=strict, + ), ) diff --git a/fastkml/overlays.py b/fastkml/overlays.py index f966581b..65325083 100644 --- a/fastkml/overlays.py +++ b/fastkml/overlays.py @@ -1,18 +1,21 @@ """Overlays.""" import logging -from typing import Any from typing import Dict from typing import List from typing import Optional from typing import Union +from typing import cast from fastkml import atom from fastkml import config from fastkml import gx +from fastkml.base import _XMLObject +from fastkml.data import ExtendedData from fastkml.enums import GridOrigin from fastkml.enums import Shape from fastkml.enums import Verbosity +from fastkml.features import Snippet from fastkml.features import _Feature from fastkml.geometry import LinearRing from fastkml.geometry import LineString @@ -21,11 +24,13 @@ from fastkml.geometry import Polygon from fastkml.links import Icon from fastkml.styles import Style +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__) @@ -75,19 +80,21 @@ def __init__( id: Optional[str] = None, target_id: Optional[str] = None, name: Optional[str] = None, - description: Optional[str] = None, - snippet: Optional[Union[str, Dict[str, Any]]] = None, - atom_author: Optional[atom.Author] = None, - atom_link: Optional[atom.Link] = None, visibility: Optional[bool] = None, isopen: Optional[bool] = None, - styles: Optional[List[Style]] = None, - style_url: Optional[str] = None, - extended_data: None = None, - view: Optional[Union[Camera, LookAt]] = 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, + # Overlay specific color: Optional[str] = None, draw_order: Optional[str] = None, icon: Optional[Icon] = None, @@ -98,62 +105,48 @@ def __init__( id=id, target_id=target_id, name=name, - description=description, - styles=styles, - style_url=style_url, - snippet=snippet, - atom_author=atom_author, - atom_link=atom_link, visibility=visibility, isopen=isopen, - extended_data=extended_data, - view=view, + 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, ) self._icon = icon self._color = color self._draw_order = draw_order @property - def color(self): + def color(self) -> Optional[str]: return self._color @color.setter - def color(self, color) -> None: - if isinstance(color, str): - self._color = color - elif color is None: - self._color = None - else: - raise ValueError + def color(self, color: Optional[str]) -> None: + self._color = color @property def draw_order(self) -> Optional[str]: return self._draw_order @draw_order.setter - def draw_order(self, value) -> None: - if isinstance(value, (str, int, float)): - self._draw_order = str(value) - elif value is None: - self._draw_order = None - else: - raise ValueError + def draw_order(self, value: Optional[str]) -> None: + self._draw_order = value @property def icon(self) -> Optional[Icon]: return self._icon @icon.setter - def icon(self, value) -> None: - if isinstance(value, Icon): - self._icon = value - elif value is None: - self._icon = None - else: - raise ValueError + def icon(self, value: Optional[Icon]) -> None: + self._icon = value def etree_element( self, @@ -162,17 +155,23 @@ def etree_element( ) -> Element: element = super().etree_element(precision=precision, verbosity=verbosity) if self._color: - color = config.etree.SubElement(element, f"{self.ns}color") + color = config.etree.SubElement( # type: ignore[attr-defined] + element, + f"{self.ns}color", + ) color.text = self._color if self._draw_order: - draw_order = config.etree.SubElement(element, f"{self.ns}drawOrder") - draw_order.text = self._draw_order + draw_order = config.etree.SubElement( # type: ignore[attr-defined] + element, + f"{self.ns}drawOrder", + ) + draw_order.text = str(self._draw_order) if self._icon: element.append(self._icon.etree_element()) return element - def from_element(self, element: Element) -> None: - super().from_element(element) + def from_element(self, element: Element, strict: bool = False) -> None: + super().from_element(element=element, strict=strict) color = element.find(f"{self.ns}color") if color is not None: self.color = color.text @@ -181,14 +180,67 @@ def from_element(self, element: Element) -> None: self.draw_order = draw_order.text icon = element.find(f"{self.ns}Icon") if icon is not None: - self._icon = Icon.class_from_element( - ns=self.ns, - name_spaces=self.name_spaces, - element=icon, - strict=False, + self._icon = cast( + Icon, + Icon.class_from_element( + ns=self.ns, + name_spaces=self.name_spaces, + element=icon, + strict=False, + ), ) +class ViewVolume(_XMLObject): + """ + The ViewVolume defines how much of the current scene is visible. + + Specifying the field of view is analogous to specifying the lens opening in a + physical camera. + A small field of view, like a telephoto lens, focuses on a small part of the scene. + A large field of view, like a wide-angle lens, focuses on a large part of the scene. + + https://developers.google.com/kml/documentation/kmlreference#viewvolume + """ + + left_fow: Optional[float] + # Angle, in degrees, between the camera's viewing direction and the left side + # of the view volume. + + right_fov: Optional[float] + # Angle, in degrees, between the camera's viewing direction and the right side + # of the view volume. + + bottom_fov: Optional[float] + # Angle, in degrees, between the camera's viewing direction and the bottom side + # of the view volume. + + top_fov: Optional[float] + # Angle, in degrees, between the camera's viewing direction and the top side + # of the view volume. + + near: Optional[float] + # Measurement in meters along the viewing direction from the camera viewpoint + # to the PhotoOverlay shape. + + def __init__( + self, + ns: Optional[str] = None, + name_spaces: Optional[Dict[str, str]] = None, + left_fov: Optional[float] = None, + right_fov: Optional[float] = None, + bottom_fov: Optional[float] = None, + top_fov: Optional[float] = None, + near: Optional[float] = None, + ) -> None: + super().__init__(ns=ns, name_spaces=name_spaces) + self.left_fov = left_fov + self.right_fov = right_fov + self.bottom_fov = bottom_fov + self.top_fov = top_fov + self.near = near + + class PhotoOverlay(_Overlay): """ The element allows you to geographically locate a photograph @@ -211,41 +263,23 @@ class PhotoOverlay(_Overlay): element that specifies the image file to use for the PhotoOverlay. In the case of a very large image, the is a special URL that indexes into a pyramid of images of varying resolutions (see ImagePyramid). + + https://developers.google.com/kml/documentation/kmlreference#photooverlay """ __name__ = "PhotoOverlay" - _rotation = None + _rotation: Optional[float] # Adjusts how the photo is placed inside the field of view. This element is # useful if your photo has been rotated and deviates slightly from a desired # horizontal view. - # - ViewVolume - - # Defines how much of the current scene is visible. Specifying the field of - # view is analogous to specifying the lens opening in a physical camera. - # A small field of view, like a telephoto lens, focuses on a small part of - # the scene. A large field of view, like a wide-angle lens, focuses on a - # large part of the scene. + _view_volume: Optional[ViewVolume] + # Defines how much of the current scene is visible. - _left_fow = None - # Angle, in degrees, between the camera's viewing direction and the left side - # of the view volume. - - _right_fov = None - # Angle, in degrees, between the camera's viewing direction and the right side - # of the view volume. - - _bottom_fov = None - # Angle, in degrees, between the camera's viewing direction and the bottom side - # of the view volume. - - _top_fov = None - # Angle, in degrees, between the camera's viewing direction and the top side - # of the view volume. - - _near = None - # Measurement in meters along the viewing direction from the camera viewpoint - # to the PhotoOverlay shape. + # _image_pyramid: Optional[ImagePyramid] + # Defines the format, resolution, and refresh rate for images that are + # displayed in the PhotoOverlay. _tile_size = "256" # Size of the tiles, in pixels. Tiles must be square, and must @@ -279,6 +313,58 @@ class PhotoOverlay(_Overlay): # sphere - # for spherical panoramas + 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, + color: Optional[str] = None, + draw_order: Optional[str] = None, + icon: Optional[Icon] = None, + # Photo Overlay specific + ) -> 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, + color=color, + draw_order=draw_order, + icon=icon, + ) + self._rotation = None + @property def rotation(self) -> Optional[str]: return self._rotation diff --git a/tests/overlays_test.py b/tests/overlays_test.py index 43baebeb..afb2b804 100644 --- a/tests/overlays_test.py +++ b/tests/overlays_test.py @@ -38,38 +38,23 @@ def test_color_none(self) -> None: o.color = None assert o.color is None - def test_color_value_error(self) -> None: - o = overlays._Overlay(name="An Overlay") - with pytest.raises(ValueError): - o.color = object() - def test_draw_order_string(self) -> None: o = overlays._Overlay(name="An Overlay") - o.draw_order = "1" - assert o.draw_order == "1" + o.draw_order = 1 + assert o.draw_order == 1 def test_draw_order_int(self) -> None: o = overlays._Overlay(name="An Overlay") o.draw_order = 1 - assert o.draw_order == "1" + assert o.draw_order == 1 def test_draw_order_none(self) -> None: o = overlays._Overlay(name="An Overlay") - o.draw_order = "1" - assert o.draw_order == "1" + o.draw_order = 1 + assert o.draw_order == 1 o.draw_order = None assert o.draw_order is None - def test_draw_order_value_error(self) -> None: - o = overlays._Overlay(name="An Overlay") - with pytest.raises(ValueError): - o.draw_order = object() - - def test_icon_raise_exception(self) -> None: - o = overlays._Overlay(name="An Overlay") - with pytest.raises(ValueError): - o.icon = 12345 - class TestGroundOverlay(StdLibrary): def test_altitude_int(self) -> None: