Skip to content

on hold: Use copier #62

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

Open
wants to merge 19 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
1 change: 1 addition & 0 deletions .copier/.copier-answers.yml.jinja
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{{ _copier_answers|to_json -}}
1 change: 1 addition & 0 deletions .devcontainer/devcontainer-start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@

set -xeo pipefail

uv lock
uv sync --frozen --no-install-project --all-groups
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "Python Template",
"name": "{{ project_name }}",
"dockerComposeFile": "docker-compose.yaml",
"service": "devcontainer",
"runServices": [
Expand All @@ -10,9 +10,9 @@
"celery_worker",
"otel-collector"
],
"workspaceFolder": "/opt/app/${localEnv:PROJECT_NAME:python-template}",
"workspaceFolder": "/opt/app/${localEnv:PROJECT_NAME:{{ project_name }}}",
"containerEnv": {
"PROJECT": "${localEnv:PROJECT_NAME:python-template}",
"PROJECT": "${localEnv:PROJECT_NAME:{{ project_name }}}",
"USER": "${localEnv:USER}"
},
"features": {
Expand Down Expand Up @@ -59,8 +59,8 @@
],
"unwantedRecommendations": []
},
"postCreateCommand": "/opt/app/${localEnv:PROJECT_NAME:python-template}/.devcontainer/devcontainer-create.sh",
"postStartCommand": "/opt/app/${localEnv:PROJECT_NAME:python-template}/.devcontainer/devcontainer-start.sh",
"postCreateCommand": "/opt/app/${localEnv:PROJECT_NAME:{{ project_name }}}/.devcontainer/devcontainer-create.sh",
"postStartCommand": "/opt/app/${localEnv:PROJECT_NAME:{{ project_name }}}/.devcontainer/devcontainer-start.sh",
"forwardPorts": [
// Backend API:
// localhost:8000 for accessing on your host
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ services:
context: ../
target: devcontainer
args:
PROJECT_NAME: ${PROJECT_NAME:-python-template}
PROJECT_NAME: ${PROJECT_NAME:-{{ project_name }}}
USER: ${USER}
ports:
- '8000:8000'
volumes:
- source: ..
target: /opt/app/${PROJECT_NAME:-python-template}
target: /opt/app/${PROJECT_NAME:-{{ project_name }}}
type: bind
- source: ./commandhistory
target: /home/${USER}/.commandhistory
Expand Down
17 changes: 17 additions & 0 deletions .env.jinja
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
PROJECT_NAME={{project_name}}

ASYNC_DATABASE_URL=postgresql+asyncpg://dev:dev@postgres:5432/dev
DATABASE_POOL_PRE_PING=True
DATABASE_POOL_SIZE=5
DATABASE_POOL_RECYCLE=3600
DATABASE_MAX_OVERFLOW=10
SERVER_URL=example.com
ACCESS_TOKEN_EXPIRE_MINUTES=15
JWT_SIGNING_KEY=

# OpenTelemetry configuration
OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317

# Celery settings
CELERY_BROKER_URL=amqp://guest:guest@rabbitmq:5672
CELERY_RESULT_BACKEND=redis://redis:6379/0
31 changes: 27 additions & 4 deletions .github/workflows/python-app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,24 @@ jobs:
with:
python-version: 3.13

- name: Install Copier
run: pip install copier

- name: Generate project from template
run: copier copy . generated --defaults --trust

- name: Install dependencies
working-directory: generated
run: |
pip install uv
uv sync --frozen --no-cache --no-install-project --all-groups
uv sync --no-cache --no-install-project --all-groups

- name: Install pre-commit
working-directory: generated
run: pip install pre-commit

- name: Run linters and formatters
working-directory: generated
run: pre-commit run --all-files

tests:
Expand Down Expand Up @@ -73,12 +83,20 @@ jobs:
with:
python-version: 3.13

- name: Install Copier
run: pip install copier

- name: Generate project from template
run: copier copy . generated --defaults --trust

- name: Install dependencies
working-directory: generated
run: |
pip install uv
uv sync --frozen --no-cache --no-install-project --group dev --no-group types
uv sync --no-cache --no-install-project --group dev --no-group types

- name: Run tests with coverage
working-directory: generated
run: |
uv run coverage run -m pytest
uv run coverage report -m --fail-under=80
Expand All @@ -87,11 +105,16 @@ jobs:
name: Build Docker Image
runs-on: ubuntu-latest
needs: tests

steps:
- name: Checkout code
uses: actions/checkout@v3

- name: Install Copier
run: pip install copier

- name: Generate project from template
run: copier copy . generated --defaults --trust

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

Expand All @@ -106,7 +129,7 @@ jobs:
- name: Build image with cache
uses: docker/build-push-action@v5
with:
context: .
context: ./generated
push: false
tags: python-template:latest
cache-from: type=local,src=/tmp/.buildx-cache
Expand Down
8 changes: 5 additions & 3 deletions Dockerfile → Dockerfile.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# Base image install all the tools needed to build the project
FROM python:3.13-slim-bookworm AS base

ARG PROJECT_NAME=python-template
ARG PROJECT_NAME={{ project_name }}
ARG USER=appuser

ENV RUNTIME_PACKAGES=libpq-dev
Expand Down Expand Up @@ -34,6 +34,7 @@ RUN pip install --upgrade pip \
WORKDIR /opt/app/${PROJECT_NAME}
COPY --chown=${USER}:${USER} . .

RUN uv lock
RUN uv sync --frozen --no-cache --no-install-project --no-default-groups


Expand Down Expand Up @@ -89,9 +90,10 @@ RUN apt-get purge -y ${BUILD_PACKAGES} \
USER ${USER}

# TODO(remer): wheel version has to match what is set in pyproject.toml
COPY --from=builder /opt/app/${PROJECT_NAME}/dist/python_template-0.1.0-py3-none-any.whl /opt/app/${PROJECT_NAME}/dist/python_template-0.1.0-py3-none-any.whl
# Note: Python wheel names convert hyphens to underscores
COPY --from=builder /opt/app/${PROJECT_NAME}/dist/*.whl /opt/app/${PROJECT_NAME}/dist/

RUN uv run pip install --no-deps dist/python_template-0.1.0-py3-none-any.whl
RUN uv run pip install --no-deps dist/*.whl

EXPOSE 8000

Expand Down
22 changes: 10 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,16 @@
- Rest API built with FastAPI and SQLAlchemy
- PostgreSQL database

## Clone the project using Copier

Decide a name for your new project's directory, you will use it below. For example, `my-awesome-project`.

Go to the directory that will be the parent of your project, and run the command with your project's name:

`copier copy --vcs-ref main [email protected]:xmartlabs/python-template.git my-awesome-project --trust`

Note the `--trust` option is necessary to be able to execute a post-creation script that updates your `.env` files.

## Project setup

The only things you need are [Docker](https://docs.docker.com/engine/install/), [Docker Compose](https://docs.docker.com/compose/install/), and a code editor with devcontainer support like [Visual Studio Code](https://code.visualstudio.com/download). Once you open the template with VS Code, it will recommend that you install the [Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) if you don’t have it already. Then, a pop-up will appear to reopen the template in the devcontainer, or you can use `Ctrl / Cmd + shift + P` -> `Dev Containers: Open Folder in Container…`. Remember to add the `.env` file at the root folder; you can use `.env.example` as a reference.
Expand All @@ -28,18 +38,6 @@ Alternatively, you must have:

For making code changes, installing `pre-commit` is necessary (see section [Code tools: pre-commit](#pre-commit))

### Customization

The project's name (`python-template`) can be edited following next steps:

1. Edit project's name in the [pyproject.toml](pyproject.toml) file
2. Set `PROJECT_NAME` env variable to be exactly the same as project's name in pyproject.toml. Ensure VSCode has this
variable loaded, otherwise the dev container might fail or not work as expected. You can open VScode with from cmd with:

```bash
PROJECT_NAME=your-awesome-project code <path/to/repo>
```

## Migrations

We use Alembic as database migration tool. You can run migration commands directly inside the dev container or use the provided shortcut in the `exec.sh` script.
Expand Down
22 changes: 22 additions & 0 deletions copier.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
project_name:
type: str
help: The name of the project
default: python-template

project_description:
type: str
help: The description of the project
default: Xmartlabs' Python project template

_exclude:
# Python
- __pycache__
- .mypy_cache
- .cache
- .venv
- uv.lock

_answers_file: .copier/.copier-answers.yml

_tasks:
- ["{{ _copier_python }}"]
6 changes: 3 additions & 3 deletions pyproject.toml → pyproject.toml.jinja
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
[project]
# Project's name must be the same as PROJECT_NAME environment variable used elsewhere.
name = "python-template"
version = "0.1.0"
description = "Xmartlabs' Python project template"
name = "{{ project_name }}"
version = "0.0.1"
description = "{{ project_description }}"
authors = [{ name = "Xmartlabs", email = "[email protected]" }]
requires-python = ">=3.13.0,<4.0.0"
readme = "README.md"
Expand Down