From a5636f431ce4b89ef6cc1bccee8a8089798f2571 Mon Sep 17 00:00:00 2001
From: benoit74 <benoit74@users.noreply.github.com>
Date: Mon, 20 Jan 2025 08:06:18 +0000
Subject: [PATCH 1/2] Upgrade to Python 3.13

---
 .github/workflows/Publish.yaml     |  2 +-
 .github/workflows/Tests.yaml       |  2 +-
 .pre-commit-config.yaml            |  2 +-
 .readthedocs.yaml                  |  2 +-
 CHANGELOG.md                       |  4 ++++
 pyproject.toml                     | 22 +++++++++++-----------
 src/zimscraperlib/__about__.py     |  2 +-
 src/zimscraperlib/zim/providers.py |  4 ++--
 tests/rewriting/conftest.py        | 18 +++++++++---------
 9 files changed, 31 insertions(+), 27 deletions(-)

diff --git a/.github/workflows/Publish.yaml b/.github/workflows/Publish.yaml
index e5a8e379..66602fcd 100644
--- a/.github/workflows/Publish.yaml
+++ b/.github/workflows/Publish.yaml
@@ -106,7 +106,7 @@ jobs:
           python -m build --sdist --wheel
 
       - name: Publish to PyPI
-        uses: pypa/gh-action-pypi-publish@release/v1.8
+        uses: pypa/gh-action-pypi-publish@release/v1.12
 # OPTIONAL PUBLICATION TO NPM, NOT NEEDED BY SCRAPERS IN THE END
 
 # publish-js:
diff --git a/.github/workflows/Tests.yaml b/.github/workflows/Tests.yaml
index 66e647fc..efed325b 100644
--- a/.github/workflows/Tests.yaml
+++ b/.github/workflows/Tests.yaml
@@ -56,7 +56,7 @@ jobs:
       - name: install ffmpeg and gifsicle
         run: sudo apt update && sudo apt install ffmpeg gifsicle
 
-      - name: Set up Python 3.12
+      - name: Set up Python
         uses: actions/setup-python@v5
         with:
           python-version-file: pyproject.toml
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index ebb0c8a9..8d75b134 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -12,7 +12,7 @@ repos:
     hooks:
       - id: black
   - repo: https://github.com/astral-sh/ruff-pre-commit
-    rev: v0.7.0
+    rev: v0.9.2
     hooks:
       - id: ruff
   - repo: https://github.com/RobertCraigie/pyright-python
diff --git a/.readthedocs.yaml b/.readthedocs.yaml
index 391730d7..8c1c416a 100644
--- a/.readthedocs.yaml
+++ b/.readthedocs.yaml
@@ -6,7 +6,7 @@ version: 2
 build:
   os: ubuntu-24.04
   tools:
-    python: '3.12'
+    python: '3.13'
 
   # custom commands to run mkdocs build within hatch, as suggested by maintainer in
   # https://github.com/readthedocs/readthedocs.org/issues/10706
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 03554e59..e0baac6f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ## [Unreleased]
 
