Skip to content

Add pre-commit #90

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 13, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .github/workflows/pre-commit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: pre-commit
on:
schedule:
- cron: '0 0 * * 1,5'
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
2 changes: 1 addition & 1 deletion .github/workflows/update-lint-and-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ jobs:
- run: git config --local user.name "GitHub Action's update-translation job"
- name: Check changes significance
run: >
! git diff -I'^"POT-Creation-Date: ' -I'^"Language-Team: ' -I'^# ' -I'^"Last-Translator: ' -I'^"Project-Id-Version: ' --exit-code && echo "SIGNIFICANT_CHANGES=1" >> $GITHUB_ENV || exit 0
! git diff -I'^"POT-Creation-Date: ' -I'^"Language-Team: ' -I'^# ' -I'^"Last-Translator: ' -I'^"Project-Id-Version: ' --exit-code && echo "SIGNIFICANT_CHANGES=1" >> "$GITHUB_ENV" || exit 0
- run: git add .
- run: git commit -m 'Update translation from Transifex'
if: env.SIGNIFICANT_CHANGES
Expand Down
35 changes: 35 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.11.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-yaml
- id: debug-statements
- id: end-of-file-fixer
exclude: ^\.tx/
- id: forbid-submodules
- id: trailing-whitespace

- repo: https://github.com/python-jsonschema/check-jsonschema
rev: 0.32.1
hooks:
- id: check-github-workflows
Comment on lines +22 to +25
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't it superfluous to the actionlint?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the redundancy hurt, it is only a fraction of a second after all?


- repo: https://github.com/rhysd/actionlint
rev: v1.7.7
hooks:
- id: actionlint

- repo: meta
hooks:
- id: check-hooks-apply
- id: check-useless-excludes
2 changes: 1 addition & 1 deletion license.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
**License**

By inviting you to work on a project on the Transifex platform, we offer a contract for donating your translations to the Python Software Foundation under the CC0 license.
By inviting you to work on a project on the Transifex platform, we offer a contract for donating your translations to the Python Software Foundation under the CC0 license.
In return, it will be visible that you are the translator of the part you translated. You signify your acceptance of this agreement by submitting your work for inclusion in the documentation.
80 changes: 45 additions & 35 deletions manage_translation.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
from polib import pofile
from transifex.api import transifex_api

LANGUAGE = 'pl'
LANGUAGE = "pl"


def fetch():
Expand All @@ -39,18 +39,18 @@ def fetch():
sys.stderr.write("The Transifex client app is required.\n")
exit(code)
lang = LANGUAGE
_call(f'tx pull -l {lang} --minimum-perc=1 --force --skip')
for file in Path().rglob('*.po'):
_call(f'msgcat --no-location -o {file} {file}')
_call(f"tx pull -l {lang} --minimum-perc=1 --force --skip")
for file in Path().rglob("*.po"):
_call(f"msgcat --no-location -o {file} {file}")


def _call(command: str):
if (return_code := call(command, shell=True)) != 0:
exit(return_code)


PROJECT_SLUG = 'python-newest'
VERSION = '3.14'
PROJECT_SLUG = "python-newest"
VERSION = "3.14"


def recreate_tx_config():
Expand All @@ -61,46 +61,50 @@ def recreate_tx_config():
with chdir(directory):
_clone_cpython_repo(VERSION)
_build_gettext()
with chdir(Path(directory) / 'cpython/Doc/build'):
with chdir(Path(directory) / "cpython/Doc/build"):
_create_txconfig()
_update_txconfig_resources()
with open('.tx/config', 'r') as file:
with open(".tx/config", "r") as file:
contents = file.read()
contents = contents.replace('./<lang>/LC_MESSAGES/', '')
with open('.tx/config', 'w') as file:
contents = contents.replace("./<lang>/LC_MESSAGES/", "")
with open(".tx/config", "w") as file:
file.write(contents)
warn_about_files_to_delete()


def warn_about_files_to_delete():
files = list(_get_files_to_delete())
if not files:
return
warn(f'Found {len(files)} file(s) to delete: {", ".join(files)}.')
warn(f"Found {len(files)} file(s) to delete: {', '.join(files)}.")


def _get_files_to_delete():
with open('.tx/config') as config_file:
with open(".tx/config") as config_file:
config = config_file.read()
for file in Path().rglob('*.po'):
for file in Path().rglob("*.po"):
if os.fsdecode(file) not in config:
yield os.fsdecode(file)


def _clone_cpython_repo(version: str):
_call(f'git clone -b {version} --single-branch https://github.com/python/cpython.git --depth 1')
_call(
f"git clone -b {version} --single-branch https://github.com/python/cpython.git --depth 1"
)


def _build_gettext():
_call("make -C cpython/Doc/ gettext")


def _create_txconfig():
_call('sphinx-intl create-txconfig')
_call("sphinx-intl create-txconfig")


def _update_txconfig_resources():
_call(
f'sphinx-intl update-txconfig-resources --transifex-organization-name python-doc '
f'--transifex-project-name={PROJECT_SLUG} --locale-dir . --pot-dir gettext'
f"sphinx-intl update-txconfig-resources --transifex-organization-name python-doc "
f"--transifex-project-name={PROJECT_SLUG} --locale-dir . --pot-dir gettext"
)


