Skip to content
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

Introduce uv for Python dependencies management #148

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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
2 changes: 2 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Exclude the project virtual environment from image builds
.venv
38 changes: 21 additions & 17 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,24 +1,28 @@
# Pull base image
FROM python:3.12.2-slim-bookworm
# First, build the application in the `/app` directory.
FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim AS builder
ENV UV_COMPILE_BYTECODE=1
ENV UV_LINK_MODE=copy
WORKDIR /app
RUN --mount=type=cache,target=/root/.cache/uv \
--mount=type=bind,source=uv.lock,target=uv.lock \
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
uv sync --frozen --no-install-project --no-dev
ADD . /app
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --frozen --no-dev

# Set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

# Create and set work directory called `app`
RUN mkdir -p /code
WORKDIR /code
# Then, use a final image without uv
FROM python:3.12-slim-bookworm
Comment on lines +14 to +15

Choose a reason for hiding this comment

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

Any reason to not include uv in our final image? It seems useful.

Copy link
Author

Choose a reason for hiding this comment

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

Two reasons yes:

  1. I think it's a best practice in most cases to avoid getting build tools in production. Your production code doesn't need it:
  • Dependencies have already been resolved and installed (that's the build step)
  • There is no multiple-Python or multiple-venv shenanigans within the container
  1. The official guide for using uv with Docker provided a ready-to-go multistage Dockerfile, so it seems not only they agree with 1., but also they make it trivial to implement.

Some figures:

  • python:3.12-slim-bookworm is 124MB
  • ghcr.io/astral-sh/uv:python3.12-bookworm-slim is 157MB

@jefftriplett do you think there are use cases for having uv in the container?

Copy link

@jefftriplett jefftriplett Dec 4, 2024

Choose a reason for hiding this comment

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

It's all trade-offs, and I think that's fine.

It might be something to re-think (maybe add a production layer) once we merge requirements.in into pyproject.toml. That makes having dev requirements easier. (after this PR merges)

I kind of view these projects as more dx/dev-friendly so being inside compose should expose uv so we can run uv lock or uv add {package} but I'm honestly still new to the Lithium.

All good and thank you for the explanation.


# Install dependencies
COPY requirements.txt /tmp/requirements.txt
# Copy the application from the builder
COPY --from=builder --chown=app:app /app /app

RUN set -ex && \
pip install --upgrade pip && \
pip install -r /tmp/requirements.txt && \
rm -rf /root/.cache/
WORKDIR /app

# Copy local project
COPY . /code/
# Set environment variables
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
ENV PATH="/app/.venv/bin:$PATH"

# Expose port 8000
EXPOSE 8000
Expand Down
28 changes: 9 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ https://github.com/wsvincent/djangox/assets/766418/a73ea730-a7b4-4e53-bf51-aa68f
## 🚀 Features

- Django 5.1 & Python 3.12
- Installation via [Pip](https://pypi.org/project/pip/) or [Docker](https://www.docker.com/)
- Installation via [uv](https://docs.astral.sh/uv/) or [Docker](https://www.docker.com/)
- User authentication--log in, sign up, password reset--via [django-allauth](https://github.com/pennersr/django-allauth)
- Static files configured with [Whitenoise](http://whitenoise.evans.io/en/stable/index.html)
- Styling with [Bootstrap v5](https://getbootstrap.com/)
Expand All @@ -21,7 +21,7 @@ https://github.com/wsvincent/djangox/assets/766418/a73ea730-a7b4-4e53-bf51-aa68f

## Table of Contents
* **[Installation](#installation)**
* [Pip](#pip)
* [Uv](#uv)
* [Docker](#docker)
* [Next Steps](#next-steps)
* [Contributing](#contributing)
Expand All @@ -36,29 +36,19 @@ $ git clone https://github.com/wsvincent/lithium.git
$ cd lithium
```

### Pip
You can use [pip](https://pypi.org/project/pip/) to create a fresh virtual environment on either Windows or macOS.
### Uv
You can use [uv](https://docs.astral.sh/uv/) to create a dedicated virtual environment.

```
# On Windows
$ python -m venv .venv
$ Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
$ .venv\Scripts\Activate.ps1
(.venv) $

# On macOS
$ python -m venv .venv
$ source .venv/bin/activate
(.venv) $
$ uv sync
```

Then install all packages hosted in `requirements.txt` and run `migrate` to configure the initial database. The command `createsuperuser` will create a new superuser account for accessing the admin. Execute the `runserver` commandt o start up the local server.
Then run `migrate` to configure the initial database. The command `createsuperuser` will create a new superuser account for accessing the admin. Execute the `runserver` commandt o start up the local server.

```
(.venv) $ pip install -r requirements.txt
(.venv) $ python manage.py migrate
(.venv) $ python manage.py createsuperuser
(.venv) $ python manage.py runserver
$ uv run manage.py migrate
$ uv run manage.py createsuperuser
$ uv run manage.py runserver
# Load the site at http://127.0.0.1:8000 or http://127.0.0.1:8000/admin for the admin
```

Expand Down
18 changes: 18 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[project]
name = "lithium"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = [
"django ~=5.1",
"django-allauth[openid,socialaccount] ~=65.2",
"django-debug-toolbar ~=4.4",
"crispy-bootstrap5 ~=2024.10",
"gunicorn ~=23.0",
"psycopg[binary] ~=3.2",
"whitenoise ~=6.7",
]

[dependency-groups]
dev = [
"typing_extensions ~=4.12",
]
26 changes: 0 additions & 26 deletions requirements.txt

This file was deleted.

Loading