diff --git a/Makefile b/Makefile index e5db101..3b28b26 100644 --- a/Makefile +++ b/Makefile @@ -19,6 +19,11 @@ up: down: docker compose down +.PHONY: update_deps +update_deps: + docker compose build --no-cache python + docker compose up -d --force-recreate --build + .PHONY: logs logs: docker compose logs -f diff --git a/docker/python/Dockerfile b/docker/python/Dockerfile index 235ac62..011b1f3 100644 --- a/docker/python/Dockerfile +++ b/docker/python/Dockerfile @@ -1,5 +1,5 @@ # Copied from https://github.com/astral-sh/rye/discussions/239#discussioncomment-6033855 and modified -FROM python:3.12.3 AS rye +FROM python:3.12.3 AS base # Prevents Python from writing pyc files. ENV PYTHONDONTWRITEBYTECODE=1 @@ -34,24 +34,34 @@ COPY pyproject.toml pyproject.toml COPY requirements.lock requirements.lock COPY .python-version .python-version COPY README.md README.md -RUN rye sync --no-dev --no-lock + +# Use a cache mount for the rye cache to improve build performance. +RUN --mount=type=cache,target=/root/.cache/rye rye sync --no-dev --no-lock RUN . .venv/bin/activate # Stage for development. # The development environment assumes a devcontainer and the environment is # closed inside the container, so you don't need to be aware of the virtual environment -FROM rye AS dev +FROM base AS dev +# Re-copy only if necessary to optimize caching COPY pyproject.toml pyproject.toml COPY requirements.lock requirements.lock COPY requirements-dev.lock requirements-dev.lock -COPY .python-version .python-version -COPY README.md README.md -RUN rye sync --no-lock + +# Check if dependencies have changed to decide whether to re-run rye sync +RUN \ + if cmp -s requirements.lock requirements.lock.new; then \ + echo "Dependencies have not changed, using cache."; \ + else \ + echo "Dependencies have changed, running rye sync."; \ + cp requirements.lock requirements.lock.new; \ + rye sync --no-lock; \ + fi # Stage for production -FROM rye AS run +FROM base AS run # Create a non-privileged user that the app will run under. # See https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#user diff --git a/pyproject.toml b/pyproject.toml index 97ae801..c1be871 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,6 +7,11 @@ authors = [ ] dependencies = [ "python-dotenv>=1.0.1", + "injector>=0.21.0", + "pydantic>=2.7.4", + "pydantic-config>=0.3.0", + "sqlalchemy>=2.0.31", + "alembic>=1.13.1", ] readme = "README.md" requires-python = ">= 3.12" diff --git a/requirements-dev.lock b/requirements-dev.lock index cff44c0..46b75d1 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -9,6 +9,10 @@ # generate-hashes: false -e file:. +alembic==1.13.1 + # via imperial-police-2 +annotated-types==0.7.0 + # via pydantic black==24.4.2 click==8.1.7 # via black @@ -17,6 +21,12 @@ coverage==7.5.3 flake8==7.0.0 iniconfig==2.0.0 # via pytest +injector==0.21.0 + # via imperial-police-2 +mako==1.3.5 + # via alembic +markupsafe==2.1.5 + # via mako mccabe==0.7.0 # via flake8 mypy==1.10.0 @@ -34,6 +44,15 @@ pluggy==1.5.0 # via pytest pycodestyle==2.11.1 # via flake8 +pydantic==2.7.4 + # via imperial-police-2 + # via pydantic-settings +pydantic-config==0.3.0 + # via imperial-police-2 +pydantic-core==2.18.4 + # via pydantic +pydantic-settings==2.3.4 + # via pydantic-config pyflakes==3.2.0 # via flake8 pytest==8.2.2 @@ -41,5 +60,13 @@ pytest==8.2.2 pytest-cov==5.0.0 python-dotenv==1.0.1 # via imperial-police-2 + # via pydantic-settings +sqlalchemy==2.0.31 + # via alembic + # via imperial-police-2 typing-extensions==4.12.2 + # via alembic # via mypy + # via pydantic + # via pydantic-core + # via sqlalchemy diff --git a/requirements.lock b/requirements.lock index cf22430..0037924 100644 --- a/requirements.lock +++ b/requirements.lock @@ -9,5 +9,33 @@ # generate-hashes: false -e file:. +alembic==1.13.1 + # via imperial-police-2 +annotated-types==0.7.0 + # via pydantic +injector==0.21.0 + # via imperial-police-2 +mako==1.3.5 + # via alembic +markupsafe==2.1.5 + # via mako +pydantic==2.7.4 + # via imperial-police-2 + # via pydantic-settings +pydantic-config==0.3.0 + # via imperial-police-2 +pydantic-core==2.18.4 + # via pydantic +pydantic-settings==2.3.4 + # via pydantic-config python-dotenv==1.0.1 # via imperial-police-2 + # via pydantic-settings +sqlalchemy==2.0.31 + # via alembic + # via imperial-police-2 +typing-extensions==4.12.2 + # via alembic + # via pydantic + # via pydantic-core + # via sqlalchemy diff --git a/src/imperial_police_2/config.py b/src/imperial_police_2/config.py new file mode 100644 index 0000000..723e462 --- /dev/null +++ b/src/imperial_police_2/config.py @@ -0,0 +1,17 @@ +from pydantic import Field + +from pydantic_config import SettingsModel, SettingsConfig + +ENV_PREFIX = "IMPERIAL_POLICE_2_" + + +class ImperialPoliceSettings(SettingsModel): + model_config = SettingsConfig( + env_prefix=ENV_PREFIX, + ) + + # Postgres settings + POSTGRES_HOST: str = Field() + POSTGRES_PORT: int = Field() + POSTGRES_USER: str = Field() + POSTGRES_PASSWORD: str = Field() diff --git a/src/imperial_police_2/injector/container.py b/src/imperial_police_2/injector/container.py new file mode 100644 index 0000000..92082b0 --- /dev/null +++ b/src/imperial_police_2/injector/container.py @@ -0,0 +1,3 @@ +from injector import Injector + +container: Injector = Injector()