From 4257d2deffe325ef2edc9d5f65bc41a4d67c121d Mon Sep 17 00:00:00 2001 From: Buried-In-Code <6057651+Buried-In-Code@users.noreply.github.com> Date: Fri, 14 Nov 2025 10:47:05 +1300 Subject: [PATCH] Remove Marvel/Esak --- .pre-commit-config.yaml | 6 +- README.md | 9 +- perdoo/__main__.py | 6 +- perdoo/services/__init__.py | 3 +- perdoo/services/marvel.py | 289 ---------------------------------- perdoo/settings.py | 10 +- perdoo/utils.py | 2 - pyproject.toml | 13 +- tests/services/marvel_test.py | 97 ------------ uv.lock | 89 +++++------ 10 files changed, 51 insertions(+), 473 deletions(-) delete mode 100644 perdoo/services/marvel.py delete mode 100644 tests/services/marvel_test.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 49fd34c..1387956 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,16 +1,16 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.14.4 + rev: v0.14.5 hooks: - id: ruff-format - id: ruff-check - - repo: https://github.com/executablebooks/mdformat + - repo: https://github.com/hukkin/mdformat rev: 1.0.0 hooks: - id: mdformat additional_dependencies: - mdformat-gfm - - mdformat-tables + - mdformat-ruff args: - --number - --wrap=keep diff --git a/README.md b/README.md index a5693b6..d179073 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,6 @@ Unlike other tagging tools, Perdoo employs a manual approach when metadata files ## Services - [Comicvine](https://comicvine.gamespot.com) using the [Simyan](https://github.com/Metron-Project/Simyan) library. -- [Marvel](https://www.marvel.com/comics) using the [Esak](https://github.com/Metron-Project/Esak) library. - [Metron](https://metron.cloud) using the [Mokkari](https://github.com/Metron-Project/Mokkari) library. ## File Renaming and Organization @@ -168,15 +167,11 @@ single_issue = "" trade_paperback = "" [services] -order = ["Metron", "Marvel", "Comicvine"] +order = ["Metron", "Comicvine"] [services.comicvine] api_key = "" -[services.marvel] -public_key = "" -private_key = "" - [services.metron] username = "" password = "" @@ -219,7 +214,7 @@ password = "" The order in which the services will be used for metadata retrieval. Metadata will be fetched from the first service that returns a result. Don't include the service name in the list if you don't want to use it. - Defaults to `["Metron", "Marvel", "Comicvine"]`, options are `Metron`, `Marvel` and `Comicvine`. + Defaults to `["Metron", "Comicvine"]`, options are `Metron` and `Comicvine`. ## Socials diff --git a/perdoo/__main__.py b/perdoo/__main__.py index 14657a2..384c49d 100644 --- a/perdoo/__main__.py +++ b/perdoo/__main__.py @@ -15,7 +15,7 @@ from perdoo.metadata import ComicInfo, MetronInfo from perdoo.metadata.comic_info import Page from perdoo.metadata.metron_info import Id, InformationSource -from perdoo.services import BaseService, Comicvine, Marvel, Metron +from perdoo.services import BaseService, Comicvine, Metron from perdoo.settings import Service, Services, Settings from perdoo.utils import ( IssueSearch, @@ -63,8 +63,6 @@ def get_services(settings: Services) -> dict[Service, BaseService]: output = {} if settings.comicvine.api_key: output[Service.COMICVINE] = Comicvine(settings.comicvine) - if settings.marvel.public_key and settings.marvel.private_key: - output[Service.MARVEL] = Marvel(settings.marvel) if settings.metron.username and settings.metron.password: output[Service.METRON] = Metron(settings.metron) return output @@ -94,13 +92,11 @@ def _create_search_from_metron(metron_info: MetronInfo) -> Search: volume=metron_info.series.volume, year=metron_info.series.start_year, comicvine=series_id if source == InformationSource.COMIC_VINE else None, - marvel=series_id if source == InformationSource.MARVEL else None, metron=series_id if source == InformationSource.METRON else None, ), issue=IssueSearch( number=metron_info.number, comicvine=_get_id_value(metron_info.ids, InformationSource.COMIC_VINE), - marvel=_get_id_value(metron_info.ids, InformationSource.MARVEL), metron=_get_id_value(metron_info.ids, InformationSource.METRON), ), ) diff --git a/perdoo/services/__init__.py b/perdoo/services/__init__.py index 2b29fa7..5e35778 100644 --- a/perdoo/services/__init__.py +++ b/perdoo/services/__init__.py @@ -1,6 +1,5 @@ -__all__ = ["BaseService", "Comicvine", "Marvel", "Metron"] +__all__ = ["BaseService", "Comicvine", "Metron"] from perdoo.services._base import BaseService from perdoo.services.comicvine import Comicvine -from perdoo.services.marvel import Marvel from perdoo.services.metron import Metron diff --git a/perdoo/services/marvel.py b/perdoo/services/marvel.py deleted file mode 100644 index 1aae9e1..0000000 --- a/perdoo/services/marvel.py +++ /dev/null @@ -1,289 +0,0 @@ -__all__ = ["Marvel"] - -import logging -from datetime import datetime - -from esak.exceptions import ApiError -from esak.schemas.comic import Comic -from esak.schemas.series import Series -from esak.session import Session as Esak -from esak.sqlite_cache import SqliteCache -from natsort import humansorted, ns -from prompt_toolkit.styles import Style -from questionary import Choice, confirm, select, text -from requests.exceptions import ConnectionError, HTTPError # noqa: A004 - -from perdoo import get_cache_root -from perdoo.metadata import ComicInfo, MetronInfo -from perdoo.services._base import BaseService -from perdoo.settings import Marvel as MarvelSettings -from perdoo.utils import IssueSearch, Search, SeriesSearch - -LOGGER = logging.getLogger(__name__) -DEFAULT_CHOICE = Choice(title="None of the Above", value=None) - - -class Marvel(BaseService[Series, Comic]): - def __init__(self, settings: MarvelSettings): - cache = SqliteCache(db_name=str(get_cache_root() / "esak.sqlite"), expire=14) - self.session = Esak( - public_key=settings.public_key, private_key=settings.private_key, cache=cache - ) - - def _search_series( - self, name: str | None, volume: int | None, year: int | None, filename: str - ) -> int | None: - name = name or text(message="Series Name").ask() - try: - params = {"title": name} - if year: - params["startYear"] = year - options = sorted( - self.session.series_list(params=params), key=lambda x: (x.title, x.start_year) - ) - if options: - search = name - if volume: - search += f" v{volume}" - if year: - search += f" ({year})" - choices = [ - Choice( - title=[("class:dim", f"{x.id} | "), ("class:title", x.title)], - description=f"https://www.marvel.com/comics/series/{x.id}", - value=x, - ) - for x in options - ] - choices.append(DEFAULT_CHOICE) - selected = select( - f"Searching Marvel for Series matching '{filename}'" - if not year - else f"Searching Marvel for Series '{search}'", - default=DEFAULT_CHOICE, - choices=choices, - style=Style([("dim", "dim")]), - ).ask() - if selected and selected != DEFAULT_CHOICE.title: - return selected.id - else: - LOGGER.warning("Unable to find any Series for the file: '%s'", filename) - if year: - LOGGER.info("Searching again without the StartYear") - return self._search_series(name=name, volume=volume, year=None, filename=filename) - if confirm(message="Search Again", default=False).ask(): - return self._search_series(name=None, volume=None, year=None, filename=filename) - except ConnectionError as err: - LOGGER.error(err) - except HTTPError as err: - LOGGER.error(err) - except ApiError as err: - LOGGER.error(err) - return None - - def fetch_series(self, search: SeriesSearch, filename: str) -> Series | None: - series_id = search.marvel or self._search_series( - name=search.name, volume=search.volume, year=search.year, filename=filename - ) - if not series_id: - return None - try: - series = self.session.series(_id=series_id) - search.marvel = series_id - return series - except ConnectionError as err: - LOGGER.error(err) - return None - except HTTPError as err: - LOGGER.error(err) - return None - except ApiError as err: - LOGGER.error(err) - if search.marvel: - search.marvel = None - return self.fetch_series(search=search, filename=filename) - return None - - def _search_issue(self, series_id: int, number: str | None, filename: str) -> int | None: - try: - options = humansorted( - self.session.comics_list( - params={"noVariants": True, "series": series_id, "issueNumber": number} - if number - else {"noVariants": True, "series": series_id} - ), - key=lambda x: x.issue_number, - alg=ns.NA | ns.G, - ) - if options: - choices = [ - Choice( - title=[ - ("class:dim", f"{x.id} | "), - ("class:title", f"{x.series.name} #{x.issue_number} - {x.format}"), - ], - description=f"https://www.marvel.com/comics/issue/{x.id}", - value=x, - ) - for x in options - ] - choices.append(DEFAULT_CHOICE) - selected = select( - f"Searching Marvel for Comics matching '{filename}'" - if not number - else f"Searching Marvel for Comics with number '{number}'", - default=DEFAULT_CHOICE, - choices=choices, - style=Style([("dim", "dim")]), - ).ask() - if selected and selected != DEFAULT_CHOICE.title: - return selected.id - else: - LOGGER.warning("Unable to find any Comics for the file: '%s'", filename) - if number: - LOGGER.info("Searching again without the IssueNumber") - return self._search_issue(series_id=series_id, number=None, filename=filename) - except ConnectionError as err: - LOGGER.error(err) - except HTTPError as err: - LOGGER.error(err) - except ApiError as err: - LOGGER.error(err) - return None - - def fetch_issue(self, series_id: int, search: IssueSearch, filename: str) -> Comic | None: - issue_id = search.marvel or self._search_issue( - series_id=series_id, number=search.number, filename=filename - ) - if not issue_id: - return None - try: - issue = self.session.comic(_id=issue_id) - search.marvel = issue_id - return issue - except ConnectionError as err: - LOGGER.error(err) - return None - except HTTPError as err: - LOGGER.error(err) - return None - except ApiError as err: - LOGGER.error(err) - if search.marvel: - search.marvel = None - return self.fetch_issue(series_id=series_id, search=search, filename=filename) - return None - - def _process_metron_info(self, series: Series, issue: Comic) -> MetronInfo | None: - from perdoo.metadata.metron_info import ( # noqa: PLC0415 - GTIN, - AgeRating, - Arc, - Credit, - Format, - Id, - InformationSource, - Price, - Publisher, - Resource, - Role, - Series, - Url, - ) - - def load_format(value: str) -> Format: - try: - return Format.load(value=value.strip()) - except ValueError: - return Format.SINGLE_ISSUE - - def load_age_rating(value: str) -> AgeRating: - try: - return AgeRating.load(value=value.strip()) - except ValueError: - return AgeRating.UNKNOWN - - def load_role(value: str) -> Role: - try: - return Role.load(value=value.strip()) - except ValueError: - return Role.OTHER - - return MetronInfo( - ids=[Id(primary=True, source=InformationSource.MARVEL, value=str(issue.id))], - publisher=Publisher(name="Marvel"), - series=Series( - id=str(series.id), - name=series.title, - format=load_format(value=issue.format), - start_year=series.start_year, - ), - collection_title=issue.title, - number=issue.issue_number, - stories=[Resource[str](id=str(x.id), value=x.name) for x in issue.stories], - summary=issue.description, - prices=[Price(country="US", value=issue.prices.print)] if issue.prices else [], - store_date=issue.dates.on_sale, - page_count=issue.page_count, - arcs=[Arc(id=str(x.id), name=x.name) for x in issue.events], - characters=[Resource[str](id=str(x.id), value=x.name) for x in issue.characters], - gtin=GTIN(isbn=issue.isbn, upc=issue.upc) if issue.isbn and issue.upc else None, - age_rating=load_age_rating(value=series.rating), - urls=[Url(primary=True, value=issue.urls.detail)], - credits=[ - Credit( - creator=Resource[str](id=str(x.id), value=x.name), - roles=[Resource[Role](value=load_role(value=x.role))], - ) - for x in issue.creators - ], - last_modified=datetime.now(), - ) - - def _process_comic_info(self, series: Series, issue: Comic) -> ComicInfo | None: - from perdoo.metadata.comic_info import AgeRating # noqa: PLC0415 - - def load_age_rating(value: str) -> AgeRating: - try: - return AgeRating.load(value=value.strip()) - except ValueError: - return AgeRating.UNKNOWN - - comic_info = ComicInfo( - title=issue.title, - series=series.title, - number=issue.issue_number, - summary=issue.description, - publisher="Marvel", - web=issue.urls.detail, - page_count=issue.page_count, - format=issue.format, - age_rating=load_age_rating(value=series.rating), - ) - - comic_info.credits = {x.name: x.role.strip() for x in issue.creators} - comic_info.character_list = [x.name for x in issue.characters] - comic_info.story_arc_list = [x.name for x in issue.events] - - return comic_info - - def fetch(self, search: Search) -> tuple[MetronInfo | None, ComicInfo | None]: - if not search.series.marvel and search.issue.marvel: - try: - temp = self.session.comic(_id=search.issue.marvel) - search.series.marvel = temp.series.id - except ApiError: - pass - - series = self.fetch_series(search=search.series, filename=search.filename) - if not series: - return None, None - - issue = self.fetch_issue(series_id=series.id, search=search.issue, filename=search.filename) - if not issue: - return None, None - - metron_info = self._process_metron_info(series=series, issue=issue) - comic_info = self._process_comic_info(series=series, issue=issue) - - return metron_info, comic_info diff --git a/perdoo/settings.py b/perdoo/settings.py index d8dfd40..c4808da 100644 --- a/perdoo/settings.py +++ b/perdoo/settings.py @@ -1,7 +1,6 @@ __all__ = [ "ComicInfo", "Comicvine", - "Marvel", "Metron", "MetronInfo", "Naming", @@ -84,11 +83,6 @@ class Comicvine(SettingsModel): api_key: Annotated[str | None, BeforeValidator(blank_is_none)] = None -class Marvel(SettingsModel): - public_key: Annotated[str | None, BeforeValidator(blank_is_none)] = None - private_key: Annotated[str | None, BeforeValidator(blank_is_none)] = None - - class Metron(SettingsModel): password: Annotated[str | None, BeforeValidator(blank_is_none)] = None username: Annotated[str | None, BeforeValidator(blank_is_none)] = None @@ -96,7 +90,6 @@ class Metron(SettingsModel): class Service(str, Enum): COMICVINE = "Comicvine" - MARVEL = "Marvel" METRON = "Metron" def __str__(self) -> str: @@ -105,9 +98,8 @@ def __str__(self) -> str: class Services(SettingsModel): comicvine: Comicvine = Comicvine() - marvel: Marvel = Marvel() metron: Metron = Metron() - order: tuple[Service, ...] = (Service.METRON, Service.MARVEL, Service.COMICVINE) + order: tuple[Service, ...] = (Service.METRON, Service.COMICVINE) def _stringify_values(content: dict[str, Any]) -> dict[str, Any]: diff --git a/perdoo/utils.py b/perdoo/utils.py index e76843c..62cc1b3 100644 --- a/perdoo/utils.py +++ b/perdoo/utils.py @@ -46,7 +46,6 @@ class SeriesSearch: volume: int | None = None year: int | None = None comicvine: str | None = None - marvel: str | None = None metron: str | None = None @@ -54,7 +53,6 @@ class SeriesSearch: class IssueSearch: number: str | None = None comicvine: str | None = None - marvel: str | None = None metron: str | None = None diff --git a/pyproject.toml b/pyproject.toml index c339ea1..d79c12f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,12 +4,12 @@ requires = ["hatchling"] [dependency-groups] dev = [ - "pre-commit >= 4.3.0" + "pre-commit >= 4.4.0" ] tests = [ - "pytest >= 8.4.0", + "pytest >= 9.0.0", "pytest-cov >= 7.0.0", - "tox >= 4.31.0", + "tox >= 4.32.0", "tox-uv >= 1.29.0" ] @@ -34,11 +34,10 @@ classifiers = [ dependencies = [ "comicfn2dict >= 0.2.0", "darkseid >= 7.1.0", - "esak >= 2.0.0", "lxml >= 6.0.0", - "mokkari >= 3.13.0", + "mokkari >= 3.14.0", "natsort >= 8.4.0", - "pillow >= 11.3.0", + "pillow >= 12.0.0", "pydantic >= 2.12.0", "pydantic-xml >= 2.18.0", "questionary >= 2.1.0", @@ -46,7 +45,7 @@ dependencies = [ "simyan >= 1.6.0", "tomli >= 2.3.0 ; python_version < '3.11'", "tomli-w >= 1.2.0", - "typer >= 0.19.0" + "typer >= 0.20.0" ] description = "Unify and organize your comic collection." dynamic = ["version"] diff --git a/tests/services/marvel_test.py b/tests/services/marvel_test.py deleted file mode 100644 index fe4ba2a..0000000 --- a/tests/services/marvel_test.py +++ /dev/null @@ -1,97 +0,0 @@ -from unittest.mock import MagicMock, patch - -import pytest -from esak.schemas.comic import Comic -from esak.schemas.series import Series - -from perdoo.services.marvel import DEFAULT_CHOICE, Marvel -from perdoo.settings import Marvel as MarvelSettings -from perdoo.utils import IssueSearch, SeriesSearch - - -@pytest.fixture -def service() -> Marvel: - settings = MarvelSettings(private_key="private-key", public_key="public-key") - return Marvel(settings=settings) - - -@pytest.fixture -def series_mock() -> Series: - return MagicMock() - - -@pytest.fixture -def comic_mock() -> Comic: - return MagicMock() - - -def test_search_series(service: Marvel, series_mock: Series) -> None: - with ( - patch.object(service.session, "series_list", return_value=[series_mock]), - patch("perdoo.services.marvel.select") as mock_select, - ): - mock_select.return_value.ask.return_value = series_mock - found = service._search_series(name="Venom", volume=None, year=None, filename="Venom") # noqa: SLF001 - assert found == series_mock.id - - -def test_search_series_default(service: Marvel, series_mock: Series) -> None: - with ( - patch.object(service.session, "series_list", return_value=[series_mock, series_mock]), - patch("perdoo.services.marvel.select") as select_mock, - patch("perdoo.services.marvel.confirm") as confirm_mock, - ): - select_mock.return_value.ask.return_value = DEFAULT_CHOICE.title - confirm_mock.return_value.ask.return_value = False - found = service._search_series(name="Venom", volume=None, year=None, filename="Venom") # noqa: SLF001 - assert found is None - - -def test_search_series_no_results(service: Marvel) -> None: - with ( - patch.object(service.session, "series_list", return_value=[]), - patch("perdoo.services.marvel.confirm") as confirm_mock, - ): - confirm_mock.return_value.ask.return_value = False - found = service._search_series(name="Venom", volume=None, year=None, filename="Venom") # noqa: SLF001 - assert found is None - - -def test_fetch_series(service: Marvel, series_mock: Series) -> None: - with patch.object(service.session, "series", return_value=series_mock): - mock_search = SeriesSearch(name="Venom", marvel=series_mock.id) - found = service.fetch_series(search=mock_search, filename="Venom") - assert found == series_mock - - -def test_search_issues(service: Marvel, comic_mock: Comic) -> None: - with ( - patch.object(service.session, "comics_list", return_value=[comic_mock]), - patch("perdoo.services.marvel.select") as mock_select, - ): - mock_select.return_value.ask.return_value = comic_mock - found = service._search_issue(series_id=466, number="1", filename="Venom") # noqa: SLF001 - assert found == comic_mock.id - - -def test_search_issues_default(service: Marvel, comic_mock: Comic) -> None: - with ( - patch.object(service.session, "comics_list", return_value=[comic_mock, comic_mock]), - patch("perdoo.services.marvel.select") as select_mock, - ): - select_mock.return_value.ask.return_value = DEFAULT_CHOICE.title - found = service._search_issue(series_id=466, number="1", filename="Venom") # noqa: SLF001 - assert found is None - - -def test_search_issues_no_results(service: Marvel) -> None: - with patch.object(service.session, "comics_list", return_value=[]): - found = service._search_issue(series_id=466, number="1", filename="Venom") # noqa: SLF001 - assert found is None - - -def test_fetch_issue(service: Marvel, comic_mock: Comic) -> None: - with patch.object(service.session, "comic", return_value=comic_mock): - mock_search = IssueSearch(marvel=comic_mock.id) - found = service.fetch_issue(series_id=466, search=mock_search, filename="Venom") - assert found == comic_mock diff --git a/uv.lock b/uv.lock index 3514bc4..fd9ab0f 100644 --- a/uv.lock +++ b/uv.lock @@ -93,20 +93,20 @@ wheels = [ [[package]] name = "cachetools" -version = "6.2.1" +version = "6.2.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cc/7e/b975b5814bd36faf009faebe22c1072a1fa1168db34d285ef0ba071ad78c/cachetools-6.2.1.tar.gz", hash = "sha256:3f391e4bd8f8bf0931169baf7456cc822705f4e2a31f840d218f445b9a854201", size = 31325, upload-time = "2025-10-12T14:55:30.139Z" } +sdist = { url = "https://files.pythonhosted.org/packages/fb/44/ca1675be2a83aeee1886ab745b28cda92093066590233cc501890eb8417a/cachetools-6.2.2.tar.gz", hash = "sha256:8e6d266b25e539df852251cfd6f990b4bc3a141db73b939058d809ebd2590fc6", size = 31571, upload-time = "2025-11-13T17:42:51.465Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/96/c5/1e741d26306c42e2bf6ab740b2202872727e0f606033c9dd713f8b93f5a8/cachetools-6.2.1-py3-none-any.whl", hash = "sha256:09868944b6dde876dfd44e1d47e18484541eaf12f26f29b7af91b26cc892d701", size = 11280, upload-time = "2025-10-12T14:55:28.382Z" }, + { url = "https://files.pythonhosted.org/packages/e6/46/eb6eca305c77a4489affe1c5d8f4cae82f285d9addd8de4ec084a7184221/cachetools-6.2.2-py3-none-any.whl", hash = "sha256:6c09c98183bf58560c97b2abfcedcbaf6a896a490f534b031b661d3723b45ace", size = 11503, upload-time = "2025-11-13T17:42:50.232Z" }, ] [[package]] name = "certifi" -version = "2025.10.5" +version = "2025.11.12" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4c/5b/b6ce21586237c77ce67d01dc5507039d444b630dd76611bbca2d8e5dcd91/certifi-2025.10.5.tar.gz", hash = "sha256:47c09d31ccf2acf0be3f701ea53595ee7e0b8fa08801c6624be771df09ae7b43", size = 164519, upload-time = "2025-10-05T04:12:15.808Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/8c/58f469717fa48465e4a50c014a0400602d3c437d7c0c468e17ada824da3a/certifi-2025.11.12.tar.gz", hash = "sha256:d8ab5478f2ecd78af242878415affce761ca6bc54a22a27e026d7c25357c3316", size = 160538, upload-time = "2025-11-12T02:54:51.517Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e4/37/af0d2ef3967ac0d6113837b44a4f0bfe1328c2b9763bd5b1744520e5cfed/certifi-2025.10.5-py3-none-any.whl", hash = "sha256:0f212c2744a9bb6de0c56639a6f68afe01ecd92d91f14ae897c4fe7bbeeef0de", size = 163286, upload-time = "2025-10-05T04:12:14.03Z" }, + { url = "https://files.pythonhosted.org/packages/70/7d/9bc192684cea499815ff478dfcdc13835ddf401365057044fb721ec6bddb/certifi-2025.11.12-py3-none-any.whl", hash = "sha256:97de8790030bbd5c2d96b7ec782fc2f7820ef8dba6db909ccf95449f2d062d4b", size = 159438, upload-time = "2025-11-12T02:54:49.735Z" }, ] [[package]] @@ -481,19 +481,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a9/b6/f85666707b9f9ff94ada851cbaa6f1c91a0f5802aa5e498772251e1e7772/elementpath-5.0.4-py3-none-any.whl", hash = "sha256:75d6f31c614d57e50eb749fc50806e3102880cd1f6552da3f2265f8eb8d3bbc6", size = 245512, upload-time = "2025-08-16T18:19:52.903Z" }, ] -[[package]] -name = "esak" -version = "2.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pydantic" }, - { name = "requests" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ec/43/8548361d99e50883c96813e5d8a4b954ef54baf236ea28039a1fa13a9b43/esak-2.0.0.tar.gz", hash = "sha256:3caeff8b6b69c9c2ac27990623dad4e868f631ecdcfdbb9b7c34733407cf7256", size = 336486, upload-time = "2024-11-26T16:56:17.999Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/37/54/da4abf304f5bd0e8efc3c5c6923fa53c750dd05207eecb8ec7445c95958c/esak-2.0.0-py3-none-any.whl", hash = "sha256:84d838d6c4472f4608169e634a330b3c375e7bbbbe2ffb804363e2608850b1b4", size = 16971, upload-time = "2024-11-26T16:56:15.952Z" }, -] - [[package]] name = "exceptiongroup" version = "1.3.0" @@ -791,7 +778,6 @@ source = { editable = "." } dependencies = [ { name = "comicfn2dict" }, { name = "darkseid" }, - { name = "esak" }, { name = "lxml" }, { name = "mokkari" }, { name = "natsort" }, @@ -827,11 +813,10 @@ requires-dist = [ { name = "comicfn2dict", specifier = ">=0.2.0" }, { name = "darkseid", specifier = ">=7.1.0" }, { name = "darkseid", extras = ["7zip"], marker = "extra == 'cb7'", specifier = ">=7.1.0" }, - { name = "esak", specifier = ">=2.0.0" }, { name = "lxml", specifier = ">=6.0.0" }, - { name = "mokkari", specifier = ">=3.13.0" }, + { name = "mokkari", specifier = ">=3.14.0" }, { name = "natsort", specifier = ">=8.4.0" }, - { name = "pillow", specifier = ">=11.3.0" }, + { name = "pillow", specifier = ">=12.0.0" }, { name = "pydantic", specifier = ">=2.12.0" }, { name = "pydantic-xml", specifier = ">=2.18.0" }, { name = "questionary", specifier = ">=2.1.0" }, @@ -839,16 +824,16 @@ requires-dist = [ { name = "simyan", specifier = ">=1.6.0" }, { name = "tomli", marker = "python_full_version < '3.11'", specifier = ">=2.3.0" }, { name = "tomli-w", specifier = ">=1.2.0" }, - { name = "typer", specifier = ">=0.19.0" }, + { name = "typer", specifier = ">=0.20.0" }, ] provides-extras = ["cb7"] [package.metadata.requires-dev] -dev = [{ name = "pre-commit", specifier = ">=4.3.0" }] +dev = [{ name = "pre-commit", specifier = ">=4.4.0" }] tests = [ - { name = "pytest", specifier = ">=8.4.0" }, + { name = "pytest", specifier = ">=9.0.0" }, { name = "pytest-cov", specifier = ">=7.0.0" }, - { name = "tox", specifier = ">=4.31.0" }, + { name = "tox", specifier = ">=4.32.0" }, { name = "tox-uv", specifier = ">=1.29.0" }, ] @@ -1371,7 +1356,7 @@ wheels = [ [[package]] name = "pytest" -version = "9.0.0" +version = "9.0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, @@ -1382,9 +1367,9 @@ dependencies = [ { name = "pygments" }, { name = "tomli", marker = "python_full_version < '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/da/1d/eb34f286b164c5e431a810a38697409cca1112cee04b287bb56ac486730b/pytest-9.0.0.tar.gz", hash = "sha256:8f44522eafe4137b0f35c9ce3072931a788a21ee40a2ed279e817d3cc16ed21e", size = 1562764, upload-time = "2025-11-08T17:25:33.34Z" } +sdist = { url = "https://files.pythonhosted.org/packages/07/56/f013048ac4bc4c1d9be45afd4ab209ea62822fb1598f40687e6bf45dcea4/pytest-9.0.1.tar.gz", hash = "sha256:3e9c069ea73583e255c3b21cf46b8d3c56f6e3a1a8f6da94ccb0fcf57b9d73c8", size = 1564125, upload-time = "2025-11-12T13:05:09.333Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/72/99/cafef234114a3b6d9f3aaed0723b437c40c57bdb7b3e4c3a575bc4890052/pytest-9.0.0-py3-none-any.whl", hash = "sha256:e5ccdf10b0bac554970ee88fc1a4ad0ee5d221f8ef22321f9b7e4584e19d7f96", size = 373364, upload-time = "2025-11-08T17:25:31.811Z" }, + { url = "https://files.pythonhosted.org/packages/0b/8b/6300fb80f858cda1c51ffa17075df5d846757081d11ab4aa35cef9e6258b/pytest-9.0.1-py3-none-any.whl", hash = "sha256:67be0030d194df2dfa7b556f2e56fb3c3315bd5c8822c6951162b92b32ce7dad", size = 373668, upload-time = "2025-11-12T13:05:07.379Z" }, ] [[package]] @@ -1774,28 +1759,28 @@ wheels = [ [[package]] name = "uv" -version = "0.9.8" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d7/78/291b32fdcc774b8ba4a0f4570af44af6cd34ef7385537d6521c7e3280030/uv-0.9.8.tar.gz", hash = "sha256:99b18bfe92c33c3862b65d74677697e799763e669e0064685f405e7e27517f25", size = 3709979, upload-time = "2025-11-07T20:41:33.748Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/11/5d/4db5a4e72f70e15491ca33289092cd127d1220861bc647ebf743ea844cd7/uv-0.9.8-py3-none-linux_armv6l.whl", hash = "sha256:d93a2227d23e81ab3a16c30363559afc483e8aca40ea9343b3f326a9a41718c9", size = 20566439, upload-time = "2025-11-07T20:40:26.268Z" }, - { url = "https://files.pythonhosted.org/packages/e6/76/3ffedb2ba3adf71719996cb4c2660a333d2267503823a02e184a839e1d4e/uv-0.9.8-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:7038a552159f2291dd0d1f4f66a36261b5f3ed5fcd92e2869186f8e910b2c935", size = 19705224, upload-time = "2025-11-07T20:40:31.384Z" }, - { url = "https://files.pythonhosted.org/packages/da/37/7716dd87189a6b062502ea41650eccd2473b6ee54b37cdf6e90a3b1aaa17/uv-0.9.8-py3-none-macosx_11_0_arm64.whl", hash = "sha256:9f2f3576c4518ff4f15e48dbca70585a513523c4738bc8cc2e48b20fd1190ce3", size = 18213823, upload-time = "2025-11-07T20:40:34.962Z" }, - { url = "https://files.pythonhosted.org/packages/8d/ed/7aa302fac3d6c880df6bdbba3fb6b4d8cded023b1398f99576dcb103051a/uv-0.9.8-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:50d130c46d97d7f10675ebea8608b7b4722c84b5745cd1bb0c8ae6d7984c05d5", size = 20090145, upload-time = "2025-11-07T20:40:38.842Z" }, - { url = "https://files.pythonhosted.org/packages/72/d2/2539fe7ecf03f5fa3dfcc4c39f59ade412bd1b8e89c9ae026b5a2d7da3dd/uv-0.9.8-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6df2e16f6df32018047c60bab2c0284868ad5c309addba9183ea2eeb71746bf0", size = 20218906, upload-time = "2025-11-07T20:40:42.189Z" }, - { url = "https://files.pythonhosted.org/packages/f7/29/2923cd822b9a1dc9b99513a00d2102c7ef979ac3001e9541e72a1e7fca07/uv-0.9.8-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:543693def38fa41b9706aba391111fe8d9dd6be86899d76f9581faf045ac1cb6", size = 21061669, upload-time = "2025-11-07T20:40:47.663Z" }, - { url = "https://files.pythonhosted.org/packages/72/c6/46b9fe190e6fafb6bf04d870ccfd547e69aa79d0448a5c2c5799f1c0850e/uv-0.9.8-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:1b8b5bdcda3e10ea70b618d0609acddc5c725cb58d4caf933030ddedd7c2e98f", size = 22668783, upload-time = "2025-11-07T20:40:51.172Z" }, - { url = "https://files.pythonhosted.org/packages/94/80/ec48165c76f863bbfcb0721aa1543cd3e7209c0cb8fdf89fe3d4e16694e2/uv-0.9.8-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a4010b3fdabbb3c4f2cf2f7aa3bf6002d00049dcbc54ce0ee5ada32a933b2290", size = 22319178, upload-time = "2025-11-07T20:40:54.719Z" }, - { url = "https://files.pythonhosted.org/packages/33/6c/2dbda528a2cd7a87a7363e8a9aad3033bff12c8b071a5e462eb852e704fd/uv-0.9.8-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75671150d6eb9d5ee829e1fdb8cf86b8e44a66d27cbb996fe807e986c4107b5d", size = 21398576, upload-time = "2025-11-07T20:40:58.509Z" }, - { url = "https://files.pythonhosted.org/packages/90/66/07e7067ace0886212217380b6e809f7dd1fed3d35c34be8d02124a656b17/uv-0.9.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14670bf55ecb5cfd0f3654fbf51c58a21dec3ad8ab531079b3ed8599271dc77b", size = 21346696, upload-time = "2025-11-07T20:41:01.931Z" }, - { url = "https://files.pythonhosted.org/packages/35/98/5b8fad804d17e76a2861c932009b0d34c7d5e3517923a808b168c2d92f2b/uv-0.9.8-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:40253d00c1e900a0a61b132b1e0dd4aa83575cfd5302d3671899b6de29b1ef67", size = 20159753, upload-time = "2025-11-07T20:41:05.51Z" }, - { url = "https://files.pythonhosted.org/packages/5d/e4/32b74e9246e71f27b8710ba44be6bfd8bdcf552dce211cecd4d1061705cc/uv-0.9.8-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:f52c6a99197028a314d4c1825f7ccb696eb9a88b822d2e2f17046266c75e543e", size = 21299928, upload-time = "2025-11-07T20:41:09.285Z" }, - { url = "https://files.pythonhosted.org/packages/b2/35/003035bc2da31cc9925a62b1510a821d701c117cf0327ab0a1df5c83db34/uv-0.9.8-py3-none-musllinux_1_1_armv7l.whl", hash = "sha256:5af28f1645eb3c50fd34a78508792db2d0799816f4eb5f55e1e6e2c724dfb125", size = 20170593, upload-time = "2025-11-07T20:41:12.745Z" }, - { url = "https://files.pythonhosted.org/packages/d7/b4/8c3d7afdc87ef07b51b87646a4c75ee5209b7f9f99a33d54746b7ee0f157/uv-0.9.8-py3-none-musllinux_1_1_i686.whl", hash = "sha256:cdbfadca9522422ab9820f5ada071c9c5c869bcd6fee719d20d91d5ec85b2a7d", size = 20560556, upload-time = "2025-11-07T20:41:16.85Z" }, - { url = "https://files.pythonhosted.org/packages/64/43/6045bb0b69c788620df4750de57319f56a9b5bd02eef56f28af0de25c117/uv-0.9.8-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:87c3b65b6d5fcbdeab199d54c74fbf75de19cb534a690c936c5616478a038576", size = 21530469, upload-time = "2025-11-07T20:41:20.336Z" }, - { url = "https://files.pythonhosted.org/packages/96/a4/8bb8dca265df52abc405161f918225fbf156fc3a16f380a382a5cd52f992/uv-0.9.8-py3-none-win32.whl", hash = "sha256:0f03bc413c933dbf850ad0dc2dba3df6b80c860a5c65cd767add49da19dadef0", size = 19440191, upload-time = "2025-11-07T20:41:23.612Z" }, - { url = "https://files.pythonhosted.org/packages/6c/b6/9a2ed2c1cc86b967de82c20aeee2860f8771adbcf010061359f5406a6bed/uv-0.9.8-py3-none-win_amd64.whl", hash = "sha256:6a01d7cd41953ffac583139b10ad1df004a67c0246a6b694eb5bcdbc8c99deaf", size = 21491715, upload-time = "2025-11-07T20:41:27.181Z" }, - { url = "https://files.pythonhosted.org/packages/95/77/4a8f429c8d89a17a5327e7be8a7f3b72f7422b0acccfc378d424ca6dc0c9/uv-0.9.8-py3-none-win_arm64.whl", hash = "sha256:bb0f8e83c2a2fc5a802e930cc8a7b71ab068180300a3f27ba38037f9fcb3d430", size = 19865491, upload-time = "2025-11-07T20:41:30.62Z" }, +version = "0.9.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/66/4a/dd4d1a772afd0ad4167a932864e145ba3010d2a148e34171070bfcb85528/uv-0.9.9.tar.gz", hash = "sha256:dc5885fda74cec4cf8eea4115a6e0e431462c6c6bf1bd925abd72699d6b54f51", size = 3724446, upload-time = "2025-11-12T18:45:24.863Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6d/d2/dcf1ee2b977ebbe12c8666b56f49d1138b565fc475c0e80c00c50da6d321/uv-0.9.9-py3-none-linux_armv6l.whl", hash = "sha256:ea700f6e43389a3bd6aa90c02f3010b61ef987c3b025842281a8bd513e26cf3a", size = 20481964, upload-time = "2025-11-12T18:44:21.532Z" }, + { url = "https://files.pythonhosted.org/packages/80/d5/d9e18da60593d8d127a435fe5451033dba2ec6d11baea06d6cbad5e2e6b0/uv-0.9.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:7ea663b3e5e5b20a17efbc6c7f8db602abf72447d7cced0882a0dff71c2de1ef", size = 19589253, upload-time = "2025-11-12T18:44:26.35Z" }, + { url = "https://files.pythonhosted.org/packages/cc/47/436863f6d99cfc3e41408e1d28d07fb3d20227d5ff66f52666564a5649f5/uv-0.9.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e8303e17b7d2a2dc65ebc4cc65cc0b2be493566b4f7421279b008ecb10adfc5f", size = 18149442, upload-time = "2025-11-12T18:44:29.45Z" }, + { url = "https://files.pythonhosted.org/packages/15/04/b22cd0716369f63265c76ab254e98573cb65e2ee7908f5ffa90e1c2e18fc/uv-0.9.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:036e8d38f87ffbebcd478e6b61a2c4f8733f77fbdf34140b78e0f5ab238810cf", size = 19960485, upload-time = "2025-11-12T18:44:32.934Z" }, + { url = "https://files.pythonhosted.org/packages/e9/cd/de0f6d6292a812159a134c7ed0b1692ad1ea7baf6de3c66e48c2500bd919/uv-0.9.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:aa5fb4ee5f85fe4364a2895bf849c98a4537f6a96a8da22922fb3eb149ef7aaf", size = 20085388, upload-time = "2025-11-12T18:44:36.036Z" }, + { url = "https://files.pythonhosted.org/packages/2f/bf/86ddcc9042d003c2edba8c534787bf5b8c15da026903084faaeb6cee4a7c/uv-0.9.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1bcb3e003d6b12cfb03a6223914b648de595a0b79ae2c0259411224966f3fd60", size = 20978689, upload-time = "2025-11-12T18:44:39.231Z" }, + { url = "https://files.pythonhosted.org/packages/fd/bb/d8f8ddfbc2c429a75df28b37594c9b8dfdf0f00f091175d5dabc6791ed09/uv-0.9.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:f423deb65d2c3aed8f896cd012f0fdaca47aff200fe35a81d9e0dfd543104c56", size = 22602188, upload-time = "2025-11-12T18:44:42.62Z" }, + { url = "https://files.pythonhosted.org/packages/ce/4d/bf42ae81d0ccee4d5bbc401465da1a20b82944435a36eebb953e836ea6a8/uv-0.9.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fb2eca9575bb993fdd4309c75f6253772b826b5a1778b83479e32e9097a35340", size = 22187774, upload-time = "2025-11-12T18:44:46.038Z" }, + { url = "https://files.pythonhosted.org/packages/4d/f9/e559d46b77a33c1ef5d10e5d6223ac6a60bbc681a11c9352782b3d391001/uv-0.9.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3bb84164437e71a55674898a1db34a1874489f362e90f0ce1d2be3c5ef214453", size = 21309545, upload-time = "2025-11-12T18:44:49.844Z" }, + { url = "https://files.pythonhosted.org/packages/4c/4a/d5357825bb47ff73762d247b1a553a966fef6802e3ab829fe60934cbf339/uv-0.9.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afdd00ddc25e12ed756e069090011ca55f127753e1192e51f45fa288a024f3df", size = 21287121, upload-time = "2025-11-12T18:44:53.745Z" }, + { url = "https://files.pythonhosted.org/packages/3a/97/9925ec558b9b7435d8646e74f8831aa10165e8768b6d9b0c702655b164fb/uv-0.9.9-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:4f2e2a818ce64b917aada5a752a92bc5665ed90f3ac1348689c4d92abe4af3f5", size = 20085994, upload-time = "2025-11-12T18:44:57.663Z" }, + { url = "https://files.pythonhosted.org/packages/11/ec/8fe7499790805913a2a8199e814aa78c1ab63db97ac654c741a2a5d493ca/uv-0.9.9-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:25892e6a4e5e1b9eb3cac8571a66c2f6f7be201ce114e443ef64e007dceeb640", size = 21118665, upload-time = "2025-11-12T18:45:00.949Z" }, + { url = "https://files.pythonhosted.org/packages/dc/49/8b93a53411789a35010bfc9f359391081c7bc2861d4d5c1d8d98b3d07cbb/uv-0.9.9-py3-none-musllinux_1_1_armv7l.whl", hash = "sha256:fa149da37045afde21d3167a5057ca8c5abbe65194f08ea59dfbd5f4faa25b13", size = 20064311, upload-time = "2025-11-12T18:45:04.425Z" }, + { url = "https://files.pythonhosted.org/packages/69/66/3c15283ffec67bd8302c34eaf871e50d71fceacfffc8ee26ff02b0adea69/uv-0.9.9-py3-none-musllinux_1_1_i686.whl", hash = "sha256:0b93153f1262873d6fc725f3a76264eb06e26a2651af17a1e797ae52e19eacb1", size = 20474039, upload-time = "2025-11-12T18:45:07.55Z" }, + { url = "https://files.pythonhosted.org/packages/08/ec/73bc3fb4613ad2b21b92a2c23d5bc6dc31c1acb1ca6a70bdc55e7c426ef6/uv-0.9.9-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:1263f03571f3fda44061862c14b92c992102d03f5e1015f3886d9252f9436d60", size = 21506473, upload-time = "2025-11-12T18:45:11.183Z" }, + { url = "https://files.pythonhosted.org/packages/85/5c/5b20529430140cc39255c0884da734610ccaaf2fd15f2cfabd29f6193d01/uv-0.9.9-py3-none-win32.whl", hash = "sha256:1d25f1aca2f8a3b24f3fdf9b029a9a923c429a828be7c9eee9fa073addedbc36", size = 19272132, upload-time = "2025-11-12T18:45:14.352Z" }, + { url = "https://files.pythonhosted.org/packages/f2/38/562295348cf2eb567fd5ea44512a645ea5bec2661a7e07b7f14fda54cb07/uv-0.9.9-py3-none-win_amd64.whl", hash = "sha256:1201765ae39643ef66bc6decfc44c5f8540fcaeae8b0914553b32e670f1941da", size = 21316052, upload-time = "2025-11-12T18:45:18.897Z" }, + { url = "https://files.pythonhosted.org/packages/9d/62/47e8d16da92ffb095388e45cc3f6e6c2ba1404d80590fb9528305517c7f3/uv-0.9.9-py3-none-win_arm64.whl", hash = "sha256:2695624ee43a8932c3fb414a98e4aed3b4f60306a24acd68e2b288dd5a58c370", size = 19821476, upload-time = "2025-11-12T18:45:22.462Z" }, ] [[package]]