summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRomain Gonçalves <me@rgoncalves.se>2024-05-12 19:42:37 +0200
committerRomain Gonçalves <me@rgoncalves.se>2024-05-12 19:42:37 +0200
commite25603a0654be26ee0c5acf6fdd42e1c45c772ab (patch)
treeb2fae96b90dfe0a8b183c5036941fae990a6ea21
parentc4f52cd8853c18671797ce196f4a7d32afa6d6f5 (diff)
downloadcip_paris_client-trunk.tar.gz
feat: add tests from last yeartrunk
-rw-r--r--.gitignore1
-rw-r--r--cip_paris_client/client.py9
-rw-r--r--cip_paris_client/parsers.py58
-rw-r--r--cip_paris_client/tests/test_parsers.py9
-rw-r--r--poetry.lock119
-rw-r--r--pyproject.toml5
-rw-r--r--setup.cfg2
7 files changed, 175 insertions, 28 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..bee8a64
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+__pycache__
diff --git a/cip_paris_client/client.py b/cip_paris_client/client.py
index cc87f4d..bb58f39 100644
--- a/cip_paris_client/client.py
+++ b/cip_paris_client/client.py
@@ -38,7 +38,12 @@ def get_sessions(
stop_after: int = 10,
) -> Iterator[Session]:
"""Retrieve available movie sessions."""
- for category, page_index in itertools.product(MovieCategories, range(1, stop_after)):
- params = {"category": category.value, "page": page_index}
+ for category, page_index in itertools.product(
+ MovieCategories, range(1, stop_after)
+ ):
+ params = {
+ "category": category.value,
+ "page": page_index,
+ }
response = httpx.get(url, params=params)
yield parse_sessions(response.content)
diff --git a/cip_paris_client/parsers.py b/cip_paris_client/parsers.py
index e22de8e..34cc1ea 100644
--- a/cip_paris_client/parsers.py
+++ b/cip_paris_client/parsers.py
@@ -1,16 +1,13 @@
from datetime import (
date,
datetime,
+ time,
)
-from typing import TYPE_CHECKING
from selectolax.parser import HTMLParser
from cip_paris_client.schemas import Session
-if TYPE_CHECKING:
- from typing import Final
-
def is_released_next_year(
current_month: int,
@@ -25,40 +22,51 @@ def is_released_next_year(
def parse_date(date_str: str) -> date:
- """Parse the CIP date from webpage."""
- date_format: Final[str] = ""
+ """Parse date from the CIP webpage format."""
day, month = map(int, date_str.split()[1].split("/"))
-
- date = datetime.date
+ year = datetime.now().year
if is_released_next_year(datetime.now().month, month):
- print()
+ year += 1
+ return date(year=year, month=month, day=day)
-def parse_sessions(html: bytes) -> list[Session]:
- """Parse movie sessions from an html webpage."""
- movie_container_query: Final[str] = "div.movie-results-container"
- movie_name_query: Final[str] = "div.desc h3"
- sessions_container_query: Final[str] = "div.session-date > div.item"
- session_url_selector: Final[str] = "a"
- session_date_selector: Final[str] = "div.sessionDate"
- session_time_selector: Final[str] = "div p.time"
+def parse_time(time_str: str) -> time:
+ """Parse the time from the CIP webpage format."""
+ hour, minute = map(int, time_str.split(":"))
+ return time(hour=hour, minute=minute, second=0)
+
+
+def parse_sessions(
+ html: bytes,
+ movie_container_query: str = "div.movie-results-container",
+ movie_name_query: str = "div.desc h3",
+ sessions_container_query: str = "div.session-date > div.item",
+ session_url_selector: str = "a",
+ session_date_selector: str = "div.sessionDate",
+ session_time_selector: str = "div p.time",
+) -> list[Session]:
+ """Parse movie sessions from an html webpage."""
for movie_tree in HTMLParser(html).css(movie_container_query):
movie_name = movie_tree.css_first(movie_name_query).text()
for session_tree in movie_tree.css(sessions_container_query):
- attributes = session_tree.css_first(session_url_selector).attributes
- date: str = session_tree.css_first(session_date_selector).text()
- time: str = session_tree.css_first(session_time_selector).text()
-
- print(date)
- print(time)
+ # Extract attributes first, conversion is done later.
+ attributes = session_tree.css_first(
+ session_url_selector
+ ).attributes
+ date_str: str = session_tree.css_first(
+ session_date_selector
+ ).text()
+ time_str: str = session_tree.css_first(
+ session_time_selector
+ ).text()
yield Session(
url=attributes.get("href") or "",
cinema=attributes.get("title") or "",
movie=movie_name,
- date=date,
- time=time,
+ date=parse_date(date_str),
+ time=parse_time(time_str),
)
diff --git a/cip_paris_client/tests/test_parsers.py b/cip_paris_client/tests/test_parsers.py
new file mode 100644
index 0000000..8bc57e8
--- /dev/null
+++ b/cip_paris_client/tests/test_parsers.py
@@ -0,0 +1,9 @@
+from cip_paris_client import parsers
+
+
+def test_is_released_next_year_true() -> None:
+ assert parsers.is_released_next_year(9, 2) is True
+
+
+def test_is_released_next_year_false() -> None:
+ assert parsers.is_released_next_year(11, 8) is False
diff --git a/poetry.lock b/poetry.lock
index f2e54e1..ae3955f 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -43,6 +43,33 @@ files = [
]
[[package]]
+name = "colorama"
+version = "0.4.6"
+description = "Cross-platform colored terminal text."
+optional = false
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
+files = [
+ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
+ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
+]
+
+[[package]]
+name = "flake8"
+version = "6.1.0"
+description = "the modular source code checker: pep8 pyflakes and co"
+optional = false
+python-versions = ">=3.8.1"
+files = [
+ {file = "flake8-6.1.0-py2.py3-none-any.whl", hash = "sha256:ffdfce58ea94c6580c77888a86506937f9a1a227dfcd15f245d694ae20a6b6e5"},
+ {file = "flake8-6.1.0.tar.gz", hash = "sha256:d5b3857f07c030bdb5bf41c7f53799571d75c4491748a3adcd47de929e34cd23"},
+]
+
+[package.dependencies]
+mccabe = ">=0.7.0,<0.8.0"
+pycodestyle = ">=2.11.0,<2.12.0"
+pyflakes = ">=3.1.0,<3.2.0"
+
+[[package]]
name = "h11"
version = "0.14.0"
description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1"
@@ -109,6 +136,28 @@ files = [
]
[[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 = "mccabe"
+version = "0.7.0"
+description = "McCabe checker, plugin for flake8"
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"},
+ {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"},
+]
+
+[[package]]
name = "mypy"
version = "1.4.1"
description = "Optional static typing for Python"
@@ -165,6 +214,43 @@ files = [
]
[[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 = "pluggy"
+version = "1.2.0"
+description = "plugin and hook calling mechanisms for python"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "pluggy-1.2.0-py3-none-any.whl", hash = "sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849"},
+ {file = "pluggy-1.2.0.tar.gz", hash = "sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3"},
+]
+
+[package.extras]
+dev = ["pre-commit", "tox"]
+testing = ["pytest", "pytest-benchmark"]
+
+[[package]]
+name = "pycodestyle"
+version = "2.11.0"
+description = "Python style guide checker"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "pycodestyle-2.11.0-py2.py3-none-any.whl", hash = "sha256:5d1013ba8dc7895b548be5afb05740ca82454fd899971563d2ef625d090326f8"},
+ {file = "pycodestyle-2.11.0.tar.gz", hash = "sha256:259bcc17857d8a8b3b4a2327324b79e5f020a13c16074670f9c8c8f872ea76d0"},
+]
+
+[[package]]
name = "pydantic"
version = "2.1.1"
description = "Data validation using Python type hints"
@@ -297,6 +383,37 @@ files = [
typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
[[package]]
+name = "pyflakes"
+version = "3.1.0"
+description = "passive checker of Python programs"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "pyflakes-3.1.0-py2.py3-none-any.whl", hash = "sha256:4132f6d49cb4dae6819e5379898f2b8cce3c5f23994194c24b77d5da2e36f774"},
+ {file = "pyflakes-3.1.0.tar.gz", hash = "sha256:a0aae034c444db0071aa077972ba4768d40c830d9539fd45bf4cd3f8f6992efc"},
+]
+
+[[package]]
+name = "pytest"
+version = "7.4.0"
+description = "pytest: simple powerful testing with Python"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "pytest-7.4.0-py3-none-any.whl", hash = "sha256:78bf16451a2eb8c7a2ea98e32dc119fd2aa758f1d5d66dbf0a59d69a3969df32"},
+ {file = "pytest-7.4.0.tar.gz", hash = "sha256:b4bf8c45bd59934ed84001ad51e11b4ee40d40a1229d2c79f9c592b0a3f6bd8a"},
+]
+
+[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 = "selectolax"
version = "0.3.16"
description = "Fast HTML5 parser with CSS selectors."
@@ -390,4 +507,4 @@ files = [
[metadata]
lock-version = "2.0"
python-versions = "^3.11"
-content-hash = "06b33a781cca0f4e6524ce0740f007a81e3e992c6b2e6b66475f4a1907b0ac04"
+content-hash = "ad04dae340bc1184b4114acb46e9c2455840140586b1c5ef96597c4b233da519"
diff --git a/pyproject.toml b/pyproject.toml
index e62c337..b36e2c5 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -13,6 +13,8 @@ pydantic = "^2.1.1"
httpx = "^0.24.1"
mypy = "^1.4.1"
selectolax = "^0.3.16"
+pytest = "^7.4.0"
+flake8 = "^6.1.0"
[tool.mypy]
plugins = [
@@ -32,6 +34,9 @@ init_forbid_extra = true
init_typed = true
warn_required_dynamic_aliases = true
+[tool.black]
+line-length = 79
+
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..bfead2c
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,2 @@
+[flake8]
+max-line-length = 79
remember that computers suck.