added event selector (w/o tests)

This commit is contained in:
Simone Robutti 2021-05-04 22:58:00 +02:00
parent e938ba709b
commit 3fe3c8efc6
7 changed files with 171 additions and 27 deletions

View File

@ -1,10 +1,18 @@
from __future__ import annotations
from dataclasses import dataclass, asdict
from datetime import datetime
from enum import Enum
from typing import Optional
from jinja2 import Template
class PublicationStatus(Enum):
WAITING = 1
FAILED = 2
PARTIAL = 3
COMPLETED = 4
@dataclass
class MobilizonEvent:
"""Class representing an event retrieved from Mobilizon."""
@ -18,9 +26,16 @@ class MobilizonEvent:
mobilizon_id: str
thumbnail_link: Optional[str] = None
location: Optional[str] = None
publication_time: Optional[datetime] = None
publication_status: PublicationStatus = PublicationStatus.WAITING
def begins_before(self, other: MobilizonEvent) -> bool:
return self.begin_datetime < other.begin_datetime
def __post_init__(self):
assert self.begin_datetime < self.end_datetime
if self.publication_time:
assert self.publication_status in [
PublicationStatus.COMPLETED,
PublicationStatus.PARTIAL,
]
def _fill_template(self, pattern: Template) -> str:
return pattern.render(**asdict(self))

46
poetry.lock generated
View File

