Merge branch 'issue-200-uv' into 'main'

Migrate from poetry to uv

Closes #200

See merge request yaal/canaille!187
This commit is contained in:
Éloi Rivard 2024-11-06 15:07:06 +00:00
commit 4fff9fa5a6
12 changed files with 2260 additions and 2896 deletions

View file

@ -11,7 +11,7 @@ on:
- '*.*.*'
jobs:
tests:
name: ${{ matrix.python }}
name: py${{ matrix.python }} unit tests
runs-on: ubuntu-latest
strategy:
fail-fast: false
@ -23,12 +23,12 @@ jobs:
- '3.10'
steps:
- uses: actions/checkout@v4
- name: Install Poetry
uses: snok/install-poetry@v1
- uses: actions/setup-python@v5
- name: Install uv
uses: astral-sh/setup-uv@v3
with:
python-version: ${{ matrix.python }}
cache: 'poetry'
enable-cache: true
- name: Install Python ${{ matrix.python }}
run: uv python install ${{ matrix.python }}
- name: Install apt dependencies
run: |
sudo apt update
@ -36,25 +36,25 @@ jobs:
- name: App armor configuration for slapd
if: ${{ !env.ACT }}
run: sudo aa-complain /usr/sbin/slapd
- name: Install dependencies and run tests
- name: Run tests
run: |
# python tzinfo fails on 'act' without this
ulimit -n 1024
export TZ=UTC
poetry --version
poetry install --extras all
poetry run pytest --showlocals
uv sync --extras-all
uv run pytest --showlocals
minversions:
name: minimum dependency versions
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Poetry
uses: snok/install-poetry@v1
- uses: actions/setup-python@v5
- name: Install uv
uses: astral-sh/setup-uv@v3
with:
python-version: '3.10'
cache: 'poetry'
enable-cache: true
- name: Install Python 3.10
run: uv python install 3.10
- name: Install apt dependencies
run: |
sudo apt update
@ -62,37 +62,33 @@ jobs:
- name: App armor configuration for slapd
if: ${{ !env.ACT }}
run: sudo aa-complain /usr/sbin/slapd
- run: sed -i -E 's/"(\^|>=)([0-9\.]+)([^,]*)"/"==\2"/' pyproject.toml
- run: sed -i -E 's/python = "==/python = "^/' pyproject.toml
- name: Install dependencies and run tests
- name: Run tests
run: |
# python tzinfo fails on 'act' without this
ulimit -n 1024
export TZ=UTC
poetry --version
poetry lock
poetry install --extras all
poetry run pytest --showlocals
uv sync --extras-all --resolution=lowest-direct
uv run pytest --showlocals
style:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pre-commit/action@v3.0.1
doc:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Poetry
uses: snok/install-poetry@v1
- uses: actions/setup-python@v5
- name: Install uv
uses: astral-sh/setup-uv@v3
with:
python-version: '3.13'
cache: 'poetry'
enable-cache: true
- name: Install apt dependencies
run: |
sudo apt update
sudo DEBIAN_FRONTEND=noninteractive apt --yes --quiet install libsasl2-dev python3-dev libldap2-dev libssl-dev slapd ldap-utils
- run: |
export TZ=UTC
poetry install --with doc
poetry run sphinx-build doc build/sphinx/html
uv sync --group doc
uv run sphinx-build doc build/sphinx/html

View file

