diff --git a/README.md b/README.md index b97e6b2..20ca026 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ # Public Django App Template -This repository provides a template for a pip-installable public Django app deployed using CircleCI to PyPI. +This repository provides a template for a pip-installable public Python project deployed using CircleCI to PyPI. This is a [cookiecutter](https://cookiecutter.readthedocs.io/en/latest/) template that can be used by [footing](https://github.com/Opus10/footing/) to create and manage the project. -A new public Django app can be started with: +A new public project can be started with: pip3 install footing footing setup git@github.com:Opus10/public-django-app-template.git @@ -24,6 +24,8 @@ When calling `footing setup`, the user will be prompted for template parameters. 1. `repo_name`: The name of the repository **and** and name that will be used when installing via pip. Be sure that the name isn't taken on PyPI before creation. 2. `module_name`: The name of the Python module that will be imported as a library. Modules must have underscores (i.e. `import my_installable_package`) 3. `short_description`: A short description of the project. This will be added as the Github repo description and the description in the `pyproject.toml` file. It will also be the description displayed when users do `footing ls github.com/Opus10` to list this project. +4. `check_types_in_ci`: True if type checking should be a required CI check. +5. `is_django`: True if this is a Django app. ## What Does This Template Provide? @@ -37,7 +39,7 @@ When using this template with [footing setup](git@github.com:Opus10/public-djang Once all of this is complete, the user can take advantage of all of the scaffolding provided by the template, which includes: -1. Automatic deployment to PyPI when merging into the master (see `.circleci/config.yaml`). +1. Automatic deployment to PyPI when merging into the main (see `.circleci/config.yaml`). 2. Ruff integration (see `pyproject.toml` for configuration). 3. Coverage integration (see `pyproject.toml` for coverage configuration). 4. Automatic version tagging and version bumping (more on this in later sections). diff --git a/build_image.sh b/build_image.sh index e5013b3..7050c3c 100644 --- a/build_image.sh +++ b/build_image.sh @@ -1 +1 @@ -docker buildx build --platform linux/amd64,linux/arm64 -t opus10/circleci-public-django-app:${VERSION} . +docker buildx build --platform linux/amd64,linux/arm64 -t opus10/circleci-python-library:${VERSION} . diff --git a/cookiecutter.json b/cookiecutter.json index ec8880c..baca3ee 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -2,5 +2,7 @@ "repo_name": null, "module_name": "{{ cookiecutter.repo_name.lower().replace('-', '_') }}", "short_description": null, + "check_types_in_ci": true, + "is_django": true, "_extensions": ["jinja2_time.TimeExtension"] } diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py index c505005..a968667 100755 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 """Prompts the user and runs project setup during ``footing setup``""" import os +import pathlib import re import subprocess import sys @@ -11,6 +12,8 @@ REPO_NAME = "{{ cookiecutter.repo_name }}" MODULE_NAME = "{{ cookiecutter.module_name }}" DESCRIPTION = "{{ cookiecutter.short_description }}" +IS_DJANGO = "{{ cookiecutter.is_django }}" == "True" +CHECK_TYPES_IN_CI = "{{ cookiecutter.check_types_in_ci }}" == "True" FOOTING_ENV_VAR = "_FOOTING" GITHUB_API_TOKEN_ENV_VAR = "GITHUB_API_TOKEN" GITHUB_ORG_NAME = "Opus10" @@ -241,12 +244,12 @@ def github_push_initial_repo( if isinstance(initial_commit, str): initial_commit = [initial_commit] - _shell("git init -b master") + _shell("git init -b main") _shell("git add .") _shell("git commit " + " ".join(f'-m "{msg}"' for msg in initial_commit)) _shell(f"git remote add origin {remote}") - ret = _shell("git push origin master", check=False) + ret = _shell("git push origin main", check=False) if ret.returncode != 0: msg = "There was an error when pushing the initial repository." prompt_msg = ( @@ -306,6 +309,15 @@ def circleci_configure_project_settings(repo_name): def footing_setup(): + # Conditionally remove files + if not IS_DJANGO: + pathlib.Path("docker-compose.yml").unlink() + pathlib.Path("manage.py").unlink() + pathlib.Path("settings.py").unlink() + + if not CHECK_TYPES_IN_CI: + (pathlib.Path(MODULE_NAME) / "py.typed").unlink() + # Make sure requests is installed print("Installing requests library for repository setup...") _shell("pip3 install requests") @@ -331,13 +343,23 @@ def footing_setup(): ) github_create_repo(REPO_NAME, DESCRIPTION) - print("Creating initial repository and pushing to master.") + print("Creating initial repository and pushing to main.") github_push_initial_repo(REPO_NAME) print("Setting up default branch protection.") + contexts = [ + "ci/circleci: check_changelog", + "ci/circleci: lint", + "ci/circleci: type_check", + ] + if IS_DJANGO: + contexts.extend(["ci/circleci: test_pg_min", "ci/circleci: test_pg_max"]) + else: + contexts.append("ci/circleci: test") + github_setup_branch_protection( REPO_NAME, - "master", + "main", { "required_pull_request_reviews": None, "required_status_checks": { @@ -346,6 +368,7 @@ def footing_setup(): "ci/circleci: test_pg_max", "ci/circleci: check_changelog", "ci/circleci: lint", + "ci/circleci: type_check", ], "strict": True, }, diff --git a/{{ cookiecutter.repo_name }}/.circleci/config.yml b/{{ cookiecutter.repo_name }}/.circleci/config.yml index bc2345b..883915d 100644 --- a/{{ cookiecutter.repo_name }}/.circleci/config.yml +++ b/{{ cookiecutter.repo_name }}/.circleci/config.yml @@ -1,84 +1,102 @@ -{% raw -%} version: 2.1 orbs: opus10: executors: - python-pg: - parameters: - pg_version: - type: "string" - default: "14.4" + python: working_directory: /code docker: - - image: opus10/circleci-public-django-app:2023-10-06 + - image: opus10/circleci-python-library:2024-04-17 environment: # Ensure makefile commands are not wrapped in "docker-compose run" EXEC_WRAPPER: '' - DATABASE_URL: postgres://root@localhost/circle_test?sslmode=disable TOX_PARALLEL_NO_SPINNER: 1 + {%- if cookiecutter.is_django == "True" %} + DATABASE_URL: postgres://root@localhost/circle_test?sslmode=disable - image: cimg/postgres:<> environment: POSTGRES_USER: root POSTGRES_DB: circle_test POSTGRES_PASSWORD: password + parameters: + pg_version: + type: "string" + default: "14.4" + {%- endif %} commands: test: steps: - checkout - restore_cache: - key: v4-{{ checksum "poetry.lock" }} + key: v4-{{ '{{' }} checksum "poetry.lock" {{ '}}' }} - run: make dependencies - run: make full-test-suite - save_cache: - key: v4-{{ checksum "poetry.lock" }} + key: v4-{{ '{{' }} checksum "poetry.lock" {{ '}}' }} paths: - /home/circleci/.cache/pypoetry/ - /code/.venv - /code/.tox jobs: + {%- if cookiecutter.is_django == "True" %} test_pg_min: executor: - name: opus10/python-pg + name: opus10/python pg_version: "12.15" steps: - opus10/test test_pg_max: executor: - name: opus10/python-pg + name: opus10/python pg_version: "16.0" steps: - opus10/test + {%- else %} + test: + executor: + name: opus10/python + steps: + - opus10/test + {%- endif %} lint: - executor: opus10/python-pg + executor: opus10/python steps: - checkout - restore_cache: - key: v4-{{ checksum "poetry.lock" }} + key: v4-{{ '{{' }} checksum "poetry.lock" {{ '}}' }} - run: make dependencies - run: make lint + type_check: + executor: opus10/python + steps: + - checkout + - restore_cache: + key: v4-{{ '{{' }} checksum "poetry.lock" {{ '}}' }} + - run: make dependencies + - run: make type-check {% if not cookiecutter.check_types_in_ci == 'True' %}|| true{% endif %} + check_changelog: - executor: opus10/python-pg + executor: opus10/python steps: - checkout - restore_cache: - key: v4-{{ checksum "poetry.lock" }} + key: v4-{{ '{{' }} checksum "poetry.lock" {{ '}}' }} - run: make dependencies - - run: git tidy-log origin/master.. + - run: git tidy-log origin/main.. - run: make tidy-lint deploy: - executor: opus10/python-pg + executor: opus10/python steps: - checkout - run: ssh-add -D - run: echo "${GITHUB_DEVOPS_PRIVATE_SSH_KEY_BASE64}" | base64 --decode | ssh-add - > /dev/null - restore_cache: - key: v4-{{ checksum "poetry.lock" }} + key: v4-{{ '{{' }} checksum "poetry.lock" {{ '}}' }} - run: make dependencies - run: poetry run python devops.py deploy @@ -86,20 +104,29 @@ workflows: version: 2 on_commit: jobs: + {%- if cookiecutter.is_django == "True" %} - test_pg_min - test_pg_max + {%- else %} + - test + {%- endif %} - lint + - type_check - check_changelog: filters: branches: - ignore: master + ignore: main - deploy: - context: public-django-app + context: python-library requires: + {%- if cookiecutter.is_django == "True" %} - test_pg_min - test_pg_max + {%- else %} + - test + {%- endif %} - lint + - type_check filters: branches: - only: master -{% endraw -%} + only: main diff --git a/{{ cookiecutter.repo_name }}/CONTRIBUTING.md b/{{ cookiecutter.repo_name }}/CONTRIBUTING.md index fb9bc00..7c6619d 100644 --- a/{{ cookiecutter.repo_name }}/CONTRIBUTING.md +++ b/{{ cookiecutter.repo_name }}/CONTRIBUTING.md @@ -12,7 +12,7 @@ Set up your development environment with: `make docker-setup` will set up a development environment managed by Docker. Install docker [here](https://www.docker.com/get-started) and be sure it is running when executing any of the commands below. -If you prefer a native development environment, `make conda-setup` will set up a development environment managed by [Conda](https://conda.io). The database must be ran manually. +If you prefer a native development environment, `make conda-setup` will set up a development environment managed by [Conda](https://conda.io). Dependent services, such as databases, must be ran manually. ## Testing and Validation @@ -48,7 +48,7 @@ To check if your commits pass linting, do: make tidy-lint -Note, the above command lints every commit since branching from master. You can also run `make shell` and run `git tidy` commands inside the docker environment to do other flavors of `git tidy` commands. +Note, the above command lints every commit since branching from main. You can also run `make shell` and run `git tidy` commands inside the docker environment to do other flavors of `git tidy` commands. ## Documentation @@ -62,7 +62,7 @@ A shortcut for serving them is: ## Releases and Versioning -Anything that is merged into the master branch will be automatically deployed to PyPI. Documentation will be published to a ReadTheDocs at `https://{{ cookiecutter.repo_name }}.readthedocs.io/`. +Anything that is merged into the main branch will be automatically deployed to PyPI. Documentation will be published to a ReadTheDocs at `https://{{ cookiecutter.repo_name }}.readthedocs.io/`. The following files will be generated and should *not* be edited by a user: diff --git a/{{ cookiecutter.repo_name }}/LICENSE b/{{ cookiecutter.repo_name }}/LICENSE index 7a31f1d..28efb8f 100644 --- a/{{ cookiecutter.repo_name }}/LICENSE +++ b/{{ cookiecutter.repo_name }}/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2023, Opus 10 +Copyright (c) 2024, Opus 10 All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/{{ cookiecutter.repo_name }}/Makefile b/{{ cookiecutter.repo_name }}/Makefile index 3cdcdcf..f31b970 100644 --- a/{{ cookiecutter.repo_name }}/Makefile +++ b/{{ cookiecutter.repo_name }}/Makefile @@ -8,6 +8,7 @@ # docs-serve - Serve documentation # lint - Run code linting and static checks # lint-fix - Fix common linting errors +# type-check - Run Pyright type-checking # test - Run tests using pytest # full-test-suite - Run full test suite using tox # shell - Run a shell in a virtualenv @@ -34,8 +35,11 @@ else ifeq (${OS}, Darwin) endif # Docker run mounts the local code directory, SSH (for git), and global git config information +{%- if cookiecutter.is_django == "True" %} DOCKER_RUN_CMD?=$(DOCKER_CMD)-compose run --name $(PACKAGE_NAME) $(DOCKER_RUN_ARGS) -d app - +{%- else %} +DOCKER_RUN_CMD?=$(DOCKER_CMD) run -t --name $(PACKAGE_NAME) $(DOCKER_RUN_ARGS) -d opus10/circleci-python-library +{%- endif %} # Print usage of main targets when user types "make" or "make help" .PHONY: help @@ -66,7 +70,11 @@ endif # Pull the latest container and start a detached run .PHONY: docker-start docker-start: + {%- if cookiecutter.is_django %} $(DOCKER_CMD)-compose pull + {%- else %} + $(DOCKER_CMD) pull opus10/circleci-public-python-library + {%- endif %} $(DOCKER_RUN_CMD) @@ -89,6 +97,7 @@ git-setup: $(EXEC_WRAPPER) git config --local commit.template .gitcommit.tpl +{% if cookiecutter.is_django == "True" -%} # Sets up the local database .PHONY: db-setup db-setup: @@ -97,6 +106,7 @@ db-setup: -psql postgres -c "CREATE DATABASE ${MODULE_NAME}_local OWNER postgres;" -psql postgres -c "GRANT ALL PRIVILEGES ON DATABASE ${MODULE_NAME}_local to postgres;" $(EXEC_WRAPPER) python manage.py migrate +{%- endif %} # Sets up a conda development environment @@ -109,7 +119,7 @@ conda-create: # Sets up a Conda development environment .PHONY: conda-setup conda-setup: EXEC_WRAPPER=conda run -n ${PACKAGE_NAME} --no-capture-output -conda-setup: conda-create lock dependencies git-setup db-setup +conda-setup: conda-create lock dependencies git-setup {% if cookiecutter.is_django == "True" %}db-setup{% endif %} # Sets up a Docker development environment @@ -120,7 +130,12 @@ docker-setup: docker-teardown docker-start lock dependencies git-setup # Spin down docker resources .PHONY: docker-teardown docker-teardown: + {%- if cookiecutter.is_django == "True" %} $(DOCKER_CMD)-compose down --remove-orphans + {%- else %} + -$(DOCKER_CMD) stop $(PACKAGE_NAME) + -$(DOCKER_CMD) rm $(PACKAGE_NAME) + {%- endif %} # Run a shell @@ -168,15 +183,17 @@ lint-fix: $(EXEC_WRAPPER) ruff format . $(EXEC_WRAPPER) ruff check ${MODULE_NAME} --fix + # Run Pyright type-checking .PHONY: type-check type-check: - $(EXEC_WRAPPER) pyright . + $(EXEC_WRAPPER) pyright $(MODULE_NAME) + # Lint commit messages .PHONY: tidy-lint tidy-lint: - $(EXEC_WRAPPER) git tidy-lint origin/master.. + $(EXEC_WRAPPER) git tidy-lint origin/main.. # Perform a tidy commit @@ -188,4 +205,4 @@ tidy-commit: # Perform a tidy squash .PHONY: tidy-squash tidy-squash: - $(EXEC_WRAPPER) git tidy-squash origin/master + $(EXEC_WRAPPER) git tidy-squash origin/main diff --git a/{{ cookiecutter.repo_name }}/README.md b/{{ cookiecutter.repo_name }}/README.md index a28a937..527e383 100644 --- a/{{ cookiecutter.repo_name }}/README.md +++ b/{{ cookiecutter.repo_name }}/README.md @@ -2,7 +2,7 @@ ## Compatibility -`{{ cookiecutter.repo_name }}` is compatible with Python 3.8 - 3.12, Django 3.2 - 5.0, Psycopg 2 - 3, and Postgres 12 - 16. +`{{ cookiecutter.repo_name }}` is compatible with Python 3.8 - 3.12{% if cookiecutter.is_django == "True" %}, Django 3.2 - 5.0, Psycopg 2 - 3, and Postgres 12 - 16{% endif %}. ## Documentation diff --git a/{{ cookiecutter.repo_name }}/devops.py b/{{ cookiecutter.repo_name }}/devops.py index f3c3495..877330d 100644 --- a/{{ cookiecutter.repo_name }}/devops.py +++ b/{{ cookiecutter.repo_name }}/devops.py @@ -10,6 +10,7 @@ Do not change this script! Any fixes or updates to this script should be made to https://github.com/Opus10/public-django-app-template """ + import os import subprocess import sys diff --git a/{{ cookiecutter.repo_name }}/docker-compose.yml b/{{ cookiecutter.repo_name }}/docker-compose.yml index 49d40ca..9c7be53 100644 --- a/{{ cookiecutter.repo_name }}/docker-compose.yml +++ b/{{ cookiecutter.repo_name }}/docker-compose.yml @@ -10,7 +10,7 @@ services: - POSTGRES_USER=postgres - POSTGRES_PASSWORD=postgres app: - image: opus10/circleci-public-django-app + image: opus10/circleci-python-library environment: - DATABASE_URL=postgres://postgres:postgres@db:5432/postgres depends_on: diff --git a/{{ cookiecutter.repo_name }}/docs/contributing.md b/{{ cookiecutter.repo_name }}/docs/contributing.md index fb9bc00..9888053 100644 --- a/{{ cookiecutter.repo_name }}/docs/contributing.md +++ b/{{ cookiecutter.repo_name }}/docs/contributing.md @@ -32,6 +32,10 @@ If your code fails the linter checks, fix common errors with: make lint-fix +Run type checking with: + + make type-check + ## Committing This project uses [git-tidy](https://github.com/Opus10/git-tidy) to produce structured commits with git trailers. Information from commit messages is used to generate release notes and bump the version properly. @@ -48,7 +52,7 @@ To check if your commits pass linting, do: make tidy-lint -Note, the above command lints every commit since branching from master. You can also run `make shell` and run `git tidy` commands inside the docker environment to do other flavors of `git tidy` commands. +Note, the above command lints every commit since branching from main. You can also run `make shell` and run `git tidy` commands inside the docker environment to do other flavors of `git tidy` commands. ## Documentation @@ -62,7 +66,7 @@ A shortcut for serving them is: ## Releases and Versioning -Anything that is merged into the master branch will be automatically deployed to PyPI. Documentation will be published to a ReadTheDocs at `https://{{ cookiecutter.repo_name }}.readthedocs.io/`. +Anything that is merged into the main branch will be automatically deployed to PyPI. Documentation will be published to a ReadTheDocs at `https://{{ cookiecutter.repo_name }}.readthedocs.io/`. The following files will be generated and should *not* be edited by a user: diff --git a/{{ cookiecutter.repo_name }}/docs/index.md b/{{ cookiecutter.repo_name }}/docs/index.md index 7b9e33d..0a22f44 100644 --- a/{{ cookiecutter.repo_name }}/docs/index.md +++ b/{{ cookiecutter.repo_name }}/docs/index.md @@ -4,4 +4,4 @@ Welcome to the docs for `{{ cookiecutter.repo_name }}`! It doesn't appear that t ## Compatibility -`{{ cookiecutter.repo_name }}` is compatible with Python 3.8 - 3.12, Django 3.2 - 5.0, Psycopg 2 - 3, and Postgres 12 - 16. +`{{ cookiecutter.repo_name }}` is compatible with Python 3.8 - 3.12{% if cookiecutter.is_django == "True" %}, Django 3.2 - 5.0, Psycopg 2 - 3, and Postgres 12 - 16{% endif %}. diff --git a/{{ cookiecutter.repo_name }}/docs/installation.md b/{{ cookiecutter.repo_name }}/docs/installation.md index a30d070..467bbec 100644 --- a/{{ cookiecutter.repo_name }}/docs/installation.md +++ b/{{ cookiecutter.repo_name }}/docs/installation.md @@ -4,4 +4,6 @@ Install `{{ cookiecutter.repo_name }}` with: pip3 install {{ cookiecutter.repo_name }} -After this, add `{{ cookiecutter.module_name }}` to the `INSTALLED_APPS` setting of your Django project. \ No newline at end of file +{% if cookiecutter.is_django == "True" -%} +After this, add `{{ cookiecutter.module_name }}` to the `INSTALLED_APPS` setting of your Django project. +{%- endif %} \ No newline at end of file diff --git a/{{ cookiecutter.repo_name }}/environment.yml b/{{ cookiecutter.repo_name }}/environment.yml index 42a4802..6e95d31 100644 --- a/{{ cookiecutter.repo_name }}/environment.yml +++ b/{{ cookiecutter.repo_name }}/environment.yml @@ -5,7 +5,11 @@ dependencies: - python==3.12.0 - poetry==1.6.1 - pip==23.2.1 + {%- if cookiecutter.is_django == "True" %} - postgresql==16.0 + {%- endif %} variables: + {%- if cookiecutter.is_django == "True" %} DATABASE_URL: "postgres://postgres@localhost:5432/{{ cookiecutter.module_name }}_local" + {%- endif %} EXEC_WRAPPER: "" diff --git a/{{ cookiecutter.repo_name }}/pyproject.toml b/{{ cookiecutter.repo_name }}/pyproject.toml index 0a5fefd..900efa5 100644 --- a/{{ cookiecutter.repo_name }}/pyproject.toml +++ b/{{ cookiecutter.repo_name }}/pyproject.toml @@ -30,12 +30,14 @@ version = "0.0.0" description = "{{ cookiecutter.short_description }}" authors = ["Opus 10 Engineering"] classifiers = [ + {%- if cookiecutter.is_django == "True" %} "Framework :: Django", "Framework :: Django :: 3.2", "Framework :: Django :: 4.0", "Framework :: Django :: 4.1", "Framework :: Django :: 4.2", "Framework :: Django :: 5.0", + {% endif %} "Intended Audience :: Developers", "Operating System :: OS Independent", "Programming Language :: Python", @@ -45,7 +47,9 @@ classifiers = [ "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3 :: Only", + {%- if cookiecutter.is_django == "True" %} "Framework :: Django", + {% endif %} ] license = "BSD-3-Clause" readme = "README.md" @@ -55,33 +59,41 @@ documentation = "https://{{ cookiecutter.repo_name }}.readthedocs.io" [tool.poetry.dependencies] python = ">=3.8.0,<4" +{%- if cookiecutter.is_django == "True" %} django = ">=3" +{%- endif %} [tool.poetry.dev-dependencies] -dj-database-url = "2.1.0" git-tidy = "1.2.0" -psycopg2-binary = "2.9.9" pytest = "7.4.2" pytest-cov = "4.1.0" pytest-dotenv = "0.5.2" -pytest-django = "4.5.2" -django-dynamic-fixture = "4.0.1" tox = "4.11.3" ruff = "0.3.7" pyright = "1.1.358" mkdocs = "1.5.3" -mkdocs-material = "9.4.4" -mkdocstrings-python = "1.7.2" +black = "24.4.0" +mkdocs-material = "9.5.18" +mkdocstrings-python = "1.9.2" footing = "*" setuptools = "*" poetry-core = "*" +typing-extensions = "*" +{%- if cookiecutter.is_django == "True" %} +dj-database-url = "2.1.0" +psycopg2-binary = "2.9.9" +pytest-django = "4.5.2" +django-dynamic-fixture = "4.0.1" +{% endif %} [tool.pytest.ini_options] xfail_strict = true -addopts = "--reuse-db" testpaths = "{{ cookiecutter.module_name }}/tests" norecursedirs = ".venv" +{%- if cookiecutter.is_django == "True" %} +addopts = "--reuse-db" DJANGO_SETTINGS_MODULE = "settings" +{%- endif %} [tool.ruff] lint.select = ["E", "F", "B", "I", "G", "C4"] @@ -94,6 +106,8 @@ exclude = [ "**/__pycache__", "src/experimental", "src/typestubs", + "**/migrations/**", + "**/tests/**", ] pythonVersion = "3.8" typeCheckingMode = "standard" diff --git a/{{ cookiecutter.repo_name }}/settings.py b/{{ cookiecutter.repo_name }}/settings.py index a9c7c48..e4a215b 100644 --- a/{{ cookiecutter.repo_name }}/settings.py +++ b/{{ cookiecutter.repo_name }}/settings.py @@ -14,3 +14,5 @@ DATABASES = {"default": dj_database_url.config()} DEFAULT_AUTO_FIELD = "django.db.models.AutoField" + +USE_TZ = False diff --git a/{{ cookiecutter.repo_name }}/tox.ini b/{{ cookiecutter.repo_name }}/tox.ini index 0afdb6a..1e216e1 100644 --- a/{{ cookiecutter.repo_name }}/tox.ini +++ b/{{ cookiecutter.repo_name }}/tox.ini @@ -1,5 +1,6 @@ [tox] isolated_build = true +{%- if cookiecutter.is_django == "True" %} envlist = py{38,39,310,311,312}-django32-psycopg2 py{38,39,310,311,312}-django42-psycopg2 @@ -7,33 +8,46 @@ envlist = py{310,311,312}-django50-psycopg2 py312-django50-psycopg3 report +{%- else %} +envlist = py{38,39,310,311},report +{%- endif %} [testenv] -install_command = pip install {opts} --no-compile {packages} -deps = - django32: Django>=3.2,<3.3 - django42: Django>=4.2,<4.3 - django50: Django>=5.0rc1,<5.1 - psycopg2: psycopg2-binary - psycopg3: psycopg[binary] allowlist_externals = poetry bash grep +skip_install = true passenv = DATABASE_URL PYTHONDONTWRITEBYTECODE -skip_install = true +{%- if cookiecutter.is_django == "True" %} +install_command = pip install {opts} --no-compile {packages} +deps = + django32: Django>=3.2,<3.3 + django42: Django>=4.2,<4.3 + django50: Django>=5.0rc1,<5.1 + psycopg2: psycopg2-binary + psycopg3: psycopg[binary] commands = bash -c 'poetry export --with dev --without-hashes -f requirements.txt | grep -v "^[dD]jango==" | grep -v "^psycopg2-binary==" | pip install --no-compile -q --no-deps -r /dev/stdin' pip install --no-compile -q --no-deps --no-build-isolation -e . pytest --create-db --cov --cov-fail-under=0 --cov-append --cov-config pyproject.toml {posargs} +{%- else %} +commands = + poetry install -v + pytest --cov --cov-fail-under=0 --cov-append --cov-config pyproject.toml {posargs} +{%- endif %} [testenv:report] allowlist_externals = coverage skip_install = true +{%- if cookiecutter.is_django == "True" %} depends = py{38,39,310,311,312}-django{32,42}-psycopg2,py312-django42-psycopg3-py{310,311,312}-django50-psycopg2-py312-django50-psycopg3 +{%- else %} +depends = py{38,39,310,311,312} +{%- endif %} parallel_show_output = true commands = coverage report --fail-under 100 diff --git a/{{ cookiecutter.repo_name }}/{{ cookiecutter.module_name }}/py.typed b/{{ cookiecutter.repo_name }}/{{ cookiecutter.module_name }}/py.typed new file mode 100644 index 0000000..e69de29