helpers.EventDays class + basic testing

This commit is contained in:
Jörn-Michael Miehe 2023-09-14 23:36:20 +00:00
parent e9ef7f67e3
commit 97d4d1e136
6 changed files with 206 additions and 1 deletions

View file

@ -13,4 +13,9 @@
"git.closeDiffOnOperation": true,
"python.analysis.typeCheckingMode": "basic",
"python.analysis.diagnosticMode": "workspace",
"python.testing.pytestArgs": [
"test"
],
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true,
}

View file

@ -0,0 +1,11 @@
from . import advent_image, calendar_config, config, depends, helpers, settings, webdav
__all__ = [
"advent_image",
"calendar_config",
"config",
"depends",
"helpers",
"settings",
"webdav",
]

View file

@ -1,11 +1,13 @@
import itertools
import random
import re
from datetime import date, datetime, timedelta
from io import BytesIO
from typing import Any, Self, Sequence, TypeVar
from fastapi.responses import StreamingResponse
from PIL import Image
from pydantic import BaseModel
from .config import get_config
from .webdav import WebDAV
@ -68,3 +70,52 @@ async def api_return_image(img: Image.Image) -> StreamingResponse:
media_type="image/jpeg",
content=img_buffer,
)
class EventDays(BaseModel):
first: date
next: date | None
last: date
end: date
@classmethod
def get(
cls,
*,
# current date
today: date,
# month/day when events begin
begin_month: int,
begin_day: int,
# events: e.g. a 2 means there is an event 2 days after begin
# -> assume sorted (asc)
events_after: list[int],
# countdown to closing begins after last event
closing_after: int,
) -> Self:
"""
foo bar
"""
# account for the last event, then add closing period
duration = timedelta(days=events_after[-1] + closing_after)
# the events may begin last year, this year or next year
maybe_begin = (
datetime(today.year + year_diff, begin_month, begin_day).date()
for year_diff in (-1, 0, +1)
)
# find the first begin where the end date is in the future
begin = next(begin for begin in maybe_begin if today <= (begin + duration))
# all event dates
events = [begin + timedelta(days=event_after) for event_after in events_after]
# return relevant event dates
return cls(
first=events[0],
next=next((event for event in events if event > today), None),
last=events[-1],
end=begin + duration,
)

59
api/poetry.lock generated
View file

@ -266,6 +266,17 @@ files = [
{file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"},
]
[[package]]
name = "iniconfig"
version = "2.0.0"
description = "brain-dead simple config-ini parsing"
optional = false
python-versions = ">=3.7"
files = [
{file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"},
{file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
]
[[package]]
name = "lxml"
version = "4.9.3"
@ -418,6 +429,17 @@ files = [
{file = "numpy-1.25.2.tar.gz", hash = "sha256:fd608e19c8d7c55021dffd43bfe5492fab8cc105cc8986f813f8c3c048b38760"},
]
[[package]]
name = "packaging"
version = "23.1"
description = "Core utilities for Python packages"
optional = false
python-versions = ">=3.7"
files = [
{file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"},
{file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"},
]
[[package]]
name = "pillow"
version = "10.0.0"
@ -487,6 +509,21 @@ files = [
docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"]
tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"]
[[package]]
name = "pluggy"
version = "1.3.0"
description = "plugin and hook calling mechanisms for python"
optional = false
python-versions = ">=3.8"
files = [
{file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"},
{file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"},
]
[package.extras]
dev = ["pre-commit", "tox"]
testing = ["pytest", "pytest-benchmark"]
[[package]]
name = "pycodestyle"
version = "2.11.0"
@ -661,6 +698,26 @@ files = [
{file = "pyflakes-3.1.0.tar.gz", hash = "sha256:a0aae034c444db0071aa077972ba4768d40c830d9539fd45bf4cd3f8f6992efc"},
]
[[package]]
name = "pytest"
version = "7.4.2"
description = "pytest: simple powerful testing with Python"
optional = false
python-versions = ">=3.7"
files = [
{file = "pytest-7.4.2-py3-none-any.whl", hash = "sha256:1d881c6124e08ff0a1bb75ba3ec0bfd8b5354a01c194ddd5a0a870a48d99b002"},
{file = "pytest-7.4.2.tar.gz", hash = "sha256:a766259cfab564a2ad52cb1aae1b881a75c3eb7e34ca3779697c23ed47c47069"},
]
[package.dependencies]
colorama = {version = "*", markers = "sys_platform == \"win32\""}
iniconfig = "*"
packaging = "*"
pluggy = ">=0.12,<2.0"
[package.extras]
testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"]
[[package]]
name = "python-dateutil"
version = "2.8.2"
@ -1047,4 +1104,4 @@ files = [
[metadata]
lock-version = "2.0"
python-versions = "^3.11"
content-hash = "c2a27f4ecbc1c234d1368320db111d6c51cd4278986e64e80398cad384037a8c"
content-hash = "9039ceba03b4dfdaa6507b4b88d45125f7d33c05438133462d1cb338c5650eed"

View file

@ -21,6 +21,7 @@ webdavclient3 = "^3.14.6"
[tool.poetry.group.dev.dependencies]
flake8 = "^6.1.0"
pytest = "^7.4.2"
[build-system]
build-backend = "poetry.core.masonry.api"

80
api/test/test_helpers.py Normal file
View file

@ -0,0 +1,80 @@
from datetime import datetime
from advent22_api.core.helpers import EventDays
class TestEventDays:
@staticmethod
def test_get_before():
ed = EventDays.get(
today=datetime(2023, 11, 30).date(),
begin_month=12,
begin_day=1,
events_after=list(range(24)),
closing_after=5,
)
assert ed.first == datetime(2023, 12, 1).date()
assert ed.next == datetime(2023, 12, 1).date()
assert ed.last == datetime(2023, 12, 24).date()
assert ed.end == datetime(2023, 12, 29).date()
@staticmethod
def test_get_after():
ed = EventDays.get(
today=datetime(2023, 12, 30).date(),
begin_month=12,
begin_day=1,
events_after=list(range(24)),
closing_after=5,
)
assert ed.first == datetime(2024, 12, 1).date()
assert ed.next == datetime(2024, 12, 1).date()
assert ed.last == datetime(2024, 12, 24).date()
assert ed.end == datetime(2024, 12, 29).date()
@staticmethod
def test_get_during_events():
ed = EventDays.get(
today=datetime(2023, 12, 10).date(),
begin_month=12,
begin_day=1,
events_after=list(range(24)),
closing_after=5,
)
assert ed.first == datetime(2023, 12, 1).date()
assert ed.next == datetime(2023, 12, 11).date()
assert ed.last == datetime(2023, 12, 24).date()
assert ed.end == datetime(2023, 12, 29).date()
@staticmethod
def test_get_during_closing():
ed = EventDays.get(
today=datetime(2023, 12, 29).date(),
begin_month=12,
begin_day=1,
events_after=list(range(24)),
closing_after=5,
)
assert ed.first == datetime(2023, 12, 1).date()
assert ed.next is None
assert ed.last == datetime(2023, 12, 24).date()
assert ed.end == datetime(2023, 12, 29).date()
@staticmethod
def test_get_during_wrap():
ed = EventDays.get(
today=datetime(2024, 1, 1).date(),
begin_month=12,
begin_day=1,
events_after=list(range(24)),
closing_after=8,
)
assert ed.first == datetime(2023, 12, 1).date()
assert ed.next is None
assert ed.last == datetime(2023, 12, 24).date()
assert ed.end == datetime(2024, 1, 1).date()