From 4d5e08429ef108c7c0586c6b14e959020142f5fe Mon Sep 17 00:00:00 2001 From: Felix Rindt Date: Fri, 13 Feb 2026 13:35:50 +0100 Subject: [PATCH 1/2] use uv, hatch-django-locale, prek, ruff --- .../.pre-commit-config.yaml | 16 ++++++ {{ cookiecutter.app_name }}/README.md | 12 +++++ .../__init__.py | 0 .../plugintests/conftest.py | 1 + .../test_{{ cookiecutter.app_name}}.py | 3 ++ {{ cookiecutter.app_name }}/pyproject.toml | 52 +++++++++++++++---- .../{{cookiecutter.app_name}}}/__init__.py | 0 .../{{cookiecutter.app_name}}/apps.py | 2 + .../locale/de/LC_MESSAGES/django.po | 16 ++++++ .../migrations/__init__.py | 0 .../{{cookiecutter.app_name}}/models.py | 0 .../{{cookiecutter.app_name}}/signals.py | 0 .../{{cookiecutter.app_name}}/tests.py | 0 .../src/{{cookiecutter.app_name}}/urls.py | 6 +++ .../{{cookiecutter.app_name}}/views.py | 0 15 files changed, 99 insertions(+), 9 deletions(-) create mode 100644 {{ cookiecutter.app_name }}/.pre-commit-config.yaml create mode 100644 {{ cookiecutter.app_name }}/README.md rename {{ cookiecutter.app_name }}/{{{cookiecutter.app_name}} => plugintests}/__init__.py (100%) create mode 100644 {{ cookiecutter.app_name }}/plugintests/conftest.py create mode 100644 {{ cookiecutter.app_name }}/plugintests/test_{{ cookiecutter.app_name}}.py rename {{ cookiecutter.app_name }}/{{{cookiecutter.app_name}}/migrations => src/{{cookiecutter.app_name}}}/__init__.py (100%) rename {{ cookiecutter.app_name }}/{ => src}/{{cookiecutter.app_name}}/apps.py (86%) create mode 100644 {{ cookiecutter.app_name }}/src/{{cookiecutter.app_name}}/locale/de/LC_MESSAGES/django.po create mode 100644 {{ cookiecutter.app_name }}/src/{{cookiecutter.app_name}}/migrations/__init__.py rename {{ cookiecutter.app_name }}/{ => src}/{{cookiecutter.app_name}}/models.py (100%) rename {{ cookiecutter.app_name }}/{ => src}/{{cookiecutter.app_name}}/signals.py (100%) rename {{ cookiecutter.app_name }}/{ => src}/{{cookiecutter.app_name}}/tests.py (100%) create mode 100644 {{ cookiecutter.app_name }}/src/{{cookiecutter.app_name}}/urls.py rename {{ cookiecutter.app_name }}/{ => src}/{{cookiecutter.app_name}}/views.py (100%) diff --git a/{{ cookiecutter.app_name }}/.pre-commit-config.yaml b/{{ cookiecutter.app_name }}/.pre-commit-config.yaml new file mode 100644 index 0000000..8f957b5 --- /dev/null +++ b/{{ cookiecutter.app_name }}/.pre-commit-config.yaml @@ -0,0 +1,16 @@ +default_language_version: + python: python3 +repos: + - repo: 'https://github.com/pre-commit/pre-commit-hooks' + rev: v6.0.0 + hooks: + - id: check-added-large-files + - repo: 'https://github.com/astral-sh/ruff-pre-commit' + rev: v0.15.0 + hooks: + - id: ruff-check + - id: ruff-format + - repo: https://github.com/rtts/djhtml + rev: 3.0.6 + hooks: + - id: djhtml diff --git a/{{ cookiecutter.app_name }}/README.md b/{{ cookiecutter.app_name }}/README.md new file mode 100644 index 0000000..b93e036 --- /dev/null +++ b/{{ cookiecutter.app_name }}/README.md @@ -0,0 +1,12 @@ +# {{ cookiecutter.app_name }} + +{{ cookiecutter.description }} + +## Development + +This project uses uv to manage dependencies and run the application. +Pre-commit hookes are managed using prek. +Versioning is based on git tags. +The build backend includes a mechanism to automatically compile locales when building the package. + +Make messages using ``ENV_PATH="../ephios/.env" django-admin makemessages -a`` diff --git a/{{ cookiecutter.app_name }}/{{cookiecutter.app_name}}/__init__.py b/{{ cookiecutter.app_name }}/plugintests/__init__.py similarity index 100% rename from {{ cookiecutter.app_name }}/{{cookiecutter.app_name}}/__init__.py rename to {{ cookiecutter.app_name }}/plugintests/__init__.py diff --git a/{{ cookiecutter.app_name }}/plugintests/conftest.py b/{{ cookiecutter.app_name }}/plugintests/conftest.py new file mode 100644 index 0000000..847732f --- /dev/null +++ b/{{ cookiecutter.app_name }}/plugintests/conftest.py @@ -0,0 +1 @@ +from tests.conftest import * # noqa diff --git a/{{ cookiecutter.app_name }}/plugintests/test_{{ cookiecutter.app_name}}.py b/{{ cookiecutter.app_name }}/plugintests/test_{{ cookiecutter.app_name}}.py new file mode 100644 index 0000000..2f740c5 --- /dev/null +++ b/{{ cookiecutter.app_name }}/plugintests/test_{{ cookiecutter.app_name}}.py @@ -0,0 +1,3 @@ + +def test_{{ cookiecutter.app_name}}(django_app, superuser): + pass \ No newline at end of file diff --git a/{{ cookiecutter.app_name }}/pyproject.toml b/{{ cookiecutter.app_name }}/pyproject.toml index dbb1fed..6ad8785 100644 --- a/{{ cookiecutter.app_name }}/pyproject.toml +++ b/{{ cookiecutter.app_name }}/pyproject.toml @@ -1,18 +1,52 @@ -[tool.poetry] +[project] name = "{{ cookiecutter.app_name|replace('_', '-') }}" -version = "0.1.0" +dynamic = ["version"] description = "{{ cookiecutter.description }}" authors = ["{{ cookiecutter.author }}"] license = "{{ cookiecutter.license }}" +readme = "README.md" -[tool.poetry.dependencies] -python = "^3.10" +dependencies = [ + # do not include ephios to avoid desync of locked versions, but make sure to include it in the test environment +] -[tool.poetry.dev-dependencies] +[dependency-groups] +dev = [ + "pytest-django>=4.5.2,<5", + "djhtml>=3.0.6,<4", + "prek>=0.3.1", + "ruff>=0.15.0", + "pytest-env>=1.3.2", +] +[project.entry-points."ephios.plugins"] +"{{ cookiecutter.app_name }}" = "{{ cookiecutter.app_name }}.apps.PluginApp" + +# build and versioning [build-system] -requires = ["poetry-core>=1.0.0"] -build-backend = "poetry.core.masonry.api" +requires = ["hatchling", "uv-dynamic-versioning", "hatch-django-locales>=0.1.4"] +build-backend = "hatchling.build" +[tool.hatch.build.hooks.django-locales] +[tool.hatch.version] +source = "uv-dynamic-versioning" +[tool.uv-dynamic-versioning] +fallback-version = "0.0.0" # used if no VCS info is available, e.g. dependabot builds +[tool.uv] +cache-keys = [{ file = "pyproject.toml" }, { git = { commit = true, tags = true }}] -[tool.poetry.plugins."ephios.plugins"] -"{{ cookiecutter.app_name }}" = "{{ cookiecutter.app_name }}.apps.PluginApp" +# Testing, format and linting +[tool.ruff] +line-length = 100 +[tool.ruff.format] +preview = true +[tool.ruff.lint] +preview = true +[tool.pytest.ini_options] +DJANGO_SETTINGS_MODULE = "tests.settings" +pythonpath = [ + "src", # to find the plugin source + "../ephios", # to find the ephios django project and ephios "tests.settings"/conftest fixtures +] +testpaths = ["plugintests"] # need a non-standard name to avoid conflicts with ephios' own tests dir +[tool.pytest_env] +ENV_PATH="../ephios/.env" \ No newline at end of file diff --git a/{{ cookiecutter.app_name }}/{{cookiecutter.app_name}}/migrations/__init__.py b/{{ cookiecutter.app_name }}/src/{{cookiecutter.app_name}}/__init__.py similarity index 100% rename from {{ cookiecutter.app_name }}/{{cookiecutter.app_name}}/migrations/__init__.py rename to {{ cookiecutter.app_name }}/src/{{cookiecutter.app_name}}/__init__.py diff --git a/{{ cookiecutter.app_name }}/{{cookiecutter.app_name}}/apps.py b/{{ cookiecutter.app_name }}/src/{{cookiecutter.app_name}}/apps.py similarity index 86% rename from {{ cookiecutter.app_name }}/{{cookiecutter.app_name}}/apps.py rename to {{ cookiecutter.app_name }}/src/{{cookiecutter.app_name}}/apps.py index 021bfc5..7d2a894 100644 --- a/{{ cookiecutter.app_name }}/{{cookiecutter.app_name}}/apps.py +++ b/{{ cookiecutter.app_name }}/src/{{cookiecutter.app_name}}/apps.py @@ -8,6 +8,8 @@ class EphiosPluginMeta: name = "{{ cookiecutter.app_name }}" author = "{{ cookiecutter.author }}" description = "{{ cookiecutter.description }}" + visible = True + force_enabled = False def ready(self): from . import signals # NOQA diff --git a/{{ cookiecutter.app_name }}/src/{{cookiecutter.app_name}}/locale/de/LC_MESSAGES/django.po b/{{ cookiecutter.app_name }}/src/{{cookiecutter.app_name}}/locale/de/LC_MESSAGES/django.po new file mode 100644 index 0000000..3cdc04a --- /dev/null +++ b/{{ cookiecutter.app_name }}/src/{{cookiecutter.app_name}}/locale/de/LC_MESSAGES/django.po @@ -0,0 +1,16 @@ +# {{ cookiecutter.app_name }} locale file for German (de) +# Copyright (C) {{ cookiecutter.author }} +# This file is distributed under the same license as the PACKAGE package. +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2026-02-13 13:25+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: {{ cookiecutter.author }}\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? " +"1 : 2;\n" \ No newline at end of file diff --git a/{{ cookiecutter.app_name }}/src/{{cookiecutter.app_name}}/migrations/__init__.py b/{{ cookiecutter.app_name }}/src/{{cookiecutter.app_name}}/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/{{ cookiecutter.app_name }}/{{cookiecutter.app_name}}/models.py b/{{ cookiecutter.app_name }}/src/{{cookiecutter.app_name}}/models.py similarity index 100% rename from {{ cookiecutter.app_name }}/{{cookiecutter.app_name}}/models.py rename to {{ cookiecutter.app_name }}/src/{{cookiecutter.app_name}}/models.py diff --git a/{{ cookiecutter.app_name }}/{{cookiecutter.app_name}}/signals.py b/{{ cookiecutter.app_name }}/src/{{cookiecutter.app_name}}/signals.py similarity index 100% rename from {{ cookiecutter.app_name }}/{{cookiecutter.app_name}}/signals.py rename to {{ cookiecutter.app_name }}/src/{{cookiecutter.app_name}}/signals.py diff --git a/{{ cookiecutter.app_name }}/{{cookiecutter.app_name}}/tests.py b/{{ cookiecutter.app_name }}/src/{{cookiecutter.app_name}}/tests.py similarity index 100% rename from {{ cookiecutter.app_name }}/{{cookiecutter.app_name}}/tests.py rename to {{ cookiecutter.app_name }}/src/{{cookiecutter.app_name}}/tests.py diff --git a/{{ cookiecutter.app_name }}/src/{{cookiecutter.app_name}}/urls.py b/{{ cookiecutter.app_name }}/src/{{cookiecutter.app_name}}/urls.py new file mode 100644 index 0000000..3e8b6df --- /dev/null +++ b/{{ cookiecutter.app_name }}/src/{{cookiecutter.app_name}}/urls.py @@ -0,0 +1,6 @@ +from django.urls import path + +app_name = "{{ cookiecutter.app_name }}" +urlpatterns = [ + # path("your-plugin-url/", YourPluginView.as_view(), name="{{ cookiecutter.app_name }}_viewname"), +] diff --git a/{{ cookiecutter.app_name }}/{{cookiecutter.app_name}}/views.py b/{{ cookiecutter.app_name }}/src/{{cookiecutter.app_name}}/views.py similarity index 100% rename from {{ cookiecutter.app_name }}/{{cookiecutter.app_name}}/views.py rename to {{ cookiecutter.app_name }}/src/{{cookiecutter.app_name}}/views.py From 5f7ad0e6da2f35515a482e442612cac6ade0638e Mon Sep 17 00:00:00 2001 From: Felix Rindt Date: Fri, 13 Feb 2026 20:11:45 +0100 Subject: [PATCH 2/2] fix author --- cookiecutter.json | 3 ++- {{ cookiecutter.app_name }}/pyproject.toml | 4 +++- .../src/{{cookiecutter.app_name}}/apps.py | 2 +- .../{{cookiecutter.app_name}}/locale/de/LC_MESSAGES/django.po | 4 ++-- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/cookiecutter.json b/cookiecutter.json index 1e06783..f090968 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -1,6 +1,7 @@ { "app_name": "ephios_mycoolplugin", "description": "My plugin does cool stuff", - "author": "Jon Doe ", + "author_name": "Jon Doe", + "author_email": "jondoe@example.com", "license": "MIT" } \ No newline at end of file diff --git a/{{ cookiecutter.app_name }}/pyproject.toml b/{{ cookiecutter.app_name }}/pyproject.toml index 6ad8785..c89e04d 100644 --- a/{{ cookiecutter.app_name }}/pyproject.toml +++ b/{{ cookiecutter.app_name }}/pyproject.toml @@ -2,7 +2,9 @@ name = "{{ cookiecutter.app_name|replace('_', '-') }}" dynamic = ["version"] description = "{{ cookiecutter.description }}" -authors = ["{{ cookiecutter.author }}"] +authors = [ + {name="{{ cookiecutter.author_name }}", email="{{ cookiecutter.author_email }}"}, +] license = "{{ cookiecutter.license }}" readme = "README.md" diff --git a/{{ cookiecutter.app_name }}/src/{{cookiecutter.app_name}}/apps.py b/{{ cookiecutter.app_name }}/src/{{cookiecutter.app_name}}/apps.py index 7d2a894..eb03c65 100644 --- a/{{ cookiecutter.app_name }}/src/{{cookiecutter.app_name}}/apps.py +++ b/{{ cookiecutter.app_name }}/src/{{cookiecutter.app_name}}/apps.py @@ -6,7 +6,7 @@ class PluginApp(PluginConfig): class EphiosPluginMeta: name = "{{ cookiecutter.app_name }}" - author = "{{ cookiecutter.author }}" + author = "{{ cookiecutter.author_name }}" description = "{{ cookiecutter.description }}" visible = True force_enabled = False diff --git a/{{ cookiecutter.app_name }}/src/{{cookiecutter.app_name}}/locale/de/LC_MESSAGES/django.po b/{{ cookiecutter.app_name }}/src/{{cookiecutter.app_name}}/locale/de/LC_MESSAGES/django.po index 3cdc04a..4f6e11d 100644 --- a/{{ cookiecutter.app_name }}/src/{{cookiecutter.app_name}}/locale/de/LC_MESSAGES/django.po +++ b/{{ cookiecutter.app_name }}/src/{{cookiecutter.app_name}}/locale/de/LC_MESSAGES/django.po @@ -1,5 +1,5 @@ # {{ cookiecutter.app_name }} locale file for German (de) -# Copyright (C) {{ cookiecutter.author }} +# Copyright (C) {{ cookiecutter.author_name }} # This file is distributed under the same license as the PACKAGE package. msgid "" msgstr "" @@ -7,7 +7,7 @@ msgstr "" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-02-13 13:25+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: {{ cookiecutter.author }}\n" +"Last-Translator: {{ cookiecutter.author_name }}\n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n"