diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 000000000..ca7306898 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,19 @@ +name: Lint + +on: [push, pull_request, workflow_dispatch] + +env: + FORCE_COLOR: 1 + +jobs: + lint: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + - uses: actions/setup-python@v5 + with: + python-version: "3.x" + - uses: tox-dev/action-pre-commit-uv@v1 diff --git a/.github/workflows/update.yml b/.github/workflows/update.yml index e162106f3..23259e2fe 100644 --- a/.github/workflows/update.yml +++ b/.github/workflows/update.yml @@ -15,7 +15,7 @@ jobs: - uses: actions/setup-python@v5 with: python-version: "3.x" - - uses: astral-sh/setup-uv@v4 + - uses: astral-sh/setup-uv@v5 - uses: actions/checkout@v4 - run: sudo apt-get install -y gettext - run: uv run generate.py # generates "index.html" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 000000000..1605084dc --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,38 @@ +repos: + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.8.4 + hooks: + - id: ruff + args: [--fix, --exit-non-zero-on-fix] + - id: ruff-format + + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + - id: check-added-large-files + - id: check-case-conflict + - id: check-merge-conflict + - id: check-toml + - id: check-yaml + - id: debug-statements + - id: end-of-file-fixer + - id: forbid-submodules + - id: trailing-whitespace + + - repo: https://github.com/python-jsonschema/check-jsonschema + rev: 0.30.0 + hooks: + - id: check-github-workflows + + - repo: https://github.com/rhysd/actionlint + rev: v1.7.5 + hooks: + - id: actionlint + + - repo: meta + hooks: + - id: check-hooks-apply + - id: check-useless-excludes + +ci: + autoupdate_schedule: quarterly diff --git a/completion.py b/completion.py index 26ca52746..8cd7959a8 100644 --- a/completion.py +++ b/completion.py @@ -14,7 +14,7 @@ def branches_from_devguide(devguide_dir: Path) -> list[str]: p = devguide_dir.joinpath('include/release-cycle.json') data = json.loads(p.read_text()) return [ - branch for branch in data if data[branch]["status"] in ("bugfix", "security") + branch for branch in data if data[branch]['status'] in ('bugfix', 'security') ] @@ -22,7 +22,9 @@ def get_completion(clones_dir: str, repo: str) -> tuple[float, int]: clone_path = Path(clones_dir, repo) for branch in branches_from_devguide(Path(clones_dir, 'devguide')) + ['master']: try: - git.Repo.clone_from(f'https://github.com/{repo}.git', clone_path, branch=branch) + git.Repo.clone_from( + f'https://github.com/{repo}.git', clone_path, branch=branch + ) except git.GitCommandError: print(f'failed to clone {repo} {branch}') translators_number = 0 @@ -32,6 +34,10 @@ def get_completion(clones_dir: str, repo: str) -> tuple[float, int]: break with TemporaryDirectory() as tmpdir: completion = potodo.merge_and_scan_path( - clone_path, pot_path=Path(clones_dir, 'cpython/Doc/build/gettext'), merge_path=Path(tmpdir), hide_reserved=False, api_url='' + clone_path, + pot_path=Path(clones_dir, 'cpython/Doc/build/gettext'), + merge_path=Path(tmpdir), + hide_reserved=False, + api_url='', ).completion return completion, translators_number diff --git a/generate.py b/generate.py index 217a799f6..fca24a121 100644 --- a/generate.py +++ b/generate.py @@ -25,13 +25,22 @@ generation_time = datetime.now(timezone.utc) with TemporaryDirectory() as clones_dir: - Repo.clone_from(f'https://github.com/python/devguide.git', devguide_dir := Path(clones_dir, 'devguide'), depth=1) + Repo.clone_from( + 'https://github.com/python/devguide.git', + devguide_dir := Path(clones_dir, 'devguide'), + depth=1, + ) latest_branch = branches_from_devguide(devguide_dir)[0] Repo.clone_from( - f'https://github.com/python/cpython.git', Path(clones_dir, 'cpython'), depth=1, branch=latest_branch + 'https://github.com/python/cpython.git', + 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', Path(clones_dir, 'cpython/Doc'), 'gettext'], check=True + ) switcher_languages = list(switcher.get_languages()) for language, repo in repositories.get_languages_and_repos(devguide_dir): if repo: @@ -78,7 +87,7 @@ {{ language }} - + {% if in_switcher %} in switcher @@ -111,7 +120,9 @@ """ ) -output = template.render(completion_progress=completion_progress, generation_time=generation_time) +output = template.render( + completion_progress=completion_progress, generation_time=generation_time +) -with open("index.html", "w") as file: +with open('index.html', 'w') as file: file.write(output) diff --git a/repositories.py b/repositories.py index c7e09323c..c266a8be1 100644 --- a/repositories.py +++ b/repositories.py @@ -1,4 +1,3 @@ -import tempfile import pathlib import re from typing import Generator, Optional @@ -7,7 +6,9 @@ from docutils.nodes import table, row -def get_languages_and_repos(devguide_dir: pathlib.Path) -> Generator[tuple[str, Optional[str]], None, None]: +def get_languages_and_repos( + devguide_dir: pathlib.Path, +) -> Generator[tuple[str, Optional[str]], None, None]: translating = devguide_dir.joinpath('documentation/translating.rst').read_text() doctree = core.publish_doctree(translating) @@ -15,6 +16,8 @@ def get_languages_and_repos(devguide_dir: pathlib.Path) -> Generator[tuple[str, for row_node in node.traverse(row)[1:]: language = row_node[0].astext() repo = row_node[2].astext() - language_code = re.match(r'.* \((.*)\)', language).group(1).lower().replace('_', '-') + language_code = ( + re.match(r'.* \((.*)\)', language).group(1).lower().replace('_', '-') + ) repo_match = re.match(':github:`GitHub <(.*)>`', repo) yield language_code, repo_match and repo_match.group(1) diff --git a/ruff.toml b/ruff.toml new file mode 100644 index 000000000..749ef043d --- /dev/null +++ b/ruff.toml @@ -0,0 +1,2 @@ +[format] +quote-style = "single" diff --git a/switcher.py b/switcher.py index 301b54812..717a04748 100644 --- a/switcher.py +++ b/switcher.py @@ -6,7 +6,6 @@ """ import tomllib -from collections import defaultdict from typing import Generator import requests @@ -14,24 +13,24 @@ def get_languages() -> Generator[str, None, None]: data = requests.get( - "https://raw.githubusercontent.com/" - "python/docsbuild-scripts/refs/heads/main/config.toml", + 'https://raw.githubusercontent.com/' + 'python/docsbuild-scripts/refs/heads/main/config.toml', timeout=10, ).text config = tomllib.loads(data) - languages = config["languages"] - defaults = config["defaults"] + languages = config['languages'] + defaults = config['defaults'] for code, language in languages.items(): - if language.get("in_prod", defaults["in_prod"]): - yield code.lower().replace("_", "-") + if language.get('in_prod', defaults['in_prod']): + yield code.lower().replace('_', '-') def main() -> None: languages = list(get_languages()) print(languages) - for code in ("en", "pl", "ar", "zh-cn"): - print(f"{code}: {code in languages}") + for code in ('en', 'pl', 'ar', 'zh-cn'): + print(f'{code}: {code in languages}') -if __name__ == "__main__": +if __name__ == '__main__': main() diff --git a/translators.py b/translators.py index dd3db133f..2fe11ccbc 100644 --- a/translators.py +++ b/translators.py @@ -10,9 +10,11 @@ def get_number(path: Path) -> int: from_git_history = get_number_from_git_history(path) return max(from_headers, from_git_history) + def get_number_from_git_history(path: Path) -> int: return len(Repo(path).git.shortlog('-s', 'HEAD').splitlines()) + def yield_from_headers(path: Path) -> Generator[str, None, None]: for file in path.rglob('*.po'): try: @@ -21,7 +23,7 @@ def yield_from_headers(path: Path) -> Generator[str, None, None]: continue if 'Translators:' not in header: continue - for translator_record in header[header.index('Translators:') + 1:]: + for translator_record in header[header.index('Translators:') + 1 :]: try: translator, _year = translator_record.split(', ') except ValueError: diff --git a/visitors.py b/visitors.py index 5c4315c76..fde5d593e 100644 --- a/visitors.py +++ b/visitors.py @@ -7,8 +7,13 @@ def get_number_of_visitors(language: str) -> int: - param = urllib.parse.urlencode({'filters': f'[["contains","event:page",["/{language}/"]]]'}) + param = urllib.parse.urlencode( + {'filters': f'[["contains","event:page",["/{language}/"]]]'} + ) r = requests.get(f'https://plausible.io/docs.python.org/export?{param}', timeout=10) - with zipfile.ZipFile(io.BytesIO(r.content), 'r') as z, z.open('visitors.csv') as csv_file: + with ( + zipfile.ZipFile(io.BytesIO(r.content), 'r') as z, + z.open('visitors.csv') as csv_file, + ): csv_reader = csv.DictReader(io.TextIOWrapper(csv_file)) - return sum(int(row["visitors"]) for row in csv_reader) + return sum(int(row['visitors']) for row in csv_reader)