+### Changed
+
+- Upgrade to support only Python 3.13 (#203)
+
 ## [5.0.0] - 2025-01-14
 
 This is a major release with a lot of breaking changes but most changes are easy to fix.
diff --git a/pyproject.toml b/pyproject.toml
index 69d59908..90d56211 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,12 +1,12 @@
 [build-system]
 # jinja2 is required to generate JS and Python rules at build time
 # PyYAML is used to parse fuzzy rules and generate Python/JS code
-requires = ["hatchling", "hatch-openzim>=0.2", "jinja2==3.1.4", "PyYAML==6.0.2"]
+requires = ["hatchling", "hatch-openzim>=0.2", "jinja2==3.1.5", "PyYAML==6.0.2"]
 build-backend = "hatchling.build"
 
 [project]
 name = "zimscraperlib"
-requires-python = ">=3.12,<3.13"
+requires-python = ">=3.13,<3.14"
 description = "Collection of python tools to re-use common code across scrapers"
 readme = "README.md"
 dependencies = [
@@ -51,13 +51,13 @@ scripts = [
   # jinja2 is required to generate JS and Python rules at build time
   # PyYAML is used to parse fuzzy rules and generate Python/JS code
   # also update version in build-system above and in build_js.sh
-  "jinja2==3.1.4",
+  "jinja2==3.1.5",
   "PyYAML==6.0.2",
 
 ]
 lint = [
   "black==24.10.0",
-  "ruff==0.8.2",
+  "ruff==0.9.2",
 ]
 check = [
   "pyright==1.1.391",
@@ -66,19 +66,19 @@ check = [
 test = [
   "pytest==8.3.4",
   "pytest-mock==3.14.0",
-  "coverage==7.6.9",
+  "coverage==7.6.10",
 ]
 docs = [
   "mkdocs==1.6.1",
   "mkdocstrings[python]==0.27.0",
-  "mkdocs-material==9.5.44",
-  "pymdown-extensions==10.12",
+  "mkdocs-material==9.5.50",
+  "pymdown-extensions==10.14",
   "mkdocs-gen-files==0.5.0",
   "mkdocs-literate-nav==0.6.1",
   "mkdocs-include-markdown-plugin==7.1.2",
 ]
 dev = [
-  "ipython==8.30.0",
+  "ipython==8.31.0",
   "pre-commit==4.0.1",
   "zimscraperlib[scripts]",
   "zimscraperlib[lint]",
@@ -155,10 +155,10 @@ build = "inv docs-build --args '{args}'"
 
 [tool.black]
 line-length = 88
-target-version = ['py312']
+target-version = ['py313']
 
 [tool.ruff]
-target-version = "py312"
+target-version = "py313"
 line-length = 88
 src = ["src", "contrib"]
 
@@ -289,7 +289,7 @@ exclude_lines = [
 include = ["contrib", "src", "tests", "tasks.py"]
 exclude = [".env/**", ".venv/**"]
 extraPaths = ["src"]
-pythonVersion = "3.12"
+pythonVersion = "3.13"
 typeCheckingMode="strict"
 disableBytesTypePromotions = true
 
diff --git a/src/zimscraperlib/__about__.py b/src/zimscraperlib/__about__.py
index 0ec9b6b1..fc504481 100644
--- a/src/zimscraperlib/__about__.py
+++ b/src/zimscraperlib/__about__.py
@@ -1 +1 @@
-__version__ = "5.0.1-dev0"
+__version__ = "5.1.0-dev0"
diff --git a/src/zimscraperlib/zim/providers.py b/src/zimscraperlib/zim/providers.py
index f1733852..cddc864b 100644
--- a/src/zimscraperlib/zim/providers.py
+++ b/src/zimscraperlib/zim/providers.py
@@ -57,7 +57,7 @@ def __init__(
     def get_size(self) -> int:
         return getattr(self, "size", -1)
 
-    def gen_blob(self) -> Generator[libzim.writer.Blob, None, None]:
+    def gen_blob(self) -> Generator[libzim.writer.Blob]:
         yield libzim.writer.Blob(self.fileobj.getvalue())  # pragma: no cover
 
 
@@ -88,7 +88,7 @@ def get_size_of(url: str) -> int | None:
     def get_size(self) -> int:
         return getattr(self, "size", -1)
 
-    def gen_blob(self) -> Generator[libzim.writer.Blob, None, None]:  # pragma: no cover
+    def gen_blob(self) -> Generator[libzim.writer.Blob]:  # pragma: no cover
         for chunk in self.resp.iter_content(10 * 1024):
             if chunk:
                 yield libzim.writer.Blob(chunk)
diff --git a/tests/rewriting/conftest.py b/tests/rewriting/conftest.py
index 40ccbc25..0b8a4807 100644
--- a/tests/rewriting/conftest.py
+++ b/tests/rewriting/conftest.py
@@ -44,9 +44,7 @@ def get_document_uri(
 
 
 @pytest.fixture(scope="module")
-def simple_url_rewriter_gen() -> (
-    Generator[Callable[[str], ArticleUrlRewriter], None, None]
-):
+def simple_url_rewriter_gen() -> Generator[Callable[[str], ArticleUrlRewriter]]:
     """Fixture to create a basic url rewriter returning URLs as-is"""
 
     def get_simple_url_rewriter(url: str, suffix: str = "") -> ArticleUrlRewriter:
@@ -56,11 +54,13 @@ def get_simple_url_rewriter(url: str, suffix: str = "") -> ArticleUrlRewriter:
 
 
 @pytest.fixture(scope="module")
-def js_rewriter_gen() -> Generator[
-    Callable[[ArticleUrlRewriter, str | None, Callable[[ZimPath], None]], JsRewriter],
-    None,
-    None,
-]:
+def js_rewriter_gen() -> (
+    Generator[
+        Callable[
+            [ArticleUrlRewriter, str | None, Callable[[ZimPath], None]], JsRewriter
+        ]
+    ]
+):
     """Fixture to create a basic url rewriter returning URLs as-is"""
 
     def get_js_rewriter(
@@ -79,7 +79,7 @@ def get_js_rewriter(
 
 @pytest.fixture(scope="module")
 def css_rewriter_gen() -> (
-    Generator[Callable[[ArticleUrlRewriter, str | None], CssRewriter], None, None]
+    Generator[Callable[[ArticleUrlRewriter, str | None], CssRewriter]]
 ):
     """Fixture to create a basic url rewriter returning URLs as-is"""
 

From cf2cc44c61b926ac6570174e56c6f4612ad7432d Mon Sep 17 00:00:00 2001
From: benoit74 <benoit74@users.noreply.github.com>
Date: Mon, 20 Jan 2025 08:10:51 +0000
Subject: [PATCH 2/2] Allow to shadow Python standard-library modules

---
 pyproject.toml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/pyproject.toml b/pyproject.toml
index 90d56211..7c7ee8c7 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -221,6 +221,8 @@ select = [
   "YTT",  # flake8-2020
 ]
 ignore = [
+  # Allow to shadow Python standard-library modules
+  "A005",
   # Allow non-abstract empty methods in abstract base classes
   "B027",
   # Remove flake8-errmsg since we consider they bloat the code and provide limited value