diff --git a/copier.yml b/copier.yml index 6716475f..afefd5d3 100644 --- a/copier.yml +++ b/copier.yml @@ -7,6 +7,7 @@ _jinja_extensions: - copier_templates_extensions.TemplateExtensionLoader - extensions/context.py:DjangoNextVersion - extensions/context.py:SecretKey + - extensions/context.py:Dependencies _min_copier_version: "9.1.0" _secret_questions: - django_twc_ui_token @@ -89,29 +90,227 @@ node_version: help: Which version of Node.js should be used? default: "20" -tailwindcss_version: +# ---------------------------------------------------------------------- +# PYTHON +# ---------------------------------------------------------------------- + +python_dependencies: + type: str + help: What Python dependencies should be included? + multiselect: true + choices: + - "attrs" + - "django-allauth[socialaccount]" + - "django-charid-field" + - "django-click" + - "django-email-relay" + - "django-extensions" + - "django-filter" + - "django-flyio" + - "django-fsm-2" + - "django-health-check" + - "django-htmx" + - "django-import-export[all]" + - "django-ninja" + - "django-q2" + - "django-q-registry" + - "django-simple-history" + - "django-simple-nav" + - "django-storages[s3]" + - "django-stubs-ext" + - "django-tailwind-cli" + - "django-template-partials" + - "django-twc-toolbox" + - "django-vite" + - "environs[django]" + - "gunicorn" + - "heroicons[django]" + - "httpx" + - "lucide[django]" + - "openpyxl" + - "psycopg[binary]" + - "sentry-sdk[django]" + - "weasyprint" + - "whitenoise" + default: + - "attrs" + - "django-allauth[socialaccount]" + - "django-click" + - "django-email-relay" + - "django-extensions" + - "django-filter" + - "django-flyio" + - "django-fsm-2" + - "django-health-check" + - "django-htmx" + - "django-import-export[all]" + - "django-ninja" + - "django-q2" + - "django-q-registry" + - "django-simple-history" + - "django-simple-nav" + - "django-storages[s3]" + - "django-stubs-ext" + - "django-tailwind-cli" + - "django-template-partials" + - "django-twc-toolbox" + - "environs[django]" + - "gunicorn" + - "heroicons[django]" + - "httpx" + - "openpyxl" + - "psycopg[binary]" + - "sentry-sdk[django]" + - "whitenoise" + +email_relay_version: + when: "{{ 'django-email-relay' in python_dependencies }}" type: str - help: Which version of Tailwind CSS should be used? - default: "3.4.9" + help: django-email-relay version to pin to + default: 0.5 + +twc_toolbox_extras: + when: "{{ 'django-twc-toolbox' in python_dependencies }}" + type: str + help: django-twc-toolbox extras + multiselect: true + choices: + - "crud" + - "cuid" + - "history" + - "sentry" + default: + - "crud" + - "cuid" + - "history" + - "sentry" + +python_dev_dependencies: + type: str + help: What Python dev dependencies should be included? + multiselect: true + choices: + - "bumpver" + - "coverage[toml]" + - "django-browser-reload" + - "django-coverage-plugin" + - "django-debug-toolbar" + - "django-perf-rec" + - "django-stubs" + - "faker" + - "ipython" + - "model-bakery" + - "mypy" + - "playwright" + - "pre-commit" + - "pytest" + - "pytest-cov" + - "pytest-django" + - "pytest-is-running" + - "pytest-playwright" + - "pytest-randomly" + - "pytest-reverse" + - "pytest-xdist" + - "ruff" + - "uv" + default: + - "bumpver" + - "coverage[toml]" + - "django-browser-reload" + - "django-coverage-plugin" + - "django-debug-toolbar" + - "django-perf-rec" + - "django-stubs" + - "faker" + - "ipython" + - "model-bakery" + - "mypy" + - "playwright" + - "pre-commit" + - "pytest" + - "pytest-cov" + - "pytest-django" + - "pytest-is-running" + - "pytest-playwright" + - "pytest-randomly" + - "pytest-reverse" + - "pytest-xdist" + - "ruff" + - "uv" playwright_version: + when: "{{ 'playwright' in python_dev_dependencies }}" type: str help: Which version of Playwright should be used? default: "1.46.0" -# ---------------------------------------------------------------------- -# DEPENDENCIES -# ---------------------------------------------------------------------- +python_doc_dependencies: + type: str + help: What Python doc dependencies should be included? + multiselect: true + choices: + - "cogapp" + - "furo" + - "myst-parser" + - "sphinx" + - "sphinx-autobuild" + - "sphinx-copybutton" + - "sphinx-inline-tabs" + default: + - "cogapp" + - "furo" + - "myst-parser" + - "sphinx" + - "sphinx-autobuild" + - "sphinx-copybutton" + - "sphinx-inline-tabs" + +include_twc_ui: + type: bool + help: Install private package django-twc-ui? + default: true -django_twc_ui_token: +twc_ui_token: + when: "{{ include_twc_ui }}" type: str - help: What is the OAuth token for accessing the `westerveltco/django-twc-ui` repository? + help: What is the OAuth token for accessing the django-twc-ui repository? default: "" -django_twc_ui_version: + +twc_ui_version: + when: "{{ include_twc_ui }}" type: str - help: Which version of `django-twc-ui` should be used? + help: Which version of django-twc-ui should be used? default: "2024.8.27" +twc_ui_extras: + when: "{{ include_twc_ui }}" + type: str + help: django-twc-ui extras + multiselect: true + choices: + - "components" + - "tables" + default: + - "tables" + +# ---------------------------------------------------------------------- +# FRONTEND +# ---------------------------------------------------------------------- + +node_dependencies: + type: str + help: What Node.js dependencies should be included? + multiselect: true + choices: + - "tailwindcss" + default: + - "tailwindcss" + +include_vite: + type: bool + help: Include Vite as a frontend build tool? + default: false + # ---------------------------------------------------------------------- # FLY.IO # ---------------------------------------------------------------------- @@ -183,15 +382,6 @@ sentry_dsn: type: str help: What is the Sentry DSN URL? -# ---------------------------------------------------------------------- -# FRONTEND -# ---------------------------------------------------------------------- - -include_vite: - type: bool - help: Include Vite as a frontend build tool? - default: false - # ---------------------------------------------------------------------- # EMAIL # ---------------------------------------------------------------------- diff --git a/extensions/context.py b/extensions/context.py index 0b9a8987..981d6a75 100644 --- a/extensions/context.py +++ b/extensions/context.py @@ -42,3 +42,123 @@ def get_next_version(self, django_version: str) -> str: raise ValueError(f"Unknown django version: {django_version}") return next_version + + +class Dependencies(ContextHook): + @override + def hook(self, context: dict[str, object]) -> dict[str, object]: + context["python_dependencies"] = self.get_python_dependencies(context) + context["python_dev_dependencies"] = self.get_python_dev_dependencies(context) + context["python_doc_dependencies"] = self.get_python_doc_dependencies(context) + context["node_dependencies"] = self.get_node_dependencies(context) + return context + + def get_python_dependencies(self, context): + deps = cast(list[str], context["python_dependencies"]) + + final_deps = [*deps] + + if "django-q2" in deps: + final_deps.append("croniter") + + if context["include_twc_ui"]: + token = context["twc_ui_token"] + version = context["twc_ui_version"] + extras = context["twc_ui_extras"] + if extras: + extras = f"[{','.join(extras)}]" + else: + extras = "" + final_deps.append( + f"django-twc-ui{extras} @ git+https://{token}:x-oauth-basic@github.com/westerveltco/django-twc-ui.git@v{version}" + ) + + lines = [] + + for dep in sorted(final_deps): + if dep == "django-email-relay": + lines.append( + "# upper bounds for `django-email-relay` since it runs distributed" + ) + lines.append( + "# https://django-email-relay.westervelt.dev/en/latest/updating.html" + ) + version = context["email_relay_version"] + dep = f"{dep}<{version}" + + elif dep == "django-storages": + lines.append( + "# https://github.com/revsys/django-health-check/issues/434" + ) + lines.append( + "# https://github.com/jschneier/django-storages/issues/1430" + ) + dep = f"{dep}<1.14.4" + + elif dep == "django-twc-toolbox": + extras = context["twc_toolbox_extras"] + if extras: + dep = f"{dep}[{','.join(extras)}]" + + elif dep == "psycopg[binary]": + django_version = context["django_version"] + # TODO: make this more robust by turning string to float or version tuple + # to help with future versions + if django_version == "5.1": + dep = f"{dep[:-1]},pool]" + + lines.append(dep) + + return self._generate_string(lines) + + def get_python_dev_dependencies(self, context): + deps = cast(list[str], context["python_dev_dependencies"]) + pydeps = cast(list[str], context["python_dependencies"]) + + final_deps = [*deps] + + if "django-q2" in pydeps: + # croniter is included if django-q2 is chosen + final_deps.append("types-croniter") + if "openpyxl" in pydeps: + final_deps.append("types-openpyxl") + + lines = [] + + for dep in sorted(final_deps): + if dep == "playwright": + version = context["playwright_version"] + dep = f"{dep}=={version}" + + lines.append(dep) + + return self._generate_string(lines) + + def get_python_doc_dependencies(self, context): + deps = cast(list[str], context["python_doc_dependencies"]) + return self._generate_string(deps) + + def get_node_dependencies(self, context): + deps = cast(list[str], context["node_dependencies"]) + final_deps = [] + if "tailwindcss" in deps: + ... + + return self._generate_string(deps) + + def _generate_string(self, lines, leading_spaces=2): + ret = "" + + for idx, line in enumerate(lines): + for space in leading_spaces: + ret += " " + if line.startswith("#"): + ret += line + else: + ret += f' "{line}"' + if idx + 1 != len(lines): + ret += "," + if idx + 1 != len(lines): + ret += "\n" + + return ret diff --git a/src/django_twc_project/package.json.jinja b/src/django_twc_project/package.json.jinja index ee6c2394..8ab93865 100644 --- a/src/django_twc_project/package.json.jinja +++ b/src/django_twc_project/package.json.jinja @@ -1,6 +1,6 @@ { "devDependencies": { - "@django-twc-ui/tailwind": "git+https://{{ django_twc_ui_token }}:x-oauth-basic@github.com/westerveltco/django-twc-ui.git#v{{ django_twc_ui_version }}", + "@django-twc-ui/tailwind": "git+https://{{ twc_ui_token }}:x-oauth-basic@github.com/westerveltco/django-twc-ui.git#v{{ twc_ui_version }}", "tailwindcss": "^{{ tailwindcss_version }}", "autoprefixer": "^10.4.16", "postcss": "^8.4.31" diff --git a/src/django_twc_project/pyproject.toml.jinja b/src/django_twc_project/pyproject.toml.jinja index 13bae422..eebebe04 100644 --- a/src/django_twc_project/pyproject.toml.jinja +++ b/src/django_twc_project/pyproject.toml.jinja @@ -5,49 +5,7 @@ requires = ["hatchling"] [project] authors = [{name = "{{ author_name }}", email = "{{ author_email }}"}] dependencies = [ - "attrs", - "croniter", - "django<{{ django_next_version }}", - "django-allauth[socialaccount]", - "django-charid-field", - "django-click", - # upper bounds for `django-email-relay` since it runs distributed - # https://django-email-relay.westervelt.dev/en/latest/updating.html - "django-email-relay<0.5", - "django-extensions", - "django-filter", - "django-flyio", - "django-fsm-2", - "django-health-check", - "django-htmx", - "django-import-export[all]", - "django-ninja", - "django-q2", - "django-q-registry", - "django-simple-history", - "django-simple-nav", - # https://github.com/revsys/django-health-check/issues/434 - # https://github.com/jschneier/django-storages/issues/1430 - "django-storages[s3]<1.14.4", - "django-stubs-ext", - "django-tailwind-cli", - "django-template-partials", - "django-twc-toolbox[crud]", - "django-twc-ui[tables] @ git+https://{{ django_twc_ui_token }}:x-oauth-basic@github.com/westerveltco/django-twc-ui.git@v{{ django_twc_ui_version }}", -{%- if include_vite %} - "django-vite", -{%- endif %} - "environs[django]", - "gunicorn", - "heroicons[django]", - "httpx", - "openpyxl", - "psycopg[binary{% if django_version >= '5.1' %}, pool{% endif %}]", - "sentry-sdk[django]", -{%- if include_weasyprint %} - "weasyprint", -{%- endif %} - "whitenoise", +{{ python_dependencies }} ] name = "{{ project_name }}" requires-python = ">={{ python_version }}" @@ -55,41 +13,10 @@ dynamic = ["version"] [project.optional-dependencies] dev = [ - "copier", - "copier-templates-extensions", - "coverage[toml]", - "django-browser-reload", - "django-coverage-plugin", - "django-debug-toolbar", - "django-perf-rec", - "django-stubs", - "faker", - "ipython", - "model_bakery", - "mypy", - "playwright=={{ playwright_version }}", - "pre-commit", - "pytest", - "pytest-cov", - "pytest-django", - "pytest-is-running", - "pytest-playwright", - "pytest-randomly", - "pytest-reverse", - "pytest-xdist", - "ruff", - "types-croniter", - "types-openpyxl", - "uv" +{{ python_dev_dependencies }} ] docs = [ - "cogapp", - "furo", - "myst-parser", - "sphinx", - "sphinx-autobuild", - "sphinx-copybutton", - "sphinx-inline-tabs" +{{ python_doc_dependencies }} ] [tool.bumpver]