From 2430e2a888312f024e4c90e3c336d0ee76166014 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Sun, 3 Nov 2024 09:09:32 +0100 Subject: [PATCH] feat: use PEP 735 for devel deps Use PEP 735 dependency groups for development dependencies. --- .github/workflows/api.yml | 4 +- .github/workflows/licenses-update.yml | 2 - .github/workflows/mypy.yml | 4 +- .github/workflows/pre-commit.yml | 2 +- .github/workflows/pylint.yml | 5 +- .github/workflows/setup.yml | 10 +--- .github/workflows/test.yml | 18 +++--- .gitignore | 1 + ci/lib.sh | 2 +- ci/pip-install | 10 ++-- ci/run-migrate | 2 +- pyproject.toml | 83 +++++++++++++++------------ scripts/generate-license-data | 11 +++- scripts/set-version | 14 ++++- scripts/show-extras | 2 +- 15 files changed, 96 insertions(+), 74 deletions(-) diff --git a/.github/workflows/api.yml b/.github/workflows/api.yml index 84b408728054..90e45f5bb3b4 100644 --- a/.github/workflows/api.yml +++ b/.github/workflows/api.yml @@ -52,11 +52,11 @@ jobs: - name: Prepare database run: ./ci/prepare-database - name: Migrate database - run: coverage run ./manage.py migrate --noinput --traceback + run: uv run ./manage.py migrate --noinput --traceback - name: Generate OpenAPI run: | echo "::add-matcher::.github/matchers/spectacular.json" - ./manage.py spectacular --urlconf="weblate.api.urls" > weblate-openapi.yaml + uv run ./manage.py spectacular --urlconf="weblate.api.urls" > weblate-openapi.yaml echo "::remove-matcher owner=spectacular::" - name: openapi-lint run: npx @redocly/cli lint --format github-actions weblate-openapi.yaml diff --git a/.github/workflows/licenses-update.yml b/.github/workflows/licenses-update.yml index 56b42e831c62..90c92e39f294 100644 --- a/.github/workflows/licenses-update.yml +++ b/.github/workflows/licenses-update.yml @@ -35,8 +35,6 @@ jobs: with: python-version: '3.12' - uses: astral-sh/setup-uv@v3 - - name: Install dependencies - run: uv pip install --system $(sed -n 's/.*"\(pre-commit==\([^"]*\)\)".*/\1/p' pyproject.toml) - run: ./scripts/generate-license-data - name: Update renovate branch if: github.ref != 'refs/heads/main' diff --git a/.github/workflows/mypy.yml b/.github/workflows/mypy.yml index 39fa1c408f8a..7eda69729c54 100644 --- a/.github/workflows/mypy.yml +++ b/.github/workflows/mypy.yml @@ -51,11 +51,9 @@ jobs: uses: actions/setup-python@v5 with: python-version: '3.12' - - name: Install dependencies - run: ./ci/pip-install mypy - name: Run mypy - run: mypy --show-column-numbers weblate > mypy.log + run: uv run --group typing mypy --show-column-numbers weblate > mypy.log # Temporary hack until we have this fully working continue-on-error: true - name: Report mypy diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index f7ab8305c23d..fada48c640fd 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -41,7 +41,7 @@ jobs: fi - name: pre-commit if: ${{ steps.pep735.outputs.found == 1 }} - run: uv run --only-group pre-commit pre-commit run --all + run: uv run --no-dev --only-group pre-commit pre-commit run --all env: RUFF_OUTPUT_FORMAT: github REUSE_OUTPUT_FORMAT: github diff --git a/.github/workflows/pylint.yml b/.github/workflows/pylint.yml index f140d3bd622f..c3838df24aa3 100644 --- a/.github/workflows/pylint.yml +++ b/.github/workflows/pylint.yml @@ -26,10 +26,7 @@ jobs: uses: actions/setup-python@v5 with: python-version: '3.12' - - name: Install dependencies - run: uv pip install --system $(sed -n 's/.*"\(pylint==\([^"]*\)\)".*/\1/p' pyproject.toml) - name: Add pylint annotator uses: pr-annotators/pylint-pr-annotator@v0.0.1 - - name: Run pylint - run: pylint weblate/ + run: uv run --no-dev --only-group pylint pylint weblate/ diff --git a/.github/workflows/setup.yml b/.github/workflows/setup.yml index 65a68b49b527..e13eb51a65b8 100644 --- a/.github/workflows/setup.yml +++ b/.github/workflows/setup.yml @@ -41,18 +41,14 @@ jobs: python-version: '3.12' - name: Used versions run: ./ci/print-versions - - name: Install Python dependencies - run: ./ci/pip-install - - name: Install setuptools - run: uv pip install --system $(sed -n 's/.*"\(setuptools[<>=]=\([^"]*\)\)".*/\1/p' pyproject.toml) - name: Install Weblate - run: coverage run ./setup.py install + run: uv run coverage run ./setup.py install - name: Check difference run: diff -ruNqp weblate $(python -c 'import weblate; import os; print(os.path.dirname(weblate.__file__))') - name: Coverage run: | - coverage combine - coverage xml + uv run coverage combine + uv run coverage xml - uses: codecov/codecov-action@v4 with: token: ${{secrets.CODECOV_TOKEN}} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index df02233dad5d..ac7ac20520f5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -91,27 +91,27 @@ jobs: - name: Prepare database run: ./ci/prepare-database - name: Compile MO files - run: coverage run ./manage.py compilemessages + run: uv run coverage run ./manage.py compilemessages - name: Collect static files - run: coverage run ./manage.py collectstatic --noinput --verbosity 0 + run: uv run coverage run ./manage.py collectstatic --noinput --verbosity 0 - name: Migrate database - run: coverage run ./manage.py migrate --noinput --traceback + run: uv run coverage run ./manage.py migrate --noinput --traceback - name: Django checks - run: coverage run ./manage.py check + run: uv run coverage run ./manage.py check - name: Demo import - run: coverage run ./manage.py import_demo + run: uv run coverage run ./manage.py import_demo - name: Test with Django run: | - pytest --junitxml=junit.xml --cov=weblate weblate + uv run --all-extras pytest --junitxml=junit.xml --cov=weblate weblate cp .coverage .coverage.pytest - name: Test wsgi startup env: PYTHONPATH: . - run: coverage run weblate/wsgi.py + run: uv run coverage run weblate/wsgi.py - name: Coverage run: | - coverage combine - coverage xml + uv run coverage combine + uv run coverage xml - uses: codecov/codecov-action@v4 with: token: ${{secrets.CODECOV_TOKEN}} diff --git a/.gitignore b/.gitignore index 1ae004197a4b..ff14653b8974 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,4 @@ weblate-*.tar.* /weblate/static/js/vendor/oss-licenses.json *node_modules/ /weblate-openapi.yaml +uv.lock diff --git a/ci/lib.sh b/ci/lib.sh index b9f39e9411eb..fa27be408820 100644 --- a/ci/lib.sh +++ b/ci/lib.sh @@ -18,7 +18,7 @@ check() { } run_coverage() { - python -m coverage run --source . --append "$@" + uv run --all-extras coverage run --source . --append "$@" } get_mysql_args() { diff --git a/ci/pip-install b/ci/pip-install index 97f57304907c..9928e2bee5f2 100755 --- a/ci/pip-install +++ b/ci/pip-install @@ -11,20 +11,20 @@ if [ "${1:-latest}" = minimal ]; then sed -i '/^ *"/ s/>=/==/' pyproject.toml fi -if [ "${1:-latest}" = mypy ]; then - uv pip install --system -e ".[all,mysql,mypy,test]" +if [ "${1:-latest}" = typing ]; then + uv sync --all-extras --dev else # TODO: lxml can use wheels once xmlsec has one # see https://github.com/xmlsec/python-xmlsec/issues/327 if python -c 'import sys; sys.exit(0 if sys.version_info >= (3,13) else 1)'; then - uv pip install --system --no-binary=lxml -e ".[all,mysql,test]" + uv sync --all-extras --dev --no-binary-package lxml else - uv pip install --system -e ".[all,mysql,test]" + uv sync --all-extras --dev fi fi if [ "${1:-latest}" = edge ]; then - uv pip install --system --upgrade -e ".[all,mysql,test]" # Install from git / pre-release + . .venv/bin/activate uv pip install --system --no-deps --upgrade --force-reinstall \ https://github.com/translate/translate/archive/master.zip \ https://github.com/WeblateOrg/language-data/archive/main.zip \ diff --git a/ci/run-migrate b/ci/run-migrate index 70bfdadccb0a..6a765574b36f 100755 --- a/ci/run-migrate +++ b/ci/run-migrate @@ -88,5 +88,5 @@ check run_coverage ./manage.py migrate check # Check migrated vote exists -./manage.py shell -c 'from weblate.trans.models import Vote; Vote.objects.get(value=1)' +uv run --all-extras ./manage.py shell -c 'from weblate.trans.models import Vote; Vote.objects.get(value=1)' check diff --git a/pyproject.toml b/pyproject.toml index 5dbe6a6a84a2..d72564c36abb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,6 +5,53 @@ requires = [ "translate-toolkit" ] +[dependency-groups] +dev = [ + "django-debug-toolbar==4.4.6", + "PyICU==2.14", + "reuse==4.0.3", + "scour==0.38.2", + "tinyunicodeblock==1.3", + "setuptools>=69.0.0", + {include-group = "lint"}, + {include-group = "test"}, + {include-group = "types"} +] +lint = [ + {include-group = "pylint"}, + {include-group = "pre-commit"} +] +pre-commit = [ + "pre-commit==4.0.1" +] +pylint = [ + "pylint==3.3.1" +] +test = [ + "coverage==7.6.4", + "pytest==8.3.3", + "pytest-cov==6.0.0", + "pytest-django==4.9.0", + "responses==0.25.3", + "respx==0.21.1", + "selenium==4.26.1" +] +types = [ + "boto3-stubs==1.35.54", + "celery-types==0.22.0", + "django-stubs-ext==5.1.1", + "django-stubs==5.1.1", + "djangorestframework-stubs==3.15.1", + "types-lxml==2024.9.16", + "mypy==1.13.0", + "types-dateparser==1.2.0.20240420", + "types-jsonschema==4.23.0.20240813", + "types-openpyxl==3.1.5.20241025", + "types-Pillow==10.2.0.20240822", + "types-python-dateutil==2.9.0.20241003", + "types-requests==2.32.0.20241016" +] + [project] authors = [{name = "Michal Čihař", email = "michal@weblate.org"}] classifiers = [ @@ -116,14 +163,6 @@ amazon = [ antispam = [ "python-akismet>=0.4.2,<0.5" ] -dev = [ - "weblate[all,test,lint,mypy]", - "django-debug-toolbar==4.4.6", - "PyICU==2.14", - "reuse==4.0.3", - "scour==0.38.2", - "tinyunicodeblock==1.3" -] gerrit = [ "git-review>=2.4.0,<2.5.0" ] @@ -133,28 +172,9 @@ google = [ ldap = [ "django-auth-ldap>=4.6.0,<6.0.0" ] -lint = [ - "pre-commit==4.0.1", - "pylint==3.3.1" -] mercurial = [ "mercurial>=6.8.0,<7.0" ] -mypy = [ - "boto3-stubs==1.35.54", - "celery-types==0.22.0", - "django-stubs-ext==5.1.1", - "django-stubs==5.1.1", - "djangorestframework-stubs==3.15.1", - "types-lxml==2024.9.16", - "mypy==1.13.0", - "types-dateparser==1.2.0.20240420", - "types-jsonschema==4.23.0.20240813", - "types-openpyxl==3.1.5.20241025", - "types-Pillow==10.2.0.20240822", - "types-python-dateutil==2.9.0.20241003", - "types-requests==2.32.0.20241016" -] mysql = [ "mysqlclient>=2.1.1,<3" ] @@ -167,15 +187,6 @@ postgres = [ saml = [ "python3-saml>=1.2.1" ] -test = [ - "coverage==7.6.4", - "pytest==8.3.3", - "pytest-cov==6.0.0", - "pytest-django==4.9.0", - "responses==0.25.3", - "respx==0.21.1", - "selenium==4.26.1" -] zxcvbn = ["django-zxcvbn-password==2.1.1"] [project.readme] diff --git a/scripts/generate-license-data b/scripts/generate-license-data index bb5aad369372..4550378fe2f5 100755 --- a/scripts/generate-license-data +++ b/scripts/generate-license-data @@ -73,6 +73,15 @@ with open("weblate/utils/licensedata.py", "w") as output: # Apply coding style subprocess.run( - ["pre-commit", "run", "--files", "weblate/utils/licensedata.py"], + [ + "uv", + "run", + "--only-group", + "pre-commit", + "pre-commit", + "run", + "--files", + "weblate/utils/licensedata.py", + ], check=False, ) diff --git a/scripts/set-version b/scripts/set-version index 81a568970caa..a2908442fdb4 100755 --- a/scripts/set-version +++ b/scripts/set-version @@ -113,7 +113,19 @@ files = [ version_contributors.as_posix(), ] subprocess.run(["git", "add", version_contributors.as_posix()], check=True) -subprocess.run(["pre-commit", "run", "--files", *files], check=False) +subprocess.run( + [ + "uv", + "run", + "--only-group", + "pre-commit", + "pre-commit", + "run", + "--files", + *files, + ], + check=False, +) subprocess.run( ["git", "commit", "-m", f"chore: setting version to {version}", *files], check=True ) diff --git a/scripts/show-extras b/scripts/show-extras index 06a63c787b81..cb89613543ae 100755 --- a/scripts/show-extras +++ b/scripts/show-extras @@ -24,7 +24,7 @@ with open("pyproject.toml", "rb") as handle: toml_dict = tomllib.load(handle) for section, data in toml_dict["project"]["optional-dependencies"].items(): - if section in {"all", "ci", "dev", "lint", "mypy", "test"}: + if section == "all": continue dependency = re.split("[;<>=[]", data[0])[0].strip() print(