@ -1,80 +1,82 @@
---
image: python
stages:
- test
- build
- release
before_script:
- apt update
- env DEBIAN_FRONTEND=noninteractive apt install --yes --quiet python3-dev libldap2-dev libsasl2-dev libssl-dev slapd ldap-utils python3-poetry
- poetry config virtualenvs.in-project true
variables:
UV_VERSION: 0.4
UV_CACHE_DIR: .uv-cache
BASE_LAYER: bookworm-slim
cache:
- key:
files:
- uv.lock
paths:
- .venv
- $UV_CACHE_DIR
before_script:
- apt update
- env DEBIAN_FRONTEND=noninteractive apt install --yes --quiet gcc python3-dev libldap2-dev libsasl2-dev libssl-dev slapd ldap-utils git curl
# Rust is needed to install the zxcvbn dependency
- curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
- export PATH="$HOME/.cargo/bin:$PATH"
# Needed until zxcvbn supports Python 3.13
# https://github.com/fief-dev/zxcvbn-rs-py/issues/2
- export PYO3_USE_ABI3_FORWARD_COMPATIBILITY=1
style:
image: python:3.13
variables:
PYTHON_VERSION: "3.13"
image: ghcr.io/astral-sh/uv:$UV_VERSION-python$PYTHON_VERSION-$BASE_LAYER
stage: test
script:
# pre-commit version is fixed until docformatted hook is compatible
# https://github.com/PyCQA/docformatter/issues/293
- pip install "pre-commit<4.0.0"
- pre-commit run --all-files --show-diff-on-failure
python310:
image: python:3.10
stage: test
script:
- poetry install --extras all
- poetry run pytest
python311:
image: python:3.11
stage: test
script:
- poetry install --extras all
- poetry run pytest
python312:
image: python:3.12
stage: test
script:
- poetry install --extras all
- poetry run pytest
python313:
image: python:3.13
stage: test
script:
- poetry install --extras all
- poetry run pytest
minversions:
image: python:3.13
stage: test
script:
- sed -i -E 's/"(\^|>=)([0-9\.]+)([^,]*)"/"==\2"/' pyproject.toml
- sed -i -E 's/python = "==/python = "^/' pyproject.toml
- poetry lock
- poetry install --extras all
- poetry run pytest
doc:
image: python:3.13
stage: test
script:
- poetry install --only doc
- poetry run sphinx-build doc build/sphinx/html
- uv sync --all-extras
- uv run pre-commit run --all-files --show-diff-on-failure
- uv cache prune --ci
coverage:
image: python:3.13
variables:
PYTHON_VERSION: "3.13"
image: ghcr.io/astral-sh/uv:$UV_VERSION-python$PYTHON_VERSION-$BASE_LAYER
stage: test
allow_failure: true
script:
- pip install coveralls pyyaml tomli
- poetry install --extras all
- poetry run pytest --cov --cov-fail-under=100 --cov-report term:skip-covered -n auto
- coveralls
- uv sync --all-extras
- uv pip install coveralls pyyaml tomli
- uv run pytest --cov --cov-fail-under=100 --cov-report term:skip-covered -n auto
- uv run coveralls
- uv cache prune --ci
tests:
needs: ["coverage", "style"]
parallel:
matrix:
- PYTHON_VERSION: ['3.10', '3.11', '3.12']
image: ghcr.io/astral-sh/uv:$UV_VERSION-python$PYTHON_VERSION-$BASE_LAYER
stage: test
script:
- uv sync --all-extras
- uv run pytest
- uv cache prune --ci
minversions:
needs: ["tests"]
variables:
PYTHON_VERSION: "3.10"
image: ghcr.io/astral-sh/uv:$UV_VERSION-python$PYTHON_VERSION-$BASE_LAYER
stage: test
script:
- uv sync --all-extras --resolution=lowest-direct
- uv run pytest
- uv cache prune --ci
doc:
variables:
PYTHON_VERSION: "3.13"
image: ghcr.io/astral-sh/uv:$UV_VERSION-python$PYTHON_VERSION-$BASE_LAYER
stage: test
script:
- uv sync --group doc
- uv run sphinx-build doc build/sphinx/html
- uv cache prune --ci

View file

@ -9,11 +9,11 @@ build:
- libldap2-dev
- libssl-dev
tools:
python: "3.11"
python: "3.12"
jobs:
post_create_environment:
- pip install poetry
- poetry export --with doc --output requirements.txt
- pip install uv
- uv export --group doc --no-hashes --output-file requirements.txt
post_install:
- pip install .
- pip install --requirement requirements.txt

View file

@ -17,6 +17,7 @@ Changed
- all password tests and validator are supported by password1 field :issue:`174`
- password2 (or Password confirmation) field only support "EQUAL TO PASSWORD" test :issue:`174`
- Update to HTMX 2.0.3 :pr:`184`
- Migrate from poetry to uv :pr:`187`
Removed
^^^^^^^

