diff --git a/completion.py b/completion.py index 9ee3dcb41..5c3e6af88 100644 --- a/completion.py +++ b/completion.py @@ -1,4 +1,5 @@ import json +from dataclasses import dataclass from functools import cache from pathlib import Path from tempfile import TemporaryDirectory @@ -19,9 +20,7 @@ def branches_from_devguide(devguide_dir: Path) -> list[str]: ] -def get_completion( - clones_dir: str, repo: str -) -> tuple[float, int, str | Literal[False]]: +def get_completion(clones_dir: str, repo: str) -> tuple[float, 'TranslatorsData']: clone_path = Path(clones_dir, repo) for branch in branches_from_devguide(Path(clones_dir, 'devguide')) + ['master']: try: @@ -30,12 +29,12 @@ def get_completion( ) except git.GitCommandError: print(f'failed to clone {repo} {branch}') - translators_number = 0 - translators_link: str | Literal[False] = False + translators_data = TranslatorsData(0, False) continue else: translators_number = translators.get_number(clone_path) translators_link = translators.get_link(clone_path, repo, branch) + translators_data = TranslatorsData(translators_number, translators_link) break with TemporaryDirectory() as tmpdir: completion = potodo.merge_and_scan_path( @@ -45,4 +44,10 @@ def get_completion( hide_reserved=False, api_url='', ).completion - return completion, translators_number, translators_link + return completion, translators_data + + +@dataclass(frozen=True) +class TranslatorsData: + number: int + link: str | Literal[False] diff --git a/generate.py b/generate.py index 94f470c69..237e12f7e 100644 --- a/generate.py +++ b/generate.py @@ -10,40 +10,25 @@ # /// import subprocess from collections.abc import Iterator +from dataclasses import dataclass from datetime import datetime, timezone +from logging import info from pathlib import Path from tempfile import TemporaryDirectory -from typing import cast, Literal from git import Repo from jinja2 import Template import contribute -import repositories import build_status -import visitors -from completion import branches_from_devguide, get_completion +from visitors import get_number_of_visitors +from completion import branches_from_devguide, get_completion, TranslatorsData +from repositories import get_languages_and_repos, Language generation_time = datetime.now(timezone.utc) -def get_completion_progress() -> ( - Iterator[ - tuple[ - str, - str, - str, - float, - int, - str | Literal[False], - int, - bool, - bool | None, - bool, - str | None, - ] - ] -): +def get_completion_progress() -> Iterator['LanguageProjectData']: with TemporaryDirectory() as clones_dir: Repo.clone_from( 'https://github.com/python/devguide.git', @@ -53,59 +38,56 @@ def get_completion_progress() -> ( latest_branch = branches_from_devguide(devguide_dir)[0] Repo.clone_from( 'https://github.com/python/cpython.git', - Path(clones_dir, 'cpython'), + cpython_dir := Path(clones_dir, 'cpython'), depth=1, branch=latest_branch, ) - subprocess.run( - ['make', '-C', Path(clones_dir, 'cpython/Doc'), 'venv'], check=True - ) - subprocess.run( - ['make', '-C', Path(clones_dir, 'cpython/Doc'), 'gettext'], check=True - ) + subprocess.run(['make', '-C', cpython_dir / 'Doc', 'venv'], check=True) + subprocess.run(['make', '-C', cpython_dir / 'Doc', 'gettext'], check=True) languages_built = dict(build_status.get_languages()) - for lang, lang_name, repo in repositories.get_languages_and_repos(devguide_dir): - built = lang in languages_built - in_switcher = languages_built.get(lang) - tx = lang in contribute.pulling_from_transifex - contrib_link = contribute.get_contrib_link(lang, repo) - if not repo: - yield ( - lang, - lang_name, - cast(str, repo), - 0.0, - 0, - False, - 0, - built, - in_switcher, - False, - None, - ) - continue - completion, translators, translators_link = get_completion(clones_dir, repo) - visitors_num = visitors.get_number_of_visitors(lang) if built else 0 - yield ( - lang, - lang_name, + for language, repo in get_languages_and_repos(devguide_dir): + built = language.code in languages_built + if repo: + completion, translators_data = get_completion(clones_dir, repo) + visitors_num = get_number_of_visitors(language.code) if built else 0 + else: + completion = 0.0 + translators_data = TranslatorsData(0, False) + visitors_num = 0 + yield LanguageProjectData( + language, repo, completion, - translators, - translators_link, + translators_data, visitors_num, built, - in_switcher, - tx, - contrib_link, + in_switcher=languages_built.get(language.code), + uses_platform=language.code in contribute.pulling_from_transifex, + contribution_link=contribute.get_contrib_link(language.code, repo), ) +@dataclass(frozen=True) +class LanguageProjectData: + language: Language + repository: str | None + completion: float + translators: TranslatorsData + visitors: int + built: bool + in_switcher: bool | None + uses_platform: bool + contribution_link: str | None + + if __name__ == '__main__': + info(f'starting at {generation_time}') template = Template(Path('template.html.jinja').read_text()) output = template.render( - completion_progress=get_completion_progress(), generation_time=generation_time + completion_progress=list(get_completion_progress()), + generation_time=generation_time, + duration=(datetime.now(timezone.utc) - generation_time).seconds, ) Path('index.html').write_text(output) diff --git a/repositories.py b/repositories.py index 9ade1d2c7..2c69c9f0e 100644 --- a/repositories.py +++ b/repositories.py @@ -1,5 +1,6 @@ import re from collections.abc import Iterator +from dataclasses import dataclass from pathlib import Path from tempfile import TemporaryDirectory @@ -10,7 +11,7 @@ def get_languages_and_repos( devguide_dir: Path, -) -> Iterator[tuple[str, str, str | None]]: +) -> Iterator[tuple['Language', str | None]]: translating = devguide_dir.joinpath('documentation/translating.rst').read_text() doctree = core.publish_doctree(translating) @@ -26,7 +27,16 @@ def get_languages_and_repos( language_name = language_match.group(1) language_code = language_match.group(2).lower().replace('_', '-') repo_match = re.match(':github:`GitHub <(.*)>`', repo) - yield language_code, language_name, repo_match and repo_match.group(1) + yield ( + Language(language_code, language_name), + repo_match and repo_match.group(1), + ) + + +@dataclass(frozen=True) +class Language: + code: str + name: str if __name__ == '__main__': diff --git a/template.html.jinja b/template.html.jinja index dd421d04a..1fefcff66 100644 --- a/template.html.jinja +++ b/template.html.jinja @@ -2,6 +2,7 @@ Python Docs Translation Dashboard +

Python Docs Translation Dashboard

@@ -11,50 +12,52 @@ language contribute build - visitors + visitors* translators completion -{% for language, language_name, repo, completion, translators, translators_link, visitors, build, in_switcher, on_platform, contrib_link in completion_progress | sort(attribute='3,4') | reverse %} +{% for project in completion_progress | sort(attribute='completion,translators.number') | reverse %} - {{ language_name }} ({{ language }}) + {{ project.language.name }} ({{ project.language.code }}) - {% if contrib_link %}{% endif %} - {% if on_platform %}platform{% else %}repository{% endif %} - {% if contrib_link %}{% endif %} + {% if project.contribution_link %}{% endif %} + {% if project.uses_platform %}platform{% else %}repository{% endif %} + {% if project.contribution_link %}{% endif %} - {% if build %} - ✓{% if in_switcher %} in switcher{% endif %} + {% if project.built %} + ✓{% if project.in_switcher %} in switcher{% endif %} {% else %} ✗ {% endif %} - {% if build %} - - {{ '{:,}'.format(visitors) }} + {% if project.built %} + + {{ '{:,}'.format(project.visitors) }} {% else %} - {{ '{:,}'.format(visitors) }} + {{ '{:,}'.format(project.visitors) }} {% endif %} - {% if translators_link %}{% endif %} - {{ translators }} - {% if translators_link %}{% endif %} + {% if project.translators.link %}{% endif %} + {{ project.translators.number }} + {% if project.translators.link %}{% endif %} -
{{ completion | round(2) }}%
-
{{ completion | round(2) }}%
+
{{ "{:.2f}".format(project.completion) }}%
+
{{ "{:.2f}".format(project.completion) }}%
{% endfor %} -

For more information about translations, see the Python Developer’s Guide.
Last updated at {{ generation_time.strftime('%A, %d %B %Y, %X %Z') }}.

+

* sum of daily unique visitors since 8 June 2024

+

For more information about translations, see the Python Developer’s Guide.

+

Last updated at {{ generation_time.strftime('%A, %-d %B %Y, %-H:%M:%S %Z') }} (in {{ duration // 60 }}:{{ "{:02}".format(duration % 60) }} minutes).