Skip to content
This repository was archived by the owner on Jun 26, 2022. It is now read-only.
Merged
39 changes: 31 additions & 8 deletions sonarr/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,29 @@
from .exceptions import SonarrError


def dt_str_to_dt(dt_str: str) -> datetime:
"""Convert ISO-8601 datetime string to datetime object."""
utc = False

if "Z" in dt_str:
utc = True
dt_str = dt_str[:-1]

if "." in dt_str:
# Python doesn't support long microsecond values
ts_bits = dt_str.split(".", 1)
dt_str = "{}.{}".format(ts_bits[0], ts_bits[1][:2])
fmt = "%Y-%m-%dT%H:%M:%S.%f"
else:
fmt = "%Y-%m-%dT%H:%M:%S"

if utc:
dt_str += "Z"
fmt += "%z"

return datetime.strptime(dt_str, fmt)


@dataclass(frozen=True)
class Disk:
"""Object holding disk information from Sonarr."""
Expand Down Expand Up @@ -85,15 +108,15 @@ def from_dict(data: dict):
"""Return Series object from Sonarr API response."""
premiere = data.get("firstAired", None)
if premiere is not None:
premiere = datetime.strptime(premiere, "%Y-%m-%dT%H:%M:%S%z")
premiere = dt_str_to_dt(premiere)

added = data.get("added", None)
if added is not None:
added = datetime.strptime(added, "%Y-%m-%dT%H:%M:%S.%f%z")
added = dt_str_to_dt(added)

synced = data.get("lastInfoSync", None)
if synced is not None:
synced = datetime.strptime(synced, "%Y-%m-%dT%H:%M:%S.%f%z")
synced = dt_str_to_dt(synced)

poster = None
for image in data.get("images", []):
Expand Down Expand Up @@ -151,7 +174,7 @@ def from_dict(data: dict):
"""Return Episode object from Sonarr API response."""
airs = data.get("airDateUtc", None)
if airs is not None:
airs = datetime.strptime(airs, "%Y-%m-%dT%H:%M:%S%z")
airs = dt_str_to_dt(airs)

episode_number = data.get("episodeNumber", 0)
season_number = data.get("seasonNumber", 0)
Expand Down Expand Up @@ -215,14 +238,14 @@ def from_dict(data: dict):
queued = started

if started is not None:
started = datetime.strptime(started, "%Y-%m-%dT%H:%M:%S.%f%z")
started = dt_str_to_dt(started)

if queued is not None:
queued = datetime.strptime(queued, "%Y-%m-%dT%H:%M:%S.%f%z")
queued = dt_str_to_dt(queued)

changed = data.get("stateChangeTime", None)
if changed is not None:
changed = datetime.strptime(changed, "%Y-%m-%dT%H:%M:%S.%f%z")
changed = dt_str_to_dt(changed)

return CommandItem(
command_id=data.get("id", 0),
Expand Down Expand Up @@ -264,7 +287,7 @@ def from_dict(data: dict):

eta = data.get("estimatedCompletionTime", None)
if eta is not None:
eta = datetime.strptime(eta, "%Y-%m-%dT%H:%M:%S.%f%z")
eta = dt_str_to_dt(eta)

return QueueItem(
queue_id=data.get("id", 0),
Expand Down
34 changes: 23 additions & 11 deletions tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,18 @@ def test_application_no_data() -> None:
models.Application({})


def test_dt_str_to_dt() -> None:
"""Test the dt_str_to_dt method."""
dt = models.dt_str_to_dt("2018-05-14T19:02:13.101496Z")
assert dt == datetime(2018, 5, 14, 19, 2, 13, 100000, tzinfo=timezone.utc)


def test_dt_str_to_dt_long_microseconds() -> None:
"""Test the dt_str_to_dt method with long microseconds."""
dt = models.dt_str_to_dt("2018-05-14T19:02:13.1014986Z")
assert dt == datetime(2018, 5, 14, 19, 2, 13, 100000, tzinfo=timezone.utc)


def test_info() -> None:
"""Test the Info model."""
info = models.Info.from_dict(INFO)
Expand All @@ -59,9 +71,9 @@ def test_command_item() -> None:
assert item.state == "started"
assert item.priority == "normal"
assert item.trigger == "manual"
assert item.started == datetime(2020, 4, 6, 16, 54, 6, 421322, tzinfo=timezone.utc)
assert item.queued == datetime(2020, 4, 6, 16, 54, 6, 419450, tzinfo=timezone.utc)
assert item.changed == datetime(2020, 4, 6, 16, 54, 6, 421322, tzinfo=timezone.utc)
assert item.started == datetime(2020, 4, 6, 16, 54, 6, 420000, tzinfo=timezone.utc)
assert item.queued == datetime(2020, 4, 6, 16, 54, 6, 410000, tzinfo=timezone.utc)
assert item.changed == datetime(2020, 4, 6, 16, 54, 6, 420000, tzinfo=timezone.utc)

item = models.CommandItem.from_dict(COMMAND[1])

Expand All @@ -71,9 +83,9 @@ def test_command_item() -> None:
assert item.state == "started"
assert item.priority == "unknown"
assert item.trigger == "unknown"
assert item.started == datetime(2020, 4, 6, 16, 57, 51, 406504, tzinfo=timezone.utc)
assert item.queued == datetime(2020, 4, 6, 16, 57, 51, 406504, tzinfo=timezone.utc)
assert item.changed == datetime(2020, 4, 6, 16, 57, 51, 417931, tzinfo=timezone.utc)
assert item.started == datetime(2020, 4, 6, 16, 57, 51, 400000, tzinfo=timezone.utc)
assert item.queued == datetime(2020, 4, 6, 16, 57, 51, 400000, tzinfo=timezone.utc)
assert item.changed == datetime(2020, 4, 6, 16, 57, 51, 410000, tzinfo=timezone.utc)


def test_episode() -> None:
Expand Down Expand Up @@ -125,7 +137,7 @@ def test_queue_item() -> None:
assert item.protocol == "usenet"
assert item.size == 4472186820
assert item.size_remaining == 0
assert item.eta == datetime(2016, 2, 5, 22, 46, 52, 440104, tzinfo=timezone.utc)
assert item.eta == datetime(2016, 2, 5, 22, 46, 52, 440000, tzinfo=timezone.utc)
assert item.time_remaining == "00:00:00"

assert item.episode
Expand Down Expand Up @@ -177,10 +189,10 @@ def test_series() -> None:
assert series.certification == "TV-14"
assert series.genres == ["Animation", "Comedy"]
assert series.added == datetime(
2011, 1, 26, 19, 25, 55, 455594, tzinfo=timezone.utc
2011, 1, 26, 19, 25, 55, 450000, tzinfo=timezone.utc
)
assert series.synced == datetime(
2014, 1, 26, 19, 25, 55, 455594, tzinfo=timezone.utc
2014, 1, 26, 19, 25, 55, 450000, tzinfo=timezone.utc
)


Expand Down Expand Up @@ -228,10 +240,10 @@ def test_series_item() -> None:
assert item.series.certification == "TV-G"
assert item.series.genres == ["Comedy"]
assert item.series.added == datetime(
2020, 4, 5, 20, 40, 20, 50044, tzinfo=timezone.utc
2020, 4, 5, 20, 40, 20, 50000, tzinfo=timezone.utc
)
assert item.series.synced == datetime(
2020, 4, 5, 20, 40, 21, 545669, tzinfo=timezone.utc
2020, 4, 5, 20, 40, 21, 540000, tzinfo=timezone.utc
)

assert item.seasons
Expand Down