View file

@ -106,23 +106,23 @@ users and groups with the ``populate`` command:
.. code-block:: console
# If using docker:
docker compose exec canaille env CONFIG=conf-docker/canaille-ldap.toml poetry run canaille populate --nb 100 users # or docker-compose
docker compose exec canaille env CONFIG=conf-docker/canaille-ldap.toml uv run canaille populate --nb 100 users # or docker-compose
# If running in local environment
env CONFIG=conf/canaille-ldap.toml poetry run canaille populate --nb 100 users
env CONFIG=conf/canaille-ldap.toml uv run canaille populate --nb 100 users
Adapt to use either the `ldap` or the `sql` configuration file. Note that this will not work with the memory backend.
Unit tests
----------
To run the tests, you just can run `poetry run pytest` and/or `tox` to test all the supported python environments.
To run the tests, you just can run `uv run pytest` and/or `uv run tox` to test all the supported python environments.
Everything must be green before patches get merged.
To test a specific backend you can pass ``--backend memory``, ``--backend sql`` or ``--backend ldap`` to pytest and tox.
The test coverage is 100%, patches won't be accepted if not entirely covered. You can check the
test coverage with ``poetry run pytest --cov --cov-report=html`` or ``tox -e coverage -- --cov-report=html``.
test coverage with ``uv run pytest --cov --cov-report=html`` or ``tox -e coverage -- --cov-report=html``.
You can check the HTML coverage report in the newly created `htmlcov` directory.
Code style
@ -170,12 +170,13 @@ The generated documentation is located at ``build/sphinx/html``.
Publish a new release
---------------------
1. Check that dependencies are up to date with ``poetry show --outdated --with dev,doc,demo`` and update dependencies accordingly in separated commits.
2. Check that tests are still green for every supported python version, and that coverage is still at 100%, by running ``tox``
1. Check that dependencies are up to date with ``uv sync --upgrade`` and update dependencies accordingly in separated commits.
2. Check that tests are still green for every supported python version, and that coverage is still at 100%, by running ``uv run tox``
3. Check that the demo environments are still working
4. Check that the :ref:`development/changelog:Release notes` section is correctly filled up
5. Increase the version number in ``pyproject.toml``
6. Commit with ``git commit``
7. Publish with ``poetry publish --build``
7. Build with ``uv build``
7. Publish with ``uv publish``
8. Tag you commit with ``git tag XX.YY.ZZ``
9. Push the release commit and the new tag on the repository with ``git push --tags``

View file

