Skip to content

Commit

Permalink
Merge pull request #255 from ha36d/develop
Browse files Browse the repository at this point in the history
feat: Use arrow instead of dateutil
  • Loading branch information
cleder committed Oct 30, 2023
2 parents 0b40936 + 029efde commit 1d43533
Show file tree
Hide file tree
Showing 9 changed files with 46 additions and 34 deletions.
1 change: 1 addition & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ Requirements

* pygeoif_
* dateutils_
* arrow_

Optional
---------
Expand Down
2 changes: 1 addition & 1 deletion docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
arrow
pygeoif>=1.1
python-dateutil
# Documentation Requirements
Sphinx
sphinx-autodoc-typehints
Expand Down
4 changes: 2 additions & 2 deletions fastkml/gx.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@
from typing import Sequence
from typing import cast

import dateutil.parser
import arrow
import pygeoif.geometry as geo

import fastkml.config as config
Expand Down Expand Up @@ -258,7 +258,7 @@ def track_items_kwargs_from_element(
time_stamps: List[Optional[datetime.datetime]] = []
for time_stamp in element.findall(f"{config.KMLNS}when"):
if time_stamp is not None and time_stamp.text:
time_stamps.append(dateutil.parser.parse(time_stamp.text))
time_stamps.append(arrow.get(time_stamp.text).datetime)
else:
time_stamps.append(None)
coords: List[Optional[geo.Point]] = []
Expand Down
14 changes: 5 additions & 9 deletions fastkml/times.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,7 @@
from typing import Optional
from typing import Union

# note that there are some ISO 8601 timeparsers at pypi
# but in my tests all of them had some errors so we rely on the
# tried and tested dateutil here which is more stable. As a side effect
# we can also parse non ISO compliant dateTimes
import dateutil.parser
import arrow

import fastkml.config as config
from fastkml.base import _BaseObject
Expand Down Expand Up @@ -126,20 +122,20 @@ def parse(cls, datestr: str) -> Optional["KmlDateTime"]:
dt = None
if len(datestr) == 4:
year = int(datestr)
dt = datetime(year, 1, 1)
dt = arrow.get(year, 1, 1).datetime
resolution = DateTimeResolution.year
elif len(datestr) in {6, 7}:
ym = year_month.match(datestr)
if ym:
year = int(ym.group("year"))
month = int(ym.group("month"))
dt = datetime(year, month, 1)
dt = arrow.get(year, month, 1).datetime
resolution = DateTimeResolution.year_month
elif len(datestr) in {8, 10}: # 8 is YYYYMMDD, 10 is YYYY-MM-DD
dt = dateutil.parser.parse(datestr)
dt = arrow.get(datestr).datetime
resolution = DateTimeResolution.date
elif len(datestr) > 10:
dt = dateutil.parser.parse(datestr)
dt = arrow.get(datestr).datetime
resolution = DateTimeResolution.datetime
return cls(dt, resolution) if dt else None

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ classifiers = [
"Topic :: Scientific/Engineering :: GIS",
]
dependencies = [
"arrow",
"pygeoif>=1.1",
"python-dateutil",
"typing-extensions>4",
]
description = "Fast KML processing in python"
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
arrow
# Base package requirements
pygeoif>=1.1.0
python-dateutil
typing_extensions
1 change: 1 addition & 0 deletions test-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pre-commit
pytest
pytest-cov
pytest-randomly
python-dateutil
radon
types-python-dateutil
types-setuptools
Expand Down
22 changes: 11 additions & 11 deletions tests/times_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def test_parse_year(self) -> None:
dt = KmlDateTime.parse("2000")

assert dt.resolution == DateTimeResolution.year
assert dt.dt == datetime.datetime(2000, 1, 1)
assert dt.dt == datetime.datetime(2000, 1, 1, tzinfo=tzutc())

def test_parse_year_0(self) -> None:
with pytest.raises(ValueError):
Expand All @@ -108,13 +108,13 @@ def test_parse_year_month(self) -> None:
dt = KmlDateTime.parse("2000-03")

assert dt.resolution == DateTimeResolution.year_month
assert dt.dt == datetime.datetime(2000, 3, 1)
assert dt.dt == datetime.datetime(2000, 3, 1, tzinfo=tzutc())

def test_parse_year_month_no_dash(self) -> None:
dt = KmlDateTime.parse("200004")

assert dt.resolution == DateTimeResolution.year_month
assert dt.dt == datetime.datetime(2000, 4, 1)
assert dt.dt == datetime.datetime(2000, 4, 1, tzinfo=tzutc())

def test_parse_year_month_0(self) -> None:
with pytest.raises(ValueError):
Expand All @@ -128,13 +128,13 @@ def test_parse_year_month_day(self) -> None:
dt = KmlDateTime.parse("2000-03-01")

assert dt.resolution == DateTimeResolution.date
assert dt.dt == datetime.datetime(2000, 3, 1)
assert dt.dt == datetime.datetime(2000, 3, 1, tzinfo=tzutc())

def test_parse_year_month_day_no_dash(self) -> None:
dt = KmlDateTime.parse("20000401")

assert dt.resolution == DateTimeResolution.date
assert dt.dt == datetime.datetime(2000, 4, 1)
assert dt.dt == datetime.datetime(2000, 4, 1, tzinfo=tzutc())

def test_parse_year_month_day_0(self) -> None:
with pytest.raises(ValueError):
Expand Down Expand Up @@ -166,7 +166,7 @@ def test_parse_datetime_no_tz(self) -> None:
dt = KmlDateTime.parse("1997-07-16T07:30:15")

assert dt.resolution == DateTimeResolution.datetime
assert dt.dt == datetime.datetime(1997, 7, 16, 7, 30, 15)
assert dt.dt == datetime.datetime(1997, 7, 16, 7, 30, 15, tzinfo=tzutc())

def test_parse_datetime_empty(self) -> None:
assert KmlDateTime.parse("") is None
Expand Down Expand Up @@ -294,7 +294,7 @@ def test_read_timestamp(self) -> None:

ts.from_string(doc)
assert ts.timestamp.resolution == DateTimeResolution.year
assert ts.timestamp.dt == datetime.datetime(1997, 1, 1, 0, 0)
assert ts.timestamp.dt == datetime.datetime(1997, 1, 1, 0, 0, tzinfo=tzutc())
doc = """
<TimeStamp>
<when>1997-07</when>
Expand All @@ -303,7 +303,7 @@ def test_read_timestamp(self) -> None:

ts.from_string(doc)
assert ts.timestamp.resolution == DateTimeResolution.year_month
assert ts.timestamp.dt == datetime.datetime(1997, 7, 1, 0, 0)
assert ts.timestamp.dt == datetime.datetime(1997, 7, 1, 0, 0, tzinfo=tzutc())
doc = """
<TimeStamp>
<when>199808</when>
Expand All @@ -312,7 +312,7 @@ def test_read_timestamp(self) -> None:

ts.from_string(doc)
assert ts.timestamp.resolution == DateTimeResolution.year_month
assert ts.timestamp.dt == datetime.datetime(1998, 8, 1, 0, 0)
assert ts.timestamp.dt == datetime.datetime(1998, 8, 1, 0, 0, tzinfo=tzutc())
doc = """
<TimeStamp>
<when>1997-07-16</when>
Expand All @@ -321,7 +321,7 @@ def test_read_timestamp(self) -> None:

ts.from_string(doc)
assert ts.timestamp.resolution == DateTimeResolution.date
assert ts.timestamp.dt == datetime.datetime(1997, 7, 16, 0, 0)
assert ts.timestamp.dt == datetime.datetime(1997, 7, 16, 0, 0, tzinfo=tzutc())
# dateTime (YYYY-MM-DDThh:mm:ssZ)
# Here, T is the separator between the calendar and the hourly notation
# of time, and Z indicates UTC. (Seconds are required.)
Expand Down Expand Up @@ -359,7 +359,7 @@ def test_read_timespan(self) -> None:

ts.from_string(doc)
assert ts.begin.resolution == DateTimeResolution.date
assert ts.begin.dt == datetime.datetime(1876, 8, 1, 0, 0)
assert ts.begin.dt == datetime.datetime(1876, 8, 1, 0, 0, tzinfo=tzutc())
assert ts.end.resolution == DateTimeResolution.datetime
assert ts.end.dt == datetime.datetime(1997, 7, 16, 7, 30, 15, tzinfo=tzutc())

Expand Down
32 changes: 23 additions & 9 deletions tests/views_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

import datetime

from dateutil.tz import tzutc

from fastkml import times
from fastkml import views
from tests.base import Lxml
Expand All @@ -31,8 +33,8 @@ def test_create_camera(self) -> None:
"""Test the creation of a camera."""
time_span = times.TimeSpan(
id="time-span-id",
begin=times.KmlDateTime(datetime.datetime(2019, 1, 1)),
end=times.KmlDateTime(datetime.datetime(2019, 1, 2)),
begin=times.KmlDateTime(datetime.datetime(2019, 1, 1, tzinfo=tzutc())),
end=times.KmlDateTime(datetime.datetime(2019, 1, 2, tzinfo=tzutc())),
)

camera = views.Camera(
Expand All @@ -57,8 +59,12 @@ def test_create_camera(self) -> None:
assert camera.longitude == 60
assert camera.id == "cam-id"
assert camera.target_id == "target-cam-id"
assert camera.begin == times.KmlDateTime(datetime.datetime(2019, 1, 1))
assert camera.end == times.KmlDateTime(datetime.datetime(2019, 1, 2))
assert camera.begin == times.KmlDateTime(
datetime.datetime(2019, 1, 1, tzinfo=tzutc())
)
assert camera.end == times.KmlDateTime(
datetime.datetime(2019, 1, 2, tzinfo=tzutc())
)
assert camera.to_string()

def test_camera_read(self) -> None:
Expand Down Expand Up @@ -92,13 +98,17 @@ def test_camera_read(self) -> None:
assert camera.longitude == 60
assert camera.id == "cam-id"
assert camera.target_id == "target-cam-id"
assert camera.begin == times.KmlDateTime(datetime.datetime(2019, 1, 1))
assert camera.end == times.KmlDateTime(datetime.datetime(2019, 1, 2))
assert camera.begin == times.KmlDateTime(
datetime.datetime(2019, 1, 1, tzinfo=tzutc())
)
assert camera.end == times.KmlDateTime(
datetime.datetime(2019, 1, 2, tzinfo=tzutc())
)

def test_create_look_at(self) -> None:
time_stamp = times.TimeStamp(
id="time-span-id",
timestamp=times.KmlDateTime(datetime.datetime(2019, 1, 1)),
timestamp=times.KmlDateTime(datetime.datetime(2019, 1, 1, tzinfo=tzutc())),
)

look_at = views.LookAt(
Expand All @@ -121,7 +131,9 @@ def test_create_look_at(self) -> None:
assert look_at.longitude == 60
assert look_at.id == "look-at-id"
assert look_at.target_id == "target-look-at-id"
assert look_at._timestamp.timestamp.dt == datetime.datetime(2019, 1, 1)
assert look_at._timestamp.timestamp.dt == datetime.datetime(
2019, 1, 1, tzinfo=tzutc()
)
assert look_at.begin is None
assert look_at.end is None
assert look_at.to_string()
Expand Down Expand Up @@ -153,7 +165,9 @@ def test_look_at_read(self) -> None:
assert look_at.longitude == 60
assert look_at.id == "look-at-id"
assert look_at.target_id == "target-look-at-id"
assert look_at._timestamp.timestamp.dt == datetime.datetime(2019, 1, 1)
assert look_at._timestamp.timestamp.dt == datetime.datetime(
2019, 1, 1, tzinfo=tzutc()
)
assert look_at.begin is None
assert look_at.end is None

Expand Down

0 comments on commit 1d43533

Please sign in to comment.