From 23b228e722e3617e15c3f589345d53dcbe97a672 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Sat, 12 Apr 2025 04:52:00 +0100 Subject: [PATCH 1/6] Convert ``Version`` to a dataclass --- build_docs.py | 47 ++++++++++++++++++++++------------------------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/build_docs.py b/build_docs.py index a204560..af2f2dc 100755 --- a/build_docs.py +++ b/build_docs.py @@ -58,7 +58,6 @@ import sys from bisect import bisect_left as bisect from contextlib import contextmanager, suppress -from functools import total_ordering from pathlib import Path from string import Template from time import perf_counter, sleep @@ -103,11 +102,23 @@ def __reversed__(self) -> Iterator[Version]: @classmethod def from_json(cls, data: dict) -> Versions: - versions = sorted( - [Version.from_json(name, release) for name, release in data.items()], - key=Version.as_tuple, - ) - return cls(versions) + """Load versions from the devguide's JSON representation.""" + permitted = ", ".join(sorted(Version.STATUSES | Version.SYNONYMS.keys())) + + versions = [] + for name, release in data.items(): + branch = release["branch"] + status = release["status"] + status = Version.SYNONYMS.get(status, status) + if status not in Version.STATUSES: + msg = ( + f"Saw invalid version status {status!r}, " + f"expected to be one of {permitted}." + ) + raise ValueError(msg) + versions.append(Version(name=name, branch_or_tag=branch, status=status)) + + return cls(sorted(versions, key=Version.as_tuple)) def filter(self, branches: Sequence[str] = ()) -> Sequence[Version]: """Filter the given versions. @@ -143,10 +154,14 @@ def setup_indexsidebar(self, current: Version, dest_path: Path) -> None: dest_path.write_text(rendered_template, encoding="UTF-8") -@total_ordering +@dataclasses.dataclass(frozen=True, kw_only=True, slots=True) class Version: """Represents a CPython version and its documentation build dependencies.""" + name: str + branch_or_tag: str | None + status: str + STATUSES = {"EOL", "security-fixes", "stable", "pre-release", "in development"} # Those synonyms map branch status vocabulary found in the devguide @@ -159,19 +174,6 @@ class Version: "prerelease": "pre-release", } - def __init__( - self, name: str, *, status: str, branch_or_tag: str | None = None - ) -> None: - status = self.SYNONYMS.get(status, status) - if status not in self.STATUSES: - raise ValueError( - "Version status expected to be one of: " - f"{', '.join(self.STATUSES | set(self.SYNONYMS.keys()))}, got {status!r}." - ) - self.name = name - self.branch_or_tag = branch_or_tag - self.status = status - def __repr__(self) -> str: return f"Version({self.name})" @@ -181,11 +183,6 @@ def __eq__(self, other: Version) -> bool: def __gt__(self, other: Version) -> bool: return self.as_tuple() > other.as_tuple() - @classmethod - def from_json(cls, name: str, values: dict) -> Version: - """Loads a version from devguide's json representation.""" - return cls(name, status=values["status"], branch_or_tag=values["branch"]) - @property def requirements(self) -> list[str]: """Generate the right requirements for this version. From 65f3a49c0f062c8b4924fed36043c882f8dec7d7 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Sat, 12 Apr 2025 04:53:46 +0100 Subject: [PATCH 2/6] Convert ``Version`` to a dataclass --- build_docs.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/build_docs.py b/build_docs.py index af2f2dc..fd8213b 100755 --- a/build_docs.py +++ b/build_docs.py @@ -174,9 +174,6 @@ class Version: "prerelease": "pre-release", } - def __repr__(self) -> str: - return f"Version({self.name})" - def __eq__(self, other: Version) -> bool: return self.name == other.name From c17db7a921fcf51a0a0050722adee5904d656c60 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Sat, 12 Apr 2025 05:03:20 +0100 Subject: [PATCH 3/6] Tests --- build_docs.py | 4 +-- tests/test_build_docs_versions.py | 48 +++++++++++++++---------------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/build_docs.py b/build_docs.py index fd8213b..236a154 100755 --- a/build_docs.py +++ b/build_docs.py @@ -116,7 +116,7 @@ def from_json(cls, data: dict) -> Versions: f"expected to be one of {permitted}." ) raise ValueError(msg) - versions.append(Version(name=name, branch_or_tag=branch, status=status)) + versions.append(Version(name=name, status=status, branch_or_tag=branch)) return cls(sorted(versions, key=Version.as_tuple)) @@ -159,8 +159,8 @@ class Version: """Represents a CPython version and its documentation build dependencies.""" name: str - branch_or_tag: str | None status: str + branch_or_tag: str STATUSES = {"EOL", "security-fixes", "stable", "pre-release", "in development"} diff --git a/tests/test_build_docs_versions.py b/tests/test_build_docs_versions.py index 662838e..621a7ad 100644 --- a/tests/test_build_docs_versions.py +++ b/tests/test_build_docs_versions.py @@ -4,12 +4,12 @@ def test_filter_default() -> None: # Arrange versions = Versions([ - Version("3.14", status="feature"), - Version("3.13", status="bugfix"), - Version("3.12", status="bugfix"), - Version("3.11", status="security"), - Version("3.10", status="security"), - Version("3.9", status="security"), + Version(name="3.14", status="feature", branch_or_tag=""), + Version(name="3.13", status="bugfix", branch_or_tag=""), + Version(name="3.12", status="bugfix", branch_or_tag=""), + Version(name="3.11", status="security", branch_or_tag=""), + Version(name="3.10", status="security", branch_or_tag=""), + Version(name="3.9", status="security", branch_or_tag=""), ]) # Act @@ -17,39 +17,39 @@ def test_filter_default() -> None: # Assert assert filtered == [ - Version("3.14", status="feature"), - Version("3.13", status="bugfix"), - Version("3.12", status="bugfix"), + Version(name="3.14", status="feature", branch_or_tag=""), + Version(name="3.13", status="bugfix", branch_or_tag=""), + Version(name="3.12", status="bugfix", branch_or_tag=""), ] def test_filter_one() -> None: # Arrange versions = Versions([ - Version("3.14", status="feature"), - Version("3.13", status="bugfix"), - Version("3.12", status="bugfix"), - Version("3.11", status="security"), - Version("3.10", status="security"), - Version("3.9", status="security"), + Version(name="3.14", status="feature", branch_or_tag=""), + Version(name="3.13", status="bugfix", branch_or_tag=""), + Version(name="3.12", status="bugfix", branch_or_tag=""), + Version(name="3.11", status="security", branch_or_tag=""), + Version(name="3.10", status="security", branch_or_tag=""), + Version(name="3.9", status="security", branch_or_tag=""), ]) # Act filtered = versions.filter(["3.13"]) # Assert - assert filtered == [Version("3.13", status="security")] + assert filtered == [Version(name="3.13", status="security", branch_or_tag="")] def test_filter_multiple() -> None: # Arrange versions = Versions([ - Version("3.14", status="feature"), - Version("3.13", status="bugfix"), - Version("3.12", status="bugfix"), - Version("3.11", status="security"), - Version("3.10", status="security"), - Version("3.9", status="security"), + Version(name="3.14", status="feature", branch_or_tag=""), + Version(name="3.13", status="bugfix", branch_or_tag=""), + Version(name="3.12", status="bugfix", branch_or_tag=""), + Version(name="3.11", status="security", branch_or_tag=""), + Version(name="3.10", status="security", branch_or_tag=""), + Version(name="3.9", status="security", branch_or_tag=""), ]) # Act @@ -57,6 +57,6 @@ def test_filter_multiple() -> None: # Assert assert filtered == [ - Version("3.14", status="feature"), - Version("3.13", status="security"), + Version(name="3.14", status="feature", branch_or_tag=""), + Version(name="3.13", status="security", branch_or_tag=""), ] From e8bb5775799c54524ad8742b8db433991f92d999 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Sat, 12 Apr 2025 05:09:40 +0100 Subject: [PATCH 4/6] Tests --- tests/test_build_docs_versions.py | 48 +++++++++++++++---------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/tests/test_build_docs_versions.py b/tests/test_build_docs_versions.py index 621a7ad..42b5392 100644 --- a/tests/test_build_docs_versions.py +++ b/tests/test_build_docs_versions.py @@ -4,12 +4,12 @@ def test_filter_default() -> None: # Arrange versions = Versions([ - Version(name="3.14", status="feature", branch_or_tag=""), - Version(name="3.13", status="bugfix", branch_or_tag=""), - Version(name="3.12", status="bugfix", branch_or_tag=""), - Version(name="3.11", status="security", branch_or_tag=""), - Version(name="3.10", status="security", branch_or_tag=""), - Version(name="3.9", status="security", branch_or_tag=""), + Version(name="3.14", status="in development", branch_or_tag=""), + Version(name="3.13", status="stable", branch_or_tag=""), + Version(name="3.12", status="stable", branch_or_tag=""), + Version(name="3.11", status="security-fixes", branch_or_tag=""), + Version(name="3.10", status="security-fixes", branch_or_tag=""), + Version(name="3.9", status="security-fixes", branch_or_tag=""), ]) # Act @@ -17,39 +17,39 @@ def test_filter_default() -> None: # Assert assert filtered == [ - Version(name="3.14", status="feature", branch_or_tag=""), - Version(name="3.13", status="bugfix", branch_or_tag=""), - Version(name="3.12", status="bugfix", branch_or_tag=""), + Version(name="3.14", status="in development", branch_or_tag=""), + Version(name="3.13", status="stable", branch_or_tag=""), + Version(name="3.12", status="stable", branch_or_tag=""), ] def test_filter_one() -> None: # Arrange versions = Versions([ - Version(name="3.14", status="feature", branch_or_tag=""), - Version(name="3.13", status="bugfix", branch_or_tag=""), - Version(name="3.12", status="bugfix", branch_or_tag=""), - Version(name="3.11", status="security", branch_or_tag=""), - Version(name="3.10", status="security", branch_or_tag=""), - Version(name="3.9", status="security", branch_or_tag=""), + Version(name="3.14", status="in development", branch_or_tag=""), + Version(name="3.13", status="stable", branch_or_tag=""), + Version(name="3.12", status="stable", branch_or_tag=""), + Version(name="3.11", status="security-fixes", branch_or_tag=""), + Version(name="3.10", status="security-fixes", branch_or_tag=""), + Version(name="3.9", status="security-fixes", branch_or_tag=""), ]) # Act filtered = versions.filter(["3.13"]) # Assert - assert filtered == [Version(name="3.13", status="security", branch_or_tag="")] + assert filtered == [Version(name="3.13", status="security-fixes", branch_or_tag="")] def test_filter_multiple() -> None: # Arrange versions = Versions([ - Version(name="3.14", status="feature", branch_or_tag=""), - Version(name="3.13", status="bugfix", branch_or_tag=""), - Version(name="3.12", status="bugfix", branch_or_tag=""), - Version(name="3.11", status="security", branch_or_tag=""), - Version(name="3.10", status="security", branch_or_tag=""), - Version(name="3.9", status="security", branch_or_tag=""), + Version(name="3.14", status="in development", branch_or_tag=""), + Version(name="3.13", status="stable", branch_or_tag=""), + Version(name="3.12", status="stable", branch_or_tag=""), + Version(name="3.11", status="security-fixes", branch_or_tag=""), + Version(name="3.10", status="security-fixes", branch_or_tag=""), + Version(name="3.9", status="security-fixes", branch_or_tag=""), ]) # Act @@ -57,6 +57,6 @@ def test_filter_multiple() -> None: # Assert assert filtered == [ - Version(name="3.14", status="feature", branch_or_tag=""), - Version(name="3.13", status="security", branch_or_tag=""), + Version(name="3.14", status="in development", branch_or_tag=""), + Version(name="3.13", status="security-fixes", branch_or_tag=""), ] From ce1ad4973968ca9703b833bbfc36a4e039dbda20 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Sat, 12 Apr 2025 05:11:11 +0100 Subject: [PATCH 5/6] typing --- build_docs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build_docs.py b/build_docs.py index 236a154..9b84d3d 100755 --- a/build_docs.py +++ b/build_docs.py @@ -159,7 +159,7 @@ class Version: """Represents a CPython version and its documentation build dependencies.""" name: str - status: str + status: Literal["EOL", "security-fixes", "stable", "pre-release", "in development"] branch_or_tag: str STATUSES = {"EOL", "security-fixes", "stable", "pre-release", "in development"} From 176c6ff1d3fcbc12c6f15b2e12b5bb4bafb976b2 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Sat, 12 Apr 2025 05:12:46 +0100 Subject: [PATCH 6/6] Remove __gt__ method --- build_docs.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/build_docs.py b/build_docs.py index 9b84d3d..57f1409 100755 --- a/build_docs.py +++ b/build_docs.py @@ -177,9 +177,6 @@ class Version: def __eq__(self, other: Version) -> bool: return self.name == other.name - def __gt__(self, other: Version) -> bool: - return self.as_tuple() > other.as_tuple() - @property def requirements(self) -> list[str]: """Generate the right requirements for this version.