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
10 changes: 9 additions & 1 deletion .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,19 @@ FROM mcr.microsoft.com/devcontainers/python:1-${VARIANT}
# They are installed by the base image (python) which does not have the patch.
RUN python3 -m pip install --upgrade setuptools

# Install poetry
RUN pip install --upgrade pip

# Install poetry
ENV PATH "/etc/poetry/bin:$PATH"
RUN curl -sSLk https://install.python-poetry.org | POETRY_HOME=/etc/poetry python - \
&& poetry completions bash >> ~/.bash_completion \
&& poetry config virtualenvs.create false \
&& poetry self add "poetry-dynamic-versioning[plugin]"

# Install uv
ENV PATH="/root/.local/bin/:$PATH"
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/

# RUN curl -sSLkf https://astral.sh/uv/install.sh | sh
RUN echo 'eval "$(uv generate-shell-completion bash)"' >> ~/.bashrc \
&& echo 'eval "$(uvx --generate-shell-completion bash)"' >> ~/.bashrc
35 changes: 35 additions & 0 deletions .github/assets/.copier-answers-poetry.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Changes here will be overwritten by Copier; NEVER EDIT MANUALLY
_src_path: ./
author_email: 45483159+twsl@users.noreply.github.com
author_username: twsl
copier_auto_update: true
copyright_holder: twsl
copyright_holder_email: 45483159+twsl@users.noreply.github.com
copyright_license: MIT
copyright_year: 2025
custom_install: true
github_runner:
- ubuntu-latest
github_runner_clean: false
github_runner_python_version:
- "3.12"
include_databricks: false
include_docs: true
include_notebooks: true
include_sample_code: false
line_ending: lf
package_manager: poetry
precommit_tool: pre-commit
primary_branch: main
project_description: "The python description"
project_name: example-project
python_package_command_line_name: example-project
python_package_distribution_name: example-project
python_package_import_name: example_project
python_version: "3.12"
repository_name: example-project
repository_namespace: twsl
repository_provider: test.ghe.com
self_signed: false
type_checker: pyright
use_precommit: true
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,34 @@
_src_path: ./
author_email: 45483159+twsl@users.noreply.github.com
author_username: twsl
copier_auto_update: true
copyright_holder: twsl
copyright_holder_email: 45483159+twsl@users.noreply.github.com
copyright_license: MIT
copyright_year: 2025
custom_install: true
github_runner:
- ubuntu-latest
github_runner_clean: false
github_runner_python_version:
- "3.11"
- "3.12"
include_databricks: false
include_docs: true
include_notebooks: true
include_sample_code: false
line_ending: lf
package_manager: uv
precommit_tool: prek
primary_branch: main
project_description: "The python description"
project_name: example-project
python_package_command_line_name: example-project
python_package_distribution_name: example-project
python_package_import_name: example_project
python_version: "3.11"
python_version: "3.12"
repository_name: example-project
repository_namespace: twsl
repository_provider: test.ghe.com
self_signed: false
type_checker: ty
use_precommit: true
precommit_tool: prek
copier_auto_update: true
github_runner_clean: false
5 changes: 3 additions & 2 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ jobs:
fail-fast: true
matrix:
os: [ubuntu-latest, windows-latest]
answers_variant: ["uv", "poetry"]
defaults:
run:
shell: bash
Expand Down Expand Up @@ -50,12 +51,12 @@ jobs:
run: poetry install --no-interaction

- name: Test
run: poetry run copier copy ./ ./dist --data-file "./.github/assets/.copier-answers.yml" -f --vcs-ref=HEAD
run: poetry run copier copy ./ ./dist --data-file "./.github/assets/.copier-answers-${{ matrix.answers_variant }}.yml" -f --vcs-ref=HEAD

- name: Upload artifacts
uses: actions/upload-artifact@v6
with:
name: copier-results-${{ runner.os }}
name: copier-results-${{ runner.os }}-${{ matrix.answers_variant }}
path: ./dist/**/*
include-hidden-files: true
if: ${{ always() }}
14 changes: 7 additions & 7 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ repos:
- id: pre-commit-update

- repo: https://github.com/python-poetry/poetry
rev: 2.2.1
rev: 2.3.1
hooks:
- id: poetry-check
- id: poetry-lock
Expand All @@ -40,12 +40,12 @@ repos:
- id: detect-private-key

- repo: https://gitlab.com/bmares/check-json5
rev: v1.0.0
rev: v1.0.1
hooks:
- id: check-json5

