Skip to content

Commit

Permalink
Merge pull request #266 from cleder/260-refactor-timestamp-and-timespan
Browse files Browse the repository at this point in the history
Fix TimeStamp and TimeSpan class to use class_from_element method
  • Loading branch information
cleder committed Nov 11, 2023
2 parents b470a60 + 046dd3f commit 58041e9
Show file tree
Hide file tree
Showing 10 changed files with 185 additions and 53 deletions.
4 changes: 2 additions & 2 deletions examples/UsageExamples.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@


def print_child_features(element):
"""Prints the name of every child node of the given element, recursively"""
"""Prints the name of every child node of the given element, recursively."""
if not getattr(element, "features", None):
return
for feature in element.features():
Expand All @@ -17,7 +17,7 @@ def print_child_features(element):

k = kml.KML()

with open(fname) as kml_file: # noqa: ENC001
with open(fname, encoding="utf-8") as kml_file:
k.from_string(kml_file.read().encode("utf-8"))

print_child_features(k)
8 changes: 7 additions & 1 deletion fastkml/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,12 @@ def class_from_element(
strict: bool,
) -> "_XMLObject":
"""Creates an XML object from an etree element."""
kwargs = cls._get_kwargs(ns=ns, element=element, strict=strict)
kwargs = cls._get_kwargs(
ns=ns,
name_spaces=name_spaces,
element=element,
strict=strict,
)
return cls(
**kwargs,
)
Expand Down Expand Up @@ -186,6 +191,7 @@ def class_from_string(
ns = cls._get_ns(ns)
return cls.class_from_element(
ns=ns,
name_spaces=name_spaces,
strict=strict,
element=cast(
Element,
Expand Down
18 changes: 12 additions & 6 deletions fastkml/kml.py
Original file line number Diff line number Diff line change
Expand Up @@ -458,14 +458,20 @@ def from_element(self, element: Element, strict: bool = False) -> None:
self.snippet = _snippet
timespan = element.find(f"{self.ns}TimeSpan")
if timespan is not None:
s = TimeSpan(self.ns)
s.from_element(timespan)
self._timespan = s
self._timespan = TimeSpan.class_from_element(
ns=self.ns,
name_spaces=self.name_spaces,
element=timespan,
strict=strict,
)
timestamp = element.find(f"{self.ns}TimeStamp")
if timestamp is not None:
s = TimeStamp(self.ns)
s.from_element(timestamp)
self._timestamp = s
self._timestamp = TimeStamp.class_from_element(
ns=self.ns,
name_spaces=self.name_spaces,
element=timestamp,
strict=strict,
)
atom_link = element.find(f"{atom.NS}link")
if atom_link is not None:
s = atom.Link()
Expand Down
62 changes: 47 additions & 15 deletions fastkml/times.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
import re
from datetime import date
from datetime import datetime
from typing import Any
from typing import Dict
from typing import Optional
from typing import Union

Expand Down Expand Up @@ -157,11 +159,12 @@ class TimeStamp(_TimePrimitive):
def __init__(
self,
ns: Optional[str] = None,
name_spaces: Optional[Dict[str, str]] = None,
id: Optional[str] = None,
target_id: Optional[str] = None,
timestamp: Optional[KmlDateTime] = None,
) -> None:
super().__init__(ns=ns, id=id, target_id=target_id)
super().__init__(ns=ns, name_spaces=name_spaces, id=id, target_id=target_id)
self.timestamp = timestamp

def etree_element(
Expand All @@ -177,11 +180,25 @@ def etree_element(
when.text = str(self.timestamp)
return element

def from_element(self, element: Element) -> None:
super().from_element(element)
when = element.find(f"{self.ns}when")
@classmethod
def _get_kwargs(
cls,
*,
ns: str,
name_spaces: Optional[Dict[str, str]] = None,
element: Element,
strict: bool,
) -> Dict[str, Any]:
kwargs = super()._get_kwargs(
ns=ns,
name_spaces=name_spaces,
element=element,
strict=strict,
)
when = element.find(f"{ns}when")
if when is not None:
self.timestamp = KmlDateTime.parse(when.text)
kwargs["timestamp"] = KmlDateTime.parse(when.text)
return kwargs


class TimeSpan(_TimePrimitive):
Expand All @@ -192,24 +209,16 @@ class TimeSpan(_TimePrimitive):
def __init__(
self,
ns: Optional[str] = None,
name_spaces: Optional[Dict[str, str]] = None,
id: Optional[str] = None,
target_id: Optional[str] = None,
begin: Optional[KmlDateTime] = None,
end: Optional[KmlDateTime] = None,
) -> None:
super().__init__(ns=ns, id=id, target_id=target_id)
super().__init__(ns=ns, name_spaces=name_spaces, id=id, target_id=target_id)
self.begin = begin
self.end = end

def from_element(self, element: Element) -> None:
super().from_element(element)
begin = element.find(f"{self.ns}begin")
if begin is not None:
self.begin = KmlDateTime.parse(begin.text)
end = element.find(f"{self.ns}end")
if end is not None:
self.end = KmlDateTime.parse(end.text)

def etree_element(
self,
precision: Optional[int] = None,
Expand Down Expand Up @@ -237,3 +246,26 @@ def etree_element(
raise ValueError(msg)
# TODO test if end > begin
return element

@classmethod
def _get_kwargs(
cls,
*,
ns: str,
name_spaces: Optional[Dict[str, str]] = None,
element: Element,
strict: bool,
) -> Dict[str, Any]:
kwargs = super()._get_kwargs(
ns=ns,
name_spaces=name_spaces,
element=element,
strict=strict,
)
begin = element.find(f"{ns}begin")
if begin is not None:
kwargs["begin"] = KmlDateTime.parse(begin.text)
end = element.find(f"{ns}end")
if end is not None:
kwargs["end"] = KmlDateTime.parse(end.text)
return kwargs
25 changes: 19 additions & 6 deletions fastkml/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from typing import Optional
from typing import SupportsFloat
from typing import Union
from typing import cast

from fastkml import config
from fastkml.base import _BaseObject
Expand Down Expand Up @@ -185,14 +186,26 @@ def from_element(self, element: Element) -> None:
self.altitude_mode = AltitudeMode(altitude_mode.text)
timespan = element.find(f"{self.ns}TimeSpan")
if timespan is not None:
span = TimeSpan(self.ns)
span.from_element(timespan)
self._timespan = span
self._timespan = cast(
TimeSpan,
TimeSpan.class_from_element(
ns=self.ns,
name_spaces=self.name_spaces,
element=timespan,
strict=False,
),
)
timestamp = element.find(f"{self.ns}TimeStamp")
if timestamp is not None:
stamp = TimeStamp(self.ns)
stamp.from_element(timestamp)
self._timestamp = stamp
self._timestamp = cast(
TimeStamp,
TimeStamp.class_from_element(
ns=self.ns,
name_spaces=self.name_spaces,
element=timestamp,
strict=False,
),
)

def etree_element(
self,
Expand Down
4 changes: 3 additions & 1 deletion tests/atom_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,9 @@ def test_atom_person_ns(self) -> None:

def test_atom_author(self) -> None:
a = atom.Author(
name="Nobody", uri="http://localhost", email="cl@donotreply.com",
name="Nobody",
uri="http://localhost",
email="cl@donotreply.com",
)

serialized = a.to_string()
Expand Down
3 changes: 2 additions & 1 deletion tests/base_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ def test_to_str_empty_ns(self) -> None:
obj.__name__ = "test"

assert obj.to_string().replace(" ", "").replace(
"\n", "",
"\n",
"",
) == '<test id="id-0" targetId="target-id-0" />'.replace(" ", "")

def test_from_string(self) -> None:
Expand Down
3 changes: 2 additions & 1 deletion tests/geometries/point_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ def test_to_string_empty_geometry(self) -> None:
point = Point(geometry=geo.Point(None, None)) # type: ignore[arg-type]

with pytest.raises(
KMLWriteError, match=r"Invalid dimensions in coordinates '\(\(\),\)'",
KMLWriteError,
match=r"Invalid dimensions in coordinates '\(\(\),\)'",
):
point.to_string()

Expand Down
44 changes: 38 additions & 6 deletions tests/gx_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,14 +95,24 @@ def test_multitrack(self) -> None:
track_items=[
TrackItem(
when=datetime.datetime(
2020, 1, 1, 0, 0, tzinfo=tzutc(),
2020,
1,
1,
0,
0,
tzinfo=tzutc(),
),
coord=geo.Point(0.0, 0.0),
angle=None,
),
TrackItem(
when=datetime.datetime(
2020, 1, 1, 0, 10, tzinfo=tzutc(),
2020,
1,
1,
0,
10,
tzinfo=tzutc(),
),
coord=geo.Point(1.0, 0.0),
angle=None,
Expand All @@ -119,14 +129,24 @@ def test_multitrack(self) -> None:
track_items=[
TrackItem(
when=datetime.datetime(
2020, 1, 1, 0, 10, tzinfo=tzutc(),
2020,
1,
1,
0,
10,
tzinfo=tzutc(),
),
coord=geo.Point(0.0, 1.0),
angle=None,
),
TrackItem(
when=datetime.datetime(
2020, 1, 1, 0, 20, tzinfo=tzutc(),
2020,
1,
1,
0,
20,
tzinfo=tzutc(),
),
coord=geo.Point(1.0, 1.0),
angle=None,
Expand Down Expand Up @@ -384,14 +404,26 @@ def test_multitrack(self) -> None:
track_items=[
TrackItem(
when=datetime.datetime(
2010, 5, 28, 2, 2, 55, tzinfo=tzutc(),
2010,
5,
28,
2,
2,
55,
tzinfo=tzutc(),
),
coord=geo.Point(-122.203451, 37.374706, 141.800003),
angle=Angle(heading=1.0, tilt=2.0, roll=3.0),
),
TrackItem(
when=datetime.datetime(
2010, 5, 28, 2, 2, 56, tzinfo=tzutc(),
2010,
5,
28,
2,
2,
56,
tzinfo=tzutc(),
),
coord=geo.Point(-122.203329, 37.37478, 141.199997),
angle=Angle(heading=1.0, tilt=2.0, roll=3.0),
Expand Down

0 comments on commit 58041e9

Please sign in to comment.