Skip to content
Merged
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
6 changes: 5 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
.env
__pycache__
__pycache__
.venv
.data
.pytest_cache
.ruff_cache
25 changes: 0 additions & 25 deletions .github/workflows/ci.yml

This file was deleted.

21 changes: 9 additions & 12 deletions .github/workflows/code-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,42 +16,39 @@ jobs:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python
uses: actions/[email protected]
with:
python-version: 3.x
- name: Install uv
uses: astral-sh/setup-uv@v5

- name: Display Python version
run: |
python --version
uv run python --version

- name: Install dependencies
run: |
pip install poetry
poetry install --no-root --with dev
uv sync --frozen

- name: Check for outdated dependencies
if: env.skip-job != 'true'
run: |
poetry show --outdated --only main
uv tree --outdated

- name: Run tests with coverage in latest stable 3.x
run: |
poetry run pytest --cov=app --cov-report=term-missing
uv run pytest --cov=app --cov-report=term-missing
continue-on-error: false

- name: Run Bandit for security analysis
run: |
poetry run bandit -r app
uv run bandit -r app
continue-on-error: false

- name: Run Ruff for linting
run: |
poetry run ruff check .
uv run ruff check .
continue-on-error: false

- name: Run Vulture for dead code analysis
run: |
poetry run vulture . --min-confidence 70
uv run vulture . --min-confidence 70 --exclude .venv
continue-on-error: false

67 changes: 0 additions & 67 deletions .github/workflows/compatability-matrix.yml

This file was deleted.

43 changes: 0 additions & 43 deletions .github/workflows/docker-matrix.yml

This file was deleted.

22 changes: 4 additions & 18 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -82,24 +82,7 @@ target/
profile_default/
ipython_config.py

# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version

# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock

# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock


# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
Expand All @@ -120,6 +103,9 @@ ENV/
env.bak/
venv.bak/

# Local Docker volume data
.data/

# Spyder project settings
.spyderproject
.spyproject
Expand Down
1 change: 0 additions & 1 deletion .python-version

This file was deleted.

112 changes: 50 additions & 62 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,76 +1,64 @@
ARG IMAGE_TAG=3.13-slim-bullseye

FROM python:${IMAGE_TAG} AS base
# Allowing the argumenets to be read into the dockerfile. Ex: .env > compose.yml > Dockerfile
ARG UID=1000
ARG GID=1000
#
# Python dependencies stage
#
FROM python:${IMAGE_TAG} AS deps

# Create the user and usergroup
RUN groupadd -g ${GID} -o app
RUN useradd -m -d /app -u ${UID} -g ${GID} -o -s /bin/bash app
# Copy uv binary for dependency management
COPY --from=ghcr.io/astral-sh/uv:0.8.4 /uv /usr/local/bin/uv

# Set the working directory to /app
WORKDIR /app

# Both build and development need poetry, so it is its own step.
FROM base AS poetry
RUN pip install poetry

# Use this page as a reference for python and poetry environment variables:
# https://docs.python.org/3/using/cmdline.html#envvar-PYTHONUNBUFFERED Ensure
# the stdout and stderr streams are sent straight to terminal, then you can see
# the output of your application
ENV PYTHONUNBUFFERED=1\
# Avoid the generation of .pyc files during package install
# Disable pip's cache, then reduce the size of the image
PIP_NO_CACHE_DIR=off \
# Save runtime because it is not look for updating pip version
PIP_DISABLE_PIP_VERSION_CHECK=on \
PIP_DEFAULT_TIMEOUT=100 \
# Disable poetry interaction
POETRY_NO_INTERACTION=1 \
POETRY_VIRTUALENVS_CREATE=1 \
POETRY_VIRTUALENVS_IN_PROJECT=1 \
POETRY_CACHE_DIR=/tmp/poetry_cache

FROM poetry AS build
COPY pyproject.toml poetry.lock ./
RUN poetry install --no-root --without dev && rm -rf ${POETRY_CACHE_DIR};

# FROM poetry AS build-minor-update
# # Install minor version updates in the absence of poetry.lock file
# COPY pyproject.toml poetry.lock ./
# RUN poetry install --no-root --without dev && rm -rf ${POETRY_CACHE_DIR};

FROM build AS test
# Install dev dependencies
RUN poetry install --only dev --no-root && rm -rf ${POETRY_CACHE_DIR};
COPY . .
# Run tests
USER app
RUN poetry run pytest tests
ENV PYTHONUNBUFFERED=1 \
# Compile Python bytecode for faster startup
UV_COMPILE_BYTECODE=1 \
# Use copy mode (required in Docker; hardlinks don't work across layers)
UV_LINK_MODE=copy

# Install production dependencies
COPY pyproject.toml uv.lock ./
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --frozen --no-install-project --no-dev

#
# Test stage
#
FROM deps AS test

FROM build AS test-minor-update
# Install dev dependencies
RUN poetry install --only dev --no-root && rm -rf ${POETRY_CACHE_DIR};
RUN poetry update
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --frozen --no-install-project

COPY . .
# Run tests
USER app
RUN poetry run pytest tests

CMD ["uv", "run", "pytest", "tests"]

FROM base AS production
RUN mkdir -p /venv && chown ${UID}:${GID} /venv
#
# Production stage
#
FROM python:${IMAGE_TAG} AS production

# By adding /venv/bin to the PATH, the dependencies in the virtual environment
# are used
ENV VIRTUAL_ENV=/venv \
PATH="/venv/bin:$PATH"
# Copy uv binary for runtime
COPY --from=ghcr.io/astral-sh/uv:0.8.4 /uv /usr/local/bin/uv

COPY --chown=${UID}:${GID} . /app
COPY --chown=${UID}:${GID} --from=build "/app/.venv" ${VIRTUAL_ENV}
COPY . .
# Create an unprivileged user and group to run the application
RUN groupadd --gid 1001 app && \
useradd --uid 1001 --gid app --no-create-home app

WORKDIR /app

ENV PYTHONUNBUFFERED=1 \
# Deps are pre-installed in the venv; no cache needed at runtime
UV_NO_CACHE=1

# Copy the virtualenv from the deps stage with correct ownership
COPY --from=deps --chown=app:app /app/.venv /app/.venv

# Copy application source with correct ownership
COPY --chown=app:app . .

# Switch to the unprivileged user before starting the process
USER app

# Switch to the app user
USER app
CMD ["uv", "run", "python", "-m", "gunicorn", "-c", "gunicorn_config.py"]
Loading
Loading