Skip to content

Commit 19ee5ce

Browse files
authored
Merge pull request #74 from openradx/poetry-to-uv
Switch from poetry to uv
2 parents 2bf845f + 02481e3 commit 19ee5ce

File tree

18 files changed

+2320
-3544
lines changed

18 files changed

+2320
-3544
lines changed

.devcontainer/Dockerfile

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ USER root
66
# - gettext for Django translations
77
# - postgresql-common for the apt.postgresql.org.sh script
88
# - postgresql-client-17 for a current version of psql
9+
# Make sure to match the version of the postgres service in the compose file!
910
RUN sudo apt-get update \
1011
&& apt-get install -y --no-install-recommends \
1112
bash-completion \
@@ -17,6 +18,3 @@ RUN sudo apt-get update \
1718
&& rm -rf /var/lib/apt/lists/*
1819

1920
USER vscode
20-
21-
RUN pipx install poetry \
22-
&& poetry completions bash >> ~/.bash_completion

.devcontainer/devcontainer.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@
66
"ghcr.io/devcontainers/features/docker-in-docker:2": {},
77
"ghcr.io/devcontainers/features/node:1": {}
88
},
9-
// https://github.com/orgs/community/discussions/50403
10-
// "initializeCommand": "docker system prune --all --force",
11-
"postCreateCommand": "poetry install && npm install && poetry run ./cli.py init-workspace",
9+
"remoteEnv": {
10+
"UV_CACHE_DIR": "/workspace/.cache"
11+
},
12+
"postCreateCommand": "uv sync && npm install && uv run ./cli.py init-workspace",
1213
"customizations": {
1314
"vscode": {
1415
"extensions": [

.github/renovate.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
"allowedVersions": "<=3.12"
3131
},
3232
{
33-
"managers": ["poetry"],
33+
"managers": ["pep621"],
3434
"matchPackageNames": ["factory-boy"],
3535
"allowedVersions": "<=3.3.2"
3636
}

.github/workflows/ci.yml

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,27 +8,23 @@ jobs:
88
ci:
99
strategy:
1010
fail-fast: false
11-
matrix:
12-
python-version: ["3.12"]
13-
poetry-version: ["2.0.1"]
14-
os: [ubuntu-latest]
15-
runs-on: ${{ matrix.os }}
11+
runs-on: "ubuntu-latest"
1612
timeout-minutes: 15
1713
steps:
1814
- name: Checkout repository
1915
uses: actions/checkout@v4
16+
- name: Install uv
17+
uses: astral-sh/setup-uv@v5
18+
with:
19+
version: "0.6.0"
2020
- name: Setup Python
2121
uses: actions/setup-python@v5
2222
with:
23-
python-version: ${{ matrix.python-version }}
24-
- name: Setup Poetry
25-
uses: abatilo/actions-poetry@v4
26-
with:
27-
poetry-version: ${{ matrix.poetry-version }}
23+
python-version-file: ".python-version"
2824
- name: Install dependencies
29-
run: poetry install
25+
run: uv sync
3026
- name: Configure environment
31-
run: poetry run ./cli.py init-workspace
27+
run: uv run ./cli.py init-workspace
3228
- name: Set up Docker Buildx
3329
uses: docker/setup-buildx-action@v3
3430
- name: Build and cache Docker images
@@ -41,14 +37,14 @@ jobs:
4137
cache-from: type=gha
4238
cache-to: type=gha,mode=max
4339
- name: Start Docker containers
44-
run: poetry run ./cli.py compose-up --no-build
40+
run: uv run ./cli.py compose-up --no-build
4541
- name: Run linting
4642
# https://github.com/actions/runner/issues/241#issuecomment-745902718
4743
shell: 'script -q -e -c "bash {0}"'
48-
run: poetry run ./cli.py lint
44+
run: uv run ./cli.py lint
4945
- name: Run tests
5046
shell: 'script -q -e -c "bash {0}"'
51-
run: poetry run ./cli.py test --cov
47+
run: uv run ./cli.py test --cov
5248
- name: Stop Docker containers
5349
if: ${{ always() }}
54-
run: poetry run ./cli.py compose-down
50+
run: uv run ./cli.py compose-down

.gitignore

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -82,16 +82,6 @@ target/
8282
profile_default/
8383
ipython_config.py
8484

85-
# pyenv
86-
.python-version
87-
88-
# pipenv
89-
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
90-
# However, in case of collaboration, if having platform-specific dependencies or dependencies
91-
# having no cross-platform support, pipenv may install dependencies that don't work, or not
92-
# install all needed dependencies.
93-
#Pipfile.lock
94-
9585
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
9686
__pypackages__/
9787

.python-version

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
3.13

.vscode/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"cSpell.diagnosticLevel": "Hint",
33
"docker.containers.label": "ContainerName",
44
"editor.formatOnSave": true,
5+
"evenBetterToml.schema.enabled": false,
56
"javascript.validate.enable": true,
67
"js/ts.implicitProjectConfig.checkJs": true,
78
"notebook.formatOnSave.enabled": true,

CONTRIBUTING.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@ It also contains a Django example project to play around with the features.
2323
```terminal
2424
git clone https://github.com/openradx/adit-radis-shared.git
2525
cd adit-radis-shared
26-
poetry install
27-
poetry run ./cli.py compose-up
26+
uv sync
27+
uv run ./cli.py compose-up
2828
```
2929

3030
The development server of the example project will be started on <http://localhost:8000>
3131

3232
If a library dependency is changed, the containers need to be rebuilt (e.g. by running
33-
`poetry run ./cli.py compose-down && poetry run ./cli.py compose-up`).
33+
`uv run ./cli.py compose-down && uv run ./cli.py compose-up`).

Dockerfile

Lines changed: 34 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,92 +1,57 @@
1-
FROM python:3.12-bullseye AS python-base
1+
# Ideas from https://docs.astral.sh/uv/guides/integration/docker/
22

3-
# python
4-
# ENV variables are also available in the later build stages
5-
ENV PYTHONUNBUFFERED=1 \
6-
# prevents python creating .pyc files
7-
PYTHONDONTWRITEBYTECODE=1 \
8-
\
9-
# pip
10-
PIP_NO_CACHE_DIR=off \
11-
PIP_DISABLE_PIP_VERSION_CHECK=on \
12-
PIP_DEFAULT_TIMEOUT=100 \
13-
\
14-
# poetry
15-
# https://python-poetry.org/docs/#installing-with-the-official-installer
16-
# https://python-poetry.org/docs/configuration/#using-environment-variables
17-
POETRY_VERSION=2.0.1 \
18-
# make poetry install to this location
19-
POETRY_HOME="/opt/poetry" \
20-
# make poetry create the virtual environment in the project's root
21-
# it gets named `.venv`
22-
POETRY_VIRTUALENVS_IN_PROJECT=true \
23-
# do not ask any interactive question
24-
POETRY_NO_INTERACTION=1 \
25-
\
26-
# paths
27-
# this is where our requirements + virtual environment will live
28-
PYSETUP_PATH="/opt/pysetup" \
29-
VENV_PATH="/opt/pysetup/.venv" \
30-
# needed for adit-radis-shared to be found
31-
PYTHONPATH="/app"
32-
33-
# prepend poetry and venv to path
34-
ENV PATH="$POETRY_HOME/bin:$VENV_PATH/bin:$PATH"
35-
36-
# deps for db management commands
37-
# make sure to match the postgres version to the service in the compose file
3+
FROM python:3.12-bullseye AS builder-base
4+
5+
# Install dependencies for the `psql` command.
6+
# Must match the version of the postgres service in the compose file!
387
RUN apt-get update \
398
&& apt-get install --no-install-recommends -y postgresql-common \
409
&& /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh -y \
4110
&& apt-get install --no-install-recommends -y \
4211
postgresql-client-17 \
4312
&& rm -rf /var/lib/apt/lists/*
4413

14+
ENV PYTHONUNBUFFERED=1 \
15+
PYTHONDONTWRITEBYTECODE=1
4516

46-
# `builder-base` stage is used to build deps + create our virtual environment
47-
FROM python-base AS builder-base
17+
COPY --from=ghcr.io/astral-sh/uv:0.6.0 /uv /uvx /bin/
4818

49-
RUN apt-get update \
50-
&& apt-get install --no-install-recommends -y \
51-
# deps for installing poetry
52-
curl \
53-
# deps for building python deps
54-
build-essential \
55-
&& rm -rf /var/lib/apt/lists/*
19+
ENV UV_COMPILE_BYTECODE=1 \
20+
UV_LINK_MODE=copy
5621

57-
# install poetry - respects $POETRY_VERSION & $POETRY_HOME
58-
RUN curl -sSL https://install.python-poetry.org | python3 -
22+
# There is no git during image build so we need to provide a fake version
23+
ENV UV_DYNAMIC_VERSIONING_BYPASS=0.0.0
5924

60-
# copy project requirement files here to ensure they will be cached.
61-
WORKDIR $PYSETUP_PATH
62-
COPY poetry.lock pyproject.toml README.md ./
25+
ENV PATH="/app/.venv/bin:$PATH"
6326

64-
# install runtime deps - uses $POETRY_VIRTUALENVS_IN_PROJECT internally
65-
RUN poetry install --without dev --no-root
27+
WORKDIR /app
6628

6729

68-
# `development` image is used during development / testing
69-
FROM python-base AS development
30+
# development image
31+
FROM builder-base AS development
7032

71-
WORKDIR $PYSETUP_PATH
33+
RUN --mount=type=cache,target=/root/.cache/uv \
34+
--mount=type=bind,source=uv.lock,target=uv.lock \
35+
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
36+
uv sync --frozen --no-install-project
7237

73-
# copy in our built poetry + venv
74-
COPY --from=builder-base $POETRY_HOME $POETRY_HOME
75-
COPY --from=builder-base $PYSETUP_PATH $PYSETUP_PATH
38+
RUN playwright install --with-deps chromium
7639

77-
# quicker install as runtime deps are already installed
78-
RUN poetry install --no-root
40+
ADD . /app
7941

80-
# Install requirements for end-to-end testing
81-
RUN playwright install --with-deps chromium
42+
RUN --mount=type=cache,target=/root/.cache/uv \
43+
uv sync --frozen
8244

83-
# will become mountpoint of our code
84-
WORKDIR /app
8545

46+
# production image
47+
FROM builder-base AS production
8648

87-
# `production` image used for runtime
88-
FROM python-base AS production
89-
COPY --from=builder-base $PYSETUP_PATH $PYSETUP_PATH
90-
COPY . /app/
49+
RUN --mount=type=cache,target=/root/.cache/uv \
50+
--mount=type=bind,source=uv.lock,target=uv.lock \
51+
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
52+
uv sync --frozen --no-install-project --no-dev
9153

92-
WORKDIR /app
54+
ADD . /app
55+
56+
RUN --mount=type=cache,target=/root/.cache/uv \
57+
uv sync --frozen --no-dev

adit_radis_shared/cli_commands.py

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -138,35 +138,34 @@ def lint():
138138
"""Lint the source code with ruff, pyright and djlint"""
139139

140140
print("Linting Python code with ruff...")
141-
helpers.execute_cmd("poetry run ruff check .")
141+
helpers.execute_cmd("uv run ruff check .")
142142

143143
print("Linting Python code with pyright...")
144-
helpers.execute_cmd("poetry run pyright")
144+
helpers.execute_cmd("uv run pyright")
145145

146146
print("Linting Django templates with djlint...")
147-
helpers.execute_cmd("poetry run djlint . --lint")
147+
helpers.execute_cmd("uv run djlint . --lint")
148148

149149

150150
def format_code():
151151
"""Format the source code with ruff and djlint"""
152152

153153
print("Formatting Python code with ruff...")
154-
helpers.execute_cmd("poetry run ruff format .")
154+
helpers.execute_cmd("uv run ruff format .")
155155

156156
print("Sorting Python imports with ruff...")
157-
helpers.execute_cmd("poetry run ruff check . --fix --select I")
157+
helpers.execute_cmd("uv run ruff check . --fix --select I")
158158

159159
print("Formatting Django templates with djlint...")
160-
helpers.execute_cmd("poetry run djlint . --reformat")
160+
helpers.execute_cmd("uv run djlint . --reformat")
161161

162162

163163
def test(ctx: typer.Context):
164164
"""Run the test suite with pytest"""
165165

166166
if not helpers.check_compose_up():
167167
sys.exit(
168-
"Acceptance tests need dev containers running.\n"
169-
"Run 'poetry run ./cli.py compose-up' first."
168+
"Acceptance tests need dev containers running.\nRun 'uv run ./cli.py compose-up' first."
170169
)
171170

172171
cmd = (
@@ -181,10 +180,10 @@ def show_outdated():
181180
"""Show outdated dependencies"""
182181

183182
print("### Outdated Python dependencies ###")
184-
helpers.execute_cmd("poetry show --outdated --top-level")
183+
helpers.print_uv_outdated()
185184

186185
print("### Outdated NPM dependencies ###")
187-
helpers.execute_cmd("npm outdated")
186+
helpers.execute_cmd("npm outdated", hidden=True)
188187

189188

190189
def backup_db():
@@ -202,7 +201,7 @@ def backup_db():
202201

203202
web_container_id = helpers.find_running_container_id("web")
204203
if web_container_id is None:
205-
sys.exit("Web container is not running. Run 'poetry run ./cli.py compose-up' first.")
204+
sys.exit("Web container is not running. Run 'uv run ./cli.py compose-up' first.")
206205

207206
helpers.execute_cmd(
208207
(
@@ -222,7 +221,7 @@ def restore_db():
222221
)
223222
web_container_id = helpers.find_running_container_id("web")
224223
if web_container_id is None:
225-
sys.exit("Web container is not running. Run 'poetry run ./manage.py compose_up' first.")
224+
sys.exit("Web container is not running. Run 'uv run ./manage.py compose-up' first.")
226225

227226
helpers.execute_cmd(
228227
(
@@ -324,7 +323,7 @@ def generate_certificate_chain(self):
324323
if not cert_path.is_file():
325324
sys.exit(
326325
f"SSL certificate file {cert_path.absolute()} does not exist. You can generate an"
327-
" unsigned certificate with 'poetry run ./manage.py generate_certificate_files'"
326+
" unsigned certificate with 'uv run ./manage.py generate-certificate_files'"
328327
" with included chain file. If you have a signed certificate from a CA, be sure to"
329328
" provide the correct SSL_SERVER_CERT_FILE setting in '.env'."
330329
)

0 commit comments

Comments
 (0)