@ -1,6 +0,0 @@
include canaille/*.sample.*
graft canaille/backends/ldap/schemas
graft canaille/templates
graft canaille/themes
graft canaille/translations
graft canaille/static

View file

@ -7,11 +7,21 @@ RUN \
gcc \
libsasl2-dev \
libldap2-dev \
libssl-dev
libssl-dev \
curl
COPY poetry.lock pyproject.toml demo/demoapp.py /opt/canaille/
RUN pip install poetry
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
ENV PATH="/root/.cargo/bin:${PATH}"
# Needed until zxcvbn supports Python 3.13
# https://github.com/fief-dev/zxcvbn-rs-py/issues/2
ENV PYO3_USE_ABI3_FORWARD_COMPATIBILITY="1"
COPY uv.lock pyproject.toml hatch_build.py LICENSE.rst README.md demo/demoapp.py /opt/canaille/
COPY canaille /opt/canaille/canaille
RUN pip install uv
WORKDIR /opt/canaille
RUN poetry install --with demo --without dev --extras all
RUN uv sync --group demo --all-extras
ENTRYPOINT ["poetry", "run", "flask", "run", "--host=0.0.0.0", "--extra-files", "/opt/canaille/conf/canaille-memory.toml", "--extra-files", "/opt/canaille/conf/canaille-ldap.toml", "--extra-files", "/opt/canaille/conf/canaille-sql.toml"]
ENTRYPOINT ["uv", "run", "flask", "run", "--host=0.0.0.0", "--extra-files", "/opt/canaille/conf/canaille-memory.toml", "--extra-files", "/opt/canaille/conf/canaille-ldap.toml", "--extra-files", "/opt/canaille/conf/canaille-sql.toml"]

View file

@ -13,24 +13,28 @@ if ! type python > /dev/null 2>&1 && ! type python3 > /dev/null 2>&1; then
exit 1
fi
if ! type poetry > /dev/null 2>&1; then
echo "Cannot start the canaille demo server. Please install poetry on your system"
if ! type uv > /dev/null 2>&1; then
echo "Cannot start the canaille demo server. Please install uv on your system"
echo "or run the demo with docker-compose."
echo "https://python-poetry.org/docs/#installation"
echo "https://docs.astral.sh/uv/getting-started/installation/"
exit 1
fi
pushd "$DIR" > /dev/null 2>&1 || exit
poetry install --with demo --all-extras
# Needed until zxcvbn supports Python 3.13
# https://github.com/fief-dev/zxcvbn-rs-py/issues/2
export PYO3_USE_ABI3_FORWARD_COMPATIBILITY=1
uv sync --group demo --all-extras
if [ "$BACKEND" = "memory" ]; then
poetry run honcho --env ../.env --procfile Procfile-memory start
uv run honcho --env ../.env --procfile Procfile-memory start
elif [ "$BACKEND" = "sql" ]; then
poetry run honcho --env ../.env --procfile Procfile-sql start
uv run honcho --env ../.env --procfile Procfile-sql start
elif [ "$BACKEND" = "ldap" ]; then
@ -40,7 +44,7 @@ elif [ "$BACKEND" = "ldap" ]; then
exit 1
fi
poetry run honcho --env ../.env --procfile Procfile-ldap start
uv run honcho --env ../.env --procfile Procfile-ldap start
else

View file

@ -1,7 +1,9 @@
import os
from hatchling.builders.hooks.plugin.interface import BuildHookInterface
def create_mo_files(setup_kwargs):
def create_mo_files():
from babel.messages.frontend import compile_catalog
cmd = compile_catalog()
@ -10,7 +12,11 @@ def create_mo_files(setup_kwargs):
cmd.statistics = True
cmd.finalize_options()
cmd.run()
return setup_kwargs
class CustomBuildHook(BuildHookInterface):
def initialize(self, version, build_data):
create_mo_files()
if __name__ == "__main__":

2615
poetry.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,13 +1,13 @@
[build-system]
requires = ["poetry-core>=1.0.0", "babel", "setuptools; python_version>='3.12'"]
build-backend = "poetry.core.masonry.api"
requires = ["hatchling", "babel", "setuptools >= 50.0.0; python_version>='3.12'"]
build-backend = "hatchling.build"
[tool]
[tool.poetry]
[project]
name = "Canaille"
version = "0.0.55"
description = "Lightweight identity and authorization management software"
license = "MIT"
license = {file = "LICENSE.rst"}
readme = "README.md"
keywords = ["oidc", "oauth", "oauth2", "openid", "identity"]
classifiers = [
"Intended Audience :: Developers",
@ -25,137 +25,99 @@ classifiers = [
"Topic :: System :: Systems Administration :: Authentication/Directory :: LDAP",
]
authors = ["Yaal Coop <contact@yaal.coop>"]
maintainers = [
"Éloi Rivard <eloi@yaal.coop>",
authors = [{name="Yaal Coop", email="contact@yaal.coop"}]
maintainers = [{name="Éloi Rivard", email="eloi@yaal.coop"}]
requires-python = ">=3.10"
dependencies = [
"flask >= 3.0.0",
"flask-wtf >= 1.2.1",
"pydantic-settings >= 2.0.3",
"wtforms >= 3.1.1",
]
[project.optional-dependencies]
front = [
"email_validator >= 2.0.0",
"flask-babel >= 4.0.0",
"flask-themer >= 2.0.0",
"pycountry >= 23.12.7",
"pytz >= 2022.7",
"toml >= 0.10.0",
"zxcvbn-rs-py >= 0.1.1",
]
oidc = [
"authlib >= 1.3.0",
]
ldap = [
"python-ldap >= 3.4.0",
]
sentry = [
"sentry-sdk >= 2.0.0",
]
sql = [
"passlib >= 1.7.4",
"sqlalchemy >= 2.0.23",
"sqlalchemy-json >= 0.7.0",
"sqlalchemy-utils >= 0.41.1",
]
[project.urls]
homepage = "https://canaille.yaal.coop"
documentation = "https://canaille.readthedocs.io/en/latest/"
repository = "https://gitlab.com/yaal/canaille"
readme = "README.md"
include = ["canaille/translations/*/LC_MESSAGES/*.mo"]
[tool.poetry.dependencies]
python = "<3.13,>=3.10"
flask = "^3.0.0"
flask-wtf = "^1.2.1"
pydantic-settings = "^2.0.3"
wtforms = "^3.1.1"
# extra : front
email_validator = {version = "^2.0.0", optional=true}
flask-babel = {version = "^4.0.0", optional=true}
flask-themer = {version = "^2.0.0", optional=true}
pycountry = {version = ">=22.1.10", optional=true}
pytz = {version = ">=2022.7", optional=true}
toml = {version = "^0.10.0", optional=true, python = "<3.11"}
zxcvbn-rs-py = {version = "^0.1.1", optional=true}
# extra : oidc
authlib = {version = "^1.2.1", optional=true}
# extra : ldap
python-ldap = {version = "^3.4.0", optional=true}
# extra : sentry
sentry-sdk = {version = "^2.0.0", optional=true, extras=["flask"]}
# extra : sql
passlib = {version = "^1.7.4", optional=true}
sqlalchemy = {version = "^2.0.23", optional=true}
sqlalchemy-json = {version = "^0.7.0", optional=true}
sqlalchemy-utils = {version = "^0.41.1", optional=true}
[tool.poetry.group.doc]
optional = true
[tool.poetry.group.doc.dependencies]
autodoc-pydantic = "^2.0.1"
shibuya = "^2024.3.1"
sphinx = ">=7.0.0"
sphinx-design = "^0.6.0"
sphinx-issues = "^5.0.0"
sphinx-click = "^6.0.0"
[tool.poetry.group.dev.dependencies]
coverage = {version = "*", extras=["toml"]}
faker = "*"
flask-webtest = "*"
# pre-commit version is fixed until docformatted hook is compatible
# https://github.com/PyCQA/docformatter/issues/293
pre-commit = "^3.0.0"
pyquery = "*"
pytest = "^8.0.0"
pytest-coverage = "*"
pytest-httpserver = "*"
pytest-lazy-fixtures = "^1.0.7"
pytest-smtpd = "^0.1.0"
pytest-xdist = "^3.3.1"
slapd = "*"
time-machine = "^2.14.1"
toml = "^0.10.0"
[dependency-groups]
dev = [
"babel >= 2.14.0",
"coverage[toml] >= 6.0.0",
"faker >= 30.0.0",
"flask-webtest >= 0.1.6",
# pre-commit version is fixed until docformatted hook is compatible
# https://github.com/PyCQA/docformatter/issues/293
"pre-commit < 4.0.0",
"pre-commit-uv>=4.1.4",
"pyquery >= 2.0.0",
"pytest >= 8.0.0",
"pytest-cov >= 6.0.0",
"pytest-httpserver >= 1.1.0",
"pytest-lazy-fixtures >= 1.0.7",
"pytest-smtpd >= 0.1.0",
"pytest-xdist >= 3.3.1",
"slapd >= 0.1.5",
"time-machine >= 2.14.1",
"toml >= 0.10.0",
"tox-uv >= 1.16.0",
# Babel 2.14 does not directly depend on setuptools
# https://github.com/python-babel/babel/blob/40e60a1f6cf178d9f57fcc14f157ea1b2ab77361/CHANGES.rst?plain=1#L22-L24
# and neither python 3.12 due to PEP 632
# https://peps.python.org/pep-0632/
setuptools = {version = "*", python = ">=3.12"}
[tool.poetry.group.demo]
optional = true
[tool.poetry.group.demo.dependencies]
faker = "*"
honcho = "*"
slapd = "*"
requests = "*"
watchdog = "^4.0.0"
[tool.poetry.extras]
front = [
"click",
"email_validator",
"flask-babel",
"flask-themer",
"pycountry",
"pytz",
"toml",
"zxcvbn-rs-py",
]
ldap = [
"python-ldap",
]
oidc = [
"authlib",
]
sentry = [
"sentry-sdk",
]
sql = [
"passlib",
"sqlalchemy",
"sqlalchemy-json",
"sqlalchemy-utils",
]
all = [
"click",
"email_validator",
"flask-babel",
"flask-themer",
"passlib",
"pycountry",
"pytz",
"toml",
"python-ldap",
"authlib",
"sentry-sdk",
"sqlalchemy",
"sqlalchemy-json",
"sqlalchemy-utils",
"zxcvbn-rs-py",
"setuptools >= 50.0.0; python_version>='3.12'"
]
[tool.poetry.scripts]
doc = [
"autodoc-pydantic >= 2.0.1",
"shibuya >= 2024.3.1",
"sphinx >= 7.0.0",
"sphinx-design >= 0.6.0",
"sphinx-issues >= 5.0.0",
"sphinx-click >= 6.0.0",
]
demo = [
"faker",
"honcho",
"slapd",
"requests",
"watchdog >= 4.0.0",
]
[project.scripts]
canaille = "canaille.commands:cli"
[options.packages.find]
@ -166,9 +128,25 @@ exclude = [
"doc.*",
]
[tool.poetry.build]
generate-setup-file = false
script = "build.py"
[tool.hatch.build]
include = [
"canaille/",
"doc/",
"tests/",
"CHANGES.rst",
"CONTRIBUTING.rst",
"README.md",
]
exclude = [
"docs/_build/",
]
artifacts = ["canaille/translations/*/LC_MESSAGES/*.mo"]
[tool.hatch.build.hooks.custom]
dependencies = [
"Babel>=2.6.0",
"setuptools >= 50.0.0; python_version>='3.12'",
]
[tool.coverage.run]
source = [
@ -206,41 +184,52 @@ force-single-line = true
docstring-code-format = true
[tool.tox]
legacy_tox_ini = """
[tox]
isolated_build = true
skipsdist = true
envlist =
style
py310
py311
py312
py313
doc
coverage
requires = ["tox>=4.19"]
env_list = [
"style",
"py310",
"py311",
"py312",
"py313",
"minversions",
"doc",
"coverage",
]
[testenv]
allowlist_externals = poetry
commands =
poetry install --extras all
poetry run pytest --showlocals --full-trace {posargs}
[tool.tox.env_run_base]
# Needed until zxcvbn supports Python 3.13
# https://github.com/fief-dev/zxcvbn-rs-py/issues/2
set_env = {PYO3_USE_ABI3_FORWARD_COMPATIBILITY = "1"}
runner = "uv-venv-lock-runner"
dependency_groups = ["dev"]
uv_sync_flags = ["--all-extras"]
commands = [
["pytest", "--showlocals", "--full-trace", "{posargs}"],
]
[testenv:style]
commands =
pip install pre-commit<4
pre-commit run --all-files
[tool.tox.env.style]
skip_install = true
runner = "uv-venv-runner"
commands = [
["pre-commit", "run", "--all-files", "--show-diff-on-failure"],
]
[testenv:doc]
commands =
poetry install --with doc --without dev --extras oidc
poetry run sphinx-build doc build/sphinx/html
[tool.tox.env.minversions]
uv_resolution = "lowest-direct"
basepython = ["python3.10"]
[testenv:coverage]
commands =
poetry install --extras all
poetry run pytest --cov --cov-fail-under=100 --cov-report term:skip-covered {posargs:-n auto}
poetry run coverage html
"""
[tool.tox.env.doc]
dependency_groups = ["doc"]
commands = [
["sphinx-build", "--builder", "html", "doc", "build/sphinx/html"],
["sphinx-build", "--builder", "man", "doc", "build/sphinx/html"],
]
[tool.tox.env.coverage]
commands = [
["pytest", "--cov", "--cov-fail-under=100", "--cov-report", "term:skip-covered", "{posargs}"],
["coverage", "html"],
]
[[tool.babel.mappings]]
method = "python"

1976
uv.lock Normal file

File diff suppressed because it is too large Load diff