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
27 changes: 27 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Tests
on:
pull_request:
branches:
- '*'
permissions:
contents: read
id-token: write
concurrency:
cancel-in-progress: true
group: ${{ github.workflow }}-${{ github.ref }}
jobs:
cookiecutter:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v5
with:
enable-cache: true
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version-file: .python-version
- name: Test
run: uv run just test
14 changes: 14 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# https://git-scm.com/docs/gitignore

# IDE
/.idea/
/.vscode/

# Python
.venv/
*.py[cod]
__pycache__/
.mypy_cache/
.ruff_cache/
.pytest_cache/
.ipynb_checkpoints/
15 changes: 15 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# https://pre-commit.com
# https://pre-commit.com/hooks.html

default_language_version:
python: python3.13
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: 'v5.0.0'
hooks:
- id: check-added-large-files
- id: check-case-conflict
- id: check-merge-conflict
- id: end-of-file-fixer
- id: mixed-line-ending
- id: trailing-whitespace
1 change: 1 addition & 0 deletions .python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.13
25 changes: 14 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ You have the freedom to structure your `src/` and `tests/` directories according
(This section was copied into the created project's README so tool info is available to users.)

* **Streamlined Project Structure:** A well-defined directory layout for source code, tests, documentation, tasks, and Docker configurations.
* **Poetry Integration:** Effortless dependency management and packaging with [Poetry](https://python-poetry.org/).
Uv Integration: Effortless dependency management and packaging with [uv](https://docs.astral.sh/uv/).
* **Automated Testing and Checks:** Pre-configured workflows using [Pytest](https://docs.pytest.org/), [Ruff](https://docs.astral.sh/ruff/), [Mypy](https://mypy.readthedocs.io/), [Bandit](https://bandit.readthedocs.io/), and [Coverage](https://coverage.readthedocs.io/) to ensure code quality, style, security, and type safety.
* **Pre-commit Hooks:** Automatic code formatting and linting with [Ruff](https://docs.astral.sh/ruff/) and other pre-commit hooks to maintain consistency.
* **Dockerized Deployment:** Dockerfile and docker-compose.yml for building and running the package within a containerized environment ([Docker](https://www.docker.com/)).
* **Invoke Task Automation:** [PyInvoke](https://www.pyinvoke.org/) tasks to simplify development workflows such as cleaning, installing, formatting, checking, building, documenting and running the project.
* **uv+just Task Automation:** [just](https://github.com/casey/just) commands to simplify development workflows such as cleaning, installing, formatting, checking, building, documenting and running the project.
* **Comprehensive Documentation:** [pdoc](https://pdoc.dev/) generates API documentation, and Markdown files provide clear usage instructions.
* **GitHub Workflow Integration:** Continuous integration and deployment workflows are set up using [GitHub Actions](https://github.com/features/actions), automating testing, checks, and publishing.

Expand Down Expand Up @@ -67,20 +67,23 @@ git init

- `src/{{cookiecutter.package}}`: Your Python package source code.
- `tests/`: Unit tests for your package.
- `tasks/`: PyInvoke tasks for automation.
- `tasks/`: `just` commands for automation.
- `Dockerfile`: Configuration for building your Docker image.
- `docker-compose.yml`: Orchestration file for running your project.

4. **Start developing!**

Use the provided Invoke tasks to manage your development workflow:

- `invoke installs`: Install dependencies and pre-commit hooks.
- `invoke formats`: Format your code.
- `invoke checks`: Run code quality, type, security, and test checks.
- `invoke docs`: Generate API documentation.
- `invoke packages`: Build your Python package.
- `invoke containers`: Build and run your Docker image.
Use the provided `just` commands to manage your development workflow:

- `uv run just check`: Run code quality, type, security, and test checks.
- `uv run just clean`: Clean up generated files.
- `uv run just commit`: Commit changes to your repository.
- `uv run just doc`: Generate API documentation.
- `uv run just docker`: Build and run your Docker image.
- `uv run just format`: Format your code with Ruff.
- `uv run just install`: Install dependencies, pre-commit hooks, and GitHub rulesets.
- `uv run just package`: Build your Python package.
- `uv run just project`: Run the project in the CLI.

## Example Usage

Expand Down
33 changes: 33 additions & 0 deletions justfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# https://just.systems/man/en/

# REQUIRES

find := require("find")
rm := require("rm")
uv := require("uv")

# DEFAULTS

# display help information
default:
@just --list

# TASKS

# clean the project
clean:
rm -rf .venv/
rm -rf .mypy_cache/
rm -rf .pytest_cache/

# install the project
install:
uv sync --all-groups

# setup the project hooks
hooks:
uv run pre-commit install

# run the project unit tests
test:
uv run pytest tests/
5 changes: 0 additions & 5 deletions poetry.toml

This file was deleted.

48 changes: 22 additions & 26 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,45 +1,41 @@
# https://python-poetry.org/docs/pyproject/
# https://docs.astral.sh/uv/reference/settings/
# https://packaging.python.org/en/latest/guides/writing-pyproject-toml/

# PACKAGE
# PROJECT

[tool.poetry]
[project]
name = "cookiecutter-mlops-package"
version = "1.0.0"
description = "Build and deploy Python packages and Docker images for MLOps tasks."
repository = "https://github.com/fmind/cookiecutter-mlops-package"
authors = ["Médéric HURIER <github@fmind.dev>"]
version = "4.1.0"
description = "Build and deploy Python packages and Docker images for MLOps projects."
authors = [{ name = "Médéric HURIER", email = "github@fmind.dev" }]
readme = "README.md"
license = "MIT"
package-mode = false
requires-python = ">=3.13"
license = { file = "LICENSE.txt" }

# DEPENDENCIES

[tool.poetry.dependencies]
python = "^3.12"
[dependency-groups]
dev = [
"commitizen>=4.1.0",
"pre-commit>=4.0.1",
"pytest-cookies>=0.7.0",
"pytest-shell-utilities>=1.9.7",
"pytest>=8.3.4",
"rust-just>=1.39.0",
]

[tool.poetry.group.dev.dependencies]
commitizen = "^3.28.0"
invoke = "^2.2.0"
pre-commit = "^3.7.1"
pytest = "^8.3.2"
pytest-cookies = "^0.7.0"
pytest-shell-utilities = "^1.9.0"
# TOOLS

# CONFIGURATIONS
[tool.uv]
package = false

[tool.commitizen]
name = "cz_conventional_commits"
tag_format = "v$version"
version_scheme = "pep440"
version_provider = "poetry"
version_provider = "pep621"
update_changelog_on_bump = true

[tool.pytest.ini_options]
log_cli = true
log_cli_level = "INFO"

# SYSTEMS

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
25 changes: 0 additions & 25 deletions tasks.py

This file was deleted.

30 changes: 14 additions & 16 deletions tests/test_cookiecutter.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@

COMMANDS = [
"git init",
"invoke cleans.reset",
"invoke installs",
"invoke formats",
"invoke checks",
"invoke docs",
"invoke projects",
"invoke packages",
"invoke containers",
"uv run just clean",
"uv run just install",
"uv run just format",
"uv run just check",
"uv run just doc",
"uv run just project",
"uv run just package",
"uv run just docker",
]

# %% TESTS
Expand All @@ -25,14 +25,13 @@
def test_project_generation(cookies: Cookies) -> None:
"""Test the generation of the project."""
# given
context = {
"user": "test",
context = {
"user": "tester",
"name": "MLOps 123",
"license": "apache-2",
"license": "Apache-2.0", # Note: needs to be a "valid SPDX identifier"
"version": "1.0.0",
"description": "DONE",
"python_version": "3.12",
"mlflow_version": "2.14.3",
"description": "A test project.",
"python_version": "3.13",
}
repository = context['name'].lower().replace(' ', '-')
package = repository.replace('-', '_')
Expand All @@ -47,13 +46,12 @@ def test_project_generation(cookies: Cookies) -> None:
assert result.context == {
"user": context['user'],
"name": context['name'],
"repository": repository,
"package": package,
"repository": repository,
"license": context['license'],
"version": context['version'],
"description": context['description'],
"python_version": context['python_version'],
"mlflow_version": context['mlflow_version'],
}
# - commands
shell = Subprocess(cwd=result.project_path)
Expand Down
Loading