From f70b86d53bd659def8c42d583a7a12f21d6e6b6f Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Sun, 8 Dec 2024 20:28:39 +0200 Subject: [PATCH 01/12] Measure test coverage --- .coveragerc | 7 +++++++ .github/workflows/test.yml | 7 +++++++ README.md | 5 +++++ tox.ini | 13 ++++++++++++- 4 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 .coveragerc diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..0f12707 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,7 @@ +# .coveragerc to control coverage.py + +[report] +# Regexes for lines to exclude from consideration +exclude_also = + # Don't complain if non-runnable code isn't run: + if __name__ == .__main__.: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2976bae..3813f3c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -33,3 +33,10 @@ jobs: - name: Tox tests run: | uvx --with tox-uv tox -e py + + - name: Upload coverage + uses: codecov/codecov-action@v5.1.1 + with: + flags: ${{ matrix.os }} + name: ${{ matrix.os }} Python ${{ matrix.python-version }} + token: ${{ secrets.CODECOV_ORG_TOKEN }} diff --git a/README.md b/README.md index 1b76bcd..87a12a4 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,8 @@ +# docsbuild-scripts + +[![GitHub Actions status](https://github.com/python/docsbuild-scripts/actions/workflows/test.yml/badge.svg)](https://github.com/python/docsbuild-scripts/actions/workflows/test.yml) +[![Codecov](https://codecov.io/gh/python/docsbuild-scripts/branch/main/graph/badge.svg)](https://codecov.io/gh/python/docsbuild-scripts) + This repository contains scripts for automatically building the Python documentation on [docs.python.org](https://docs.python.org). diff --git a/tox.ini b/tox.ini index 56c6420..12efcdf 100644 --- a/tox.ini +++ b/tox.ini @@ -12,8 +12,19 @@ skip_install = true deps = -r requirements.txt pytest + pytest-cov +pass_env = + FORCE_COLOR +set_env = + COVERAGE_CORE = sysmon commands = - {envpython} -m pytest {posargs} + {envpython} -m pytest \ + --cov . \ + --cov tests \ + --cov-report html \ + --cov-report term \ + --cov-report xml \ + {posargs} [testenv:lint] skip_install = true From 22d1fbaa42754d0bf463221e83d95be03864977a Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Sun, 8 Dec 2024 20:26:03 +0200 Subject: [PATCH 02/12] Add a test for Version.filter for single version --- tests/test_build_docs_version.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 tests/test_build_docs_version.py diff --git a/tests/test_build_docs_version.py b/tests/test_build_docs_version.py new file mode 100644 index 0000000..293388c --- /dev/null +++ b/tests/test_build_docs_version.py @@ -0,0 +1,19 @@ +from build_docs import Version + + +def test_filter() -> None: + # Arrange + 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"), + ] + + # Act + filtered = Version.filter(versions, "3.13") + + # Assert + assert filtered == [Version("3.13", status="security")] From 08cf923cb82f89687547505c209176e8a1438684 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Fri, 11 Apr 2025 13:50:53 +0300 Subject: [PATCH 03/12] Add a test for Versions.filter for single version --- ..._build_docs_version.py => test_build_docs_versions.py} | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) rename tests/{test_build_docs_version.py => test_build_docs_versions.py} (77%) diff --git a/tests/test_build_docs_version.py b/tests/test_build_docs_versions.py similarity index 77% rename from tests/test_build_docs_version.py rename to tests/test_build_docs_versions.py index 293388c..301c5e2 100644 --- a/tests/test_build_docs_version.py +++ b/tests/test_build_docs_versions.py @@ -1,19 +1,19 @@ -from build_docs import Version +from build_docs import Versions, Version def test_filter() -> None: # Arrange - versions = [ + 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"), - ] + ]) # Act - filtered = Version.filter(versions, "3.13") + filtered = versions.filter("3.13") # Assert assert filtered == [Version("3.13", status="security")] From 6979d6c1593822c3f82ff3878f64c53f9c6a8d1e Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Sun, 8 Dec 2024 20:31:34 +0200 Subject: [PATCH 04/12] Add a test for Version.filter with default branch --- tests/test_build_docs_versions.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/tests/test_build_docs_versions.py b/tests/test_build_docs_versions.py index 301c5e2..f81d5ae 100644 --- a/tests/test_build_docs_versions.py +++ b/tests/test_build_docs_versions.py @@ -1,7 +1,29 @@ from build_docs import Versions, Version -def test_filter() -> None: +def test_filter_default() -> None: + # Arrange + 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"), + ] + + # Act + filtered = Version.filter(versions) + + # Assert + assert filtered == [ + Version("3.14", status="feature"), + Version("3.13", status="bugfix"), + Version("3.12", status="bugfix"), + ] + + +def test_filter_one() -> None: # Arrange versions = Versions([ Version("3.14", status="feature"), From 174c46d8c0041b24c7b30aba2b31ed49514e6f9b Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Fri, 11 Apr 2025 13:52:53 +0300 Subject: [PATCH 05/12] Add a test for Versions.filter with default branch --- tests/test_build_docs_versions.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_build_docs_versions.py b/tests/test_build_docs_versions.py index f81d5ae..5d936c9 100644 --- a/tests/test_build_docs_versions.py +++ b/tests/test_build_docs_versions.py @@ -3,17 +3,17 @@ def test_filter_default() -> None: # Arrange - versions = [ + 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"), - ] + ]) # Act - filtered = Version.filter(versions) + filtered = versions.filter() # Assert assert filtered == [ From 40dc145e26bad2cc0107f2d0c97a0180e5f700dd Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Sun, 8 Dec 2024 20:54:08 +0200 Subject: [PATCH 06/12] Allow passing multiple branches build via CLI --- README.md | 2 +- build_docs.py | 16 ++++++++++------ tests/test_build_docs_versions.py | 23 ++++++++++++++++++++++- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 87a12a4..8d6e689 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ python3 ./build_docs.py --quick --build-root ./build_root --www-root ./www --log ``` If you don't need to build all translations of all branches, add -`--language en --branch main`. +`--language en --branches main`. ## Check current version diff --git a/build_docs.py b/build_docs.py index 08ce611..c8d252a 100755 --- a/build_docs.py +++ b/build_docs.py @@ -86,16 +86,18 @@ def from_json(cls, data) -> Versions: ) return cls(versions) - def filter(self, branch: str = "") -> Sequence[Version]: + def filter(self, branches: list[str] = None) -> Sequence[Version]: """Filter the given versions. - If *branch* is given, only *versions* matching *branch* are returned. + If *branches* is given, only *versions* matching *branches* are returned. Else all live versions are returned (this means no EOL and no security-fixes branches). """ - if branch: - return [v for v in self if branch in (v.name, v.branch_or_tag)] + if branches: + return [ + v for v in self if v.name in branches or v.branch_or_tag in branches + ] return [v for v in self if v.status not in {"EOL", "security-fixes"}] @property @@ -935,9 +937,11 @@ def parse_args(): ) parser.add_argument( "-b", - "--branch", + "--branch", # Deprecated + "--branches", + nargs="*", metavar="3.12", - help="Version to build (defaults to all maintained branches).", + help="Versions to build (defaults to all maintained branches).", ) parser.add_argument( "-r", diff --git a/tests/test_build_docs_versions.py b/tests/test_build_docs_versions.py index 5d936c9..5ed9bcb 100644 --- a/tests/test_build_docs_versions.py +++ b/tests/test_build_docs_versions.py @@ -35,7 +35,28 @@ def test_filter_one() -> None: ]) # Act - filtered = versions.filter("3.13") + filtered = versions.filter(["3.13"]) # Assert assert filtered == [Version("3.13", status="security")] + + +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"), + ]) + + # Act + filtered = versions.filter(["3.13", "3.14"]) + + # Assert + assert filtered == [ + Version("3.14", status="feature"), + Version("3.13", status="security"), + ] From f7e617d0da4c48d3cae52cc7d4ef950b9808d6e1 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Fri, 11 Apr 2025 14:23:39 +0300 Subject: [PATCH 07/12] Use argparse's 'deprecated', added in 3.13 --- build_docs.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/build_docs.py b/build_docs.py index c8d252a..4ba15e2 100755 --- a/build_docs.py +++ b/build_docs.py @@ -935,9 +935,15 @@ def parse_args(): action="store_true", help="Run a quick build (only HTML files).", ) + parser.add_argument( + "--branch", + nargs="*", + metavar="3.12", + deprecated=True, + help="Deprecated; use --branches instead.", + ) parser.add_argument( "-b", - "--branch", # Deprecated "--branches", nargs="*", metavar="3.12", @@ -998,6 +1004,9 @@ def parse_args(): version_info() sys.exit(0) del args.version + if args.branch and not args.branches: + args.branches = args.branch + del args.branch if args.log_directory: args.log_directory = args.log_directory.resolve() if args.build_root: @@ -1049,10 +1058,10 @@ def build_docs(args: argparse.Namespace) -> bool: # This runs languages in config.toml order and versions newest first. todo = [ (version, language) - for version in versions.filter(args.branch) + for version in versions.filter(args.branches) for language in reversed(languages.filter(args.languages)) ] - del args.branch + del args.branches del args.languages build_succeeded = set() From f85bbfc74f7fa337408ac7e5086f0ea0386c6383 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Fri, 11 Apr 2025 14:40:15 +0300 Subject: [PATCH 08/12] Upgrade action --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3813f3c..e272e76 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -35,7 +35,7 @@ jobs: uvx --with tox-uv tox -e py - name: Upload coverage - uses: codecov/codecov-action@v5.1.1 + uses: codecov/codecov-action@v5 with: flags: ${{ matrix.os }} name: ${{ matrix.os }} Python ${{ matrix.python-version }} From 5b5d21a04ea1158d2210dbea23588d724abeed97 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Sun, 8 Dec 2024 23:46:58 +0200 Subject: [PATCH 09/12] Correct --language to --languages in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8d6e689..d78bdb7 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ python3 ./build_docs.py --quick --build-root ./build_root --www-root ./www --log ``` If you don't need to build all translations of all branches, add -`--language en --branches main`. +`--languages en --branches main`. ## Check current version From 7aef3ec73fdc52626b3d46e0ed0ebc0160937b85 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Fri, 11 Apr 2025 17:18:49 +0300 Subject: [PATCH 10/12] Just remove --branch --- build_docs.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/build_docs.py b/build_docs.py index 4ba15e2..42aef7f 100755 --- a/build_docs.py +++ b/build_docs.py @@ -935,13 +935,6 @@ def parse_args(): action="store_true", help="Run a quick build (only HTML files).", ) - parser.add_argument( - "--branch", - nargs="*", - metavar="3.12", - deprecated=True, - help="Deprecated; use --branches instead.", - ) parser.add_argument( "-b", "--branches", @@ -981,7 +974,6 @@ def parse_args(): ) parser.add_argument( "--languages", - "--language", nargs="*", help="Language translation, as a PEP 545 language tag like" " 'fr' or 'pt-br'. " From 212ec60b8046d610a40d4b9174f2dd00bc669993 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Fri, 11 Apr 2025 17:27:15 +0300 Subject: [PATCH 11/12] Apply suggestions from code review Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- build_docs.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/build_docs.py b/build_docs.py index 42aef7f..85d89a0 100755 --- a/build_docs.py +++ b/build_docs.py @@ -86,7 +86,7 @@ def from_json(cls, data) -> Versions: ) return cls(versions) - def filter(self, branches: list[str] = None) -> Sequence[Version]: + def filter(self, branches: Sequence[str] = ()) -> Sequence[Version]: """Filter the given versions. If *branches* is given, only *versions* matching *branches* are returned. @@ -95,8 +95,9 @@ def filter(self, branches: list[str] = None) -> Sequence[Version]: security-fixes branches). """ if branches: + branches = frozenset(branches) return [ - v for v in self if v.name in branches or v.branch_or_tag in branches + v for v in self if {v.name, v.branch_or_tag} & branches ] return [v for v in self if v.status not in {"EOL", "security-fixes"}] @@ -996,9 +997,6 @@ def parse_args(): version_info() sys.exit(0) del args.version - if args.branch and not args.branches: - args.branches = args.branch - del args.branch if args.log_directory: args.log_directory = args.log_directory.resolve() if args.build_root: From 36e1eb59cbc25ac81043ab077231003c85c097a5 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Fri, 11 Apr 2025 15:44:20 +0100 Subject: [PATCH 12/12] Format --- build_docs.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/build_docs.py b/build_docs.py index 85d89a0..ba60f53 100755 --- a/build_docs.py +++ b/build_docs.py @@ -96,9 +96,7 @@ def filter(self, branches: Sequence[str] = ()) -> Sequence[Version]: """ if branches: branches = frozenset(branches) - return [ - v for v in self if {v.name, v.branch_or_tag} & branches - ] + return [v for v in self if {v.name, v.branch_or_tag} & branches] return [v for v in self if v.status not in {"EOL", "security-fixes"}] @property