Expand All @@ -115,32 +119,34 @@ class ResourceLanguageStatistics:
@classmethod
def from_api_entry(cls, data: transifex_api.ResourceLanguageStats) -> Self:
return cls(
name=data.id.removeprefix(f'o:python-doc:p:{PROJECT_SLUG}:r:').removesuffix(f':l:{LANGUAGE}'),
total_words=data.attributes['total_words'],
translated_words=data.attributes['translated_words'],
total_strings=data.attributes['total_strings'],
translated_strings=data.attributes['translated_strings'],
name=data.id.removeprefix(f"o:python-doc:p:{PROJECT_SLUG}:r:").removesuffix(
f":l:{LANGUAGE}"
),
total_words=data.attributes["total_words"],
translated_words=data.attributes["translated_words"],
total_strings=data.attributes["total_strings"],
translated_strings=data.attributes["translated_strings"],
)


def _get_tx_token() -> str:
if os.path.exists('.tx/api-key'):
with open('.tx/api-key') as f:
if os.path.exists(".tx/api-key"):
with open(".tx/api-key") as f:
transifex_api_key = f.read()
else:
transifex_api_key = os.getenv('TX_TOKEN', '')
transifex_api_key = os.getenv("TX_TOKEN", "")
return transifex_api_key


def _get_resources() -> list[transifex_api.Resource]:
transifex_api.setup(auth=_get_tx_token())
return transifex_api.Resource.filter(project=f'o:python-doc:p:{PROJECT_SLUG}').all()
return transifex_api.Resource.filter(project=f"o:python-doc:p:{PROJECT_SLUG}").all()


def get_resource_language_stats() -> list[ResourceLanguageStatistics]:
transifex_api.setup(auth=_get_tx_token())
resources = transifex_api.ResourceLanguageStats.filter(
project=f'o:python-doc:p:{PROJECT_SLUG}', language=f'l:{LANGUAGE}'
project=f"o:python-doc:p:{PROJECT_SLUG}", language=f"l:{LANGUAGE}"
).all()
return [ResourceLanguageStatistics.from_api_entry(entry) for entry in resources]

Expand All @@ -159,10 +165,10 @@ def get_number_of_translators():


def _fetch_translators() -> Generator[str, None, None]:
for file in Path().rglob('*.po'):
for file in Path().rglob("*.po"):
header = pofile(file).header.splitlines()
for translator_record in header[header.index('Translators:') + 1:]:
translator, _year = translator_record.split(', ')
for translator_record in header[header.index("Translators:") + 1 :]:
translator, _year = translator_record.split(", ")
yield translator


Expand All @@ -174,7 +180,9 @@ def _eliminate_aliases(translators: set[str]) -> set[str]:
unique = set()
for name in translators:
for match in unique:
if (ratio := SequenceMatcher(lambda x: x in '<>@', name, match).ratio()) > 0.64:
if (
ratio := SequenceMatcher(lambda x: x in "<>@", name, match).ratio()
) > 0.64:
info(f"{name} and {match} are similar ({ratio:.3f}). Deduplicating.")
break
else:
Expand All @@ -183,15 +191,17 @@ def _eliminate_aliases(translators: set[str]) -> set[str]:


def language_switcher(entry: ResourceLanguageStatistics) -> bool:
language_switcher_resources_prefixes = ('bugs', 'tutorial', 'library--functions')
return any(entry.name.startswith(prefix) for prefix in language_switcher_resources_prefixes)
language_switcher_resources_prefixes = ("bugs", "tutorial", "library--functions")
return any(
entry.name.startswith(prefix) for prefix in language_switcher_resources_prefixes
)


if __name__ == "__main__":
RUNNABLE_SCRIPTS = ('fetch', 'recreate_tx_config', 'warn_about_files_to_delete')
RUNNABLE_SCRIPTS = ("fetch", "recreate_tx_config", "warn_about_files_to_delete")

parser = ArgumentParser()
parser.add_argument('cmd', choices=RUNNABLE_SCRIPTS)
parser.add_argument("cmd", choices=RUNNABLE_SCRIPTS)
options = parser.parse_args()

eval(options.cmd)()
12 changes: 6 additions & 6 deletions update_switcher_chart.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,26 @@
from matplotlib import pyplot
from matplotlib.ticker import PercentFormatter

repo = Repo('.')
repo = Repo(".")
progress, dates = [], []
for commit in repo.iter_commits():
try:
readme_content = repo.git.show('{}:{}'.format(commit.hexsha, 'README.md'))
readme_content = repo.git.show("{}:{}".format(commit.hexsha, "README.md"))
except GitCommandError:
continue
found = search(r'!\[(\d\d.\d\d)% przełącznika języków]', readme_content)
found = search(r"!\[(\d\d.\d\d)% przełącznika języków]", readme_content)
if not found:
found = search(r'!\[(\d+.\d\d)% language switchera]', readme_content)
found = search(r"!\[(\d+.\d\d)% language switchera]", readme_content)
if not found:
found = search(r'!\[(\d+.\d\d)% do language switchera]', readme_content)
found = search(r"!\[(\d+.\d\d)% do language switchera]", readme_content)
if not found:
print(readme_content)
continue
number = float(found.group(1))
progress.append(number)
dates.append(datetime.fromtimestamp(commit.authored_date))

pyplot.plot_date(dates, progress, linestyle='-', marker='')
pyplot.plot_date(dates, progress, linestyle="-", marker="")
pyplot.ylim(ymin=0)
pyplot.grid()
pyplot.gcf().autofmt_xdate()
Expand Down