@ -56,6 +56,34 @@ toml = ["toml"]
vault = ["hvac"]
yaml = ["ruamel.yaml"]
[[package]]
name = "hypothesis"
version = "6.10.1"
description = "A library for property-based testing"
category = "dev"
optional = false
python-versions = ">=3.6"
[package.dependencies]
attrs = ">=19.2.0"
sortedcontainers = ">=2.1.0,<3.0.0"
[package.extras]
all = ["black (>=19.10b0)", "click (>=7.0)", "django (>=2.2)", "dpcontracts (>=0.4)", "lark-parser (>=0.6.5)", "libcst (>=0.3.16)", "numpy (>=1.9.0)", "pandas (>=0.25)", "pytest (>=4.6)", "python-dateutil (>=1.4)", "pytz (>=2014.1)", "redis (>=3.0.0)", "rich (>=9.0.0)", "importlib-resources (>=3.3.0)", "importlib-metadata (>=3.6)", "backports.zoneinfo (>=0.2.1)", "tzdata (>=2020.4)"]
cli = ["click (>=7.0)", "black (>=19.10b0)", "rich (>=9.0.0)"]
codemods = ["libcst (>=0.3.16)"]
dateutil = ["python-dateutil (>=1.4)"]
django = ["pytz (>=2014.1)", "django (>=2.2)"]
dpcontracts = ["dpcontracts (>=0.4)"]
ghostwriter = ["black (>=19.10b0)"]
lark = ["lark-parser (>=0.6.5)"]
numpy = ["numpy (>=1.9.0)"]
pandas = ["pandas (>=0.25)"]
pytest = ["pytest (>=4.6)"]
pytz = ["pytz (>=2014.1)"]
redis = ["redis (>=3.0.0)"]
zoneinfo = ["importlib-resources (>=3.3.0)", "backports.zoneinfo (>=0.2.1)", "tzdata (>=2020.4)"]
[[package]]
name = "iso8601"
version = "0.1.14"
@ -170,6 +198,14 @@ category = "main"
optional = false
python-versions = "*"
[[package]]
name = "sortedcontainers"
version = "2.3.0"
description = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set"
category = "dev"
optional = false
python-versions = "*"
[[package]]
name = "tortoise-orm"
version = "0.17.2"
@ -210,7 +246,7 @@ python-versions = "*"
[metadata]
lock-version = "1.1"
python-versions = "^3.9"
content-hash = "2a9d2f27ed4c4197d4dd022c2e1f8968ef7fff2ab73145a4bd74712f35d88855"
content-hash = "f78f8e295d8c94dfe0e4e0f29ce5056f5cea948037cc62b9903b6bc8263a0db6"
[metadata.files]
aiosqlite = [
@ -233,6 +269,10 @@ dynaconf = [
{file = "dynaconf-3.1.4-py2.py3-none-any.whl", hash = "sha256:e6f383b84150b70fc439c8b2757581a38a58d07962aa14517292dcce1a77e160"},
{file = "dynaconf-3.1.4.tar.gz", hash = "sha256:b2f472d83052f809c5925565b8a2ba76a103d5dc1dbb9748b693ed67212781b9"},
]
hypothesis = [
{file = "hypothesis-6.10.1-py3-none-any.whl", hash = "sha256:1d65f58d82d1cbd35b6441bda3bb11cb1adc879d6b2af191aea388fa412171b1"},
{file = "hypothesis-6.10.1.tar.gz", hash = "sha256:586b6c46e90878c2546743afbed348bca51e1f30e3461fa701fad58c2c47c650"},
]
iso8601 = [
{file = "iso8601-0.1.14-py2.py3-none-any.whl", hash = "sha256:e7e1122f064d626e17d47cd5106bed2c620cb38fe464999e0ddae2b6d2de6004"},
{file = "iso8601-0.1.14.tar.gz", hash = "sha256:8aafd56fa0290496c5edbb13c311f78fa3a241f0853540da09d9363eae3ebd79"},
@ -303,6 +343,10 @@ pytz = [
{file = "pytz-2020.5-py2.py3-none-any.whl", hash = "sha256:16962c5fb8db4a8f63a26646d8886e9d769b6c511543557bc84e9569fb9a9cb4"},
{file = "pytz-2020.5.tar.gz", hash = "sha256:180befebb1927b16f6b57101720075a984c019ac16b1b7575673bea42c6c3da5"},
]
sortedcontainers = [
{file = "sortedcontainers-2.3.0-py2.py3-none-any.whl", hash = "sha256:37257a32add0a3ee490bb170b599e93095eed89a55da91fa9f48753ea12fd73f"},
{file = "sortedcontainers-2.3.0.tar.gz", hash = "sha256:59cc937650cf60d677c16775597c89a960658a09cf7c1a668f86e1e4464b10a1"},
]
tortoise-orm = [
{file = "tortoise-orm-0.17.2.tar.gz", hash = "sha256:1a742b2f15a31d47a8dea7706b478cc9a7ce9af268b61d77d0fa22cfbaea271a"},
{file = "tortoise_orm-0.17.2-py3-none-any.whl", hash = "sha256:b0c02be3800398053058377ddca91fa051eb98eebb704d2db2a3ab1c6a58e347"},

View File

@ -13,6 +13,7 @@ Jinja2 = "^2.11.3"
[tool.poetry.dev-dependencies]
pytest = "^5.2"
hypothesis = "^6.10.1"
[build-system]
requires = ["poetry-core>=1.0.0"]

View File

@ -0,0 +1,33 @@
import hypothesis
from hypothesis import assume
from hypothesis.provisional import urls
from hypothesis.strategies import characters, datetimes, text, sampled_from
from mobilizon_bots.event.event import MobilizonEvent, PublicationStatus
@hypothesis.strategies.composite
def events(draw, published: bool = False):
begin_datetime = draw(datetimes())
end_datetime = draw(datetimes())
assume(begin_datetime < end_datetime)
return MobilizonEvent(
name=draw(characters()),
description=draw(text()),
begin_datetime=begin_datetime,
end_datetime=end_datetime,
last_accessed=draw(datetimes()),
mobilizon_link=draw(urls()),
mobilizon_id=draw(characters()),
thumbnail_link=draw(urls()),
location=draw(text()),
publication_time=draw(datetimes()) if published else None,
publication_status=draw(
sampled_from(
[PublicationStatus.COMPLETED, PublicationStatus.PARTIAL]
if published
else [PublicationStatus.WAITING, PublicationStatus.FAILED]
)
),
)

View File

@ -0,0 +1,58 @@
from datetime import timedelta, datetime
from typing import List, Optional
from mobilizon_bots.event.event import MobilizonEvent
from abc import ABC, abstractmethod
class EventSelectionStrategy(ABC):
@abstractmethod
def select(
self,
published_events: List[MobilizonEvent],
unpublished_events: List[MobilizonEvent],
) -> Optional[MobilizonEvent]:
pass
class SelectNextEventStrategy(EventSelectionStrategy):
def __init__(self, minimum_break_between_events: timedelta = timedelta(days=0)):
self.minimum_break_between_events = minimum_break_between_events
def select(
self,
published_events: List[MobilizonEvent],
unpublished_events: List[MobilizonEvent],
) -> Optional[MobilizonEvent]:
last_published_event = published_events[-1]
first_unpublished_event = unpublished_events[0]
assert (
last_published_event.publication_time < datetime.now()
), "Last published event has been published in the future"
if (
last_published_event.publication_time + self.minimum_break_between_events
> first_unpublished_event.begin_datetime
):
return None
return first_unpublished_event
class EventSelector:
def __init__(
self,
published_events: List[MobilizonEvent],
unpublished_events: List[MobilizonEvent],
):
self.published_events = published_events.sort(key=lambda x: x.begin_datetime)
self.unpublished_events = unpublished_events.sort(
key=lambda x: x.begin_datetime
)
def select_event_to_publish(
self, strategy: EventSelectionStrategy
) -> Optional[MobilizonEvent]:
return strategy.select(self.published_events, self.unpublished_events)

View File

@ -1,9 +1,11 @@
from datetime import datetime
import pytest
from hypothesis import given
from jinja2 import Template
from mobilizon_bots.event.event import MobilizonEvent
from tests import events
@pytest.fixture()
@ -42,27 +44,6 @@ def test_format(event, simple_template):
)
def test_is_newer():
older_event = MobilizonEvent(
name="test event",
description="description of the event",
begin_datetime=datetime(year=2021, month=1, day=1, hour=11, minute=30),
end_datetime=datetime(year=2021, month=1, day=1, hour=12, minute=30),
last_accessed=datetime.now(),
mobilizon_link="http://some_link.com/123",
mobilizon_id="12345",
thumbnail_link="http://some_link.com/123.jpg",
location="location",
)
newer_event = MobilizonEvent(
name="test event",
description="description of the event",
begin_datetime=datetime(year=2021, month=1, day=2, hour=11, minute=30),
end_datetime=datetime(year=2021, month=1, day=1, hour=12, minute=30),
last_accessed=datetime.now(),
mobilizon_link="http://some_link.com/123",
mobilizon_id="12345",
thumbnail_link="http://some_link.com/123.jpg",
location="location",
)
assert older_event.begins_before(newer_event)
@given(events())
def test_event_properties(event):
assert event.end_datetime > event.begin_datetime

View File

@ -0,0 +1,12 @@
from hypothesis import given
from hypothesis.strategies import lists
from tests import events
@given(
unpublished_events=lists(events(published=True), max_size=5),
published_events=lists(events(published=False), max_size=3),
)
def test_select_next_event_properties(unpublished_events, published_events):
pass