# - repo: https://github.com/aristanetworks/j2lint.git
# rev: v1.1.0
# hooks:
# - id: j2lint
# args: [--ignore, S7, --, --warn, V2, --]
# - repo: https://github.com/aristanetworks/j2lint.git
# rev: v1.1.0
# hooks:
# - id: j2lint
# args: [--ignore, S7, --, --warn, V2, --]
52 changes: 31 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,35 +1,43 @@
# Python Project Template

[![Copier](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/copier-org/copier/master/img/badge/badge-grayscale-border.json)](https://github.com/copier-org/copier)
[![Poetry](https://img.shields.io/endpoint?url=https://python-poetry.org/badge/v0.json)](https://python-poetry.org/)
[![Docs with MkDocs](https://img.shields.io/badge/MkDocs-docs?style=flat&logo=materialformkdocs&logoColor=white&color=%23526CFE)](https://squidfunk.github.io/mkdocs-material/)
[![linting: ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit)](.pre-commit-config.yaml)
[![Checked with pyright](https://microsoft.github.io/pyright/img/pyright_badge.svg)](https://microsoft.github.io/pyright/)
[![security: bandit](https://img.shields.io/badge/security-bandit-yellow.svg)](https://github.com/PyCQA/bandit)
[![Semantic Versions](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--versions-e10079.svg)](https://github.com/twsl/python-project-template/releases)
[![License](https://img.shields.io/badge/license-MIT-blue)](LICENSE)

A generic python project template based on [`copier`](https://copier.readthedocs.io/en/stable/) for my data science focused projects.

- Package Manager: [![uv](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json)](https://github.com/astral-sh/uv) or [![Poetry](https://img.shields.io/endpoint?url=https://python-poetry.org/badge/v0.json)](https://python-poetry.org/)
- pre-commit: [![prek](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/j178/prek/master/docs/assets/badge-v0.json)](https://github.com/j178/prek) or [![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit)](https://github.com/pre-commit/pre-commit)
- Type checker: [![ty](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ty/main/assets/badge/v0.json)](https://github.com/astral-sh/ty) or [![Checked with pyright](https://microsoft.github.io/pyright/img/pyright_badge.svg)](https://microsoft.github.io/pyright/)

## TL;DR

```bash
copier copy --trust --vcs-ref=HEAD git+https://github.com/twsl/python-project-template path/to/destination
pip install copier
```

```bash
copier copy --trust --vcs-ref=HEAD git+https://github.com/twsl/python-project-template /path/to/destination
```

## Features

### Development features

- Supports `Python 3.10` and [higher](https://devguide.python.org/versions/).
- [`Poetry`](https://python-poetry.org/) as a dependencies manager. See configuration in `pyproject.toml`.
- [`uv`](https://github.com/astral-sh/uv) or [`Poetry`](https://python-poetry.org/) as a dependencies manager. See configuration in `pyproject.toml`.
- Automatic codestyle with [`ruff`](https://github.com/astral-sh/ruff).
- Ready-to-use [`pre-commit`](https://pre-commit.com/) hooks with code-formatting.
- Type checks with [`pyright`](https://github.com/microsoft/pyright).
- Ready-to-use [`pre-commit`](https://pre-commit.com/) hooks with code-formatting. Execute with [`prek`](https://github.com/j178/prek) or [`pre-commit`](https://github.com/pre-commit/pre-commit)
- Type checks with [`ty`](https://github.com/astral-sh/ty) or [`pyright`](https://github.com/microsoft/pyright).
- Security checks with [`bandit`](https://github.com/PyCQA/bandit).
- Testing with [`pytest`](https://docs.pytest.org/en/latest/).
- Ready-to-use `.editorconfig` and `.gitignore`.
- Ready-to-use [`Devcontainer`](https://containers.dev/).
- Find dead code with [`vulture`](https://github.com/jendrikseipp/vulture).
- Avoid credential leaks with [`gitleaks`](https://github.com/gitleaks/gitleaks).

### Deployment features

Expand Down Expand Up @@ -76,7 +84,11 @@ The devcontainer is already set up for you, just open the project in VSCode and
To test the project you can run:

```bash
copier copy ./ ./dist --data-file "./.github/assets/.copier-answers.yml" -f --vcs-ref=HEAD
copier copy ./ ./dist --data-file "./.github/assets/.copier-answers-uv.yml" -f --vcs-ref=HEAD
```

```bash
copier copy ./ ./dist --data-file "./.github/assets/.copier-answers-poetry.yml" -f --vcs-ref=HEAD
```

### Variables
Expand All @@ -88,6 +100,9 @@ The template uses the following variables to customize the project:
| `custom_install` | `customized` |
| `project_name` | `example_project` |
| `project_description` | `` |
| `repository_provider` | `github.com` |
| `ghec` | `false` |
| `ghes` | `false` |
| `primary_branch` | `main` |
| `author_username` | `` |
| `author_email` | `{{ author_username }}@users.noreply.github.com` |
Expand All @@ -96,32 +111,27 @@ The template uses the following variables to customize the project:
| `repository_name` | `{{ project_name }}` |
| `copyright_holder` | `{{ author_username }}` |
| `copyright_holder_email` | `{{ author_email }}` |
| `copyright_year` | `2025` |
| `copyright_year` | `2026` |
| `copyright_license` | `MIT` |
| `python_version` | `3.11` |
| `python_version` | `3.12` |
| `python_package_distribution_name` | `{{ project_name }}` |
| `python_package_import_name` | `{{ project_name }}` |
| `python_package_command_line_name` | `{{ project_name }}` |
| `line_ending` | `lf` |
| `package_manager` | `uv` |
| `type_checker` | `ty` |
| `use_precommit` | `true` |
| `precommit_tool` | `prek` |
| `include_docs` | `true` |
| `include_notebooks` | `true` |
| `include_databricks` | `true` |
| `github_runner_python_version` | `3.11` |
| `include_databricks` | `false` |
| `github_runner_python_version` | `[3.12]` |
| `github_runner` | `ubuntu-latest` |
| `github_runner_ghec` | `ubuntu-2core-amd64` |
| `github_runner_clean` | `true` |
| `github_rate_limit` | `false` |
| `include_sample_code` | `false` |
| `self_signed` | `false` |
| `copier_auto_update` | `false` |

All input values will be saved in the `.copier-answers.yml`

## Credits

I just combined multiple templates to create this one, therefore all credits belong to the following projects:

- [poetry-copier](https://github.com/lukin0110/poetry-copier)
- [python-project-template](https://github.com/lincc-frameworks/python-project-template)
- [copier-poetry](https://github.com/pawamoy/copier-poetry)
- [python-package-template](https://github.com/TezRomacH/python-package-template)
24 changes: 21 additions & 3 deletions copier.yml
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ copyright_holder_email:
copyright_year:
type: int
help: The copyright year?
default: 2025
default: 2026
when: "{{ custom_install }}"

copyright_license:
Expand All @@ -129,8 +129,8 @@ copyright_license:
# https://devguide.python.org/versions/
python_version:
type: str
help: What version of python are you targeting?
default: "3.11"
help: What version of python are you targeting? See https://devguide.python.org/versions/
default: "3.12"
choices:
- "3.10"
- "3.11"
Expand Down Expand Up @@ -164,6 +164,24 @@ line_ending:
LF: lf
CLRF: crlf

package_manager:
type: str
help: Which Python package and project manager do you want to use?
default: uv
choices:
uv: uv
poetry: poetry
when: "{{ custom_install }}"

type_checker:
type: str
help: Which Python type checker do you want to use?
default: ty
choices:
pyright: pyright
ty: ty
when: "{{ custom_install }}"

use_precommit:
type: bool
default: yes
Expand Down
15 changes: 12 additions & 3 deletions project/.devcontainer/Dockerfile.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,21 @@ FROM mcr.microsoft.com/devcontainers/python:1-${VARIANT}
# They are installed by the base image (python) which does not have the patch.
RUN python3 -m pip install --upgrade setuptools

# Install poetry
RUN pip install --upgrade pip
RUN pip install --upgrade pip{% if package_manager == 'poetry' %}

# Install poetry
ENV PATH="/etc/poetry/bin:$PATH"
RUN curl -sSL {% if self_signed %}-k{% endif %} https://install.python-poetry.org | POETRY_HOME=/etc/poetry python - \
&& poetry completions bash >> ~/.bash_completion \
&& poetry config virtualenvs.create false \
&& poetry self add "poetry-dynamic-versioning[plugin]"
&& poetry self add "poetry-dynamic-versioning[plugin]"{% elif package_manager == 'uv'%}

# Install uv
ENV PATH="/root/.local/bin/:$PATH"
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/

# RUN curl -LsSf https://astral.sh/uv/install.sh | sh
RUN echo 'eval "$(uv generate-shell-completion bash)"' >> ~/.bashrc \
&& echo 'eval "$(uvx --generate-shell-completion bash)"' >> ~/.bashrc{% endif %}

{% if self_signed %}RUN echo "--insecure" > ~/.curlrc{% endif %}
Loading