From 3693f356e702afad968cc0857ca0545c24d89dce Mon Sep 17 00:00:00 2001 From: hnthh Date: Mon, 27 Nov 2023 10:49:06 +0300 Subject: [PATCH 001/116] post gen project sh done --- Makefile | 9 +- hooks/post_gen_project.sh | 33 +- .../.github/workflows/ci.yml | 4 +- {{cookiecutter.project_slug}}/.python-version | 1 - {{cookiecutter.project_slug}}/Dockerfile | 2 +- {{cookiecutter.project_slug}}/Makefile | 34 +- {{cookiecutter.project_slug}}/README.md | 6 +- .../dev-requirements.txt | 342 ------------------ .../{src => }/mypy.ini | 10 +- {{cookiecutter.project_slug}}/mypy.ini~ | 51 +++ {{cookiecutter.project_slug}}/pyproject.toml | 220 +++++------ .../requirements.txt | 114 ------ .../src/.django-app-template/admin.py-tpl | 2 +- .../src/.django-app-template/api/urls.py-tpl | 2 +- .../api/views/app_name.py-tpl | 2 +- .../src/.django-app-template/apps.py-tpl | 2 +- .../src/.django-app-template/factory.py-tpl | 2 +- .../models/app_name.py-tpl | 2 +- {{cookiecutter.project_slug}}/src/app/.env | 3 - .../src/app/conf/environ.py | 13 - .../src/app/fixtures/__init__.py | 9 - .../src/app/fixtures/api.py | 14 - .../src/{ => apps}/a12n/__init__.py | 0 .../src/{ => apps}/a12n/api/serializers.py | 0 .../src/apps/a12n/api/throttling.py | 9 + .../a12n/api/throttling.py~} | 0 .../src/apps/a12n/api/urls.py | 10 + .../api/urls.py => apps/a12n/api/urls.py~} | 0 .../src/apps/a12n/api/views.py | 11 + .../api/views.py => apps/a12n/api/views.py~} | 0 .../{ => apps}/a12n/migrations/__init__.py | 0 .../src/apps/a12n/utils.py | 13 + .../{a12n/utils.py => apps/a12n/utils.py~} | 0 .../src/{app => apps/users}/__init__.py | 0 .../src/apps/users/admin.py | 6 + .../{users/admin.py => apps/users/admin.py~} | 0 .../src/apps/users/api/serializers.py | 21 ++ .../users/api/serializers.py~} | 0 .../src/apps/users/api/urls.py | 9 + .../api/urls.py => apps/users/api/urls.py~} | 2 +- .../src/apps/users/api/viewsets.py | 26 ++ .../users/api/viewsets.py~} | 0 .../users/migrations/0001_initial.py | 0 .../users/migrations}/__init__.py | 0 .../src/{ => apps}/users/models.py | 0 {{cookiecutter.project_slug}}/src/conftest.py | 6 - .../src/{app => core}/.env.ci | 0 .../{app/tests/testing => core}/__init__.py | 0 .../src/core/admin/README.md | 15 + .../admin/README.md => core/admin/README.md~} | 0 .../src/core/admin/__init__.py | 8 + .../__init__.py => core/admin/__init__.py~} | 0 .../src/{app => core}/admin/model_admin.py | 0 .../src/{app => core}/api/pagination.py | 0 .../src/{app => core}/api/renderers.py | 0 .../src/{app => core}/api/throttling.py | 0 .../src/{app => core}/api/viewsets.py | 0 .../src/core/asgi.py | 16 + .../src/{app/asgi.py => core/asgi.py~} | 0 .../src/{app => core}/base_config.py | 0 .../src/core/conf/api.py | 51 +++ .../{app/conf/api.py => core/conf/api.py~} | 2 +- .../src/core/conf/auth.py | 34 ++ .../{app/conf/auth.py => core/conf/auth.py~} | 0 .../src/core/conf/boilerplate.py | 10 + .../conf/boilerplate.py~} | 4 +- .../src/core/conf/db.py | 12 + .../src/{app/conf/db.py => core/conf/db.py~} | 0 .../src/core/conf/environ.py | 18 + .../src/core/conf/environ.py~ | 18 + .../src/{app => core}/conf/healthchecks.py | 0 .../src/core/conf/http.py | 11 + .../{app/conf/http.py => core/conf/http.py~} | 0 .../src/{app => core}/conf/i18n.py | 0 .../src/core/conf/installed_apps.py | 25 ++ .../conf/installed_apps.py~} | 0 .../src/core/conf/media.py | 4 + .../conf/media.py => core/conf/media.py~} | 0 .../src/core/conf/middleware.py | 12 + .../conf/middleware.py~} | 0 .../src/core/conf/sentry.py | 15 + .../conf/sentry.py => core/conf/sentry.py~} | 0 .../src/core/conf/static.py | 7 + .../conf/static.py => core/conf/static.py~} | 0 .../src/core/conf/storage.py | 10 + .../conf/storage.py => core/conf/storage.py~} | 0 .../src/{app => core}/conf/templates.py | 0 .../src/{app => core}/conf/timezone.py | 0 .../src/{app => core}/locale/.gitkeep | 0 .../management/commands/makemigrations.py | 0 .../management/commands/startapp.py | 0 .../src/{app => core}/middleware/real_ip.py | 0 .../src/{app => core}/models.py | 0 .../src/{app => core}/services.py | 0 .../src/core/settings.py | 32 ++ .../{app/settings.py => core/settings.py~} | 0 .../src/core/testing/__init__.py | 9 + .../__init__.py => core/testing/__init__.py~} | 0 .../src/core/testing/api.py | 79 ++++ .../testing/api.py => core/testing/api.py~} | 0 .../src/core/testing/factory.py | 46 +++ .../factory.py => core/testing/factory.py~} | 0 .../src/{app => core}/testing/mixer.py | 0 .../src/{app => core}/testing/runner.py | 0 .../src/{app => core}/testing/types.py | 0 .../src/core/urls/__init__.py | 12 + .../__init__.py => core/urls/__init__.py~} | 0 .../src/{app => core}/urls/v1.py | 5 +- .../src/core/urls/v1.py~ | 15 + .../src/core/wsgi.py | 16 + .../src/{app/wsgi.py => core/wsgi.py~} | 0 {{cookiecutter.project_slug}}/src/manage.py | 2 +- .../testing/factory => tests}/__init__.py | 0 .../a12n}/jwt_views/test_obtain_jwt_view.py | 0 .../a12n/jwt_views/test_refresh_jwt_token.py | 72 ++++ .../jwt_views/test_refresh_jwt_token.py~} | 0 .../apps/users/conftest.py~} | 2 +- .../tests/apps/users/factory.py | 15 + .../apps/users/factory.py~} | 0 .../tests/apps/users/fixtures.py | 12 + .../tests/apps/users/test_password_hashing.py | 15 + .../apps/users/test_password_hashing.py~} | 0 .../tests => tests/apps/users}/test_whoami.py | 0 .../tests/conftest.py | 9 + .../tests/conftest.py~ | 9 + .../{src/users => tests/core}/__init__.py | 0 .../factory.py => tests/core/conftest.py~} | 0 .../tests/core/factory.py | 13 + .../app/factory.py => tests/core/factory.py~} | 0 .../tests/core/fixtures.py | 24 ++ .../tests/core/fixtures.py~ | 23 ++ .../app/tests => tests/core}/test_health.py | 0 .../core}/test_remote_addr_midlleware.py | 4 +- .../core/test_remote_addr_midlleware.py~ | 30 ++ .../core/testing}/__init__.py | 0 .../tests/core/testing/factory/__init__.py | 0 .../core/testing/factory/test_factory.py | 42 +++ .../core/testing/factory/test_factory.py~} | 0 .../core/testing/factory/test_registry.py | 24 ++ .../core/testing/factory/test_registry.py~} | 0 140 files changed, 1066 insertions(+), 706 deletions(-) delete mode 100644 {{cookiecutter.project_slug}}/.python-version delete mode 100644 {{cookiecutter.project_slug}}/dev-requirements.txt rename {{cookiecutter.project_slug}}/{src => }/mypy.ini (87%) create mode 100644 {{cookiecutter.project_slug}}/mypy.ini~ delete mode 100644 {{cookiecutter.project_slug}}/requirements.txt delete mode 100644 {{cookiecutter.project_slug}}/src/app/.env delete mode 100644 {{cookiecutter.project_slug}}/src/app/conf/environ.py delete mode 100644 {{cookiecutter.project_slug}}/src/app/fixtures/__init__.py delete mode 100644 {{cookiecutter.project_slug}}/src/app/fixtures/api.py rename {{cookiecutter.project_slug}}/src/{ => apps}/a12n/__init__.py (100%) rename {{cookiecutter.project_slug}}/src/{ => apps}/a12n/api/serializers.py (100%) create mode 100644 {{cookiecutter.project_slug}}/src/apps/a12n/api/throttling.py rename {{cookiecutter.project_slug}}/src/{a12n/api/throttling.py => apps/a12n/api/throttling.py~} (100%) create mode 100644 {{cookiecutter.project_slug}}/src/apps/a12n/api/urls.py rename {{cookiecutter.project_slug}}/src/{a12n/api/urls.py => apps/a12n/api/urls.py~} (100%) create mode 100644 {{cookiecutter.project_slug}}/src/apps/a12n/api/views.py rename {{cookiecutter.project_slug}}/src/{a12n/api/views.py => apps/a12n/api/views.py~} (100%) rename {{cookiecutter.project_slug}}/src/{ => apps}/a12n/migrations/__init__.py (100%) create mode 100644 {{cookiecutter.project_slug}}/src/apps/a12n/utils.py rename {{cookiecutter.project_slug}}/src/{a12n/utils.py => apps/a12n/utils.py~} (100%) rename {{cookiecutter.project_slug}}/src/{app => apps/users}/__init__.py (100%) create mode 100644 {{cookiecutter.project_slug}}/src/apps/users/admin.py rename {{cookiecutter.project_slug}}/src/{users/admin.py => apps/users/admin.py~} (100%) create mode 100644 {{cookiecutter.project_slug}}/src/apps/users/api/serializers.py rename {{cookiecutter.project_slug}}/src/{users/api/serializers.py => apps/users/api/serializers.py~} (100%) create mode 100644 {{cookiecutter.project_slug}}/src/apps/users/api/urls.py rename {{cookiecutter.project_slug}}/src/{users/api/urls.py => apps/users/api/urls.py~} (76%) create mode 100644 {{cookiecutter.project_slug}}/src/apps/users/api/viewsets.py rename {{cookiecutter.project_slug}}/src/{users/api/viewsets.py => apps/users/api/viewsets.py~} (100%) rename {{cookiecutter.project_slug}}/src/{ => apps}/users/migrations/0001_initial.py (100%) rename {{cookiecutter.project_slug}}/src/{app/tests => apps/users/migrations}/__init__.py (100%) rename {{cookiecutter.project_slug}}/src/{ => apps}/users/models.py (100%) delete mode 100644 {{cookiecutter.project_slug}}/src/conftest.py rename {{cookiecutter.project_slug}}/src/{app => core}/.env.ci (100%) rename {{cookiecutter.project_slug}}/src/{app/tests/testing => core}/__init__.py (100%) create mode 100644 {{cookiecutter.project_slug}}/src/core/admin/README.md rename {{cookiecutter.project_slug}}/src/{app/admin/README.md => core/admin/README.md~} (100%) create mode 100644 {{cookiecutter.project_slug}}/src/core/admin/__init__.py rename {{cookiecutter.project_slug}}/src/{app/admin/__init__.py => core/admin/__init__.py~} (100%) rename {{cookiecutter.project_slug}}/src/{app => core}/admin/model_admin.py (100%) rename {{cookiecutter.project_slug}}/src/{app => core}/api/pagination.py (100%) rename {{cookiecutter.project_slug}}/src/{app => core}/api/renderers.py (100%) rename {{cookiecutter.project_slug}}/src/{app => core}/api/throttling.py (100%) rename {{cookiecutter.project_slug}}/src/{app => core}/api/viewsets.py (100%) create mode 100644 {{cookiecutter.project_slug}}/src/core/asgi.py rename {{cookiecutter.project_slug}}/src/{app/asgi.py => core/asgi.py~} (100%) rename {{cookiecutter.project_slug}}/src/{app => core}/base_config.py (100%) create mode 100644 {{cookiecutter.project_slug}}/src/core/conf/api.py rename {{cookiecutter.project_slug}}/src/{app/conf/api.py => core/conf/api.py~} (98%) create mode 100644 {{cookiecutter.project_slug}}/src/core/conf/auth.py rename {{cookiecutter.project_slug}}/src/{app/conf/auth.py => core/conf/auth.py~} (100%) create mode 100644 {{cookiecutter.project_slug}}/src/core/conf/boilerplate.py rename {{cookiecutter.project_slug}}/src/{app/conf/boilerplate.py => core/conf/boilerplate.py~} (71%) create mode 100644 {{cookiecutter.project_slug}}/src/core/conf/db.py rename {{cookiecutter.project_slug}}/src/{app/conf/db.py => core/conf/db.py~} (100%) create mode 100644 {{cookiecutter.project_slug}}/src/core/conf/environ.py create mode 100644 {{cookiecutter.project_slug}}/src/core/conf/environ.py~ rename {{cookiecutter.project_slug}}/src/{app => core}/conf/healthchecks.py (100%) create mode 100644 {{cookiecutter.project_slug}}/src/core/conf/http.py rename {{cookiecutter.project_slug}}/src/{app/conf/http.py => core/conf/http.py~} (100%) rename {{cookiecutter.project_slug}}/src/{app => core}/conf/i18n.py (100%) create mode 100644 {{cookiecutter.project_slug}}/src/core/conf/installed_apps.py rename {{cookiecutter.project_slug}}/src/{app/conf/installed_apps.py => core/conf/installed_apps.py~} (100%) create mode 100644 {{cookiecutter.project_slug}}/src/core/conf/media.py rename {{cookiecutter.project_slug}}/src/{app/conf/media.py => core/conf/media.py~} (100%) create mode 100644 {{cookiecutter.project_slug}}/src/core/conf/middleware.py rename {{cookiecutter.project_slug}}/src/{app/conf/middleware.py => core/conf/middleware.py~} (100%) create mode 100644 {{cookiecutter.project_slug}}/src/core/conf/sentry.py rename {{cookiecutter.project_slug}}/src/{app/conf/sentry.py => core/conf/sentry.py~} (100%) create mode 100644 {{cookiecutter.project_slug}}/src/core/conf/static.py rename {{cookiecutter.project_slug}}/src/{app/conf/static.py => core/conf/static.py~} (100%) create mode 100644 {{cookiecutter.project_slug}}/src/core/conf/storage.py rename {{cookiecutter.project_slug}}/src/{app/conf/storage.py => core/conf/storage.py~} (100%) rename {{cookiecutter.project_slug}}/src/{app => core}/conf/templates.py (100%) rename {{cookiecutter.project_slug}}/src/{app => core}/conf/timezone.py (100%) rename {{cookiecutter.project_slug}}/src/{app => core}/locale/.gitkeep (100%) rename {{cookiecutter.project_slug}}/src/{app => core}/management/commands/makemigrations.py (100%) rename {{cookiecutter.project_slug}}/src/{app => core}/management/commands/startapp.py (100%) rename {{cookiecutter.project_slug}}/src/{app => core}/middleware/real_ip.py (100%) rename {{cookiecutter.project_slug}}/src/{app => core}/models.py (100%) rename {{cookiecutter.project_slug}}/src/{app => core}/services.py (100%) create mode 100644 {{cookiecutter.project_slug}}/src/core/settings.py rename {{cookiecutter.project_slug}}/src/{app/settings.py => core/settings.py~} (100%) create mode 100644 {{cookiecutter.project_slug}}/src/core/testing/__init__.py rename {{cookiecutter.project_slug}}/src/{app/testing/__init__.py => core/testing/__init__.py~} (100%) create mode 100644 {{cookiecutter.project_slug}}/src/core/testing/api.py rename {{cookiecutter.project_slug}}/src/{app/testing/api.py => core/testing/api.py~} (100%) create mode 100644 {{cookiecutter.project_slug}}/src/core/testing/factory.py rename {{cookiecutter.project_slug}}/src/{app/testing/factory.py => core/testing/factory.py~} (100%) rename {{cookiecutter.project_slug}}/src/{app => core}/testing/mixer.py (100%) rename {{cookiecutter.project_slug}}/src/{app => core}/testing/runner.py (100%) rename {{cookiecutter.project_slug}}/src/{app => core}/testing/types.py (100%) create mode 100644 {{cookiecutter.project_slug}}/src/core/urls/__init__.py rename {{cookiecutter.project_slug}}/src/{app/urls/__init__.py => core/urls/__init__.py~} (100%) rename {{cookiecutter.project_slug}}/src/{app => core}/urls/v1.py (80%) create mode 100644 {{cookiecutter.project_slug}}/src/core/urls/v1.py~ create mode 100644 {{cookiecutter.project_slug}}/src/core/wsgi.py rename {{cookiecutter.project_slug}}/src/{app/wsgi.py => core/wsgi.py~} (100%) rename {{cookiecutter.project_slug}}/{src/app/tests/testing/factory => tests}/__init__.py (100%) rename {{cookiecutter.project_slug}}/{src/a12n/tests => tests/apps/a12n}/jwt_views/test_obtain_jwt_view.py (100%) create mode 100644 {{cookiecutter.project_slug}}/tests/apps/a12n/jwt_views/test_refresh_jwt_token.py rename {{cookiecutter.project_slug}}/{src/a12n/tests/jwt_views/test_refresh_jwt_token.py => tests/apps/a12n/jwt_views/test_refresh_jwt_token.py~} (100%) rename {{cookiecutter.project_slug}}/{src/users/fixtures.py => tests/apps/users/conftest.py~} (85%) create mode 100644 {{cookiecutter.project_slug}}/tests/apps/users/factory.py rename {{cookiecutter.project_slug}}/{src/users/factory.py => tests/apps/users/factory.py~} (100%) create mode 100644 {{cookiecutter.project_slug}}/tests/apps/users/fixtures.py create mode 100644 {{cookiecutter.project_slug}}/tests/apps/users/test_password_hashing.py rename {{cookiecutter.project_slug}}/{src/users/tests/test_password_hashing.py => tests/apps/users/test_password_hashing.py~} (100%) rename {{cookiecutter.project_slug}}/{src/users/tests => tests/apps/users}/test_whoami.py (100%) create mode 100644 {{cookiecutter.project_slug}}/tests/conftest.py create mode 100644 {{cookiecutter.project_slug}}/tests/conftest.py~ rename {{cookiecutter.project_slug}}/{src/users => tests/core}/__init__.py (100%) rename {{cookiecutter.project_slug}}/{src/app/fixtures/factory.py => tests/core/conftest.py~} (100%) create mode 100644 {{cookiecutter.project_slug}}/tests/core/factory.py rename {{cookiecutter.project_slug}}/{src/app/factory.py => tests/core/factory.py~} (100%) create mode 100644 {{cookiecutter.project_slug}}/tests/core/fixtures.py create mode 100644 {{cookiecutter.project_slug}}/tests/core/fixtures.py~ rename {{cookiecutter.project_slug}}/{src/app/tests => tests/core}/test_health.py (100%) rename {{cookiecutter.project_slug}}/{src/app/tests => tests/core}/test_remote_addr_midlleware.py (91%) create mode 100644 {{cookiecutter.project_slug}}/tests/core/test_remote_addr_midlleware.py~ rename {{cookiecutter.project_slug}}/{src/users/migrations => tests/core/testing}/__init__.py (100%) create mode 100644 {{cookiecutter.project_slug}}/tests/core/testing/factory/__init__.py create mode 100644 {{cookiecutter.project_slug}}/tests/core/testing/factory/test_factory.py rename {{cookiecutter.project_slug}}/{src/app/tests/testing/factory/test_factory.py => tests/core/testing/factory/test_factory.py~} (100%) create mode 100644 {{cookiecutter.project_slug}}/tests/core/testing/factory/test_registry.py rename {{cookiecutter.project_slug}}/{src/app/tests/testing/factory/test_registry.py => tests/core/testing/factory/test_registry.py~} (100%) diff --git a/Makefile b/Makefile index cf65296f..b5e09466 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,15 @@ -VENV=cd testproject/django/src && ../venv/bin/python +VENV=cd testproject/django && poetry run python src/manage.py test: bootstrap - $(VENV) ./manage.py makemigrations --check - $(VENV) ./manage.py startapp test_app + $(VENV) makemigrations --check + $(VENV) startapp test_app bootstrap: rm -Rf testproject mkdir -p testproject + cd testproject && cookiecutter --no-input ../ coverage: $(VENV) -m pip install pytest-cov - $(VENV) -m pytest --cov-report=xml --cov=app --cov=users --cov=a12n --cov=sepulkas + $(VENV) -m pytest --cov-report=xml --cov=core --cov=users --cov=a12n --cov=sepulkas diff --git a/hooks/post_gen_project.sh b/hooks/post_gen_project.sh index 926215f4..f1face43 100644 --- a/hooks/post_gen_project.sh +++ b/hooks/post_gen_project.sh @@ -1,33 +1,10 @@ #!/bin/bash -e -echo -ne "Running with " +cp src/core/.env.ci src/core/.env -python --version +poetry install -echo Creating and populating virtualenv.. +poetry run python src/manage.py collectstatic +poetry run python src/manage.py migrate -python -m venv venv -. venv/bin/activate - -pip install --upgrade pip pip-tools wheel -make - -cd src - -echo Collecting static assets... -./manage.py collectstatic - -echo Running initial migrations... -./manage.py migrate - -cd ../ -echo Apply formatting.. -make fmt - -echo Running flake8.. -make lint - -echo Running pytest... -make test - -echo Done +make fmt lint test diff --git a/{{cookiecutter.project_slug}}/.github/workflows/ci.yml b/{{cookiecutter.project_slug}}/.github/workflows/ci.yml index 95458b84..2e5c3e69 100644 --- a/{{cookiecutter.project_slug}}/.github/workflows/ci.yml +++ b/{{cookiecutter.project_slug}}/.github/workflows/ci.yml @@ -31,7 +31,7 @@ jobs: - name: Run the linter run: | . venv/bin/activate - cp src/app/.env.ci src/app/.env + cp src/core/.env.ci src/core/.env make lint test: @@ -73,5 +73,5 @@ jobs: run: | . venv/bin/activate - cp src/app/.env.ci src/app/.env + cp src/core/.env.ci src/core/.env make test diff --git a/{{cookiecutter.project_slug}}/.python-version b/{{cookiecutter.project_slug}}/.python-version deleted file mode 100644 index 375f5cab..00000000 --- a/{{cookiecutter.project_slug}}/.python-version +++ /dev/null @@ -1 +0,0 @@ -3.11.6 diff --git a/{{cookiecutter.project_slug}}/Dockerfile b/{{cookiecutter.project_slug}}/Dockerfile index 6b277cb1..6c3eb8c1 100644 --- a/{{cookiecutter.project_slug}}/Dockerfile +++ b/{{cookiecutter.project_slug}}/Dockerfile @@ -43,4 +43,4 @@ ENV DD_VERSION ${RELEASE} USER nobody -CMD uwsgi --master --http :8000 --module app.wsgi --workers 2 --threads 2 --harakiri 25 --max-requests 1000 --log-x-forwarded-for --buffer-size 32000 +CMD uwsgi --master --http :8000 --module core.wsgi --workers 2 --threads 2 --harakiri 25 --max-requests 1000 --log-x-forwarded-for --buffer-size 32000 diff --git a/{{cookiecutter.project_slug}}/Makefile b/{{cookiecutter.project_slug}}/Makefile index 0e04bbac..41117427 100644 --- a/{{cookiecutter.project_slug}}/Makefile +++ b/{{cookiecutter.project_slug}}/Makefile @@ -1,31 +1,21 @@ -install-dev-deps: dev-deps - pip-sync requirements.txt dev-requirements.txt - -install-deps: deps - pip-sync requirements.txt - -deps: - pip-compile --resolver=backtracking --output-file=requirements.txt pyproject.toml - -dev-deps: deps - pip-compile --resolver=backtracking --extra=dev --output-file=dev-requirements.txt pyproject.toml +manage = poetry run src/manage.py fmt: - cd src && autoflake --in-place --remove-all-unused-imports --recursive . - cd src && isort . - cd src && black . + poetry run autoflake --in-place --remove-all-unused-imports --recursive src tests + poetry run black src tests lint: - dotenv-linter src/app/.env.ci - cd src && ./manage.py check - flake8 src - cd src && mypy + $(manage) check + poetry run flake8 src tests + poetry run mypy src tests + poetry run dotenv-linter src/core/.env.ci test: mkdir -p src/static - cd src && ./manage.py makemigrations --dry-run --no-input --check - cd src && ./manage.py compilemessages - cd src && pytest --dead-fixtures - cd src && pytest -x + + $(manage) makemigrations --dry-run --no-input --check + $(manage) compilemessages + poetry run pytest --dead-fixtures + poetry run pytest -x pr: fmt lint test diff --git a/{{cookiecutter.project_slug}}/README.md b/{{cookiecutter.project_slug}}/README.md index 48002eb6..4a0074b7 100644 --- a/{{cookiecutter.project_slug}}/README.md +++ b/{{cookiecutter.project_slug}}/README.md @@ -4,9 +4,9 @@ This project is bootstrapped using [fandsdev/django](http://github.com/fandsdev/ ## Project structure -The main django app is called `app`. It contains `.env` file for django-environ. For examples see `src/app/.env.ci`. Here are some usefull app-wide tools: +The main django app is called `app`. It contains `.env` file for django-environ. For examples see `src/core/.env.ci`. Here are some usefull app-wide tools: * `app.admin` — app-wide django-admin customizations (empty yet), check out usage [examples](https://github.com/f213/django/tree/master/%7B%7Bcookiecutter.project_slug%7D%7D/src/app/admin) -* `app.test.api_client` (available as `api` and `anon` fixtures within pytest) — a [convinient DRF test client](https://github.com/f213/django/blob/master/%7B%7Bcookiecutter.project_slug%7D%7D/src/users/tests/tests_whoami.py#L6-L16). +* `core.test.api_client` (available as `api` and `anon` fixtures within pytest) — a [convinient DRF test client](https://github.com/f213/django/blob/master/%7B%7Bcookiecutter.project_slug%7D%7D/src/users/tests/tests_whoami.py#L6-L16). Django user model is located in the separate `users` app. @@ -25,7 +25,7 @@ $ make Run the server: ```bash -$ cd src && cp app/.env.ci app/.env # default environment variables +$ cd src && cp core/.env.ci core/.env # default environment variables $ ./manage.py migrate $ ./manage.py createsuperuser $ ./manage.py runserver diff --git a/{{cookiecutter.project_slug}}/dev-requirements.txt b/{{cookiecutter.project_slug}}/dev-requirements.txt deleted file mode 100644 index 201c8d2b..00000000 --- a/{{cookiecutter.project_slug}}/dev-requirements.txt +++ /dev/null @@ -1,342 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.11 -# by the following command: -# -# pip-compile --extra=dev --output-file=dev-requirements.txt pyproject.toml -# -appnope==0.1.3 - # via ipython -asgiref==3.7.2 - # via django -astor==0.8.1 - # via flake8-simplify -astroid==2.15.8 - # via flake8-django -asttokens==2.4.1 - # via stack-data -attrs==23.1.0 - # via - # dotenv-linter - # flake8-bugbear - # flake8-eradicate - # jsonschema - # referencing -autoflake==1.7.0 - # via django (pyproject.toml) -bcrypt==4.0.1 - # via django (pyproject.toml) -black==23.11.0 - # via - # django (pyproject.toml) - # flake8-black -certifi==2023.11.17 - # via - # django-healthchecks - # requests - # sentry-sdk -cffi==1.16.0 - # via cryptography -charset-normalizer==3.3.2 - # via requests -click==8.1.7 - # via - # black - # click-default-group - # dotenv-linter -click-default-group==1.2.4 - # via dotenv-linter -cognitive-complexity==1.3.0 - # via flake8-cognitive-complexity -cryptography==41.0.5 - # via pyjwt -decorator==5.1.1 - # via ipython -django==4.2.7 - # via - # django (pyproject.toml) - # django-axes - # django-filter - # django-healthchecks - # django-storages - # django-stubs - # django-stubs-ext - # djangorestframework - # drf-jwt - # drf-spectacular - # drf-spectacular-sidecar -django-axes==6.1.1 - # via django (pyproject.toml) -django-behaviors==0.5.1 - # via django (pyproject.toml) -django-environ==0.11.2 - # via django (pyproject.toml) -django-filter==23.4 - # via django (pyproject.toml) -django-healthchecks==1.5.0 - # via django (pyproject.toml) -django-ipware==5.0.2 - # via django (pyproject.toml) -django-split-settings==1.2.0 - # via django (pyproject.toml) -django-storages==1.14.2 - # via django (pyproject.toml) -django-stubs==4.2.6 - # via - # django (pyproject.toml) - # djangorestframework-stubs -django-stubs-ext==4.2.5 - # via django-stubs -djangorestframework==3.14.0 - # via - # django (pyproject.toml) - # drf-jwt - # drf-spectacular -djangorestframework-camel-case==1.4.2 - # via django (pyproject.toml) -djangorestframework-stubs==3.14.4 - # via django (pyproject.toml) -dotenv-linter==0.4.0 - # via django (pyproject.toml) -drf-jwt==1.19.2 - # via django (pyproject.toml) -drf-spectacular[sidecar]==0.26.5 - # via django (pyproject.toml) -drf-spectacular-sidecar==2023.10.1 - # via drf-spectacular -eradicate==2.3.0 - # via flake8-eradicate -executing==2.0.1 - # via stack-data -faker==12.0.1 - # via mixer -flake8==6.1.0 - # via - # flake8-absolute-import - # flake8-black - # flake8-bugbear - # flake8-django - # flake8-eradicate - # flake8-isort - # flake8-pep3101 - # flake8-print - # flake8-printf-formatting - # flake8-pyproject - # flake8-pytest - # flake8-simplify - # flake8-use-fstring - # flake8-walrus -flake8-absolute-import==1.0.0.2 - # via django (pyproject.toml) -flake8-black==0.3.6 - # via django (pyproject.toml) -flake8-bugbear==23.9.16 - # via django (pyproject.toml) -flake8-cognitive-complexity==0.1.0 - # via django (pyproject.toml) -flake8-django==1.4 - # via django (pyproject.toml) -flake8-eradicate==1.5.0 - # via django (pyproject.toml) -flake8-fixme==1.1.1 - # via django (pyproject.toml) -flake8-isort==6.1.1 - # via django (pyproject.toml) -flake8-pep3101==2.1.0 - # via django (pyproject.toml) -flake8-pie==0.16.0 - # via django (pyproject.toml) -flake8-plugin-utils==1.3.3 - # via flake8-pytest-style -flake8-print==5.0.0 - # via django (pyproject.toml) -flake8-printf-formatting==1.1.2 - # via django (pyproject.toml) -flake8-pyproject==1.2.3 - # via django (pyproject.toml) -flake8-pytest==1.4 - # via django (pyproject.toml) -flake8-pytest-style==1.7.2 - # via django (pyproject.toml) -flake8-simplify==0.21.0 - # via django (pyproject.toml) -flake8-todo==0.7 - # via django (pyproject.toml) -flake8-use-fstring==1.4 - # via django (pyproject.toml) -flake8-variables-names==0.0.6 - # via django (pyproject.toml) -flake8-walrus==1.2.0 - # via django (pyproject.toml) -freezegun==1.2.2 - # via - # django (pyproject.toml) - # pytest-freezegun -idna==3.4 - # via requests -inflection==0.5.1 - # via drf-spectacular -iniconfig==2.0.0 - # via pytest -ipython==8.17.2 - # via django (pyproject.toml) -isort==5.12.0 - # via flake8-isort -jedi==0.19.1 - # via - # django (pyproject.toml) - # ipython -jsonschema==4.20.0 - # via drf-spectacular -jsonschema-specifications==2023.11.1 - # via jsonschema -lazy-object-proxy==1.9.0 - # via astroid -matplotlib-inline==0.1.6 - # via ipython -mccabe==0.7.0 - # via flake8 -mixer==7.2.2 - # via django (pyproject.toml) -mypy==1.7.0 - # via - # django (pyproject.toml) - # djangorestframework-stubs -mypy-extensions==1.0.0 - # via - # black - # mypy -packaging==23.2 - # via - # black - # pytest -parso==0.8.3 - # via jedi -pathspec==0.11.2 - # via black -pexpect==4.8.0 - # via ipython -pillow==10.1.0 - # via django (pyproject.toml) -platformdirs==4.0.0 - # via black -pluggy==1.3.0 - # via pytest -ply==3.11 - # via dotenv-linter -prompt-toolkit==3.0.41 - # via ipython -psycopg2-binary==2.9.9 - # via django (pyproject.toml) -ptyprocess==0.7.0 - # via pexpect -pure-eval==0.2.2 - # via stack-data -pycodestyle==2.11.1 - # via - # flake8 - # flake8-print - # flake8-todo -pycparser==2.21 - # via cffi -pyflakes==3.1.0 - # via - # autoflake - # flake8 -pygments==2.17.1 - # via ipython -pyjwt[crypto]==2.8.0 - # via - # drf-jwt - # pyjwt -pytest==7.4.3 - # via - # pytest-deadfixtures - # pytest-django - # pytest-env - # pytest-freezegun - # pytest-mock - # pytest-randomly -pytest-deadfixtures==2.2.1 - # via django (pyproject.toml) -pytest-django==4.7.0 - # via django (pyproject.toml) -pytest-env==1.1.1 - # via django (pyproject.toml) -pytest-freezegun==0.4.2 - # via django (pyproject.toml) -pytest-mock==3.12.0 - # via django (pyproject.toml) -pytest-randomly==3.15.0 - # via django (pyproject.toml) -python-dateutil==2.8.2 - # via - # faker - # freezegun -pytz==2023.3.post1 - # via djangorestframework -pyyaml==6.0.1 - # via drf-spectacular -redis==5.0.1 - # via django (pyproject.toml) -referencing==0.31.0 - # via - # jsonschema - # jsonschema-specifications -requests==2.31.0 - # via - # django-healthchecks - # djangorestframework-stubs -rpds-py==0.13.1 - # via - # jsonschema - # referencing -sentry-sdk==1.35.0 - # via django (pyproject.toml) -six==1.16.0 - # via - # asttokens - # python-dateutil -sqlparse==0.4.4 - # via django -stack-data==0.6.3 - # via ipython -traitlets==5.13.0 - # via - # ipython - # matplotlib-inline -types-freezegun==1.1.10 - # via django (pyproject.toml) -types-pillow==10.1.0.2 - # via django (pyproject.toml) -types-pytz==2023.3.1.1 - # via django-stubs -types-pyyaml==6.0.12.12 - # via - # django-stubs - # djangorestframework-stubs -types-requests==2.31.0.10 - # via djangorestframework-stubs -typing-extensions==4.8.0 - # via - # django-stubs - # django-stubs-ext - # djangorestframework-stubs - # dotenv-linter - # flake8-pie - # mypy -uritemplate==4.1.1 - # via drf-spectacular -urllib3==2.1.0 - # via - # requests - # sentry-sdk - # types-requests -wcwidth==0.2.11 - # via prompt-toolkit -whitenoise==6.6.0 - # via django (pyproject.toml) -wrapt==1.16.0 - # via astroid - -# The following packages are considered to be unsafe in a requirements file: -# setuptools diff --git a/{{cookiecutter.project_slug}}/src/mypy.ini b/{{cookiecutter.project_slug}}/mypy.ini similarity index 87% rename from {{cookiecutter.project_slug}}/src/mypy.ini rename to {{cookiecutter.project_slug}}/mypy.ini index bca1220b..7c220768 100644 --- a/{{cookiecutter.project_slug}}/src/mypy.ini +++ b/{{cookiecutter.project_slug}}/mypy.ini @@ -1,6 +1,6 @@ [mypy] -python_version = 3.10 -files = . +python_version = 3.11 +mypy_path = src namespace_packages = on explicit_package_bases = on warn_no_return = off @@ -20,15 +20,15 @@ plugins = mypy_django_plugin.main [mypy.plugins.django-stubs] -django_settings_module = "app.settings" +django_settings_module = "core.settings" [mypy-rest_framework_jwt.*] ignore_missing_imports = on -[mypy-app.testing.api.*] +[mypy-core.testing.api.*] disallow_untyped_defs = off -[mypy-*.tests.*] +[mypy-tests.*] disallow_untyped_defs = off [mypy-*.management.*] diff --git a/{{cookiecutter.project_slug}}/mypy.ini~ b/{{cookiecutter.project_slug}}/mypy.ini~ new file mode 100644 index 00000000..53c339e6 --- /dev/null +++ b/{{cookiecutter.project_slug}}/mypy.ini~ @@ -0,0 +1,51 @@ +[mypy] +python_version = 3.11 +mypy_path = src +namespace_packages = on +explicit_package_bases = on +warn_no_return = off +warn_unused_configs = on +warn_unused_ignores = on +warn_redundant_casts = on +no_implicit_optional = on +no_implicit_reexport = on +strict_equality = on +warn_unreachable = on +disallow_untyped_calls = on +disallow_untyped_defs = on +exclude = migrations/ + +plugins = + mypy_drf_plugin.main, + mypy_django_plugin.main + +[mypy.plugins.django-stubs] +django_settings_module = "core.settings" + +[mypy-rest_framework_jwt.*] +ignore_missing_imports = on + +[mypy-core.testing.api.*] +disallow_untyped_defs = off + +[mypy-*.tests.*] +disallow_untyped_defs = off + +[mypy-*.management.*] +disallow_untyped_defs = off + +[mypy-djangorestframework_camel_case.*] +ignore_missing_imports = on + +[mypy-django_filters.*] +ignore_missing_imports = on + +[mypy-axes.*] +ignore_missing_imports = on + +[mypy-mixer.*] +ignore_missing_imports = on + +[mypy-ipware.*] +ignore_missing_imports = on + diff --git a/{{cookiecutter.project_slug}}/pyproject.toml b/{{cookiecutter.project_slug}}/pyproject.toml index 8d7f7da3..d8af9f37 100644 --- a/{{cookiecutter.project_slug}}/pyproject.toml +++ b/{{cookiecutter.project_slug}}/pyproject.toml @@ -1,135 +1,109 @@ -[project] -name = "{{cookiecutter.project_slug}}" -version = "{{cookiecutter.project_version}}" -dependencies = [ - "Django<4.3", - "bcrypt", - "django-behaviors", - "django-environ", - "django-ipware", - "django-axes", - "whitenoise", - "django-storages", - "djangorestframework", - "djangorestframework-camel-case", - "drf-jwt", - "drf-spectacular[sidecar]", - "django-filter", - "django-split-settings", - "django-healthchecks", - "redis", - "sentry-sdk", - "Pillow", - "psycopg2-binary", -] - - -[project.optional-dependencies] -dev = [ - "ipython", - - "pytest-django>=3.9", - "pytest-deadfixtures", - "pytest-env", - "pytest-freezegun", - "pytest-mock", - "pytest-randomly", - - "black", - - "autoflake==1.7.0", - - "dotenv-linter", - - "freezegun", - "mixer", - - "jedi", - "flake8-absolute-import", - "flake8-black", - "flake8-bugbear", - "flake8-cognitive-complexity", - "flake8-django", - "flake8-eradicate", - "flake8-isort>=4.0.0", - "flake8-fixme", - "flake8-pep3101", - "flake8-pie", - "flake8-print", - "flake8-printf-formatting", - "flake8-pytest", - "flake8-pytest-style", - "flake8-simplify", - "flake8-todo", - "flake8-use-fstring", - "flake8-variables-names", - "flake8-walrus", - "flake8-pyproject", - - "mypy", - "django-stubs", - "djangorestframework-stubs", - "types-freezegun", - "types-Pillow", -] - +[tool.poetry] +authors = ["you "] +description = "your project description" +name = "your-project-name" +readme = "README.md" +version = "0.1.0" + +[tool.poetry.dependencies] +python = "~3.11" +bcrypt = "^4.0.1" +django = "^4.2.7" +django-axes = "^6.1.1" +django-behaviors = "^0.5.1" +django-environ = "^0.11.2" +django-filter = "^23.4" +django-healthchecks = "^1.5.0" +django-ipware = "^6.0.0" +django-split-settings = "^1.2.0" +django-storages = "^1.14.2" +djangorestframework = "^3.14.0" +djangorestframework-camel-case = "^1.4.2" +drf-jwt = "^1.19.2" +drf-spectacular = {extras = ["sidecar"], version = "^0.26.5"} +pillow = "^10.1.0" +psycopg2-binary = "^2.9.9" +redis = "^5.0.1" +sentry-sdk = "^1.37.0" +whitenoise = "^6.6.0" + +[tool.poetry.group.dev.dependencies] +autoflake = "^2.2.1" +black = "^23.11.0" +django-stubs = "^4.2.6" +djangorestframework-stubs = "^3.14.4" +dotenv-linter = "^0.4.0" +flake8-absolute-import = "^1.0.0.2" +flake8-bugbear = "^23.9.16" +flake8-cognitive-complexity = "^0.1.0" +flake8-django = "^1.4" +flake8-eradicate = "^1.5.0" +flake8-fixme = "^1.1.1" +flake8-pep3101 = "^2.1.0" +flake8-pie = "^0.16.0" +flake8-print = "^5.0.0" +flake8-printf-formatting = "^1.1.2" +flake8-pyproject = "^1.2.3" +flake8-variables-names = "^0.0.6" +flake8-walrus = "^1.2.0" +freezegun = "^1.2.2" +ipython = "^8.18.0" +jedi = "^0.19.1" +mixer = {extras = ["django"], version = "^7.2.2"} +mypy = "^1.7.1" +pytest-deadfixtures = "^2.2.1" +pytest-django = "^4.7.0" +pytest-env = "^1.1.1" +pytest-freezegun = "^0.4.2" +pytest-mock = "^3.12.0" +pytest-randomly = "^3.15.0" +types-freezegun = "^1.1.10" +types-pillow = "^10.1.0.2" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" [tool.flake8] -max-line-length = 160 -inline-quotes = "\"" +exclude = ["migrations", "__pycache__"] ignore = [ - "DJ05", # URLs include() should set a namespace - "E501", # Line too long - "E265", # Block comments should have one space before the pound sign (#) and the comment itself - "F811", # Redefinition of unused name from line n - "PT001", # Use @pytest.fixture() over @pytest.fixture - "SIM102", # Use a single if-statement instead of nested if-statements - "SIM113", # Use enumerate instead of manually incrementing a counter - "E203", # whitespace before ':', disabled for black purposes https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html#slices -] -exclude = [ - "static", - "migrations", - "frontend", - ".git", - "__pycache__", + "DJ05", # URLs include() should set a namespace + "E501", # Line too long + "E265", # Block comments should have one space before the pound sign (#) and the comment itself + "F811", # Redefinition of unused name from line n + "PT001", # Use @pytest.fixture() over @pytest.fixture + "SIM102", # Use a single if-statement instead of nested if-statements + "SIM113", # Use enumerate instead of manually incrementing a counter + "E203", # whitespace before ':', disabled for black purposes https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html#slices ] - +inline-quotes = "\"" +max-line-length = 160 [tool.isort] -profile = "google" -line_length = 160 extra_standard_library = ["pytest"] +include_trailing_comma = true known_django = ["django", "restframework"] +line_length = 160 +multi_line_output = 3 +profile = "google" sections = ["FUTURE", "STDLIB", "THIRDPARTY", "DJANGO", "FIRSTPARTY", "LOCALFOLDER"] use_parentheses = true -include_trailing_comma = true -multi_line_output = 3 - - -[tool.black] -exclude = ''' -/( - | migrations -)/ -''' -line_length = 160 - [tool.pytest.ini_options] - DJANGO_SETTINGS_MODULE = "app.settings" - python_files = ["test*.py"] - addopts = ["--reuse-db"] - markers = [ - "freeze_time: freezing time marker (pytest-freezegun does not register it)", - ] - filterwarnings = [ # Pattern: `action:message:category:module:line` (https://docs.python.org/3/library/warnings.html#describing-warning-filters) - "ignore:.*'rest_framework_jwt.blacklist' defines default_app_config.*You can remove default_app_config.::django", - "ignore:distutils Version classes are deprecated. Use packaging.version instead.:DeprecationWarning:pytest_freezegun:17", - ] - env = [ - "CI=1", - "CELERY_ALWAYS_EAGER=True", - "DISABLE_THROTTLING=True", - "AXES_ENABLED=False", - ] +addopts = ["--reuse-db"] +DJANGO_SETTINGS_MODULE = "core.settings" +env = [ + "AXES_ENABLED = False", + "CELERY_ALWAYS_EAGER = True", + "CI = 1", + "DISABLE_THROTTLING = True", +] +filterwarnings = [ + "ignore:.*'rest_framework_jwt.blacklist' defines default_app_config.*You can remove default_app_config.::django", + "ignore:distutils Version classes are deprecated. Use packaging.version instead.:DeprecationWarning:pytest_freezegun:17", +] +markers = [ + "freeze_time: freezing time marker (pytest-freezegun does not register it)", +] +python_files = ["test*.py"] +pythonpath = ". src" diff --git a/{{cookiecutter.project_slug}}/requirements.txt b/{{cookiecutter.project_slug}}/requirements.txt deleted file mode 100644 index 89a2fb0b..00000000 --- a/{{cookiecutter.project_slug}}/requirements.txt +++ /dev/null @@ -1,114 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.11 -# by the following command: -# -# pip-compile --output-file=requirements.txt pyproject.toml -# -asgiref==3.7.2 - # via django -attrs==23.1.0 - # via - # jsonschema - # referencing -bcrypt==4.0.1 - # via django (pyproject.toml) -certifi==2023.11.17 - # via - # django-healthchecks - # requests - # sentry-sdk -cffi==1.16.0 - # via cryptography -charset-normalizer==3.3.2 - # via requests -cryptography==41.0.5 - # via pyjwt -django==4.2.7 - # via - # django (pyproject.toml) - # django-axes - # django-filter - # django-healthchecks - # django-storages - # djangorestframework - # drf-jwt - # drf-spectacular - # drf-spectacular-sidecar -django-axes==6.1.1 - # via django (pyproject.toml) -django-behaviors==0.5.1 - # via django (pyproject.toml) -django-environ==0.11.2 - # via django (pyproject.toml) -django-filter==23.4 - # via django (pyproject.toml) -django-healthchecks==1.5.0 - # via django (pyproject.toml) -django-ipware==5.0.2 - # via django (pyproject.toml) -django-split-settings==1.2.0 - # via django (pyproject.toml) -django-storages==1.14.2 - # via django (pyproject.toml) -djangorestframework==3.14.0 - # via - # django (pyproject.toml) - # drf-jwt - # drf-spectacular -djangorestframework-camel-case==1.4.2 - # via django (pyproject.toml) -drf-jwt==1.19.2 - # via django (pyproject.toml) -drf-spectacular[sidecar]==0.26.5 - # via django (pyproject.toml) -drf-spectacular-sidecar==2023.10.1 - # via drf-spectacular -idna==3.4 - # via requests -inflection==0.5.1 - # via drf-spectacular -jsonschema==4.20.0 - # via drf-spectacular -jsonschema-specifications==2023.11.1 - # via jsonschema -pillow==10.1.0 - # via django (pyproject.toml) -psycopg2-binary==2.9.9 - # via django (pyproject.toml) -pycparser==2.21 - # via cffi -pyjwt[crypto]==2.8.0 - # via - # drf-jwt - # pyjwt -pytz==2023.3.post1 - # via djangorestframework -pyyaml==6.0.1 - # via drf-spectacular -redis==5.0.1 - # via django (pyproject.toml) -referencing==0.31.0 - # via - # jsonschema - # jsonschema-specifications -requests==2.31.0 - # via django-healthchecks -rpds-py==0.13.1 - # via - # jsonschema - # referencing -sentry-sdk==1.35.0 - # via django (pyproject.toml) -sqlparse==0.4.4 - # via django -uritemplate==4.1.1 - # via drf-spectacular -urllib3==2.1.0 - # via - # requests - # sentry-sdk -whitenoise==6.6.0 - # via django (pyproject.toml) - -# The following packages are considered to be unsafe in a requirements file: -# setuptools diff --git a/{{cookiecutter.project_slug}}/src/.django-app-template/admin.py-tpl b/{{cookiecutter.project_slug}}/src/.django-app-template/admin.py-tpl index 86c4c274..cb14af7d 100644 --- a/{{cookiecutter.project_slug}}/src/.django-app-template/admin.py-tpl +++ b/{{cookiecutter.project_slug}}/src/.django-app-template/admin.py-tpl @@ -1,5 +1,5 @@ from django.contrib import admin -from app.admin import ModelAdmin +from core.admin import ModelAdmin # Register your models here. diff --git a/{{cookiecutter.project_slug}}/src/.django-app-template/api/urls.py-tpl b/{{cookiecutter.project_slug}}/src/.django-app-template/api/urls.py-tpl index 9d561b38..3b47c24d 100644 --- a/{{cookiecutter.project_slug}}/src/.django-app-template/api/urls.py-tpl +++ b/{{cookiecutter.project_slug}}/src/.django-app-template/api/urls.py-tpl @@ -3,7 +3,7 @@ from rest_framework.routers import SimpleRouter from django.urls import include from django.urls import path -from {{ app_name }}.api import viewsets +from apps.{{ app_name }}.api import viewsets router = SimpleRouter() diff --git a/{{cookiecutter.project_slug}}/src/.django-app-template/api/views/app_name.py-tpl b/{{cookiecutter.project_slug}}/src/.django-app-template/api/views/app_name.py-tpl index 999e02e2..18dce71c 100644 --- a/{{cookiecutter.project_slug}}/src/.django-app-template/api/views/app_name.py-tpl +++ b/{{cookiecutter.project_slug}}/src/.django-app-template/api/views/app_name.py-tpl @@ -1,3 +1,3 @@ -from app.api.viewsets import DefaultModelViewSet +from core.api.viewsets import DefaultModelViewSet # Rename this file to singular form of your entity, e.g. "orders.py -> order.py". Add your class to __init__.py. diff --git a/{{cookiecutter.project_slug}}/src/.django-app-template/apps.py-tpl b/{{cookiecutter.project_slug}}/src/.django-app-template/apps.py-tpl index 865202f2..8e8abc6d 100644 --- a/{{cookiecutter.project_slug}}/src/.django-app-template/apps.py-tpl +++ b/{{cookiecutter.project_slug}}/src/.django-app-template/apps.py-tpl @@ -1,4 +1,4 @@ -from app.base_config import AppConfig +from core.base_config import AppConfig class {{ camel_case_app_name }}Config(AppConfig): diff --git a/{{cookiecutter.project_slug}}/src/.django-app-template/factory.py-tpl b/{{cookiecutter.project_slug}}/src/.django-app-template/factory.py-tpl index f729a781..7ece787a 100644 --- a/{{cookiecutter.project_slug}}/src/.django-app-template/factory.py-tpl +++ b/{{cookiecutter.project_slug}}/src/.django-app-template/factory.py-tpl @@ -1,4 +1,4 @@ -from app.testing import register +from core.testing import register # Register your factory methods here. # Add this file to root conftest pytest_plugins. diff --git a/{{cookiecutter.project_slug}}/src/.django-app-template/models/app_name.py-tpl b/{{cookiecutter.project_slug}}/src/.django-app-template/models/app_name.py-tpl index 0ca24cdc..8e466bdc 100644 --- a/{{cookiecutter.project_slug}}/src/.django-app-template/models/app_name.py-tpl +++ b/{{cookiecutter.project_slug}}/src/.django-app-template/models/app_name.py-tpl @@ -1,5 +1,5 @@ from django.db import models -from app.models import DefaultModel, TimestampedModel +from core.models import DefaultModel, TimestampedModel # Rename this file to singular form of your entity, e.g. "orders.py -> order.py". Add your class to __init__.py. diff --git a/{{cookiecutter.project_slug}}/src/app/.env b/{{cookiecutter.project_slug}}/src/app/.env deleted file mode 100644 index a8c5339c..00000000 --- a/{{cookiecutter.project_slug}}/src/app/.env +++ /dev/null @@ -1,3 +0,0 @@ -DEBUG=On -SECRET_KEY="{{ random_ascii_string(48, punctuation=False) }}" -DATABASE_URL=sqlite:///db.sqlite diff --git a/{{cookiecutter.project_slug}}/src/app/conf/environ.py b/{{cookiecutter.project_slug}}/src/app/conf/environ.py deleted file mode 100644 index d706412c..00000000 --- a/{{cookiecutter.project_slug}}/src/app/conf/environ.py +++ /dev/null @@ -1,13 +0,0 @@ -"""Read .env file""" -import environ # type: ignore - -env = environ.Env( - DEBUG=(bool, False), - CI=(bool, False), -) - -environ.Env.read_env("app/.env") # reading .env file - -__all__ = [ - env, -] diff --git a/{{cookiecutter.project_slug}}/src/app/fixtures/__init__.py b/{{cookiecutter.project_slug}}/src/app/fixtures/__init__.py deleted file mode 100644 index 8e7e465e..00000000 --- a/{{cookiecutter.project_slug}}/src/app/fixtures/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -from app.fixtures.api import as_anon -from app.fixtures.api import as_user -from app.fixtures.factory import factory - -__all__ = [ - "as_anon", - "as_user", - "factory", -] diff --git a/{{cookiecutter.project_slug}}/src/app/fixtures/api.py b/{{cookiecutter.project_slug}}/src/app/fixtures/api.py deleted file mode 100644 index 64be3ec7..00000000 --- a/{{cookiecutter.project_slug}}/src/app/fixtures/api.py +++ /dev/null @@ -1,14 +0,0 @@ -import pytest - -from app.testing import ApiClient -from users.models import User - - -@pytest.fixture -def as_anon() -> ApiClient: - return ApiClient() - - -@pytest.fixture -def as_user(user: User) -> ApiClient: - return ApiClient(user=user) diff --git a/{{cookiecutter.project_slug}}/src/a12n/__init__.py b/{{cookiecutter.project_slug}}/src/apps/a12n/__init__.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/a12n/__init__.py rename to {{cookiecutter.project_slug}}/src/apps/a12n/__init__.py diff --git a/{{cookiecutter.project_slug}}/src/a12n/api/serializers.py b/{{cookiecutter.project_slug}}/src/apps/a12n/api/serializers.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/a12n/api/serializers.py rename to {{cookiecutter.project_slug}}/src/apps/a12n/api/serializers.py diff --git a/{{cookiecutter.project_slug}}/src/apps/a12n/api/throttling.py b/{{cookiecutter.project_slug}}/src/apps/a12n/api/throttling.py new file mode 100644 index 00000000..8f636d88 --- /dev/null +++ b/{{cookiecutter.project_slug}}/src/apps/a12n/api/throttling.py @@ -0,0 +1,9 @@ +from rest_framework.throttling import AnonRateThrottle + +from core.api.throttling import ConfigurableThrottlingMixin + + +class AuthAnonRateThrottle(ConfigurableThrottlingMixin, AnonRateThrottle): + """Throttle for any authorization views.""" + + scope = "anon-auth" diff --git a/{{cookiecutter.project_slug}}/src/a12n/api/throttling.py b/{{cookiecutter.project_slug}}/src/apps/a12n/api/throttling.py~ similarity index 100% rename from {{cookiecutter.project_slug}}/src/a12n/api/throttling.py rename to {{cookiecutter.project_slug}}/src/apps/a12n/api/throttling.py~ diff --git a/{{cookiecutter.project_slug}}/src/apps/a12n/api/urls.py b/{{cookiecutter.project_slug}}/src/apps/a12n/api/urls.py new file mode 100644 index 00000000..1232aa9f --- /dev/null +++ b/{{cookiecutter.project_slug}}/src/apps/a12n/api/urls.py @@ -0,0 +1,10 @@ +from django.urls import path + +from apps.a12n.api import views + +app_name = "a12n" + +urlpatterns = [ + path("token/", views.ObtainJSONWebTokenView.as_view()), + path("token/refresh/", views.RefreshJSONWebTokenView.as_view()), +] diff --git a/{{cookiecutter.project_slug}}/src/a12n/api/urls.py b/{{cookiecutter.project_slug}}/src/apps/a12n/api/urls.py~ similarity index 100% rename from {{cookiecutter.project_slug}}/src/a12n/api/urls.py rename to {{cookiecutter.project_slug}}/src/apps/a12n/api/urls.py~ diff --git a/{{cookiecutter.project_slug}}/src/apps/a12n/api/views.py b/{{cookiecutter.project_slug}}/src/apps/a12n/api/views.py new file mode 100644 index 00000000..fea82c61 --- /dev/null +++ b/{{cookiecutter.project_slug}}/src/apps/a12n/api/views.py @@ -0,0 +1,11 @@ +from rest_framework_jwt import views as jwt + +from apps.a12n.api.throttling import AuthAnonRateThrottle + + +class ObtainJSONWebTokenView(jwt.ObtainJSONWebTokenView): + throttle_classes = [AuthAnonRateThrottle] + + +class RefreshJSONWebTokenView(jwt.RefreshJSONWebTokenView): + throttle_classes = [AuthAnonRateThrottle] diff --git a/{{cookiecutter.project_slug}}/src/a12n/api/views.py b/{{cookiecutter.project_slug}}/src/apps/a12n/api/views.py~ similarity index 100% rename from {{cookiecutter.project_slug}}/src/a12n/api/views.py rename to {{cookiecutter.project_slug}}/src/apps/a12n/api/views.py~ diff --git a/{{cookiecutter.project_slug}}/src/a12n/migrations/__init__.py b/{{cookiecutter.project_slug}}/src/apps/a12n/migrations/__init__.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/a12n/migrations/__init__.py rename to {{cookiecutter.project_slug}}/src/apps/a12n/migrations/__init__.py diff --git a/{{cookiecutter.project_slug}}/src/apps/a12n/utils.py b/{{cookiecutter.project_slug}}/src/apps/a12n/utils.py new file mode 100644 index 00000000..a018d718 --- /dev/null +++ b/{{cookiecutter.project_slug}}/src/apps/a12n/utils.py @@ -0,0 +1,13 @@ +from rest_framework_jwt.settings import api_settings + +from apps.users.models import User + + +def get_jwt(user: User) -> str: + """Make JWT for given user""" + jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER + jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER + + payload = jwt_payload_handler(user) + + return jwt_encode_handler(payload) diff --git a/{{cookiecutter.project_slug}}/src/a12n/utils.py b/{{cookiecutter.project_slug}}/src/apps/a12n/utils.py~ similarity index 100% rename from {{cookiecutter.project_slug}}/src/a12n/utils.py rename to {{cookiecutter.project_slug}}/src/apps/a12n/utils.py~ diff --git a/{{cookiecutter.project_slug}}/src/app/__init__.py b/{{cookiecutter.project_slug}}/src/apps/users/__init__.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/__init__.py rename to {{cookiecutter.project_slug}}/src/apps/users/__init__.py diff --git a/{{cookiecutter.project_slug}}/src/apps/users/admin.py b/{{cookiecutter.project_slug}}/src/apps/users/admin.py new file mode 100644 index 00000000..bfe68dda --- /dev/null +++ b/{{cookiecutter.project_slug}}/src/apps/users/admin.py @@ -0,0 +1,6 @@ +from django.contrib import admin +from django.contrib.auth.admin import UserAdmin + +from apps.users.models import User + +admin.site.register(User, UserAdmin) diff --git a/{{cookiecutter.project_slug}}/src/users/admin.py b/{{cookiecutter.project_slug}}/src/apps/users/admin.py~ similarity index 100% rename from {{cookiecutter.project_slug}}/src/users/admin.py rename to {{cookiecutter.project_slug}}/src/apps/users/admin.py~ diff --git a/{{cookiecutter.project_slug}}/src/apps/users/api/serializers.py b/{{cookiecutter.project_slug}}/src/apps/users/api/serializers.py new file mode 100644 index 00000000..822fb5fa --- /dev/null +++ b/{{cookiecutter.project_slug}}/src/apps/users/api/serializers.py @@ -0,0 +1,21 @@ +from rest_framework import serializers + +from apps.users.models import User + + +class UserSerializer(serializers.ModelSerializer): + remote_addr = serializers.SerializerMethodField() + + class Meta: + model = User + fields = [ + "id", + "username", + "first_name", + "last_name", + "email", + "remote_addr", + ] + + def get_remote_addr(self, obj: User) -> str: + return self.context["request"].META["REMOTE_ADDR"] diff --git a/{{cookiecutter.project_slug}}/src/users/api/serializers.py b/{{cookiecutter.project_slug}}/src/apps/users/api/serializers.py~ similarity index 100% rename from {{cookiecutter.project_slug}}/src/users/api/serializers.py rename to {{cookiecutter.project_slug}}/src/apps/users/api/serializers.py~ diff --git a/{{cookiecutter.project_slug}}/src/apps/users/api/urls.py b/{{cookiecutter.project_slug}}/src/apps/users/api/urls.py new file mode 100644 index 00000000..97528452 --- /dev/null +++ b/{{cookiecutter.project_slug}}/src/apps/users/api/urls.py @@ -0,0 +1,9 @@ +from django.urls import path + +from apps.users.api import viewsets + +app_name = "users" + +urlpatterns = [ + path("me/", viewsets.SelfView.as_view()), +] diff --git a/{{cookiecutter.project_slug}}/src/users/api/urls.py b/{{cookiecutter.project_slug}}/src/apps/users/api/urls.py~ similarity index 76% rename from {{cookiecutter.project_slug}}/src/users/api/urls.py rename to {{cookiecutter.project_slug}}/src/apps/users/api/urls.py~ index cf6239c9..47272b83 100644 --- a/{{cookiecutter.project_slug}}/src/users/api/urls.py +++ b/{{cookiecutter.project_slug}}/src/apps/users/api/urls.py~ @@ -1,6 +1,6 @@ from django.urls import path -from users.api import viewsets +from apps.users.api import viewsets app_name = "users" urlpatterns = [ diff --git a/{{cookiecutter.project_slug}}/src/apps/users/api/viewsets.py b/{{cookiecutter.project_slug}}/src/apps/users/api/viewsets.py new file mode 100644 index 00000000..faf560e7 --- /dev/null +++ b/{{cookiecutter.project_slug}}/src/apps/users/api/viewsets.py @@ -0,0 +1,26 @@ +from rest_framework.generics import GenericAPIView +from rest_framework.permissions import IsAuthenticated +from rest_framework.request import Request +from rest_framework.response import Response + +from django.db.models import QuerySet + +from apps.users.api.serializers import UserSerializer +from apps.users.models import User + + +class SelfView(GenericAPIView): + serializer_class = UserSerializer + permission_classes = [IsAuthenticated] + + def get(self, request: Request) -> Response: + user = self.get_object() + serializer = self.get_serializer(user) + + return Response(serializer.data) + + def get_object(self) -> User: + return self.get_queryset().get(pk=self.request.user.pk) + + def get_queryset(self) -> QuerySet[User]: + return User.objects.filter(is_active=True) diff --git a/{{cookiecutter.project_slug}}/src/users/api/viewsets.py b/{{cookiecutter.project_slug}}/src/apps/users/api/viewsets.py~ similarity index 100% rename from {{cookiecutter.project_slug}}/src/users/api/viewsets.py rename to {{cookiecutter.project_slug}}/src/apps/users/api/viewsets.py~ diff --git a/{{cookiecutter.project_slug}}/src/users/migrations/0001_initial.py b/{{cookiecutter.project_slug}}/src/apps/users/migrations/0001_initial.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/users/migrations/0001_initial.py rename to {{cookiecutter.project_slug}}/src/apps/users/migrations/0001_initial.py diff --git a/{{cookiecutter.project_slug}}/src/app/tests/__init__.py b/{{cookiecutter.project_slug}}/src/apps/users/migrations/__init__.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/tests/__init__.py rename to {{cookiecutter.project_slug}}/src/apps/users/migrations/__init__.py diff --git a/{{cookiecutter.project_slug}}/src/users/models.py b/{{cookiecutter.project_slug}}/src/apps/users/models.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/users/models.py rename to {{cookiecutter.project_slug}}/src/apps/users/models.py diff --git a/{{cookiecutter.project_slug}}/src/conftest.py b/{{cookiecutter.project_slug}}/src/conftest.py deleted file mode 100644 index 542d1812..00000000 --- a/{{cookiecutter.project_slug}}/src/conftest.py +++ /dev/null @@ -1,6 +0,0 @@ -pytest_plugins = [ - "app.factory", - "app.fixtures", - "users.factory", - "users.fixtures", -] diff --git a/{{cookiecutter.project_slug}}/src/app/.env.ci b/{{cookiecutter.project_slug}}/src/core/.env.ci similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/.env.ci rename to {{cookiecutter.project_slug}}/src/core/.env.ci diff --git a/{{cookiecutter.project_slug}}/src/app/tests/testing/__init__.py b/{{cookiecutter.project_slug}}/src/core/__init__.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/tests/testing/__init__.py rename to {{cookiecutter.project_slug}}/src/core/__init__.py diff --git a/{{cookiecutter.project_slug}}/src/core/admin/README.md b/{{cookiecutter.project_slug}}/src/core/admin/README.md new file mode 100644 index 00000000..08e1c8b9 --- /dev/null +++ b/{{cookiecutter.project_slug}}/src/core/admin/README.md @@ -0,0 +1,15 @@ +## App-wide admin customizations + +This is a place for app-wide django-admin customizations. To make your admin interface customizable, scaffold your admin modules like this: + +```python +from apps.books.models import Book +from core.admin import ModelAdmin, admin + + +@admin.register(Book) +class BookAdmin(ModelAdmin): + fields = [ + "name", + ] +``` \ No newline at end of file diff --git a/{{cookiecutter.project_slug}}/src/app/admin/README.md b/{{cookiecutter.project_slug}}/src/core/admin/README.md~ similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/admin/README.md rename to {{cookiecutter.project_slug}}/src/core/admin/README.md~ diff --git a/{{cookiecutter.project_slug}}/src/core/admin/__init__.py b/{{cookiecutter.project_slug}}/src/core/admin/__init__.py new file mode 100644 index 00000000..6fabbafa --- /dev/null +++ b/{{cookiecutter.project_slug}}/src/core/admin/__init__.py @@ -0,0 +1,8 @@ +from django.contrib import admin + +from core.admin.model_admin import ModelAdmin + +__all__ = [ + "admin", + "ModelAdmin", +] diff --git a/{{cookiecutter.project_slug}}/src/app/admin/__init__.py b/{{cookiecutter.project_slug}}/src/core/admin/__init__.py~ similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/admin/__init__.py rename to {{cookiecutter.project_slug}}/src/core/admin/__init__.py~ diff --git a/{{cookiecutter.project_slug}}/src/app/admin/model_admin.py b/{{cookiecutter.project_slug}}/src/core/admin/model_admin.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/admin/model_admin.py rename to {{cookiecutter.project_slug}}/src/core/admin/model_admin.py diff --git a/{{cookiecutter.project_slug}}/src/app/api/pagination.py b/{{cookiecutter.project_slug}}/src/core/api/pagination.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/api/pagination.py rename to {{cookiecutter.project_slug}}/src/core/api/pagination.py diff --git a/{{cookiecutter.project_slug}}/src/app/api/renderers.py b/{{cookiecutter.project_slug}}/src/core/api/renderers.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/api/renderers.py rename to {{cookiecutter.project_slug}}/src/core/api/renderers.py diff --git a/{{cookiecutter.project_slug}}/src/app/api/throttling.py b/{{cookiecutter.project_slug}}/src/core/api/throttling.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/api/throttling.py rename to {{cookiecutter.project_slug}}/src/core/api/throttling.py diff --git a/{{cookiecutter.project_slug}}/src/app/api/viewsets.py b/{{cookiecutter.project_slug}}/src/core/api/viewsets.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/api/viewsets.py rename to {{cookiecutter.project_slug}}/src/core/api/viewsets.py diff --git a/{{cookiecutter.project_slug}}/src/core/asgi.py b/{{cookiecutter.project_slug}}/src/core/asgi.py new file mode 100644 index 00000000..bf502ef8 --- /dev/null +++ b/{{cookiecutter.project_slug}}/src/core/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for app project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/3.0/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "core.settings") + +application = get_asgi_application() diff --git a/{{cookiecutter.project_slug}}/src/app/asgi.py b/{{cookiecutter.project_slug}}/src/core/asgi.py~ similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/asgi.py rename to {{cookiecutter.project_slug}}/src/core/asgi.py~ diff --git a/{{cookiecutter.project_slug}}/src/app/base_config.py b/{{cookiecutter.project_slug}}/src/core/base_config.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/base_config.py rename to {{cookiecutter.project_slug}}/src/core/base_config.py diff --git a/{{cookiecutter.project_slug}}/src/core/conf/api.py b/{{cookiecutter.project_slug}}/src/core/conf/api.py new file mode 100644 index 00000000..1d76eee0 --- /dev/null +++ b/{{cookiecutter.project_slug}}/src/core/conf/api.py @@ -0,0 +1,51 @@ +from core.conf.environ import env + +# Django REST Framework +# https://www.django-rest-framework.org/api-guide/settings/ + +DISABLE_THROTTLING = env("DISABLE_THROTTLING", cast=bool, default=False) +MAX_PAGE_SIZE = env("MAX_PAGE_SIZE", cast=int, default=1000) + +REST_FRAMEWORK = { + "DEFAULT_FILTER_BACKENDS": ("django_filters.rest_framework.DjangoFilterBackend",), + "DEFAULT_PERMISSION_CLASSES": ("rest_framework.permissions.IsAuthenticatedOrReadOnly",), + "DEFAULT_AUTHENTICATION_CLASSES": [ + "rest_framework.authentication.TokenAuthentication", + "rest_framework_jwt.authentication.JSONWebTokenAuthentication", + ], + "DEFAULT_RENDERER_CLASSES": [ + "core.api.renderers.AppJSONRenderer", + ], + "DEFAULT_PARSER_CLASSES": [ + "djangorestframework_camel_case.parser.CamelCaseJSONParser", + "djangorestframework_camel_case.parser.CamelCaseMultiPartParser", + "djangorestframework_camel_case.parser.CamelCaseFormParser", + ], + "DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.NamespaceVersioning", + "DEFAULT_PAGINATION_CLASS": "core.api.pagination.AppPagination", + "PAGE_SIZE": env("PAGE_SIZE", cast=int, default=20), + "DEFAULT_THROTTLE_RATES": { + "anon-auth": "10/min", + }, + "DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema", +} + +# Adding session auth and browsable API at the developer machine +if env("DEBUG", cast=bool, default=False): + REST_FRAMEWORK["DEFAULT_AUTHENTICATION_CLASSES"].append("rest_framework.authentication.SessionAuthentication") + REST_FRAMEWORK["DEFAULT_RENDERER_CLASSES"].append("djangorestframework_camel_case.render.CamelCaseBrowsableAPIRenderer") + + +# Set up drf_spectacular, https://drf-spectacular.readthedocs.io/en/latest/settings.html +SPECTACULAR_SETTINGS = { + "TITLE": "Our fancy API", + "DESCRIPTION": "So great, needs no docs", + "SWAGGER_UI_DIST": "SIDECAR", + "SWAGGER_UI_FAVICON_HREF": "SIDECAR", + "REDOC_DIST": "SIDECAR", + "CAMELIZE_NAMES": True, + "POSTPROCESSING_HOOKS": [ + "drf_spectacular.hooks.postprocess_schema_enums", + "drf_spectacular.contrib.djangorestframework_camel_case.camelize_serializer_fields", + ], +} diff --git a/{{cookiecutter.project_slug}}/src/app/conf/api.py b/{{cookiecutter.project_slug}}/src/core/conf/api.py~ similarity index 98% rename from {{cookiecutter.project_slug}}/src/app/conf/api.py rename to {{cookiecutter.project_slug}}/src/core/conf/api.py~ index 94d115c6..c935ec7e 100644 --- a/{{cookiecutter.project_slug}}/src/app/conf/api.py +++ b/{{cookiecutter.project_slug}}/src/core/conf/api.py~ @@ -1,4 +1,4 @@ -from app.conf.environ import env +from core.conf.environ import env # Django REST Framework # https://www.django-rest-framework.org/api-guide/settings/ diff --git a/{{cookiecutter.project_slug}}/src/core/conf/auth.py b/{{cookiecutter.project_slug}}/src/core/conf/auth.py new file mode 100644 index 00000000..22ae28f7 --- /dev/null +++ b/{{cookiecutter.project_slug}}/src/core/conf/auth.py @@ -0,0 +1,34 @@ +from datetime import timedelta + +from core.conf.environ import env + +AUTH_USER_MODEL = "users.User" +AXES_ENABLED = env("AXES_ENABLED", cast=bool, default=True) + +AUTHENTICATION_BACKENDS = [ + "axes.backends.AxesBackend", + "django.contrib.auth.backends.ModelBackend", +] + +JWT_AUTH = { + "JWT_EXPIRATION_DELTA": timedelta(days=14), + "JWT_REFRESH_EXPIRATION_DELTA": timedelta(days=21), + "JWT_ALLOW_REFRESH": True, +} + + +# +# Security notice: we use plain bcrypt to store passwords. +# +# We avoid django default pre-hashing algorithm +# from contrib.auth.hashers.BCryptSHA256PasswordHasher. +# +# The reason is compatibility with other hashing libraries, like +# Ruby Devise or Laravel default hashing algorithm. +# +# This means we can't store passwords longer then 72 symbols. +# + +PASSWORD_HASHERS = [ + "django.contrib.auth.hashers.BCryptPasswordHasher", +] diff --git a/{{cookiecutter.project_slug}}/src/app/conf/auth.py b/{{cookiecutter.project_slug}}/src/core/conf/auth.py~ similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/conf/auth.py rename to {{cookiecutter.project_slug}}/src/core/conf/auth.py~ diff --git a/{{cookiecutter.project_slug}}/src/core/conf/boilerplate.py b/{{cookiecutter.project_slug}}/src/core/conf/boilerplate.py new file mode 100644 index 00000000..f293b221 --- /dev/null +++ b/{{cookiecutter.project_slug}}/src/core/conf/boilerplate.py @@ -0,0 +1,10 @@ +from pathlib import Path + +BASE_DIR = Path(__file__).resolve().parent.parent + +ROOT_URLCONF = "core.urls" + +# Disable built-in ./manage.py test command in favor of pytest +TEST_RUNNER = "core.test.disable_test_command_runner.DisableTestCommandRunner" + +WSGI_APPLICATION = "core.wsgi.application" diff --git a/{{cookiecutter.project_slug}}/src/app/conf/boilerplate.py b/{{cookiecutter.project_slug}}/src/core/conf/boilerplate.py~ similarity index 71% rename from {{cookiecutter.project_slug}}/src/app/conf/boilerplate.py rename to {{cookiecutter.project_slug}}/src/core/conf/boilerplate.py~ index 7e88e28c..f16ff2a1 100644 --- a/{{cookiecutter.project_slug}}/src/app/conf/boilerplate.py +++ b/{{cookiecutter.project_slug}}/src/core/conf/boilerplate.py~ @@ -1,6 +1,6 @@ -import os.path +from pathlib import Path -BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +BASE_DIR = Path(__file__).resolve().parent.parent ROOT_URLCONF = "app.urls" diff --git a/{{cookiecutter.project_slug}}/src/core/conf/db.py b/{{cookiecutter.project_slug}}/src/core/conf/db.py new file mode 100644 index 00000000..066c8b3f --- /dev/null +++ b/{{cookiecutter.project_slug}}/src/core/conf/db.py @@ -0,0 +1,12 @@ +# Database +# https://docs.djangoproject.com/en/3.0/ref/settings/#databases + +from core.conf.environ import env + +DATABASES = { + # read os.environ["DATABASE_URL"] and raises ImproperlyConfigured exception if not found + "default": env.db(), +} + +# https://docs.djangoproject.com/en/3.2/releases/3.2/#customizing-type-of-auto-created-primary-keys +DEFAULT_AUTO_FIELD = "django.db.models.AutoField" diff --git a/{{cookiecutter.project_slug}}/src/app/conf/db.py b/{{cookiecutter.project_slug}}/src/core/conf/db.py~ similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/conf/db.py rename to {{cookiecutter.project_slug}}/src/core/conf/db.py~ diff --git a/{{cookiecutter.project_slug}}/src/core/conf/environ.py b/{{cookiecutter.project_slug}}/src/core/conf/environ.py new file mode 100644 index 00000000..a5557bf5 --- /dev/null +++ b/{{cookiecutter.project_slug}}/src/core/conf/environ.py @@ -0,0 +1,18 @@ +import environ # type: ignore[import-untyped] + +from core.conf.boilerplate import BASE_DIR + +env = environ.Env( + DEBUG=(bool, False), + CI=(bool, False), +) + +envpath = BASE_DIR / ".env" + +if envpath.exists(): + env.read_env(envpath) + + +__all__ = [ + "env", +] diff --git a/{{cookiecutter.project_slug}}/src/core/conf/environ.py~ b/{{cookiecutter.project_slug}}/src/core/conf/environ.py~ new file mode 100644 index 00000000..1f81d47e --- /dev/null +++ b/{{cookiecutter.project_slug}}/src/core/conf/environ.py~ @@ -0,0 +1,18 @@ +import environ # type: ignore[import-untyped] + +from app.conf.boilerplate import BASE_DIR + +env = environ.Env( + DEBUG=(bool, False), + CI=(bool, False), +) + +envpath = BASE_DIR / ".env" + +if envpath.exists(): + env.read_env(envpath) + + +__all__ = [ + "env", +] diff --git a/{{cookiecutter.project_slug}}/src/app/conf/healthchecks.py b/{{cookiecutter.project_slug}}/src/core/conf/healthchecks.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/conf/healthchecks.py rename to {{cookiecutter.project_slug}}/src/core/conf/healthchecks.py diff --git a/{{cookiecutter.project_slug}}/src/core/conf/http.py b/{{cookiecutter.project_slug}}/src/core/conf/http.py new file mode 100644 index 00000000..87ff3f0f --- /dev/null +++ b/{{cookiecutter.project_slug}}/src/core/conf/http.py @@ -0,0 +1,11 @@ +from core.conf.environ import env + +ALLOWED_HOSTS = ["*"] # host validation is not necessary in 2020 +CSRF_TRUSTED_ORIGINS = [ + "http://your.app.origin", +] + +if env("DEBUG"): + ABSOLUTE_HOST = "http://localhost:3000" +else: + ABSOLUTE_HOST = "https://your.app.com" diff --git a/{{cookiecutter.project_slug}}/src/app/conf/http.py b/{{cookiecutter.project_slug}}/src/core/conf/http.py~ similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/conf/http.py rename to {{cookiecutter.project_slug}}/src/core/conf/http.py~ diff --git a/{{cookiecutter.project_slug}}/src/app/conf/i18n.py b/{{cookiecutter.project_slug}}/src/core/conf/i18n.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/conf/i18n.py rename to {{cookiecutter.project_slug}}/src/core/conf/i18n.py diff --git a/{{cookiecutter.project_slug}}/src/core/conf/installed_apps.py b/{{cookiecutter.project_slug}}/src/core/conf/installed_apps.py new file mode 100644 index 00000000..ed681b84 --- /dev/null +++ b/{{cookiecutter.project_slug}}/src/core/conf/installed_apps.py @@ -0,0 +1,25 @@ +# Application definition + +APPS = [ + "core", + "apps.a12n", + "apps.users", +] + +THIRD_PARTY_APPS = [ + "drf_spectacular", + "drf_spectacular_sidecar", + "rest_framework", + "rest_framework.authtoken", + "rest_framework_jwt.blacklist", + "django_filters", + "axes", + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", +] + +INSTALLED_APPS = APPS + THIRD_PARTY_APPS diff --git a/{{cookiecutter.project_slug}}/src/app/conf/installed_apps.py b/{{cookiecutter.project_slug}}/src/core/conf/installed_apps.py~ similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/conf/installed_apps.py rename to {{cookiecutter.project_slug}}/src/core/conf/installed_apps.py~ diff --git a/{{cookiecutter.project_slug}}/src/core/conf/media.py b/{{cookiecutter.project_slug}}/src/core/conf/media.py new file mode 100644 index 00000000..85e62198 --- /dev/null +++ b/{{cookiecutter.project_slug}}/src/core/conf/media.py @@ -0,0 +1,4 @@ +from core.conf.environ import env + +MEDIA_URL = "/media/" +MEDIA_ROOT = env("MEDIA_ROOT", cast=str, default="media") diff --git a/{{cookiecutter.project_slug}}/src/app/conf/media.py b/{{cookiecutter.project_slug}}/src/core/conf/media.py~ similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/conf/media.py rename to {{cookiecutter.project_slug}}/src/core/conf/media.py~ diff --git a/{{cookiecutter.project_slug}}/src/core/conf/middleware.py b/{{cookiecutter.project_slug}}/src/core/conf/middleware.py new file mode 100644 index 00000000..e7e10025 --- /dev/null +++ b/{{cookiecutter.project_slug}}/src/core/conf/middleware.py @@ -0,0 +1,12 @@ +MIDDLEWARE = [ + "django.middleware.security.SecurityMiddleware", + "whitenoise.middleware.WhiteNoiseMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", + "core.middleware.real_ip.real_ip_middleware", + "axes.middleware.AxesMiddleware", +] diff --git a/{{cookiecutter.project_slug}}/src/app/conf/middleware.py b/{{cookiecutter.project_slug}}/src/core/conf/middleware.py~ similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/conf/middleware.py rename to {{cookiecutter.project_slug}}/src/core/conf/middleware.py~ diff --git a/{{cookiecutter.project_slug}}/src/core/conf/sentry.py b/{{cookiecutter.project_slug}}/src/core/conf/sentry.py new file mode 100644 index 00000000..86cc1b0c --- /dev/null +++ b/{{cookiecutter.project_slug}}/src/core/conf/sentry.py @@ -0,0 +1,15 @@ +from core.conf.environ import env + +# Sentry +# https://sentry.io/for/django/ + +SENTRY_DSN = env("SENTRY_DSN", cast=str, default="") + +if not env("DEBUG") and len(SENTRY_DSN): + import sentry_sdk + from sentry_sdk.integrations.django import DjangoIntegration + + sentry_sdk.init( + dsn=SENTRY_DSN, + integrations=[DjangoIntegration()], + ) diff --git a/{{cookiecutter.project_slug}}/src/app/conf/sentry.py b/{{cookiecutter.project_slug}}/src/core/conf/sentry.py~ similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/conf/sentry.py rename to {{cookiecutter.project_slug}}/src/core/conf/sentry.py~ diff --git a/{{cookiecutter.project_slug}}/src/core/conf/static.py b/{{cookiecutter.project_slug}}/src/core/conf/static.py new file mode 100644 index 00000000..89870167 --- /dev/null +++ b/{{cookiecutter.project_slug}}/src/core/conf/static.py @@ -0,0 +1,7 @@ +from core.conf.environ import env + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/3.0/howto/static-files/ + +STATIC_URL = "/static/" +STATIC_ROOT = env("STATIC_ROOT", cast=str, default="static") diff --git a/{{cookiecutter.project_slug}}/src/app/conf/static.py b/{{cookiecutter.project_slug}}/src/core/conf/static.py~ similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/conf/static.py rename to {{cookiecutter.project_slug}}/src/core/conf/static.py~ diff --git a/{{cookiecutter.project_slug}}/src/core/conf/storage.py b/{{cookiecutter.project_slug}}/src/core/conf/storage.py new file mode 100644 index 00000000..039afa4b --- /dev/null +++ b/{{cookiecutter.project_slug}}/src/core/conf/storage.py @@ -0,0 +1,10 @@ +from core.conf.environ import env + +DEFAULT_FILE_STORAGE = env("DEFAULT_FILE_STORAGE", cast=str, default="django.core.files.storage.FileSystemStorage") + +AWS_ACCESS_KEY_ID = env("AWS_ACCESS_KEY_ID", default="") +AWS_SECRET_ACCESS_KEY = env("AWS_SECRET_ACCESS_KEY", default="") +AWS_STORAGE_BUCKET_NAME = env("AWS_STORAGE_BUCKET_NAME", default="") +AWS_S3_REGION_NAME = env("AWS_S3_REGION_NAME", default="") +AWS_S3_ENDPOINT_URL = env("AWS_S3_ENDPOINT_URL", default="") +AWS_DEFAULT_ACL = env("AWS_DEFAULT_ACL", default="") diff --git a/{{cookiecutter.project_slug}}/src/app/conf/storage.py b/{{cookiecutter.project_slug}}/src/core/conf/storage.py~ similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/conf/storage.py rename to {{cookiecutter.project_slug}}/src/core/conf/storage.py~ diff --git a/{{cookiecutter.project_slug}}/src/app/conf/templates.py b/{{cookiecutter.project_slug}}/src/core/conf/templates.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/conf/templates.py rename to {{cookiecutter.project_slug}}/src/core/conf/templates.py diff --git a/{{cookiecutter.project_slug}}/src/app/conf/timezone.py b/{{cookiecutter.project_slug}}/src/core/conf/timezone.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/conf/timezone.py rename to {{cookiecutter.project_slug}}/src/core/conf/timezone.py diff --git a/{{cookiecutter.project_slug}}/src/app/locale/.gitkeep b/{{cookiecutter.project_slug}}/src/core/locale/.gitkeep similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/locale/.gitkeep rename to {{cookiecutter.project_slug}}/src/core/locale/.gitkeep diff --git a/{{cookiecutter.project_slug}}/src/app/management/commands/makemigrations.py b/{{cookiecutter.project_slug}}/src/core/management/commands/makemigrations.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/management/commands/makemigrations.py rename to {{cookiecutter.project_slug}}/src/core/management/commands/makemigrations.py diff --git a/{{cookiecutter.project_slug}}/src/app/management/commands/startapp.py b/{{cookiecutter.project_slug}}/src/core/management/commands/startapp.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/management/commands/startapp.py rename to {{cookiecutter.project_slug}}/src/core/management/commands/startapp.py diff --git a/{{cookiecutter.project_slug}}/src/app/middleware/real_ip.py b/{{cookiecutter.project_slug}}/src/core/middleware/real_ip.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/middleware/real_ip.py rename to {{cookiecutter.project_slug}}/src/core/middleware/real_ip.py diff --git a/{{cookiecutter.project_slug}}/src/app/models.py b/{{cookiecutter.project_slug}}/src/core/models.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/models.py rename to {{cookiecutter.project_slug}}/src/core/models.py diff --git a/{{cookiecutter.project_slug}}/src/app/services.py b/{{cookiecutter.project_slug}}/src/core/services.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/services.py rename to {{cookiecutter.project_slug}}/src/core/services.py diff --git a/{{cookiecutter.project_slug}}/src/core/settings.py b/{{cookiecutter.project_slug}}/src/core/settings.py new file mode 100644 index 00000000..08fb98e6 --- /dev/null +++ b/{{cookiecutter.project_slug}}/src/core/settings.py @@ -0,0 +1,32 @@ +# This file was generated using http://github.com/f213/django starter template. +# +# Settings are split into multiple files using http://github.com/sobolevn/django-split-settings + +from split_settings.tools import include + +from core.conf.environ import env + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = env("SECRET_KEY") + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = env("DEBUG", cast=bool, default=False) +CI = env("CI", cast=bool, default=False) + +include( + "conf/api.py", + "conf/auth.py", + "conf/boilerplate.py", + "conf/db.py", + "conf/healthchecks.py", + "conf/http.py", + "conf/i18n.py", + "conf/installed_apps.py", + "conf/media.py", + "conf/middleware.py", + "conf/storage.py", + "conf/sentry.py", + "conf/static.py", + "conf/templates.py", + "conf/timezone.py", +) diff --git a/{{cookiecutter.project_slug}}/src/app/settings.py b/{{cookiecutter.project_slug}}/src/core/settings.py~ similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/settings.py rename to {{cookiecutter.project_slug}}/src/core/settings.py~ diff --git a/{{cookiecutter.project_slug}}/src/core/testing/__init__.py b/{{cookiecutter.project_slug}}/src/core/testing/__init__.py new file mode 100644 index 00000000..791bc413 --- /dev/null +++ b/{{cookiecutter.project_slug}}/src/core/testing/__init__.py @@ -0,0 +1,9 @@ +from core.testing.api import ApiClient +from core.testing.factory import FixtureFactory +from core.testing.factory import register + +__all__ = [ + "ApiClient", + "FixtureFactory", + "register", +] diff --git a/{{cookiecutter.project_slug}}/src/app/testing/__init__.py b/{{cookiecutter.project_slug}}/src/core/testing/__init__.py~ similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/testing/__init__.py rename to {{cookiecutter.project_slug}}/src/core/testing/__init__.py~ diff --git a/{{cookiecutter.project_slug}}/src/core/testing/api.py b/{{cookiecutter.project_slug}}/src/core/testing/api.py new file mode 100644 index 00000000..1be9a4e3 --- /dev/null +++ b/{{cookiecutter.project_slug}}/src/core/testing/api.py @@ -0,0 +1,79 @@ +import json +import random +import string +from typing import Optional + +from rest_framework.authtoken.models import Token +from rest_framework.test import APIClient as DRFAPIClient + +from apps.users.models import User + + +class ApiClient(DRFAPIClient): + def __init__(self, user: Optional[User] = None, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + + if user: + self.user = user + self.password = "".join([random.choice(string.hexdigits) for _ in range(6)]) + self.user.set_password(self.password) + self.user.save() + + token = Token.objects.create(user=self.user) + self.credentials( + HTTP_AUTHORIZATION=f"Token {token}", + HTTP_X_CLIENT="testing", + ) + + def get(self, *args, **kwargs): + expected_status = kwargs.get("expected_status", 200) + return self._request("get", expected_status, *args, **kwargs) + + def patch(self, *args, **kwargs): + expected_status = kwargs.get("expected_status", 200) + return self._request("patch", expected_status, *args, **kwargs) + + def post(self, *args, **kwargs): + expected_status = kwargs.get("expected_status", 201) + return self._request("post", expected_status, *args, **kwargs) + + def put(self, *args, **kwargs): + expected_status = kwargs.get("expected_status", 200) + return self._request("put", expected_status, *args, **kwargs) + + def delete(self, *args, **kwargs): + expected_status = kwargs.get("expected_status", 204) + return self._request("delete", expected_status, *args, **kwargs) + + def _request(self, method, expected, *args, **kwargs): + kwargs["format"] = kwargs.get("format", "json") + as_response = kwargs.pop("as_response", False) + method = getattr(super(), method) + + response = method(*args, **kwargs) + if as_response: + return response + + content = self._decode(response) + assert response.status_code == expected, content + return content + + def _decode(self, response): + content = response.content.decode("utf-8", errors="ignore") + + if self.is_json(response): + return json.loads(content) + else: + return content + + @staticmethod + def is_json(response) -> bool: + if response.has_header("content-type"): + return "json" in response.get("content-type") + + return False + + +__all__ = [ + "ApiClient", +] diff --git a/{{cookiecutter.project_slug}}/src/app/testing/api.py b/{{cookiecutter.project_slug}}/src/core/testing/api.py~ similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/testing/api.py rename to {{cookiecutter.project_slug}}/src/core/testing/api.py~ diff --git a/{{cookiecutter.project_slug}}/src/core/testing/factory.py b/{{cookiecutter.project_slug}}/src/core/testing/factory.py new file mode 100644 index 00000000..26b7f3a1 --- /dev/null +++ b/{{cookiecutter.project_slug}}/src/core/testing/factory.py @@ -0,0 +1,46 @@ +from functools import partial +from typing import Callable + +from core.testing.mixer import mixer + + +def register(method: Callable) -> Callable: + name = method.__name__ + FixtureRegistry.METHODS[name] = method + return method + + +class FixtureRegistry: + METHODS: dict[str, Callable] = {} + + def get(self, name: str) -> Callable: + method = self.METHODS.get(name) + if not method: + raise AttributeError(f"Factory method “{name}” not found.") + return method + + +class CycleFixtureFactory: + def __init__(self, factory: "FixtureFactory", count: int) -> None: + self.factory = factory + self.count = count + + def __getattr__(self, name: str) -> Callable: + return lambda *args, **kwargs: [getattr(self.factory, name)(*args, **kwargs) for _ in range(self.count)] + + +class FixtureFactory: + def __init__(self) -> None: + self.mixer = mixer + self.registry = FixtureRegistry() + + def __getattr__(self, name: str) -> Callable: + method = self.registry.get(name) + return partial(method, self) + + def cycle(self, count: int) -> CycleFixtureFactory: + """ + Run given method X times: + factory.cycle(5).order() # gives 5 orders + """ + return CycleFixtureFactory(self, count) diff --git a/{{cookiecutter.project_slug}}/src/app/testing/factory.py b/{{cookiecutter.project_slug}}/src/core/testing/factory.py~ similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/testing/factory.py rename to {{cookiecutter.project_slug}}/src/core/testing/factory.py~ diff --git a/{{cookiecutter.project_slug}}/src/app/testing/mixer.py b/{{cookiecutter.project_slug}}/src/core/testing/mixer.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/testing/mixer.py rename to {{cookiecutter.project_slug}}/src/core/testing/mixer.py diff --git a/{{cookiecutter.project_slug}}/src/app/testing/runner.py b/{{cookiecutter.project_slug}}/src/core/testing/runner.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/testing/runner.py rename to {{cookiecutter.project_slug}}/src/core/testing/runner.py diff --git a/{{cookiecutter.project_slug}}/src/app/testing/types.py b/{{cookiecutter.project_slug}}/src/core/testing/types.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/testing/types.py rename to {{cookiecutter.project_slug}}/src/core/testing/types.py diff --git a/{{cookiecutter.project_slug}}/src/core/urls/__init__.py b/{{cookiecutter.project_slug}}/src/core/urls/__init__.py new file mode 100644 index 00000000..db251116 --- /dev/null +++ b/{{cookiecutter.project_slug}}/src/core/urls/__init__.py @@ -0,0 +1,12 @@ +from django.contrib import admin +from django.urls import include +from django.urls import path + +api = [ + path("v1/", include("core.urls.v1", namespace="v1")), +] + +urlpatterns = [ + path("admin/", admin.site.urls), + path("api/", include(api)), +] diff --git a/{{cookiecutter.project_slug}}/src/app/urls/__init__.py b/{{cookiecutter.project_slug}}/src/core/urls/__init__.py~ similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/urls/__init__.py rename to {{cookiecutter.project_slug}}/src/core/urls/__init__.py~ diff --git a/{{cookiecutter.project_slug}}/src/app/urls/v1.py b/{{cookiecutter.project_slug}}/src/core/urls/v1.py similarity index 80% rename from {{cookiecutter.project_slug}}/src/app/urls/v1.py rename to {{cookiecutter.project_slug}}/src/core/urls/v1.py index c49cc038..11a13b64 100644 --- a/{{cookiecutter.project_slug}}/src/app/urls/v1.py +++ b/{{cookiecutter.project_slug}}/src/core/urls/v1.py @@ -5,9 +5,10 @@ from django.urls import path app_name = "api_v1" + urlpatterns = [ - path("auth/", include("a12n.api.urls")), - path("users/", include("users.api.urls")), + path("auth/", include("apps.a12n.api.urls")), + path("users/", include("apps.users.api.urls")), path("healthchecks/", include("django_healthchecks.urls")), path("docs/schema/", SpectacularAPIView.as_view(), name="schema"), path("docs/swagger/", SpectacularSwaggerView.as_view(url_name="schema")), diff --git a/{{cookiecutter.project_slug}}/src/core/urls/v1.py~ b/{{cookiecutter.project_slug}}/src/core/urls/v1.py~ new file mode 100644 index 00000000..d8f89f4d --- /dev/null +++ b/{{cookiecutter.project_slug}}/src/core/urls/v1.py~ @@ -0,0 +1,15 @@ +from drf_spectacular.views import SpectacularAPIView +from drf_spectacular.views import SpectacularSwaggerView + +from django.urls import include +from django.urls import path + +app_name = "api_v1" + +urlpatterns = [ + path("auth/", include("a12n.api.urls")), + path("users/", include("users.api.urls")), + path("healthchecks/", include("django_healthchecks.urls")), + path("docs/schema/", SpectacularAPIView.as_view(), name="schema"), + path("docs/swagger/", SpectacularSwaggerView.as_view(url_name="schema")), +] diff --git a/{{cookiecutter.project_slug}}/src/core/wsgi.py b/{{cookiecutter.project_slug}}/src/core/wsgi.py new file mode 100644 index 00000000..d59bd34a --- /dev/null +++ b/{{cookiecutter.project_slug}}/src/core/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for app project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/3.0/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "core.settings") + +application = get_wsgi_application() diff --git a/{{cookiecutter.project_slug}}/src/app/wsgi.py b/{{cookiecutter.project_slug}}/src/core/wsgi.py~ similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/wsgi.py rename to {{cookiecutter.project_slug}}/src/core/wsgi.py~ diff --git a/{{cookiecutter.project_slug}}/src/manage.py b/{{cookiecutter.project_slug}}/src/manage.py index 661e27f5..fd4cfdf9 100755 --- a/{{cookiecutter.project_slug}}/src/manage.py +++ b/{{cookiecutter.project_slug}}/src/manage.py @@ -5,7 +5,7 @@ def main() -> None: - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "app.settings") + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "core.settings") try: from django.core.management import execute_from_command_line except ImportError as exc: diff --git a/{{cookiecutter.project_slug}}/src/app/tests/testing/factory/__init__.py b/{{cookiecutter.project_slug}}/tests/__init__.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/tests/testing/factory/__init__.py rename to {{cookiecutter.project_slug}}/tests/__init__.py diff --git a/{{cookiecutter.project_slug}}/src/a12n/tests/jwt_views/test_obtain_jwt_view.py b/{{cookiecutter.project_slug}}/tests/apps/a12n/jwt_views/test_obtain_jwt_view.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/a12n/tests/jwt_views/test_obtain_jwt_view.py rename to {{cookiecutter.project_slug}}/tests/apps/a12n/jwt_views/test_obtain_jwt_view.py diff --git a/{{cookiecutter.project_slug}}/tests/apps/a12n/jwt_views/test_refresh_jwt_token.py b/{{cookiecutter.project_slug}}/tests/apps/a12n/jwt_views/test_refresh_jwt_token.py new file mode 100644 index 00000000..23556276 --- /dev/null +++ b/{{cookiecutter.project_slug}}/tests/apps/a12n/jwt_views/test_refresh_jwt_token.py @@ -0,0 +1,72 @@ +import pytest + +from freezegun import freeze_time + +from apps.a12n.utils import get_jwt + +pytestmark = [ + pytest.mark.django_db, + pytest.mark.freeze_time("2049-01-05"), +] + + +@pytest.fixture +def refresh_token(as_user): + def _refresh_token(token, expected_status=201): + return as_user.post( + "/api/v1/auth/token/refresh/", + { + "token": token, + }, + format="json", + expected_status=expected_status, + ) + + return _refresh_token + + +@pytest.fixture +def initial_token(as_user): + with freeze_time("2049-01-03"): + return get_jwt(as_user.user) + + +def test_refresh_token_ok(initial_token, refresh_token): + result = refresh_token(initial_token) + + assert "token" in result + + +def test_refreshed_token_is_a_token(initial_token, refresh_token): + result = refresh_token(initial_token) + + assert len(result["token"]) > 32 + + +def test_refreshed_token_is_new_one(initial_token, refresh_token): + result = refresh_token(initial_token) + + assert result["token"] != initial_token + + +def test_refresh_token_fails_with_incorrect_previous_token(refresh_token): + result = refresh_token("some-invalid-previous-token", expected_status=400) + + assert "nonFieldErrors" in result + + +def test_token_is_not_allowed_to_refresh_if_expired(initial_token, refresh_token): + with freeze_time("2049-02-05"): + + result = refresh_token(initial_token, expected_status=400) + + assert "expired" in result["nonFieldErrors"][0] + + +def test_received_token_works(as_anon, refresh_token, initial_token): + token = refresh_token(initial_token)["token"] + as_anon.credentials(HTTP_AUTHORIZATION=f"Bearer {token}") + + result = as_anon.get("/api/v1/users/me/") + + assert result is not None diff --git a/{{cookiecutter.project_slug}}/src/a12n/tests/jwt_views/test_refresh_jwt_token.py b/{{cookiecutter.project_slug}}/tests/apps/a12n/jwt_views/test_refresh_jwt_token.py~ similarity index 100% rename from {{cookiecutter.project_slug}}/src/a12n/tests/jwt_views/test_refresh_jwt_token.py rename to {{cookiecutter.project_slug}}/tests/apps/a12n/jwt_views/test_refresh_jwt_token.py~ diff --git a/{{cookiecutter.project_slug}}/src/users/fixtures.py b/{{cookiecutter.project_slug}}/tests/apps/users/conftest.py~ similarity index 85% rename from {{cookiecutter.project_slug}}/src/users/fixtures.py rename to {{cookiecutter.project_slug}}/tests/apps/users/conftest.py~ index b8d2b207..6fa5fd23 100644 --- a/{{cookiecutter.project_slug}}/src/users/fixtures.py +++ b/{{cookiecutter.project_slug}}/tests/apps/users/conftest.py~ @@ -1,7 +1,7 @@ import pytest from typing import TYPE_CHECKING -from users.models import User +from apps.users.models import User if TYPE_CHECKING: from app.testing.factory import FixtureFactory diff --git a/{{cookiecutter.project_slug}}/tests/apps/users/factory.py b/{{cookiecutter.project_slug}}/tests/apps/users/factory.py new file mode 100644 index 00000000..0bf9b1a4 --- /dev/null +++ b/{{cookiecutter.project_slug}}/tests/apps/users/factory.py @@ -0,0 +1,15 @@ +from django.contrib.auth.models import AnonymousUser + +from core.testing import register +from core.testing.types import FactoryProtocol +from apps.users.models import User + + +@register +def user(self: FactoryProtocol, **kwargs: dict) -> User: + return self.mixer.blend("users.User", **kwargs) + + +@register +def anon(self: FactoryProtocol, **kwargs: dict) -> AnonymousUser: + return AnonymousUser() diff --git a/{{cookiecutter.project_slug}}/src/users/factory.py b/{{cookiecutter.project_slug}}/tests/apps/users/factory.py~ similarity index 100% rename from {{cookiecutter.project_slug}}/src/users/factory.py rename to {{cookiecutter.project_slug}}/tests/apps/users/factory.py~ diff --git a/{{cookiecutter.project_slug}}/tests/apps/users/fixtures.py b/{{cookiecutter.project_slug}}/tests/apps/users/fixtures.py new file mode 100644 index 00000000..b61fe541 --- /dev/null +++ b/{{cookiecutter.project_slug}}/tests/apps/users/fixtures.py @@ -0,0 +1,12 @@ +import pytest +from typing import TYPE_CHECKING + +from apps.users.models import User + +if TYPE_CHECKING: + from core.testing.factory import FixtureFactory + + +@pytest.fixture +def user(factory: "FixtureFactory") -> User: + return factory.user() diff --git a/{{cookiecutter.project_slug}}/tests/apps/users/test_password_hashing.py b/{{cookiecutter.project_slug}}/tests/apps/users/test_password_hashing.py new file mode 100644 index 00000000..72e96a84 --- /dev/null +++ b/{{cookiecutter.project_slug}}/tests/apps/users/test_password_hashing.py @@ -0,0 +1,15 @@ +import pytest +import uuid + +from apps.users.models import User + +pytestmark = [pytest.mark.django_db] + + +def test(): + user = User.objects.create(username=str(uuid.uuid4())) + user.set_password("l0ve") + + user.save() # act + + assert user.password.startswith("bcrypt") diff --git a/{{cookiecutter.project_slug}}/src/users/tests/test_password_hashing.py b/{{cookiecutter.project_slug}}/tests/apps/users/test_password_hashing.py~ similarity index 100% rename from {{cookiecutter.project_slug}}/src/users/tests/test_password_hashing.py rename to {{cookiecutter.project_slug}}/tests/apps/users/test_password_hashing.py~ diff --git a/{{cookiecutter.project_slug}}/src/users/tests/test_whoami.py b/{{cookiecutter.project_slug}}/tests/apps/users/test_whoami.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/users/tests/test_whoami.py rename to {{cookiecutter.project_slug}}/tests/apps/users/test_whoami.py diff --git a/{{cookiecutter.project_slug}}/tests/conftest.py b/{{cookiecutter.project_slug}}/tests/conftest.py new file mode 100644 index 00000000..c5d58281 --- /dev/null +++ b/{{cookiecutter.project_slug}}/tests/conftest.py @@ -0,0 +1,9 @@ +# fmt: off +pytest_plugins = [ + "tests.apps.users.factory", + "tests.core.factory", + + "tests.apps.users.fixtures", + "tests.core.fixtures", +] +# fmt: on diff --git a/{{cookiecutter.project_slug}}/tests/conftest.py~ b/{{cookiecutter.project_slug}}/tests/conftest.py~ new file mode 100644 index 00000000..e80dd146 --- /dev/null +++ b/{{cookiecutter.project_slug}}/tests/conftest.py~ @@ -0,0 +1,9 @@ +# fmt: off +pytest_plugins = [ + "tests.apps.users.conftest", + "tests.core.conftest", + + "tests.apps.users.factory", + "tests.core.factory", +] +# fmt: on diff --git a/{{cookiecutter.project_slug}}/src/users/__init__.py b/{{cookiecutter.project_slug}}/tests/core/__init__.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/users/__init__.py rename to {{cookiecutter.project_slug}}/tests/core/__init__.py diff --git a/{{cookiecutter.project_slug}}/src/app/fixtures/factory.py b/{{cookiecutter.project_slug}}/tests/core/conftest.py~ similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/fixtures/factory.py rename to {{cookiecutter.project_slug}}/tests/core/conftest.py~ diff --git a/{{cookiecutter.project_slug}}/tests/core/factory.py b/{{cookiecutter.project_slug}}/tests/core/factory.py new file mode 100644 index 00000000..5dbc2361 --- /dev/null +++ b/{{cookiecutter.project_slug}}/tests/core/factory.py @@ -0,0 +1,13 @@ +from faker import Faker + +from django.core.files.uploadedfile import SimpleUploadedFile + +from core.testing import register +from core.testing.types import FactoryProtocol + +faker = Faker() + + +@register +def image(self: FactoryProtocol, name: str = "image.gif", content_type: str = "image/gif") -> SimpleUploadedFile: + return SimpleUploadedFile(name=name, content=faker.image(), content_type=content_type) diff --git a/{{cookiecutter.project_slug}}/src/app/factory.py b/{{cookiecutter.project_slug}}/tests/core/factory.py~ similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/factory.py rename to {{cookiecutter.project_slug}}/tests/core/factory.py~ diff --git a/{{cookiecutter.project_slug}}/tests/core/fixtures.py b/{{cookiecutter.project_slug}}/tests/core/fixtures.py new file mode 100644 index 00000000..be464894 --- /dev/null +++ b/{{cookiecutter.project_slug}}/tests/core/fixtures.py @@ -0,0 +1,24 @@ +import pytest + +from typing import TYPE_CHECKING + +from core.testing import ApiClient +from core.testing.factory import FixtureFactory + +if TYPE_CHECKING: + from apps.users.models import User + + +@pytest.fixture +def as_anon() -> "ApiClient": + return ApiClient() + + +@pytest.fixture +def as_user(user: "User") -> "ApiClient": + return ApiClient(user=user) + + +@pytest.fixture +def factory() -> "FixtureFactory": + return FixtureFactory() diff --git a/{{cookiecutter.project_slug}}/tests/core/fixtures.py~ b/{{cookiecutter.project_slug}}/tests/core/fixtures.py~ new file mode 100644 index 00000000..06dd91aa --- /dev/null +++ b/{{cookiecutter.project_slug}}/tests/core/fixtures.py~ @@ -0,0 +1,23 @@ +import pytest + +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from apps.users.models import User + from core.testing import ApiClient + from core.testing.factory import FixtureFactory + + +@pytest.fixture +def as_anon() -> "ApiClient": + return ApiClient() + + +@pytest.fixture +def as_user(user: "User") -> "ApiClient": + return ApiClient(user=user) + + +@pytest.fixture +def factory() -> "FixtureFactory": + return FixtureFactory() diff --git a/{{cookiecutter.project_slug}}/src/app/tests/test_health.py b/{{cookiecutter.project_slug}}/tests/core/test_health.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/tests/test_health.py rename to {{cookiecutter.project_slug}}/tests/core/test_health.py diff --git a/{{cookiecutter.project_slug}}/src/app/tests/test_remote_addr_midlleware.py b/{{cookiecutter.project_slug}}/tests/core/test_remote_addr_midlleware.py similarity index 91% rename from {{cookiecutter.project_slug}}/src/app/tests/test_remote_addr_midlleware.py rename to {{cookiecutter.project_slug}}/tests/core/test_remote_addr_midlleware.py index 44952417..d3b1662f 100644 --- a/{{cookiecutter.project_slug}}/src/app/tests/test_remote_addr_midlleware.py +++ b/{{cookiecutter.project_slug}}/tests/core/test_remote_addr_midlleware.py @@ -2,7 +2,7 @@ from django.apps import apps -from app.testing.api import ApiClient +from core.testing.api import ApiClient pytestmark = [pytest.mark.django_db] @@ -10,7 +10,7 @@ @pytest.fixture(autouse=True) def _require_users_app_installed(settings): assert apps.is_installed( - "users" + "apps.users" ), """ Stock f213/django users app should be installed to run this test. diff --git a/{{cookiecutter.project_slug}}/tests/core/test_remote_addr_midlleware.py~ b/{{cookiecutter.project_slug}}/tests/core/test_remote_addr_midlleware.py~ new file mode 100644 index 00000000..43b4bfaf --- /dev/null +++ b/{{cookiecutter.project_slug}}/tests/core/test_remote_addr_midlleware.py~ @@ -0,0 +1,30 @@ +import pytest + +from django.apps import apps + +from core.testing.api import ApiClient + +pytestmark = [pytest.mark.django_db] + + +@pytest.fixture(autouse=True) +def _require_users_app_installed(settings): + assert apps.is_installed( + "users" + ), """ + Stock f213/django users app should be installed to run this test. + + Make sure to test app.middleware.real_ip.real_ip_middleware on your own, if you drop + the stock users app. + """ + + +@pytest.fixture +def api(user): + return ApiClient(user=user, HTTP_X_FORWARDED_FOR="100.200.250.150, 10.0.0.1") + + +def test_remote_addr(api): + result = api.get("/api/v1/users/me/") + + assert result["remoteAddr"] == "100.200.250.150" diff --git a/{{cookiecutter.project_slug}}/src/users/migrations/__init__.py b/{{cookiecutter.project_slug}}/tests/core/testing/__init__.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/users/migrations/__init__.py rename to {{cookiecutter.project_slug}}/tests/core/testing/__init__.py diff --git a/{{cookiecutter.project_slug}}/tests/core/testing/factory/__init__.py b/{{cookiecutter.project_slug}}/tests/core/testing/factory/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/{{cookiecutter.project_slug}}/tests/core/testing/factory/test_factory.py b/{{cookiecutter.project_slug}}/tests/core/testing/factory/test_factory.py new file mode 100644 index 00000000..a91f13f0 --- /dev/null +++ b/{{cookiecutter.project_slug}}/tests/core/testing/factory/test_factory.py @@ -0,0 +1,42 @@ +import pytest + +from core.testing import FixtureFactory +from core.testing import register + + +@pytest.fixture +def fixture_factory() -> FixtureFactory: + return FixtureFactory() + + +@pytest.fixture +def registered_method(mocker): + mock = mocker.Mock(name="registered_method", return_value="i should be returned after gettatr") + mock.__name__ = "registered_method" + register(mock) + return mock + + +def test_call_getattr_returns_what_method_returned(fixture_factory: FixtureFactory, registered_method): + result = fixture_factory.registered_method() + + assert result == "i should be returned after gettatr" + + +def test_registered_method_called_with_factory_instance(fixture_factory: FixtureFactory, registered_method): + fixture_factory.registered_method(foo=1) # act + + registered_method.assert_called_with(fixture_factory, foo=1) + + +def test_cycle_returns_given_method_n_times(fixture_factory: FixtureFactory, registered_method, mocker): + fixture_factory.cycle(4).registered_method(bar=1) # act + + registered_method.assert_has_calls( + calls=[ + mocker.call(fixture_factory, bar=1), + mocker.call(fixture_factory, bar=1), + mocker.call(fixture_factory, bar=1), + mocker.call(fixture_factory, bar=1), + ], + ) diff --git a/{{cookiecutter.project_slug}}/src/app/tests/testing/factory/test_factory.py b/{{cookiecutter.project_slug}}/tests/core/testing/factory/test_factory.py~ similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/tests/testing/factory/test_factory.py rename to {{cookiecutter.project_slug}}/tests/core/testing/factory/test_factory.py~ diff --git a/{{cookiecutter.project_slug}}/tests/core/testing/factory/test_registry.py b/{{cookiecutter.project_slug}}/tests/core/testing/factory/test_registry.py new file mode 100644 index 00000000..ba1491ba --- /dev/null +++ b/{{cookiecutter.project_slug}}/tests/core/testing/factory/test_registry.py @@ -0,0 +1,24 @@ +import pytest + +from core.testing.factory import FixtureRegistry +from core.testing.factory import register + + +@pytest.fixture +def fixture_registry() -> FixtureRegistry: + return FixtureRegistry() + + +def test_registry_raises_exception_if_no_method(fixture_registry: FixtureRegistry): + with pytest.raises(AttributeError, match=r"Factory method \“not_real\” not found\."): + fixture_registry.get("not_real") + + +def test_registry_returns_correct_method_after_register_decorator(fixture_registry: FixtureRegistry): + @register + def some_method_to_add(): + pass + + method = fixture_registry.get("some_method_to_add") # act + + assert some_method_to_add == method diff --git a/{{cookiecutter.project_slug}}/src/app/tests/testing/factory/test_registry.py b/{{cookiecutter.project_slug}}/tests/core/testing/factory/test_registry.py~ similarity index 100% rename from {{cookiecutter.project_slug}}/src/app/tests/testing/factory/test_registry.py rename to {{cookiecutter.project_slug}}/tests/core/testing/factory/test_registry.py~ From c97c10d5243ac8289fed7dce1f8ef41348236b8f Mon Sep 17 00:00:00 2001 From: hnthh Date: Tue, 28 Nov 2023 14:03:30 +0300 Subject: [PATCH 002/116] lots of --- .gitignore | 10 +- Makefile | 5 +- cookiecutter.json | 2 +- {{cookiecutter.project_slug}}/Makefile | 3 + {{cookiecutter.project_slug}}/poetry.lock | 2347 +++++++++++++++++ {{cookiecutter.project_slug}}/pyproject.toml | 5 +- .../src/.django-app-template/admin.py-tpl | 4 +- .../src/.django-app-template/factory.py-tpl | 4 - .../src/.django-app-template/fixtures.py-tpl | 4 - .../tests/conftest.py-tpl | 3 - .../src/apps/users/migrations/0001_initial.py | 127 +- .../src/apps/users/models.py | 3 +- .../src/core/.env.ci | 2 +- .../src/core/api/renderers.py | 4 +- .../src/core/api/viewsets.py | 16 +- .../src/core/conf/api.py | 12 +- .../src/core/conf/i18n.py | 14 +- .../src/core/conf/storage.py | 13 +- .../src/core/locale/.gitkeep | 0 .../management/commands/makemigrations.py | 8 +- .../src/core/management/commands/startapp.py | 15 +- .../src/core/models.py | 2 +- .../src/core/testing/factory.py | 4 +- .../a12n/jwt_views/test_obtain_jwt_view.py | 8 +- .../a12n/jwt_views/test_refresh_jwt_token.py | 1 - .../tests/apps/users/factory.py | 2 +- .../tests/core/factory.py | 8 +- .../tests/core/fixtures.py | 1 - .../core/testing/factory/test_factory.py | 16 +- .../core/testing/factory/test_registry.py | 8 +- 30 files changed, 2572 insertions(+), 79 deletions(-) create mode 100644 {{cookiecutter.project_slug}}/poetry.lock delete mode 100644 {{cookiecutter.project_slug}}/src/.django-app-template/factory.py-tpl delete mode 100644 {{cookiecutter.project_slug}}/src/.django-app-template/fixtures.py-tpl delete mode 100644 {{cookiecutter.project_slug}}/src/.django-app-template/tests/conftest.py-tpl delete mode 100644 {{cookiecutter.project_slug}}/src/core/locale/.gitkeep diff --git a/.gitignore b/.gitignore index f8170519..8c17939d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,8 @@ -venv -testproject -.vscode .idea +.vscode + +**/*~ +**/.DS_Store + +testproject +venv diff --git a/Makefile b/Makefile index b5e09466..aa87b8f7 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -VENV=cd testproject/django && poetry run python src/manage.py +VENV = cd testproject && poetry run python src/manage.py test: bootstrap $(VENV) makemigrations --check @@ -6,9 +6,8 @@ test: bootstrap bootstrap: rm -Rf testproject - mkdir -p testproject - cd testproject && cookiecutter --no-input ../ + cookiecutter --no-input ./ coverage: $(VENV) -m pip install pytest-cov diff --git a/cookiecutter.json b/cookiecutter.json index 0e2243ca..9565ae8a 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -1,5 +1,5 @@ { - "project_slug": "django", + "project_slug": "testproject", "email": "", "project_version": "0.0.0-dev", "_copy_without_render": [ diff --git a/{{cookiecutter.project_slug}}/Makefile b/{{cookiecutter.project_slug}}/Makefile index 41117427..4201290c 100644 --- a/{{cookiecutter.project_slug}}/Makefile +++ b/{{cookiecutter.project_slug}}/Makefile @@ -2,10 +2,13 @@ manage = poetry run src/manage.py fmt: poetry run autoflake --in-place --remove-all-unused-imports --recursive src tests + poetry run isort src tests poetry run black src tests lint: $(manage) check + poetry run isort --check-only src tests + poetry run black --check src tests poetry run flake8 src tests poetry run mypy src tests poetry run dotenv-linter src/core/.env.ci diff --git a/{{cookiecutter.project_slug}}/poetry.lock b/{{cookiecutter.project_slug}}/poetry.lock new file mode 100644 index 00000000..02730576 --- /dev/null +++ b/{{cookiecutter.project_slug}}/poetry.lock @@ -0,0 +1,2347 @@ +# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. + +[[package]] +name = "asgiref" +version = "3.7.2" +description = "ASGI specs, helper code, and adapters" +optional = false +python-versions = ">=3.7" +files = [ + {file = "asgiref-3.7.2-py3-none-any.whl", hash = "sha256:89b2ef2247e3b562a16eef663bc0e2e703ec6468e2fa8a5cd61cd449786d4f6e"}, + {file = "asgiref-3.7.2.tar.gz", hash = "sha256:9e0ce3aa93a819ba5b45120216b23878cf6e8525eb3848653452b4192b92afed"}, +] + +[package.extras] +tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] + +[[package]] +name = "astroid" +version = "2.15.8" +description = "An abstract syntax tree for Python with inference support." +optional = false +python-versions = ">=3.7.2" +files = [ + {file = "astroid-2.15.8-py3-none-any.whl", hash = "sha256:1aa149fc5c6589e3d0ece885b4491acd80af4f087baafa3fb5203b113e68cd3c"}, + {file = "astroid-2.15.8.tar.gz", hash = "sha256:6c107453dffee9055899705de3c9ead36e74119cee151e5a9aaf7f0b0e020a6a"}, +] + +[package.dependencies] +lazy-object-proxy = ">=1.4.0" +wrapt = {version = ">=1.14,<2", markers = "python_version >= \"3.11\""} + +[[package]] +name = "asttokens" +version = "2.4.1" +description = "Annotate AST trees with source code positions" +optional = false +python-versions = "*" +files = [ + {file = "asttokens-2.4.1-py2.py3-none-any.whl", hash = "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24"}, + {file = "asttokens-2.4.1.tar.gz", hash = "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0"}, +] + +[package.dependencies] +six = ">=1.12.0" + +[package.extras] +astroid = ["astroid (>=1,<2)", "astroid (>=2,<4)"] +test = ["astroid (>=1,<2)", "astroid (>=2,<4)", "pytest"] + +[[package]] +name = "async-timeout" +version = "4.0.3" +description = "Timeout context manager for asyncio programs" +optional = false +python-versions = ">=3.7" +files = [ + {file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"}, + {file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"}, +] + +[[package]] +name = "attrs" +version = "23.1.0" +description = "Classes Without Boilerplate" +optional = false +python-versions = ">=3.7" +files = [ + {file = "attrs-23.1.0-py3-none-any.whl", hash = "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"}, + {file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"}, +] + +[package.extras] +cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] +dev = ["attrs[docs,tests]", "pre-commit"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] +tests = ["attrs[tests-no-zope]", "zope-interface"] +tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] + +[[package]] +name = "autoflake" +version = "2.2.1" +description = "Removes unused imports and unused variables" +optional = false +python-versions = ">=3.8" +files = [ + {file = "autoflake-2.2.1-py3-none-any.whl", hash = "sha256:265cde0a43c1f44ecfb4f30d95b0437796759d07be7706a2f70e4719234c0f79"}, + {file = "autoflake-2.2.1.tar.gz", hash = "sha256:62b7b6449a692c3c9b0c916919bbc21648da7281e8506bcf8d3f8280e431ebc1"}, +] + +[package.dependencies] +pyflakes = ">=3.0.0" + +[[package]] +name = "bcrypt" +version = "4.0.1" +description = "Modern password hashing for your software and your servers" +optional = false +python-versions = ">=3.6" +files = [ + {file = "bcrypt-4.0.1-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:b1023030aec778185a6c16cf70f359cbb6e0c289fd564a7cfa29e727a1c38f8f"}, + {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:08d2947c490093a11416df18043c27abe3921558d2c03e2076ccb28a116cb6d0"}, + {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0eaa47d4661c326bfc9d08d16debbc4edf78778e6aaba29c1bc7ce67214d4410"}, + {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ae88eca3024bb34bb3430f964beab71226e761f51b912de5133470b649d82344"}, + {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:a522427293d77e1c29e303fc282e2d71864579527a04ddcfda6d4f8396c6c36a"}, + {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:fbdaec13c5105f0c4e5c52614d04f0bca5f5af007910daa8b6b12095edaa67b3"}, + {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:ca3204d00d3cb2dfed07f2d74a25f12fc12f73e606fcaa6975d1f7ae69cacbb2"}, + {file = "bcrypt-4.0.1-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:089098effa1bc35dc055366740a067a2fc76987e8ec75349eb9484061c54f535"}, + {file = "bcrypt-4.0.1-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:e9a51bbfe7e9802b5f3508687758b564069ba937748ad7b9e890086290d2f79e"}, + {file = "bcrypt-4.0.1-cp36-abi3-win32.whl", hash = "sha256:2caffdae059e06ac23fce178d31b4a702f2a3264c20bfb5ff541b338194d8fab"}, + {file = "bcrypt-4.0.1-cp36-abi3-win_amd64.whl", hash = "sha256:8a68f4341daf7522fe8d73874de8906f3a339048ba406be6ddc1b3ccb16fc0d9"}, + {file = "bcrypt-4.0.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf4fa8b2ca74381bb5442c089350f09a3f17797829d958fad058d6e44d9eb83c"}, + {file = "bcrypt-4.0.1-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:67a97e1c405b24f19d08890e7ae0c4f7ce1e56a712a016746c8b2d7732d65d4b"}, + {file = "bcrypt-4.0.1-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b3b85202d95dd568efcb35b53936c5e3b3600c7cdcc6115ba461df3a8e89f38d"}, + {file = "bcrypt-4.0.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbb03eec97496166b704ed663a53680ab57c5084b2fc98ef23291987b525cb7d"}, + {file = "bcrypt-4.0.1-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:5ad4d32a28b80c5fa6671ccfb43676e8c1cc232887759d1cd7b6f56ea4355215"}, + {file = "bcrypt-4.0.1-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b57adba8a1444faf784394de3436233728a1ecaeb6e07e8c22c8848f179b893c"}, + {file = "bcrypt-4.0.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:705b2cea8a9ed3d55b4491887ceadb0106acf7c6387699fca771af56b1cdeeda"}, + {file = "bcrypt-4.0.1-pp39-pypy39_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:2b3ac11cf45161628f1f3733263e63194f22664bf4d0c0f3ab34099c02134665"}, + {file = "bcrypt-4.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:3100851841186c25f127731b9fa11909ab7b1df6fc4b9f8353f4f1fd952fbf71"}, + {file = "bcrypt-4.0.1.tar.gz", hash = "sha256:27d375903ac8261cfe4047f6709d16f7d18d39b1ec92aaf72af989552a650ebd"}, +] + +[package.extras] +tests = ["pytest (>=3.2.1,!=3.3.0)"] +typecheck = ["mypy"] + +[[package]] +name = "black" +version = "23.11.0" +description = "The uncompromising code formatter." +optional = false +python-versions = ">=3.8" +files = [ + {file = "black-23.11.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dbea0bb8575c6b6303cc65017b46351dc5953eea5c0a59d7b7e3a2d2f433a911"}, + {file = "black-23.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:412f56bab20ac85927f3a959230331de5614aecda1ede14b373083f62ec24e6f"}, + {file = "black-23.11.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d136ef5b418c81660ad847efe0e55c58c8208b77a57a28a503a5f345ccf01394"}, + {file = "black-23.11.0-cp310-cp310-win_amd64.whl", hash = "sha256:6c1cac07e64433f646a9a838cdc00c9768b3c362805afc3fce341af0e6a9ae9f"}, + {file = "black-23.11.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cf57719e581cfd48c4efe28543fea3d139c6b6f1238b3f0102a9c73992cbb479"}, + {file = "black-23.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:698c1e0d5c43354ec5d6f4d914d0d553a9ada56c85415700b81dc90125aac244"}, + {file = "black-23.11.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:760415ccc20f9e8747084169110ef75d545f3b0932ee21368f63ac0fee86b221"}, + {file = "black-23.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:58e5f4d08a205b11800332920e285bd25e1a75c54953e05502052738fe16b3b5"}, + {file = "black-23.11.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:45aa1d4675964946e53ab81aeec7a37613c1cb71647b5394779e6efb79d6d187"}, + {file = "black-23.11.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4c44b7211a3a0570cc097e81135faa5f261264f4dfaa22bd5ee2875a4e773bd6"}, + {file = "black-23.11.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a9acad1451632021ee0d146c8765782a0c3846e0e0ea46659d7c4f89d9b212b"}, + {file = "black-23.11.0-cp38-cp38-win_amd64.whl", hash = "sha256:fc7f6a44d52747e65a02558e1d807c82df1d66ffa80a601862040a43ec2e3142"}, + {file = "black-23.11.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7f622b6822f02bfaf2a5cd31fdb7cd86fcf33dab6ced5185c35f5db98260b055"}, + {file = "black-23.11.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:250d7e60f323fcfc8ea6c800d5eba12f7967400eb6c2d21ae85ad31c204fb1f4"}, + {file = "black-23.11.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5133f5507007ba08d8b7b263c7aa0f931af5ba88a29beacc4b2dc23fcefe9c06"}, + {file = "black-23.11.0-cp39-cp39-win_amd64.whl", hash = "sha256:421f3e44aa67138ab1b9bfbc22ee3780b22fa5b291e4db8ab7eee95200726b07"}, + {file = "black-23.11.0-py3-none-any.whl", hash = "sha256:54caaa703227c6e0c87b76326d0862184729a69b73d3b7305b6288e1d830067e"}, + {file = "black-23.11.0.tar.gz", hash = "sha256:4c68855825ff432d197229846f971bc4d6666ce90492e5b02013bcaca4d9ab05"}, +] + +[package.dependencies] +click = ">=8.0.0" +mypy-extensions = ">=0.4.3" +packaging = ">=22.0" +pathspec = ">=0.9.0" +platformdirs = ">=2" + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.7.4)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +uvloop = ["uvloop (>=0.15.2)"] + +[[package]] +name = "certifi" +version = "2023.11.17" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.6" +files = [ + {file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"}, + {file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"}, +] + +[[package]] +name = "cffi" +version = "1.16.0" +description = "Foreign Function Interface for Python calling C code." +optional = false +python-versions = ">=3.8" +files = [ + {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, + {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, + {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, + {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, + {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, + {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, + {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, + {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, + {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, + {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, + {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, + {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, + {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"}, + {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"}, + {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"}, + {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"}, + {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"}, + {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"}, + {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"}, + {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"}, + {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, + {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, + {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, + {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, + {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, + {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, + {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, +] + +[package.dependencies] +pycparser = "*" + +[[package]] +name = "charset-normalizer" +version = "3.3.2" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, + {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, +] + +[[package]] +name = "click" +version = "8.1.7" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +files = [ + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "click-default-group" +version = "1.2.4" +description = "click_default_group" +optional = false +python-versions = ">=2.7" +files = [ + {file = "click_default_group-1.2.4-py2.py3-none-any.whl", hash = "sha256:9b60486923720e7fc61731bdb32b617039aba820e22e1c88766b1125592eaa5f"}, + {file = "click_default_group-1.2.4.tar.gz", hash = "sha256:eb3f3c99ec0d456ca6cd2a7f08f7d4e91771bef51b01bdd9580cc6450fe1251e"}, +] + +[package.dependencies] +click = "*" + +[package.extras] +test = ["pytest"] + +[[package]] +name = "cognitive-complexity" +version = "1.3.0" +description = "Library to calculate Python functions cognitive complexity via code" +optional = false +python-versions = ">=3.6" +files = [ + {file = "cognitive_complexity-1.3.0.tar.gz", hash = "sha256:a0cfbd47dee0b19f4056f892389f501694b205c3af69fb703cc744541e03dde5"}, +] + +[package.dependencies] +setuptools = "*" + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "cryptography" +version = "41.0.5" +description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +optional = false +python-versions = ">=3.7" +files = [ + {file = "cryptography-41.0.5-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:da6a0ff8f1016ccc7477e6339e1d50ce5f59b88905585f77193ebd5068f1e797"}, + {file = "cryptography-41.0.5-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:b948e09fe5fb18517d99994184854ebd50b57248736fd4c720ad540560174ec5"}, + {file = "cryptography-41.0.5-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d38e6031e113b7421db1de0c1b1f7739564a88f1684c6b89234fbf6c11b75147"}, + {file = "cryptography-41.0.5-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e270c04f4d9b5671ebcc792b3ba5d4488bf7c42c3c241a3748e2599776f29696"}, + {file = "cryptography-41.0.5-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ec3b055ff8f1dce8e6ef28f626e0972981475173d7973d63f271b29c8a2897da"}, + {file = "cryptography-41.0.5-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:7d208c21e47940369accfc9e85f0de7693d9a5d843c2509b3846b2db170dfd20"}, + {file = "cryptography-41.0.5-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:8254962e6ba1f4d2090c44daf50a547cd5f0bf446dc658a8e5f8156cae0d8548"}, + {file = "cryptography-41.0.5-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:a48e74dad1fb349f3dc1d449ed88e0017d792997a7ad2ec9587ed17405667e6d"}, + {file = "cryptography-41.0.5-cp37-abi3-win32.whl", hash = "sha256:d3977f0e276f6f5bf245c403156673db103283266601405376f075c849a0b936"}, + {file = "cryptography-41.0.5-cp37-abi3-win_amd64.whl", hash = "sha256:73801ac9736741f220e20435f84ecec75ed70eda90f781a148f1bad546963d81"}, + {file = "cryptography-41.0.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3be3ca726e1572517d2bef99a818378bbcf7d7799d5372a46c79c29eb8d166c1"}, + {file = "cryptography-41.0.5-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:e886098619d3815e0ad5790c973afeee2c0e6e04b4da90b88e6bd06e2a0b1b72"}, + {file = "cryptography-41.0.5-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:573eb7128cbca75f9157dcde974781209463ce56b5804983e11a1c462f0f4e88"}, + {file = "cryptography-41.0.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0c327cac00f082013c7c9fb6c46b7cc9fa3c288ca702c74773968173bda421bf"}, + {file = "cryptography-41.0.5-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:227ec057cd32a41c6651701abc0328135e472ed450f47c2766f23267b792a88e"}, + {file = "cryptography-41.0.5-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:22892cc830d8b2c89ea60148227631bb96a7da0c1b722f2aac8824b1b7c0b6b8"}, + {file = "cryptography-41.0.5-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:5a70187954ba7292c7876734183e810b728b4f3965fbe571421cb2434d279179"}, + {file = "cryptography-41.0.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:88417bff20162f635f24f849ab182b092697922088b477a7abd6664ddd82291d"}, + {file = "cryptography-41.0.5-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c707f7afd813478e2019ae32a7c49cd932dd60ab2d2a93e796f68236b7e1fbf1"}, + {file = "cryptography-41.0.5-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:580afc7b7216deeb87a098ef0674d6ee34ab55993140838b14c9b83312b37b86"}, + {file = "cryptography-41.0.5-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fba1e91467c65fe64a82c689dc6cf58151158993b13eb7a7f3f4b7f395636723"}, + {file = "cryptography-41.0.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:0d2a6a598847c46e3e321a7aef8af1436f11c27f1254933746304ff014664d84"}, + {file = "cryptography-41.0.5.tar.gz", hash = "sha256:392cb88b597247177172e02da6b7a63deeff1937fa6fec3bbf902ebd75d97ec7"}, +] + +[package.dependencies] +cffi = ">=1.12" + +[package.extras] +docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"] +docstest = ["pyenchant (>=1.6.11)", "sphinxcontrib-spelling (>=4.0.1)", "twine (>=1.12.0)"] +nox = ["nox"] +pep8test = ["black", "check-sdist", "mypy", "ruff"] +sdist = ["build"] +ssh = ["bcrypt (>=3.1.5)"] +test = ["pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] +test-randomorder = ["pytest-randomly"] + +[[package]] +name = "decorator" +version = "5.1.1" +description = "Decorators for Humans" +optional = false +python-versions = ">=3.5" +files = [ + {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"}, + {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, +] + +[[package]] +name = "django" +version = "4.2.7" +description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." +optional = false +python-versions = ">=3.8" +files = [ + {file = "Django-4.2.7-py3-none-any.whl", hash = "sha256:e1d37c51ad26186de355cbcec16613ebdabfa9689bbade9c538835205a8abbe9"}, + {file = "Django-4.2.7.tar.gz", hash = "sha256:8e0f1c2c2786b5c0e39fe1afce24c926040fad47c8ea8ad30aaf1188df29fc41"}, +] + +[package.dependencies] +asgiref = ">=3.6.0,<4" +sqlparse = ">=0.3.1" +tzdata = {version = "*", markers = "sys_platform == \"win32\""} + +[package.extras] +argon2 = ["argon2-cffi (>=19.1.0)"] +bcrypt = ["bcrypt"] + +[[package]] +name = "django-axes" +version = "6.1.1" +description = "Keep track of failed login attempts in Django-powered sites." +optional = false +python-versions = ">=3.7" +files = [ + {file = "django-axes-6.1.1.tar.gz", hash = "sha256:cd1bc4f7becc8e9243eb4090dffa258d7d7125ca0ce3153b6ffc920bccbf2c3f"}, + {file = "django_axes-6.1.1-py3-none-any.whl", hash = "sha256:29c48ff5f09046afd5e9a16e96d3bbb79f6c11c59f0a7bbd732559e60d0aa9fa"}, +] + +[package.dependencies] +django = ">=3.2" +setuptools = "*" + +[package.extras] +ipware = ["django-ipware (>=3)"] + +[[package]] +name = "django-behaviors" +version = "0.5.1" +description = "Common behaviors for Django Models, e.g. Timestamps, Publishing, Authoring/Editing and more." +optional = false +python-versions = "*" +files = [ + {file = "django-behaviors-0.5.1.tar.gz", hash = "sha256:75e6828573c25ffa71c8ce6c568d294fc659b3b6d572507b012ce70fbb27aaff"}, + {file = "django_behaviors-0.5.1-py2.py3-none-any.whl", hash = "sha256:1ac2ec9c9e919ca4b962f9dee861a53f5af27749c8d13a21077b5a61fb879501"}, +] + +[[package]] +name = "django-environ" +version = "0.11.2" +description = "A package that allows you to utilize 12factor inspired environment variables to configure your Django application." +optional = false +python-versions = ">=3.6,<4" +files = [ + {file = "django-environ-0.11.2.tar.gz", hash = "sha256:f32a87aa0899894c27d4e1776fa6b477e8164ed7f6b3e410a62a6d72caaf64be"}, + {file = "django_environ-0.11.2-py2.py3-none-any.whl", hash = "sha256:0ff95ab4344bfeff693836aa978e6840abef2e2f1145adff7735892711590c05"}, +] + +[package.extras] +develop = ["coverage[toml] (>=5.0a4)", "furo (>=2021.8.17b43,<2021.9.dev0)", "pytest (>=4.6.11)", "sphinx (>=3.5.0)", "sphinx-notfound-page"] +docs = ["furo (>=2021.8.17b43,<2021.9.dev0)", "sphinx (>=3.5.0)", "sphinx-notfound-page"] +testing = ["coverage[toml] (>=5.0a4)", "pytest (>=4.6.11)"] + +[[package]] +name = "django-filter" +version = "23.4" +description = "Django-filter is a reusable Django application for allowing users to filter querysets dynamically." +optional = false +python-versions = ">=3.7" +files = [ + {file = "django-filter-23.4.tar.gz", hash = "sha256:bed070b38359dce7d2dbe057b165d59773057986356cb809ded983b36c77a976"}, + {file = "django_filter-23.4-py3-none-any.whl", hash = "sha256:526954f18bd7d6423f232a9a7974f58fbc6863908b9fc160de075e01adcc2a5f"}, +] + +[package.dependencies] +Django = ">=3.2" + +[[package]] +name = "django-healthchecks" +version = "1.5.0" +description = "Simple Django app/framework to publish health checks" +optional = false +python-versions = "*" +files = [ + {file = "django-healthchecks-1.5.0.tar.gz", hash = "sha256:0f167deaa30bde59552796799abf2a97a118bc190e8601eef713379703cf9f64"}, + {file = "django_healthchecks-1.5.0-py2.py3-none-any.whl", hash = "sha256:25eb021a4a94240b28d996e82775ad6c3b392a2b262360b965a24b88fcfad78d"}, +] + +[package.dependencies] +certifi = ">=2020.6.20" +Django = ">=3.2" +requests = ">=2.24.0" + +[package.extras] +docs = ["sphinx (>=1.4.0)"] +test = ["coverage[toml] (==5.2)", "flake8 (==3.8.3)", "flake8-blind-except (==0.1.1)", "flake8-debugger (==3.2.1)", "freezegun (==0.3.15)", "isort (==5.0.6)", "pytest (==6.2.5)", "pytest-django (==3.9.0)", "requests-mock (==1.8.0)"] + +[[package]] +name = "django-ipware" +version = "6.0.0" +description = "A Django application to retrieve user's IP address" +optional = false +python-versions = ">=3.8" +files = [ + {file = "django-ipware-6.0.0.tar.gz", hash = "sha256:c656805c824449b5171e6f851f6369000fe204ec03ac9977110a9b0aff4825b6"}, + {file = "django_ipware-6.0.0-py2.py3-none-any.whl", hash = "sha256:5595aa3819d6c82c2a09a307dfe58f3d40bff3e098c2e8508118195ac3270465"}, +] + +[package.dependencies] +python-ipware = ">=2.0.0" + +[[package]] +name = "django-split-settings" +version = "1.2.0" +description = "Organize Django settings into multiple files and directories. Easily override and modify settings. Use wildcards and optional settings files." +optional = false +python-versions = ">=3.7,<4.0" +files = [ + {file = "django-split-settings-1.2.0.tar.gz", hash = "sha256:31415a618256b54c5cee8662cbaa72a890683b8b7465d64ba88fdd3affdd6c60"}, + {file = "django_split_settings-1.2.0-py3-none-any.whl", hash = "sha256:4b3be146776d49c61bd9dcf89fad40edb1544f13ab27a87a0b1aecf5a0d636f4"}, +] + +[[package]] +name = "django-storages" +version = "1.14.2" +description = "Support for many storage backends in Django" +optional = false +python-versions = ">=3.7" +files = [ + {file = "django-storages-1.14.2.tar.gz", hash = "sha256:51b36af28cc5813b98d5f3dfe7459af638d84428c8df4a03990c7d74d1bea4e5"}, + {file = "django_storages-1.14.2-py3-none-any.whl", hash = "sha256:1db759346b52ada6c2efd9f23d8241ecf518813eb31db9e2589207174f58f6ad"}, +] + +[package.dependencies] +Django = ">=3.2" + +[package.extras] +azure = ["azure-core (>=1.13)", "azure-storage-blob (>=12)"] +boto3 = ["boto3 (>=1.4.4)"] +dropbox = ["dropbox (>=7.2.1)"] +google = ["google-cloud-storage (>=1.27)"] +libcloud = ["apache-libcloud"] +s3 = ["boto3 (>=1.4.4)"] +sftp = ["paramiko (>=1.15)"] + +[[package]] +name = "django-stubs" +version = "4.2.6" +description = "Mypy stubs for Django" +optional = false +python-versions = ">=3.8" +files = [ + {file = "django-stubs-4.2.6.tar.gz", hash = "sha256:e60b43de662a199db4b15c803c06669e0ac5035614af291cbd3b91591f7dcc94"}, + {file = "django_stubs-4.2.6-py3-none-any.whl", hash = "sha256:2fcd257884a68dfa02de41ee5410ec805264d9b07d9b5b119e4dea82c7b8345e"}, +] + +[package.dependencies] +django = "*" +django-stubs-ext = ">=4.2.5" +types-pytz = "*" +types-PyYAML = "*" +typing-extensions = "*" + +[package.extras] +compatible-mypy = ["mypy (>=1.6.0,<1.7.0)"] + +[[package]] +name = "django-stubs-ext" +version = "4.2.5" +description = "Monkey-patching and extensions for django-stubs" +optional = false +python-versions = ">=3.8" +files = [ + {file = "django-stubs-ext-4.2.5.tar.gz", hash = "sha256:8c4d1fb5f68419b3b2474c659681a189803e27d6a5e5abf5aa0da57601b58633"}, + {file = "django_stubs_ext-4.2.5-py3-none-any.whl", hash = "sha256:921cd7ae4614e74c234bc0fe86ee75537d163addfe1fc6f134bf03e29d86c01e"}, +] + +[package.dependencies] +django = "*" +typing-extensions = "*" + +[[package]] +name = "djangorestframework" +version = "3.14.0" +description = "Web APIs for Django, made easy." +optional = false +python-versions = ">=3.6" +files = [ + {file = "djangorestframework-3.14.0-py3-none-any.whl", hash = "sha256:eb63f58c9f218e1a7d064d17a70751f528ed4e1d35547fdade9aaf4cd103fd08"}, + {file = "djangorestframework-3.14.0.tar.gz", hash = "sha256:579a333e6256b09489cbe0a067e66abe55c6595d8926be6b99423786334350c8"}, +] + +[package.dependencies] +django = ">=3.0" +pytz = "*" + +[[package]] +name = "djangorestframework-camel-case" +version = "1.4.2" +description = "Camel case JSON support for Django REST framework." +optional = false +python-versions = ">=3.5" +files = [ + {file = "djangorestframework-camel-case-1.4.2.tar.gz", hash = "sha256:cdae75846648abb6585c7470639a1d2fb064dc45f8e8b62aaa50be7f1a7a61f4"}, +] + +[[package]] +name = "djangorestframework-stubs" +version = "3.14.4" +description = "PEP-484 stubs for django-rest-framework" +optional = false +python-versions = ">=3.8" +files = [ + {file = "djangorestframework-stubs-3.14.4.tar.gz", hash = "sha256:8ee8719bfeb647b92cc200e15b3cc9813d2e4468c8190777a55a121542a4b2d4"}, + {file = "djangorestframework_stubs-3.14.4-py3-none-any.whl", hash = "sha256:5be8275dd05d6629b3d1688929586ef7b6bc66b4f3f728b5e0389305f07c7a7f"}, +] + +[package.dependencies] +django-stubs = ">=4.2.5" +mypy = ">=0.991" +requests = ">=2.0.0" +types-PyYAML = ">=5.4.3" +types-requests = ">=0.1.12" +typing-extensions = ">=3.10.0" + +[package.extras] +compatible-mypy = ["mypy (>=1.6.0,<1.7.0)"] +coreapi = ["coreapi (>=2.0.0)"] +markdown = ["types-Markdown (>=0.1.5)"] + +[[package]] +name = "dotenv-linter" +version = "0.4.0" +description = "Linting dotenv files like a charm!" +optional = false +python-versions = ">=3.7,<4.0" +files = [ + {file = "dotenv-linter-0.4.0.tar.gz", hash = "sha256:88ea58482d0f4a79822538155b13b31cd54d213197d157ed06fdd532963583c9"}, + {file = "dotenv_linter-0.4.0-py3-none-any.whl", hash = "sha256:2c73f0fc750f5599ad656f5ab9e62561460a533915ee30feb7259ff2393be6f5"}, +] + +[package.dependencies] +attrs = "*" +click = ">=6,<9" +click_default_group = ">=1.2,<2.0" +ply = ">=3.11,<4.0" +typing_extensions = ">=3.6,<5.0" + +[[package]] +name = "drf-jwt" +version = "1.19.2" +description = "JSON Web Token based authentication for Django REST framework" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +files = [ + {file = "drf-jwt-1.19.2.tar.gz", hash = "sha256:660bc66f992065cef59832adcbbdf871847e9738671c19e5121971e773768235"}, + {file = "drf_jwt-1.19.2-py2.py3-none-any.whl", hash = "sha256:63c3d4ed61a1013958cd63416e2d5c84467d8ae3e6e1be44b1fb58743dbd1582"}, +] + +[package.dependencies] +Django = ">=1.11" +djangorestframework = ">=3.7" +PyJWT = {version = ">=1.5.2,<3.0.0", extras = ["crypto"]} + +[package.extras] +dev = ["tox"] +docs = ["mkdocs (==0.13.2)"] +lint = ["black", "flake8", "isort"] +test = ["mock", "pytest (>=3.0)", "pytest-cov", "pytest-django", "pytest-runner", "six"] + +[[package]] +name = "drf-spectacular" +version = "0.26.5" +description = "Sane and flexible OpenAPI 3 schema generation for Django REST framework" +optional = false +python-versions = ">=3.6" +files = [ + {file = "drf-spectacular-0.26.5.tar.gz", hash = "sha256:aee55330a774ba8a9cbdb125714d1c9ee05a8aafd3ce3be8bfd26527649aeb44"}, + {file = "drf_spectacular-0.26.5-py3-none-any.whl", hash = "sha256:c0002a820b11771fdbf37853deb371947caf0159d1afeeffe7598e964bc1db94"}, +] + +[package.dependencies] +Django = ">=2.2" +djangorestframework = ">=3.10.3" +drf-spectacular-sidecar = {version = "*", optional = true, markers = "extra == \"sidecar\""} +inflection = ">=0.3.1" +jsonschema = ">=2.6.0" +PyYAML = ">=5.1" +uritemplate = ">=2.0.0" + +[package.extras] +offline = ["drf-spectacular-sidecar"] +sidecar = ["drf-spectacular-sidecar"] + +[[package]] +name = "drf-spectacular-sidecar" +version = "2023.10.1" +description = "Serve self-contained distribution builds of Swagger UI and Redoc with Django" +optional = false +python-versions = ">=3.6" +files = [ + {file = "drf-spectacular-sidecar-2023.10.1.tar.gz", hash = "sha256:546a83c173589715e530fad211af60cbcda2db54eb9e0935d44251639332af6d"}, + {file = "drf_spectacular_sidecar-2023.10.1-py3-none-any.whl", hash = "sha256:3d042a6772512f4d238f0385d3430acf5f669f595fd0be2641fe6bbfb4c7b376"}, +] + +[package.dependencies] +Django = ">=2.2" + +[[package]] +name = "eradicate" +version = "2.3.0" +description = "Removes commented-out code." +optional = false +python-versions = "*" +files = [ + {file = "eradicate-2.3.0-py3-none-any.whl", hash = "sha256:2b29b3dd27171f209e4ddd8204b70c02f0682ae95eecb353f10e8d72b149c63e"}, + {file = "eradicate-2.3.0.tar.gz", hash = "sha256:06df115be3b87d0fc1c483db22a2ebb12bcf40585722810d809cc770f5031c37"}, +] + +[[package]] +name = "executing" +version = "2.0.1" +description = "Get the currently executing AST node of a frame, and other information" +optional = false +python-versions = ">=3.5" +files = [ + {file = "executing-2.0.1-py2.py3-none-any.whl", hash = "sha256:eac49ca94516ccc753f9fb5ce82603156e590b27525a8bc32cce8ae302eb61bc"}, + {file = "executing-2.0.1.tar.gz", hash = "sha256:35afe2ce3affba8ee97f2d69927fa823b08b472b7b994e36a52a964b93d16147"}, +] + +[package.extras] +tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich"] + +[[package]] +name = "faker" +version = "12.0.1" +description = "Faker is a Python package that generates fake data for you." +optional = false +python-versions = ">=3.6" +files = [ + {file = "Faker-12.0.1-py3-none-any.whl", hash = "sha256:1dc2811f20e163892fefe7006f2ce00778f8099a40aee265bfa60a13400de63d"}, + {file = "Faker-12.0.1.tar.gz", hash = "sha256:aa7103805ae793277abbb85da9f6f05e76a1a295a9384a8e17c2fba2b3a690cb"}, +] + +[package.dependencies] +python-dateutil = ">=2.4" + +[[package]] +name = "flake8" +version = "6.1.0" +description = "the modular source code checker: pep8 pyflakes and co" +optional = false +python-versions = ">=3.8.1" +files = [ + {file = "flake8-6.1.0-py2.py3-none-any.whl", hash = "sha256:ffdfce58ea94c6580c77888a86506937f9a1a227dfcd15f245d694ae20a6b6e5"}, + {file = "flake8-6.1.0.tar.gz", hash = "sha256:d5b3857f07c030bdb5bf41c7f53799571d75c4491748a3adcd47de929e34cd23"}, +] + +[package.dependencies] +mccabe = ">=0.7.0,<0.8.0" +pycodestyle = ">=2.11.0,<2.12.0" +pyflakes = ">=3.1.0,<3.2.0" + +[[package]] +name = "flake8-absolute-import" +version = "1.0.0.2" +description = "flake8 plugin to require absolute imports" +optional = false +python-versions = ">=3.6" +files = [ + {file = "flake8-absolute-import-1.0.0.2.tar.gz", hash = "sha256:fcb734ac5a9639fa4ffbc6242ae9d6e9d8063f9cd078d6d218597ee883a99d48"}, + {file = "flake8_absolute_import-1.0.0.2-py3-none-any.whl", hash = "sha256:b72142db999ec5e0ac4f4ac57fb8776a2959d07346c4d3742c446f206d45fcef"}, +] + +[package.dependencies] +flake8 = ">=5.0" + +[[package]] +name = "flake8-bugbear" +version = "23.11.26" +description = "A plugin for flake8 finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes and pycodestyle." +optional = false +python-versions = ">=3.8.1" +files = [ + {file = "flake8-bugbear-23.11.26.tar.gz", hash = "sha256:8e36119071bab626b6dab834fadd6d03c06090e9b189e67b4905821df8212fee"}, + {file = "flake8_bugbear-23.11.26-py3-none-any.whl", hash = "sha256:55d00c8a3c48c995c1f0ec0df54f8c9cf530c06035ce53975a03517d2e7f53e5"}, +] + +[package.dependencies] +attrs = ">=19.2.0" +flake8 = ">=6.0.0" + +[package.extras] +dev = ["coverage", "hypothesis", "hypothesmith (>=0.2)", "pre-commit", "pytest", "tox"] + +[[package]] +name = "flake8-cognitive-complexity" +version = "0.1.0" +description = "An extension for flake8 that validates cognitive functions complexity" +optional = false +python-versions = ">=3.6" +files = [ + {file = "flake8_cognitive_complexity-0.1.0.tar.gz", hash = "sha256:f202df054e4f6ff182b659c261922b9c684628a47beb19cb0973c50d6a7831c1"}, +] + +[package.dependencies] +cognitive_complexity = "*" +setuptools = "*" + +[[package]] +name = "flake8-django" +version = "1.4" +description = "Plugin to catch bad style specific to Django Projects." +optional = false +python-versions = ">=3.7.2,<4.0.0" +files = [ + {file = "flake8_django-1.4.tar.gz", hash = "sha256:4debba883084191568e3187416d1d6bdd4abd826da988f197a3c36572e9f30de"}, +] + +[package.dependencies] +astroid = ">=2.15.2,<3.0.0" +flake8 = ">=3.8.4,<7" + +[[package]] +name = "flake8-eradicate" +version = "1.5.0" +description = "Flake8 plugin to find commented out code" +optional = false +python-versions = ">=3.8,<4.0" +files = [ + {file = "flake8_eradicate-1.5.0-py3-none-any.whl", hash = "sha256:18acc922ad7de623f5247c7d5595da068525ec5437dd53b22ec2259b96ce9d22"}, + {file = "flake8_eradicate-1.5.0.tar.gz", hash = "sha256:aee636cb9ecb5594a7cd92d67ad73eb69909e5cc7bd81710cf9d00970f3983a6"}, +] + +[package.dependencies] +attrs = "*" +eradicate = ">=2.0,<3.0" +flake8 = ">5" + +[[package]] +name = "flake8-fixme" +version = "1.1.1" +description = "Check for FIXME, TODO and other temporary developer notes. Plugin for flake8." +optional = false +python-versions = "*" +files = [ + {file = "flake8-fixme-1.1.1.tar.gz", hash = "sha256:50cade07d27a4c30d4f12351478df87339e67640c83041b664724bda6d16f33a"}, + {file = "flake8_fixme-1.1.1-py2.py3-none-any.whl", hash = "sha256:226a6f2ef916730899f29ac140bed5d4a17e5aba79f00a0e3ae1eff1997cb1ac"}, +] + +[[package]] +name = "flake8-pep3101" +version = "2.1.0" +description = "Checks for old string formatting" +optional = false +python-versions = ">=3.8" +files = [ + {file = "flake8_pep3101-2.1.0-py3-none-any.whl", hash = "sha256:2d2b8b997ccf0bf0df91532e861465dcfa32a6a306d1dc98f93889cae49f4231"}, + {file = "flake8_pep3101-2.1.0.tar.gz", hash = "sha256:1b84b61685f1e631f2f710e5d5ed3ca68b5fc45fb9402fa8ae1b8a9a058a3387"}, +] + +[package.dependencies] +flake8 = "*" + +[package.extras] +test = ["pytest"] + +[[package]] +name = "flake8-pie" +version = "0.16.0" +description = "A flake8 extension that implements misc. lints" +optional = false +python-versions = ">=3.7" +files = [ + {file = "flake8-pie-0.16.0.tar.gz", hash = "sha256:b8dcb7b92706fa33d05d92a4b3e49b7a9fd3f0041849166275b646ba50e515ba"}, + {file = "flake8_pie-0.16.0-py3-none-any.whl", hash = "sha256:24cd7849b0eee22e2328b9e9d2a1dea40013b0a3106864bbadd06a4b05dbb71f"}, +] + +[package.dependencies] +typing_extensions = "*" + +[[package]] +name = "flake8-print" +version = "5.0.0" +description = "print statement checker plugin for flake8" +optional = false +python-versions = ">=3.7" +files = [ + {file = "flake8-print-5.0.0.tar.gz", hash = "sha256:76915a2a389cc1c0879636c219eb909c38501d3a43cc8dae542081c9ba48bdf9"}, + {file = "flake8_print-5.0.0-py3-none-any.whl", hash = "sha256:84a1a6ea10d7056b804221ac5e62b1cee1aefc897ce16f2e5c42d3046068f5d8"}, +] + +[package.dependencies] +flake8 = ">=3.0" +pycodestyle = "*" + +[[package]] +name = "flake8-printf-formatting" +version = "1.1.2" +description = "flake8 plugin which forbids printf-style string formatting" +optional = false +python-versions = ">=3.6" +files = [ + {file = "flake8-printf-formatting-1.1.2.tar.gz", hash = "sha256:0f9e1308ac290356e4b271d4f26adfc3f9165680a7b6c221503b0f3e155a2784"}, + {file = "flake8_printf_formatting-1.1.2-py2.py3-none-any.whl", hash = "sha256:d908ffabdf08581043a50572744fd60563d82386630b0335445894120089d2df"}, +] + +[package.dependencies] +flake8 = "*" + +[[package]] +name = "flake8-pyproject" +version = "1.2.3" +description = "Flake8 plug-in loading the configuration from pyproject.toml" +optional = false +python-versions = ">= 3.6" +files = [ + {file = "flake8_pyproject-1.2.3-py3-none-any.whl", hash = "sha256:6249fe53545205af5e76837644dc80b4c10037e73a0e5db87ff562d75fb5bd4a"}, +] + +[package.dependencies] +Flake8 = ">=5" + +[package.extras] +dev = ["pyTest", "pyTest-cov"] + +[[package]] +name = "flake8-variables-names" +version = "0.0.6" +description = "A flake8 extension that helps to make more readable variables names" +optional = false +python-versions = ">=3.7" +files = [ + {file = "flake8_variables_names-0.0.6-py3-none-any.whl", hash = "sha256:4aff935d54b3f7afcd026b4dae55029877bd05a7c507b294b45bc7bf577d7b47"}, + {file = "flake8_variables_names-0.0.6.tar.gz", hash = "sha256:292c50e4813d632aa3adcd02c185e7bb583f5fc8ebe02e70f13c958bfe46ad91"}, +] + +[[package]] +name = "flake8-walrus" +version = "1.2.0" +description = "flake8 plugin which forbids assignment expressions (the walrus operator)" +optional = false +python-versions = ">=3.8" +files = [ + {file = "flake8_walrus-1.2.0-py2.py3-none-any.whl", hash = "sha256:a9f72722188b95a393f8727a0eaeb8f31d9796eeb5a4328c9c4499ccd57e589d"}, + {file = "flake8_walrus-1.2.0.tar.gz", hash = "sha256:5dff966f0cc67abae104349812cd255ef3b5e09a7f768eac39b5a4a39f4d1e73"}, +] + +[package.dependencies] +flake8 = ">=5.0" + +[[package]] +name = "freezegun" +version = "1.2.2" +description = "Let your Python tests travel through time" +optional = false +python-versions = ">=3.6" +files = [ + {file = "freezegun-1.2.2-py3-none-any.whl", hash = "sha256:ea1b963b993cb9ea195adbd893a48d573fda951b0da64f60883d7e988b606c9f"}, + {file = "freezegun-1.2.2.tar.gz", hash = "sha256:cd22d1ba06941384410cd967d8a99d5ae2442f57dfafeff2fda5de8dc5c05446"}, +] + +[package.dependencies] +python-dateutil = ">=2.7" + +[[package]] +name = "idna" +version = "3.6" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.5" +files = [ + {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, + {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, +] + +[[package]] +name = "inflection" +version = "0.5.1" +description = "A port of Ruby on Rails inflector to Python" +optional = false +python-versions = ">=3.5" +files = [ + {file = "inflection-0.5.1-py2.py3-none-any.whl", hash = "sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2"}, + {file = "inflection-0.5.1.tar.gz", hash = "sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417"}, +] + +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.7" +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + +[[package]] +name = "ipython" +version = "8.18.0" +description = "IPython: Productive Interactive Computing" +optional = false +python-versions = ">=3.9" +files = [ + {file = "ipython-8.18.0-py3-none-any.whl", hash = "sha256:d538a7a98ad9b7e018926447a5f35856113a85d08fd68a165d7871ab5175f6e0"}, + {file = "ipython-8.18.0.tar.gz", hash = "sha256:4feb61210160f75e229ce932dbf8b719bff37af123c0b985fd038b14233daa16"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +decorator = "*" +jedi = ">=0.16" +matplotlib-inline = "*" +pexpect = {version = ">4.3", markers = "sys_platform != \"win32\""} +prompt-toolkit = ">=3.0.30,<3.0.37 || >3.0.37,<3.1.0" +pygments = ">=2.4.0" +stack-data = "*" +traitlets = ">=5" + +[package.extras] +all = ["black", "curio", "docrepr", "exceptiongroup", "ipykernel", "ipyparallel", "ipywidgets", "matplotlib", "matplotlib (!=3.2.0)", "nbconvert", "nbformat", "notebook", "numpy (>=1.22)", "pandas", "pickleshare", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio (<0.22)", "qtconsole", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "trio", "typing-extensions"] +black = ["black"] +doc = ["docrepr", "exceptiongroup", "ipykernel", "matplotlib", "pickleshare", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio (<0.22)", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "typing-extensions"] +kernel = ["ipykernel"] +nbconvert = ["nbconvert"] +nbformat = ["nbformat"] +notebook = ["ipywidgets", "notebook"] +parallel = ["ipyparallel"] +qtconsole = ["qtconsole"] +test = ["pickleshare", "pytest (<7.1)", "pytest-asyncio (<0.22)", "testpath"] +test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.22)", "pandas", "pickleshare", "pytest (<7.1)", "pytest-asyncio (<0.22)", "testpath", "trio"] + +[[package]] +name = "isort" +version = "5.12.0" +description = "A Python utility / library to sort Python imports." +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "isort-5.12.0-py3-none-any.whl", hash = "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6"}, + {file = "isort-5.12.0.tar.gz", hash = "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504"}, +] + +[package.extras] +colors = ["colorama (>=0.4.3)"] +pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"] +plugins = ["setuptools"] +requirements-deprecated-finder = ["pip-api", "pipreqs"] + +[[package]] +name = "jedi" +version = "0.19.1" +description = "An autocompletion tool for Python that can be used for text editors." +optional = false +python-versions = ">=3.6" +files = [ + {file = "jedi-0.19.1-py2.py3-none-any.whl", hash = "sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0"}, + {file = "jedi-0.19.1.tar.gz", hash = "sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd"}, +] + +[package.dependencies] +parso = ">=0.8.3,<0.9.0" + +[package.extras] +docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alabaster (==0.7.12)", "babel (==2.9.1)", "chardet (==4.0.0)", "commonmark (==0.8.1)", "docutils (==0.17.1)", "future (==0.18.2)", "idna (==2.10)", "imagesize (==1.2.0)", "mock (==1.0.1)", "packaging (==20.9)", "pyparsing (==2.4.7)", "pytz (==2021.1)", "readthedocs-sphinx-ext (==2.1.4)", "recommonmark (==0.5.0)", "requests (==2.25.1)", "six (==1.15.0)", "snowballstemmer (==2.1.0)", "sphinx (==1.8.5)", "sphinx-rtd-theme (==0.4.3)", "sphinxcontrib-serializinghtml (==1.1.4)", "sphinxcontrib-websupport (==1.2.4)", "urllib3 (==1.26.4)"] +qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] +testing = ["Django", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] + +[[package]] +name = "jsonschema" +version = "4.20.0" +description = "An implementation of JSON Schema validation for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jsonschema-4.20.0-py3-none-any.whl", hash = "sha256:ed6231f0429ecf966f5bc8dfef245998220549cbbcf140f913b7464c52c3b6b3"}, + {file = "jsonschema-4.20.0.tar.gz", hash = "sha256:4f614fd46d8d61258610998997743ec5492a648b33cf478c1ddc23ed4598a5fa"}, +] + +[package.dependencies] +attrs = ">=22.2.0" +jsonschema-specifications = ">=2023.03.6" +referencing = ">=0.28.4" +rpds-py = ">=0.7.1" + +[package.extras] +format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"] +format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=1.11)"] + +[[package]] +name = "jsonschema-specifications" +version = "2023.11.1" +description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jsonschema_specifications-2023.11.1-py3-none-any.whl", hash = "sha256:f596778ab612b3fd29f72ea0d990393d0540a5aab18bf0407a46632eab540779"}, + {file = "jsonschema_specifications-2023.11.1.tar.gz", hash = "sha256:c9b234904ffe02f079bf91b14d79987faa685fd4b39c377a0996954c0090b9ca"}, +] + +[package.dependencies] +referencing = ">=0.31.0" + +[[package]] +name = "lazy-object-proxy" +version = "1.9.0" +description = "A fast and thorough lazy object proxy." +optional = false +python-versions = ">=3.7" +files = [ + {file = "lazy-object-proxy-1.9.0.tar.gz", hash = "sha256:659fb5809fa4629b8a1ac5106f669cfc7bef26fbb389dda53b3e010d1ac4ebae"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b40387277b0ed2d0602b8293b94d7257e17d1479e257b4de114ea11a8cb7f2d7"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8c6cfb338b133fbdbc5cfaa10fe3c6aeea827db80c978dbd13bc9dd8526b7d4"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:721532711daa7db0d8b779b0bb0318fa87af1c10d7fe5e52ef30f8eff254d0cd"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:66a3de4a3ec06cd8af3f61b8e1ec67614fbb7c995d02fa224813cb7afefee701"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1aa3de4088c89a1b69f8ec0dcc169aa725b0ff017899ac568fe44ddc1396df46"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-win32.whl", hash = "sha256:f0705c376533ed2a9e5e97aacdbfe04cecd71e0aa84c7c0595d02ef93b6e4455"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:ea806fd4c37bf7e7ad82537b0757999264d5f70c45468447bb2b91afdbe73a6e"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:946d27deaff6cf8452ed0dba83ba38839a87f4f7a9732e8f9fd4107b21e6ff07"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79a31b086e7e68b24b99b23d57723ef7e2c6d81ed21007b6281ebcd1688acb0a"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f699ac1c768270c9e384e4cbd268d6e67aebcfae6cd623b4d7c3bfde5a35db59"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bfb38f9ffb53b942f2b5954e0f610f1e721ccebe9cce9025a38c8ccf4a5183a4"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:189bbd5d41ae7a498397287c408617fe5c48633e7755287b21d741f7db2706a9"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-win32.whl", hash = "sha256:81fc4d08b062b535d95c9ea70dbe8a335c45c04029878e62d744bdced5141586"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:f2457189d8257dd41ae9b434ba33298aec198e30adf2dcdaaa3a28b9994f6adb"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d9e25ef10a39e8afe59a5c348a4dbf29b4868ab76269f81ce1674494e2565a6e"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cbf9b082426036e19c6924a9ce90c740a9861e2bdc27a4834fd0a910742ac1e8"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f5fa4a61ce2438267163891961cfd5e32ec97a2c444e5b842d574251ade27d2"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:8fa02eaab317b1e9e03f69aab1f91e120e7899b392c4fc19807a8278a07a97e8"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e7c21c95cae3c05c14aafffe2865bbd5e377cfc1348c4f7751d9dc9a48ca4bda"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-win32.whl", hash = "sha256:f12ad7126ae0c98d601a7ee504c1122bcef553d1d5e0c3bfa77b16b3968d2734"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-win_amd64.whl", hash = "sha256:edd20c5a55acb67c7ed471fa2b5fb66cb17f61430b7a6b9c3b4a1e40293b1671"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2d0daa332786cf3bb49e10dc6a17a52f6a8f9601b4cf5c295a4f85854d61de63"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cd077f3d04a58e83d04b20e334f678c2b0ff9879b9375ed107d5d07ff160171"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:660c94ea760b3ce47d1855a30984c78327500493d396eac4dfd8bd82041b22be"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:212774e4dfa851e74d393a2370871e174d7ff0ebc980907723bb67d25c8a7c30"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f0117049dd1d5635bbff65444496c90e0baa48ea405125c088e93d9cf4525b11"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-win32.whl", hash = "sha256:0a891e4e41b54fd5b8313b96399f8b0e173bbbfc03c7631f01efbe29bb0bcf82"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:9990d8e71b9f6488e91ad25f322898c136b008d87bf852ff65391b004da5e17b"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9e7551208b2aded9c1447453ee366f1c4070602b3d932ace044715d89666899b"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f83ac4d83ef0ab017683d715ed356e30dd48a93746309c8f3517e1287523ef4"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7322c3d6f1766d4ef1e51a465f47955f1e8123caee67dd641e67d539a534d006"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:18b78ec83edbbeb69efdc0e9c1cb41a3b1b1ed11ddd8ded602464c3fc6020494"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:09763491ce220c0299688940f8dc2c5d05fd1f45af1e42e636b2e8b2303e4382"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-win32.whl", hash = "sha256:9090d8e53235aa280fc9239a86ae3ea8ac58eff66a705fa6aa2ec4968b95c821"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:db1c1722726f47e10e0b5fdbf15ac3b8adb58c091d12b3ab713965795036985f"}, +] + +[[package]] +name = "matplotlib-inline" +version = "0.1.6" +description = "Inline Matplotlib backend for Jupyter" +optional = false +python-versions = ">=3.5" +files = [ + {file = "matplotlib-inline-0.1.6.tar.gz", hash = "sha256:f887e5f10ba98e8d2b150ddcf4702c1e5f8b3a20005eb0f74bfdbd360ee6f304"}, + {file = "matplotlib_inline-0.1.6-py3-none-any.whl", hash = "sha256:f1f41aab5328aa5aaea9b16d083b128102f8712542f819fe7e6a420ff581b311"}, +] + +[package.dependencies] +traitlets = "*" + +[[package]] +name = "mccabe" +version = "0.7.0" +description = "McCabe checker, plugin for flake8" +optional = false +python-versions = ">=3.6" +files = [ + {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, + {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, +] + +[[package]] +name = "mixer" +version = "7.2.2" +description = "Mixer -- Is a fixtures replacement. Supported Django ORM, SqlAlchemy ORM, Mongoengine ODM and custom python objects." +optional = false +python-versions = ">=3.7" +files = [ + {file = "mixer-7.2.2-py3-none-any.whl", hash = "sha256:8089b8e2d00288c77e622936198f5dd03c8ac1603a1530a4f870dc213363b2ae"}, + {file = "mixer-7.2.2.tar.gz", hash = "sha256:9b3f1a261b56d8f2394f39955f83adbc7ff3ab4bb1065ebfec19a10d3e8501e0"}, +] + +[package.dependencies] +Faker = ">=5.4.0,<12.1" + +[package.extras] +tests = ["Django (>=3.0)", "Flask (>=1.0)", "Marshmallow (>=3.9)", "SQLAlchemy (>=1.1.4)", "flask-sqlalchemy (>=2.1)", "mongoengine (>=0.10.1)", "peewee (>=3.7.0)", "pony (>=0.7)", "psycopg2-binary (>=2.8.4)", "pytest"] + +[[package]] +name = "mypy" +version = "1.7.1" +description = "Optional static typing for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "mypy-1.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:12cce78e329838d70a204293e7b29af9faa3ab14899aec397798a4b41be7f340"}, + {file = "mypy-1.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1484b8fa2c10adf4474f016e09d7a159602f3239075c7bf9f1627f5acf40ad49"}, + {file = "mypy-1.7.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31902408f4bf54108bbfb2e35369877c01c95adc6192958684473658c322c8a5"}, + {file = "mypy-1.7.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f2c2521a8e4d6d769e3234350ba7b65ff5d527137cdcde13ff4d99114b0c8e7d"}, + {file = "mypy-1.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:fcd2572dd4519e8a6642b733cd3a8cfc1ef94bafd0c1ceed9c94fe736cb65b6a"}, + {file = "mypy-1.7.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4b901927f16224d0d143b925ce9a4e6b3a758010673eeded9b748f250cf4e8f7"}, + {file = "mypy-1.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2f7f6985d05a4e3ce8255396df363046c28bea790e40617654e91ed580ca7c51"}, + {file = "mypy-1.7.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:944bdc21ebd620eafefc090cdf83158393ec2b1391578359776c00de00e8907a"}, + {file = "mypy-1.7.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9c7ac372232c928fff0645d85f273a726970c014749b924ce5710d7d89763a28"}, + {file = "mypy-1.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:f6efc9bd72258f89a3816e3a98c09d36f079c223aa345c659622f056b760ab42"}, + {file = "mypy-1.7.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6dbdec441c60699288adf051f51a5d512b0d818526d1dcfff5a41f8cd8b4aaf1"}, + {file = "mypy-1.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4fc3d14ee80cd22367caaaf6e014494415bf440980a3045bf5045b525680ac33"}, + {file = "mypy-1.7.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c6e4464ed5f01dc44dc9821caf67b60a4e5c3b04278286a85c067010653a0eb"}, + {file = "mypy-1.7.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:d9b338c19fa2412f76e17525c1b4f2c687a55b156320acb588df79f2e6fa9fea"}, + {file = "mypy-1.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:204e0d6de5fd2317394a4eff62065614c4892d5a4d1a7ee55b765d7a3d9e3f82"}, + {file = "mypy-1.7.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:84860e06ba363d9c0eeabd45ac0fde4b903ad7aa4f93cd8b648385a888e23200"}, + {file = "mypy-1.7.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8c5091ebd294f7628eb25ea554852a52058ac81472c921150e3a61cdd68f75a7"}, + {file = "mypy-1.7.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40716d1f821b89838589e5b3106ebbc23636ffdef5abc31f7cd0266db936067e"}, + {file = "mypy-1.7.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5cf3f0c5ac72139797953bd50bc6c95ac13075e62dbfcc923571180bebb662e9"}, + {file = "mypy-1.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:78e25b2fd6cbb55ddfb8058417df193f0129cad5f4ee75d1502248e588d9e0d7"}, + {file = "mypy-1.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:75c4d2a6effd015786c87774e04331b6da863fc3fc4e8adfc3b40aa55ab516fe"}, + {file = "mypy-1.7.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2643d145af5292ee956aa0a83c2ce1038a3bdb26e033dadeb2f7066fb0c9abce"}, + {file = "mypy-1.7.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75aa828610b67462ffe3057d4d8a4112105ed211596b750b53cbfe182f44777a"}, + {file = "mypy-1.7.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ee5d62d28b854eb61889cde4e1dbc10fbaa5560cb39780c3995f6737f7e82120"}, + {file = "mypy-1.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:72cf32ce7dd3562373f78bd751f73c96cfb441de147cc2448a92c1a308bd0ca6"}, + {file = "mypy-1.7.1-py3-none-any.whl", hash = "sha256:f7c5d642db47376a0cc130f0de6d055056e010debdaf0707cd2b0fc7e7ef30ea"}, + {file = "mypy-1.7.1.tar.gz", hash = "sha256:fcb6d9afb1b6208b4c712af0dafdc650f518836065df0d4fb1d800f5d6773db2"}, +] + +[package.dependencies] +mypy-extensions = ">=1.0.0" +typing-extensions = ">=4.1.0" + +[package.extras] +dmypy = ["psutil (>=4.0)"] +install-types = ["pip"] +mypyc = ["setuptools (>=50)"] +reports = ["lxml"] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.5" +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[[package]] +name = "packaging" +version = "23.2" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, + {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, +] + +[[package]] +name = "parso" +version = "0.8.3" +description = "A Python Parser" +optional = false +python-versions = ">=3.6" +files = [ + {file = "parso-0.8.3-py2.py3-none-any.whl", hash = "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"}, + {file = "parso-0.8.3.tar.gz", hash = "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0"}, +] + +[package.extras] +qa = ["flake8 (==3.8.3)", "mypy (==0.782)"] +testing = ["docopt", "pytest (<6.0.0)"] + +[[package]] +name = "pathspec" +version = "0.11.2" +description = "Utility library for gitignore style pattern matching of file paths." +optional = false +python-versions = ">=3.7" +files = [ + {file = "pathspec-0.11.2-py3-none-any.whl", hash = "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"}, + {file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"}, +] + +[[package]] +name = "pexpect" +version = "4.9.0" +description = "Pexpect allows easy control of interactive console applications." +optional = false +python-versions = "*" +files = [ + {file = "pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"}, + {file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"}, +] + +[package.dependencies] +ptyprocess = ">=0.5" + +[[package]] +name = "pillow" +version = "10.1.0" +description = "Python Imaging Library (Fork)" +optional = false +python-versions = ">=3.8" +files = [ + {file = "Pillow-10.1.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1ab05f3db77e98f93964697c8efc49c7954b08dd61cff526b7f2531a22410106"}, + {file = "Pillow-10.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6932a7652464746fcb484f7fc3618e6503d2066d853f68a4bd97193a3996e273"}, + {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5f63b5a68daedc54c7c3464508d8c12075e56dcfbd42f8c1bf40169061ae666"}, + {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0949b55eb607898e28eaccb525ab104b2d86542a85c74baf3a6dc24002edec2"}, + {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:ae88931f93214777c7a3aa0a8f92a683f83ecde27f65a45f95f22d289a69e593"}, + {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b0eb01ca85b2361b09480784a7931fc648ed8b7836f01fb9241141b968feb1db"}, + {file = "Pillow-10.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d27b5997bdd2eb9fb199982bb7eb6164db0426904020dc38c10203187ae2ff2f"}, + {file = "Pillow-10.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7df5608bc38bd37ef585ae9c38c9cd46d7c81498f086915b0f97255ea60c2818"}, + {file = "Pillow-10.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:41f67248d92a5e0a2076d3517d8d4b1e41a97e2df10eb8f93106c89107f38b57"}, + {file = "Pillow-10.1.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1fb29c07478e6c06a46b867e43b0bcdb241b44cc52be9bc25ce5944eed4648e7"}, + {file = "Pillow-10.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2cdc65a46e74514ce742c2013cd4a2d12e8553e3a2563c64879f7c7e4d28bce7"}, + {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50d08cd0a2ecd2a8657bd3d82c71efd5a58edb04d9308185d66c3a5a5bed9610"}, + {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:062a1610e3bc258bff2328ec43f34244fcec972ee0717200cb1425214fe5b839"}, + {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:61f1a9d247317fa08a308daaa8ee7b3f760ab1809ca2da14ecc88ae4257d6172"}, + {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a646e48de237d860c36e0db37ecaecaa3619e6f3e9d5319e527ccbc8151df061"}, + {file = "Pillow-10.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:47e5bf85b80abc03be7455c95b6d6e4896a62f6541c1f2ce77a7d2bb832af262"}, + {file = "Pillow-10.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a92386125e9ee90381c3369f57a2a50fa9e6aa8b1cf1d9c4b200d41a7dd8e992"}, + {file = "Pillow-10.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:0f7c276c05a9767e877a0b4c5050c8bee6a6d960d7f0c11ebda6b99746068c2a"}, + {file = "Pillow-10.1.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:a89b8312d51715b510a4fe9fc13686283f376cfd5abca8cd1c65e4c76e21081b"}, + {file = "Pillow-10.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:00f438bb841382b15d7deb9a05cc946ee0f2c352653c7aa659e75e592f6fa17d"}, + {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d929a19f5469b3f4df33a3df2983db070ebb2088a1e145e18facbc28cae5b27"}, + {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a92109192b360634a4489c0c756364c0c3a2992906752165ecb50544c251312"}, + {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:0248f86b3ea061e67817c47ecbe82c23f9dd5d5226200eb9090b3873d3ca32de"}, + {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:9882a7451c680c12f232a422730f986a1fcd808da0fd428f08b671237237d651"}, + {file = "Pillow-10.1.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1c3ac5423c8c1da5928aa12c6e258921956757d976405e9467c5f39d1d577a4b"}, + {file = "Pillow-10.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:806abdd8249ba3953c33742506fe414880bad78ac25cc9a9b1c6ae97bedd573f"}, + {file = "Pillow-10.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:eaed6977fa73408b7b8a24e8b14e59e1668cfc0f4c40193ea7ced8e210adf996"}, + {file = "Pillow-10.1.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:fe1e26e1ffc38be097f0ba1d0d07fcade2bcfd1d023cda5b29935ae8052bd793"}, + {file = "Pillow-10.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7a7e3daa202beb61821c06d2517428e8e7c1aab08943e92ec9e5755c2fc9ba5e"}, + {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:24fadc71218ad2b8ffe437b54876c9382b4a29e030a05a9879f615091f42ffc2"}, + {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa1d323703cfdac2036af05191b969b910d8f115cf53093125e4058f62012c9a"}, + {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:912e3812a1dbbc834da2b32299b124b5ddcb664ed354916fd1ed6f193f0e2d01"}, + {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:7dbaa3c7de82ef37e7708521be41db5565004258ca76945ad74a8e998c30af8d"}, + {file = "Pillow-10.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9d7bc666bd8c5a4225e7ac71f2f9d12466ec555e89092728ea0f5c0c2422ea80"}, + {file = "Pillow-10.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:baada14941c83079bf84c037e2d8b7506ce201e92e3d2fa0d1303507a8538212"}, + {file = "Pillow-10.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:2ef6721c97894a7aa77723740a09547197533146fba8355e86d6d9a4a1056b14"}, + {file = "Pillow-10.1.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0a026c188be3b443916179f5d04548092e253beb0c3e2ee0a4e2cdad72f66099"}, + {file = "Pillow-10.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:04f6f6149f266a100374ca3cc368b67fb27c4af9f1cc8cb6306d849dcdf12616"}, + {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb40c011447712d2e19cc261c82655f75f32cb724788df315ed992a4d65696bb"}, + {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a8413794b4ad9719346cd9306118450b7b00d9a15846451549314a58ac42219"}, + {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:c9aeea7b63edb7884b031a35305629a7593272b54f429a9869a4f63a1bf04c34"}, + {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b4005fee46ed9be0b8fb42be0c20e79411533d1fd58edabebc0dd24626882cfd"}, + {file = "Pillow-10.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4d0152565c6aa6ebbfb1e5d8624140a440f2b99bf7afaafbdbf6430426497f28"}, + {file = "Pillow-10.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d921bc90b1defa55c9917ca6b6b71430e4286fc9e44c55ead78ca1a9f9eba5f2"}, + {file = "Pillow-10.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:cfe96560c6ce2f4c07d6647af2d0f3c54cc33289894ebd88cfbb3bcd5391e256"}, + {file = "Pillow-10.1.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:937bdc5a7f5343d1c97dc98149a0be7eb9704e937fe3dc7140e229ae4fc572a7"}, + {file = "Pillow-10.1.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1c25762197144e211efb5f4e8ad656f36c8d214d390585d1d21281f46d556ba"}, + {file = "Pillow-10.1.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:afc8eef765d948543a4775f00b7b8c079b3321d6b675dde0d02afa2ee23000b4"}, + {file = "Pillow-10.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:883f216eac8712b83a63f41b76ddfb7b2afab1b74abbb413c5df6680f071a6b9"}, + {file = "Pillow-10.1.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b920e4d028f6442bea9a75b7491c063f0b9a3972520731ed26c83e254302eb1e"}, + {file = "Pillow-10.1.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c41d960babf951e01a49c9746f92c5a7e0d939d1652d7ba30f6b3090f27e412"}, + {file = "Pillow-10.1.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1fafabe50a6977ac70dfe829b2d5735fd54e190ab55259ec8aea4aaea412fa0b"}, + {file = "Pillow-10.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3b834f4b16173e5b92ab6566f0473bfb09f939ba14b23b8da1f54fa63e4b623f"}, + {file = "Pillow-10.1.0.tar.gz", hash = "sha256:e6bf8de6c36ed96c86ea3b6e1d5273c53f46ef518a062464cd7ef5dd2cf92e38"}, +] + +[package.extras] +docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"] +tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] + +[[package]] +name = "platformdirs" +version = "4.0.0" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +optional = false +python-versions = ">=3.7" +files = [ + {file = "platformdirs-4.0.0-py3-none-any.whl", hash = "sha256:118c954d7e949b35437270383a3f2531e99dd93cf7ce4dc8340d3356d30f173b"}, + {file = "platformdirs-4.0.0.tar.gz", hash = "sha256:cb633b2bcf10c51af60beb0ab06d2f1d69064b43abf4c185ca6b28865f3f9731"}, +] + +[package.extras] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] + +[[package]] +name = "pluggy" +version = "1.3.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, + {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "ply" +version = "3.11" +description = "Python Lex & Yacc" +optional = false +python-versions = "*" +files = [ + {file = "ply-3.11-py2.py3-none-any.whl", hash = "sha256:096f9b8350b65ebd2fd1346b12452efe5b9607f7482813ffca50c22722a807ce"}, + {file = "ply-3.11.tar.gz", hash = "sha256:00c7c1aaa88358b9c765b6d3000c6eec0ba42abca5351b095321aef446081da3"}, +] + +[[package]] +name = "prompt-toolkit" +version = "3.0.41" +description = "Library for building powerful interactive command lines in Python" +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "prompt_toolkit-3.0.41-py3-none-any.whl", hash = "sha256:f36fe301fafb7470e86aaf90f036eef600a3210be4decf461a5b1ca8403d3cb2"}, + {file = "prompt_toolkit-3.0.41.tar.gz", hash = "sha256:941367d97fc815548822aa26c2a269fdc4eb21e9ec05fc5d447cf09bad5d75f0"}, +] + +[package.dependencies] +wcwidth = "*" + +[[package]] +name = "psycopg2-binary" +version = "2.9.9" +description = "psycopg2 - Python-PostgreSQL Database Adapter" +optional = false +python-versions = ">=3.7" +files = [ + {file = "psycopg2-binary-2.9.9.tar.gz", hash = "sha256:7f01846810177d829c7692f1f5ada8096762d9172af1b1a28d4ab5b77c923c1c"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c2470da5418b76232f02a2fcd2229537bb2d5a7096674ce61859c3229f2eb202"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c6af2a6d4b7ee9615cbb162b0738f6e1fd1f5c3eda7e5da17861eacf4c717ea7"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:75723c3c0fbbf34350b46a3199eb50638ab22a0228f93fb472ef4d9becc2382b"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83791a65b51ad6ee6cf0845634859d69a038ea9b03d7b26e703f94c7e93dbcf9"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0ef4854e82c09e84cc63084a9e4ccd6d9b154f1dbdd283efb92ecd0b5e2b8c84"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed1184ab8f113e8d660ce49a56390ca181f2981066acc27cf637d5c1e10ce46e"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d2997c458c690ec2bc6b0b7ecbafd02b029b7b4283078d3b32a852a7ce3ddd98"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:b58b4710c7f4161b5e9dcbe73bb7c62d65670a87df7bcce9e1faaad43e715245"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:0c009475ee389757e6e34611d75f6e4f05f0cf5ebb76c6037508318e1a1e0d7e"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8dbf6d1bc73f1d04ec1734bae3b4fb0ee3cb2a493d35ede9badbeb901fb40f6f"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-win32.whl", hash = "sha256:3f78fd71c4f43a13d342be74ebbc0666fe1f555b8837eb113cb7416856c79682"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-win_amd64.whl", hash = "sha256:876801744b0dee379e4e3c38b76fc89f88834bb15bf92ee07d94acd06ec890a0"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ee825e70b1a209475622f7f7b776785bd68f34af6e7a46e2e42f27b659b5bc26"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1ea665f8ce695bcc37a90ee52de7a7980be5161375d42a0b6c6abedbf0d81f0f"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:143072318f793f53819048fdfe30c321890af0c3ec7cb1dfc9cc87aa88241de2"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c332c8d69fb64979ebf76613c66b985414927a40f8defa16cf1bc028b7b0a7b0"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7fc5a5acafb7d6ccca13bfa8c90f8c51f13d8fb87d95656d3950f0158d3ce53"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:977646e05232579d2e7b9c59e21dbe5261f403a88417f6a6512e70d3f8a046be"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b6356793b84728d9d50ead16ab43c187673831e9d4019013f1402c41b1db9b27"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:bc7bb56d04601d443f24094e9e31ae6deec9ccb23581f75343feebaf30423359"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:77853062a2c45be16fd6b8d6de2a99278ee1d985a7bd8b103e97e41c034006d2"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:78151aa3ec21dccd5cdef6c74c3e73386dcdfaf19bced944169697d7ac7482fc"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-win32.whl", hash = "sha256:dc4926288b2a3e9fd7b50dc6a1909a13bbdadfc67d93f3374d984e56f885579d"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-win_amd64.whl", hash = "sha256:b76bedd166805480ab069612119ea636f5ab8f8771e640ae103e05a4aae3e417"}, + {file = "psycopg2_binary-2.9.9-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:8532fd6e6e2dc57bcb3bc90b079c60de896d2128c5d9d6f24a63875a95a088cf"}, + {file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f8544b092a29a6ddd72f3556a9fcf249ec412e10ad28be6a0c0d948924f2212"}, + {file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2d423c8d8a3c82d08fe8af900ad5b613ce3632a1249fd6a223941d0735fce493"}, + {file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e5afae772c00980525f6d6ecf7cbca55676296b580c0e6abb407f15f3706996"}, + {file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e6f98446430fdf41bd36d4faa6cb409f5140c1c2cf58ce0bbdaf16af7d3f119"}, + {file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c77e3d1862452565875eb31bdb45ac62502feabbd53429fdc39a1cc341d681ba"}, + {file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:cb16c65dcb648d0a43a2521f2f0a2300f40639f6f8c1ecbc662141e4e3e1ee07"}, + {file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:911dda9c487075abd54e644ccdf5e5c16773470a6a5d3826fda76699410066fb"}, + {file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:57fede879f08d23c85140a360c6a77709113efd1c993923c59fde17aa27599fe"}, + {file = "psycopg2_binary-2.9.9-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2293b001e319ab0d869d660a704942c9e2cce19745262a8aba2115ef41a0a42a"}, + {file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:03ef7df18daf2c4c07e2695e8cfd5ee7f748a1d54d802330985a78d2a5a6dca9"}, + {file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a602ea5aff39bb9fac6308e9c9d82b9a35c2bf288e184a816002c9fae930b77"}, + {file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8359bf4791968c5a78c56103702000105501adb557f3cf772b2c207284273984"}, + {file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:275ff571376626195ab95a746e6a04c7df8ea34638b99fc11160de91f2fef503"}, + {file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f9b5571d33660d5009a8b3c25dc1db560206e2d2f89d3df1cb32d72c0d117d52"}, + {file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:420f9bbf47a02616e8554e825208cb947969451978dceb77f95ad09c37791dae"}, + {file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:4154ad09dac630a0f13f37b583eae260c6aa885d67dfbccb5b02c33f31a6d420"}, + {file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a148c5d507bb9b4f2030a2025c545fccb0e1ef317393eaba42e7eabd28eb6041"}, + {file = "psycopg2_binary-2.9.9-cp37-cp37m-win32.whl", hash = "sha256:68fc1f1ba168724771e38bee37d940d2865cb0f562380a1fb1ffb428b75cb692"}, + {file = "psycopg2_binary-2.9.9-cp37-cp37m-win_amd64.whl", hash = "sha256:281309265596e388ef483250db3640e5f414168c5a67e9c665cafce9492eda2f"}, + {file = "psycopg2_binary-2.9.9-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:60989127da422b74a04345096c10d416c2b41bd7bf2a380eb541059e4e999980"}, + {file = "psycopg2_binary-2.9.9-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:246b123cc54bb5361588acc54218c8c9fb73068bf227a4a531d8ed56fa3ca7d6"}, + {file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34eccd14566f8fe14b2b95bb13b11572f7c7d5c36da61caf414d23b91fcc5d94"}, + {file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18d0ef97766055fec15b5de2c06dd8e7654705ce3e5e5eed3b6651a1d2a9a152"}, + {file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d3f82c171b4ccd83bbaf35aa05e44e690113bd4f3b7b6cc54d2219b132f3ae55"}, + {file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ead20f7913a9c1e894aebe47cccf9dc834e1618b7aa96155d2091a626e59c972"}, + {file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ca49a8119c6cbd77375ae303b0cfd8c11f011abbbd64601167ecca18a87e7cdd"}, + {file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:323ba25b92454adb36fa425dc5cf6f8f19f78948cbad2e7bc6cdf7b0d7982e59"}, + {file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:1236ed0952fbd919c100bc839eaa4a39ebc397ed1c08a97fc45fee2a595aa1b3"}, + {file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:729177eaf0aefca0994ce4cffe96ad3c75e377c7b6f4efa59ebf003b6d398716"}, + {file = "psycopg2_binary-2.9.9-cp38-cp38-win32.whl", hash = "sha256:804d99b24ad523a1fe18cc707bf741670332f7c7412e9d49cb5eab67e886b9b5"}, + {file = "psycopg2_binary-2.9.9-cp38-cp38-win_amd64.whl", hash = "sha256:a6cdcc3ede532f4a4b96000b6362099591ab4a3e913d70bcbac2b56c872446f7"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:72dffbd8b4194858d0941062a9766f8297e8868e1dd07a7b36212aaa90f49472"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:30dcc86377618a4c8f3b72418df92e77be4254d8f89f14b8e8f57d6d43603c0f"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:31a34c508c003a4347d389a9e6fcc2307cc2150eb516462a7a17512130de109e"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:15208be1c50b99203fe88d15695f22a5bed95ab3f84354c494bcb1d08557df67"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1873aade94b74715be2246321c8650cabf5a0d098a95bab81145ffffa4c13876"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a58c98a7e9c021f357348867f537017057c2ed7f77337fd914d0bedb35dace7"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4686818798f9194d03c9129a4d9a702d9e113a89cb03bffe08c6cf799e053291"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:ebdc36bea43063116f0486869652cb2ed7032dbc59fbcb4445c4862b5c1ecf7f"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:ca08decd2697fdea0aea364b370b1249d47336aec935f87b8bbfd7da5b2ee9c1"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ac05fb791acf5e1a3e39402641827780fe44d27e72567a000412c648a85ba860"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-win32.whl", hash = "sha256:9dba73be7305b399924709b91682299794887cbbd88e38226ed9f6712eabee90"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-win_amd64.whl", hash = "sha256:f7ae5d65ccfbebdfa761585228eb4d0df3a8b15cfb53bd953e713e09fbb12957"}, +] + +[[package]] +name = "ptyprocess" +version = "0.7.0" +description = "Run a subprocess in a pseudo terminal" +optional = false +python-versions = "*" +files = [ + {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, + {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, +] + +[[package]] +name = "pure-eval" +version = "0.2.2" +description = "Safely evaluate AST nodes without side effects" +optional = false +python-versions = "*" +files = [ + {file = "pure_eval-0.2.2-py3-none-any.whl", hash = "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350"}, + {file = "pure_eval-0.2.2.tar.gz", hash = "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3"}, +] + +[package.extras] +tests = ["pytest"] + +[[package]] +name = "pycodestyle" +version = "2.11.1" +description = "Python style guide checker" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pycodestyle-2.11.1-py2.py3-none-any.whl", hash = "sha256:44fe31000b2d866f2e41841b18528a505fbd7fef9017b04eff4e2648a0fadc67"}, + {file = "pycodestyle-2.11.1.tar.gz", hash = "sha256:41ba0e7afc9752dfb53ced5489e89f8186be00e599e712660695b7a75ff2663f"}, +] + +[[package]] +name = "pycparser" +version = "2.21" +description = "C parser in Python" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, + {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, +] + +[[package]] +name = "pyflakes" +version = "3.1.0" +description = "passive checker of Python programs" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pyflakes-3.1.0-py2.py3-none-any.whl", hash = "sha256:4132f6d49cb4dae6819e5379898f2b8cce3c5f23994194c24b77d5da2e36f774"}, + {file = "pyflakes-3.1.0.tar.gz", hash = "sha256:a0aae034c444db0071aa077972ba4768d40c830d9539fd45bf4cd3f8f6992efc"}, +] + +[[package]] +name = "pygments" +version = "2.17.2" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.7" +files = [ + {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"}, + {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"}, +] + +[package.extras] +plugins = ["importlib-metadata"] +windows-terminal = ["colorama (>=0.4.6)"] + +[[package]] +name = "pyjwt" +version = "2.8.0" +description = "JSON Web Token implementation in Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "PyJWT-2.8.0-py3-none-any.whl", hash = "sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320"}, + {file = "PyJWT-2.8.0.tar.gz", hash = "sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de"}, +] + +[package.dependencies] +cryptography = {version = ">=3.4.0", optional = true, markers = "extra == \"crypto\""} + +[package.extras] +crypto = ["cryptography (>=3.4.0)"] +dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"] +docs = ["sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"] +tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] + +[[package]] +name = "pytest" +version = "7.4.3" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-7.4.3-py3-none-any.whl", hash = "sha256:0d009c083ea859a71b76adf7c1d502e4bc170b80a8ef002da5806527b9591fac"}, + {file = "pytest-7.4.3.tar.gz", hash = "sha256:d989d136982de4e3b29dabcc838ad581c64e8ed52c11fbe86ddebd9da0818cd5"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=0.12,<2.0" + +[package.extras] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "pytest-deadfixtures" +version = "2.2.1" +description = "A simple plugin to list unused fixtures in pytest" +optional = false +python-versions = "*" +files = [ + {file = "pytest-deadfixtures-2.2.1.tar.gz", hash = "sha256:ca15938a4e8330993ccec9c6c847383d88b3cd574729530647dc6b492daa9c1e"}, + {file = "pytest_deadfixtures-2.2.1-py2.py3-none-any.whl", hash = "sha256:db71533f2d9456227084e00a1231e732973e299ccb7c37ab92e95032ab6c083e"}, +] + +[package.dependencies] +pytest = ">=3.0.0" + +[[package]] +name = "pytest-django" +version = "4.7.0" +description = "A Django plugin for pytest." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-django-4.7.0.tar.gz", hash = "sha256:92d6fd46b1d79b54fb6b060bbb39428073396cec717d5f2e122a990d4b6aa5e8"}, + {file = "pytest_django-4.7.0-py3-none-any.whl", hash = "sha256:4e1c79d5261ade2dd58d91208017cd8f62cb4710b56e012ecd361d15d5d662a2"}, +] + +[package.dependencies] +pytest = ">=7.0.0" + +[package.extras] +docs = ["sphinx", "sphinx-rtd-theme"] +testing = ["Django", "django-configurations (>=2.0)"] + +[[package]] +name = "pytest-env" +version = "1.1.1" +description = "pytest plugin that allows you to add environment variables." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest_env-1.1.1-py3-none-any.whl", hash = "sha256:2b71b37c6810f28bec790a7b373c777af87352b3a359b3de0edb9d24df5cf8b3"}, + {file = "pytest_env-1.1.1.tar.gz", hash = "sha256:1efb8acce1f6431196150f3b30673443ff05a6fabff64539a9495cd2248adf9e"}, +] + +[package.dependencies] +pytest = ">=7.4.3" + +[package.extras] +test = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "pytest-mock (>=3.12)"] + +[[package]] +name = "pytest-freezegun" +version = "0.4.2" +description = "Wrap tests with fixtures in freeze_time" +optional = false +python-versions = "*" +files = [ + {file = "pytest-freezegun-0.4.2.zip", hash = "sha256:19c82d5633751bf3ec92caa481fb5cffaac1787bd485f0df6436fd6242176949"}, + {file = "pytest_freezegun-0.4.2-py2.py3-none-any.whl", hash = "sha256:5318a6bfb8ba4b709c8471c94d0033113877b3ee02da5bfcd917c1889cde99a7"}, +] + +[package.dependencies] +freezegun = ">0.3" +pytest = ">=3.0.0" + +[[package]] +name = "pytest-mock" +version = "3.12.0" +description = "Thin-wrapper around the mock package for easier use with pytest" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-mock-3.12.0.tar.gz", hash = "sha256:31a40f038c22cad32287bb43932054451ff5583ff094bca6f675df2f8bc1a6e9"}, + {file = "pytest_mock-3.12.0-py3-none-any.whl", hash = "sha256:0972719a7263072da3a21c7f4773069bcc7486027d7e8e1f81d98a47e701bc4f"}, +] + +[package.dependencies] +pytest = ">=5.0" + +[package.extras] +dev = ["pre-commit", "pytest-asyncio", "tox"] + +[[package]] +name = "pytest-randomly" +version = "3.15.0" +description = "Pytest plugin to randomly order tests and control random.seed." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest_randomly-3.15.0-py3-none-any.whl", hash = "sha256:0516f4344b29f4e9cdae8bce31c4aeebf59d0b9ef05927c33354ff3859eeeca6"}, + {file = "pytest_randomly-3.15.0.tar.gz", hash = "sha256:b908529648667ba5e54723088edd6f82252f540cc340d748d1fa985539687047"}, +] + +[package.dependencies] +pytest = "*" + +[[package]] +name = "python-dateutil" +version = "2.8.2" +description = "Extensions to the standard Python datetime module" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +files = [ + {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, + {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, +] + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "python-ipware" +version = "2.0.0" +description = "A Python package to retrieve user's IP address" +optional = false +python-versions = ">=3.7" +files = [ + {file = "python-ipware-2.0.0.tar.gz", hash = "sha256:a52757123c718342f74b16ab2d9d4a531888d69d10b8197c073164635df0a13b"}, + {file = "python_ipware-2.0.0-py3-none-any.whl", hash = "sha256:802858aa13308d572876d1883edae0eae380fe70a51fdefcb46c8a2099240862"}, +] + +[package.extras] +dev = ["coverage[toml]", "coveralls (>=3.3,<4.0)", "ruff", "twine"] + +[[package]] +name = "pytz" +version = "2023.3.post1" +description = "World timezone definitions, modern and historical" +optional = false +python-versions = "*" +files = [ + {file = "pytz-2023.3.post1-py2.py3-none-any.whl", hash = "sha256:ce42d816b81b68506614c11e8937d3aa9e41007ceb50bfdcb0749b921bf646c7"}, + {file = "pytz-2023.3.post1.tar.gz", hash = "sha256:7b4fddbeb94a1eba4b557da24f19fdf9db575192544270a9101d8509f9f43d7b"}, +] + +[[package]] +name = "pyyaml" +version = "6.0.1" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.6" +files = [ + {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, + {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, + {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, + {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, + {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, + {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, + {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, +] + +[[package]] +name = "redis" +version = "5.0.1" +description = "Python client for Redis database and key-value store" +optional = false +python-versions = ">=3.7" +files = [ + {file = "redis-5.0.1-py3-none-any.whl", hash = "sha256:ed4802971884ae19d640775ba3b03aa2e7bd5e8fb8dfaed2decce4d0fc48391f"}, + {file = "redis-5.0.1.tar.gz", hash = "sha256:0dab495cd5753069d3bc650a0dde8a8f9edde16fc5691b689a566eda58100d0f"}, +] + +[package.dependencies] +async-timeout = {version = ">=4.0.2", markers = "python_full_version <= \"3.11.2\""} + +[package.extras] +hiredis = ["hiredis (>=1.0.0)"] +ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)"] + +[[package]] +name = "referencing" +version = "0.31.0" +description = "JSON Referencing + Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "referencing-0.31.0-py3-none-any.whl", hash = "sha256:381b11e53dd93babb55696c71cf42aef2d36b8a150c49bf0bc301e36d536c882"}, + {file = "referencing-0.31.0.tar.gz", hash = "sha256:cc28f2c88fbe7b961a7817a0abc034c09a1e36358f82fedb4ffdf29a25398863"}, +] + +[package.dependencies] +attrs = ">=22.2.0" +rpds-py = ">=0.7.0" + +[[package]] +name = "requests" +version = "2.31.0" +description = "Python HTTP for Humans." +optional = false +python-versions = ">=3.7" +files = [ + {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, + {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, +] + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "rpds-py" +version = "0.13.1" +description = "Python bindings to Rust's persistent data structures (rpds)" +optional = false +python-versions = ">=3.8" +files = [ + {file = "rpds_py-0.13.1-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:83feb0f682d75a09ddc11aa37ba5c07dd9b824b22915207f6176ea458474ff75"}, + {file = "rpds_py-0.13.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fa84bbe22ffa108f91631935c28a623001e335d66e393438258501e618fb0dde"}, + {file = "rpds_py-0.13.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e04f8c76b8d5c70695b4e8f1d0b391d8ef91df00ef488c6c1ffb910176459bc6"}, + {file = "rpds_py-0.13.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:032c242a595629aacace44128f9795110513ad27217b091e834edec2fb09e800"}, + {file = "rpds_py-0.13.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91276caef95556faeb4b8f09fe4439670d3d6206fee78d47ddb6e6de837f0b4d"}, + {file = "rpds_py-0.13.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d22f2cb82e0b40e427a74a93c9a4231335bbc548aed79955dde0b64ea7f88146"}, + {file = "rpds_py-0.13.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63c9e2794329ef070844ff9bfc012004aeddc0468dc26970953709723f76c8a5"}, + {file = "rpds_py-0.13.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c797ea56f36c6f248656f0223b11307fdf4a1886f3555eba371f34152b07677f"}, + {file = "rpds_py-0.13.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:82dbcd6463e580bcfb7561cece35046aaabeac5a9ddb775020160b14e6c58a5d"}, + {file = "rpds_py-0.13.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:736817dbbbd030a69a1faf5413a319976c9c8ba8cdcfa98c022d3b6b2e01eca6"}, + {file = "rpds_py-0.13.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1f36a1e80ef4ed1996445698fd91e0d3e54738bf597c9995118b92da537d7a28"}, + {file = "rpds_py-0.13.1-cp310-none-win32.whl", hash = "sha256:4f13d3f6585bd07657a603780e99beda96a36c86acaba841f131e81393958336"}, + {file = "rpds_py-0.13.1-cp310-none-win_amd64.whl", hash = "sha256:545e94c84575057d3d5c62634611858dac859702b1519b6ffc58eca7fb1adfcf"}, + {file = "rpds_py-0.13.1-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:6bfe72b249264cc1ff2f3629be240d7d2fdc778d9d298087cdec8524c91cd11f"}, + {file = "rpds_py-0.13.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edc91c50e17f5cd945d821f0f1af830522dba0c10267c3aab186dc3dbaab8def"}, + {file = "rpds_py-0.13.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2eca04a365be380ca1f8fa48b334462e19e3382c0bb7386444d8ca43aa01c481"}, + {file = "rpds_py-0.13.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3e3ac5b602fea378243f993d8b707189f9061e55ebb4e56cb9fdef8166060f28"}, + {file = "rpds_py-0.13.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dfb5d2ab183c0efe5e7b8917e4eaa2e837aacafad8a69b89aa6bc81550eed857"}, + {file = "rpds_py-0.13.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d9793d46d3e6522ae58e9321032827c9c0df1e56cbe5d3de965facb311aed6aa"}, + {file = "rpds_py-0.13.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9cd935c0220d012a27c20135c140f9cdcbc6249d5954345c81bfb714071b985c"}, + {file = "rpds_py-0.13.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:37b08df45f02ff1866043b95096cbe91ac99de05936dd09d6611987a82a3306a"}, + {file = "rpds_py-0.13.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ad666a904212aa9a6c77da7dce9d5170008cda76b7776e6731928b3f8a0d40fa"}, + {file = "rpds_py-0.13.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8a6ad8429340e0a4de89353447c6441329def3632e7b2293a7d6e873217d3c2b"}, + {file = "rpds_py-0.13.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7c40851b659d958c5245c1236e34f0d065cc53dca8d978b49a032c8e0adfda6e"}, + {file = "rpds_py-0.13.1-cp311-none-win32.whl", hash = "sha256:4145172ab59b6c27695db6d78d040795f635cba732cead19c78cede74800949a"}, + {file = "rpds_py-0.13.1-cp311-none-win_amd64.whl", hash = "sha256:46a07a258bda12270de02b34c4884f200f864bba3dcd6e3a37fef36a168b859d"}, + {file = "rpds_py-0.13.1-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:ba4432301ad7eeb1b00848cf46fae0e5fecfd18a8cb5fdcf856c67985f79ecc7"}, + {file = "rpds_py-0.13.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d22e0660de24bd8e9ac82f4230a22a5fe4e397265709289d61d5fb333839ba50"}, + {file = "rpds_py-0.13.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76a8374b294e4ccb39ccaf11d39a0537ed107534139c00b4393ca3b542cc66e5"}, + {file = "rpds_py-0.13.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7d152ec7bb431040af2500e01436c9aa0d993f243346f0594a15755016bf0be1"}, + {file = "rpds_py-0.13.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:74a2044b870df7c9360bb3ce7e12f9ddf8e72e49cd3a353a1528cbf166ad2383"}, + {file = "rpds_py-0.13.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:960e7e460fda2d0af18c75585bbe0c99f90b8f09963844618a621b804f8c3abe"}, + {file = "rpds_py-0.13.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37f79f4f1f06cc96151f4a187528c3fd4a7e1065538a4af9eb68c642365957f7"}, + {file = "rpds_py-0.13.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cd4ea56c9542ad0091dfdef3e8572ae7a746e1e91eb56c9e08b8d0808b40f1d1"}, + {file = "rpds_py-0.13.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0290712eb5603a725769b5d857f7cf15cf6ca93dda3128065bbafe6fdb709beb"}, + {file = "rpds_py-0.13.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0b70c1f800059c92479dc94dda41288fd6607f741f9b1b8f89a21a86428f6383"}, + {file = "rpds_py-0.13.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3dd5fb7737224e1497c886fb3ca681c15d9c00c76171f53b3c3cc8d16ccfa7fb"}, + {file = "rpds_py-0.13.1-cp312-none-win32.whl", hash = "sha256:74be3b215a5695690a0f1a9f68b1d1c93f8caad52e23242fcb8ba56aaf060281"}, + {file = "rpds_py-0.13.1-cp312-none-win_amd64.whl", hash = "sha256:f47eef55297799956464efc00c74ae55c48a7b68236856d56183fe1ddf866205"}, + {file = "rpds_py-0.13.1-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:e4a45ba34f904062c63049a760790c6a2fa7a4cc4bd160d8af243b12371aaa05"}, + {file = "rpds_py-0.13.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:20147996376be452cd82cd6c17701daba69a849dc143270fa10fe067bb34562a"}, + {file = "rpds_py-0.13.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42b9535aa22ab023704cfc6533e968f7e420affe802d85e956d8a7b4c0b0b5ea"}, + {file = "rpds_py-0.13.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d4fa1eeb9bea6d9b64ac91ec51ee94cc4fc744955df5be393e1c923c920db2b0"}, + {file = "rpds_py-0.13.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b2415d5a7b7ee96aa3a54d4775c1fec140476a17ee12353806297e900eaeddc"}, + {file = "rpds_py-0.13.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:577d40a72550eac1386b77b43836151cb61ff6700adacda2ad4d883ca5a0b6f2"}, + {file = "rpds_py-0.13.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af2d1648eb625a460eee07d3e1ea3a4a6e84a1fb3a107f6a8e95ac19f7dcce67"}, + {file = "rpds_py-0.13.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5b769396eb358d6b55dbf78f3f7ca631ca1b2fe02136faad5af74f0111b4b6b7"}, + {file = "rpds_py-0.13.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:249c8e0055ca597707d71c5ad85fd2a1c8fdb99386a8c6c257e1b47b67a9bec1"}, + {file = "rpds_py-0.13.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:fe30ef31172bdcf946502a945faad110e8fff88c32c4bec9a593df0280e64d8a"}, + {file = "rpds_py-0.13.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:2647192facf63be9ed2d7a49ceb07efe01dc6cfb083bd2cc53c418437400cb99"}, + {file = "rpds_py-0.13.1-cp38-none-win32.whl", hash = "sha256:4011d5c854aa804c833331d38a2b6f6f2fe58a90c9f615afdb7aa7cf9d31f721"}, + {file = "rpds_py-0.13.1-cp38-none-win_amd64.whl", hash = "sha256:7cfae77da92a20f56cf89739a557b76e5c6edc094f6ad5c090b9e15fbbfcd1a4"}, + {file = "rpds_py-0.13.1-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:e9be1f7c5f9673616f875299339984da9447a40e3aea927750c843d6e5e2e029"}, + {file = "rpds_py-0.13.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:839676475ac2ccd1532d36af3d10d290a2ca149b702ed464131e450a767550df"}, + {file = "rpds_py-0.13.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a90031658805c63fe488f8e9e7a88b260ea121ba3ee9cdabcece9c9ddb50da39"}, + {file = "rpds_py-0.13.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8ba9fbc5d6e36bfeb5292530321cc56c4ef3f98048647fabd8f57543c34174ec"}, + {file = "rpds_py-0.13.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:08832078767545c5ee12561ce980714e1e4c6619b5b1e9a10248de60cddfa1fd"}, + {file = "rpds_py-0.13.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:19f5aa7f5078d35ed8e344bcba40f35bc95f9176dddb33fc4f2084e04289fa63"}, + {file = "rpds_py-0.13.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80080972e1d000ad0341c7cc58b6855c80bd887675f92871221451d13a975072"}, + {file = "rpds_py-0.13.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:181ee352691c4434eb1c01802e9daa5edcc1007ff15023a320e2693fed6a661b"}, + {file = "rpds_py-0.13.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:d20da6b4c7aa9ee75ad0730beaba15d65157f5beeaca54a038bb968f92bf3ce3"}, + {file = "rpds_py-0.13.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:faa12a9f34671a30ea6bb027f04ec4e1fb8fa3fb3ed030893e729d4d0f3a9791"}, + {file = "rpds_py-0.13.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7cf241dbb50ea71c2e628ab2a32b5bfcd36e199152fc44e5c1edb0b773f1583e"}, + {file = "rpds_py-0.13.1-cp39-none-win32.whl", hash = "sha256:dab979662da1c9fbb464e310c0b06cb5f1d174d09a462553af78f0bfb3e01920"}, + {file = "rpds_py-0.13.1-cp39-none-win_amd64.whl", hash = "sha256:a2b3c79586636f1fa69a7bd59c87c15fca80c0d34b5c003d57f2f326e5276575"}, + {file = "rpds_py-0.13.1-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:5967fa631d0ed9f8511dede08bc943a9727c949d05d1efac4ac82b2938024fb7"}, + {file = "rpds_py-0.13.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8308a8d49d1354278d5c068c888a58d7158a419b2e4d87c7839ed3641498790c"}, + {file = "rpds_py-0.13.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0580faeb9def6d0beb7aa666294d5604e569c4e24111ada423cf9936768d95c"}, + {file = "rpds_py-0.13.1-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2da81c1492291c1a90987d76a47c7b2d310661bf7c93a9de0511e27b796a8b46"}, + {file = "rpds_py-0.13.1-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1c9a1dc5e898ce30e2f9c0aa57181cddd4532b22b7780549441d6429d22d3b58"}, + {file = "rpds_py-0.13.1-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4ae6f423cb7d1c6256b7482025ace2825728f53b7ac58bcd574de6ee9d242c2"}, + {file = "rpds_py-0.13.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc3179e0815827cf963e634095ae5715ee73a5af61defbc8d6ca79f1bdae1d1d"}, + {file = "rpds_py-0.13.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0d9f8930092558fd15c9e07198625efb698f7cc00b3dc311c83eeec2540226a8"}, + {file = "rpds_py-0.13.1-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:d1d388d2f5f5a6065cf83c54dd12112b7389095669ff395e632003ae8999c6b8"}, + {file = "rpds_py-0.13.1-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:08b335fb0c45f0a9e2478a9ece6a1bfb00b6f4c4780f9be3cf36479c5d8dd374"}, + {file = "rpds_py-0.13.1-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:d11afdc5992bbd7af60ed5eb519873690d921425299f51d80aa3099ed49f2bcc"}, + {file = "rpds_py-0.13.1-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:8c1f6c8df23be165eb0cb78f305483d00c6827a191e3a38394c658d5b9c80bbd"}, + {file = "rpds_py-0.13.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:528e2afaa56d815d2601b857644aeb395afe7e59212ab0659906dc29ae68d9a6"}, + {file = "rpds_py-0.13.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df2af1180b8eeececf4f819d22cc0668bfadadfd038b19a90bd2fb2ee419ec6f"}, + {file = "rpds_py-0.13.1-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:88956c993a20201744282362e3fd30962a9d86dc4f1dcf2bdb31fab27821b61f"}, + {file = "rpds_py-0.13.1-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee70ee5f4144a45a9e6169000b5b525d82673d5dab9f7587eccc92794814e7ac"}, + {file = "rpds_py-0.13.1-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c5fd099acaee2325f01281a130a39da08d885e4dedf01b84bf156ec2737d78fe"}, + {file = "rpds_py-0.13.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9656a09653b18b80764647d585750df2dff8928e03a706763ab40ec8c4872acc"}, + {file = "rpds_py-0.13.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7ba239bb37663b2b4cd08e703e79e13321512dccd8e5f0e9451d9e53a6b8509a"}, + {file = "rpds_py-0.13.1-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:3f55ae773abd96b1de25fc5c3fb356f491bd19116f8f854ba705beffc1ddc3c5"}, + {file = "rpds_py-0.13.1-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:f4b15a163448ec79241fb2f1bc5a8ae1a4a304f7a48d948d208a2935b26bf8a5"}, + {file = "rpds_py-0.13.1-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:1a3b2583c86bbfbf417304eeb13400ce7f8725376dc7d3efbf35dc5d7052ad48"}, + {file = "rpds_py-0.13.1-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:f1059ca9a51c936c9a8d46fbc2c9a6b4c15ab3f13a97f1ad32f024b39666ba85"}, + {file = "rpds_py-0.13.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:f55601fb58f92e4f4f1d05d80c24cb77505dc42103ddfd63ddfdc51d3da46fa2"}, + {file = "rpds_py-0.13.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fcfd5f91b882eedf8d9601bd21261d6ce0e61a8c66a7152d1f5df08d3f643ab1"}, + {file = "rpds_py-0.13.1-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6574f619e8734140d96c59bfa8a6a6e7a3336820ccd1bfd95ffa610673b650a2"}, + {file = "rpds_py-0.13.1-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a4b9d3f5c48bbe8d9e3758e498b3c34863f2c9b1ac57a4e6310183740e59c980"}, + {file = "rpds_py-0.13.1-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cdd6f8738e1f1d9df5b1603bb03cb30e442710e5672262b95d0f9fcb4edb0dab"}, + {file = "rpds_py-0.13.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8c2bf286e5d755a075e5e97ba56b3de08cccdad6b323ab0b21cc98875176b03"}, + {file = "rpds_py-0.13.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b3d4b390ee70ca9263b331ccfaf9819ee20e90dfd0201a295e23eb64a005dbef"}, + {file = "rpds_py-0.13.1-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:db8d0f0ad92f74feb61c4e4a71f1d573ef37c22ef4dc19cab93e501bfdad8cbd"}, + {file = "rpds_py-0.13.1-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:2abd669a39be69cdfe145927c7eb53a875b157740bf1e2d49e9619fc6f43362e"}, + {file = "rpds_py-0.13.1-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:2c173f529666bab8e3f948b74c6d91afa22ea147e6ebae49a48229d9020a47c4"}, + {file = "rpds_py-0.13.1.tar.gz", hash = "sha256:264f3a5906c62b9df3a00ad35f6da1987d321a053895bd85f9d5c708de5c0fbf"}, +] + +[[package]] +name = "sentry-sdk" +version = "1.37.1" +description = "Python client for Sentry (https://sentry.io)" +optional = false +python-versions = "*" +files = [ + {file = "sentry-sdk-1.37.1.tar.gz", hash = "sha256:7cd324dd2877fdc861f75cba4242bce23a58272a6fea581fcb218bb718bd9cc5"}, + {file = "sentry_sdk-1.37.1-py2.py3-none-any.whl", hash = "sha256:a249c7364827ee89daaa078bb8b56ece0b3d52d9130961bef2302b79bdf7fe70"}, +] + +[package.dependencies] +certifi = "*" +urllib3 = {version = ">=1.26.11", markers = "python_version >= \"3.6\""} + +[package.extras] +aiohttp = ["aiohttp (>=3.5)"] +arq = ["arq (>=0.23)"] +asyncpg = ["asyncpg (>=0.23)"] +beam = ["apache-beam (>=2.12)"] +bottle = ["bottle (>=0.12.13)"] +celery = ["celery (>=3)"] +chalice = ["chalice (>=1.16.0)"] +clickhouse-driver = ["clickhouse-driver (>=0.2.0)"] +django = ["django (>=1.8)"] +falcon = ["falcon (>=1.4)"] +fastapi = ["fastapi (>=0.79.0)"] +flask = ["blinker (>=1.1)", "flask (>=0.11)", "markupsafe"] +grpcio = ["grpcio (>=1.21.1)"] +httpx = ["httpx (>=0.16.0)"] +huey = ["huey (>=2)"] +loguru = ["loguru (>=0.5)"] +opentelemetry = ["opentelemetry-distro (>=0.35b0)"] +opentelemetry-experimental = ["opentelemetry-distro (>=0.40b0,<1.0)", "opentelemetry-instrumentation-aiohttp-client (>=0.40b0,<1.0)", "opentelemetry-instrumentation-django (>=0.40b0,<1.0)", "opentelemetry-instrumentation-fastapi (>=0.40b0,<1.0)", "opentelemetry-instrumentation-flask (>=0.40b0,<1.0)", "opentelemetry-instrumentation-requests (>=0.40b0,<1.0)", "opentelemetry-instrumentation-sqlite3 (>=0.40b0,<1.0)", "opentelemetry-instrumentation-urllib (>=0.40b0,<1.0)"] +pure-eval = ["asttokens", "executing", "pure-eval"] +pymongo = ["pymongo (>=3.1)"] +pyspark = ["pyspark (>=2.4.4)"] +quart = ["blinker (>=1.1)", "quart (>=0.16.1)"] +rq = ["rq (>=0.6)"] +sanic = ["sanic (>=0.8)"] +sqlalchemy = ["sqlalchemy (>=1.2)"] +starlette = ["starlette (>=0.19.1)"] +starlite = ["starlite (>=1.48)"] +tornado = ["tornado (>=5)"] + +[[package]] +name = "setuptools" +version = "69.0.2" +description = "Easily download, build, install, upgrade, and uninstall Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "setuptools-69.0.2-py3-none-any.whl", hash = "sha256:1e8fdff6797d3865f37397be788a4e3cba233608e9b509382a2777d25ebde7f2"}, + {file = "setuptools-69.0.2.tar.gz", hash = "sha256:735896e78a4742605974de002ac60562d286fa8051a7e2299445e8e8fbb01aa6"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] + +[[package]] +name = "sqlparse" +version = "0.4.4" +description = "A non-validating SQL parser." +optional = false +python-versions = ">=3.5" +files = [ + {file = "sqlparse-0.4.4-py3-none-any.whl", hash = "sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3"}, + {file = "sqlparse-0.4.4.tar.gz", hash = "sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c"}, +] + +[package.extras] +dev = ["build", "flake8"] +doc = ["sphinx"] +test = ["pytest", "pytest-cov"] + +[[package]] +name = "stack-data" +version = "0.6.3" +description = "Extract data from python stack frames and tracebacks for informative displays" +optional = false +python-versions = "*" +files = [ + {file = "stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695"}, + {file = "stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9"}, +] + +[package.dependencies] +asttokens = ">=2.1.0" +executing = ">=1.2.0" +pure-eval = "*" + +[package.extras] +tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] + +[[package]] +name = "traitlets" +version = "5.13.0" +description = "Traitlets Python configuration system" +optional = false +python-versions = ">=3.8" +files = [ + {file = "traitlets-5.13.0-py3-none-any.whl", hash = "sha256:baf991e61542da48fe8aef8b779a9ea0aa38d8a54166ee250d5af5ecf4486619"}, + {file = "traitlets-5.13.0.tar.gz", hash = "sha256:9b232b9430c8f57288c1024b34a8f0251ddcc47268927367a0dd3eeaca40deb5"}, +] + +[package.extras] +docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] +test = ["argcomplete (>=3.0.3)", "mypy (>=1.6.0)", "pre-commit", "pytest (>=7.0,<7.5)", "pytest-mock", "pytest-mypy-testing"] + +[[package]] +name = "types-freezegun" +version = "1.1.10" +description = "Typing stubs for freezegun" +optional = false +python-versions = "*" +files = [ + {file = "types-freezegun-1.1.10.tar.gz", hash = "sha256:cb3a2d2eee950eacbaac0673ab50499823365ceb8c655babb1544a41446409ec"}, + {file = "types_freezegun-1.1.10-py3-none-any.whl", hash = "sha256:fadebe72213e0674036153366205038e1f95c8ca96deb4ef9b71ddc15413543e"}, +] + +[[package]] +name = "types-pillow" +version = "10.1.0.2" +description = "Typing stubs for Pillow" +optional = false +python-versions = ">=3.7" +files = [ + {file = "types-Pillow-10.1.0.2.tar.gz", hash = "sha256:525c1c5ee67b0ac1721c40d2bc618226ef2123c347e527e14e05b920721a13b9"}, + {file = "types_Pillow-10.1.0.2-py3-none-any.whl", hash = "sha256:131078ffa547bf9a201d39ffcdc65633e108148085f4f1b07d4647fcfec6e923"}, +] + +[[package]] +name = "types-pytz" +version = "2023.3.1.1" +description = "Typing stubs for pytz" +optional = false +python-versions = "*" +files = [ + {file = "types-pytz-2023.3.1.1.tar.gz", hash = "sha256:cc23d0192cd49c8f6bba44ee0c81e4586a8f30204970fc0894d209a6b08dab9a"}, + {file = "types_pytz-2023.3.1.1-py3-none-any.whl", hash = "sha256:1999a123a3dc0e39a2ef6d19f3f8584211de9e6a77fe7a0259f04a524e90a5cf"}, +] + +[[package]] +name = "types-pyyaml" +version = "6.0.12.12" +description = "Typing stubs for PyYAML" +optional = false +python-versions = "*" +files = [ + {file = "types-PyYAML-6.0.12.12.tar.gz", hash = "sha256:334373d392fde0fdf95af5c3f1661885fa10c52167b14593eb856289e1855062"}, + {file = "types_PyYAML-6.0.12.12-py3-none-any.whl", hash = "sha256:c05bc6c158facb0676674b7f11fe3960db4f389718e19e62bd2b84d6205cfd24"}, +] + +[[package]] +name = "types-requests" +version = "2.31.0.10" +description = "Typing stubs for requests" +optional = false +python-versions = ">=3.7" +files = [ + {file = "types-requests-2.31.0.10.tar.gz", hash = "sha256:dc5852a76f1eaf60eafa81a2e50aefa3d1f015c34cf0cba130930866b1b22a92"}, + {file = "types_requests-2.31.0.10-py3-none-any.whl", hash = "sha256:b32b9a86beffa876c0c3ac99a4cd3b8b51e973fb8e3bd4e0a6bb32c7efad80fc"}, +] + +[package.dependencies] +urllib3 = ">=2" + +[[package]] +name = "typing-extensions" +version = "4.8.0" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typing_extensions-4.8.0-py3-none-any.whl", hash = "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0"}, + {file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"}, +] + +[[package]] +name = "tzdata" +version = "2023.3" +description = "Provider of IANA time zone data" +optional = false +python-versions = ">=2" +files = [ + {file = "tzdata-2023.3-py2.py3-none-any.whl", hash = "sha256:7e65763eef3120314099b6939b5546db7adce1e7d6f2e179e3df563c70511eda"}, + {file = "tzdata-2023.3.tar.gz", hash = "sha256:11ef1e08e54acb0d4f95bdb1be05da659673de4acbd21bf9c69e94cc5e907a3a"}, +] + +[[package]] +name = "uritemplate" +version = "4.1.1" +description = "Implementation of RFC 6570 URI Templates" +optional = false +python-versions = ">=3.6" +files = [ + {file = "uritemplate-4.1.1-py2.py3-none-any.whl", hash = "sha256:830c08b8d99bdd312ea4ead05994a38e8936266f84b9a7878232db50b044e02e"}, + {file = "uritemplate-4.1.1.tar.gz", hash = "sha256:4346edfc5c3b79f694bccd6d6099a322bbeb628dbf2cd86eea55a456ce5124f0"}, +] + +[[package]] +name = "urllib3" +version = "2.1.0" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=3.8" +files = [ + {file = "urllib3-2.1.0-py3-none-any.whl", hash = "sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3"}, + {file = "urllib3-2.1.0.tar.gz", hash = "sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54"}, +] + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] + +[[package]] +name = "wcwidth" +version = "0.2.12" +description = "Measures the displayed width of unicode strings in a terminal" +optional = false +python-versions = "*" +files = [ + {file = "wcwidth-0.2.12-py2.py3-none-any.whl", hash = "sha256:f26ec43d96c8cbfed76a5075dac87680124fa84e0855195a6184da9c187f133c"}, + {file = "wcwidth-0.2.12.tar.gz", hash = "sha256:f01c104efdf57971bcb756f054dd58ddec5204dd15fa31d6503ea57947d97c02"}, +] + +[[package]] +name = "whitenoise" +version = "6.6.0" +description = "Radically simplified static file serving for WSGI applications" +optional = false +python-versions = ">=3.8" +files = [ + {file = "whitenoise-6.6.0-py3-none-any.whl", hash = "sha256:b1f9db9bf67dc183484d760b99f4080185633136a273a03f6436034a41064146"}, + {file = "whitenoise-6.6.0.tar.gz", hash = "sha256:8998f7370973447fac1e8ef6e8ded2c5209a7b1f67c1012866dbcd09681c3251"}, +] + +[package.extras] +brotli = ["Brotli"] + +[[package]] +name = "wrapt" +version = "1.16.0" +description = "Module for decorators, wrappers and monkey patching." +optional = false +python-versions = ">=3.6" +files = [ + {file = "wrapt-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4"}, + {file = "wrapt-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020"}, + {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb2dee3874a500de01c93d5c71415fcaef1d858370d405824783e7a8ef5db440"}, + {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a88e6010048489cda82b1326889ec075a8c856c2e6a256072b28eaee3ccf487"}, + {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf"}, + {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:73aa7d98215d39b8455f103de64391cb79dfcad601701a3aa0dddacf74911d72"}, + {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:807cc8543a477ab7422f1120a217054f958a66ef7314f76dd9e77d3f02cdccd0"}, + {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bf5703fdeb350e36885f2875d853ce13172ae281c56e509f4e6eca049bdfb136"}, + {file = "wrapt-1.16.0-cp310-cp310-win32.whl", hash = "sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d"}, + {file = "wrapt-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:decbfa2f618fa8ed81c95ee18a387ff973143c656ef800c9f24fb7e9c16054e2"}, + {file = "wrapt-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09"}, + {file = "wrapt-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d"}, + {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389"}, + {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060"}, + {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1"}, + {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3"}, + {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956"}, + {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d"}, + {file = "wrapt-1.16.0-cp311-cp311-win32.whl", hash = "sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362"}, + {file = "wrapt-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89"}, + {file = "wrapt-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b"}, + {file = "wrapt-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36"}, + {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73"}, + {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809"}, + {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b"}, + {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81"}, + {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9"}, + {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c"}, + {file = "wrapt-1.16.0-cp312-cp312-win32.whl", hash = "sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc"}, + {file = "wrapt-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8"}, + {file = "wrapt-1.16.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d462f28826f4657968ae51d2181a074dfe03c200d6131690b7d65d55b0f360f8"}, + {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a33a747400b94b6d6b8a165e4480264a64a78c8a4c734b62136062e9a248dd39"}, + {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3646eefa23daeba62643a58aac816945cadc0afaf21800a1421eeba5f6cfb9c"}, + {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ebf019be5c09d400cf7b024aa52b1f3aeebeff51550d007e92c3c1c4afc2a40"}, + {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc"}, + {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:1acd723ee2a8826f3d53910255643e33673e1d11db84ce5880675954183ec47e"}, + {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:bc57efac2da352a51cc4658878a68d2b1b67dbe9d33c36cb826ca449d80a8465"}, + {file = "wrapt-1.16.0-cp36-cp36m-win32.whl", hash = "sha256:da4813f751142436b075ed7aa012a8778aa43a99f7b36afe9b742d3ed8bdc95e"}, + {file = "wrapt-1.16.0-cp36-cp36m-win_amd64.whl", hash = "sha256:6f6eac2360f2d543cc875a0e5efd413b6cbd483cb3ad7ebf888884a6e0d2e966"}, + {file = "wrapt-1.16.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a0ea261ce52b5952bf669684a251a66df239ec6d441ccb59ec7afa882265d593"}, + {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bd2d7ff69a2cac767fbf7a2b206add2e9a210e57947dd7ce03e25d03d2de292"}, + {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9159485323798c8dc530a224bd3ffcf76659319ccc7bbd52e01e73bd0241a0c5"}, + {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a86373cf37cd7764f2201b76496aba58a52e76dedfaa698ef9e9688bfd9e41cf"}, + {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:73870c364c11f03ed072dda68ff7aea6d2a3a5c3fe250d917a429c7432e15228"}, + {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b935ae30c6e7400022b50f8d359c03ed233d45b725cfdd299462f41ee5ffba6f"}, + {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:db98ad84a55eb09b3c32a96c576476777e87c520a34e2519d3e59c44710c002c"}, + {file = "wrapt-1.16.0-cp37-cp37m-win32.whl", hash = "sha256:9153ed35fc5e4fa3b2fe97bddaa7cbec0ed22412b85bcdaf54aeba92ea37428c"}, + {file = "wrapt-1.16.0-cp37-cp37m-win_amd64.whl", hash = "sha256:66dfbaa7cfa3eb707bbfcd46dab2bc6207b005cbc9caa2199bcbc81d95071a00"}, + {file = "wrapt-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1dd50a2696ff89f57bd8847647a1c363b687d3d796dc30d4dd4a9d1689a706f0"}, + {file = "wrapt-1.16.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:44a2754372e32ab315734c6c73b24351d06e77ffff6ae27d2ecf14cf3d229202"}, + {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e9723528b9f787dc59168369e42ae1c3b0d3fadb2f1a71de14531d321ee05b0"}, + {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbed418ba5c3dce92619656802cc5355cb679e58d0d89b50f116e4a9d5a9603e"}, + {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:941988b89b4fd6b41c3f0bfb20e92bd23746579736b7343283297c4c8cbae68f"}, + {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6a42cd0cfa8ffc1915aef79cb4284f6383d8a3e9dcca70c445dcfdd639d51267"}, + {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1ca9b6085e4f866bd584fb135a041bfc32cab916e69f714a7d1d397f8c4891ca"}, + {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5e49454f19ef621089e204f862388d29e6e8d8b162efce05208913dde5b9ad6"}, + {file = "wrapt-1.16.0-cp38-cp38-win32.whl", hash = "sha256:c31f72b1b6624c9d863fc095da460802f43a7c6868c5dda140f51da24fd47d7b"}, + {file = "wrapt-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:490b0ee15c1a55be9c1bd8609b8cecd60e325f0575fc98f50058eae366e01f41"}, + {file = "wrapt-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9b201ae332c3637a42f02d1045e1d0cccfdc41f1f2f801dafbaa7e9b4797bfc2"}, + {file = "wrapt-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2076fad65c6736184e77d7d4729b63a6d1ae0b70da4868adeec40989858eb3fb"}, + {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5cd603b575ebceca7da5a3a251e69561bec509e0b46e4993e1cac402b7247b8"}, + {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b47cfad9e9bbbed2339081f4e346c93ecd7ab504299403320bf85f7f85c7d46c"}, + {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a"}, + {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5f15814a33e42b04e3de432e573aa557f9f0f56458745c2074952f564c50e664"}, + {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db2e408d983b0e61e238cf579c09ef7020560441906ca990fe8412153e3b291f"}, + {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:edfad1d29c73f9b863ebe7082ae9321374ccb10879eeabc84ba3b69f2579d537"}, + {file = "wrapt-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed867c42c268f876097248e05b6117a65bcd1e63b779e916fe2e33cd6fd0d3c3"}, + {file = "wrapt-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:eb1b046be06b0fce7249f1d025cd359b4b80fc1c3e24ad9eca33e0dcdb2e4a35"}, + {file = "wrapt-1.16.0-py3-none-any.whl", hash = "sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1"}, + {file = "wrapt-1.16.0.tar.gz", hash = "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d"}, +] + +[metadata] +lock-version = "2.0" +python-versions = "~3.11" +content-hash = "bb83763d7bfabc3fda739af05e88a9c8600e401a2179281d9df265cdfa5a49f4" diff --git a/{{cookiecutter.project_slug}}/pyproject.toml b/{{cookiecutter.project_slug}}/pyproject.toml index d8af9f37..3ab5c1a8 100644 --- a/{{cookiecutter.project_slug}}/pyproject.toml +++ b/{{cookiecutter.project_slug}}/pyproject.toml @@ -1,9 +1,9 @@ [tool.poetry] authors = ["you "] description = "your project description" -name = "your-project-name" +name = "{{cookiecutter.project_slug}}" readme = "README.md" -version = "0.1.0" +version = "{{cookiecutter.project_version}}" [tool.poetry.dependencies] python = "~3.11" @@ -48,6 +48,7 @@ flake8-variables-names = "^0.0.6" flake8-walrus = "^1.2.0" freezegun = "^1.2.2" ipython = "^8.18.0" +isort = "^5.12.0" jedi = "^0.19.1" mixer = {extras = ["django"], version = "^7.2.2"} mypy = "^1.7.1" diff --git a/{{cookiecutter.project_slug}}/src/.django-app-template/admin.py-tpl b/{{cookiecutter.project_slug}}/src/.django-app-template/admin.py-tpl index cb14af7d..00b062ee 100644 --- a/{{cookiecutter.project_slug}}/src/.django-app-template/admin.py-tpl +++ b/{{cookiecutter.project_slug}}/src/.django-app-template/admin.py-tpl @@ -1,5 +1,3 @@ from django.contrib import admin -from core.admin import ModelAdmin - -# Register your models here. +from core.admin import ModelAdmin \ No newline at end of file diff --git a/{{cookiecutter.project_slug}}/src/.django-app-template/factory.py-tpl b/{{cookiecutter.project_slug}}/src/.django-app-template/factory.py-tpl deleted file mode 100644 index 7ece787a..00000000 --- a/{{cookiecutter.project_slug}}/src/.django-app-template/factory.py-tpl +++ /dev/null @@ -1,4 +0,0 @@ -from core.testing import register - -# Register your factory methods here. -# Add this file to root conftest pytest_plugins. diff --git a/{{cookiecutter.project_slug}}/src/.django-app-template/fixtures.py-tpl b/{{cookiecutter.project_slug}}/src/.django-app-template/fixtures.py-tpl deleted file mode 100644 index a2fe13af..00000000 --- a/{{cookiecutter.project_slug}}/src/.django-app-template/fixtures.py-tpl +++ /dev/null @@ -1,4 +0,0 @@ -import pytest - -# Register your project-wide fixtures here. -# Add this file to root conftest pytest_plugins. diff --git a/{{cookiecutter.project_slug}}/src/.django-app-template/tests/conftest.py-tpl b/{{cookiecutter.project_slug}}/src/.django-app-template/tests/conftest.py-tpl deleted file mode 100644 index 61258b76..00000000 --- a/{{cookiecutter.project_slug}}/src/.django-app-template/tests/conftest.py-tpl +++ /dev/null @@ -1,3 +0,0 @@ -import pytest - -# Register your app-wide fixtures here. diff --git a/{{cookiecutter.project_slug}}/src/apps/users/migrations/0001_initial.py b/{{cookiecutter.project_slug}}/src/apps/users/migrations/0001_initial.py index 6d6f56db..19cb5247 100644 --- a/{{cookiecutter.project_slug}}/src/apps/users/migrations/0001_initial.py +++ b/{{cookiecutter.project_slug}}/src/apps/users/migrations/0001_initial.py @@ -8,38 +8,125 @@ class Migration(migrations.Migration): - initial = True dependencies = [ - ('auth', '0012_alter_user_first_name_max_length'), + ("auth", "0012_alter_user_first_name_max_length"), ] operations = [ migrations.CreateModel( - name='User', + name="User", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('password', models.CharField(max_length=128, verbose_name='password')), - ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), - ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), - ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')), - ('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')), - ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')), - ('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')), - ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), - ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), - ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), - ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')), - ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("password", models.CharField(max_length=128, verbose_name="password")), + ( + "last_login", + models.DateTimeField( + blank=True, null=True, verbose_name="last login" + ), + ), + ( + "is_superuser", + models.BooleanField( + default=False, + help_text="Designates that this user has all permissions without explicitly assigning them.", + verbose_name="superuser status", + ), + ), + ( + "username", + models.CharField( + error_messages={ + "unique": "A user with that username already exists." + }, + help_text="Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.", + max_length=150, + unique=True, + validators=[ + django.contrib.auth.validators.UnicodeUsernameValidator() + ], + verbose_name="username", + ), + ), + ( + "first_name", + models.CharField( + blank=True, max_length=150, verbose_name="first name" + ), + ), + ( + "last_name", + models.CharField( + blank=True, max_length=150, verbose_name="last name" + ), + ), + ( + "email", + models.EmailField( + blank=True, max_length=254, verbose_name="email address" + ), + ), + ( + "is_staff", + models.BooleanField( + default=False, + help_text="Designates whether the user can log into this admin site.", + verbose_name="staff status", + ), + ), + ( + "is_active", + models.BooleanField( + default=True, + help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.", + verbose_name="active", + ), + ), + ( + "date_joined", + models.DateTimeField( + default=django.utils.timezone.now, verbose_name="date joined" + ), + ), + ( + "groups", + models.ManyToManyField( + blank=True, + help_text="The groups this user belongs to. A user will get all permissions granted to each of their groups.", + related_name="user_set", + related_query_name="user", + to="auth.Group", + verbose_name="groups", + ), + ), + ( + "user_permissions", + models.ManyToManyField( + blank=True, + help_text="Specific permissions for this user.", + related_name="user_set", + related_query_name="user", + to="auth.Permission", + verbose_name="user permissions", + ), + ), ], options={ - 'verbose_name': 'user', - 'verbose_name_plural': 'users', - 'abstract': False, + "verbose_name": "user", + "verbose_name_plural": "users", + "abstract": False, }, managers=[ - ('objects', django.contrib.auth.models.UserManager()), + ("objects", django.contrib.auth.models.UserManager()), ], ), ] diff --git a/{{cookiecutter.project_slug}}/src/apps/users/models.py b/{{cookiecutter.project_slug}}/src/apps/users/models.py index 5c821928..d1c036c5 100644 --- a/{{cookiecutter.project_slug}}/src/apps/users/models.py +++ b/{{cookiecutter.project_slug}}/src/apps/users/models.py @@ -1,6 +1,7 @@ +from typing import ClassVar + from django.contrib.auth.models import AbstractUser from django.contrib.auth.models import UserManager as _UserManager -from typing import ClassVar class User(AbstractUser): # noqa diff --git a/{{cookiecutter.project_slug}}/src/core/.env.ci b/{{cookiecutter.project_slug}}/src/core/.env.ci index 48e70354..c5be2fe6 100644 --- a/{{cookiecutter.project_slug}}/src/core/.env.ci +++ b/{{cookiecutter.project_slug}}/src/core/.env.ci @@ -1,3 +1,3 @@ DEBUG=Off -SECRET_KEY={{ random_ascii_string(48, punctuation=True) }} +SECRET_KEY=l!@xGb!Jkd]pQsvtU,@y`=%/c}mY;]oYwnsVeU}".VwwClOX DATABASE_URL=sqlite:///db.sqlite diff --git a/{{cookiecutter.project_slug}}/src/core/api/renderers.py b/{{cookiecutter.project_slug}}/src/core/api/renderers.py index 89fded20..03060e42 100644 --- a/{{cookiecutter.project_slug}}/src/core/api/renderers.py +++ b/{{cookiecutter.project_slug}}/src/core/api/renderers.py @@ -3,4 +3,6 @@ class AppJSONRenderer(CamelCaseJSONRenderer): charset = "utf-8" # force DRF to add charset header to the content-type - json_underscoreize = {"no_underscore_before_number": True} # https://github.com/vbabiy/djangorestframework-camel-case#underscoreize-options + json_underscoreize = { + "no_underscore_before_number": True + } # https://github.com/vbabiy/djangorestframework-camel-case#underscoreize-options diff --git a/{{cookiecutter.project_slug}}/src/core/api/viewsets.py b/{{cookiecutter.project_slug}}/src/core/api/viewsets.py index f64616d1..dfae0417 100644 --- a/{{cookiecutter.project_slug}}/src/core/api/viewsets.py +++ b/{{cookiecutter.project_slug}}/src/core/api/viewsets.py @@ -38,10 +38,14 @@ def get_object(self, *args: Any, **kwargs: Any) -> Any: class DefaultCreateModelMixin(CreateModelMixin): """Return detail-serialized created instance""" - def create(self: BaseGenericViewSet, request: Request, *args: Any, **kwargs: Any) -> Response: + def create( + self: BaseGenericViewSet, request: Request, *args: Any, **kwargs: Any + ) -> Response: serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) - instance = self.perform_create(serializer) # No getting created instance in original DRF + instance = self.perform_create( + serializer + ) # No getting created instance in original DRF headers = self.get_success_headers(serializer.data) return self.get_response(instance, status.HTTP_201_CREATED, headers) @@ -52,12 +56,16 @@ def perform_create(self: BaseGenericViewSet, serializer: Any) -> Any: class DefaultUpdateModelMixin(UpdateModelMixin): """Return detail-serialized updated instance""" - def update(self: BaseGenericViewSet, request: Request, *args: Any, **kwargs: Any) -> Response: + def update( + self: BaseGenericViewSet, request: Request, *args: Any, **kwargs: Any + ) -> Response: partial = kwargs.pop("partial", False) instance = self.get_object() serializer = self.get_serializer(instance, data=request.data, partial=partial) serializer.is_valid(raise_exception=True) - instance = self.perform_update(serializer) # No getting updated instance in original DRF + instance = self.perform_update( + serializer + ) # No getting updated instance in original DRF if getattr(instance, "_prefetched_objects_cache", None): # If 'prefetch_related' has been applied to a queryset, we need to diff --git a/{{cookiecutter.project_slug}}/src/core/conf/api.py b/{{cookiecutter.project_slug}}/src/core/conf/api.py index 1d76eee0..3fcd7071 100644 --- a/{{cookiecutter.project_slug}}/src/core/conf/api.py +++ b/{{cookiecutter.project_slug}}/src/core/conf/api.py @@ -8,7 +8,9 @@ REST_FRAMEWORK = { "DEFAULT_FILTER_BACKENDS": ("django_filters.rest_framework.DjangoFilterBackend",), - "DEFAULT_PERMISSION_CLASSES": ("rest_framework.permissions.IsAuthenticatedOrReadOnly",), + "DEFAULT_PERMISSION_CLASSES": ( + "rest_framework.permissions.IsAuthenticatedOrReadOnly", + ), "DEFAULT_AUTHENTICATION_CLASSES": [ "rest_framework.authentication.TokenAuthentication", "rest_framework_jwt.authentication.JSONWebTokenAuthentication", @@ -32,8 +34,12 @@ # Adding session auth and browsable API at the developer machine if env("DEBUG", cast=bool, default=False): - REST_FRAMEWORK["DEFAULT_AUTHENTICATION_CLASSES"].append("rest_framework.authentication.SessionAuthentication") - REST_FRAMEWORK["DEFAULT_RENDERER_CLASSES"].append("djangorestframework_camel_case.render.CamelCaseBrowsableAPIRenderer") + REST_FRAMEWORK["DEFAULT_AUTHENTICATION_CLASSES"].append( + "rest_framework.authentication.SessionAuthentication" + ) + REST_FRAMEWORK["DEFAULT_RENDERER_CLASSES"].append( + "djangorestframework_camel_case.render.CamelCaseBrowsableAPIRenderer" + ) # Set up drf_spectacular, https://drf-spectacular.readthedocs.io/en/latest/settings.html diff --git a/{{cookiecutter.project_slug}}/src/core/conf/i18n.py b/{{cookiecutter.project_slug}}/src/core/conf/i18n.py index 45a29d36..6b3dc9d7 100644 --- a/{{cookiecutter.project_slug}}/src/core/conf/i18n.py +++ b/{{cookiecutter.project_slug}}/src/core/conf/i18n.py @@ -1,7 +1,9 @@ -# Internationalization -# https://docs.djangoproject.com/en/3.0/topics/i18n/ +from pathlib import Path -LANGUAGE_CODE = "en-us" -LOCALE_PATHS = ["locale"] -USE_L10N = True -USE_I18N = True +from core.conf.boilerplate import BASE_DIR + +LANGUAGE_CODE = "ru" + +LOCALE_PATHS = [Path(BASE_DIR).parent / "locale"] + +USE_i18N = True diff --git a/{{cookiecutter.project_slug}}/src/core/conf/storage.py b/{{cookiecutter.project_slug}}/src/core/conf/storage.py index 039afa4b..f90634ca 100644 --- a/{{cookiecutter.project_slug}}/src/core/conf/storage.py +++ b/{{cookiecutter.project_slug}}/src/core/conf/storage.py @@ -1,6 +1,17 @@ from core.conf.environ import env -DEFAULT_FILE_STORAGE = env("DEFAULT_FILE_STORAGE", cast=str, default="django.core.files.storage.FileSystemStorage") +STORAGES = { + "default": { + "BACKEND": env( + "DEFAULT_FILE_STORAGE", + cast=str, + default="django.core.files.storage.FileSystemStorage", + ), + }, + "staticfiles": { + "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage", + }, +} AWS_ACCESS_KEY_ID = env("AWS_ACCESS_KEY_ID", default="") AWS_SECRET_ACCESS_KEY = env("AWS_SECRET_ACCESS_KEY", default="") diff --git a/{{cookiecutter.project_slug}}/src/core/locale/.gitkeep b/{{cookiecutter.project_slug}}/src/core/locale/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/{{cookiecutter.project_slug}}/src/core/management/commands/makemigrations.py b/{{cookiecutter.project_slug}}/src/core/management/commands/makemigrations.py index 557b5176..5ed88e1f 100644 --- a/{{cookiecutter.project_slug}}/src/core/management/commands/makemigrations.py +++ b/{{cookiecutter.project_slug}}/src/core/management/commands/makemigrations.py @@ -10,7 +10,11 @@ class Command(BaseCommand): """Disable automatic names for django migrations, thanks https://adamj.eu/tech/2020/02/24/how-to-disallow-auto-named-django-migrations/""" def handle(self, *app_labels, **options): - if options["name"] is None and not any([options["dry_run"], options["check_changes"]]): - raise MakemigrationsError("Migration name is required. Run again with `-n/--name` argument and specify name explicitly.") + if options["name"] is None and not any( + [options["dry_run"], options["check_changes"]] + ): + raise MakemigrationsError( + "Migration name is required. Run again with `-n/--name` argument and specify name explicitly." + ) super().handle(*app_labels, **options) diff --git a/{{cookiecutter.project_slug}}/src/core/management/commands/startapp.py b/{{cookiecutter.project_slug}}/src/core/management/commands/startapp.py index 4f41f201..49c21bdd 100644 --- a/{{cookiecutter.project_slug}}/src/core/management/commands/startapp.py +++ b/{{cookiecutter.project_slug}}/src/core/management/commands/startapp.py @@ -1,4 +1,4 @@ -from os import path +from pathlib import Path from django.conf import settings from django.core.management.commands.startapp import Command as BaseCommand @@ -9,6 +9,17 @@ class Command(BaseCommand): def handle(self, **options): if "template" not in options or options["template"] is None: - options["template"] = path.join(settings.BASE_DIR, ".django-app-template") + options["template"] = str( + Path(settings.BASE_DIR).parent / ".django-app-template" + ) super().handle(**options) + + testsdir = ( + Path(settings.BASE_DIR).parent.parent / "tests" / "apps" / options["name"] + ) + testsdir.mkdir(parents=True, exist_ok=True) + + (testsdir / "__init__.py").touch() + (testsdir / "factory.py").touch() + (testsdir / "fixtures.py").touch() diff --git a/{{cookiecutter.project_slug}}/src/core/models.py b/{{cookiecutter.project_slug}}/src/core/models.py index cec342ce..46c75985 100644 --- a/{{cookiecutter.project_slug}}/src/core/models.py +++ b/{{cookiecutter.project_slug}}/src/core/models.py @@ -30,7 +30,7 @@ def get_contenttype(cls) -> ContentType: def update_from_kwargs(self, **kwargs: dict[str, Any]) -> None: """A shortcut method to update model instance from the kwargs.""" - for (key, value) in kwargs.items(): + for key, value in kwargs.items(): setattr(self, key, value) def setattr_and_save(self, key: str, value: Any) -> None: diff --git a/{{cookiecutter.project_slug}}/src/core/testing/factory.py b/{{cookiecutter.project_slug}}/src/core/testing/factory.py index 26b7f3a1..73ae832e 100644 --- a/{{cookiecutter.project_slug}}/src/core/testing/factory.py +++ b/{{cookiecutter.project_slug}}/src/core/testing/factory.py @@ -26,7 +26,9 @@ def __init__(self, factory: "FixtureFactory", count: int) -> None: self.count = count def __getattr__(self, name: str) -> Callable: - return lambda *args, **kwargs: [getattr(self.factory, name)(*args, **kwargs) for _ in range(self.count)] + return lambda *args, **kwargs: [ + getattr(self.factory, name)(*args, **kwargs) for _ in range(self.count) + ] class FixtureFactory: diff --git a/{{cookiecutter.project_slug}}/tests/apps/a12n/jwt_views/test_obtain_jwt_view.py b/{{cookiecutter.project_slug}}/tests/apps/a12n/jwt_views/test_obtain_jwt_view.py index ec75c499..d0e11549 100644 --- a/{{cookiecutter.project_slug}}/tests/apps/a12n/jwt_views/test_obtain_jwt_view.py +++ b/{{cookiecutter.project_slug}}/tests/apps/a12n/jwt_views/test_obtain_jwt_view.py @@ -40,7 +40,9 @@ def test_getting_token_ok(as_user, get_token): def test_getting_token_is_token(as_user, get_token): result = get_token(as_user.user.username, as_user.password) - assert len(result["token"]) > 32 # every stuff that is long enough, may be a JWT token + assert ( + len(result["token"]) > 32 + ) # every stuff that is long enough, may be a JWT token def test_getting_token_with_incorrect_password(as_user, get_token): @@ -49,7 +51,9 @@ def test_getting_token_with_incorrect_password(as_user, get_token): assert "nonFieldErrors" in result -def test_getting_token_with_incorrect_password_creates_access_attempt_log_entry(as_user, get_token): +def test_getting_token_with_incorrect_password_creates_access_attempt_log_entry( + as_user, get_token +): get_token(as_user.user.username, "z3r0c00l", expected_status=400) # act assert AccessAttempt.objects.count() == 1 diff --git a/{{cookiecutter.project_slug}}/tests/apps/a12n/jwt_views/test_refresh_jwt_token.py b/{{cookiecutter.project_slug}}/tests/apps/a12n/jwt_views/test_refresh_jwt_token.py index 23556276..cd9270c9 100644 --- a/{{cookiecutter.project_slug}}/tests/apps/a12n/jwt_views/test_refresh_jwt_token.py +++ b/{{cookiecutter.project_slug}}/tests/apps/a12n/jwt_views/test_refresh_jwt_token.py @@ -57,7 +57,6 @@ def test_refresh_token_fails_with_incorrect_previous_token(refresh_token): def test_token_is_not_allowed_to_refresh_if_expired(initial_token, refresh_token): with freeze_time("2049-02-05"): - result = refresh_token(initial_token, expected_status=400) assert "expired" in result["nonFieldErrors"][0] diff --git a/{{cookiecutter.project_slug}}/tests/apps/users/factory.py b/{{cookiecutter.project_slug}}/tests/apps/users/factory.py index 0bf9b1a4..ecf95ec4 100644 --- a/{{cookiecutter.project_slug}}/tests/apps/users/factory.py +++ b/{{cookiecutter.project_slug}}/tests/apps/users/factory.py @@ -1,8 +1,8 @@ from django.contrib.auth.models import AnonymousUser +from apps.users.models import User from core.testing import register from core.testing.types import FactoryProtocol -from apps.users.models import User @register diff --git a/{{cookiecutter.project_slug}}/tests/core/factory.py b/{{cookiecutter.project_slug}}/tests/core/factory.py index 5dbc2361..0002e156 100644 --- a/{{cookiecutter.project_slug}}/tests/core/factory.py +++ b/{{cookiecutter.project_slug}}/tests/core/factory.py @@ -9,5 +9,9 @@ @register -def image(self: FactoryProtocol, name: str = "image.gif", content_type: str = "image/gif") -> SimpleUploadedFile: - return SimpleUploadedFile(name=name, content=faker.image(), content_type=content_type) +def image( + self: FactoryProtocol, name: str = "image.gif", content_type: str = "image/gif" +) -> SimpleUploadedFile: + return SimpleUploadedFile( + name=name, content=faker.image(), content_type=content_type + ) diff --git a/{{cookiecutter.project_slug}}/tests/core/fixtures.py b/{{cookiecutter.project_slug}}/tests/core/fixtures.py index be464894..b52db1bd 100644 --- a/{{cookiecutter.project_slug}}/tests/core/fixtures.py +++ b/{{cookiecutter.project_slug}}/tests/core/fixtures.py @@ -1,5 +1,4 @@ import pytest - from typing import TYPE_CHECKING from core.testing import ApiClient diff --git a/{{cookiecutter.project_slug}}/tests/core/testing/factory/test_factory.py b/{{cookiecutter.project_slug}}/tests/core/testing/factory/test_factory.py index a91f13f0..68e937a5 100644 --- a/{{cookiecutter.project_slug}}/tests/core/testing/factory/test_factory.py +++ b/{{cookiecutter.project_slug}}/tests/core/testing/factory/test_factory.py @@ -11,25 +11,33 @@ def fixture_factory() -> FixtureFactory: @pytest.fixture def registered_method(mocker): - mock = mocker.Mock(name="registered_method", return_value="i should be returned after gettatr") + mock = mocker.Mock( + name="registered_method", return_value="i should be returned after gettatr" + ) mock.__name__ = "registered_method" register(mock) return mock -def test_call_getattr_returns_what_method_returned(fixture_factory: FixtureFactory, registered_method): +def test_call_getattr_returns_what_method_returned( + fixture_factory: FixtureFactory, registered_method +): result = fixture_factory.registered_method() assert result == "i should be returned after gettatr" -def test_registered_method_called_with_factory_instance(fixture_factory: FixtureFactory, registered_method): +def test_registered_method_called_with_factory_instance( + fixture_factory: FixtureFactory, registered_method +): fixture_factory.registered_method(foo=1) # act registered_method.assert_called_with(fixture_factory, foo=1) -def test_cycle_returns_given_method_n_times(fixture_factory: FixtureFactory, registered_method, mocker): +def test_cycle_returns_given_method_n_times( + fixture_factory: FixtureFactory, registered_method, mocker +): fixture_factory.cycle(4).registered_method(bar=1) # act registered_method.assert_has_calls( diff --git a/{{cookiecutter.project_slug}}/tests/core/testing/factory/test_registry.py b/{{cookiecutter.project_slug}}/tests/core/testing/factory/test_registry.py index ba1491ba..c5233905 100644 --- a/{{cookiecutter.project_slug}}/tests/core/testing/factory/test_registry.py +++ b/{{cookiecutter.project_slug}}/tests/core/testing/factory/test_registry.py @@ -10,11 +10,15 @@ def fixture_registry() -> FixtureRegistry: def test_registry_raises_exception_if_no_method(fixture_registry: FixtureRegistry): - with pytest.raises(AttributeError, match=r"Factory method \“not_real\” not found\."): + with pytest.raises( + AttributeError, match=r"Factory method \“not_real\” not found\." + ): fixture_registry.get("not_real") -def test_registry_returns_correct_method_after_register_decorator(fixture_registry: FixtureRegistry): +def test_registry_returns_correct_method_after_register_decorator( + fixture_registry: FixtureRegistry, +): @register def some_method_to_add(): pass From ad7537cd8d2c2b945084814f360499533dc9185d Mon Sep 17 00:00:00 2001 From: hnthh Date: Tue, 28 Nov 2023 14:17:05 +0300 Subject: [PATCH 003/116] remove staged `~`-files --- .gitignore | 1 + {{cookiecutter.project_slug}}/.gitignore | 2 + {{cookiecutter.project_slug}}/mypy.ini~ | 51 ------------ .../src/apps/a12n/api/throttling.py~ | 9 --- .../src/apps/a12n/api/urls.py~ | 9 --- .../src/apps/a12n/api/views.py~ | 11 --- .../src/apps/a12n/utils.py~ | 13 --- .../src/apps/users/admin.py~ | 6 -- .../src/apps/users/api/serializers.py~ | 21 ----- .../src/apps/users/api/urls.py~ | 8 -- .../src/apps/users/api/viewsets.py~ | 26 ------ .../src/core/admin/README.md~ | 15 ---- .../src/core/admin/__init__.py~ | 8 -- .../src/core/asgi.py~ | 16 ---- .../src/core/settings.py~ | 32 -------- .../src/core/testing/__init__.py~ | 9 --- .../src/core/testing/api.py~ | 79 ------------------- .../src/core/testing/factory.py~ | 46 ----------- .../src/core/urls/__init__.py~ | 12 --- .../src/core/urls/v1.py~ | 15 ---- .../src/core/wsgi.py~ | 16 ---- .../a12n/jwt_views/test_refresh_jwt_token.py~ | 72 ----------------- .../tests/apps/users/conftest.py~ | 12 --- .../tests/apps/users/factory.py~ | 15 ---- .../apps/users/test_password_hashing.py~ | 15 ---- .../tests/conftest.py~ | 9 --- .../tests/core/conftest.py~ | 8 -- .../tests/core/factory.py~ | 13 --- .../tests/core/fixtures.py~ | 23 ------ .../core/test_remote_addr_midlleware.py~ | 30 ------- .../core/testing/factory/test_factory.py~ | 42 ---------- .../core/testing/factory/test_registry.py~ | 24 ------ 32 files changed, 3 insertions(+), 665 deletions(-) delete mode 100644 {{cookiecutter.project_slug}}/mypy.ini~ delete mode 100644 {{cookiecutter.project_slug}}/src/apps/a12n/api/throttling.py~ delete mode 100644 {{cookiecutter.project_slug}}/src/apps/a12n/api/urls.py~ delete mode 100644 {{cookiecutter.project_slug}}/src/apps/a12n/api/views.py~ delete mode 100644 {{cookiecutter.project_slug}}/src/apps/a12n/utils.py~ delete mode 100644 {{cookiecutter.project_slug}}/src/apps/users/admin.py~ delete mode 100644 {{cookiecutter.project_slug}}/src/apps/users/api/serializers.py~ delete mode 100644 {{cookiecutter.project_slug}}/src/apps/users/api/urls.py~ delete mode 100644 {{cookiecutter.project_slug}}/src/apps/users/api/viewsets.py~ delete mode 100644 {{cookiecutter.project_slug}}/src/core/admin/README.md~ delete mode 100644 {{cookiecutter.project_slug}}/src/core/admin/__init__.py~ delete mode 100644 {{cookiecutter.project_slug}}/src/core/asgi.py~ delete mode 100644 {{cookiecutter.project_slug}}/src/core/settings.py~ delete mode 100644 {{cookiecutter.project_slug}}/src/core/testing/__init__.py~ delete mode 100644 {{cookiecutter.project_slug}}/src/core/testing/api.py~ delete mode 100644 {{cookiecutter.project_slug}}/src/core/testing/factory.py~ delete mode 100644 {{cookiecutter.project_slug}}/src/core/urls/__init__.py~ delete mode 100644 {{cookiecutter.project_slug}}/src/core/urls/v1.py~ delete mode 100644 {{cookiecutter.project_slug}}/src/core/wsgi.py~ delete mode 100644 {{cookiecutter.project_slug}}/tests/apps/a12n/jwt_views/test_refresh_jwt_token.py~ delete mode 100644 {{cookiecutter.project_slug}}/tests/apps/users/conftest.py~ delete mode 100644 {{cookiecutter.project_slug}}/tests/apps/users/factory.py~ delete mode 100644 {{cookiecutter.project_slug}}/tests/apps/users/test_password_hashing.py~ delete mode 100644 {{cookiecutter.project_slug}}/tests/conftest.py~ delete mode 100644 {{cookiecutter.project_slug}}/tests/core/conftest.py~ delete mode 100644 {{cookiecutter.project_slug}}/tests/core/factory.py~ delete mode 100644 {{cookiecutter.project_slug}}/tests/core/fixtures.py~ delete mode 100644 {{cookiecutter.project_slug}}/tests/core/test_remote_addr_midlleware.py~ delete mode 100644 {{cookiecutter.project_slug}}/tests/core/testing/factory/test_factory.py~ delete mode 100644 {{cookiecutter.project_slug}}/tests/core/testing/factory/test_registry.py~ diff --git a/.gitignore b/.gitignore index 8c17939d..fdc7b380 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.git .idea .vscode diff --git a/{{cookiecutter.project_slug}}/.gitignore b/{{cookiecutter.project_slug}}/.gitignore index 21fba42a..1c54582e 100644 --- a/{{cookiecutter.project_slug}}/.gitignore +++ b/{{cookiecutter.project_slug}}/.gitignore @@ -6,6 +6,7 @@ __pycache__/ *.py[cod] *$py.class +**/.DS_Store # C extensions *.so @@ -106,6 +107,7 @@ dmypy.json # End of https://www.gitignore.io/api/python # IDE stuff +**.*~ .vscode .idea diff --git a/{{cookiecutter.project_slug}}/mypy.ini~ b/{{cookiecutter.project_slug}}/mypy.ini~ deleted file mode 100644 index 53c339e6..00000000 --- a/{{cookiecutter.project_slug}}/mypy.ini~ +++ /dev/null @@ -1,51 +0,0 @@ -[mypy] -python_version = 3.11 -mypy_path = src -namespace_packages = on -explicit_package_bases = on -warn_no_return = off -warn_unused_configs = on -warn_unused_ignores = on -warn_redundant_casts = on -no_implicit_optional = on -no_implicit_reexport = on -strict_equality = on -warn_unreachable = on -disallow_untyped_calls = on -disallow_untyped_defs = on -exclude = migrations/ - -plugins = - mypy_drf_plugin.main, - mypy_django_plugin.main - -[mypy.plugins.django-stubs] -django_settings_module = "core.settings" - -[mypy-rest_framework_jwt.*] -ignore_missing_imports = on - -[mypy-core.testing.api.*] -disallow_untyped_defs = off - -[mypy-*.tests.*] -disallow_untyped_defs = off - -[mypy-*.management.*] -disallow_untyped_defs = off - -[mypy-djangorestframework_camel_case.*] -ignore_missing_imports = on - -[mypy-django_filters.*] -ignore_missing_imports = on - -[mypy-axes.*] -ignore_missing_imports = on - -[mypy-mixer.*] -ignore_missing_imports = on - -[mypy-ipware.*] -ignore_missing_imports = on - diff --git a/{{cookiecutter.project_slug}}/src/apps/a12n/api/throttling.py~ b/{{cookiecutter.project_slug}}/src/apps/a12n/api/throttling.py~ deleted file mode 100644 index e2a690aa..00000000 --- a/{{cookiecutter.project_slug}}/src/apps/a12n/api/throttling.py~ +++ /dev/null @@ -1,9 +0,0 @@ -from rest_framework.throttling import AnonRateThrottle - -from app.api.throttling import ConfigurableThrottlingMixin - - -class AuthAnonRateThrottle(ConfigurableThrottlingMixin, AnonRateThrottle): - """Throttle for any authorization views.""" - - scope = "anon-auth" diff --git a/{{cookiecutter.project_slug}}/src/apps/a12n/api/urls.py~ b/{{cookiecutter.project_slug}}/src/apps/a12n/api/urls.py~ deleted file mode 100644 index 955c2c52..00000000 --- a/{{cookiecutter.project_slug}}/src/apps/a12n/api/urls.py~ +++ /dev/null @@ -1,9 +0,0 @@ -from django.urls import path - -from a12n.api import views - -app_name = "a12n" -urlpatterns = [ - path("token/", views.ObtainJSONWebTokenView.as_view()), - path("token/refresh/", views.RefreshJSONWebTokenView.as_view()), -] diff --git a/{{cookiecutter.project_slug}}/src/apps/a12n/api/views.py~ b/{{cookiecutter.project_slug}}/src/apps/a12n/api/views.py~ deleted file mode 100644 index 6bf404b3..00000000 --- a/{{cookiecutter.project_slug}}/src/apps/a12n/api/views.py~ +++ /dev/null @@ -1,11 +0,0 @@ -from rest_framework_jwt import views as jwt - -from a12n.api.throttling import AuthAnonRateThrottle - - -class ObtainJSONWebTokenView(jwt.ObtainJSONWebTokenView): - throttle_classes = [AuthAnonRateThrottle] - - -class RefreshJSONWebTokenView(jwt.RefreshJSONWebTokenView): - throttle_classes = [AuthAnonRateThrottle] diff --git a/{{cookiecutter.project_slug}}/src/apps/a12n/utils.py~ b/{{cookiecutter.project_slug}}/src/apps/a12n/utils.py~ deleted file mode 100644 index 33e68e3a..00000000 --- a/{{cookiecutter.project_slug}}/src/apps/a12n/utils.py~ +++ /dev/null @@ -1,13 +0,0 @@ -from rest_framework_jwt.settings import api_settings - -from users.models import User - - -def get_jwt(user: User) -> str: - """Make JWT for given user""" - jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER - jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER - - payload = jwt_payload_handler(user) - - return jwt_encode_handler(payload) diff --git a/{{cookiecutter.project_slug}}/src/apps/users/admin.py~ b/{{cookiecutter.project_slug}}/src/apps/users/admin.py~ deleted file mode 100644 index 20908271..00000000 --- a/{{cookiecutter.project_slug}}/src/apps/users/admin.py~ +++ /dev/null @@ -1,6 +0,0 @@ -from django.contrib import admin -from django.contrib.auth.admin import UserAdmin - -from users.models import User - -admin.site.register(User, UserAdmin) diff --git a/{{cookiecutter.project_slug}}/src/apps/users/api/serializers.py~ b/{{cookiecutter.project_slug}}/src/apps/users/api/serializers.py~ deleted file mode 100644 index d4786b21..00000000 --- a/{{cookiecutter.project_slug}}/src/apps/users/api/serializers.py~ +++ /dev/null @@ -1,21 +0,0 @@ -from rest_framework import serializers - -from users.models import User - - -class UserSerializer(serializers.ModelSerializer): - remote_addr = serializers.SerializerMethodField() - - class Meta: - model = User - fields = [ - "id", - "username", - "first_name", - "last_name", - "email", - "remote_addr", - ] - - def get_remote_addr(self, obj: User) -> str: - return self.context["request"].META["REMOTE_ADDR"] diff --git a/{{cookiecutter.project_slug}}/src/apps/users/api/urls.py~ b/{{cookiecutter.project_slug}}/src/apps/users/api/urls.py~ deleted file mode 100644 index 47272b83..00000000 --- a/{{cookiecutter.project_slug}}/src/apps/users/api/urls.py~ +++ /dev/null @@ -1,8 +0,0 @@ -from django.urls import path - -from apps.users.api import viewsets - -app_name = "users" -urlpatterns = [ - path("me/", viewsets.SelfView.as_view()), -] diff --git a/{{cookiecutter.project_slug}}/src/apps/users/api/viewsets.py~ b/{{cookiecutter.project_slug}}/src/apps/users/api/viewsets.py~ deleted file mode 100644 index d3268e50..00000000 --- a/{{cookiecutter.project_slug}}/src/apps/users/api/viewsets.py~ +++ /dev/null @@ -1,26 +0,0 @@ -from rest_framework.generics import GenericAPIView -from rest_framework.permissions import IsAuthenticated -from rest_framework.request import Request -from rest_framework.response import Response - -from django.db.models import QuerySet - -from users.api.serializers import UserSerializer -from users.models import User - - -class SelfView(GenericAPIView): - serializer_class = UserSerializer - permission_classes = [IsAuthenticated] - - def get(self, request: Request) -> Response: - user = self.get_object() - serializer = self.get_serializer(user) - - return Response(serializer.data) - - def get_object(self) -> User: - return self.get_queryset().get(pk=self.request.user.pk) - - def get_queryset(self) -> QuerySet[User]: - return User.objects.filter(is_active=True) diff --git a/{{cookiecutter.project_slug}}/src/core/admin/README.md~ b/{{cookiecutter.project_slug}}/src/core/admin/README.md~ deleted file mode 100644 index ed2902db..00000000 --- a/{{cookiecutter.project_slug}}/src/core/admin/README.md~ +++ /dev/null @@ -1,15 +0,0 @@ -## App-wide admin customizations - -This is a place for app-wide django-admin customizations. To make your admin interface customizable, scaffold your admin modules like this: - -```python -from app.admin import ModelAdmin, admin -from books.models import Book - - -@admin.register(Book) -class BookAdmin(ModelAdmin): - fields = [ - "name", - ] -``` \ No newline at end of file diff --git a/{{cookiecutter.project_slug}}/src/core/admin/__init__.py~ b/{{cookiecutter.project_slug}}/src/core/admin/__init__.py~ deleted file mode 100644 index cb848394..00000000 --- a/{{cookiecutter.project_slug}}/src/core/admin/__init__.py~ +++ /dev/null @@ -1,8 +0,0 @@ -from django.contrib import admin - -from app.admin.model_admin import ModelAdmin - -__all__ = [ - "admin", - "ModelAdmin", -] diff --git a/{{cookiecutter.project_slug}}/src/core/asgi.py~ b/{{cookiecutter.project_slug}}/src/core/asgi.py~ deleted file mode 100644 index 8b0b6000..00000000 --- a/{{cookiecutter.project_slug}}/src/core/asgi.py~ +++ /dev/null @@ -1,16 +0,0 @@ -""" -ASGI config for app project. - -It exposes the ASGI callable as a module-level variable named ``application``. - -For more information on this file, see -https://docs.djangoproject.com/en/3.0/howto/deployment/asgi/ -""" - -import os - -from django.core.asgi import get_asgi_application - -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "app.settings") - -application = get_asgi_application() diff --git a/{{cookiecutter.project_slug}}/src/core/settings.py~ b/{{cookiecutter.project_slug}}/src/core/settings.py~ deleted file mode 100644 index f235565d..00000000 --- a/{{cookiecutter.project_slug}}/src/core/settings.py~ +++ /dev/null @@ -1,32 +0,0 @@ -# This file was generated using http://github.com/f213/django starter template. -# -# Settings are split into multiple files using http://github.com/sobolevn/django-split-settings - -from split_settings.tools import include - -from app.conf.environ import env - -# SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = env("SECRET_KEY") - -# SECURITY WARNING: don't run with debug turned on in production! -DEBUG = env("DEBUG", cast=bool, default=False) -CI = env("CI", cast=bool, default=False) - -include( - "conf/api.py", - "conf/auth.py", - "conf/boilerplate.py", - "conf/db.py", - "conf/healthchecks.py", - "conf/http.py", - "conf/i18n.py", - "conf/installed_apps.py", - "conf/media.py", - "conf/middleware.py", - "conf/storage.py", - "conf/sentry.py", - "conf/static.py", - "conf/templates.py", - "conf/timezone.py", -) diff --git a/{{cookiecutter.project_slug}}/src/core/testing/__init__.py~ b/{{cookiecutter.project_slug}}/src/core/testing/__init__.py~ deleted file mode 100644 index 89377995..00000000 --- a/{{cookiecutter.project_slug}}/src/core/testing/__init__.py~ +++ /dev/null @@ -1,9 +0,0 @@ -from app.testing.api import ApiClient -from app.testing.factory import FixtureFactory -from app.testing.factory import register - -__all__ = [ - "ApiClient", - "FixtureFactory", - "register", -] diff --git a/{{cookiecutter.project_slug}}/src/core/testing/api.py~ b/{{cookiecutter.project_slug}}/src/core/testing/api.py~ deleted file mode 100644 index f9d66ae2..00000000 --- a/{{cookiecutter.project_slug}}/src/core/testing/api.py~ +++ /dev/null @@ -1,79 +0,0 @@ -import json -import random -import string -from typing import Optional - -from rest_framework.authtoken.models import Token -from rest_framework.test import APIClient as DRFAPIClient - -from users.models import User - - -class ApiClient(DRFAPIClient): - def __init__(self, user: Optional[User] = None, *args, **kwargs) -> None: - super().__init__(*args, **kwargs) - - if user: - self.user = user - self.password = "".join([random.choice(string.hexdigits) for _ in range(6)]) - self.user.set_password(self.password) - self.user.save() - - token = Token.objects.create(user=self.user) - self.credentials( - HTTP_AUTHORIZATION=f"Token {token}", - HTTP_X_CLIENT="testing", - ) - - def get(self, *args, **kwargs): - expected_status = kwargs.get("expected_status", 200) - return self._request("get", expected_status, *args, **kwargs) - - def patch(self, *args, **kwargs): - expected_status = kwargs.get("expected_status", 200) - return self._request("patch", expected_status, *args, **kwargs) - - def post(self, *args, **kwargs): - expected_status = kwargs.get("expected_status", 201) - return self._request("post", expected_status, *args, **kwargs) - - def put(self, *args, **kwargs): - expected_status = kwargs.get("expected_status", 200) - return self._request("put", expected_status, *args, **kwargs) - - def delete(self, *args, **kwargs): - expected_status = kwargs.get("expected_status", 204) - return self._request("delete", expected_status, *args, **kwargs) - - def _request(self, method, expected, *args, **kwargs): - kwargs["format"] = kwargs.get("format", "json") - as_response = kwargs.pop("as_response", False) - method = getattr(super(), method) - - response = method(*args, **kwargs) - if as_response: - return response - - content = self._decode(response) - assert response.status_code == expected, content - return content - - def _decode(self, response): - content = response.content.decode("utf-8", errors="ignore") - - if self.is_json(response): - return json.loads(content) - else: - return content - - @staticmethod - def is_json(response) -> bool: - if response.has_header("content-type"): - return "json" in response.get("content-type") - - return False - - -__all__ = [ - "ApiClient", -] diff --git a/{{cookiecutter.project_slug}}/src/core/testing/factory.py~ b/{{cookiecutter.project_slug}}/src/core/testing/factory.py~ deleted file mode 100644 index bbe5ae26..00000000 --- a/{{cookiecutter.project_slug}}/src/core/testing/factory.py~ +++ /dev/null @@ -1,46 +0,0 @@ -from functools import partial -from typing import Callable - -from app.testing.mixer import mixer - - -def register(method: Callable) -> Callable: - name = method.__name__ - FixtureRegistry.METHODS[name] = method - return method - - -class FixtureRegistry: - METHODS: dict[str, Callable] = {} - - def get(self, name: str) -> Callable: - method = self.METHODS.get(name) - if not method: - raise AttributeError(f"Factory method “{name}” not found.") - return method - - -class CycleFixtureFactory: - def __init__(self, factory: "FixtureFactory", count: int) -> None: - self.factory = factory - self.count = count - - def __getattr__(self, name: str) -> Callable: - return lambda *args, **kwargs: [getattr(self.factory, name)(*args, **kwargs) for _ in range(self.count)] - - -class FixtureFactory: - def __init__(self) -> None: - self.mixer = mixer - self.registry = FixtureRegistry() - - def __getattr__(self, name: str) -> Callable: - method = self.registry.get(name) - return partial(method, self) - - def cycle(self, count: int) -> CycleFixtureFactory: - """ - Run given method X times: - factory.cycle(5).order() # gives 5 orders - """ - return CycleFixtureFactory(self, count) diff --git a/{{cookiecutter.project_slug}}/src/core/urls/__init__.py~ b/{{cookiecutter.project_slug}}/src/core/urls/__init__.py~ deleted file mode 100644 index 319d5e65..00000000 --- a/{{cookiecutter.project_slug}}/src/core/urls/__init__.py~ +++ /dev/null @@ -1,12 +0,0 @@ -from django.contrib import admin -from django.urls import include -from django.urls import path - -api = [ - path("v1/", include("app.urls.v1", namespace="v1")), -] - -urlpatterns = [ - path("admin/", admin.site.urls), - path("api/", include(api)), -] diff --git a/{{cookiecutter.project_slug}}/src/core/urls/v1.py~ b/{{cookiecutter.project_slug}}/src/core/urls/v1.py~ deleted file mode 100644 index d8f89f4d..00000000 --- a/{{cookiecutter.project_slug}}/src/core/urls/v1.py~ +++ /dev/null @@ -1,15 +0,0 @@ -from drf_spectacular.views import SpectacularAPIView -from drf_spectacular.views import SpectacularSwaggerView - -from django.urls import include -from django.urls import path - -app_name = "api_v1" - -urlpatterns = [ - path("auth/", include("a12n.api.urls")), - path("users/", include("users.api.urls")), - path("healthchecks/", include("django_healthchecks.urls")), - path("docs/schema/", SpectacularAPIView.as_view(), name="schema"), - path("docs/swagger/", SpectacularSwaggerView.as_view(url_name="schema")), -] diff --git a/{{cookiecutter.project_slug}}/src/core/wsgi.py~ b/{{cookiecutter.project_slug}}/src/core/wsgi.py~ deleted file mode 100644 index 1c508c03..00000000 --- a/{{cookiecutter.project_slug}}/src/core/wsgi.py~ +++ /dev/null @@ -1,16 +0,0 @@ -""" -WSGI config for app project. - -It exposes the WSGI callable as a module-level variable named ``application``. - -For more information on this file, see -https://docs.djangoproject.com/en/3.0/howto/deployment/wsgi/ -""" - -import os - -from django.core.wsgi import get_wsgi_application - -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "app.settings") - -application = get_wsgi_application() diff --git a/{{cookiecutter.project_slug}}/tests/apps/a12n/jwt_views/test_refresh_jwt_token.py~ b/{{cookiecutter.project_slug}}/tests/apps/a12n/jwt_views/test_refresh_jwt_token.py~ deleted file mode 100644 index f9d66cbe..00000000 --- a/{{cookiecutter.project_slug}}/tests/apps/a12n/jwt_views/test_refresh_jwt_token.py~ +++ /dev/null @@ -1,72 +0,0 @@ -import pytest - -from freezegun import freeze_time - -from a12n.utils import get_jwt - -pytestmark = [ - pytest.mark.django_db, - pytest.mark.freeze_time("2049-01-05"), -] - - -@pytest.fixture -def refresh_token(as_user): - def _refresh_token(token, expected_status=201): - return as_user.post( - "/api/v1/auth/token/refresh/", - { - "token": token, - }, - format="json", - expected_status=expected_status, - ) - - return _refresh_token - - -@pytest.fixture -def initial_token(as_user): - with freeze_time("2049-01-03"): - return get_jwt(as_user.user) - - -def test_refresh_token_ok(initial_token, refresh_token): - result = refresh_token(initial_token) - - assert "token" in result - - -def test_refreshed_token_is_a_token(initial_token, refresh_token): - result = refresh_token(initial_token) - - assert len(result["token"]) > 32 - - -def test_refreshed_token_is_new_one(initial_token, refresh_token): - result = refresh_token(initial_token) - - assert result["token"] != initial_token - - -def test_refresh_token_fails_with_incorrect_previous_token(refresh_token): - result = refresh_token("some-invalid-previous-token", expected_status=400) - - assert "nonFieldErrors" in result - - -def test_token_is_not_allowed_to_refresh_if_expired(initial_token, refresh_token): - with freeze_time("2049-02-05"): - - result = refresh_token(initial_token, expected_status=400) - - assert "expired" in result["nonFieldErrors"][0] - - -def test_received_token_works(as_anon, refresh_token, initial_token): - token = refresh_token(initial_token)["token"] - as_anon.credentials(HTTP_AUTHORIZATION=f"Bearer {token}") - - result = as_anon.get("/api/v1/users/me/") - - assert result is not None diff --git a/{{cookiecutter.project_slug}}/tests/apps/users/conftest.py~ b/{{cookiecutter.project_slug}}/tests/apps/users/conftest.py~ deleted file mode 100644 index 6fa5fd23..00000000 --- a/{{cookiecutter.project_slug}}/tests/apps/users/conftest.py~ +++ /dev/null @@ -1,12 +0,0 @@ -import pytest -from typing import TYPE_CHECKING - -from apps.users.models import User - -if TYPE_CHECKING: - from app.testing.factory import FixtureFactory - - -@pytest.fixture -def user(factory: "FixtureFactory") -> User: - return factory.user() diff --git a/{{cookiecutter.project_slug}}/tests/apps/users/factory.py~ b/{{cookiecutter.project_slug}}/tests/apps/users/factory.py~ deleted file mode 100644 index 57a1c786..00000000 --- a/{{cookiecutter.project_slug}}/tests/apps/users/factory.py~ +++ /dev/null @@ -1,15 +0,0 @@ -from django.contrib.auth.models import AnonymousUser - -from app.testing import register -from app.testing.types import FactoryProtocol -from users.models import User - - -@register -def user(self: FactoryProtocol, **kwargs: dict) -> User: - return self.mixer.blend("users.User", **kwargs) - - -@register -def anon(self: FactoryProtocol, **kwargs: dict) -> AnonymousUser: - return AnonymousUser() diff --git a/{{cookiecutter.project_slug}}/tests/apps/users/test_password_hashing.py~ b/{{cookiecutter.project_slug}}/tests/apps/users/test_password_hashing.py~ deleted file mode 100644 index 39418069..00000000 --- a/{{cookiecutter.project_slug}}/tests/apps/users/test_password_hashing.py~ +++ /dev/null @@ -1,15 +0,0 @@ -import pytest -import uuid - -from users.models import User - -pytestmark = [pytest.mark.django_db] - - -def test(): - user = User.objects.create(username=str(uuid.uuid4())) - user.set_password("l0ve") - - user.save() # act - - assert user.password.startswith("bcrypt") diff --git a/{{cookiecutter.project_slug}}/tests/conftest.py~ b/{{cookiecutter.project_slug}}/tests/conftest.py~ deleted file mode 100644 index e80dd146..00000000 --- a/{{cookiecutter.project_slug}}/tests/conftest.py~ +++ /dev/null @@ -1,9 +0,0 @@ -# fmt: off -pytest_plugins = [ - "tests.apps.users.conftest", - "tests.core.conftest", - - "tests.apps.users.factory", - "tests.core.factory", -] -# fmt: on diff --git a/{{cookiecutter.project_slug}}/tests/core/conftest.py~ b/{{cookiecutter.project_slug}}/tests/core/conftest.py~ deleted file mode 100644 index aa4c777e..00000000 --- a/{{cookiecutter.project_slug}}/tests/core/conftest.py~ +++ /dev/null @@ -1,8 +0,0 @@ -import pytest - -from app.testing.factory import FixtureFactory - - -@pytest.fixture -def factory() -> FixtureFactory: - return FixtureFactory() diff --git a/{{cookiecutter.project_slug}}/tests/core/factory.py~ b/{{cookiecutter.project_slug}}/tests/core/factory.py~ deleted file mode 100644 index 036810d3..00000000 --- a/{{cookiecutter.project_slug}}/tests/core/factory.py~ +++ /dev/null @@ -1,13 +0,0 @@ -from faker import Faker - -from django.core.files.uploadedfile import SimpleUploadedFile - -from app.testing import register -from app.testing.types import FactoryProtocol - -faker = Faker() - - -@register -def image(self: FactoryProtocol, name: str = "image.gif", content_type: str = "image/gif") -> SimpleUploadedFile: - return SimpleUploadedFile(name=name, content=faker.image(), content_type=content_type) diff --git a/{{cookiecutter.project_slug}}/tests/core/fixtures.py~ b/{{cookiecutter.project_slug}}/tests/core/fixtures.py~ deleted file mode 100644 index 06dd91aa..00000000 --- a/{{cookiecutter.project_slug}}/tests/core/fixtures.py~ +++ /dev/null @@ -1,23 +0,0 @@ -import pytest - -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - from apps.users.models import User - from core.testing import ApiClient - from core.testing.factory import FixtureFactory - - -@pytest.fixture -def as_anon() -> "ApiClient": - return ApiClient() - - -@pytest.fixture -def as_user(user: "User") -> "ApiClient": - return ApiClient(user=user) - - -@pytest.fixture -def factory() -> "FixtureFactory": - return FixtureFactory() diff --git a/{{cookiecutter.project_slug}}/tests/core/test_remote_addr_midlleware.py~ b/{{cookiecutter.project_slug}}/tests/core/test_remote_addr_midlleware.py~ deleted file mode 100644 index 43b4bfaf..00000000 --- a/{{cookiecutter.project_slug}}/tests/core/test_remote_addr_midlleware.py~ +++ /dev/null @@ -1,30 +0,0 @@ -import pytest - -from django.apps import apps - -from core.testing.api import ApiClient - -pytestmark = [pytest.mark.django_db] - - -@pytest.fixture(autouse=True) -def _require_users_app_installed(settings): - assert apps.is_installed( - "users" - ), """ - Stock f213/django users app should be installed to run this test. - - Make sure to test app.middleware.real_ip.real_ip_middleware on your own, if you drop - the stock users app. - """ - - -@pytest.fixture -def api(user): - return ApiClient(user=user, HTTP_X_FORWARDED_FOR="100.200.250.150, 10.0.0.1") - - -def test_remote_addr(api): - result = api.get("/api/v1/users/me/") - - assert result["remoteAddr"] == "100.200.250.150" diff --git a/{{cookiecutter.project_slug}}/tests/core/testing/factory/test_factory.py~ b/{{cookiecutter.project_slug}}/tests/core/testing/factory/test_factory.py~ deleted file mode 100644 index 858df883..00000000 --- a/{{cookiecutter.project_slug}}/tests/core/testing/factory/test_factory.py~ +++ /dev/null @@ -1,42 +0,0 @@ -import pytest - -from app.testing import FixtureFactory -from app.testing import register - - -@pytest.fixture -def fixture_factory() -> FixtureFactory: - return FixtureFactory() - - -@pytest.fixture -def registered_method(mocker): - mock = mocker.Mock(name="registered_method", return_value="i should be returned after gettatr") - mock.__name__ = "registered_method" - register(mock) - return mock - - -def test_call_getattr_returns_what_method_returned(fixture_factory: FixtureFactory, registered_method): - result = fixture_factory.registered_method() - - assert result == "i should be returned after gettatr" - - -def test_registered_method_called_with_factory_instance(fixture_factory: FixtureFactory, registered_method): - fixture_factory.registered_method(foo=1) # act - - registered_method.assert_called_with(fixture_factory, foo=1) - - -def test_cycle_returns_given_method_n_times(fixture_factory: FixtureFactory, registered_method, mocker): - fixture_factory.cycle(4).registered_method(bar=1) # act - - registered_method.assert_has_calls( - calls=[ - mocker.call(fixture_factory, bar=1), - mocker.call(fixture_factory, bar=1), - mocker.call(fixture_factory, bar=1), - mocker.call(fixture_factory, bar=1), - ], - ) diff --git a/{{cookiecutter.project_slug}}/tests/core/testing/factory/test_registry.py~ b/{{cookiecutter.project_slug}}/tests/core/testing/factory/test_registry.py~ deleted file mode 100644 index 0dcfc793..00000000 --- a/{{cookiecutter.project_slug}}/tests/core/testing/factory/test_registry.py~ +++ /dev/null @@ -1,24 +0,0 @@ -import pytest - -from app.testing.factory import FixtureRegistry -from app.testing.factory import register - - -@pytest.fixture -def fixture_registry() -> FixtureRegistry: - return FixtureRegistry() - - -def test_registry_raises_exception_if_no_method(fixture_registry: FixtureRegistry): - with pytest.raises(AttributeError, match=r"Factory method \“not_real\” not found\."): - fixture_registry.get("not_real") - - -def test_registry_returns_correct_method_after_register_decorator(fixture_registry: FixtureRegistry): - @register - def some_method_to_add(): - pass - - method = fixture_registry.get("some_method_to_add") # act - - assert some_method_to_add == method From 13ff22d6cecd0f04eead14e49dcde3f852e4dd43 Mon Sep 17 00:00:00 2001 From: hnthh Date: Wed, 29 Nov 2023 00:31:15 +0300 Subject: [PATCH 004/116] lots of * makefile `coverage` cmd doesn't work; * remove forgotten `~`-files. --- .gitignore | 1 + Makefile | 15 +- poetry.lock | 511 ++++++++++++++++++ pyproject.toml | 14 + {{cookiecutter.project_slug}}/Makefile | 9 +- .../src/.django-app-template/admin.py-tpl | 2 +- .../src/core/conf/api.py~ | 51 -- .../src/core/conf/auth.py~ | 34 -- .../src/core/conf/boilerplate.py~ | 10 - .../src/core/conf/db.py~ | 12 - .../src/core/conf/environ.py~ | 18 - .../src/core/conf/http.py~ | 11 - .../src/core/conf/installed_apps.py~ | 25 - .../src/core/conf/media.py~ | 4 - .../src/core/conf/middleware.py~ | 12 - .../src/core/conf/sentry.py~ | 15 - .../src/core/conf/static.py~ | 7 - .../src/core/conf/storage.py~ | 10 - 18 files changed, 541 insertions(+), 220 deletions(-) create mode 100644 poetry.lock create mode 100644 pyproject.toml delete mode 100644 {{cookiecutter.project_slug}}/src/core/conf/api.py~ delete mode 100644 {{cookiecutter.project_slug}}/src/core/conf/auth.py~ delete mode 100644 {{cookiecutter.project_slug}}/src/core/conf/boilerplate.py~ delete mode 100644 {{cookiecutter.project_slug}}/src/core/conf/db.py~ delete mode 100644 {{cookiecutter.project_slug}}/src/core/conf/environ.py~ delete mode 100644 {{cookiecutter.project_slug}}/src/core/conf/http.py~ delete mode 100644 {{cookiecutter.project_slug}}/src/core/conf/installed_apps.py~ delete mode 100644 {{cookiecutter.project_slug}}/src/core/conf/media.py~ delete mode 100644 {{cookiecutter.project_slug}}/src/core/conf/middleware.py~ delete mode 100644 {{cookiecutter.project_slug}}/src/core/conf/sentry.py~ delete mode 100644 {{cookiecutter.project_slug}}/src/core/conf/static.py~ delete mode 100644 {{cookiecutter.project_slug}}/src/core/conf/storage.py~ diff --git a/.gitignore b/.gitignore index fdc7b380..260a84b0 100644 --- a/.gitignore +++ b/.gitignore @@ -5,5 +5,6 @@ **/*~ **/.DS_Store +db.sqlite testproject venv diff --git a/Makefile b/Makefile index aa87b8f7..bed71bcd 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,15 @@ -VENV = cd testproject && poetry run python src/manage.py - test: bootstrap - $(VENV) makemigrations --check - $(VENV) startapp test_app + cd testproject && poetry run src/manage.py makemigrations --check + cd testproject && poetry run src/manage.py startapp test_app + + make coverage bootstrap: rm -Rf testproject - cookiecutter --no-input ./ + poetry run cookiecutter --no-input ./ + + cd testproject && poetry install coverage: - $(VENV) -m pip install pytest-cov - $(VENV) -m pytest --cov-report=xml --cov=core --cov=users --cov=a12n --cov=sepulkas + cd testproject && poetry run python -m pytest --cov-report=xml --cov=core --cov=apps.a12n --cov=apps.users --cov=sepulkas diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 00000000..bbb5fa54 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,511 @@ +# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. + +[[package]] +name = "arrow" +version = "1.3.0" +description = "Better dates & times for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "arrow-1.3.0-py3-none-any.whl", hash = "sha256:c728b120ebc00eb84e01882a6f5e7927a53960aa990ce7dd2b10f39005a67f80"}, + {file = "arrow-1.3.0.tar.gz", hash = "sha256:d4540617648cb5f895730f1ad8c82a65f2dad0166f57b75f3ca54759c4d67a85"}, +] + +[package.dependencies] +python-dateutil = ">=2.7.0" +types-python-dateutil = ">=2.8.10" + +[package.extras] +doc = ["doc8", "sphinx (>=7.0.0)", "sphinx-autobuild", "sphinx-autodoc-typehints", "sphinx_rtd_theme (>=1.3.0)"] +test = ["dateparser (==1.*)", "pre-commit", "pytest", "pytest-cov", "pytest-mock", "pytz (==2021.1)", "simplejson (==3.*)"] + +[[package]] +name = "binaryornot" +version = "0.4.4" +description = "Ultra-lightweight pure Python package to check if a file is binary or text." +optional = false +python-versions = "*" +files = [ + {file = "binaryornot-0.4.4-py2.py3-none-any.whl", hash = "sha256:b8b71173c917bddcd2c16070412e369c3ed7f0528926f70cac18a6c97fd563e4"}, + {file = "binaryornot-0.4.4.tar.gz", hash = "sha256:359501dfc9d40632edc9fac890e19542db1a287bbcfa58175b66658392018061"}, +] + +[package.dependencies] +chardet = ">=3.0.2" + +[[package]] +name = "certifi" +version = "2023.11.17" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.6" +files = [ + {file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"}, + {file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"}, +] + +[[package]] +name = "chardet" +version = "5.2.0" +description = "Universal encoding detector for Python 3" +optional = false +python-versions = ">=3.7" +files = [ + {file = "chardet-5.2.0-py3-none-any.whl", hash = "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970"}, + {file = "chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7"}, +] + +[[package]] +name = "charset-normalizer" +version = "3.3.2" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, + {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, +] + +[[package]] +name = "click" +version = "8.1.7" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +files = [ + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "cookiecutter" +version = "2.5.0" +description = "A command-line utility that creates projects from project templates, e.g. creating a Python package project from a Python package project template." +optional = false +python-versions = ">=3.7" +files = [ + {file = "cookiecutter-2.5.0-py3-none-any.whl", hash = "sha256:8aa2f12ed11bc05628651e9dc4353a10571dd9908aaaaeec959a2b9ea465a5d2"}, + {file = "cookiecutter-2.5.0.tar.gz", hash = "sha256:e61e9034748e3f41b8bd2c11f00d030784b48711c4d5c42363c50989a65331ec"}, +] + +[package.dependencies] +arrow = "*" +binaryornot = ">=0.4.4" +click = ">=7.0,<9.0.0" +Jinja2 = ">=2.7,<4.0.0" +python-slugify = ">=4.0.0" +pyyaml = ">=5.3.1" +requests = ">=2.23.0" +rich = "*" + +[[package]] +name = "idna" +version = "3.6" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.5" +files = [ + {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, + {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, +] + +[[package]] +name = "jinja2" +version = "3.1.2" +description = "A very fast and expressive template engine." +optional = false +python-versions = ">=3.7" +files = [ + {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, + {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, +] + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "markdown-it-py" +version = "3.0.0" +description = "Python port of markdown-it. Markdown parsing, done right!" +optional = false +python-versions = ">=3.8" +files = [ + {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, + {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, +] + +[package.dependencies] +mdurl = ">=0.1,<1.0" + +[package.extras] +benchmarking = ["psutil", "pytest", "pytest-benchmark"] +code-style = ["pre-commit (>=3.0,<4.0)"] +compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] +linkify = ["linkify-it-py (>=1,<3)"] +plugins = ["mdit-py-plugins"] +profiling = ["gprof2dot"] +rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] + +[[package]] +name = "markupsafe" +version = "2.1.3" +description = "Safely add untrusted strings to HTML/XML markup." +optional = false +python-versions = ">=3.7" +files = [ + {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-win32.whl", hash = "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-win32.whl", hash = "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-win_amd64.whl", hash = "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-win32.whl", hash = "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-win_amd64.whl", hash = "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-win32.whl", hash = "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba"}, + {file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"}, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +description = "Markdown URL utilities" +optional = false +python-versions = ">=3.7" +files = [ + {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, + {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, +] + +[[package]] +name = "pygments" +version = "2.17.2" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.7" +files = [ + {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"}, + {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"}, +] + +[package.extras] +plugins = ["importlib-metadata"] +windows-terminal = ["colorama (>=0.4.6)"] + +[[package]] +name = "python-dateutil" +version = "2.8.2" +description = "Extensions to the standard Python datetime module" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +files = [ + {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, + {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, +] + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "python-slugify" +version = "8.0.1" +description = "A Python slugify application that also handles Unicode" +optional = false +python-versions = ">=3.7" +files = [ + {file = "python-slugify-8.0.1.tar.gz", hash = "sha256:ce0d46ddb668b3be82f4ed5e503dbc33dd815d83e2eb6824211310d3fb172a27"}, + {file = "python_slugify-8.0.1-py2.py3-none-any.whl", hash = "sha256:70ca6ea68fe63ecc8fa4fcf00ae651fc8a5d02d93dcd12ae6d4fc7ca46c4d395"}, +] + +[package.dependencies] +text-unidecode = ">=1.3" + +[package.extras] +unidecode = ["Unidecode (>=1.1.1)"] + +[[package]] +name = "pyyaml" +version = "6.0.1" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.6" +files = [ + {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, + {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, + {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, + {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, + {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, + {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, + {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, +] + +[[package]] +name = "requests" +version = "2.31.0" +description = "Python HTTP for Humans." +optional = false +python-versions = ">=3.7" +files = [ + {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, + {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, +] + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "rich" +version = "13.7.0" +description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "rich-13.7.0-py3-none-any.whl", hash = "sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235"}, + {file = "rich-13.7.0.tar.gz", hash = "sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa"}, +] + +[package.dependencies] +markdown-it-py = ">=2.2.0" +pygments = ">=2.13.0,<3.0.0" + +[package.extras] +jupyter = ["ipywidgets (>=7.5.1,<9)"] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] + +[[package]] +name = "text-unidecode" +version = "1.3" +description = "The most basic Text::Unidecode port" +optional = false +python-versions = "*" +files = [ + {file = "text-unidecode-1.3.tar.gz", hash = "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93"}, + {file = "text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8"}, +] + +[[package]] +name = "types-python-dateutil" +version = "2.8.19.14" +description = "Typing stubs for python-dateutil" +optional = false +python-versions = "*" +files = [ + {file = "types-python-dateutil-2.8.19.14.tar.gz", hash = "sha256:1f4f10ac98bb8b16ade9dbee3518d9ace017821d94b057a425b069f834737f4b"}, + {file = "types_python_dateutil-2.8.19.14-py3-none-any.whl", hash = "sha256:f977b8de27787639986b4e28963263fd0e5158942b3ecef91b9335c130cb1ce9"}, +] + +[[package]] +name = "urllib3" +version = "2.1.0" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=3.8" +files = [ + {file = "urllib3-2.1.0-py3-none-any.whl", hash = "sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3"}, + {file = "urllib3-2.1.0.tar.gz", hash = "sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54"}, +] + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] + +[metadata] +lock-version = "2.0" +python-versions = "~3.11" +content-hash = "d6d0e3ca33f5cc8ff39cb535e2d1d0e8c980759e7a708dfdbef90ff204d43941" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..90adcab3 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,14 @@ +[tool.poetry] +authors = ["Fedor Borshev "] +description = "" +name = "django-fandsdev" +readme = "README.md" +version = "2023.11.29" + +[tool.poetry.dependencies] +cookiecutter = "^2.5.0" +python = "~3.11" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/{{cookiecutter.project_slug}}/Makefile b/{{cookiecutter.project_slug}}/Makefile index 4201290c..1e4308d4 100644 --- a/{{cookiecutter.project_slug}}/Makefile +++ b/{{cookiecutter.project_slug}}/Makefile @@ -1,5 +1,8 @@ manage = poetry run src/manage.py +compilemessages: messages + $(manage) compilemessages + fmt: poetry run autoflake --in-place --remove-all-unused-imports --recursive src tests poetry run isort src tests @@ -13,11 +16,11 @@ lint: poetry run mypy src tests poetry run dotenv-linter src/core/.env.ci -test: - mkdir -p src/static +messages: + $(manage) makemessages --locale ru +test: compilemessages $(manage) makemigrations --dry-run --no-input --check - $(manage) compilemessages poetry run pytest --dead-fixtures poetry run pytest -x diff --git a/{{cookiecutter.project_slug}}/src/.django-app-template/admin.py-tpl b/{{cookiecutter.project_slug}}/src/.django-app-template/admin.py-tpl index 00b062ee..f026a054 100644 --- a/{{cookiecutter.project_slug}}/src/.django-app-template/admin.py-tpl +++ b/{{cookiecutter.project_slug}}/src/.django-app-template/admin.py-tpl @@ -1,3 +1,3 @@ from django.contrib import admin -from core.admin import ModelAdmin \ No newline at end of file +from core.admin import ModelAdmin diff --git a/{{cookiecutter.project_slug}}/src/core/conf/api.py~ b/{{cookiecutter.project_slug}}/src/core/conf/api.py~ deleted file mode 100644 index c935ec7e..00000000 --- a/{{cookiecutter.project_slug}}/src/core/conf/api.py~ +++ /dev/null @@ -1,51 +0,0 @@ -from core.conf.environ import env - -# Django REST Framework -# https://www.django-rest-framework.org/api-guide/settings/ - -DISABLE_THROTTLING = env("DISABLE_THROTTLING", cast=bool, default=False) -MAX_PAGE_SIZE = env("MAX_PAGE_SIZE", cast=int, default=1000) - -REST_FRAMEWORK = { - "DEFAULT_FILTER_BACKENDS": ("django_filters.rest_framework.DjangoFilterBackend",), - "DEFAULT_PERMISSION_CLASSES": ("rest_framework.permissions.IsAuthenticatedOrReadOnly",), - "DEFAULT_AUTHENTICATION_CLASSES": [ - "rest_framework.authentication.TokenAuthentication", - "rest_framework_jwt.authentication.JSONWebTokenAuthentication", - ], - "DEFAULT_RENDERER_CLASSES": [ - "app.api.renderers.AppJSONRenderer", - ], - "DEFAULT_PARSER_CLASSES": [ - "djangorestframework_camel_case.parser.CamelCaseJSONParser", - "djangorestframework_camel_case.parser.CamelCaseMultiPartParser", - "djangorestframework_camel_case.parser.CamelCaseFormParser", - ], - "DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.NamespaceVersioning", - "DEFAULT_PAGINATION_CLASS": "app.api.pagination.AppPagination", - "PAGE_SIZE": env("PAGE_SIZE", cast=int, default=20), - "DEFAULT_THROTTLE_RATES": { - "anon-auth": "10/min", - }, - "DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema", -} - -# Adding session auth and browsable API at the developer machine -if env("DEBUG", cast=bool, default=False): - REST_FRAMEWORK["DEFAULT_AUTHENTICATION_CLASSES"].append("rest_framework.authentication.SessionAuthentication") - REST_FRAMEWORK["DEFAULT_RENDERER_CLASSES"].append("djangorestframework_camel_case.render.CamelCaseBrowsableAPIRenderer") - - -# Set up drf_spectacular, https://drf-spectacular.readthedocs.io/en/latest/settings.html -SPECTACULAR_SETTINGS = { - "TITLE": "Our fancy API", - "DESCRIPTION": "So great, needs no docs", - "SWAGGER_UI_DIST": "SIDECAR", - "SWAGGER_UI_FAVICON_HREF": "SIDECAR", - "REDOC_DIST": "SIDECAR", - "CAMELIZE_NAMES": True, - "POSTPROCESSING_HOOKS": [ - "drf_spectacular.hooks.postprocess_schema_enums", - "drf_spectacular.contrib.djangorestframework_camel_case.camelize_serializer_fields", - ], -} diff --git a/{{cookiecutter.project_slug}}/src/core/conf/auth.py~ b/{{cookiecutter.project_slug}}/src/core/conf/auth.py~ deleted file mode 100644 index b69e08d4..00000000 --- a/{{cookiecutter.project_slug}}/src/core/conf/auth.py~ +++ /dev/null @@ -1,34 +0,0 @@ -from datetime import timedelta - -from app.conf.environ import env - -AUTH_USER_MODEL = "users.User" -AXES_ENABLED = env("AXES_ENABLED", cast=bool, default=True) - -AUTHENTICATION_BACKENDS = [ - "axes.backends.AxesBackend", - "django.contrib.auth.backends.ModelBackend", -] - -JWT_AUTH = { - "JWT_EXPIRATION_DELTA": timedelta(days=14), - "JWT_REFRESH_EXPIRATION_DELTA": timedelta(days=21), - "JWT_ALLOW_REFRESH": True, -} - - -# -# Security notice: we use plain bcrypt to store passwords. -# -# We avoid django default pre-hashing algorithm -# from contrib.auth.hashers.BCryptSHA256PasswordHasher. -# -# The reason is compatibility with other hashing libraries, like -# Ruby Devise or Laravel default hashing algorithm. -# -# This means we can't store passwords longer then 72 symbols. -# - -PASSWORD_HASHERS = [ - "django.contrib.auth.hashers.BCryptPasswordHasher", -] diff --git a/{{cookiecutter.project_slug}}/src/core/conf/boilerplate.py~ b/{{cookiecutter.project_slug}}/src/core/conf/boilerplate.py~ deleted file mode 100644 index f16ff2a1..00000000 --- a/{{cookiecutter.project_slug}}/src/core/conf/boilerplate.py~ +++ /dev/null @@ -1,10 +0,0 @@ -from pathlib import Path - -BASE_DIR = Path(__file__).resolve().parent.parent - -ROOT_URLCONF = "app.urls" - -# Disable built-in ./manage.py test command in favor of pytest -TEST_RUNNER = "app.test.disable_test_command_runner.DisableTestCommandRunner" - -WSGI_APPLICATION = "app.wsgi.application" diff --git a/{{cookiecutter.project_slug}}/src/core/conf/db.py~ b/{{cookiecutter.project_slug}}/src/core/conf/db.py~ deleted file mode 100644 index 935f531e..00000000 --- a/{{cookiecutter.project_slug}}/src/core/conf/db.py~ +++ /dev/null @@ -1,12 +0,0 @@ -# Database -# https://docs.djangoproject.com/en/3.0/ref/settings/#databases - -from app.conf.environ import env - -DATABASES = { - # read os.environ["DATABASE_URL"] and raises ImproperlyConfigured exception if not found - "default": env.db(), -} - -# https://docs.djangoproject.com/en/3.2/releases/3.2/#customizing-type-of-auto-created-primary-keys -DEFAULT_AUTO_FIELD = "django.db.models.AutoField" diff --git a/{{cookiecutter.project_slug}}/src/core/conf/environ.py~ b/{{cookiecutter.project_slug}}/src/core/conf/environ.py~ deleted file mode 100644 index 1f81d47e..00000000 --- a/{{cookiecutter.project_slug}}/src/core/conf/environ.py~ +++ /dev/null @@ -1,18 +0,0 @@ -import environ # type: ignore[import-untyped] - -from app.conf.boilerplate import BASE_DIR - -env = environ.Env( - DEBUG=(bool, False), - CI=(bool, False), -) - -envpath = BASE_DIR / ".env" - -if envpath.exists(): - env.read_env(envpath) - - -__all__ = [ - "env", -] diff --git a/{{cookiecutter.project_slug}}/src/core/conf/http.py~ b/{{cookiecutter.project_slug}}/src/core/conf/http.py~ deleted file mode 100644 index ff265e4f..00000000 --- a/{{cookiecutter.project_slug}}/src/core/conf/http.py~ +++ /dev/null @@ -1,11 +0,0 @@ -from app.conf.environ import env - -ALLOWED_HOSTS = ["*"] # host validation is not necessary in 2020 -CSRF_TRUSTED_ORIGINS = [ - "http://your.app.origin", -] - -if env("DEBUG"): - ABSOLUTE_HOST = "http://localhost:3000" -else: - ABSOLUTE_HOST = "https://your.app.com" diff --git a/{{cookiecutter.project_slug}}/src/core/conf/installed_apps.py~ b/{{cookiecutter.project_slug}}/src/core/conf/installed_apps.py~ deleted file mode 100644 index efab9b26..00000000 --- a/{{cookiecutter.project_slug}}/src/core/conf/installed_apps.py~ +++ /dev/null @@ -1,25 +0,0 @@ -# Application definition - -APPS = [ - "app", - "a12n", - "users", -] - -THIRD_PARTY_APPS = [ - "drf_spectacular", - "drf_spectacular_sidecar", - "rest_framework", - "rest_framework.authtoken", - "rest_framework_jwt.blacklist", - "django_filters", - "axes", - "django.contrib.admin", - "django.contrib.auth", - "django.contrib.contenttypes", - "django.contrib.sessions", - "django.contrib.messages", - "django.contrib.staticfiles", -] - -INSTALLED_APPS = APPS + THIRD_PARTY_APPS diff --git a/{{cookiecutter.project_slug}}/src/core/conf/media.py~ b/{{cookiecutter.project_slug}}/src/core/conf/media.py~ deleted file mode 100644 index 7c655753..00000000 --- a/{{cookiecutter.project_slug}}/src/core/conf/media.py~ +++ /dev/null @@ -1,4 +0,0 @@ -from app.conf.environ import env - -MEDIA_URL = "/media/" -MEDIA_ROOT = env("MEDIA_ROOT", cast=str, default="media") diff --git a/{{cookiecutter.project_slug}}/src/core/conf/middleware.py~ b/{{cookiecutter.project_slug}}/src/core/conf/middleware.py~ deleted file mode 100644 index a59a180e..00000000 --- a/{{cookiecutter.project_slug}}/src/core/conf/middleware.py~ +++ /dev/null @@ -1,12 +0,0 @@ -MIDDLEWARE = [ - "django.middleware.security.SecurityMiddleware", - "whitenoise.middleware.WhiteNoiseMiddleware", - "django.contrib.sessions.middleware.SessionMiddleware", - "django.middleware.common.CommonMiddleware", - "django.middleware.csrf.CsrfViewMiddleware", - "django.contrib.auth.middleware.AuthenticationMiddleware", - "django.contrib.messages.middleware.MessageMiddleware", - "django.middleware.clickjacking.XFrameOptionsMiddleware", - "app.middleware.real_ip.real_ip_middleware", - "axes.middleware.AxesMiddleware", -] diff --git a/{{cookiecutter.project_slug}}/src/core/conf/sentry.py~ b/{{cookiecutter.project_slug}}/src/core/conf/sentry.py~ deleted file mode 100644 index 3050ea95..00000000 --- a/{{cookiecutter.project_slug}}/src/core/conf/sentry.py~ +++ /dev/null @@ -1,15 +0,0 @@ -from app.conf.environ import env - -# Sentry -# https://sentry.io/for/django/ - -SENTRY_DSN = env("SENTRY_DSN", cast=str, default="") - -if not env("DEBUG") and len(SENTRY_DSN): - import sentry_sdk - from sentry_sdk.integrations.django import DjangoIntegration - - sentry_sdk.init( - dsn=SENTRY_DSN, - integrations=[DjangoIntegration()], - ) diff --git a/{{cookiecutter.project_slug}}/src/core/conf/static.py~ b/{{cookiecutter.project_slug}}/src/core/conf/static.py~ deleted file mode 100644 index 33530c17..00000000 --- a/{{cookiecutter.project_slug}}/src/core/conf/static.py~ +++ /dev/null @@ -1,7 +0,0 @@ -from app.conf.environ import env - -# Static files (CSS, JavaScript, Images) -# https://docs.djangoproject.com/en/3.0/howto/static-files/ - -STATIC_URL = "/static/" -STATIC_ROOT = env("STATIC_ROOT", cast=str, default="static") diff --git a/{{cookiecutter.project_slug}}/src/core/conf/storage.py~ b/{{cookiecutter.project_slug}}/src/core/conf/storage.py~ deleted file mode 100644 index 761bdf2b..00000000 --- a/{{cookiecutter.project_slug}}/src/core/conf/storage.py~ +++ /dev/null @@ -1,10 +0,0 @@ -from app.conf.environ import env - -DEFAULT_FILE_STORAGE = env("DEFAULT_FILE_STORAGE", cast=str, default="django.core.files.storage.FileSystemStorage") - -AWS_ACCESS_KEY_ID = env("AWS_ACCESS_KEY_ID", default="") -AWS_SECRET_ACCESS_KEY = env("AWS_SECRET_ACCESS_KEY", default="") -AWS_STORAGE_BUCKET_NAME = env("AWS_STORAGE_BUCKET_NAME", default="") -AWS_S3_REGION_NAME = env("AWS_S3_REGION_NAME", default="") -AWS_S3_ENDPOINT_URL = env("AWS_S3_ENDPOINT_URL", default="") -AWS_DEFAULT_ACL = env("AWS_DEFAULT_ACL", default="") From 4a0ffbf4c63c3ba7b807a3a5854e71166011226b Mon Sep 17 00:00:00 2001 From: hnthh Date: Wed, 29 Nov 2023 21:21:03 +0300 Subject: [PATCH 005/116] simplify --- Makefile | 11 ----------- cookiecutter.json | 13 ++++++++----- hooks/post_gen_project.sh | 7 ++++++- .../.dockerignore | 0 .../.editorconfig | 0 .../.github/workflows/ci.yml | 0 .../.gitignore | 0 .../Dockerfile | 0 .../Makefile | 0 .../README.md | 0 .../docker-compose.yml | 0 .../mypy.ini | 0 .../poetry.lock | 0 .../pyproject.toml | 4 ++-- .../src/.django-app-template/__init__.py-tpl | 0 .../src/.django-app-template/admin.py-tpl | 0 .../api/serializers/__init__.py | 0 .../api/serializers/app_name.py-tpl | 0 .../src/.django-app-template/api/urls.py-tpl | 0 .../src/.django-app-template/api/views/__init__.py | 0 .../.django-app-template/api/views/app_name.py-tpl | 0 .../src/.django-app-template/apps.py-tpl | 0 .../.django-app-template/migrations/__init__.py-tpl | 0 .../src/.django-app-template/models/__init__.py | 0 .../src/.django-app-template/models/app_name.py-tpl | 0 .../src/apps/a12n/__init__.py | 0 .../src/apps/a12n/api/serializers.py | 0 .../src/apps/a12n/api/throttling.py | 0 .../src/apps/a12n/api/urls.py | 0 .../src/apps/a12n/api/views.py | 0 .../src/apps/a12n/migrations/__init__.py | 0 .../src/apps/a12n/utils.py | 0 .../src/apps/users/__init__.py | 0 .../src/apps/users/admin.py | 0 .../src/apps/users/api/serializers.py | 0 .../src/apps/users/api/urls.py | 0 .../src/apps/users/api/viewsets.py | 0 .../src/apps/users/migrations/0001_initial.py | 0 .../src/apps/users/migrations/__init__.py | 0 .../src/apps/users/models.py | 0 .../src/core/.env.ci | 0 .../src/core/__init__.py | 0 .../src/core/admin/README.md | 0 .../src/core/admin/__init__.py | 0 .../src/core/admin/model_admin.py | 0 .../src/core/api/pagination.py | 0 .../src/core/api/renderers.py | 0 .../src/core/api/throttling.py | 0 .../src/core/api/viewsets.py | 0 .../src/core/asgi.py | 0 .../src/core/base_config.py | 0 .../src/core/conf/api.py | 0 .../src/core/conf/auth.py | 0 .../src/core/conf/boilerplate.py | 0 .../src/core/conf/db.py | 0 .../src/core/conf/environ.py | 0 .../src/core/conf/healthchecks.py | 0 .../src/core/conf/http.py | 0 .../src/core/conf/i18n.py | 0 .../src/core/conf/installed_apps.py | 0 .../src/core/conf/media.py | 0 .../src/core/conf/middleware.py | 0 .../src/core/conf/sentry.py | 0 .../src/core/conf/static.py | 0 .../src/core/conf/storage.py | 0 .../src/core/conf/templates.py | 0 .../src/core/conf/timezone.py | 0 .../src/core/management/commands/makemigrations.py | 0 .../src/core/management/commands/startapp.py | 0 .../src/core/middleware/real_ip.py | 0 .../src/core/models.py | 0 .../src/core/services.py | 0 .../src/core/settings.py | 0 .../src/core/testing/__init__.py | 0 .../src/core/testing/api.py | 0 .../src/core/testing/factory.py | 0 .../src/core/testing/mixer.py | 0 .../src/core/testing/runner.py | 0 .../src/core/testing/types.py | 0 .../src/core/urls/__init__.py | 0 .../src/core/urls/v1.py | 0 .../src/core/wsgi.py | 0 .../src/manage.py | 0 .../tests/__init__.py | 0 .../apps/a12n/jwt_views/test_obtain_jwt_view.py | 0 .../apps/a12n/jwt_views/test_refresh_jwt_token.py | 0 .../tests/apps/users/factory.py | 0 .../tests/apps/users/fixtures.py | 0 .../tests/apps/users/test_password_hashing.py | 0 .../tests/apps/users/test_whoami.py | 0 .../tests/conftest.py | 0 .../tests/core/__init__.py | 0 .../tests/core/factory.py | 0 .../tests/core/fixtures.py | 0 .../tests/core/test_health.py | 0 .../tests/core/test_remote_addr_midlleware.py | 0 .../tests/core/testing/__init__.py | 0 .../tests/core/testing/factory/__init__.py | 0 .../tests/core/testing/factory/test_factory.py | 0 .../tests/core/testing/factory/test_registry.py | 0 100 files changed, 16 insertions(+), 19 deletions(-) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/.dockerignore (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/.editorconfig (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/.github/workflows/ci.yml (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/.gitignore (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/Dockerfile (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/Makefile (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/README.md (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/docker-compose.yml (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/mypy.ini (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/poetry.lock (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/pyproject.toml (97%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/.django-app-template/__init__.py-tpl (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/.django-app-template/admin.py-tpl (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/.django-app-template/api/serializers/__init__.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/.django-app-template/api/serializers/app_name.py-tpl (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/.django-app-template/api/urls.py-tpl (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/.django-app-template/api/views/__init__.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/.django-app-template/api/views/app_name.py-tpl (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/.django-app-template/apps.py-tpl (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/.django-app-template/migrations/__init__.py-tpl (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/.django-app-template/models/__init__.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/.django-app-template/models/app_name.py-tpl (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/apps/a12n/__init__.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/apps/a12n/api/serializers.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/apps/a12n/api/throttling.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/apps/a12n/api/urls.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/apps/a12n/api/views.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/apps/a12n/migrations/__init__.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/apps/a12n/utils.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/apps/users/__init__.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/apps/users/admin.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/apps/users/api/serializers.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/apps/users/api/urls.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/apps/users/api/viewsets.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/apps/users/migrations/0001_initial.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/apps/users/migrations/__init__.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/apps/users/models.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/core/.env.ci (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/core/__init__.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/core/admin/README.md (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/core/admin/__init__.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/core/admin/model_admin.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/core/api/pagination.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/core/api/renderers.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/core/api/throttling.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/core/api/viewsets.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/core/asgi.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/core/base_config.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/core/conf/api.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/core/conf/auth.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/core/conf/boilerplate.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/core/conf/db.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/core/conf/environ.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/core/conf/healthchecks.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/core/conf/http.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/core/conf/i18n.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/core/conf/installed_apps.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/core/conf/media.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/core/conf/middleware.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/core/conf/sentry.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/core/conf/static.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/core/conf/storage.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/core/conf/templates.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/core/conf/timezone.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/core/management/commands/makemigrations.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/core/management/commands/startapp.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/core/middleware/real_ip.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/core/models.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/core/services.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/core/settings.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/core/testing/__init__.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/core/testing/api.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/core/testing/factory.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/core/testing/mixer.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/core/testing/runner.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/core/testing/types.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/core/urls/__init__.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/core/urls/v1.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/core/wsgi.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/src/manage.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/tests/__init__.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/tests/apps/a12n/jwt_views/test_obtain_jwt_view.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/tests/apps/a12n/jwt_views/test_refresh_jwt_token.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/tests/apps/users/factory.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/tests/apps/users/fixtures.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/tests/apps/users/test_password_hashing.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/tests/apps/users/test_whoami.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/tests/conftest.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/tests/core/__init__.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/tests/core/factory.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/tests/core/fixtures.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/tests/core/test_health.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/tests/core/test_remote_addr_midlleware.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/tests/core/testing/__init__.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/tests/core/testing/factory/__init__.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/tests/core/testing/factory/test_factory.py (100%) rename {{{cookiecutter.project_slug}} => {{cookiecutter.name}}}/tests/core/testing/factory/test_registry.py (100%) diff --git a/Makefile b/Makefile index bed71bcd..972496ee 100644 --- a/Makefile +++ b/Makefile @@ -1,15 +1,4 @@ -test: bootstrap - cd testproject && poetry run src/manage.py makemigrations --check - cd testproject && poetry run src/manage.py startapp test_app - - make coverage - bootstrap: rm -Rf testproject poetry run cookiecutter --no-input ./ - - cd testproject && poetry install - -coverage: - cd testproject && poetry run python -m pytest --cov-report=xml --cov=core --cov=apps.a12n --cov=apps.users --cov=sepulkas diff --git a/cookiecutter.json b/cookiecutter.json index 9565ae8a..645fe819 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -1,9 +1,12 @@ { - "project_slug": "testproject", - "email": "", - "project_version": "0.0.0-dev", + "name": "testproject", "_copy_without_render": [ - "*.py-tpl", - ".github/workflows/ci.yml" + ".github/workflows/ci.yml", + ".mypy_cache", + ".pytest_cache", + ".venv", + "**/__pycache__", + "db.sqlite", + "src/.django-app-template" ] } diff --git a/hooks/post_gen_project.sh b/hooks/post_gen_project.sh index f1face43..66b1b492 100644 --- a/hooks/post_gen_project.sh +++ b/hooks/post_gen_project.sh @@ -1,10 +1,15 @@ #!/bin/bash -e +rm -rf .mypy_cache \ + .pytest_cache \ + .venv + cp src/core/.env.ci src/core/.env poetry install poetry run python src/manage.py collectstatic poetry run python src/manage.py migrate +poetry run python src/manage.py startapp test_app -make fmt lint test +make lint test diff --git a/{{cookiecutter.project_slug}}/.dockerignore b/{{cookiecutter.name}}/.dockerignore similarity index 100% rename from {{cookiecutter.project_slug}}/.dockerignore rename to {{cookiecutter.name}}/.dockerignore diff --git a/{{cookiecutter.project_slug}}/.editorconfig b/{{cookiecutter.name}}/.editorconfig similarity index 100% rename from {{cookiecutter.project_slug}}/.editorconfig rename to {{cookiecutter.name}}/.editorconfig diff --git a/{{cookiecutter.project_slug}}/.github/workflows/ci.yml b/{{cookiecutter.name}}/.github/workflows/ci.yml similarity index 100% rename from {{cookiecutter.project_slug}}/.github/workflows/ci.yml rename to {{cookiecutter.name}}/.github/workflows/ci.yml diff --git a/{{cookiecutter.project_slug}}/.gitignore b/{{cookiecutter.name}}/.gitignore similarity index 100% rename from {{cookiecutter.project_slug}}/.gitignore rename to {{cookiecutter.name}}/.gitignore diff --git a/{{cookiecutter.project_slug}}/Dockerfile b/{{cookiecutter.name}}/Dockerfile similarity index 100% rename from {{cookiecutter.project_slug}}/Dockerfile rename to {{cookiecutter.name}}/Dockerfile diff --git a/{{cookiecutter.project_slug}}/Makefile b/{{cookiecutter.name}}/Makefile similarity index 100% rename from {{cookiecutter.project_slug}}/Makefile rename to {{cookiecutter.name}}/Makefile diff --git a/{{cookiecutter.project_slug}}/README.md b/{{cookiecutter.name}}/README.md similarity index 100% rename from {{cookiecutter.project_slug}}/README.md rename to {{cookiecutter.name}}/README.md diff --git a/{{cookiecutter.project_slug}}/docker-compose.yml b/{{cookiecutter.name}}/docker-compose.yml similarity index 100% rename from {{cookiecutter.project_slug}}/docker-compose.yml rename to {{cookiecutter.name}}/docker-compose.yml diff --git a/{{cookiecutter.project_slug}}/mypy.ini b/{{cookiecutter.name}}/mypy.ini similarity index 100% rename from {{cookiecutter.project_slug}}/mypy.ini rename to {{cookiecutter.name}}/mypy.ini diff --git a/{{cookiecutter.project_slug}}/poetry.lock b/{{cookiecutter.name}}/poetry.lock similarity index 100% rename from {{cookiecutter.project_slug}}/poetry.lock rename to {{cookiecutter.name}}/poetry.lock diff --git a/{{cookiecutter.project_slug}}/pyproject.toml b/{{cookiecutter.name}}/pyproject.toml similarity index 97% rename from {{cookiecutter.project_slug}}/pyproject.toml rename to {{cookiecutter.name}}/pyproject.toml index 3ab5c1a8..52da4dbf 100644 --- a/{{cookiecutter.project_slug}}/pyproject.toml +++ b/{{cookiecutter.name}}/pyproject.toml @@ -1,9 +1,9 @@ [tool.poetry] authors = ["you "] description = "your project description" -name = "{{cookiecutter.project_slug}}" +name = "your project name" readme = "README.md" -version = "{{cookiecutter.project_version}}" +version = "0.0.0-dev" [tool.poetry.dependencies] python = "~3.11" diff --git a/{{cookiecutter.project_slug}}/src/.django-app-template/__init__.py-tpl b/{{cookiecutter.name}}/src/.django-app-template/__init__.py-tpl similarity index 100% rename from {{cookiecutter.project_slug}}/src/.django-app-template/__init__.py-tpl rename to {{cookiecutter.name}}/src/.django-app-template/__init__.py-tpl diff --git a/{{cookiecutter.project_slug}}/src/.django-app-template/admin.py-tpl b/{{cookiecutter.name}}/src/.django-app-template/admin.py-tpl similarity index 100% rename from {{cookiecutter.project_slug}}/src/.django-app-template/admin.py-tpl rename to {{cookiecutter.name}}/src/.django-app-template/admin.py-tpl diff --git a/{{cookiecutter.project_slug}}/src/.django-app-template/api/serializers/__init__.py b/{{cookiecutter.name}}/src/.django-app-template/api/serializers/__init__.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/.django-app-template/api/serializers/__init__.py rename to {{cookiecutter.name}}/src/.django-app-template/api/serializers/__init__.py diff --git a/{{cookiecutter.project_slug}}/src/.django-app-template/api/serializers/app_name.py-tpl b/{{cookiecutter.name}}/src/.django-app-template/api/serializers/app_name.py-tpl similarity index 100% rename from {{cookiecutter.project_slug}}/src/.django-app-template/api/serializers/app_name.py-tpl rename to {{cookiecutter.name}}/src/.django-app-template/api/serializers/app_name.py-tpl diff --git a/{{cookiecutter.project_slug}}/src/.django-app-template/api/urls.py-tpl b/{{cookiecutter.name}}/src/.django-app-template/api/urls.py-tpl similarity index 100% rename from {{cookiecutter.project_slug}}/src/.django-app-template/api/urls.py-tpl rename to {{cookiecutter.name}}/src/.django-app-template/api/urls.py-tpl diff --git a/{{cookiecutter.project_slug}}/src/.django-app-template/api/views/__init__.py b/{{cookiecutter.name}}/src/.django-app-template/api/views/__init__.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/.django-app-template/api/views/__init__.py rename to {{cookiecutter.name}}/src/.django-app-template/api/views/__init__.py diff --git a/{{cookiecutter.project_slug}}/src/.django-app-template/api/views/app_name.py-tpl b/{{cookiecutter.name}}/src/.django-app-template/api/views/app_name.py-tpl similarity index 100% rename from {{cookiecutter.project_slug}}/src/.django-app-template/api/views/app_name.py-tpl rename to {{cookiecutter.name}}/src/.django-app-template/api/views/app_name.py-tpl diff --git a/{{cookiecutter.project_slug}}/src/.django-app-template/apps.py-tpl b/{{cookiecutter.name}}/src/.django-app-template/apps.py-tpl similarity index 100% rename from {{cookiecutter.project_slug}}/src/.django-app-template/apps.py-tpl rename to {{cookiecutter.name}}/src/.django-app-template/apps.py-tpl diff --git a/{{cookiecutter.project_slug}}/src/.django-app-template/migrations/__init__.py-tpl b/{{cookiecutter.name}}/src/.django-app-template/migrations/__init__.py-tpl similarity index 100% rename from {{cookiecutter.project_slug}}/src/.django-app-template/migrations/__init__.py-tpl rename to {{cookiecutter.name}}/src/.django-app-template/migrations/__init__.py-tpl diff --git a/{{cookiecutter.project_slug}}/src/.django-app-template/models/__init__.py b/{{cookiecutter.name}}/src/.django-app-template/models/__init__.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/.django-app-template/models/__init__.py rename to {{cookiecutter.name}}/src/.django-app-template/models/__init__.py diff --git a/{{cookiecutter.project_slug}}/src/.django-app-template/models/app_name.py-tpl b/{{cookiecutter.name}}/src/.django-app-template/models/app_name.py-tpl similarity index 100% rename from {{cookiecutter.project_slug}}/src/.django-app-template/models/app_name.py-tpl rename to {{cookiecutter.name}}/src/.django-app-template/models/app_name.py-tpl diff --git a/{{cookiecutter.project_slug}}/src/apps/a12n/__init__.py b/{{cookiecutter.name}}/src/apps/a12n/__init__.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/apps/a12n/__init__.py rename to {{cookiecutter.name}}/src/apps/a12n/__init__.py diff --git a/{{cookiecutter.project_slug}}/src/apps/a12n/api/serializers.py b/{{cookiecutter.name}}/src/apps/a12n/api/serializers.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/apps/a12n/api/serializers.py rename to {{cookiecutter.name}}/src/apps/a12n/api/serializers.py diff --git a/{{cookiecutter.project_slug}}/src/apps/a12n/api/throttling.py b/{{cookiecutter.name}}/src/apps/a12n/api/throttling.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/apps/a12n/api/throttling.py rename to {{cookiecutter.name}}/src/apps/a12n/api/throttling.py diff --git a/{{cookiecutter.project_slug}}/src/apps/a12n/api/urls.py b/{{cookiecutter.name}}/src/apps/a12n/api/urls.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/apps/a12n/api/urls.py rename to {{cookiecutter.name}}/src/apps/a12n/api/urls.py diff --git a/{{cookiecutter.project_slug}}/src/apps/a12n/api/views.py b/{{cookiecutter.name}}/src/apps/a12n/api/views.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/apps/a12n/api/views.py rename to {{cookiecutter.name}}/src/apps/a12n/api/views.py diff --git a/{{cookiecutter.project_slug}}/src/apps/a12n/migrations/__init__.py b/{{cookiecutter.name}}/src/apps/a12n/migrations/__init__.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/apps/a12n/migrations/__init__.py rename to {{cookiecutter.name}}/src/apps/a12n/migrations/__init__.py diff --git a/{{cookiecutter.project_slug}}/src/apps/a12n/utils.py b/{{cookiecutter.name}}/src/apps/a12n/utils.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/apps/a12n/utils.py rename to {{cookiecutter.name}}/src/apps/a12n/utils.py diff --git a/{{cookiecutter.project_slug}}/src/apps/users/__init__.py b/{{cookiecutter.name}}/src/apps/users/__init__.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/apps/users/__init__.py rename to {{cookiecutter.name}}/src/apps/users/__init__.py diff --git a/{{cookiecutter.project_slug}}/src/apps/users/admin.py b/{{cookiecutter.name}}/src/apps/users/admin.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/apps/users/admin.py rename to {{cookiecutter.name}}/src/apps/users/admin.py diff --git a/{{cookiecutter.project_slug}}/src/apps/users/api/serializers.py b/{{cookiecutter.name}}/src/apps/users/api/serializers.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/apps/users/api/serializers.py rename to {{cookiecutter.name}}/src/apps/users/api/serializers.py diff --git a/{{cookiecutter.project_slug}}/src/apps/users/api/urls.py b/{{cookiecutter.name}}/src/apps/users/api/urls.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/apps/users/api/urls.py rename to {{cookiecutter.name}}/src/apps/users/api/urls.py diff --git a/{{cookiecutter.project_slug}}/src/apps/users/api/viewsets.py b/{{cookiecutter.name}}/src/apps/users/api/viewsets.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/apps/users/api/viewsets.py rename to {{cookiecutter.name}}/src/apps/users/api/viewsets.py diff --git a/{{cookiecutter.project_slug}}/src/apps/users/migrations/0001_initial.py b/{{cookiecutter.name}}/src/apps/users/migrations/0001_initial.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/apps/users/migrations/0001_initial.py rename to {{cookiecutter.name}}/src/apps/users/migrations/0001_initial.py diff --git a/{{cookiecutter.project_slug}}/src/apps/users/migrations/__init__.py b/{{cookiecutter.name}}/src/apps/users/migrations/__init__.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/apps/users/migrations/__init__.py rename to {{cookiecutter.name}}/src/apps/users/migrations/__init__.py diff --git a/{{cookiecutter.project_slug}}/src/apps/users/models.py b/{{cookiecutter.name}}/src/apps/users/models.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/apps/users/models.py rename to {{cookiecutter.name}}/src/apps/users/models.py diff --git a/{{cookiecutter.project_slug}}/src/core/.env.ci b/{{cookiecutter.name}}/src/core/.env.ci similarity index 100% rename from {{cookiecutter.project_slug}}/src/core/.env.ci rename to {{cookiecutter.name}}/src/core/.env.ci diff --git a/{{cookiecutter.project_slug}}/src/core/__init__.py b/{{cookiecutter.name}}/src/core/__init__.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/core/__init__.py rename to {{cookiecutter.name}}/src/core/__init__.py diff --git a/{{cookiecutter.project_slug}}/src/core/admin/README.md b/{{cookiecutter.name}}/src/core/admin/README.md similarity index 100% rename from {{cookiecutter.project_slug}}/src/core/admin/README.md rename to {{cookiecutter.name}}/src/core/admin/README.md diff --git a/{{cookiecutter.project_slug}}/src/core/admin/__init__.py b/{{cookiecutter.name}}/src/core/admin/__init__.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/core/admin/__init__.py rename to {{cookiecutter.name}}/src/core/admin/__init__.py diff --git a/{{cookiecutter.project_slug}}/src/core/admin/model_admin.py b/{{cookiecutter.name}}/src/core/admin/model_admin.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/core/admin/model_admin.py rename to {{cookiecutter.name}}/src/core/admin/model_admin.py diff --git a/{{cookiecutter.project_slug}}/src/core/api/pagination.py b/{{cookiecutter.name}}/src/core/api/pagination.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/core/api/pagination.py rename to {{cookiecutter.name}}/src/core/api/pagination.py diff --git a/{{cookiecutter.project_slug}}/src/core/api/renderers.py b/{{cookiecutter.name}}/src/core/api/renderers.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/core/api/renderers.py rename to {{cookiecutter.name}}/src/core/api/renderers.py diff --git a/{{cookiecutter.project_slug}}/src/core/api/throttling.py b/{{cookiecutter.name}}/src/core/api/throttling.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/core/api/throttling.py rename to {{cookiecutter.name}}/src/core/api/throttling.py diff --git a/{{cookiecutter.project_slug}}/src/core/api/viewsets.py b/{{cookiecutter.name}}/src/core/api/viewsets.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/core/api/viewsets.py rename to {{cookiecutter.name}}/src/core/api/viewsets.py diff --git a/{{cookiecutter.project_slug}}/src/core/asgi.py b/{{cookiecutter.name}}/src/core/asgi.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/core/asgi.py rename to {{cookiecutter.name}}/src/core/asgi.py diff --git a/{{cookiecutter.project_slug}}/src/core/base_config.py b/{{cookiecutter.name}}/src/core/base_config.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/core/base_config.py rename to {{cookiecutter.name}}/src/core/base_config.py diff --git a/{{cookiecutter.project_slug}}/src/core/conf/api.py b/{{cookiecutter.name}}/src/core/conf/api.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/core/conf/api.py rename to {{cookiecutter.name}}/src/core/conf/api.py diff --git a/{{cookiecutter.project_slug}}/src/core/conf/auth.py b/{{cookiecutter.name}}/src/core/conf/auth.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/core/conf/auth.py rename to {{cookiecutter.name}}/src/core/conf/auth.py diff --git a/{{cookiecutter.project_slug}}/src/core/conf/boilerplate.py b/{{cookiecutter.name}}/src/core/conf/boilerplate.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/core/conf/boilerplate.py rename to {{cookiecutter.name}}/src/core/conf/boilerplate.py diff --git a/{{cookiecutter.project_slug}}/src/core/conf/db.py b/{{cookiecutter.name}}/src/core/conf/db.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/core/conf/db.py rename to {{cookiecutter.name}}/src/core/conf/db.py diff --git a/{{cookiecutter.project_slug}}/src/core/conf/environ.py b/{{cookiecutter.name}}/src/core/conf/environ.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/core/conf/environ.py rename to {{cookiecutter.name}}/src/core/conf/environ.py diff --git a/{{cookiecutter.project_slug}}/src/core/conf/healthchecks.py b/{{cookiecutter.name}}/src/core/conf/healthchecks.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/core/conf/healthchecks.py rename to {{cookiecutter.name}}/src/core/conf/healthchecks.py diff --git a/{{cookiecutter.project_slug}}/src/core/conf/http.py b/{{cookiecutter.name}}/src/core/conf/http.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/core/conf/http.py rename to {{cookiecutter.name}}/src/core/conf/http.py diff --git a/{{cookiecutter.project_slug}}/src/core/conf/i18n.py b/{{cookiecutter.name}}/src/core/conf/i18n.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/core/conf/i18n.py rename to {{cookiecutter.name}}/src/core/conf/i18n.py diff --git a/{{cookiecutter.project_slug}}/src/core/conf/installed_apps.py b/{{cookiecutter.name}}/src/core/conf/installed_apps.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/core/conf/installed_apps.py rename to {{cookiecutter.name}}/src/core/conf/installed_apps.py diff --git a/{{cookiecutter.project_slug}}/src/core/conf/media.py b/{{cookiecutter.name}}/src/core/conf/media.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/core/conf/media.py rename to {{cookiecutter.name}}/src/core/conf/media.py diff --git a/{{cookiecutter.project_slug}}/src/core/conf/middleware.py b/{{cookiecutter.name}}/src/core/conf/middleware.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/core/conf/middleware.py rename to {{cookiecutter.name}}/src/core/conf/middleware.py diff --git a/{{cookiecutter.project_slug}}/src/core/conf/sentry.py b/{{cookiecutter.name}}/src/core/conf/sentry.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/core/conf/sentry.py rename to {{cookiecutter.name}}/src/core/conf/sentry.py diff --git a/{{cookiecutter.project_slug}}/src/core/conf/static.py b/{{cookiecutter.name}}/src/core/conf/static.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/core/conf/static.py rename to {{cookiecutter.name}}/src/core/conf/static.py diff --git a/{{cookiecutter.project_slug}}/src/core/conf/storage.py b/{{cookiecutter.name}}/src/core/conf/storage.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/core/conf/storage.py rename to {{cookiecutter.name}}/src/core/conf/storage.py diff --git a/{{cookiecutter.project_slug}}/src/core/conf/templates.py b/{{cookiecutter.name}}/src/core/conf/templates.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/core/conf/templates.py rename to {{cookiecutter.name}}/src/core/conf/templates.py diff --git a/{{cookiecutter.project_slug}}/src/core/conf/timezone.py b/{{cookiecutter.name}}/src/core/conf/timezone.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/core/conf/timezone.py rename to {{cookiecutter.name}}/src/core/conf/timezone.py diff --git a/{{cookiecutter.project_slug}}/src/core/management/commands/makemigrations.py b/{{cookiecutter.name}}/src/core/management/commands/makemigrations.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/core/management/commands/makemigrations.py rename to {{cookiecutter.name}}/src/core/management/commands/makemigrations.py diff --git a/{{cookiecutter.project_slug}}/src/core/management/commands/startapp.py b/{{cookiecutter.name}}/src/core/management/commands/startapp.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/core/management/commands/startapp.py rename to {{cookiecutter.name}}/src/core/management/commands/startapp.py diff --git a/{{cookiecutter.project_slug}}/src/core/middleware/real_ip.py b/{{cookiecutter.name}}/src/core/middleware/real_ip.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/core/middleware/real_ip.py rename to {{cookiecutter.name}}/src/core/middleware/real_ip.py diff --git a/{{cookiecutter.project_slug}}/src/core/models.py b/{{cookiecutter.name}}/src/core/models.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/core/models.py rename to {{cookiecutter.name}}/src/core/models.py diff --git a/{{cookiecutter.project_slug}}/src/core/services.py b/{{cookiecutter.name}}/src/core/services.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/core/services.py rename to {{cookiecutter.name}}/src/core/services.py diff --git a/{{cookiecutter.project_slug}}/src/core/settings.py b/{{cookiecutter.name}}/src/core/settings.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/core/settings.py rename to {{cookiecutter.name}}/src/core/settings.py diff --git a/{{cookiecutter.project_slug}}/src/core/testing/__init__.py b/{{cookiecutter.name}}/src/core/testing/__init__.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/core/testing/__init__.py rename to {{cookiecutter.name}}/src/core/testing/__init__.py diff --git a/{{cookiecutter.project_slug}}/src/core/testing/api.py b/{{cookiecutter.name}}/src/core/testing/api.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/core/testing/api.py rename to {{cookiecutter.name}}/src/core/testing/api.py diff --git a/{{cookiecutter.project_slug}}/src/core/testing/factory.py b/{{cookiecutter.name}}/src/core/testing/factory.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/core/testing/factory.py rename to {{cookiecutter.name}}/src/core/testing/factory.py diff --git a/{{cookiecutter.project_slug}}/src/core/testing/mixer.py b/{{cookiecutter.name}}/src/core/testing/mixer.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/core/testing/mixer.py rename to {{cookiecutter.name}}/src/core/testing/mixer.py diff --git a/{{cookiecutter.project_slug}}/src/core/testing/runner.py b/{{cookiecutter.name}}/src/core/testing/runner.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/core/testing/runner.py rename to {{cookiecutter.name}}/src/core/testing/runner.py diff --git a/{{cookiecutter.project_slug}}/src/core/testing/types.py b/{{cookiecutter.name}}/src/core/testing/types.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/core/testing/types.py rename to {{cookiecutter.name}}/src/core/testing/types.py diff --git a/{{cookiecutter.project_slug}}/src/core/urls/__init__.py b/{{cookiecutter.name}}/src/core/urls/__init__.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/core/urls/__init__.py rename to {{cookiecutter.name}}/src/core/urls/__init__.py diff --git a/{{cookiecutter.project_slug}}/src/core/urls/v1.py b/{{cookiecutter.name}}/src/core/urls/v1.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/core/urls/v1.py rename to {{cookiecutter.name}}/src/core/urls/v1.py diff --git a/{{cookiecutter.project_slug}}/src/core/wsgi.py b/{{cookiecutter.name}}/src/core/wsgi.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/core/wsgi.py rename to {{cookiecutter.name}}/src/core/wsgi.py diff --git a/{{cookiecutter.project_slug}}/src/manage.py b/{{cookiecutter.name}}/src/manage.py similarity index 100% rename from {{cookiecutter.project_slug}}/src/manage.py rename to {{cookiecutter.name}}/src/manage.py diff --git a/{{cookiecutter.project_slug}}/tests/__init__.py b/{{cookiecutter.name}}/tests/__init__.py similarity index 100% rename from {{cookiecutter.project_slug}}/tests/__init__.py rename to {{cookiecutter.name}}/tests/__init__.py diff --git a/{{cookiecutter.project_slug}}/tests/apps/a12n/jwt_views/test_obtain_jwt_view.py b/{{cookiecutter.name}}/tests/apps/a12n/jwt_views/test_obtain_jwt_view.py similarity index 100% rename from {{cookiecutter.project_slug}}/tests/apps/a12n/jwt_views/test_obtain_jwt_view.py rename to {{cookiecutter.name}}/tests/apps/a12n/jwt_views/test_obtain_jwt_view.py diff --git a/{{cookiecutter.project_slug}}/tests/apps/a12n/jwt_views/test_refresh_jwt_token.py b/{{cookiecutter.name}}/tests/apps/a12n/jwt_views/test_refresh_jwt_token.py similarity index 100% rename from {{cookiecutter.project_slug}}/tests/apps/a12n/jwt_views/test_refresh_jwt_token.py rename to {{cookiecutter.name}}/tests/apps/a12n/jwt_views/test_refresh_jwt_token.py diff --git a/{{cookiecutter.project_slug}}/tests/apps/users/factory.py b/{{cookiecutter.name}}/tests/apps/users/factory.py similarity index 100% rename from {{cookiecutter.project_slug}}/tests/apps/users/factory.py rename to {{cookiecutter.name}}/tests/apps/users/factory.py diff --git a/{{cookiecutter.project_slug}}/tests/apps/users/fixtures.py b/{{cookiecutter.name}}/tests/apps/users/fixtures.py similarity index 100% rename from {{cookiecutter.project_slug}}/tests/apps/users/fixtures.py rename to {{cookiecutter.name}}/tests/apps/users/fixtures.py diff --git a/{{cookiecutter.project_slug}}/tests/apps/users/test_password_hashing.py b/{{cookiecutter.name}}/tests/apps/users/test_password_hashing.py similarity index 100% rename from {{cookiecutter.project_slug}}/tests/apps/users/test_password_hashing.py rename to {{cookiecutter.name}}/tests/apps/users/test_password_hashing.py diff --git a/{{cookiecutter.project_slug}}/tests/apps/users/test_whoami.py b/{{cookiecutter.name}}/tests/apps/users/test_whoami.py similarity index 100% rename from {{cookiecutter.project_slug}}/tests/apps/users/test_whoami.py rename to {{cookiecutter.name}}/tests/apps/users/test_whoami.py diff --git a/{{cookiecutter.project_slug}}/tests/conftest.py b/{{cookiecutter.name}}/tests/conftest.py similarity index 100% rename from {{cookiecutter.project_slug}}/tests/conftest.py rename to {{cookiecutter.name}}/tests/conftest.py diff --git a/{{cookiecutter.project_slug}}/tests/core/__init__.py b/{{cookiecutter.name}}/tests/core/__init__.py similarity index 100% rename from {{cookiecutter.project_slug}}/tests/core/__init__.py rename to {{cookiecutter.name}}/tests/core/__init__.py diff --git a/{{cookiecutter.project_slug}}/tests/core/factory.py b/{{cookiecutter.name}}/tests/core/factory.py similarity index 100% rename from {{cookiecutter.project_slug}}/tests/core/factory.py rename to {{cookiecutter.name}}/tests/core/factory.py diff --git a/{{cookiecutter.project_slug}}/tests/core/fixtures.py b/{{cookiecutter.name}}/tests/core/fixtures.py similarity index 100% rename from {{cookiecutter.project_slug}}/tests/core/fixtures.py rename to {{cookiecutter.name}}/tests/core/fixtures.py diff --git a/{{cookiecutter.project_slug}}/tests/core/test_health.py b/{{cookiecutter.name}}/tests/core/test_health.py similarity index 100% rename from {{cookiecutter.project_slug}}/tests/core/test_health.py rename to {{cookiecutter.name}}/tests/core/test_health.py diff --git a/{{cookiecutter.project_slug}}/tests/core/test_remote_addr_midlleware.py b/{{cookiecutter.name}}/tests/core/test_remote_addr_midlleware.py similarity index 100% rename from {{cookiecutter.project_slug}}/tests/core/test_remote_addr_midlleware.py rename to {{cookiecutter.name}}/tests/core/test_remote_addr_midlleware.py diff --git a/{{cookiecutter.project_slug}}/tests/core/testing/__init__.py b/{{cookiecutter.name}}/tests/core/testing/__init__.py similarity index 100% rename from {{cookiecutter.project_slug}}/tests/core/testing/__init__.py rename to {{cookiecutter.name}}/tests/core/testing/__init__.py diff --git a/{{cookiecutter.project_slug}}/tests/core/testing/factory/__init__.py b/{{cookiecutter.name}}/tests/core/testing/factory/__init__.py similarity index 100% rename from {{cookiecutter.project_slug}}/tests/core/testing/factory/__init__.py rename to {{cookiecutter.name}}/tests/core/testing/factory/__init__.py diff --git a/{{cookiecutter.project_slug}}/tests/core/testing/factory/test_factory.py b/{{cookiecutter.name}}/tests/core/testing/factory/test_factory.py similarity index 100% rename from {{cookiecutter.project_slug}}/tests/core/testing/factory/test_factory.py rename to {{cookiecutter.name}}/tests/core/testing/factory/test_factory.py diff --git a/{{cookiecutter.project_slug}}/tests/core/testing/factory/test_registry.py b/{{cookiecutter.name}}/tests/core/testing/factory/test_registry.py similarity index 100% rename from {{cookiecutter.project_slug}}/tests/core/testing/factory/test_registry.py rename to {{cookiecutter.name}}/tests/core/testing/factory/test_registry.py From c17676c78095bdeadfb3356dc4c2e4e92771c209 Mon Sep 17 00:00:00 2001 From: hnthh Date: Wed, 29 Nov 2023 21:27:49 +0300 Subject: [PATCH 006/116] do not compile messages for tests --- {{cookiecutter.name}}/Makefile | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/{{cookiecutter.name}}/Makefile b/{{cookiecutter.name}}/Makefile index 1e4308d4..44af9c27 100644 --- a/{{cookiecutter.name}}/Makefile +++ b/{{cookiecutter.name}}/Makefile @@ -1,8 +1,5 @@ manage = poetry run src/manage.py -compilemessages: messages - $(manage) compilemessages - fmt: poetry run autoflake --in-place --remove-all-unused-imports --recursive src tests poetry run isort src tests @@ -16,10 +13,7 @@ lint: poetry run mypy src tests poetry run dotenv-linter src/core/.env.ci -messages: - $(manage) makemessages --locale ru - -test: compilemessages +test: $(manage) makemigrations --dry-run --no-input --check poetry run pytest --dead-fixtures poetry run pytest -x From bec4e7db57c95ef4460c85acdae3bd5fb856c2eb Mon Sep 17 00:00:00 2001 From: hnthh Date: Wed, 29 Nov 2023 21:56:37 +0300 Subject: [PATCH 007/116] refactor makefile, add xdist --- hooks/post_gen_project.sh | 5 ++-- {{cookiecutter.name}}/Makefile | 10 ++++---- {{cookiecutter.name}}/poetry.lock | 36 +++++++++++++++++++++++++++- {{cookiecutter.name}}/pyproject.toml | 1 + 4 files changed, 45 insertions(+), 7 deletions(-) diff --git a/hooks/post_gen_project.sh b/hooks/post_gen_project.sh index 66b1b492..e92de978 100644 --- a/hooks/post_gen_project.sh +++ b/hooks/post_gen_project.sh @@ -2,7 +2,8 @@ rm -rf .mypy_cache \ .pytest_cache \ - .venv + .venv \ + db.sqlite cp src/core/.env.ci src/core/.env @@ -12,4 +13,4 @@ poetry run python src/manage.py collectstatic poetry run python src/manage.py migrate poetry run python src/manage.py startapp test_app -make lint test +make checks test diff --git a/{{cookiecutter.name}}/Makefile b/{{cookiecutter.name}}/Makefile index 44af9c27..6577cbbe 100644 --- a/{{cookiecutter.name}}/Makefile +++ b/{{cookiecutter.name}}/Makefile @@ -1,12 +1,15 @@ manage = poetry run src/manage.py +numprocesses = 4 fmt: poetry run autoflake --in-place --remove-all-unused-imports --recursive src tests poetry run isort src tests poetry run black src tests -lint: +checks: $(manage) check + $(manage) makemigrations --check --dry-run --no-input + poetry run isort --check-only src tests poetry run black --check src tests poetry run flake8 src tests @@ -14,8 +17,7 @@ lint: poetry run dotenv-linter src/core/.env.ci test: - $(manage) makemigrations --dry-run --no-input --check poetry run pytest --dead-fixtures - poetry run pytest -x + poetry run pytest --create-db --exitfirst --numprocesses ${numprocesses} -pr: fmt lint test +pr: fmt checks test diff --git a/{{cookiecutter.name}}/poetry.lock b/{{cookiecutter.name}}/poetry.lock index 02730576..788d2549 100644 --- a/{{cookiecutter.name}}/poetry.lock +++ b/{{cookiecutter.name}}/poetry.lock @@ -770,6 +770,20 @@ files = [ {file = "eradicate-2.3.0.tar.gz", hash = "sha256:06df115be3b87d0fc1c483db22a2ebb12bcf40585722810d809cc770f5031c37"}, ] +[[package]] +name = "execnet" +version = "2.0.2" +description = "execnet: rapid multi-Python deployment" +optional = false +python-versions = ">=3.7" +files = [ + {file = "execnet-2.0.2-py3-none-any.whl", hash = "sha256:88256416ae766bc9e8895c76a87928c0012183da3cc4fc18016e6f050e025f41"}, + {file = "execnet-2.0.2.tar.gz", hash = "sha256:cc59bc4423742fd71ad227122eb0dd44db51efb3dc4095b45ac9a08c770096af"}, +] + +[package.extras] +testing = ["hatch", "pre-commit", "pytest", "tox"] + [[package]] name = "executing" version = "2.0.1" @@ -1758,6 +1772,26 @@ files = [ [package.dependencies] pytest = "*" +[[package]] +name = "pytest-xdist" +version = "3.5.0" +description = "pytest xdist plugin for distributed testing, most importantly across multiple CPUs" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-xdist-3.5.0.tar.gz", hash = "sha256:cbb36f3d67e0c478baa57fa4edc8843887e0f6cfc42d677530a36d7472b32d8a"}, + {file = "pytest_xdist-3.5.0-py3-none-any.whl", hash = "sha256:d075629c7e00b611df89f490a5063944bee7a4362a5ff11c7cc7824a03dfce24"}, +] + +[package.dependencies] +execnet = ">=1.1" +pytest = ">=6.2.0" + +[package.extras] +psutil = ["psutil (>=3.0)"] +setproctitle = ["setproctitle"] +testing = ["filelock"] + [[package]] name = "python-dateutil" version = "2.8.2" @@ -2344,4 +2378,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = "~3.11" -content-hash = "bb83763d7bfabc3fda739af05e88a9c8600e401a2179281d9df265cdfa5a49f4" +content-hash = "7be9742978068475147ce2116693b14fdb3532c3d8fe9fc9a02bebdd86831097" diff --git a/{{cookiecutter.name}}/pyproject.toml b/{{cookiecutter.name}}/pyproject.toml index 52da4dbf..3c96c17c 100644 --- a/{{cookiecutter.name}}/pyproject.toml +++ b/{{cookiecutter.name}}/pyproject.toml @@ -58,6 +58,7 @@ pytest-env = "^1.1.1" pytest-freezegun = "^0.4.2" pytest-mock = "^3.12.0" pytest-randomly = "^3.15.0" +pytest-xdist = "^3.5.0" types-freezegun = "^1.1.10" types-pillow = "^10.1.0.2" From bb07cd4523abba5ee17961bd43b0a3fd07a3a1f7 Mon Sep 17 00:00:00 2001 From: hnthh Date: Wed, 29 Nov 2023 22:19:33 +0300 Subject: [PATCH 008/116] return/apply black, isort --- {{cookiecutter.name}}/Makefile | 10 +-- {{cookiecutter.name}}/pyproject.toml | 8 +-- .../src/apps/a12n/api/serializers.py | 2 - .../src/apps/users/api/viewsets.py | 3 +- .../src/apps/users/migrations/0001_initial.py | 62 +++---------------- {{cookiecutter.name}}/src/core/.env.ci | 4 +- .../src/core/api/pagination.py | 3 +- .../src/core/api/renderers.py | 4 +- .../src/core/api/throttling.py | 3 +- .../src/core/api/viewsets.py | 22 ++----- {{cookiecutter.name}}/src/core/asgi.py | 9 --- {{cookiecutter.name}}/src/core/conf/api.py | 12 +--- .../management/commands/makemigrations.py | 8 +-- .../src/core/management/commands/startapp.py | 8 +-- .../src/core/middleware/real_ip.py | 4 +- {{cookiecutter.name}}/src/core/models.py | 1 - {{cookiecutter.name}}/src/core/services.py | 3 +- .../src/core/testing/__init__.py | 3 +- .../src/core/testing/factory.py | 4 +- .../src/core/urls/__init__.py | 3 +- {{cookiecutter.name}}/src/core/urls/v1.py | 7 +-- {{cookiecutter.name}}/src/core/wsgi.py | 9 --- {{cookiecutter.name}}/src/manage.py | 3 +- .../a12n/jwt_views/test_obtain_jwt_view.py | 10 +-- .../a12n/jwt_views/test_refresh_jwt_token.py | 1 - .../tests/apps/users/fixtures.py | 3 +- .../tests/apps/users/test_password_hashing.py | 3 +- {{cookiecutter.name}}/tests/core/factory.py | 11 +--- {{cookiecutter.name}}/tests/core/fixtures.py | 3 +- .../tests/core/test_remote_addr_midlleware.py | 1 - .../core/testing/factory/test_factory.py | 19 ++---- .../core/testing/factory/test_registry.py | 7 +-- 32 files changed, 66 insertions(+), 187 deletions(-) delete mode 100644 {{cookiecutter.name}}/src/apps/a12n/api/serializers.py diff --git a/{{cookiecutter.name}}/Makefile b/{{cookiecutter.name}}/Makefile index 6577cbbe..5e4c98a3 100644 --- a/{{cookiecutter.name}}/Makefile +++ b/{{cookiecutter.name}}/Makefile @@ -1,11 +1,6 @@ manage = poetry run src/manage.py numprocesses = 4 -fmt: - poetry run autoflake --in-place --remove-all-unused-imports --recursive src tests - poetry run isort src tests - poetry run black src tests - checks: $(manage) check $(manage) makemigrations --check --dry-run --no-input @@ -16,6 +11,11 @@ checks: poetry run mypy src tests poetry run dotenv-linter src/core/.env.ci +fmt: + poetry run autoflake --in-place --remove-all-unused-imports --recursive src tests + poetry run isort src tests + poetry run black src tests + test: poetry run pytest --dead-fixtures poetry run pytest --create-db --exitfirst --numprocesses ${numprocesses} diff --git a/{{cookiecutter.name}}/pyproject.toml b/{{cookiecutter.name}}/pyproject.toml index 3c96c17c..e9adaf18 100644 --- a/{{cookiecutter.name}}/pyproject.toml +++ b/{{cookiecutter.name}}/pyproject.toml @@ -66,6 +66,9 @@ types-pillow = "^10.1.0.2" requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" +[tool.black] +line_length = 160 + [tool.flake8] exclude = ["migrations", "__pycache__"] ignore = [ @@ -82,13 +85,10 @@ inline-quotes = "\"" max-line-length = 160 [tool.isort] -extra_standard_library = ["pytest"] include_trailing_comma = true -known_django = ["django", "restframework"] line_length = 160 multi_line_output = 3 -profile = "google" -sections = ["FUTURE", "STDLIB", "THIRDPARTY", "DJANGO", "FIRSTPARTY", "LOCALFOLDER"] +src_paths = ["src", "tests"] use_parentheses = true [tool.pytest.ini_options] diff --git a/{{cookiecutter.name}}/src/apps/a12n/api/serializers.py b/{{cookiecutter.name}}/src/apps/a12n/api/serializers.py deleted file mode 100644 index 5754b069..00000000 --- a/{{cookiecutter.name}}/src/apps/a12n/api/serializers.py +++ /dev/null @@ -1,2 +0,0 @@ -# Create your DRF serializers here -# https://www.django-rest-framework.org/tutorial/1-serialization/#creating-a-serializer-class diff --git a/{{cookiecutter.name}}/src/apps/users/api/viewsets.py b/{{cookiecutter.name}}/src/apps/users/api/viewsets.py index faf560e7..549f1831 100644 --- a/{{cookiecutter.name}}/src/apps/users/api/viewsets.py +++ b/{{cookiecutter.name}}/src/apps/users/api/viewsets.py @@ -1,10 +1,9 @@ +from django.db.models import QuerySet from rest_framework.generics import GenericAPIView from rest_framework.permissions import IsAuthenticated from rest_framework.request import Request from rest_framework.response import Response -from django.db.models import QuerySet - from apps.users.api.serializers import UserSerializer from apps.users.models import User diff --git a/{{cookiecutter.name}}/src/apps/users/migrations/0001_initial.py b/{{cookiecutter.name}}/src/apps/users/migrations/0001_initial.py index 19cb5247..8117842a 100644 --- a/{{cookiecutter.name}}/src/apps/users/migrations/0001_initial.py +++ b/{{cookiecutter.name}}/src/apps/users/migrations/0001_initial.py @@ -2,9 +2,8 @@ import django.contrib.auth.models import django.contrib.auth.validators -from django.db import migrations -from django.db import models import django.utils.timezone +from django.db import migrations, models class Migration(migrations.Migration): @@ -18,22 +17,9 @@ class Migration(migrations.Migration): migrations.CreateModel( name="User", fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), + ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), ("password", models.CharField(max_length=128, verbose_name="password")), - ( - "last_login", - models.DateTimeField( - blank=True, null=True, verbose_name="last login" - ), - ), + ("last_login", models.DateTimeField(blank=True, null=True, verbose_name="last login")), ( "is_superuser", models.BooleanField( @@ -45,43 +31,20 @@ class Migration(migrations.Migration): ( "username", models.CharField( - error_messages={ - "unique": "A user with that username already exists." - }, + error_messages={"unique": "A user with that username already exists."}, help_text="Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.", max_length=150, unique=True, - validators=[ - django.contrib.auth.validators.UnicodeUsernameValidator() - ], + validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name="username", ), ), - ( - "first_name", - models.CharField( - blank=True, max_length=150, verbose_name="first name" - ), - ), - ( - "last_name", - models.CharField( - blank=True, max_length=150, verbose_name="last name" - ), - ), - ( - "email", - models.EmailField( - blank=True, max_length=254, verbose_name="email address" - ), - ), + ("first_name", models.CharField(blank=True, max_length=150, verbose_name="first name")), + ("last_name", models.CharField(blank=True, max_length=150, verbose_name="last name")), + ("email", models.EmailField(blank=True, max_length=254, verbose_name="email address")), ( "is_staff", - models.BooleanField( - default=False, - help_text="Designates whether the user can log into this admin site.", - verbose_name="staff status", - ), + models.BooleanField(default=False, help_text="Designates whether the user can log into this admin site.", verbose_name="staff status"), ), ( "is_active", @@ -91,12 +54,7 @@ class Migration(migrations.Migration): verbose_name="active", ), ), - ( - "date_joined", - models.DateTimeField( - default=django.utils.timezone.now, verbose_name="date joined" - ), - ), + ("date_joined", models.DateTimeField(default=django.utils.timezone.now, verbose_name="date joined")), ( "groups", models.ManyToManyField( diff --git a/{{cookiecutter.name}}/src/core/.env.ci b/{{cookiecutter.name}}/src/core/.env.ci index c5be2fe6..9eb2374e 100644 --- a/{{cookiecutter.name}}/src/core/.env.ci +++ b/{{cookiecutter.name}}/src/core/.env.ci @@ -1,3 +1,3 @@ -DEBUG=Off -SECRET_KEY=l!@xGb!Jkd]pQsvtU,@y`=%/c}mY;]oYwnsVeU}".VwwClOX DATABASE_URL=sqlite:///db.sqlite +DEBUG=off +SECRET_KEY=l!@xGb!Jkd]pQsvtU,@y`=%/c}mY;]oYwnsVeU}".VwwClOX diff --git a/{{cookiecutter.name}}/src/core/api/pagination.py b/{{cookiecutter.name}}/src/core/api/pagination.py index 85f200fd..c8b88cad 100644 --- a/{{cookiecutter.name}}/src/core/api/pagination.py +++ b/{{cookiecutter.name}}/src/core/api/pagination.py @@ -1,6 +1,5 @@ -from rest_framework.pagination import PageNumberPagination - from django.conf import settings +from rest_framework.pagination import PageNumberPagination class AppPagination(PageNumberPagination): diff --git a/{{cookiecutter.name}}/src/core/api/renderers.py b/{{cookiecutter.name}}/src/core/api/renderers.py index 03060e42..89fded20 100644 --- a/{{cookiecutter.name}}/src/core/api/renderers.py +++ b/{{cookiecutter.name}}/src/core/api/renderers.py @@ -3,6 +3,4 @@ class AppJSONRenderer(CamelCaseJSONRenderer): charset = "utf-8" # force DRF to add charset header to the content-type - json_underscoreize = { - "no_underscore_before_number": True - } # https://github.com/vbabiy/djangorestframework-camel-case#underscoreize-options + json_underscoreize = {"no_underscore_before_number": True} # https://github.com/vbabiy/djangorestframework-camel-case#underscoreize-options diff --git a/{{cookiecutter.name}}/src/core/api/throttling.py b/{{cookiecutter.name}}/src/core/api/throttling.py index 46028513..99dd51c6 100644 --- a/{{cookiecutter.name}}/src/core/api/throttling.py +++ b/{{cookiecutter.name}}/src/core/api/throttling.py @@ -1,10 +1,9 @@ from typing import Protocol +from django.conf import settings from rest_framework.request import Request from rest_framework.views import APIView -from django.conf import settings - class BaseThrottle(Protocol): def allow_request(self, request: Request, view: APIView) -> bool: diff --git a/{{cookiecutter.name}}/src/core/api/viewsets.py b/{{cookiecutter.name}}/src/core/api/viewsets.py index dfae0417..a5f60b91 100644 --- a/{{cookiecutter.name}}/src/core/api/viewsets.py +++ b/{{cookiecutter.name}}/src/core/api/viewsets.py @@ -1,9 +1,7 @@ from typing import Any, Optional, Protocol, Type -from rest_framework import mixins -from rest_framework import status -from rest_framework.mixins import CreateModelMixin -from rest_framework.mixins import UpdateModelMixin +from rest_framework import mixins, status +from rest_framework.mixins import CreateModelMixin, UpdateModelMixin from rest_framework.request import Request from rest_framework.response import Response from rest_framework.serializers import BaseSerializer @@ -38,14 +36,10 @@ def get_object(self, *args: Any, **kwargs: Any) -> Any: class DefaultCreateModelMixin(CreateModelMixin): """Return detail-serialized created instance""" - def create( - self: BaseGenericViewSet, request: Request, *args: Any, **kwargs: Any - ) -> Response: + def create(self: BaseGenericViewSet, request: Request, *args: Any, **kwargs: Any) -> Response: serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) - instance = self.perform_create( - serializer - ) # No getting created instance in original DRF + instance = self.perform_create(serializer) # No getting created instance in original DRF headers = self.get_success_headers(serializer.data) return self.get_response(instance, status.HTTP_201_CREATED, headers) @@ -56,16 +50,12 @@ def perform_create(self: BaseGenericViewSet, serializer: Any) -> Any: class DefaultUpdateModelMixin(UpdateModelMixin): """Return detail-serialized updated instance""" - def update( - self: BaseGenericViewSet, request: Request, *args: Any, **kwargs: Any - ) -> Response: + def update(self: BaseGenericViewSet, request: Request, *args: Any, **kwargs: Any) -> Response: partial = kwargs.pop("partial", False) instance = self.get_object() serializer = self.get_serializer(instance, data=request.data, partial=partial) serializer.is_valid(raise_exception=True) - instance = self.perform_update( - serializer - ) # No getting updated instance in original DRF + instance = self.perform_update(serializer) # No getting updated instance in original DRF if getattr(instance, "_prefetched_objects_cache", None): # If 'prefetch_related' has been applied to a queryset, we need to diff --git a/{{cookiecutter.name}}/src/core/asgi.py b/{{cookiecutter.name}}/src/core/asgi.py index bf502ef8..d40fe22b 100644 --- a/{{cookiecutter.name}}/src/core/asgi.py +++ b/{{cookiecutter.name}}/src/core/asgi.py @@ -1,12 +1,3 @@ -""" -ASGI config for app project. - -It exposes the ASGI callable as a module-level variable named ``application``. - -For more information on this file, see -https://docs.djangoproject.com/en/3.0/howto/deployment/asgi/ -""" - import os from django.core.asgi import get_asgi_application diff --git a/{{cookiecutter.name}}/src/core/conf/api.py b/{{cookiecutter.name}}/src/core/conf/api.py index 3fcd7071..1d76eee0 100644 --- a/{{cookiecutter.name}}/src/core/conf/api.py +++ b/{{cookiecutter.name}}/src/core/conf/api.py @@ -8,9 +8,7 @@ REST_FRAMEWORK = { "DEFAULT_FILTER_BACKENDS": ("django_filters.rest_framework.DjangoFilterBackend",), - "DEFAULT_PERMISSION_CLASSES": ( - "rest_framework.permissions.IsAuthenticatedOrReadOnly", - ), + "DEFAULT_PERMISSION_CLASSES": ("rest_framework.permissions.IsAuthenticatedOrReadOnly",), "DEFAULT_AUTHENTICATION_CLASSES": [ "rest_framework.authentication.TokenAuthentication", "rest_framework_jwt.authentication.JSONWebTokenAuthentication", @@ -34,12 +32,8 @@ # Adding session auth and browsable API at the developer machine if env("DEBUG", cast=bool, default=False): - REST_FRAMEWORK["DEFAULT_AUTHENTICATION_CLASSES"].append( - "rest_framework.authentication.SessionAuthentication" - ) - REST_FRAMEWORK["DEFAULT_RENDERER_CLASSES"].append( - "djangorestframework_camel_case.render.CamelCaseBrowsableAPIRenderer" - ) + REST_FRAMEWORK["DEFAULT_AUTHENTICATION_CLASSES"].append("rest_framework.authentication.SessionAuthentication") + REST_FRAMEWORK["DEFAULT_RENDERER_CLASSES"].append("djangorestframework_camel_case.render.CamelCaseBrowsableAPIRenderer") # Set up drf_spectacular, https://drf-spectacular.readthedocs.io/en/latest/settings.html diff --git a/{{cookiecutter.name}}/src/core/management/commands/makemigrations.py b/{{cookiecutter.name}}/src/core/management/commands/makemigrations.py index 5ed88e1f..557b5176 100644 --- a/{{cookiecutter.name}}/src/core/management/commands/makemigrations.py +++ b/{{cookiecutter.name}}/src/core/management/commands/makemigrations.py @@ -10,11 +10,7 @@ class Command(BaseCommand): """Disable automatic names for django migrations, thanks https://adamj.eu/tech/2020/02/24/how-to-disallow-auto-named-django-migrations/""" def handle(self, *app_labels, **options): - if options["name"] is None and not any( - [options["dry_run"], options["check_changes"]] - ): - raise MakemigrationsError( - "Migration name is required. Run again with `-n/--name` argument and specify name explicitly." - ) + if options["name"] is None and not any([options["dry_run"], options["check_changes"]]): + raise MakemigrationsError("Migration name is required. Run again with `-n/--name` argument and specify name explicitly.") super().handle(*app_labels, **options) diff --git a/{{cookiecutter.name}}/src/core/management/commands/startapp.py b/{{cookiecutter.name}}/src/core/management/commands/startapp.py index 49c21bdd..e6fc0108 100644 --- a/{{cookiecutter.name}}/src/core/management/commands/startapp.py +++ b/{{cookiecutter.name}}/src/core/management/commands/startapp.py @@ -9,15 +9,11 @@ class Command(BaseCommand): def handle(self, **options): if "template" not in options or options["template"] is None: - options["template"] = str( - Path(settings.BASE_DIR).parent / ".django-app-template" - ) + options["template"] = str(Path(settings.BASE_DIR).parent / ".django-app-template") super().handle(**options) - testsdir = ( - Path(settings.BASE_DIR).parent.parent / "tests" / "apps" / options["name"] - ) + testsdir = Path(settings.BASE_DIR).parent.parent / "tests" / "apps" / options["name"] testsdir.mkdir(parents=True, exist_ok=True) (testsdir / "__init__.py").touch() diff --git a/{{cookiecutter.name}}/src/core/middleware/real_ip.py b/{{cookiecutter.name}}/src/core/middleware/real_ip.py index a8b536a9..5fa01841 100644 --- a/{{cookiecutter.name}}/src/core/middleware/real_ip.py +++ b/{{cookiecutter.name}}/src/core/middleware/real_ip.py @@ -1,10 +1,8 @@ from typing import Callable +from django.http import HttpRequest, HttpResponse from ipware import get_client_ip -from django.http import HttpRequest -from django.http import HttpResponse - def real_ip_middleware(get_response: Callable) -> Callable: """Set request.META["REMOTE_ADDR"] to ip guessed by django-ipware. diff --git a/{{cookiecutter.name}}/src/core/models.py b/{{cookiecutter.name}}/src/core/models.py index 46c75985..5f9c12b9 100644 --- a/{{cookiecutter.name}}/src/core/models.py +++ b/{{cookiecutter.name}}/src/core/models.py @@ -1,7 +1,6 @@ from typing import Any from behaviors.behaviors import Timestamped # type: ignore - from django.contrib.contenttypes.models import ContentType from django.db import models diff --git a/{{cookiecutter.name}}/src/core/services.py b/{{cookiecutter.name}}/src/core/services.py index 61988855..f2de05c1 100644 --- a/{{cookiecutter.name}}/src/core/services.py +++ b/{{cookiecutter.name}}/src/core/services.py @@ -1,5 +1,4 @@ -from abc import ABCMeta -from abc import abstractmethod +from abc import ABCMeta, abstractmethod from typing import Any, Callable diff --git a/{{cookiecutter.name}}/src/core/testing/__init__.py b/{{cookiecutter.name}}/src/core/testing/__init__.py index 791bc413..55edfa3b 100644 --- a/{{cookiecutter.name}}/src/core/testing/__init__.py +++ b/{{cookiecutter.name}}/src/core/testing/__init__.py @@ -1,6 +1,5 @@ from core.testing.api import ApiClient -from core.testing.factory import FixtureFactory -from core.testing.factory import register +from core.testing.factory import FixtureFactory, register __all__ = [ "ApiClient", diff --git a/{{cookiecutter.name}}/src/core/testing/factory.py b/{{cookiecutter.name}}/src/core/testing/factory.py index 73ae832e..26b7f3a1 100644 --- a/{{cookiecutter.name}}/src/core/testing/factory.py +++ b/{{cookiecutter.name}}/src/core/testing/factory.py @@ -26,9 +26,7 @@ def __init__(self, factory: "FixtureFactory", count: int) -> None: self.count = count def __getattr__(self, name: str) -> Callable: - return lambda *args, **kwargs: [ - getattr(self.factory, name)(*args, **kwargs) for _ in range(self.count) - ] + return lambda *args, **kwargs: [getattr(self.factory, name)(*args, **kwargs) for _ in range(self.count)] class FixtureFactory: diff --git a/{{cookiecutter.name}}/src/core/urls/__init__.py b/{{cookiecutter.name}}/src/core/urls/__init__.py index db251116..8a5cba80 100644 --- a/{{cookiecutter.name}}/src/core/urls/__init__.py +++ b/{{cookiecutter.name}}/src/core/urls/__init__.py @@ -1,6 +1,5 @@ from django.contrib import admin -from django.urls import include -from django.urls import path +from django.urls import include, path api = [ path("v1/", include("core.urls.v1", namespace="v1")), diff --git a/{{cookiecutter.name}}/src/core/urls/v1.py b/{{cookiecutter.name}}/src/core/urls/v1.py index 11a13b64..22d2bbe2 100644 --- a/{{cookiecutter.name}}/src/core/urls/v1.py +++ b/{{cookiecutter.name}}/src/core/urls/v1.py @@ -1,8 +1,5 @@ -from drf_spectacular.views import SpectacularAPIView -from drf_spectacular.views import SpectacularSwaggerView - -from django.urls import include -from django.urls import path +from django.urls import include, path +from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView app_name = "api_v1" diff --git a/{{cookiecutter.name}}/src/core/wsgi.py b/{{cookiecutter.name}}/src/core/wsgi.py index d59bd34a..4892961c 100644 --- a/{{cookiecutter.name}}/src/core/wsgi.py +++ b/{{cookiecutter.name}}/src/core/wsgi.py @@ -1,12 +1,3 @@ -""" -WSGI config for app project. - -It exposes the WSGI callable as a module-level variable named ``application``. - -For more information on this file, see -https://docs.djangoproject.com/en/3.0/howto/deployment/wsgi/ -""" - import os from django.core.wsgi import get_wsgi_application diff --git a/{{cookiecutter.name}}/src/manage.py b/{{cookiecutter.name}}/src/manage.py index fd4cfdf9..df71b05a 100755 --- a/{{cookiecutter.name}}/src/manage.py +++ b/{{cookiecutter.name}}/src/manage.py @@ -1,11 +1,11 @@ #!/usr/bin/env python -"""Django's command-line utility for administrative tasks.""" import os import sys def main() -> None: os.environ.setdefault("DJANGO_SETTINGS_MODULE", "core.settings") + try: from django.core.management import execute_from_command_line except ImportError as exc: @@ -14,6 +14,7 @@ def main() -> None: "available on your PYTHONPATH environment variable? Did you " "forget to activate a virtual environment?", ) from exc + execute_from_command_line(sys.argv) diff --git a/{{cookiecutter.name}}/tests/apps/a12n/jwt_views/test_obtain_jwt_view.py b/{{cookiecutter.name}}/tests/apps/a12n/jwt_views/test_obtain_jwt_view.py index d0e11549..329dd3d6 100644 --- a/{{cookiecutter.name}}/tests/apps/a12n/jwt_views/test_obtain_jwt_view.py +++ b/{{cookiecutter.name}}/tests/apps/a12n/jwt_views/test_obtain_jwt_view.py @@ -1,6 +1,6 @@ import json -import pytest +import pytest from axes.models import AccessAttempt pytestmark = pytest.mark.django_db @@ -40,9 +40,7 @@ def test_getting_token_ok(as_user, get_token): def test_getting_token_is_token(as_user, get_token): result = get_token(as_user.user.username, as_user.password) - assert ( - len(result["token"]) > 32 - ) # every stuff that is long enough, may be a JWT token + assert len(result["token"]) > 32 # every stuff that is long enough, may be a JWT token def test_getting_token_with_incorrect_password(as_user, get_token): @@ -51,9 +49,7 @@ def test_getting_token_with_incorrect_password(as_user, get_token): assert "nonFieldErrors" in result -def test_getting_token_with_incorrect_password_creates_access_attempt_log_entry( - as_user, get_token -): +def test_getting_token_with_incorrect_password_creates_access_attempt_log_entry(as_user, get_token): get_token(as_user.user.username, "z3r0c00l", expected_status=400) # act assert AccessAttempt.objects.count() == 1 diff --git a/{{cookiecutter.name}}/tests/apps/a12n/jwt_views/test_refresh_jwt_token.py b/{{cookiecutter.name}}/tests/apps/a12n/jwt_views/test_refresh_jwt_token.py index cd9270c9..91fe53d1 100644 --- a/{{cookiecutter.name}}/tests/apps/a12n/jwt_views/test_refresh_jwt_token.py +++ b/{{cookiecutter.name}}/tests/apps/a12n/jwt_views/test_refresh_jwt_token.py @@ -1,5 +1,4 @@ import pytest - from freezegun import freeze_time from apps.a12n.utils import get_jwt diff --git a/{{cookiecutter.name}}/tests/apps/users/fixtures.py b/{{cookiecutter.name}}/tests/apps/users/fixtures.py index b61fe541..317ebe77 100644 --- a/{{cookiecutter.name}}/tests/apps/users/fixtures.py +++ b/{{cookiecutter.name}}/tests/apps/users/fixtures.py @@ -1,6 +1,7 @@ -import pytest from typing import TYPE_CHECKING +import pytest + from apps.users.models import User if TYPE_CHECKING: diff --git a/{{cookiecutter.name}}/tests/apps/users/test_password_hashing.py b/{{cookiecutter.name}}/tests/apps/users/test_password_hashing.py index 72e96a84..0afd569a 100644 --- a/{{cookiecutter.name}}/tests/apps/users/test_password_hashing.py +++ b/{{cookiecutter.name}}/tests/apps/users/test_password_hashing.py @@ -1,6 +1,7 @@ -import pytest import uuid +import pytest + from apps.users.models import User pytestmark = [pytest.mark.django_db] diff --git a/{{cookiecutter.name}}/tests/core/factory.py b/{{cookiecutter.name}}/tests/core/factory.py index 0002e156..1c1d022b 100644 --- a/{{cookiecutter.name}}/tests/core/factory.py +++ b/{{cookiecutter.name}}/tests/core/factory.py @@ -1,6 +1,5 @@ -from faker import Faker - from django.core.files.uploadedfile import SimpleUploadedFile +from faker import Faker from core.testing import register from core.testing.types import FactoryProtocol @@ -9,9 +8,5 @@ @register -def image( - self: FactoryProtocol, name: str = "image.gif", content_type: str = "image/gif" -) -> SimpleUploadedFile: - return SimpleUploadedFile( - name=name, content=faker.image(), content_type=content_type - ) +def image(self: FactoryProtocol, name: str = "image.gif", content_type: str = "image/gif") -> SimpleUploadedFile: + return SimpleUploadedFile(name=name, content=faker.image(), content_type=content_type) diff --git a/{{cookiecutter.name}}/tests/core/fixtures.py b/{{cookiecutter.name}}/tests/core/fixtures.py index b52db1bd..859887c9 100644 --- a/{{cookiecutter.name}}/tests/core/fixtures.py +++ b/{{cookiecutter.name}}/tests/core/fixtures.py @@ -1,6 +1,7 @@ -import pytest from typing import TYPE_CHECKING +import pytest + from core.testing import ApiClient from core.testing.factory import FixtureFactory diff --git a/{{cookiecutter.name}}/tests/core/test_remote_addr_midlleware.py b/{{cookiecutter.name}}/tests/core/test_remote_addr_midlleware.py index d3b1662f..c647d05e 100644 --- a/{{cookiecutter.name}}/tests/core/test_remote_addr_midlleware.py +++ b/{{cookiecutter.name}}/tests/core/test_remote_addr_midlleware.py @@ -1,5 +1,4 @@ import pytest - from django.apps import apps from core.testing.api import ApiClient diff --git a/{{cookiecutter.name}}/tests/core/testing/factory/test_factory.py b/{{cookiecutter.name}}/tests/core/testing/factory/test_factory.py index 68e937a5..58c1206a 100644 --- a/{{cookiecutter.name}}/tests/core/testing/factory/test_factory.py +++ b/{{cookiecutter.name}}/tests/core/testing/factory/test_factory.py @@ -1,7 +1,6 @@ import pytest -from core.testing import FixtureFactory -from core.testing import register +from core.testing import FixtureFactory, register @pytest.fixture @@ -11,33 +10,25 @@ def fixture_factory() -> FixtureFactory: @pytest.fixture def registered_method(mocker): - mock = mocker.Mock( - name="registered_method", return_value="i should be returned after gettatr" - ) + mock = mocker.Mock(name="registered_method", return_value="i should be returned after gettatr") mock.__name__ = "registered_method" register(mock) return mock -def test_call_getattr_returns_what_method_returned( - fixture_factory: FixtureFactory, registered_method -): +def test_call_getattr_returns_what_method_returned(fixture_factory: FixtureFactory, registered_method): result = fixture_factory.registered_method() assert result == "i should be returned after gettatr" -def test_registered_method_called_with_factory_instance( - fixture_factory: FixtureFactory, registered_method -): +def test_registered_method_called_with_factory_instance(fixture_factory: FixtureFactory, registered_method): fixture_factory.registered_method(foo=1) # act registered_method.assert_called_with(fixture_factory, foo=1) -def test_cycle_returns_given_method_n_times( - fixture_factory: FixtureFactory, registered_method, mocker -): +def test_cycle_returns_given_method_n_times(fixture_factory: FixtureFactory, registered_method, mocker): fixture_factory.cycle(4).registered_method(bar=1) # act registered_method.assert_has_calls( diff --git a/{{cookiecutter.name}}/tests/core/testing/factory/test_registry.py b/{{cookiecutter.name}}/tests/core/testing/factory/test_registry.py index c5233905..cf43bc52 100644 --- a/{{cookiecutter.name}}/tests/core/testing/factory/test_registry.py +++ b/{{cookiecutter.name}}/tests/core/testing/factory/test_registry.py @@ -1,7 +1,6 @@ import pytest -from core.testing.factory import FixtureRegistry -from core.testing.factory import register +from core.testing.factory import FixtureRegistry, register @pytest.fixture @@ -10,9 +9,7 @@ def fixture_registry() -> FixtureRegistry: def test_registry_raises_exception_if_no_method(fixture_registry: FixtureRegistry): - with pytest.raises( - AttributeError, match=r"Factory method \“not_real\” not found\." - ): + with pytest.raises(AttributeError, match=r"Factory method \“not_real\” not found\."): fixture_registry.get("not_real") From 2b8dc43705ad52569b95db7a9d8788a62ad41511 Mon Sep 17 00:00:00 2001 From: hnthh Date: Wed, 29 Nov 2023 22:50:03 +0300 Subject: [PATCH 009/116] refactor pyproject --- {{cookiecutter.name}}/Makefile | 2 + {{cookiecutter.name}}/poetry.lock | 27 ++++++++++++- {{cookiecutter.name}}/pyproject.toml | 39 +++++++++++-------- .../core/testing/factory/test_registry.py | 4 +- 4 files changed, 52 insertions(+), 20 deletions(-) diff --git a/{{cookiecutter.name}}/Makefile b/{{cookiecutter.name}}/Makefile index 5e4c98a3..c6e053b8 100644 --- a/{{cookiecutter.name}}/Makefile +++ b/{{cookiecutter.name}}/Makefile @@ -9,12 +9,14 @@ checks: poetry run black --check src tests poetry run flake8 src tests poetry run mypy src tests + poetry run toml-sort pyproject.toml --check poetry run dotenv-linter src/core/.env.ci fmt: poetry run autoflake --in-place --remove-all-unused-imports --recursive src tests poetry run isort src tests poetry run black src tests + poetry run toml-sort pyproject.toml test: poetry run pytest --dead-fixtures diff --git a/{{cookiecutter.name}}/poetry.lock b/{{cookiecutter.name}}/poetry.lock index 788d2549..653578dc 100644 --- a/{{cookiecutter.name}}/poetry.lock +++ b/{{cookiecutter.name}}/poetry.lock @@ -2149,6 +2149,31 @@ pure-eval = "*" [package.extras] tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] +[[package]] +name = "toml-sort" +version = "0.23.1" +description = "Toml sorting library" +optional = false +python-versions = ">=3.7,<4.0" +files = [ + {file = "toml_sort-0.23.1-py3-none-any.whl", hash = "sha256:69ae60de9c4d67478533697eb4119092e2b30ddffe5ca09bbad3912905c935a0"}, + {file = "toml_sort-0.23.1.tar.gz", hash = "sha256:833728c48b0f8d509aecd9ae8347768ca3a9332977b32c9fd2002932f0eb9c90"}, +] + +[package.dependencies] +tomlkit = ">=0.11.2" + +[[package]] +name = "tomlkit" +version = "0.12.3" +description = "Style preserving TOML library" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomlkit-0.12.3-py3-none-any.whl", hash = "sha256:b0a645a9156dc7cb5d3a1f0d4bab66db287fcb8e0430bdd4664a095ea16414ba"}, + {file = "tomlkit-0.12.3.tar.gz", hash = "sha256:75baf5012d06501f07bee5bf8e801b9f343e7aac5a92581f20f80ce632e6b5a4"}, +] + [[package]] name = "traitlets" version = "5.13.0" @@ -2378,4 +2403,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = "~3.11" -content-hash = "7be9742978068475147ce2116693b14fdb3532c3d8fe9fc9a02bebdd86831097" +content-hash = "b2da918eced3e7745c78ad7f59b734cea8080503e9e7a15dba92321683777611" diff --git a/{{cookiecutter.name}}/pyproject.toml b/{{cookiecutter.name}}/pyproject.toml index e9adaf18..54cf824e 100644 --- a/{{cookiecutter.name}}/pyproject.toml +++ b/{{cookiecutter.name}}/pyproject.toml @@ -1,3 +1,7 @@ +[build-system] +build-backend = "poetry.core.masonry.api" +requires = ["poetry-core"] + [tool.poetry] authors = ["you "] description = "your project description" @@ -6,7 +10,6 @@ readme = "README.md" version = "0.0.0-dev" [tool.poetry.dependencies] -python = "~3.11" bcrypt = "^4.0.1" django = "^4.2.7" django-axes = "^6.1.1" @@ -23,6 +26,7 @@ drf-jwt = "^1.19.2" drf-spectacular = {extras = ["sidecar"], version = "^0.26.5"} pillow = "^10.1.0" psycopg2-binary = "^2.9.9" +python = "~3.11" redis = "^5.0.1" sentry-sdk = "^1.37.0" whitenoise = "^6.6.0" @@ -59,30 +63,25 @@ pytest-freezegun = "^0.4.2" pytest-mock = "^3.12.0" pytest-randomly = "^3.15.0" pytest-xdist = "^3.5.0" +toml-sort = "^0.23.1" types-freezegun = "^1.1.10" types-pillow = "^10.1.0.2" -[build-system] -requires = ["poetry-core"] -build-backend = "poetry.core.masonry.api" - [tool.black] line_length = 160 [tool.flake8] -exclude = ["migrations", "__pycache__"] +exclude = ["__pycache__", "migrations"] ignore = [ - "DJ05", # URLs include() should set a namespace - "E501", # Line too long - "E265", # Block comments should have one space before the pound sign (#) and the comment itself - "F811", # Redefinition of unused name from line n - "PT001", # Use @pytest.fixture() over @pytest.fixture - "SIM102", # Use a single if-statement instead of nested if-statements - "SIM113", # Use enumerate instead of manually incrementing a counter - "E203", # whitespace before ':', disabled for black purposes https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html#slices + "E203", # whitespace before ':' + "E265", # block comment should start with '#' + "E501", # line too long ({} > {} characters) + "F811", # redefinition of unused name from line {} + "PT001", # use @pytest.fixture() over @pytest.fixture + "SIM102", # use a single if-statement instead of nested if-statements + "SIM113", # use enumerate instead of manually incrementing a counter ] inline-quotes = "\"" -max-line-length = 160 [tool.isort] include_trailing_comma = true @@ -92,8 +91,8 @@ src_paths = ["src", "tests"] use_parentheses = true [tool.pytest.ini_options] -addopts = ["--reuse-db"] DJANGO_SETTINGS_MODULE = "core.settings" +addopts = ["--reuse-db"] env = [ "AXES_ENABLED = False", "CELERY_ALWAYS_EAGER = True", @@ -109,3 +108,11 @@ markers = [ ] python_files = ["test*.py"] pythonpath = ". src" + +[tool.tomlsort] +all = true +in_place = true +sort_first = ["tool.poetry"] +spaces_before_inline_comment = 2 +spaces_indent_inline_array = 4 +trailing_comma_inline_array = true diff --git a/{{cookiecutter.name}}/tests/core/testing/factory/test_registry.py b/{{cookiecutter.name}}/tests/core/testing/factory/test_registry.py index cf43bc52..fee78241 100644 --- a/{{cookiecutter.name}}/tests/core/testing/factory/test_registry.py +++ b/{{cookiecutter.name}}/tests/core/testing/factory/test_registry.py @@ -13,9 +13,7 @@ def test_registry_raises_exception_if_no_method(fixture_registry: FixtureRegistr fixture_registry.get("not_real") -def test_registry_returns_correct_method_after_register_decorator( - fixture_registry: FixtureRegistry, -): +def test_registry_returns_correct_method_after_register_decorator(fixture_registry: FixtureRegistry): @register def some_method_to_add(): pass From 8d26610c232c8b704dbe58ca73601553a416e9d1 Mon Sep 17 00:00:00 2001 From: hnthh Date: Thu, 30 Nov 2023 23:28:06 +0300 Subject: [PATCH 010/116] lots of --- .gitignore | 7 +- hooks/post_gen_project.sh | 7 +- {{cookiecutter.name}}/Makefile | 2 +- .../src/.django-app-template/admin.py-tpl | 6 ++ .../api/serializers/__init__.py | 3 - .../api/serializers/app_name.py-tpl | 3 - .../src/.django-app-template/api/urls.py-tpl | 12 ---- .../api/v1/__init__.py-tpl | 0 .../api/v1/serializers/__init__.py-tpl | 5 ++ .../api/v1/serializers/entity_name.py-tpl | 10 +++ .../.django-app-template/api/v1/urls.py-tpl | 11 +++ .../api/v1/views/__init__.py-tpl | 5 ++ .../api/v1/views/entity_name.py-tpl | 5 ++ .../api/views/__init__.py | 3 - .../api/views/app_name.py-tpl | 3 - .../src/.django-app-template/apps.py-tpl | 2 +- .../migrations/0001_entity_name.py-tpl | 23 ++++++ .../.django-app-template/models/__init__.py | 3 - .../models/__init__.py-tpl | 5 ++ .../models/app_name.py-tpl | 5 -- .../models/entity_name.py-tpl | 7 ++ .../tests/__init__.py-tpl | 0 .../.django-app-template/tests/factory.py-tpl | 0 .../.django-app-template/tests/fixtures.py | 0 .../src/core/admin/README.md | 15 ---- .../src/core/conf/environ.py | 1 - .../src/core/management/commands/startapp.py | 71 ++++++++++++++++--- 27 files changed, 147 insertions(+), 67 deletions(-) delete mode 100644 {{cookiecutter.name}}/src/.django-app-template/api/serializers/__init__.py delete mode 100644 {{cookiecutter.name}}/src/.django-app-template/api/serializers/app_name.py-tpl delete mode 100644 {{cookiecutter.name}}/src/.django-app-template/api/urls.py-tpl create mode 100644 {{cookiecutter.name}}/src/.django-app-template/api/v1/__init__.py-tpl create mode 100644 {{cookiecutter.name}}/src/.django-app-template/api/v1/serializers/__init__.py-tpl create mode 100644 {{cookiecutter.name}}/src/.django-app-template/api/v1/serializers/entity_name.py-tpl create mode 100644 {{cookiecutter.name}}/src/.django-app-template/api/v1/urls.py-tpl create mode 100644 {{cookiecutter.name}}/src/.django-app-template/api/v1/views/__init__.py-tpl create mode 100644 {{cookiecutter.name}}/src/.django-app-template/api/v1/views/entity_name.py-tpl delete mode 100644 {{cookiecutter.name}}/src/.django-app-template/api/views/__init__.py delete mode 100644 {{cookiecutter.name}}/src/.django-app-template/api/views/app_name.py-tpl create mode 100644 {{cookiecutter.name}}/src/.django-app-template/migrations/0001_entity_name.py-tpl delete mode 100644 {{cookiecutter.name}}/src/.django-app-template/models/__init__.py create mode 100644 {{cookiecutter.name}}/src/.django-app-template/models/__init__.py-tpl delete mode 100644 {{cookiecutter.name}}/src/.django-app-template/models/app_name.py-tpl create mode 100644 {{cookiecutter.name}}/src/.django-app-template/models/entity_name.py-tpl create mode 100644 {{cookiecutter.name}}/src/.django-app-template/tests/__init__.py-tpl create mode 100644 {{cookiecutter.name}}/src/.django-app-template/tests/factory.py-tpl create mode 100644 {{cookiecutter.name}}/src/.django-app-template/tests/fixtures.py delete mode 100644 {{cookiecutter.name}}/src/core/admin/README.md diff --git a/.gitignore b/.gitignore index 260a84b0..b6d7d336 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,13 @@ .git .idea +.venv .vscode **/*~ **/.DS_Store +**/db.sqlite + +{{cookiecutter.name}}/src/apps/testapp +{{cookiecutter.name}}/tests/apps/testapp -db.sqlite testproject -venv diff --git a/hooks/post_gen_project.sh b/hooks/post_gen_project.sh index e92de978..abb80dcf 100644 --- a/hooks/post_gen_project.sh +++ b/hooks/post_gen_project.sh @@ -1,16 +1,11 @@ #!/bin/bash -e -rm -rf .mypy_cache \ - .pytest_cache \ - .venv \ - db.sqlite - cp src/core/.env.ci src/core/.env poetry install poetry run python src/manage.py collectstatic poetry run python src/manage.py migrate -poetry run python src/manage.py startapp test_app +poetry run python src/manage.py startapp some_app --entity_name some_entity make checks test diff --git a/{{cookiecutter.name}}/Makefile b/{{cookiecutter.name}}/Makefile index c6e053b8..be6d8872 100644 --- a/{{cookiecutter.name}}/Makefile +++ b/{{cookiecutter.name}}/Makefile @@ -1,4 +1,4 @@ -manage = poetry run src/manage.py +manage = poetry run python src/manage.py numprocesses = 4 checks: diff --git a/{{cookiecutter.name}}/src/.django-app-template/admin.py-tpl b/{{cookiecutter.name}}/src/.django-app-template/admin.py-tpl index f026a054..de5aa61a 100644 --- a/{{cookiecutter.name}}/src/.django-app-template/admin.py-tpl +++ b/{{cookiecutter.name}}/src/.django-app-template/admin.py-tpl @@ -1,3 +1,9 @@ from django.contrib import admin +from apps.{{ app_name }}.models import {{ camel_case_entity_name }} from core.admin import ModelAdmin + + +@admin.register({{ camel_case_entity_name }}) +class {{ camel_case_entity_name }}Admin(ModelAdmin): + pass diff --git a/{{cookiecutter.name}}/src/.django-app-template/api/serializers/__init__.py b/{{cookiecutter.name}}/src/.django-app-template/api/serializers/__init__.py deleted file mode 100644 index 44f0b885..00000000 --- a/{{cookiecutter.name}}/src/.django-app-template/api/serializers/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -__all__ = [ - "", -] diff --git a/{{cookiecutter.name}}/src/.django-app-template/api/serializers/app_name.py-tpl b/{{cookiecutter.name}}/src/.django-app-template/api/serializers/app_name.py-tpl deleted file mode 100644 index 3cfd0eef..00000000 --- a/{{cookiecutter.name}}/src/.django-app-template/api/serializers/app_name.py-tpl +++ /dev/null @@ -1,3 +0,0 @@ -from rest_framework import serializers - -# Rename this file to singular form of your entity, e.g. "orders.py -> order.py". Add your class to __init__.py. diff --git a/{{cookiecutter.name}}/src/.django-app-template/api/urls.py-tpl b/{{cookiecutter.name}}/src/.django-app-template/api/urls.py-tpl deleted file mode 100644 index 3b47c24d..00000000 --- a/{{cookiecutter.name}}/src/.django-app-template/api/urls.py-tpl +++ /dev/null @@ -1,12 +0,0 @@ -from rest_framework.routers import SimpleRouter - -from django.urls import include -from django.urls import path - -from apps.{{ app_name }}.api import viewsets - -router = SimpleRouter() - -urlpatterns = [ - path('', include(router.urls)), -] diff --git a/{{cookiecutter.name}}/src/.django-app-template/api/v1/__init__.py-tpl b/{{cookiecutter.name}}/src/.django-app-template/api/v1/__init__.py-tpl new file mode 100644 index 00000000..e69de29b diff --git a/{{cookiecutter.name}}/src/.django-app-template/api/v1/serializers/__init__.py-tpl b/{{cookiecutter.name}}/src/.django-app-template/api/v1/serializers/__init__.py-tpl new file mode 100644 index 00000000..aeaf4f0b --- /dev/null +++ b/{{cookiecutter.name}}/src/.django-app-template/api/v1/serializers/__init__.py-tpl @@ -0,0 +1,5 @@ +from apps.{{ app_name }}.api.v1.serializers.{{ entity_name }} import {{ camel_case_entity_name }}ReadSerializer + +__all__ = [ + "{{ camel_case_entity_name }}ReadSerializer", +] diff --git a/{{cookiecutter.name}}/src/.django-app-template/api/v1/serializers/entity_name.py-tpl b/{{cookiecutter.name}}/src/.django-app-template/api/v1/serializers/entity_name.py-tpl new file mode 100644 index 00000000..a3e16471 --- /dev/null +++ b/{{cookiecutter.name}}/src/.django-app-template/api/v1/serializers/entity_name.py-tpl @@ -0,0 +1,10 @@ +from rest_framework import serializers + +from apps.{{ app_name }}.models import {{ camel_case_entity_name }} + + +class {{ camel_case_entity_name }}ReadSerializer(serializers.ModelSerializer): + class Meta: + fields = ("somefield",) + model = {{ camel_case_entity_name }} + read_only_fields = fields diff --git a/{{cookiecutter.name}}/src/.django-app-template/api/v1/urls.py-tpl b/{{cookiecutter.name}}/src/.django-app-template/api/v1/urls.py-tpl new file mode 100644 index 00000000..18bc8d4f --- /dev/null +++ b/{{cookiecutter.name}}/src/.django-app-template/api/v1/urls.py-tpl @@ -0,0 +1,11 @@ +from django.urls import include, path +from rest_framework.routers import SimpleRouter + +from apps.{{ app_name }}.api.v1 import views + +router = SimpleRouter() +router.register("{{ app_name }}", views.{{ camel_case_entity_name }}ViewSet) + +urlpatterns = [ + path("", include(router.urls)), +] diff --git a/{{cookiecutter.name}}/src/.django-app-template/api/v1/views/__init__.py-tpl b/{{cookiecutter.name}}/src/.django-app-template/api/v1/views/__init__.py-tpl new file mode 100644 index 00000000..882408d2 --- /dev/null +++ b/{{cookiecutter.name}}/src/.django-app-template/api/v1/views/__init__.py-tpl @@ -0,0 +1,5 @@ +from apps.{{ app_name }}.api.v1.views.{{ entity_name }} import {{ camel_case_entity_name }}ViewSet + +__all__ = [ + "{{ camel_case_entity_name }}ViewSet", +] diff --git a/{{cookiecutter.name}}/src/.django-app-template/api/v1/views/entity_name.py-tpl b/{{cookiecutter.name}}/src/.django-app-template/api/v1/views/entity_name.py-tpl new file mode 100644 index 00000000..0af971cc --- /dev/null +++ b/{{cookiecutter.name}}/src/.django-app-template/api/v1/views/entity_name.py-tpl @@ -0,0 +1,5 @@ +from core.api.viewsets import DefaultModelViewSet + + +class {{ camel_case_entity_name }}ViewSet(DefaultModelViewSet): + pass diff --git a/{{cookiecutter.name}}/src/.django-app-template/api/views/__init__.py b/{{cookiecutter.name}}/src/.django-app-template/api/views/__init__.py deleted file mode 100644 index 44f0b885..00000000 --- a/{{cookiecutter.name}}/src/.django-app-template/api/views/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -__all__ = [ - "", -] diff --git a/{{cookiecutter.name}}/src/.django-app-template/api/views/app_name.py-tpl b/{{cookiecutter.name}}/src/.django-app-template/api/views/app_name.py-tpl deleted file mode 100644 index 18dce71c..00000000 --- a/{{cookiecutter.name}}/src/.django-app-template/api/views/app_name.py-tpl +++ /dev/null @@ -1,3 +0,0 @@ -from core.api.viewsets import DefaultModelViewSet - -# Rename this file to singular form of your entity, e.g. "orders.py -> order.py". Add your class to __init__.py. diff --git a/{{cookiecutter.name}}/src/.django-app-template/apps.py-tpl b/{{cookiecutter.name}}/src/.django-app-template/apps.py-tpl index 8e8abc6d..427cdb03 100644 --- a/{{cookiecutter.name}}/src/.django-app-template/apps.py-tpl +++ b/{{cookiecutter.name}}/src/.django-app-template/apps.py-tpl @@ -2,4 +2,4 @@ from core.base_config import AppConfig class {{ camel_case_app_name }}Config(AppConfig): - name = "{{ app_name }}" + name = "apps.{{ app_name }}" diff --git a/{{cookiecutter.name}}/src/.django-app-template/migrations/0001_entity_name.py-tpl b/{{cookiecutter.name}}/src/.django-app-template/migrations/0001_entity_name.py-tpl new file mode 100644 index 00000000..1a4f8fc3 --- /dev/null +++ b/{{cookiecutter.name}}/src/.django-app-template/migrations/0001_entity_name.py-tpl @@ -0,0 +1,23 @@ +# Generated by Django 4.2.7 on 2023-11-30 19:50 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + initial = True + + dependencies = [] + + operations = [ + migrations.CreateModel( + name="{{ camel_case_entity_name }}", + fields=[ + ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("created", models.DateTimeField(auto_now_add=True, db_index=True)), + ("modified", models.DateTimeField(blank=True, db_index=True, null=True)), + ], + options={ + "abstract": False, + }, + ), + ] diff --git a/{{cookiecutter.name}}/src/.django-app-template/models/__init__.py b/{{cookiecutter.name}}/src/.django-app-template/models/__init__.py deleted file mode 100644 index 44f0b885..00000000 --- a/{{cookiecutter.name}}/src/.django-app-template/models/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -__all__ = [ - "", -] diff --git a/{{cookiecutter.name}}/src/.django-app-template/models/__init__.py-tpl b/{{cookiecutter.name}}/src/.django-app-template/models/__init__.py-tpl new file mode 100644 index 00000000..b97bb379 --- /dev/null +++ b/{{cookiecutter.name}}/src/.django-app-template/models/__init__.py-tpl @@ -0,0 +1,5 @@ +from apps.{{ app_name }}.models.{{ entity_name }} import {{ camel_case_entity_name }} + +__all__ = [ + "{{ camel_case_entity_name }}", +] diff --git a/{{cookiecutter.name}}/src/.django-app-template/models/app_name.py-tpl b/{{cookiecutter.name}}/src/.django-app-template/models/app_name.py-tpl deleted file mode 100644 index 8e466bdc..00000000 --- a/{{cookiecutter.name}}/src/.django-app-template/models/app_name.py-tpl +++ /dev/null @@ -1,5 +0,0 @@ -from django.db import models - -from core.models import DefaultModel, TimestampedModel - -# Rename this file to singular form of your entity, e.g. "orders.py -> order.py". Add your class to __init__.py. diff --git a/{{cookiecutter.name}}/src/.django-app-template/models/entity_name.py-tpl b/{{cookiecutter.name}}/src/.django-app-template/models/entity_name.py-tpl new file mode 100644 index 00000000..558ef681 --- /dev/null +++ b/{{cookiecutter.name}}/src/.django-app-template/models/entity_name.py-tpl @@ -0,0 +1,7 @@ +from django.db import models # noqa: F401 + +from core.models import TimestampedModel + + +class {{ camel_case_entity_name }}(TimestampedModel): + pass diff --git a/{{cookiecutter.name}}/src/.django-app-template/tests/__init__.py-tpl b/{{cookiecutter.name}}/src/.django-app-template/tests/__init__.py-tpl new file mode 100644 index 00000000..e69de29b diff --git a/{{cookiecutter.name}}/src/.django-app-template/tests/factory.py-tpl b/{{cookiecutter.name}}/src/.django-app-template/tests/factory.py-tpl new file mode 100644 index 00000000..e69de29b diff --git a/{{cookiecutter.name}}/src/.django-app-template/tests/fixtures.py b/{{cookiecutter.name}}/src/.django-app-template/tests/fixtures.py new file mode 100644 index 00000000..e69de29b diff --git a/{{cookiecutter.name}}/src/core/admin/README.md b/{{cookiecutter.name}}/src/core/admin/README.md deleted file mode 100644 index 08e1c8b9..00000000 --- a/{{cookiecutter.name}}/src/core/admin/README.md +++ /dev/null @@ -1,15 +0,0 @@ -## App-wide admin customizations - -This is a place for app-wide django-admin customizations. To make your admin interface customizable, scaffold your admin modules like this: - -```python -from apps.books.models import Book -from core.admin import ModelAdmin, admin - - -@admin.register(Book) -class BookAdmin(ModelAdmin): - fields = [ - "name", - ] -``` \ No newline at end of file diff --git a/{{cookiecutter.name}}/src/core/conf/environ.py b/{{cookiecutter.name}}/src/core/conf/environ.py index a5557bf5..d59a1587 100644 --- a/{{cookiecutter.name}}/src/core/conf/environ.py +++ b/{{cookiecutter.name}}/src/core/conf/environ.py @@ -12,7 +12,6 @@ if envpath.exists(): env.read_env(envpath) - __all__ = [ "env", ] diff --git a/{{cookiecutter.name}}/src/core/management/commands/startapp.py b/{{cookiecutter.name}}/src/core/management/commands/startapp.py index e6fc0108..f105ebd7 100644 --- a/{{cookiecutter.name}}/src/core/management/commands/startapp.py +++ b/{{cookiecutter.name}}/src/core/management/commands/startapp.py @@ -1,21 +1,74 @@ -from pathlib import Path +from typing import TYPE_CHECKING from django.conf import settings from django.core.management.commands.startapp import Command as BaseCommand +if TYPE_CHECKING: + from argparse import ArgumentParser + from typing import Any + class Command(BaseCommand): - """Set custom template for all newly generated apps""" + def add_arguments(self, parser: "ArgumentParser") -> None: + super().add_arguments(parser) + + parser.add_argument( + "--entity_name", + help="The name of some application entity given in `snake_case`; e. g., if the application name is `users`, then the entity is `user`, and so on.", + ) + + def handle(self, **options: "Any") -> None: # type: ignore[override] + app_name = options["name"] + + directory = settings.BASE_DIR.parent / "apps" / app_name # type: ignore[misc] + directory.mkdir() + directory = str(directory) - def handle(self, **options): if "template" not in options or options["template"] is None: - options["template"] = str(Path(settings.BASE_DIR).parent / ".django-app-template") + template = str(settings.BASE_DIR.parent / ".django-app-template") # type: ignore[misc] + + options.update( + camel_case_entity_name=self.make_entity_name_camelized(options["entity_name"]), + directory=directory, + template=template, + ) super().handle(**options) - testsdir = Path(settings.BASE_DIR).parent.parent / "tests" / "apps" / options["name"] - testsdir.mkdir(parents=True, exist_ok=True) + self.rename_entity_name_modules(app_name=app_name, entity_name=options["entity_name"]) + self.add_app_to_installed_apps(app_name=app_name) + self.move_created_tests_directory(app_name=app_name) + + def make_entity_name_camelized(self, entity_name: str) -> str: + return entity_name.replace("_", " ").title().replace(" ", "") + + def rename_entity_name_modules(self, app_name: str, entity_name: str) -> None: + app_dir = settings.BASE_DIR.parent / "apps" / app_name # type: ignore[misc] + + for path in app_dir.rglob("*.py"): + if "entity_name" in path.name: + new_name = path.name.replace("entity_name", entity_name) + path.rename(path.with_name(new_name)) + + def add_app_to_installed_apps(self, app_name: str) -> None: + installed_apps_path = settings.BASE_DIR / "conf" / "installed_apps.py" # type: ignore[misc] + + with installed_apps_path.open() as reader: + lines = reader.readlines() + + for lineno, line in enumerate(lines): + if line.strip().startswith("APPS ="): + lines.insert(lineno + 1, f' "apps.{app_name}",\n') + break + + with installed_apps_path.open("w") as writer: + writer.writelines(lines) + + def move_created_tests_directory(self, app_name: str) -> None: + root = settings.BASE_DIR.parent.parent # type: ignore[misc] + + src = root / "src" / "apps" / app_name / "tests" + dst = root / "tests" / "apps" / app_name - (testsdir / "__init__.py").touch() - (testsdir / "factory.py").touch() - (testsdir / "fixtures.py").touch() + dst.mkdir() + src.rename(dst) From b272a47fc258e7c3aec51d6044125e62a5750148 Mon Sep 17 00:00:00 2001 From: hnthh Date: Thu, 30 Nov 2023 23:31:32 +0300 Subject: [PATCH 011/116] fix gitignore --- .gitignore | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index b6d7d336..0f2bbb5f 100644 --- a/.gitignore +++ b/.gitignore @@ -6,8 +6,6 @@ **/*~ **/.DS_Store **/db.sqlite - -{{cookiecutter.name}}/src/apps/testapp -{{cookiecutter.name}}/tests/apps/testapp +**/some_app testproject From 2872826b9b4e6d9952361a191e465a54f0f48af0 Mon Sep 17 00:00:00 2001 From: hnthh Date: Thu, 30 Nov 2023 23:33:30 +0300 Subject: [PATCH 012/116] fix copy without render list --- cookiecutter.json | 5 ----- 1 file changed, 5 deletions(-) diff --git a/cookiecutter.json b/cookiecutter.json index 645fe819..07ddf7f8 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -2,11 +2,6 @@ "name": "testproject", "_copy_without_render": [ ".github/workflows/ci.yml", - ".mypy_cache", - ".pytest_cache", - ".venv", - "**/__pycache__", - "db.sqlite", "src/.django-app-template" ] } From f78cb87d3ca80c2826d2352a3e4077044b877430 Mon Sep 17 00:00:00 2001 From: hnthh Date: Fri, 1 Dec 2023 22:13:21 +0300 Subject: [PATCH 013/116] parent project ci --- .circleci/config.yml | 78 ---------------------------------------- .github/workflows/ci.yml | 41 ++++++++++++++------- 2 files changed, 29 insertions(+), 90 deletions(-) delete mode 100644 .circleci/config.yml diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index beef2d54..00000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,78 +0,0 @@ -version: 2.1 -orbs: - docker: circleci/docker@2.4.0 - -jobs: - build: - docker: - - image: cimg/python:3.11 - - steps: - - checkout - - run: - command: sudo apt-get update && sudo apt-get --no-install-recommends install -y locales-all gettext - - - run: - name: Install cookiecutter - command: | - python3 -m venv venv - . venv/bin/activate - - pip install cookiecutter - - - run: - name: Bootstrap the project - command: | - . venv/bin/activate - make test - - - persist_to_workspace: - root: . - paths: - - "venv" - - "testproject" - - coverage: - docker: - - image: cimg/python:3.11 - steps: - - checkout - - attach_workspace: - at: . - - run: - name: Install Codeclimate helper - command: | - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter - chmod +x ./cc-test-reporter - - run: - name: Run tests - command: | - . venv/bin/activate - ./cc-test-reporter before-build - make coverage - - - run: - name: Upload coverage to codeclimate - command: | - cd testproject/django/src && ../../../cc-test-reporter after-build -t coverage.py - -workflows: - version: 2 - ci: - jobs: - - build - - coverage: - name: Measure test coverage - requires: - - build - - - docker/publish: - name: Make sure docker image is buildable - requires: - - build - image: f213/django - path: testproject/django - docker-context: testproject/django - extra_build_args: '--build-arg PYTHON_VERSION=3.11' - deploy: false - attach-at: . diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cc285aca..8b580723 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,5 +1,5 @@ ---- name: CI + on: push jobs: @@ -7,18 +7,35 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - name: checkout + uses: actions/checkout@v3 + + - name: load cached poetry installation + id: cached-poetry + uses: actions/cache@v3 + with: + path: ~/.local + key: poetry-v1-${{ hashFiles("pyproject.toml") }} + + - name: install poetry + if: steps.cached-poetry.outputs.cache-hit != "true" + uses: snok/install-poetry@v1 + with: + version: 1.6.1 - - name: Install gettext for correct manage.py compilemessages - run: sudo apt-get update && sudo apt-get --no-install-recommends install -y locales-all gettext + - name: install python + id: setup-python + uses: actions/setup-python@v4 + with: + cache: "poetry" + python-version-file: "pyproject.toml" - - uses: actions/setup-python@v4 - with: - python-version: '3.10' - cache: 'pip' + - name: make sure poetry lockfile is up to date + run: poetry check --lock - - name: Install cookiecutter - run: pip install cookiecutter + - name: install deps + if: steps.setup-python.outputs.cache-hit != "true" + run: poetry install --no-interaction --no-root - - name: Bootstrap the project - run: make test + - name: bootstrap + run: make bootstrap From f4e0b5fd6cffbaeb0f34f5e333ffdfae579d67a5 Mon Sep 17 00:00:00 2001 From: hnthh Date: Sun, 3 Dec 2023 22:26:56 +0300 Subject: [PATCH 014/116] run circleci --- .circleci/config.yml | 46 ++++++++++++++++++++++ .github/workflows/ci.yml | 41 ------------------- Makefile | 3 ++ {{cookiecutter.name}}/Dockerfile | 67 +++++++++++++++++--------------- 4 files changed, 85 insertions(+), 72 deletions(-) create mode 100644 .circleci/config.yml delete mode 100644 .github/workflows/ci.yml diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 00000000..c9648ef9 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,46 @@ +version: 2.1 + +orbs: + docker: circleci/docker@2.4.0 + +jobs: + build: + docker: + - image: cimg/python:3.11 + + steps: + - checkout + + - run: + name: install poetry + command: pip install poetry==1.6.1 + + - run: + name: install deps + command: poetry install + + - run: + name: bootstrap + command: make bootstrap + + - persist_to_workspace: + paths: + - ".venv" + - "testproject" + root: . + +workflows: + version: 2 + ci: + jobs: + - build + + - docker/publish: + attach-at: . + deploy: false + docker-context: testproject/django + extra_build_args: "--build-arg POETRY_VERSION=1.6.1 --build-arg PYTHON_VERSION=3.11" + image: f213/django + name: make sure docker image is buildable + path: testproject + requires: build diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 8b580723..00000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: CI - -on: push - -jobs: - build: - runs-on: ubuntu-latest - - steps: - - name: checkout - uses: actions/checkout@v3 - - - name: load cached poetry installation - id: cached-poetry - uses: actions/cache@v3 - with: - path: ~/.local - key: poetry-v1-${{ hashFiles("pyproject.toml") }} - - - name: install poetry - if: steps.cached-poetry.outputs.cache-hit != "true" - uses: snok/install-poetry@v1 - with: - version: 1.6.1 - - - name: install python - id: setup-python - uses: actions/setup-python@v4 - with: - cache: "poetry" - python-version-file: "pyproject.toml" - - - name: make sure poetry lockfile is up to date - run: poetry check --lock - - - name: install deps - if: steps.setup-python.outputs.cache-hit != "true" - run: poetry install --no-interaction --no-root - - - name: bootstrap - run: make bootstrap diff --git a/Makefile b/Makefile index 972496ee..4fe66477 100644 --- a/Makefile +++ b/Makefile @@ -2,3 +2,6 @@ bootstrap: rm -Rf testproject poetry run cookiecutter --no-input ./ + +build: + docker build --build-arg POETRY_VERSION=1.6.1 --build-arg PYTHON_VERSION=3.11 --tag f213/django testproject diff --git a/{{cookiecutter.name}}/Dockerfile b/{{cookiecutter.name}}/Dockerfile index 6c3eb8c1..aff9d30b 100644 --- a/{{cookiecutter.name}}/Dockerfile +++ b/{{cookiecutter.name}}/Dockerfile @@ -1,46 +1,51 @@ ARG PYTHON_VERSION -FROM python:${PYTHON_VERSION}-slim-bookworm -LABEL maintainer="fedor@borshev.com" -LABEL com.datadoghq.ad.logs='[{"source": "uwsgi", "service": "django"}]' +FROM python:${PYTHON_VERSION}-slim-bookworm as uwsgi-compile -ENV PYTHONUNBUFFERED 1 -ENV DEBIAN_FRONTEND noninteractive +ENV _UWSGI_VERSION 2.0.22 + +RUN apt-get update && apt-get --no-install-recommends install -y build-essential wget && rm -rf /var/lib/apt/lists/* +RUN wget -O uwsgi-${_UWSGI_VERSION}.tar.gz https://github.com/unbit/uwsgi/archive/${_UWSGI_VERSION}.tar.gz \ + && tar zxvf uwsgi-*.tar.gz \ + && UWSGI_BIN_NAME=/uwsgi make -C uwsgi-${_UWSGI_VERSION} \ + && rm -Rf uwsgi-* -ENV STATIC_ROOT /static +FROM python:${PYTHON_VERSION}-slim-bookworm as deps-compile -ENV _UWSGI_VERSION 2.0.23 +WORKDIR / +COPY poetry.lock pyproject.toml / -RUN echo deb http://deb.debian.org/debian bookworm contrib non-free > /etc/apt/sources.list.d/debian-contrib.list \ - && apt update \ - && apt --no-install-recommends install -y gettext locales-all wget \ - imagemagick tzdata wait-for-it build-essential \ - libxml2-dev libxslt1-dev libjpeg62-turbo-dev libjpeg-dev libfreetype6-dev \ - libtiff5-dev liblcms2-dev libwebp-dev tk8.6-dev \ - libffi-dev libcgraph6 libgraphviz-dev libmagic-dev libpq-dev \ - default-mysql-client default-libmysqlclient-dev \ - && rm -rf /var/lib/apt/lists/* +ARG POETRY_VERSION -RUN wget -O uwsgi-${_UWSGI_VERSION}.tar.gz https://github.com/unbit/uwsgi/archive/${_UWSGI_VERSION}.tar.gz \ - && tar zxvf uwsgi-*.tar.gz \ - && UWSGI_BIN_NAME=/usr/local/bin/uwsgi make -C uwsgi-${_UWSGI_VERSION} \ - && rm -Rf uwsgi-* +RUN pip install --no-cache-dir poetry==${POETRY_VERSION} +RUN poetry export --format=requirements.txt > requirements.txt + +FROM python:${PYTHON_VERSION}-slim-bookworm as base +LABEL maintainer="fedor@borshev.com" +LABEL com.datadoghq.ad.logs='[{"service": "django", "source": "uwsgi"}]' + +ENV DEBIAN_FRONTEND noninteractive +ENV PYTHONUNBUFFERED 1 +ENV STATIC_ROOT /var/lib/django-static +ENV _WAITFOR_VERSION 2.2.3 -RUN pip install --upgrade pip +RUN apt-get update \ + && apt-get --no-install-recommends install -y gettext locales-all tzdata git wait-for-it wget \ + && rm -rf /var/lib/apt/lists/* + +COPY --from=uwsgi-compile /uwsgi /usr/local/bin/ +RUN pip install --no-cache-dir --upgrade pip -ADD requirements.txt / -RUN pip install --no-cache-dir -r /requirements.txt +COPY --from=deps-compile /requirements.txt / +RUN pip install --no-cache-dir -r requirements.txt WORKDIR /src -ADD src /src +COPY src /src +ENV NO_CACHE=on RUN ./manage.py compilemessages RUN ./manage.py collectstatic --noinput +ENV NO_CACHE=off -ARG RELEASE=dev-untagged -ENV SENTRY_RELEASE ${RELEASE} -ENV DD_VERSION ${RELEASE} - -USER nobody - -CMD uwsgi --master --http :8000 --module core.wsgi --workers 2 --threads 2 --harakiri 25 --max-requests 1000 --log-x-forwarded-for --buffer-size 32000 +FROM base as web +CMD ./manage.py migrate && uwsgi --master --http :8000 --module core.wsgi --workers 2 --threads 2 --harakiri 25 --max-requests 1000 --log-x-forwarded-for From 208c0c872e3228f3e900321c512bc1ed3a706d9e Mon Sep 17 00:00:00 2001 From: hnthh Date: Sun, 3 Dec 2023 22:29:37 +0300 Subject: [PATCH 015/116] fix indentation --- .circleci/config.yml | 68 ++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index c9648ef9..4fe5824d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,46 +1,46 @@ version: 2.1 orbs: - docker: circleci/docker@2.4.0 + docker: circleci/docker@2.4.0 jobs: - build: - docker: - - image: cimg/python:3.11 + build: + docker: + - image: cimg/python:3.11 - steps: - - checkout + steps: + - checkout - - run: - name: install poetry - command: pip install poetry==1.6.1 + - run: + name: install poetry + command: pip install poetry==1.6.1 - - run: - name: install deps - command: poetry install + - run: + name: install deps + command: poetry install - - run: - name: bootstrap - command: make bootstrap + - run: + name: bootstrap + command: make bootstrap - - persist_to_workspace: - paths: - - ".venv" - - "testproject" - root: . + - persist_to_workspace: + paths: + - ".venv" + - "testproject" + root: . workflows: - version: 2 - ci: - jobs: - - build - - - docker/publish: - attach-at: . - deploy: false - docker-context: testproject/django - extra_build_args: "--build-arg POETRY_VERSION=1.6.1 --build-arg PYTHON_VERSION=3.11" - image: f213/django - name: make sure docker image is buildable - path: testproject - requires: build + version: 2 + ci: + jobs: + - build + + - docker/publish: + attach-at: . + deploy: false + docker-context: testproject/django + extra_build_args: "--build-arg POETRY_VERSION=1.6.1 --build-arg PYTHON_VERSION=3.11" + image: f213/django + name: make sure docker image is buildable + path: testproject + requires: build From b91afffe877c73d3485e2300d0bbbd216bb7f14d Mon Sep 17 00:00:00 2001 From: hnthh Date: Sun, 3 Dec 2023 22:31:23 +0300 Subject: [PATCH 016/116] ya ci fix --- .circleci/config.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 4fe5824d..69614283 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -36,10 +36,13 @@ workflows: - build - docker/publish: + context: docker attach-at: . deploy: false docker-context: testproject/django - extra_build_args: "--build-arg POETRY_VERSION=1.6.1 --build-arg PYTHON_VERSION=3.11" + extra_build_args: + - "--build-arg POETRY_VERSION=1.6.1" + - "--build-arg PYTHON_VERSION=3.11" image: f213/django name: make sure docker image is buildable path: testproject From c0cb074ebf8dd377906e1bad4e65a78f5cad0353 Mon Sep 17 00:00:00 2001 From: hnthh Date: Sun, 3 Dec 2023 22:37:09 +0300 Subject: [PATCH 017/116] ya ci fix --- .circleci/config.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 69614283..ea40d2d7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -36,8 +36,8 @@ workflows: - build - docker/publish: - context: docker attach-at: . + context: docker deploy: false docker-context: testproject/django extra_build_args: @@ -46,4 +46,5 @@ workflows: image: f213/django name: make sure docker image is buildable path: testproject - requires: build + requires: + - build From 8f6815358c8595af61ffad4547a7647e53f1a361 Mon Sep 17 00:00:00 2001 From: hnthh Date: Sun, 3 Dec 2023 22:38:04 +0300 Subject: [PATCH 018/116] ya ci fix --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index ea40d2d7..5f8131fe 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -37,7 +37,7 @@ workflows: - docker/publish: attach-at: . - context: docker + context: docker deploy: false docker-context: testproject/django extra_build_args: From 108bc9a17a3b726596aae70f1ca2e59d605cc24e Mon Sep 17 00:00:00 2001 From: hnthh Date: Sun, 3 Dec 2023 22:39:00 +0300 Subject: [PATCH 019/116] ya ci fix --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 5f8131fe..05879968 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -47,4 +47,4 @@ workflows: name: make sure docker image is buildable path: testproject requires: - - build + - build From 4d4b65b75ec45bf2616738c41ca1b875d5953a9d Mon Sep 17 00:00:00 2001 From: hnthh Date: Sun, 3 Dec 2023 22:39:59 +0300 Subject: [PATCH 020/116] ya ci fix --- .circleci/config.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 05879968..9bc9ebc3 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -40,9 +40,7 @@ workflows: context: docker deploy: false docker-context: testproject/django - extra_build_args: - - "--build-arg POETRY_VERSION=1.6.1" - - "--build-arg PYTHON_VERSION=3.11" + extra_build_args: "--build-arg POETRY_VERSION=1.6.1 --build-arg PYTHON_VERSION=3.11" image: f213/django name: make sure docker image is buildable path: testproject From 5115443d7d6c52c1887edd83c25102ea33b6dfbc Mon Sep 17 00:00:00 2001 From: hnthh Date: Sun, 3 Dec 2023 22:46:40 +0300 Subject: [PATCH 021/116] ya ci fix --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 9bc9ebc3..0268103d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -39,7 +39,7 @@ workflows: attach-at: . context: docker deploy: false - docker-context: testproject/django + docker-context: testproject extra_build_args: "--build-arg POETRY_VERSION=1.6.1 --build-arg PYTHON_VERSION=3.11" image: f213/django name: make sure docker image is buildable From 7823e99687c310ced1c978153ea3e129d633dd1f Mon Sep 17 00:00:00 2001 From: hnthh Date: Sun, 3 Dec 2023 22:56:44 +0300 Subject: [PATCH 022/116] fix dockerfile --- {{cookiecutter.name}}/Dockerfile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/{{cookiecutter.name}}/Dockerfile b/{{cookiecutter.name}}/Dockerfile index aff9d30b..7dc40c8e 100644 --- a/{{cookiecutter.name}}/Dockerfile +++ b/{{cookiecutter.name}}/Dockerfile @@ -42,10 +42,9 @@ RUN pip install --no-cache-dir -r requirements.txt WORKDIR /src COPY src /src -ENV NO_CACHE=on +RUN ./manage.py makemessages --locale ru RUN ./manage.py compilemessages RUN ./manage.py collectstatic --noinput -ENV NO_CACHE=off FROM base as web CMD ./manage.py migrate && uwsgi --master --http :8000 --module core.wsgi --workers 2 --threads 2 --harakiri 25 --max-requests 1000 --log-x-forwarded-for From 5a485b524cba81b41f839871a131a6eeb8527535 Mon Sep 17 00:00:00 2001 From: hnthh Date: Sun, 3 Dec 2023 23:15:46 +0300 Subject: [PATCH 023/116] rewrite child project ci --- .../.github/workflows/ci.yml | 84 +++++++++---------- 1 file changed, 38 insertions(+), 46 deletions(-) diff --git a/{{cookiecutter.name}}/.github/workflows/ci.yml b/{{cookiecutter.name}}/.github/workflows/ci.yml index 2e5c3e69..6f457aeb 100644 --- a/{{cookiecutter.name}}/.github/workflows/ci.yml +++ b/{{cookiecutter.name}}/.github/workflows/ci.yml @@ -1,45 +1,37 @@ ---- name: CI -on: push + +on: + push: + branches: + - master + pull_request: jobs: - build: + checks: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - name: checkout + uses: actions/checkout@v3 - - uses: actions/setup-python@v4 - id: setup-python - with: - python-version-file: '.python-version' + - name: build + uses: ./.github/actions/build - - uses: actions/cache@v3 - id: cache-dependencies + - name: restore mypy cache + uses: actions/cache@v3 with: - path: | - venv - key: ${{ runner.os }}-venv-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('**/*requirements.txt') }} + path: .mypy_cache + key: mypy-cache-${{ github.ref_name }} + restore-keys: mypy-cache-master - - name: Install dependencies - if: steps.cache-dependencies.outputs.cache-hit != 'true' - run: | - python -m venv venv - . venv/bin/activate - pip install --upgrade pip pip-tools - pip-sync requirements.txt dev-requirements.txt - - - name: Run the linter - run: | - . venv/bin/activate - cp src/core/.env.ci src/core/.env - make lint + - name: checks + run: make checks test: - needs: build - runs-on: ubuntu-latest + needs: checks + runs-on: ${{ contains(github.triggering_actor, "[bot]") && "ubuntu-latest" || "ubuntu-8x" }} services: postgres: - image: postgres:13.3-alpine + image: postgres:13.9-alpine env: POSTGRES_PASSWORD: secret options: >- @@ -49,29 +41,29 @@ jobs: --health-retries 5 ports: - 5432:5432 + redis: + image: redis:6.2.10-alpine + ports: + - 6379:6379 steps: - - uses: actions/checkout@v3 + - name: checkout + uses: actions/checkout@v3 - - uses: actions/setup-python@v4 - id: setup-python - with: - python-version-file: '.python-version' + - name: build + uses: ./.github/actions/build - - uses: actions/cache@v3 + - name: install locale stuff + uses: awalsh128/cache-apt-pkgs-action@v1 with: - path: | - venv - key: ${{ runner.os }}-venv-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('**/*requirements.txt') }} + packages: locales-all gettext + version: 1 - - name: Install locale stuff - run: sudo apt-get update && sudo apt-get --no-install-recommends install -y locales-all gettext + - name: get number of cpu cores + uses: SimenB/github-actions-cpu-cores@v2.0.0 + id: cpu-cores - - name: Run the tests + - name: test env: DATABASE_URL: postgres://postgres:secret@localhost:5432/postgres - - run: | - . venv/bin/activate - cp src/core/.env.ci src/core/.env - make test + run: make test -e numprocesses=${{ steps.cpu-cores.outputs.count }} From 1ec28209094b503ff1e3a6d237d26940c14b01f4 Mon Sep 17 00:00:00 2001 From: hnthh Date: Sun, 3 Dec 2023 23:51:49 +0300 Subject: [PATCH 024/116] add pymarkdownlnt, fix child proj readme --- {{cookiecutter.name}}/Makefile | 3 +- {{cookiecutter.name}}/README.md | 45 ++++++++---------- {{cookiecutter.name}}/poetry.lock | 71 +++++++++++++++++++++++++++- {{cookiecutter.name}}/pyproject.toml | 7 +++ 4 files changed, 100 insertions(+), 26 deletions(-) diff --git a/{{cookiecutter.name}}/Makefile b/{{cookiecutter.name}}/Makefile index be6d8872..89e85490 100644 --- a/{{cookiecutter.name}}/Makefile +++ b/{{cookiecutter.name}}/Makefile @@ -10,6 +10,7 @@ checks: poetry run flake8 src tests poetry run mypy src tests poetry run toml-sort pyproject.toml --check + poetry run pymarkdown scan README.md poetry run dotenv-linter src/core/.env.ci fmt: @@ -22,4 +23,4 @@ test: poetry run pytest --dead-fixtures poetry run pytest --create-db --exitfirst --numprocesses ${numprocesses} -pr: fmt checks test +mr: fmt checks test diff --git a/{{cookiecutter.name}}/README.md b/{{cookiecutter.name}}/README.md index 4a0074b7..d0904351 100644 --- a/{{cookiecutter.name}}/README.md +++ b/{{cookiecutter.name}}/README.md @@ -4,58 +4,55 @@ This project is bootstrapped using [fandsdev/django](http://github.com/fandsdev/ ## Project structure -The main django app is called `app`. It contains `.env` file for django-environ. For examples see `src/core/.env.ci`. Here are some usefull app-wide tools: -* `app.admin` — app-wide django-admin customizations (empty yet), check out usage [examples](https://github.com/f213/django/tree/master/%7B%7Bcookiecutter.project_slug%7D%7D/src/app/admin) -* `core.test.api_client` (available as `api` and `anon` fixtures within pytest) — a [convinient DRF test client](https://github.com/f213/django/blob/master/%7B%7Bcookiecutter.project_slug%7D%7D/src/users/tests/tests_whoami.py#L6-L16). +The main django app is called `core`. It contains `.env` file for django-environ. For examples see `src/core/.env.ci`. Here are some usefull app-wide tools: + +* `core.admin` — app-wide django-admin customizations (empty yet), check out usage [examples](https://github.com/f213/django/tree/master/%7B%7Bcookiecutter.project_slug%7D%7D/src/core/admin) +* `core.test.api_client` (available as `api` and `anon` fixtures within pytest) — a [convinient DRF test client](https://github.com/f213/django/blob/master/%7B%7Bcookiecutter.project_slug%7D%7D/src/tests/apps/users/tests_whoami.py#L6-L16). Django user model is located in the separate `users` app. Also, feel free to add as much django apps as you want. ## Installing on a local machine -This project requires python 3.10. Deps are managed by [pip-tools](https://github.com/jazzband/pip-tools) + +This project requires python 3.11. Deps are managed by [poetry](https://python-poetry.org). Install requirements: ```bash -$ pip install --upgrade pip pip-tools -$ make +poetry install ``` Run the server: ```bash -$ cd src && cp core/.env.ci core/.env # default environment variables -$ ./manage.py migrate -$ ./manage.py createsuperuser -$ ./manage.py runserver -``` +cp src/core/.env.ci src/core/.env -Testing: -```bash -# run lint -$ make lint - -# run unit tests -$ make test +poetry run python src/manage.py migrate +poetry run python src/manage.py createsuperuser +poetry run python src/manage.py runserver ``` -Development servers: +Useful commands ```bash -# run django dev server -$ ./manage.py runserver +make checks # run code quality checks + +make fmt # run code formatters + +make test # run tests +make mr # run all of above one-by-one ``` -## Backend Code requirements +## Backend code requirements ### Style * Obey [django's style guide](https://docs.djangoproject.com/en/dev/internals/contributing/writing-code/coding-style/#model-style). -* Configure your IDE to use [flake8](https://pypi.python.org/pypi/flake8) for checking your python code. To run our linters manualy, do `make lint` +* Configure your IDE to use [flake8](https://pypi.python.org/pypi/flake8) for checking your python code. To run our linters manualy, do `make lint`. * Prefer English over your native language in comments and commit messages. -* Commit messages should contain the unique id of issue they are linked to (refs #100500) +* Commit messages should contain the unique id of issue they are linked to (refs #100500). * Every model, service and model method should have a docstring. ### Code organisation diff --git a/{{cookiecutter.name}}/poetry.lock b/{{cookiecutter.name}}/poetry.lock index 653578dc..51b91988 100644 --- a/{{cookiecutter.name}}/poetry.lock +++ b/{{cookiecutter.name}}/poetry.lock @@ -1,5 +1,21 @@ # This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. +[[package]] +name = "application-properties" +version = "0.8.1" +description = "A simple, easy to use, unified manner of accessing program properties." +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "application_properties-0.8.1-py3-none-any.whl", hash = "sha256:f442e403ab7c8f97b048cf0ab92845057d595989653f65ced48579ad7cf35607"}, + {file = "application_properties-0.8.1.tar.gz", hash = "sha256:101667125383940651e72a2a9b3aa32225f359050c3be45b4ef4b51009930bb4"}, +] + +[package.dependencies] +pyyaml = ">=6.0" +tomli = ">=2.0.1" +typing-extensions = ">=4.5.0" + [[package]] name = "asgiref" version = "3.7.2" @@ -393,6 +409,21 @@ files = [ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +[[package]] +name = "columnar" +version = "1.4.1" +description = "A tool for printing data in a columnar format." +optional = false +python-versions = "*" +files = [ + {file = "Columnar-1.4.1-py3-none-any.whl", hash = "sha256:8efb692a7e6ca07dcc8f4ea889960421331a5dffa8e5af81f0a67ad8ea1fc798"}, + {file = "Columnar-1.4.1.tar.gz", hash = "sha256:c3cb57273333b2ff9cfaafc86f09307419330c97faa88dcfe23df05e6fbb9c72"}, +] + +[package.dependencies] +toolz = "*" +wcwidth = "*" + [[package]] name = "cryptography" version = "41.0.5" @@ -1657,6 +1688,22 @@ dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pyte docs = ["sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"] tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] +[[package]] +name = "pymarkdownlnt" +version = "0.9.14" +description = "A GitHub Flavored Markdown compliant Markdown linter." +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "pymarkdownlnt-0.9.14-py3-none-any.whl", hash = "sha256:7db466fe9170b8144a4101362171d111233dbd5c7710f896c525456e27559efb"}, + {file = "pymarkdownlnt-0.9.14.tar.gz", hash = "sha256:3f75977a812a14b305773167a8774b6930ff30528cd7f75da8c4e865c19a504f"}, +] + +[package.dependencies] +application-properties = ">=0.8.1" +columnar = ">=1.4.0" +typing-extensions = ">=4.7.0" + [[package]] name = "pytest" version = "7.4.3" @@ -2163,6 +2210,17 @@ files = [ [package.dependencies] tomlkit = ">=0.11.2" +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] + [[package]] name = "tomlkit" version = "0.12.3" @@ -2174,6 +2232,17 @@ files = [ {file = "tomlkit-0.12.3.tar.gz", hash = "sha256:75baf5012d06501f07bee5bf8e801b9f343e7aac5a92581f20f80ce632e6b5a4"}, ] +[[package]] +name = "toolz" +version = "0.12.0" +description = "List processing tools and functional utilities" +optional = false +python-versions = ">=3.5" +files = [ + {file = "toolz-0.12.0-py3-none-any.whl", hash = "sha256:2059bd4148deb1884bb0eb770a3cde70e7f954cfbbdc2285f1f2de01fd21eb6f"}, + {file = "toolz-0.12.0.tar.gz", hash = "sha256:88c570861c440ee3f2f6037c4654613228ff40c93a6c25e0eba70d17282c6194"}, +] + [[package]] name = "traitlets" version = "5.13.0" @@ -2403,4 +2472,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = "~3.11" -content-hash = "b2da918eced3e7745c78ad7f59b734cea8080503e9e7a15dba92321683777611" +content-hash = "528770c50e5a22550d6d4808bfdd8ec2f7df869927f845cf8d805b1a0375fbfc" diff --git a/{{cookiecutter.name}}/pyproject.toml b/{{cookiecutter.name}}/pyproject.toml index 54cf824e..a50d61fe 100644 --- a/{{cookiecutter.name}}/pyproject.toml +++ b/{{cookiecutter.name}}/pyproject.toml @@ -56,6 +56,7 @@ isort = "^5.12.0" jedi = "^0.19.1" mixer = {extras = ["django"], version = "^7.2.2"} mypy = "^1.7.1" +pymarkdownlnt = "^0.9.14" pytest-deadfixtures = "^2.2.1" pytest-django = "^4.7.0" pytest-env = "^1.1.1" @@ -90,6 +91,12 @@ multi_line_output = 3 src_paths = ["src", "tests"] use_parentheses = true +[tool.pymarkdown.plugins.md013] +enabled = false + +[tool.pymarkdown.plugins.md045] +enabled = false + [tool.pytest.ini_options] DJANGO_SETTINGS_MODULE = "core.settings" addopts = ["--reuse-db"] From 6c85aaa946619143ff667c6c9ef967d2d4b7a0a3 Mon Sep 17 00:00:00 2001 From: hnthh Date: Mon, 4 Dec 2023 00:09:45 +0300 Subject: [PATCH 025/116] add pymarkdownlnt to parent proj, fix parent readme --- Makefile | 7 +++ README.md | 44 +++++++++-------- cookiecutter.json | 1 + poetry.lock | 118 +++++++++++++++++++++++++++++++++++++++++++++- pyproject.toml | 27 +++++++++-- 5 files changed, 170 insertions(+), 27 deletions(-) diff --git a/Makefile b/Makefile index 4fe66477..fc923d15 100644 --- a/Makefile +++ b/Makefile @@ -5,3 +5,10 @@ bootstrap: build: docker build --build-arg POETRY_VERSION=1.6.1 --build-arg PYTHON_VERSION=3.11 --tag f213/django testproject + +checks: + poetry run toml-sort pyproject.toml --check + poetry run pymarkdown scan README.md + +fmt: + poetry run toml-sort pyproject.toml diff --git a/README.md b/README.md index 6f2bc5ae..cc94d12d 100644 --- a/README.md +++ b/README.md @@ -1,46 +1,44 @@ # My personal (very) opinionated django template -[![CircleCI](https://circleci.com/gh/fandsdev/django.svg?style=svg&circle-token=8ce8cbe93d81d60af6b67c82a82563d93da0cb03)](https://circleci.com/gh/f213/django) ![Shields.io](https://img.shields.io/github/last-commit/fandsdev/django?style=flat-square) [![Maintainability](https://api.codeclimate.com/v1/badges/2b9800b10414a4ad2622/maintainability)](https://codeclimate.com/github/f213/django/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/2b9800b10414a4ad2622/test_coverage)](https://codeclimate.com/github/f213/django/test_coverage) [![Support me on Patreon](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fshieldsio-patreon.vercel.app%2Fapi%3Fusername%3Df213%26type%3Dpatrons&style=flat)](https://patreon.com/f213) - -![Easy peasy](https://user-images.githubusercontent.com/1592663/79918184-93bca100-8434-11ea-9902-0ff726a864a3.gif) +[![CircleCI](https://circleci.com/gh/fandsdev/django.svg?style=svg&circle-token=8ce8cbe93d81d60af6b67c82a82563d93da0cb03)](https://circleci.com/gh/f213/django) ![Shields.io](https://img.shields.io/github/last-commit/fandsdev/django?style=flat-square) [![Support me on Patreon](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fshieldsio-patreon.vercel.app%2Fapi%3Fusername%3Df213%26type%3Dpatrons&style=flat)](https://patreon.com/f213) +![Easy peasy](https://user-images.githubusercontent.com/1592663/79918184-93bca100-8434-11ea-9902-0ff726a864a3. ## What is in the box -* API-only django (checkout [this post](https://t.me/pmdaily/257) in Russian) based on Django REST Framework with JWT support -* [pip-tools](https://github.com/jazzband/pip-tools) with separate development-time dependencies -* Strict type checking with mypy, [django-stubs](https://github.com/typeddjango/django-stubs) and [djangorestframework-stubs](https://github.com/typeddjango/djangorestframework-stubs) -* flake8 with ton of plugins (contact me if you know more) -* [black](https://github.com/psf/black) as uncompromising code formatter -* Starter CI configuration on GitHub Actions -* pytest with useful stuff like freezegun, pytest-mock and super convinient [DRF test client](https://github.com/f213/django/blob/master/%7B%7Bcookiecutter.project_slug%7D%7D/src/app/tests/tests_health.py#L9) -* Custom [user model](https://docs.djangoproject.com/en/3.0/topics/auth/customizing/#specifying-a-custom-user-model) -* [drf-spectacular](https://github.com/tfranzel/drf-spectacular) for API Schema generation -* [django-axes](https://github.com/jazzband/django-axes) for additional security -* [Whitenoise](http://whitenoise.evans.io) for effortless static files hosting -* cloudflare-ready with [django-ipware](https://github.com/un33k/django-ipware) +* API-only django (checkout [this post](https://t.me/pmdaily/257) in Russian) based on Django REST Framework with JWT support. +* [poetry](https://python-poetry.org) with separate development-time dependencies. +* Strict type checking with mypy, [django-stubs](https://github.com/typeddjango/django-stubs) and [djangorestframework-stubs](https://github.com/typeddjango/djangorestframework-stubs). +* tons of linters and formatters (contact me if something interesting not included, see `Makefile` `check`, `fmt` commands). +* Starter CI configuration on GitHub Actions. +* `pytest` with useful stuff like `freezegun`, `pytest-mock` and super convinient [DRF test client](https://github.com/f213/django/blob/master/%7B%7Bcookiecutter.project_slug%7D%7D/src/tests/core/tests_health.py#L9) +* Custom [user model](https://docs.djangoproject.com/en/3.0/topics/auth/customizing/#specifying-a-custom-user-model). +* [drf-spectacular](https://github.com/tfranzel/drf-spectacular) for API Schema generation. +* [django-axes](https://github.com/jazzband/django-axes) for additional security. +* [Whitenoise](http://whitenoise.evans.io) for effortless static files hosting. +* cloudflare-ready with [django-ipware](https://github.com/un33k/django-ipware). * Sentry. Set `SENTRY_DSN` env var if you need it. -* Postgres ready. Set `DATABASE_URL` env var to something like `DATABASE_URL=postgres://postgres@localhost:5432/postgres` - +* Postgres ready. Set `DATABASE_URL` env var to something like `DATABASE_URL=postgres://postgres@localhost:5432/postgres`. ## Optional next steps + You definetely should consider this steps after installation: -* Install [pytest-xdist](https://github.com/pytest-dev/pytest-xdist) if you plan to grow beyond 500 unittests -* If you are into docker, check out this [docker-compose.yml](https://github.com/f213/django/blob/master/%7B%7Bcookiecutter.project_slug%7D%7D/docker-compose.yml) to run on your machine +* If you are into docker, check out this [docker-compose.yml](https://github.com/f213/django/blob/master/%7B%7Bcookiecutter.project_slug%7D%7D/docker-compose.yml) to run on your machine. ## Installation -``` -$ pip install --upgrade cookiecutter -$ cookiecutter gh:fandsdev/django +```bash +poetry install + +poetry run cookiecutter gh:fandsdev/django ``` ## FAQ ### I have got an error «'random_ascii_string' is undefined» -You should upgrade cookiecutter to the latest version: `pip install --upgrade cookiecutter` +You should upgrade cookiecutter to the latest version: `pip install --upgrade cookiecutter`. ### I wanna hack this! diff --git a/cookiecutter.json b/cookiecutter.json index 07ddf7f8..695bf575 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -1,6 +1,7 @@ { "name": "testproject", "_copy_without_render": [ + ".github/actions/build/action.yml", ".github/workflows/ci.yml", "src/.django-app-template" ] diff --git a/poetry.lock b/poetry.lock index bbb5fa54..1fd9fefe 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,5 +1,21 @@ # This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. +[[package]] +name = "application-properties" +version = "0.8.1" +description = "A simple, easy to use, unified manner of accessing program properties." +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "application_properties-0.8.1-py3-none-any.whl", hash = "sha256:f442e403ab7c8f97b048cf0ab92845057d595989653f65ced48579ad7cf35607"}, + {file = "application_properties-0.8.1.tar.gz", hash = "sha256:101667125383940651e72a2a9b3aa32225f359050c3be45b4ef4b51009930bb4"}, +] + +[package.dependencies] +pyyaml = ">=6.0" +tomli = ">=2.0.1" +typing-extensions = ">=4.5.0" + [[package]] name = "arrow" version = "1.3.0" @@ -179,6 +195,21 @@ files = [ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +[[package]] +name = "columnar" +version = "1.4.1" +description = "A tool for printing data in a columnar format." +optional = false +python-versions = "*" +files = [ + {file = "Columnar-1.4.1-py3-none-any.whl", hash = "sha256:8efb692a7e6ca07dcc8f4ea889960421331a5dffa8e5af81f0a67ad8ea1fc798"}, + {file = "Columnar-1.4.1.tar.gz", hash = "sha256:c3cb57273333b2ff9cfaafc86f09307419330c97faa88dcfe23df05e6fbb9c72"}, +] + +[package.dependencies] +toolz = "*" +wcwidth = "*" + [[package]] name = "cookiecutter" version = "2.5.0" @@ -337,6 +368,22 @@ files = [ plugins = ["importlib-metadata"] windows-terminal = ["colorama (>=0.4.6)"] +[[package]] +name = "pymarkdownlnt" +version = "0.9.14" +description = "A GitHub Flavored Markdown compliant Markdown linter." +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "pymarkdownlnt-0.9.14-py3-none-any.whl", hash = "sha256:7db466fe9170b8144a4101362171d111233dbd5c7710f896c525456e27559efb"}, + {file = "pymarkdownlnt-0.9.14.tar.gz", hash = "sha256:3f75977a812a14b305773167a8774b6930ff30528cd7f75da8c4e865c19a504f"}, +] + +[package.dependencies] +application-properties = ">=0.8.1" +columnar = ">=1.4.0" +typing-extensions = ">=4.7.0" + [[package]] name = "python-dateutil" version = "2.8.2" @@ -478,6 +525,53 @@ files = [ {file = "text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8"}, ] +[[package]] +name = "toml-sort" +version = "0.23.1" +description = "Toml sorting library" +optional = false +python-versions = ">=3.7,<4.0" +files = [ + {file = "toml_sort-0.23.1-py3-none-any.whl", hash = "sha256:69ae60de9c4d67478533697eb4119092e2b30ddffe5ca09bbad3912905c935a0"}, + {file = "toml_sort-0.23.1.tar.gz", hash = "sha256:833728c48b0f8d509aecd9ae8347768ca3a9332977b32c9fd2002932f0eb9c90"}, +] + +[package.dependencies] +tomlkit = ">=0.11.2" + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] + +[[package]] +name = "tomlkit" +version = "0.12.3" +description = "Style preserving TOML library" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomlkit-0.12.3-py3-none-any.whl", hash = "sha256:b0a645a9156dc7cb5d3a1f0d4bab66db287fcb8e0430bdd4664a095ea16414ba"}, + {file = "tomlkit-0.12.3.tar.gz", hash = "sha256:75baf5012d06501f07bee5bf8e801b9f343e7aac5a92581f20f80ce632e6b5a4"}, +] + +[[package]] +name = "toolz" +version = "0.12.0" +description = "List processing tools and functional utilities" +optional = false +python-versions = ">=3.5" +files = [ + {file = "toolz-0.12.0-py3-none-any.whl", hash = "sha256:2059bd4148deb1884bb0eb770a3cde70e7f954cfbbdc2285f1f2de01fd21eb6f"}, + {file = "toolz-0.12.0.tar.gz", hash = "sha256:88c570861c440ee3f2f6037c4654613228ff40c93a6c25e0eba70d17282c6194"}, +] + [[package]] name = "types-python-dateutil" version = "2.8.19.14" @@ -489,6 +583,17 @@ files = [ {file = "types_python_dateutil-2.8.19.14-py3-none-any.whl", hash = "sha256:f977b8de27787639986b4e28963263fd0e5158942b3ecef91b9335c130cb1ce9"}, ] +[[package]] +name = "typing-extensions" +version = "4.8.0" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typing_extensions-4.8.0-py3-none-any.whl", hash = "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0"}, + {file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"}, +] + [[package]] name = "urllib3" version = "2.1.0" @@ -505,7 +610,18 @@ brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] +[[package]] +name = "wcwidth" +version = "0.2.12" +description = "Measures the displayed width of unicode strings in a terminal" +optional = false +python-versions = "*" +files = [ + {file = "wcwidth-0.2.12-py2.py3-none-any.whl", hash = "sha256:f26ec43d96c8cbfed76a5075dac87680124fa84e0855195a6184da9c187f133c"}, + {file = "wcwidth-0.2.12.tar.gz", hash = "sha256:f01c104efdf57971bcb756f054dd58ddec5204dd15fa31d6503ea57947d97c02"}, +] + [metadata] lock-version = "2.0" python-versions = "~3.11" -content-hash = "d6d0e3ca33f5cc8ff39cb535e2d1d0e8c980759e7a708dfdbef90ff204d43941" +content-hash = "f2d4bf92c0c7a1e19ee869b62c4c7cb88fa7c88863a3f9ab953c6adc69cc6624" diff --git a/pyproject.toml b/pyproject.toml index 90adcab3..12482758 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,7 @@ +[build-system] +build-backend = "poetry.core.masonry.api" +requires = ["poetry-core"] + [tool.poetry] authors = ["Fedor Borshev "] description = "" @@ -9,6 +13,23 @@ version = "2023.11.29" cookiecutter = "^2.5.0" python = "~3.11" -[build-system] -requires = ["poetry-core"] -build-backend = "poetry.core.masonry.api" +[tool.poetry.group.dev.dependencies] +pymarkdownlnt = "^0.9.14" +toml-sort = "^0.23.1" + +[tool.pymarkdown.plugins.md013] +enabled = false + +[tool.pymarkdown.plugins.md026] +enabled = false + +[tool.pymarkdown.plugins.md045] +enabled = false + +[tool.tomlsort] +all = true +in_place = true +sort_first = ["tool.poetry"] +spaces_before_inline_comment = 2 +spaces_indent_inline_array = 4 +trailing_comma_inline_array = true From f15ef0d65df715099cbd3ddcd70b265606b02464 Mon Sep 17 00:00:00 2001 From: hnthh Date: Mon, 4 Dec 2023 02:20:27 +0300 Subject: [PATCH 026/116] circle config fix indentation --- .circleci/config.yml | 70 +++++++++++++++++++++--------------------- .github/dependabot.yml | 2 +- .github/funding.yml | 2 +- 3 files changed, 37 insertions(+), 37 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 0268103d..c6320ed8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -4,45 +4,45 @@ orbs: docker: circleci/docker@2.4.0 jobs: - build: - docker: - - image: cimg/python:3.11 + build: + docker: + - image: cimg/python:3.11 - steps: - - checkout + steps: + - checkout - - run: - name: install poetry - command: pip install poetry==1.6.1 + - run: + name: install poetry + command: pip install poetry==1.6.1 - - run: - name: install deps - command: poetry install + - run: + name: install deps + command: poetry install - - run: - name: bootstrap - command: make bootstrap + - run: + name: bootstrap + command: make bootstrap - - persist_to_workspace: - paths: - - ".venv" - - "testproject" - root: . + - persist_to_workspace: + paths: + - ".venv" + - "testproject" + root: . workflows: - version: 2 - ci: - jobs: - - build - - - docker/publish: - attach-at: . - context: docker - deploy: false - docker-context: testproject - extra_build_args: "--build-arg POETRY_VERSION=1.6.1 --build-arg PYTHON_VERSION=3.11" - image: f213/django - name: make sure docker image is buildable - path: testproject - requires: - - build + version: 2 + ci: + jobs: + - build + + - docker/publish: + attach-at: . + context: docker + deploy: false + docker-context: testproject + extra_build_args: "--build-arg POETRY_VERSION=1.6.1 --build-arg PYTHON_VERSION=3.11" + image: f213/django + name: make sure docker image is buildable + path: testproject + requires: + - build diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 54539ffd..f297c0f1 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,7 +1,7 @@ version: 2 updates: - package-ecosystem: pip - directory: "/{{cookiecutter.project_slug}}" + directory: "/{{cookiecutter.name}}" schedule: interval: daily time: "02:00" diff --git a/.github/funding.yml b/.github/funding.yml index 6654d144..6345cf4e 100644 --- a/.github/funding.yml +++ b/.github/funding.yml @@ -1 +1 @@ -patreon: f213 \ No newline at end of file +patreon: f213 From eca84d8277afa8862ad3ae57e656d538a22edaf3 Mon Sep 17 00:00:00 2001 From: hnthh Date: Mon, 4 Dec 2023 02:22:58 +0300 Subject: [PATCH 027/116] fix config --- .circleci/config.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index c6320ed8..e9eaf933 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,12 +1,12 @@ version: 2.1 orbs: - docker: circleci/docker@2.4.0 + docker: circleci/docker@2.4.0 jobs: build: docker: - - image: cimg/python:3.11 + - image: 'cimg/python:3.11' steps: - checkout @@ -25,8 +25,8 @@ jobs: - persist_to_workspace: paths: - - ".venv" - - "testproject" + - .venv + - testproject root: . workflows: @@ -34,13 +34,12 @@ workflows: ci: jobs: - build - - docker/publish: attach-at: . context: docker deploy: false docker-context: testproject - extra_build_args: "--build-arg POETRY_VERSION=1.6.1 --build-arg PYTHON_VERSION=3.11" + extra_build_args: '--build-arg POETRY_VERSION=1.6.1 --build-arg PYTHON_VERSION=3.11' image: f213/django name: make sure docker image is buildable path: testproject From 30a9b6010250e063e20a5af3c25cc20575e019b5 Mon Sep 17 00:00:00 2001 From: hnthh Date: Mon, 4 Dec 2023 02:25:52 +0300 Subject: [PATCH 028/116] circle config fix indentation --- .circleci/config.yml | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index e9eaf933..bc1574df 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -8,26 +8,26 @@ jobs: docker: - image: 'cimg/python:3.11' - steps: - - checkout - - - run: - name: install poetry - command: pip install poetry==1.6.1 - - - run: - name: install deps - command: poetry install - - - run: - name: bootstrap - command: make bootstrap - - - persist_to_workspace: - paths: - - .venv - - testproject - root: . + steps: + - checkout + + - run: + name: install poetry + command: pip install poetry==1.6.1 + + - run: + name: install deps + command: poetry install + + - run: + name: bootstrap + command: make bootstrap + + - persist_to_workspace: + paths: + - .venv + - testproject + root: . workflows: version: 2 From d66af0e4c213fe748faa20933e06e469f4f9867b Mon Sep 17 00:00:00 2001 From: hnthh Date: Mon, 4 Dec 2023 02:31:51 +0300 Subject: [PATCH 029/116] remove migrations file from app template --- hooks/post_gen_project.sh | 3 ++- .../migrations/0001_entity_name.py-tpl | 23 ------------------- 2 files changed, 2 insertions(+), 24 deletions(-) delete mode 100644 {{cookiecutter.name}}/src/.django-app-template/migrations/0001_entity_name.py-tpl diff --git a/hooks/post_gen_project.sh b/hooks/post_gen_project.sh index abb80dcf..ebcef762 100644 --- a/hooks/post_gen_project.sh +++ b/hooks/post_gen_project.sh @@ -5,7 +5,8 @@ cp src/core/.env.ci src/core/.env poetry install poetry run python src/manage.py collectstatic -poetry run python src/manage.py migrate poetry run python src/manage.py startapp some_app --entity_name some_entity +poetry run python src/manage.py makemigrations --name some_entity +poetry run python src/manage.py migrate make checks test diff --git a/{{cookiecutter.name}}/src/.django-app-template/migrations/0001_entity_name.py-tpl b/{{cookiecutter.name}}/src/.django-app-template/migrations/0001_entity_name.py-tpl deleted file mode 100644 index 1a4f8fc3..00000000 --- a/{{cookiecutter.name}}/src/.django-app-template/migrations/0001_entity_name.py-tpl +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 4.2.7 on 2023-11-30 19:50 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - initial = True - - dependencies = [] - - operations = [ - migrations.CreateModel( - name="{{ camel_case_entity_name }}", - fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ("created", models.DateTimeField(auto_now_add=True, db_index=True)), - ("modified", models.DateTimeField(blank=True, db_index=True, null=True)), - ], - options={ - "abstract": False, - }, - ), - ] From 26b001d6eb4151fa409f01ef9bdaef5925335890 Mon Sep 17 00:00:00 2001 From: hnthh Date: Mon, 4 Dec 2023 03:08:22 +0300 Subject: [PATCH 030/116] use cookiecutter variables in child pyproject --- README.md | 2 +- cookiecutter.json | 3 +++ {{cookiecutter.name}}/pyproject.toml | 6 +++--- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index cc94d12d..1796c190 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# My personal (very) opinionated django template +# fands.dev django template [![CircleCI](https://circleci.com/gh/fandsdev/django.svg?style=svg&circle-token=8ce8cbe93d81d60af6b67c82a82563d93da0cb03)](https://circleci.com/gh/f213/django) ![Shields.io](https://img.shields.io/github/last-commit/fandsdev/django?style=flat-square) [![Support me on Patreon](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fshieldsio-patreon.vercel.app%2Fapi%3Fusername%3Df213%26type%3Dpatrons&style=flat)](https://patreon.com/f213) diff --git a/cookiecutter.json b/cookiecutter.json index 695bf575..11589da8 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -1,4 +1,7 @@ { + "author": "Fedor Borshev", + "description": "", + "email": "fedor@borshev.com", "name": "testproject", "_copy_without_render": [ ".github/actions/build/action.yml", diff --git a/{{cookiecutter.name}}/pyproject.toml b/{{cookiecutter.name}}/pyproject.toml index a50d61fe..0143f3fc 100644 --- a/{{cookiecutter.name}}/pyproject.toml +++ b/{{cookiecutter.name}}/pyproject.toml @@ -3,9 +3,9 @@ build-backend = "poetry.core.masonry.api" requires = ["poetry-core"] [tool.poetry] -authors = ["you "] -description = "your project description" -name = "your project name" +authors = ["{{ cookiecutter.author }} <{{ cookiecutter.email }}>"] +description = "{{ cookiecutter.description }}" +name = "{{ cookiecutter.name }}" readme = "README.md" version = "0.0.0-dev" From 95fd044c4c35b012856252c874424ef1818f3a6f Mon Sep 17 00:00:00 2001 From: hnthh Date: Tue, 5 Dec 2023 17:49:34 +0300 Subject: [PATCH 031/116] remove circleci dir --- .circleci/config.yml | 47 -------------------------------------------- 1 file changed, 47 deletions(-) delete mode 100644 .circleci/config.yml diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index bc1574df..00000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,47 +0,0 @@ -version: 2.1 - -orbs: - docker: circleci/docker@2.4.0 - -jobs: - build: - docker: - - image: 'cimg/python:3.11' - - steps: - - checkout - - - run: - name: install poetry - command: pip install poetry==1.6.1 - - - run: - name: install deps - command: poetry install - - - run: - name: bootstrap - command: make bootstrap - - - persist_to_workspace: - paths: - - .venv - - testproject - root: . - -workflows: - version: 2 - ci: - jobs: - - build - - docker/publish: - attach-at: . - context: docker - deploy: false - docker-context: testproject - extra_build_args: '--build-arg POETRY_VERSION=1.6.1 --build-arg PYTHON_VERSION=3.11' - image: f213/django - name: make sure docker image is buildable - path: testproject - requires: - - build From 3aef0d1f21fe64787b212f47fadd1ccd1da8cb4b Mon Sep 17 00:00:00 2001 From: hnthh Date: Tue, 5 Dec 2023 21:27:26 +0300 Subject: [PATCH 032/116] add github actions ci --- .github/workflows/actions/build/action.yml | 34 ++++++++++++++++++++++ .github/workflows/ci.yml | 34 ++++++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 .github/workflows/actions/build/action.yml create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/actions/build/action.yml b/.github/workflows/actions/build/action.yml new file mode 100644 index 00000000..902674ce --- /dev/null +++ b/.github/workflows/actions/build/action.yml @@ -0,0 +1,34 @@ +name: build + +runs: + using: composite + + steps: + - name: load cached poetry installation + id: cached-poetry + uses: actions/cache@v3 + with: + path: ~/.local + key: poetry-v1-${{ hashFiles("pyproject.toml") }} + + - name: install poetry + if: steps.cached-poetry.outputs.cache-hit != "true" + uses: snok/install-poetry@v1 + with: + version: 1.6.1 + + - name: install python + id: setup-python + uses: actions/setup-python@v4 + with: + cache: "poetry" + python-version-file: "pyproject.toml" + + - name: make sure poetry lockfile is up to date + run: poetry check --lock + shell: bash + + - name: install deps + if: steps.setup-python.outputs.cache-hit != "true" + run: poetry install --no-interaction --no-root + shell: bash diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..8570ad18 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,34 @@ +name: CI + +on: + push: + branches: + - master + pull_request: + +jobs: + check: + runs-on: ubuntu-latest + + steps: + - name: checkout + uses: actions/checkout@v3 + + - name: build + uses: ./.github/actions/build + + - name: check + run: make checks + + bootstrap: + needs: check + + steps: + - name: checkout + uses: actions/checkout@v3 + + - name: build + run: ./.github/actions/build + + - name: bootstrap + run: make bootstrap From 4cf8276566f6adcad66899efb8312af02fda8f50 Mon Sep 17 00:00:00 2001 From: hnthh Date: Tue, 5 Dec 2023 21:33:30 +0300 Subject: [PATCH 033/116] add runs-on property --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8570ad18..d680062f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,6 +22,7 @@ jobs: bootstrap: needs: check + runs-on: ubuntu-latest steps: - name: checkout From f23a85dab28c1babbd6d57083dd648b5a369d167 Mon Sep 17 00:00:00 2001 From: hnthh Date: Tue, 5 Dec 2023 21:38:14 +0300 Subject: [PATCH 034/116] move actions dir --- .github/{workflows => }/actions/build/action.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/{workflows => }/actions/build/action.yml (100%) diff --git a/.github/workflows/actions/build/action.yml b/.github/actions/build/action.yml similarity index 100% rename from .github/workflows/actions/build/action.yml rename to .github/actions/build/action.yml From 37fa2d01710335688405bb2b0d1e22fa1de97932 Mon Sep 17 00:00:00 2001 From: hnthh Date: Tue, 5 Dec 2023 21:42:37 +0300 Subject: [PATCH 035/116] use single quotes --- .github/actions/build/action.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/actions/build/action.yml b/.github/actions/build/action.yml index 902674ce..88d1ba5d 100644 --- a/.github/actions/build/action.yml +++ b/.github/actions/build/action.yml @@ -9,10 +9,10 @@ runs: uses: actions/cache@v3 with: path: ~/.local - key: poetry-v1-${{ hashFiles("pyproject.toml") }} + key: poetry-v1-${{ hashFiles('pyproject.toml') }} - name: install poetry - if: steps.cached-poetry.outputs.cache-hit != "true" + if: steps.cached-poetry.outputs.cache-hit != 'true' uses: snok/install-poetry@v1 with: version: 1.6.1 @@ -21,14 +21,14 @@ runs: id: setup-python uses: actions/setup-python@v4 with: - cache: "poetry" - python-version-file: "pyproject.toml" + cache: 'poetry' + python-version-file: 'pyproject.toml' - name: make sure poetry lockfile is up to date run: poetry check --lock shell: bash - name: install deps - if: steps.setup-python.outputs.cache-hit != "true" + if: steps.setup-python.outputs.cache-hit != 'true' run: poetry install --no-interaction --no-root shell: bash From 3d71abcc25270be954146568ddcb884eb81d5764 Mon Sep 17 00:00:00 2001 From: hnthh Date: Tue, 5 Dec 2023 21:44:51 +0300 Subject: [PATCH 036/116] fix syntax --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d680062f..16776034 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,7 +29,7 @@ jobs: uses: actions/checkout@v3 - name: build - run: ./.github/actions/build + uses: ./.github/actions/build - name: bootstrap run: make bootstrap From 35387dbff80fb3b3e55c78a65e38e351c7fa6886 Mon Sep 17 00:00:00 2001 From: hnthh Date: Tue, 5 Dec 2023 22:08:59 +0300 Subject: [PATCH 037/116] cleanup `.gitignore` --- .gitignore | 2 -- 1 file changed, 2 deletions(-) diff --git a/.gitignore b/.gitignore index 0f2bbb5f..632efcf4 100644 --- a/.gitignore +++ b/.gitignore @@ -3,9 +3,7 @@ .venv .vscode -**/*~ **/.DS_Store **/db.sqlite -**/some_app testproject From 9bc50d1a71c439e04734204b13cf5809b804a623 Mon Sep 17 00:00:00 2001 From: hnthh Date: Tue, 5 Dec 2023 22:55:49 +0300 Subject: [PATCH 038/116] fix app tamplate --- hooks/post_gen_project.sh | 3 +- .../src/.django-app-template/admin.py-tpl | 10 +---- .../api/v1/serializers/__init__.py-tpl | 5 --- .../api/v1/serializers/entity_name.py-tpl | 10 ----- .../.django-app-template/api/v1/urls.py-tpl | 3 -- .../api/v1/views/__init__.py-tpl | 4 +- .../api/v1/views/entity_name.py-tpl | 5 --- .../models/__init__.py-tpl | 4 +- .../models/app_name.py-tpl | 3 ++ .../models/entity_name.py-tpl | 7 ---- .../{fixtures.py => api/__init__.py-tpl} | 0 .../tests/api/v1/__init__.py-tpl | 0 .../tests/fixtures.py-tpl | 0 .../src/core/management/commands/startapp.py | 42 +------------------ 14 files changed, 8 insertions(+), 88 deletions(-) delete mode 100644 {{cookiecutter.name}}/src/.django-app-template/api/v1/serializers/entity_name.py-tpl delete mode 100644 {{cookiecutter.name}}/src/.django-app-template/api/v1/views/entity_name.py-tpl create mode 100644 {{cookiecutter.name}}/src/.django-app-template/models/app_name.py-tpl delete mode 100644 {{cookiecutter.name}}/src/.django-app-template/models/entity_name.py-tpl rename {{cookiecutter.name}}/src/.django-app-template/tests/{fixtures.py => api/__init__.py-tpl} (100%) create mode 100644 {{cookiecutter.name}}/src/.django-app-template/tests/api/v1/__init__.py-tpl create mode 100644 {{cookiecutter.name}}/src/.django-app-template/tests/fixtures.py-tpl diff --git a/hooks/post_gen_project.sh b/hooks/post_gen_project.sh index ebcef762..6ca02033 100644 --- a/hooks/post_gen_project.sh +++ b/hooks/post_gen_project.sh @@ -5,8 +5,7 @@ cp src/core/.env.ci src/core/.env poetry install poetry run python src/manage.py collectstatic -poetry run python src/manage.py startapp some_app --entity_name some_entity -poetry run python src/manage.py makemigrations --name some_entity +poetry run python src/manage.py startapp some_app poetry run python src/manage.py migrate make checks test diff --git a/{{cookiecutter.name}}/src/.django-app-template/admin.py-tpl b/{{cookiecutter.name}}/src/.django-app-template/admin.py-tpl index de5aa61a..fe7369cf 100644 --- a/{{cookiecutter.name}}/src/.django-app-template/admin.py-tpl +++ b/{{cookiecutter.name}}/src/.django-app-template/admin.py-tpl @@ -1,9 +1 @@ -from django.contrib import admin - -from apps.{{ app_name }}.models import {{ camel_case_entity_name }} -from core.admin import ModelAdmin - - -@admin.register({{ camel_case_entity_name }}) -class {{ camel_case_entity_name }}Admin(ModelAdmin): - pass +from core.admin import ModelAdmin, admin # noqa: F401 diff --git a/{{cookiecutter.name}}/src/.django-app-template/api/v1/serializers/__init__.py-tpl b/{{cookiecutter.name}}/src/.django-app-template/api/v1/serializers/__init__.py-tpl index aeaf4f0b..e69de29b 100644 --- a/{{cookiecutter.name}}/src/.django-app-template/api/v1/serializers/__init__.py-tpl +++ b/{{cookiecutter.name}}/src/.django-app-template/api/v1/serializers/__init__.py-tpl @@ -1,5 +0,0 @@ -from apps.{{ app_name }}.api.v1.serializers.{{ entity_name }} import {{ camel_case_entity_name }}ReadSerializer - -__all__ = [ - "{{ camel_case_entity_name }}ReadSerializer", -] diff --git a/{{cookiecutter.name}}/src/.django-app-template/api/v1/serializers/entity_name.py-tpl b/{{cookiecutter.name}}/src/.django-app-template/api/v1/serializers/entity_name.py-tpl deleted file mode 100644 index a3e16471..00000000 --- a/{{cookiecutter.name}}/src/.django-app-template/api/v1/serializers/entity_name.py-tpl +++ /dev/null @@ -1,10 +0,0 @@ -from rest_framework import serializers - -from apps.{{ app_name }}.models import {{ camel_case_entity_name }} - - -class {{ camel_case_entity_name }}ReadSerializer(serializers.ModelSerializer): - class Meta: - fields = ("somefield",) - model = {{ camel_case_entity_name }} - read_only_fields = fields diff --git a/{{cookiecutter.name}}/src/.django-app-template/api/v1/urls.py-tpl b/{{cookiecutter.name}}/src/.django-app-template/api/v1/urls.py-tpl index 18bc8d4f..b0df5123 100644 --- a/{{cookiecutter.name}}/src/.django-app-template/api/v1/urls.py-tpl +++ b/{{cookiecutter.name}}/src/.django-app-template/api/v1/urls.py-tpl @@ -1,10 +1,7 @@ from django.urls import include, path from rest_framework.routers import SimpleRouter -from apps.{{ app_name }}.api.v1 import views - router = SimpleRouter() -router.register("{{ app_name }}", views.{{ camel_case_entity_name }}ViewSet) urlpatterns = [ path("", include(router.urls)), diff --git a/{{cookiecutter.name}}/src/.django-app-template/api/v1/views/__init__.py-tpl b/{{cookiecutter.name}}/src/.django-app-template/api/v1/views/__init__.py-tpl index 882408d2..44f0b885 100644 --- a/{{cookiecutter.name}}/src/.django-app-template/api/v1/views/__init__.py-tpl +++ b/{{cookiecutter.name}}/src/.django-app-template/api/v1/views/__init__.py-tpl @@ -1,5 +1,3 @@ -from apps.{{ app_name }}.api.v1.views.{{ entity_name }} import {{ camel_case_entity_name }}ViewSet - __all__ = [ - "{{ camel_case_entity_name }}ViewSet", + "", ] diff --git a/{{cookiecutter.name}}/src/.django-app-template/api/v1/views/entity_name.py-tpl b/{{cookiecutter.name}}/src/.django-app-template/api/v1/views/entity_name.py-tpl deleted file mode 100644 index 0af971cc..00000000 --- a/{{cookiecutter.name}}/src/.django-app-template/api/v1/views/entity_name.py-tpl +++ /dev/null @@ -1,5 +0,0 @@ -from core.api.viewsets import DefaultModelViewSet - - -class {{ camel_case_entity_name }}ViewSet(DefaultModelViewSet): - pass diff --git a/{{cookiecutter.name}}/src/.django-app-template/models/__init__.py-tpl b/{{cookiecutter.name}}/src/.django-app-template/models/__init__.py-tpl index b97bb379..44f0b885 100644 --- a/{{cookiecutter.name}}/src/.django-app-template/models/__init__.py-tpl +++ b/{{cookiecutter.name}}/src/.django-app-template/models/__init__.py-tpl @@ -1,5 +1,3 @@ -from apps.{{ app_name }}.models.{{ entity_name }} import {{ camel_case_entity_name }} - __all__ = [ - "{{ camel_case_entity_name }}", + "", ] diff --git a/{{cookiecutter.name}}/src/.django-app-template/models/app_name.py-tpl b/{{cookiecutter.name}}/src/.django-app-template/models/app_name.py-tpl new file mode 100644 index 00000000..f423d2ee --- /dev/null +++ b/{{cookiecutter.name}}/src/.django-app-template/models/app_name.py-tpl @@ -0,0 +1,3 @@ +from core.models import DefaultModel, TimestampedModel, models # noqa: F401 + +# Rename this file to singular form of your entity, e.g. "orders.py -> order.py". Add your class to __init__.py. diff --git a/{{cookiecutter.name}}/src/.django-app-template/models/entity_name.py-tpl b/{{cookiecutter.name}}/src/.django-app-template/models/entity_name.py-tpl deleted file mode 100644 index 558ef681..00000000 --- a/{{cookiecutter.name}}/src/.django-app-template/models/entity_name.py-tpl +++ /dev/null @@ -1,7 +0,0 @@ -from django.db import models # noqa: F401 - -from core.models import TimestampedModel - - -class {{ camel_case_entity_name }}(TimestampedModel): - pass diff --git a/{{cookiecutter.name}}/src/.django-app-template/tests/fixtures.py b/{{cookiecutter.name}}/src/.django-app-template/tests/api/__init__.py-tpl similarity index 100% rename from {{cookiecutter.name}}/src/.django-app-template/tests/fixtures.py rename to {{cookiecutter.name}}/src/.django-app-template/tests/api/__init__.py-tpl diff --git a/{{cookiecutter.name}}/src/.django-app-template/tests/api/v1/__init__.py-tpl b/{{cookiecutter.name}}/src/.django-app-template/tests/api/v1/__init__.py-tpl new file mode 100644 index 00000000..e69de29b diff --git a/{{cookiecutter.name}}/src/.django-app-template/tests/fixtures.py-tpl b/{{cookiecutter.name}}/src/.django-app-template/tests/fixtures.py-tpl new file mode 100644 index 00000000..e69de29b diff --git a/{{cookiecutter.name}}/src/core/management/commands/startapp.py b/{{cookiecutter.name}}/src/core/management/commands/startapp.py index f105ebd7..092b9426 100644 --- a/{{cookiecutter.name}}/src/core/management/commands/startapp.py +++ b/{{cookiecutter.name}}/src/core/management/commands/startapp.py @@ -4,19 +4,10 @@ from django.core.management.commands.startapp import Command as BaseCommand if TYPE_CHECKING: - from argparse import ArgumentParser from typing import Any class Command(BaseCommand): - def add_arguments(self, parser: "ArgumentParser") -> None: - super().add_arguments(parser) - - parser.add_argument( - "--entity_name", - help="The name of some application entity given in `snake_case`; e. g., if the application name is `users`, then the entity is `user`, and so on.", - ) - def handle(self, **options: "Any") -> None: # type: ignore[override] app_name = options["name"] @@ -27,43 +18,12 @@ def handle(self, **options: "Any") -> None: # type: ignore[override] if "template" not in options or options["template"] is None: template = str(settings.BASE_DIR.parent / ".django-app-template") # type: ignore[misc] - options.update( - camel_case_entity_name=self.make_entity_name_camelized(options["entity_name"]), - directory=directory, - template=template, - ) + options.update(directory=directory, template=template) super().handle(**options) - self.rename_entity_name_modules(app_name=app_name, entity_name=options["entity_name"]) - self.add_app_to_installed_apps(app_name=app_name) self.move_created_tests_directory(app_name=app_name) - def make_entity_name_camelized(self, entity_name: str) -> str: - return entity_name.replace("_", " ").title().replace(" ", "") - - def rename_entity_name_modules(self, app_name: str, entity_name: str) -> None: - app_dir = settings.BASE_DIR.parent / "apps" / app_name # type: ignore[misc] - - for path in app_dir.rglob("*.py"): - if "entity_name" in path.name: - new_name = path.name.replace("entity_name", entity_name) - path.rename(path.with_name(new_name)) - - def add_app_to_installed_apps(self, app_name: str) -> None: - installed_apps_path = settings.BASE_DIR / "conf" / "installed_apps.py" # type: ignore[misc] - - with installed_apps_path.open() as reader: - lines = reader.readlines() - - for lineno, line in enumerate(lines): - if line.strip().startswith("APPS ="): - lines.insert(lineno + 1, f' "apps.{app_name}",\n') - break - - with installed_apps_path.open("w") as writer: - writer.writelines(lines) - def move_created_tests_directory(self, app_name: str) -> None: root = settings.BASE_DIR.parent.parent # type: ignore[misc] From 425bb8249b61a0d8b707318c42136f26356e08ac Mon Sep 17 00:00:00 2001 From: hnthh Date: Tue, 5 Dec 2023 22:59:42 +0300 Subject: [PATCH 039/116] add whitespaces to project template folder name --- {{{cookiecutter.name}} => {{ cookiecutter.name }}}/.dockerignore | 0 {{{cookiecutter.name}} => {{ cookiecutter.name }}}/.editorconfig | 0 .../.github/workflows/ci.yml | 0 {{{cookiecutter.name}} => {{ cookiecutter.name }}}/.gitignore | 0 {{{cookiecutter.name}} => {{ cookiecutter.name }}}/Dockerfile | 0 {{{cookiecutter.name}} => {{ cookiecutter.name }}}/Makefile | 0 {{{cookiecutter.name}} => {{ cookiecutter.name }}}/README.md | 0 .../docker-compose.yml | 0 {{{cookiecutter.name}} => {{ cookiecutter.name }}}/mypy.ini | 0 {{{cookiecutter.name}} => {{ cookiecutter.name }}}/poetry.lock | 0 {{{cookiecutter.name}} => {{ cookiecutter.name }}}/pyproject.toml | 0 .../src/.django-app-template/__init__.py-tpl | 0 .../src/.django-app-template/admin.py-tpl | 0 .../src/.django-app-template/api/v1/__init__.py-tpl | 0 .../src/.django-app-template/api/v1/serializers/__init__.py-tpl | 0 .../src/.django-app-template/api/v1/urls.py-tpl | 0 .../src/.django-app-template/api/v1/views/__init__.py-tpl | 0 .../src/.django-app-template/apps.py-tpl | 0 .../src/.django-app-template/migrations/__init__.py-tpl | 0 .../src/.django-app-template/models/__init__.py-tpl | 0 .../src/.django-app-template/models/app_name.py-tpl | 0 .../src/.django-app-template/tests/__init__.py-tpl | 0 .../src/.django-app-template/tests/api/__init__.py-tpl | 0 .../src/.django-app-template/tests/api/v1/__init__.py-tpl | 0 .../src/.django-app-template/tests/factory.py-tpl | 0 .../src/.django-app-template/tests/fixtures.py-tpl | 0 .../src/apps/a12n/__init__.py | 0 .../src/apps/a12n/api/throttling.py | 0 .../src/apps/a12n/api/urls.py | 0 .../src/apps/a12n/api/views.py | 0 .../src/apps/a12n/migrations/__init__.py | 0 .../src/apps/a12n/utils.py | 0 .../src/apps/users/__init__.py | 0 .../src/apps/users/admin.py | 0 .../src/apps/users/api/serializers.py | 0 .../src/apps/users/api/urls.py | 0 .../src/apps/users/api/viewsets.py | 0 .../src/apps/users/migrations/0001_initial.py | 0 .../src/apps/users/migrations/__init__.py | 0 .../src/apps/users/models.py | 0 .../src/core/.env.ci | 0 .../src/core/__init__.py | 0 .../src/core/admin/__init__.py | 0 .../src/core/admin/model_admin.py | 0 .../src/core/api/pagination.py | 0 .../src/core/api/renderers.py | 0 .../src/core/api/throttling.py | 0 .../src/core/api/viewsets.py | 0 .../src/core/asgi.py | 0 .../src/core/base_config.py | 0 .../src/core/conf/api.py | 0 .../src/core/conf/auth.py | 0 .../src/core/conf/boilerplate.py | 0 .../src/core/conf/db.py | 0 .../src/core/conf/environ.py | 0 .../src/core/conf/healthchecks.py | 0 .../src/core/conf/http.py | 0 .../src/core/conf/i18n.py | 0 .../src/core/conf/installed_apps.py | 0 .../src/core/conf/media.py | 0 .../src/core/conf/middleware.py | 0 .../src/core/conf/sentry.py | 0 .../src/core/conf/static.py | 0 .../src/core/conf/storage.py | 0 .../src/core/conf/templates.py | 0 .../src/core/conf/timezone.py | 0 .../src/core/management/commands/makemigrations.py | 0 .../src/core/management/commands/startapp.py | 0 .../src/core/middleware/real_ip.py | 0 .../src/core/models.py | 0 .../src/core/services.py | 0 .../src/core/settings.py | 0 .../src/core/testing/__init__.py | 0 .../src/core/testing/api.py | 0 .../src/core/testing/factory.py | 0 .../src/core/testing/mixer.py | 0 .../src/core/testing/runner.py | 0 .../src/core/testing/types.py | 0 .../src/core/urls/__init__.py | 0 .../src/core/urls/v1.py | 0 .../src/core/wsgi.py | 0 {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/manage.py | 0 .../tests/__init__.py | 0 .../tests/apps/a12n/jwt_views/test_obtain_jwt_view.py | 0 .../tests/apps/a12n/jwt_views/test_refresh_jwt_token.py | 0 .../tests/apps/users/factory.py | 0 .../tests/apps/users/fixtures.py | 0 .../tests/apps/users/test_password_hashing.py | 0 .../tests/apps/users/test_whoami.py | 0 .../tests/conftest.py | 0 .../tests/core/__init__.py | 0 .../tests/core/factory.py | 0 .../tests/core/fixtures.py | 0 .../tests/core/test_health.py | 0 .../tests/core/test_remote_addr_midlleware.py | 0 .../tests/core/testing/__init__.py | 0 .../tests/core/testing/factory/__init__.py | 0 .../tests/core/testing/factory/test_factory.py | 0 .../tests/core/testing/factory/test_registry.py | 0 99 files changed, 0 insertions(+), 0 deletions(-) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/.dockerignore (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/.editorconfig (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/.github/workflows/ci.yml (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/.gitignore (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/Dockerfile (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/Makefile (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/README.md (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/docker-compose.yml (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/mypy.ini (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/poetry.lock (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/pyproject.toml (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/.django-app-template/__init__.py-tpl (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/.django-app-template/admin.py-tpl (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/.django-app-template/api/v1/__init__.py-tpl (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/.django-app-template/api/v1/serializers/__init__.py-tpl (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/.django-app-template/api/v1/urls.py-tpl (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/.django-app-template/api/v1/views/__init__.py-tpl (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/.django-app-template/apps.py-tpl (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/.django-app-template/migrations/__init__.py-tpl (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/.django-app-template/models/__init__.py-tpl (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/.django-app-template/models/app_name.py-tpl (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/.django-app-template/tests/__init__.py-tpl (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/.django-app-template/tests/api/__init__.py-tpl (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/.django-app-template/tests/api/v1/__init__.py-tpl (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/.django-app-template/tests/factory.py-tpl (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/.django-app-template/tests/fixtures.py-tpl (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/apps/a12n/__init__.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/apps/a12n/api/throttling.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/apps/a12n/api/urls.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/apps/a12n/api/views.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/apps/a12n/migrations/__init__.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/apps/a12n/utils.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/apps/users/__init__.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/apps/users/admin.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/apps/users/api/serializers.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/apps/users/api/urls.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/apps/users/api/viewsets.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/apps/users/migrations/0001_initial.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/apps/users/migrations/__init__.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/apps/users/models.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/core/.env.ci (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/core/__init__.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/core/admin/__init__.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/core/admin/model_admin.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/core/api/pagination.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/core/api/renderers.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/core/api/throttling.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/core/api/viewsets.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/core/asgi.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/core/base_config.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/core/conf/api.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/core/conf/auth.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/core/conf/boilerplate.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/core/conf/db.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/core/conf/environ.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/core/conf/healthchecks.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/core/conf/http.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/core/conf/i18n.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/core/conf/installed_apps.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/core/conf/media.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/core/conf/middleware.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/core/conf/sentry.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/core/conf/static.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/core/conf/storage.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/core/conf/templates.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/core/conf/timezone.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/core/management/commands/makemigrations.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/core/management/commands/startapp.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/core/middleware/real_ip.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/core/models.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/core/services.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/core/settings.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/core/testing/__init__.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/core/testing/api.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/core/testing/factory.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/core/testing/mixer.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/core/testing/runner.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/core/testing/types.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/core/urls/__init__.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/core/urls/v1.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/core/wsgi.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/src/manage.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/tests/__init__.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/tests/apps/a12n/jwt_views/test_obtain_jwt_view.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/tests/apps/a12n/jwt_views/test_refresh_jwt_token.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/tests/apps/users/factory.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/tests/apps/users/fixtures.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/tests/apps/users/test_password_hashing.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/tests/apps/users/test_whoami.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/tests/conftest.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/tests/core/__init__.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/tests/core/factory.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/tests/core/fixtures.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/tests/core/test_health.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/tests/core/test_remote_addr_midlleware.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/tests/core/testing/__init__.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/tests/core/testing/factory/__init__.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/tests/core/testing/factory/test_factory.py (100%) rename {{{cookiecutter.name}} => {{ cookiecutter.name }}}/tests/core/testing/factory/test_registry.py (100%) diff --git a/{{cookiecutter.name}}/.dockerignore b/{{ cookiecutter.name }}/.dockerignore similarity index 100% rename from {{cookiecutter.name}}/.dockerignore rename to {{ cookiecutter.name }}/.dockerignore diff --git a/{{cookiecutter.name}}/.editorconfig b/{{ cookiecutter.name }}/.editorconfig similarity index 100% rename from {{cookiecutter.name}}/.editorconfig rename to {{ cookiecutter.name }}/.editorconfig diff --git a/{{cookiecutter.name}}/.github/workflows/ci.yml b/{{ cookiecutter.name }}/.github/workflows/ci.yml similarity index 100% rename from {{cookiecutter.name}}/.github/workflows/ci.yml rename to {{ cookiecutter.name }}/.github/workflows/ci.yml diff --git a/{{cookiecutter.name}}/.gitignore b/{{ cookiecutter.name }}/.gitignore similarity index 100% rename from {{cookiecutter.name}}/.gitignore rename to {{ cookiecutter.name }}/.gitignore diff --git a/{{cookiecutter.name}}/Dockerfile b/{{ cookiecutter.name }}/Dockerfile similarity index 100% rename from {{cookiecutter.name}}/Dockerfile rename to {{ cookiecutter.name }}/Dockerfile diff --git a/{{cookiecutter.name}}/Makefile b/{{ cookiecutter.name }}/Makefile similarity index 100% rename from {{cookiecutter.name}}/Makefile rename to {{ cookiecutter.name }}/Makefile diff --git a/{{cookiecutter.name}}/README.md b/{{ cookiecutter.name }}/README.md similarity index 100% rename from {{cookiecutter.name}}/README.md rename to {{ cookiecutter.name }}/README.md diff --git a/{{cookiecutter.name}}/docker-compose.yml b/{{ cookiecutter.name }}/docker-compose.yml similarity index 100% rename from {{cookiecutter.name}}/docker-compose.yml rename to {{ cookiecutter.name }}/docker-compose.yml diff --git a/{{cookiecutter.name}}/mypy.ini b/{{ cookiecutter.name }}/mypy.ini similarity index 100% rename from {{cookiecutter.name}}/mypy.ini rename to {{ cookiecutter.name }}/mypy.ini diff --git a/{{cookiecutter.name}}/poetry.lock b/{{ cookiecutter.name }}/poetry.lock similarity index 100% rename from {{cookiecutter.name}}/poetry.lock rename to {{ cookiecutter.name }}/poetry.lock diff --git a/{{cookiecutter.name}}/pyproject.toml b/{{ cookiecutter.name }}/pyproject.toml similarity index 100% rename from {{cookiecutter.name}}/pyproject.toml rename to {{ cookiecutter.name }}/pyproject.toml diff --git a/{{cookiecutter.name}}/src/.django-app-template/__init__.py-tpl b/{{ cookiecutter.name }}/src/.django-app-template/__init__.py-tpl similarity index 100% rename from {{cookiecutter.name}}/src/.django-app-template/__init__.py-tpl rename to {{ cookiecutter.name }}/src/.django-app-template/__init__.py-tpl diff --git a/{{cookiecutter.name}}/src/.django-app-template/admin.py-tpl b/{{ cookiecutter.name }}/src/.django-app-template/admin.py-tpl similarity index 100% rename from {{cookiecutter.name}}/src/.django-app-template/admin.py-tpl rename to {{ cookiecutter.name }}/src/.django-app-template/admin.py-tpl diff --git a/{{cookiecutter.name}}/src/.django-app-template/api/v1/__init__.py-tpl b/{{ cookiecutter.name }}/src/.django-app-template/api/v1/__init__.py-tpl similarity index 100% rename from {{cookiecutter.name}}/src/.django-app-template/api/v1/__init__.py-tpl rename to {{ cookiecutter.name }}/src/.django-app-template/api/v1/__init__.py-tpl diff --git a/{{cookiecutter.name}}/src/.django-app-template/api/v1/serializers/__init__.py-tpl b/{{ cookiecutter.name }}/src/.django-app-template/api/v1/serializers/__init__.py-tpl similarity index 100% rename from {{cookiecutter.name}}/src/.django-app-template/api/v1/serializers/__init__.py-tpl rename to {{ cookiecutter.name }}/src/.django-app-template/api/v1/serializers/__init__.py-tpl diff --git a/{{cookiecutter.name}}/src/.django-app-template/api/v1/urls.py-tpl b/{{ cookiecutter.name }}/src/.django-app-template/api/v1/urls.py-tpl similarity index 100% rename from {{cookiecutter.name}}/src/.django-app-template/api/v1/urls.py-tpl rename to {{ cookiecutter.name }}/src/.django-app-template/api/v1/urls.py-tpl diff --git a/{{cookiecutter.name}}/src/.django-app-template/api/v1/views/__init__.py-tpl b/{{ cookiecutter.name }}/src/.django-app-template/api/v1/views/__init__.py-tpl similarity index 100% rename from {{cookiecutter.name}}/src/.django-app-template/api/v1/views/__init__.py-tpl rename to {{ cookiecutter.name }}/src/.django-app-template/api/v1/views/__init__.py-tpl diff --git a/{{cookiecutter.name}}/src/.django-app-template/apps.py-tpl b/{{ cookiecutter.name }}/src/.django-app-template/apps.py-tpl similarity index 100% rename from {{cookiecutter.name}}/src/.django-app-template/apps.py-tpl rename to {{ cookiecutter.name }}/src/.django-app-template/apps.py-tpl diff --git a/{{cookiecutter.name}}/src/.django-app-template/migrations/__init__.py-tpl b/{{ cookiecutter.name }}/src/.django-app-template/migrations/__init__.py-tpl similarity index 100% rename from {{cookiecutter.name}}/src/.django-app-template/migrations/__init__.py-tpl rename to {{ cookiecutter.name }}/src/.django-app-template/migrations/__init__.py-tpl diff --git a/{{cookiecutter.name}}/src/.django-app-template/models/__init__.py-tpl b/{{ cookiecutter.name }}/src/.django-app-template/models/__init__.py-tpl similarity index 100% rename from {{cookiecutter.name}}/src/.django-app-template/models/__init__.py-tpl rename to {{ cookiecutter.name }}/src/.django-app-template/models/__init__.py-tpl diff --git a/{{cookiecutter.name}}/src/.django-app-template/models/app_name.py-tpl b/{{ cookiecutter.name }}/src/.django-app-template/models/app_name.py-tpl similarity index 100% rename from {{cookiecutter.name}}/src/.django-app-template/models/app_name.py-tpl rename to {{ cookiecutter.name }}/src/.django-app-template/models/app_name.py-tpl diff --git a/{{cookiecutter.name}}/src/.django-app-template/tests/__init__.py-tpl b/{{ cookiecutter.name }}/src/.django-app-template/tests/__init__.py-tpl similarity index 100% rename from {{cookiecutter.name}}/src/.django-app-template/tests/__init__.py-tpl rename to {{ cookiecutter.name }}/src/.django-app-template/tests/__init__.py-tpl diff --git a/{{cookiecutter.name}}/src/.django-app-template/tests/api/__init__.py-tpl b/{{ cookiecutter.name }}/src/.django-app-template/tests/api/__init__.py-tpl similarity index 100% rename from {{cookiecutter.name}}/src/.django-app-template/tests/api/__init__.py-tpl rename to {{ cookiecutter.name }}/src/.django-app-template/tests/api/__init__.py-tpl diff --git a/{{cookiecutter.name}}/src/.django-app-template/tests/api/v1/__init__.py-tpl b/{{ cookiecutter.name }}/src/.django-app-template/tests/api/v1/__init__.py-tpl similarity index 100% rename from {{cookiecutter.name}}/src/.django-app-template/tests/api/v1/__init__.py-tpl rename to {{ cookiecutter.name }}/src/.django-app-template/tests/api/v1/__init__.py-tpl diff --git a/{{cookiecutter.name}}/src/.django-app-template/tests/factory.py-tpl b/{{ cookiecutter.name }}/src/.django-app-template/tests/factory.py-tpl similarity index 100% rename from {{cookiecutter.name}}/src/.django-app-template/tests/factory.py-tpl rename to {{ cookiecutter.name }}/src/.django-app-template/tests/factory.py-tpl diff --git a/{{cookiecutter.name}}/src/.django-app-template/tests/fixtures.py-tpl b/{{ cookiecutter.name }}/src/.django-app-template/tests/fixtures.py-tpl similarity index 100% rename from {{cookiecutter.name}}/src/.django-app-template/tests/fixtures.py-tpl rename to {{ cookiecutter.name }}/src/.django-app-template/tests/fixtures.py-tpl diff --git a/{{cookiecutter.name}}/src/apps/a12n/__init__.py b/{{ cookiecutter.name }}/src/apps/a12n/__init__.py similarity index 100% rename from {{cookiecutter.name}}/src/apps/a12n/__init__.py rename to {{ cookiecutter.name }}/src/apps/a12n/__init__.py diff --git a/{{cookiecutter.name}}/src/apps/a12n/api/throttling.py b/{{ cookiecutter.name }}/src/apps/a12n/api/throttling.py similarity index 100% rename from {{cookiecutter.name}}/src/apps/a12n/api/throttling.py rename to {{ cookiecutter.name }}/src/apps/a12n/api/throttling.py diff --git a/{{cookiecutter.name}}/src/apps/a12n/api/urls.py b/{{ cookiecutter.name }}/src/apps/a12n/api/urls.py similarity index 100% rename from {{cookiecutter.name}}/src/apps/a12n/api/urls.py rename to {{ cookiecutter.name }}/src/apps/a12n/api/urls.py diff --git a/{{cookiecutter.name}}/src/apps/a12n/api/views.py b/{{ cookiecutter.name }}/src/apps/a12n/api/views.py similarity index 100% rename from {{cookiecutter.name}}/src/apps/a12n/api/views.py rename to {{ cookiecutter.name }}/src/apps/a12n/api/views.py diff --git a/{{cookiecutter.name}}/src/apps/a12n/migrations/__init__.py b/{{ cookiecutter.name }}/src/apps/a12n/migrations/__init__.py similarity index 100% rename from {{cookiecutter.name}}/src/apps/a12n/migrations/__init__.py rename to {{ cookiecutter.name }}/src/apps/a12n/migrations/__init__.py diff --git a/{{cookiecutter.name}}/src/apps/a12n/utils.py b/{{ cookiecutter.name }}/src/apps/a12n/utils.py similarity index 100% rename from {{cookiecutter.name}}/src/apps/a12n/utils.py rename to {{ cookiecutter.name }}/src/apps/a12n/utils.py diff --git a/{{cookiecutter.name}}/src/apps/users/__init__.py b/{{ cookiecutter.name }}/src/apps/users/__init__.py similarity index 100% rename from {{cookiecutter.name}}/src/apps/users/__init__.py rename to {{ cookiecutter.name }}/src/apps/users/__init__.py diff --git a/{{cookiecutter.name}}/src/apps/users/admin.py b/{{ cookiecutter.name }}/src/apps/users/admin.py similarity index 100% rename from {{cookiecutter.name}}/src/apps/users/admin.py rename to {{ cookiecutter.name }}/src/apps/users/admin.py diff --git a/{{cookiecutter.name}}/src/apps/users/api/serializers.py b/{{ cookiecutter.name }}/src/apps/users/api/serializers.py similarity index 100% rename from {{cookiecutter.name}}/src/apps/users/api/serializers.py rename to {{ cookiecutter.name }}/src/apps/users/api/serializers.py diff --git a/{{cookiecutter.name}}/src/apps/users/api/urls.py b/{{ cookiecutter.name }}/src/apps/users/api/urls.py similarity index 100% rename from {{cookiecutter.name}}/src/apps/users/api/urls.py rename to {{ cookiecutter.name }}/src/apps/users/api/urls.py diff --git a/{{cookiecutter.name}}/src/apps/users/api/viewsets.py b/{{ cookiecutter.name }}/src/apps/users/api/viewsets.py similarity index 100% rename from {{cookiecutter.name}}/src/apps/users/api/viewsets.py rename to {{ cookiecutter.name }}/src/apps/users/api/viewsets.py diff --git a/{{cookiecutter.name}}/src/apps/users/migrations/0001_initial.py b/{{ cookiecutter.name }}/src/apps/users/migrations/0001_initial.py similarity index 100% rename from {{cookiecutter.name}}/src/apps/users/migrations/0001_initial.py rename to {{ cookiecutter.name }}/src/apps/users/migrations/0001_initial.py diff --git a/{{cookiecutter.name}}/src/apps/users/migrations/__init__.py b/{{ cookiecutter.name }}/src/apps/users/migrations/__init__.py similarity index 100% rename from {{cookiecutter.name}}/src/apps/users/migrations/__init__.py rename to {{ cookiecutter.name }}/src/apps/users/migrations/__init__.py diff --git a/{{cookiecutter.name}}/src/apps/users/models.py b/{{ cookiecutter.name }}/src/apps/users/models.py similarity index 100% rename from {{cookiecutter.name}}/src/apps/users/models.py rename to {{ cookiecutter.name }}/src/apps/users/models.py diff --git a/{{cookiecutter.name}}/src/core/.env.ci b/{{ cookiecutter.name }}/src/core/.env.ci similarity index 100% rename from {{cookiecutter.name}}/src/core/.env.ci rename to {{ cookiecutter.name }}/src/core/.env.ci diff --git a/{{cookiecutter.name}}/src/core/__init__.py b/{{ cookiecutter.name }}/src/core/__init__.py similarity index 100% rename from {{cookiecutter.name}}/src/core/__init__.py rename to {{ cookiecutter.name }}/src/core/__init__.py diff --git a/{{cookiecutter.name}}/src/core/admin/__init__.py b/{{ cookiecutter.name }}/src/core/admin/__init__.py similarity index 100% rename from {{cookiecutter.name}}/src/core/admin/__init__.py rename to {{ cookiecutter.name }}/src/core/admin/__init__.py diff --git a/{{cookiecutter.name}}/src/core/admin/model_admin.py b/{{ cookiecutter.name }}/src/core/admin/model_admin.py similarity index 100% rename from {{cookiecutter.name}}/src/core/admin/model_admin.py rename to {{ cookiecutter.name }}/src/core/admin/model_admin.py diff --git a/{{cookiecutter.name}}/src/core/api/pagination.py b/{{ cookiecutter.name }}/src/core/api/pagination.py similarity index 100% rename from {{cookiecutter.name}}/src/core/api/pagination.py rename to {{ cookiecutter.name }}/src/core/api/pagination.py diff --git a/{{cookiecutter.name}}/src/core/api/renderers.py b/{{ cookiecutter.name }}/src/core/api/renderers.py similarity index 100% rename from {{cookiecutter.name}}/src/core/api/renderers.py rename to {{ cookiecutter.name }}/src/core/api/renderers.py diff --git a/{{cookiecutter.name}}/src/core/api/throttling.py b/{{ cookiecutter.name }}/src/core/api/throttling.py similarity index 100% rename from {{cookiecutter.name}}/src/core/api/throttling.py rename to {{ cookiecutter.name }}/src/core/api/throttling.py diff --git a/{{cookiecutter.name}}/src/core/api/viewsets.py b/{{ cookiecutter.name }}/src/core/api/viewsets.py similarity index 100% rename from {{cookiecutter.name}}/src/core/api/viewsets.py rename to {{ cookiecutter.name }}/src/core/api/viewsets.py diff --git a/{{cookiecutter.name}}/src/core/asgi.py b/{{ cookiecutter.name }}/src/core/asgi.py similarity index 100% rename from {{cookiecutter.name}}/src/core/asgi.py rename to {{ cookiecutter.name }}/src/core/asgi.py diff --git a/{{cookiecutter.name}}/src/core/base_config.py b/{{ cookiecutter.name }}/src/core/base_config.py similarity index 100% rename from {{cookiecutter.name}}/src/core/base_config.py rename to {{ cookiecutter.name }}/src/core/base_config.py diff --git a/{{cookiecutter.name}}/src/core/conf/api.py b/{{ cookiecutter.name }}/src/core/conf/api.py similarity index 100% rename from {{cookiecutter.name}}/src/core/conf/api.py rename to {{ cookiecutter.name }}/src/core/conf/api.py diff --git a/{{cookiecutter.name}}/src/core/conf/auth.py b/{{ cookiecutter.name }}/src/core/conf/auth.py similarity index 100% rename from {{cookiecutter.name}}/src/core/conf/auth.py rename to {{ cookiecutter.name }}/src/core/conf/auth.py diff --git a/{{cookiecutter.name}}/src/core/conf/boilerplate.py b/{{ cookiecutter.name }}/src/core/conf/boilerplate.py similarity index 100% rename from {{cookiecutter.name}}/src/core/conf/boilerplate.py rename to {{ cookiecutter.name }}/src/core/conf/boilerplate.py diff --git a/{{cookiecutter.name}}/src/core/conf/db.py b/{{ cookiecutter.name }}/src/core/conf/db.py similarity index 100% rename from {{cookiecutter.name}}/src/core/conf/db.py rename to {{ cookiecutter.name }}/src/core/conf/db.py diff --git a/{{cookiecutter.name}}/src/core/conf/environ.py b/{{ cookiecutter.name }}/src/core/conf/environ.py similarity index 100% rename from {{cookiecutter.name}}/src/core/conf/environ.py rename to {{ cookiecutter.name }}/src/core/conf/environ.py diff --git a/{{cookiecutter.name}}/src/core/conf/healthchecks.py b/{{ cookiecutter.name }}/src/core/conf/healthchecks.py similarity index 100% rename from {{cookiecutter.name}}/src/core/conf/healthchecks.py rename to {{ cookiecutter.name }}/src/core/conf/healthchecks.py diff --git a/{{cookiecutter.name}}/src/core/conf/http.py b/{{ cookiecutter.name }}/src/core/conf/http.py similarity index 100% rename from {{cookiecutter.name}}/src/core/conf/http.py rename to {{ cookiecutter.name }}/src/core/conf/http.py diff --git a/{{cookiecutter.name}}/src/core/conf/i18n.py b/{{ cookiecutter.name }}/src/core/conf/i18n.py similarity index 100% rename from {{cookiecutter.name}}/src/core/conf/i18n.py rename to {{ cookiecutter.name }}/src/core/conf/i18n.py diff --git a/{{cookiecutter.name}}/src/core/conf/installed_apps.py b/{{ cookiecutter.name }}/src/core/conf/installed_apps.py similarity index 100% rename from {{cookiecutter.name}}/src/core/conf/installed_apps.py rename to {{ cookiecutter.name }}/src/core/conf/installed_apps.py diff --git a/{{cookiecutter.name}}/src/core/conf/media.py b/{{ cookiecutter.name }}/src/core/conf/media.py similarity index 100% rename from {{cookiecutter.name}}/src/core/conf/media.py rename to {{ cookiecutter.name }}/src/core/conf/media.py diff --git a/{{cookiecutter.name}}/src/core/conf/middleware.py b/{{ cookiecutter.name }}/src/core/conf/middleware.py similarity index 100% rename from {{cookiecutter.name}}/src/core/conf/middleware.py rename to {{ cookiecutter.name }}/src/core/conf/middleware.py diff --git a/{{cookiecutter.name}}/src/core/conf/sentry.py b/{{ cookiecutter.name }}/src/core/conf/sentry.py similarity index 100% rename from {{cookiecutter.name}}/src/core/conf/sentry.py rename to {{ cookiecutter.name }}/src/core/conf/sentry.py diff --git a/{{cookiecutter.name}}/src/core/conf/static.py b/{{ cookiecutter.name }}/src/core/conf/static.py similarity index 100% rename from {{cookiecutter.name}}/src/core/conf/static.py rename to {{ cookiecutter.name }}/src/core/conf/static.py diff --git a/{{cookiecutter.name}}/src/core/conf/storage.py b/{{ cookiecutter.name }}/src/core/conf/storage.py similarity index 100% rename from {{cookiecutter.name}}/src/core/conf/storage.py rename to {{ cookiecutter.name }}/src/core/conf/storage.py diff --git a/{{cookiecutter.name}}/src/core/conf/templates.py b/{{ cookiecutter.name }}/src/core/conf/templates.py similarity index 100% rename from {{cookiecutter.name}}/src/core/conf/templates.py rename to {{ cookiecutter.name }}/src/core/conf/templates.py diff --git a/{{cookiecutter.name}}/src/core/conf/timezone.py b/{{ cookiecutter.name }}/src/core/conf/timezone.py similarity index 100% rename from {{cookiecutter.name}}/src/core/conf/timezone.py rename to {{ cookiecutter.name }}/src/core/conf/timezone.py diff --git a/{{cookiecutter.name}}/src/core/management/commands/makemigrations.py b/{{ cookiecutter.name }}/src/core/management/commands/makemigrations.py similarity index 100% rename from {{cookiecutter.name}}/src/core/management/commands/makemigrations.py rename to {{ cookiecutter.name }}/src/core/management/commands/makemigrations.py diff --git a/{{cookiecutter.name}}/src/core/management/commands/startapp.py b/{{ cookiecutter.name }}/src/core/management/commands/startapp.py similarity index 100% rename from {{cookiecutter.name}}/src/core/management/commands/startapp.py rename to {{ cookiecutter.name }}/src/core/management/commands/startapp.py diff --git a/{{cookiecutter.name}}/src/core/middleware/real_ip.py b/{{ cookiecutter.name }}/src/core/middleware/real_ip.py similarity index 100% rename from {{cookiecutter.name}}/src/core/middleware/real_ip.py rename to {{ cookiecutter.name }}/src/core/middleware/real_ip.py diff --git a/{{cookiecutter.name}}/src/core/models.py b/{{ cookiecutter.name }}/src/core/models.py similarity index 100% rename from {{cookiecutter.name}}/src/core/models.py rename to {{ cookiecutter.name }}/src/core/models.py diff --git a/{{cookiecutter.name}}/src/core/services.py b/{{ cookiecutter.name }}/src/core/services.py similarity index 100% rename from {{cookiecutter.name}}/src/core/services.py rename to {{ cookiecutter.name }}/src/core/services.py diff --git a/{{cookiecutter.name}}/src/core/settings.py b/{{ cookiecutter.name }}/src/core/settings.py similarity index 100% rename from {{cookiecutter.name}}/src/core/settings.py rename to {{ cookiecutter.name }}/src/core/settings.py diff --git a/{{cookiecutter.name}}/src/core/testing/__init__.py b/{{ cookiecutter.name }}/src/core/testing/__init__.py similarity index 100% rename from {{cookiecutter.name}}/src/core/testing/__init__.py rename to {{ cookiecutter.name }}/src/core/testing/__init__.py diff --git a/{{cookiecutter.name}}/src/core/testing/api.py b/{{ cookiecutter.name }}/src/core/testing/api.py similarity index 100% rename from {{cookiecutter.name}}/src/core/testing/api.py rename to {{ cookiecutter.name }}/src/core/testing/api.py diff --git a/{{cookiecutter.name}}/src/core/testing/factory.py b/{{ cookiecutter.name }}/src/core/testing/factory.py similarity index 100% rename from {{cookiecutter.name}}/src/core/testing/factory.py rename to {{ cookiecutter.name }}/src/core/testing/factory.py diff --git a/{{cookiecutter.name}}/src/core/testing/mixer.py b/{{ cookiecutter.name }}/src/core/testing/mixer.py similarity index 100% rename from {{cookiecutter.name}}/src/core/testing/mixer.py rename to {{ cookiecutter.name }}/src/core/testing/mixer.py diff --git a/{{cookiecutter.name}}/src/core/testing/runner.py b/{{ cookiecutter.name }}/src/core/testing/runner.py similarity index 100% rename from {{cookiecutter.name}}/src/core/testing/runner.py rename to {{ cookiecutter.name }}/src/core/testing/runner.py diff --git a/{{cookiecutter.name}}/src/core/testing/types.py b/{{ cookiecutter.name }}/src/core/testing/types.py similarity index 100% rename from {{cookiecutter.name}}/src/core/testing/types.py rename to {{ cookiecutter.name }}/src/core/testing/types.py diff --git a/{{cookiecutter.name}}/src/core/urls/__init__.py b/{{ cookiecutter.name }}/src/core/urls/__init__.py similarity index 100% rename from {{cookiecutter.name}}/src/core/urls/__init__.py rename to {{ cookiecutter.name }}/src/core/urls/__init__.py diff --git a/{{cookiecutter.name}}/src/core/urls/v1.py b/{{ cookiecutter.name }}/src/core/urls/v1.py similarity index 100% rename from {{cookiecutter.name}}/src/core/urls/v1.py rename to {{ cookiecutter.name }}/src/core/urls/v1.py diff --git a/{{cookiecutter.name}}/src/core/wsgi.py b/{{ cookiecutter.name }}/src/core/wsgi.py similarity index 100% rename from {{cookiecutter.name}}/src/core/wsgi.py rename to {{ cookiecutter.name }}/src/core/wsgi.py diff --git a/{{cookiecutter.name}}/src/manage.py b/{{ cookiecutter.name }}/src/manage.py similarity index 100% rename from {{cookiecutter.name}}/src/manage.py rename to {{ cookiecutter.name }}/src/manage.py diff --git a/{{cookiecutter.name}}/tests/__init__.py b/{{ cookiecutter.name }}/tests/__init__.py similarity index 100% rename from {{cookiecutter.name}}/tests/__init__.py rename to {{ cookiecutter.name }}/tests/__init__.py diff --git a/{{cookiecutter.name}}/tests/apps/a12n/jwt_views/test_obtain_jwt_view.py b/{{ cookiecutter.name }}/tests/apps/a12n/jwt_views/test_obtain_jwt_view.py similarity index 100% rename from {{cookiecutter.name}}/tests/apps/a12n/jwt_views/test_obtain_jwt_view.py rename to {{ cookiecutter.name }}/tests/apps/a12n/jwt_views/test_obtain_jwt_view.py diff --git a/{{cookiecutter.name}}/tests/apps/a12n/jwt_views/test_refresh_jwt_token.py b/{{ cookiecutter.name }}/tests/apps/a12n/jwt_views/test_refresh_jwt_token.py similarity index 100% rename from {{cookiecutter.name}}/tests/apps/a12n/jwt_views/test_refresh_jwt_token.py rename to {{ cookiecutter.name }}/tests/apps/a12n/jwt_views/test_refresh_jwt_token.py diff --git a/{{cookiecutter.name}}/tests/apps/users/factory.py b/{{ cookiecutter.name }}/tests/apps/users/factory.py similarity index 100% rename from {{cookiecutter.name}}/tests/apps/users/factory.py rename to {{ cookiecutter.name }}/tests/apps/users/factory.py diff --git a/{{cookiecutter.name}}/tests/apps/users/fixtures.py b/{{ cookiecutter.name }}/tests/apps/users/fixtures.py similarity index 100% rename from {{cookiecutter.name}}/tests/apps/users/fixtures.py rename to {{ cookiecutter.name }}/tests/apps/users/fixtures.py diff --git a/{{cookiecutter.name}}/tests/apps/users/test_password_hashing.py b/{{ cookiecutter.name }}/tests/apps/users/test_password_hashing.py similarity index 100% rename from {{cookiecutter.name}}/tests/apps/users/test_password_hashing.py rename to {{ cookiecutter.name }}/tests/apps/users/test_password_hashing.py diff --git a/{{cookiecutter.name}}/tests/apps/users/test_whoami.py b/{{ cookiecutter.name }}/tests/apps/users/test_whoami.py similarity index 100% rename from {{cookiecutter.name}}/tests/apps/users/test_whoami.py rename to {{ cookiecutter.name }}/tests/apps/users/test_whoami.py diff --git a/{{cookiecutter.name}}/tests/conftest.py b/{{ cookiecutter.name }}/tests/conftest.py similarity index 100% rename from {{cookiecutter.name}}/tests/conftest.py rename to {{ cookiecutter.name }}/tests/conftest.py diff --git a/{{cookiecutter.name}}/tests/core/__init__.py b/{{ cookiecutter.name }}/tests/core/__init__.py similarity index 100% rename from {{cookiecutter.name}}/tests/core/__init__.py rename to {{ cookiecutter.name }}/tests/core/__init__.py diff --git a/{{cookiecutter.name}}/tests/core/factory.py b/{{ cookiecutter.name }}/tests/core/factory.py similarity index 100% rename from {{cookiecutter.name}}/tests/core/factory.py rename to {{ cookiecutter.name }}/tests/core/factory.py diff --git a/{{cookiecutter.name}}/tests/core/fixtures.py b/{{ cookiecutter.name }}/tests/core/fixtures.py similarity index 100% rename from {{cookiecutter.name}}/tests/core/fixtures.py rename to {{ cookiecutter.name }}/tests/core/fixtures.py diff --git a/{{cookiecutter.name}}/tests/core/test_health.py b/{{ cookiecutter.name }}/tests/core/test_health.py similarity index 100% rename from {{cookiecutter.name}}/tests/core/test_health.py rename to {{ cookiecutter.name }}/tests/core/test_health.py diff --git a/{{cookiecutter.name}}/tests/core/test_remote_addr_midlleware.py b/{{ cookiecutter.name }}/tests/core/test_remote_addr_midlleware.py similarity index 100% rename from {{cookiecutter.name}}/tests/core/test_remote_addr_midlleware.py rename to {{ cookiecutter.name }}/tests/core/test_remote_addr_midlleware.py diff --git a/{{cookiecutter.name}}/tests/core/testing/__init__.py b/{{ cookiecutter.name }}/tests/core/testing/__init__.py similarity index 100% rename from {{cookiecutter.name}}/tests/core/testing/__init__.py rename to {{ cookiecutter.name }}/tests/core/testing/__init__.py diff --git a/{{cookiecutter.name}}/tests/core/testing/factory/__init__.py b/{{ cookiecutter.name }}/tests/core/testing/factory/__init__.py similarity index 100% rename from {{cookiecutter.name}}/tests/core/testing/factory/__init__.py rename to {{ cookiecutter.name }}/tests/core/testing/factory/__init__.py diff --git a/{{cookiecutter.name}}/tests/core/testing/factory/test_factory.py b/{{ cookiecutter.name }}/tests/core/testing/factory/test_factory.py similarity index 100% rename from {{cookiecutter.name}}/tests/core/testing/factory/test_factory.py rename to {{ cookiecutter.name }}/tests/core/testing/factory/test_factory.py diff --git a/{{cookiecutter.name}}/tests/core/testing/factory/test_registry.py b/{{ cookiecutter.name }}/tests/core/testing/factory/test_registry.py similarity index 100% rename from {{cookiecutter.name}}/tests/core/testing/factory/test_registry.py rename to {{ cookiecutter.name }}/tests/core/testing/factory/test_registry.py From 927715d8cab5b8cbe96019ebd02514e6cadb61df Mon Sep 17 00:00:00 2001 From: hnthh Date: Tue, 5 Dec 2023 23:17:46 +0300 Subject: [PATCH 040/116] bump child proj ci postgres, redis versions --- .github/actions/build/action.yml | 8 +- .gitignore | 4 +- .../.github/workflows/ci.yml | 15 +- {{ cookiecutter.name }}/poetry.lock | 2475 ----------------- 4 files changed, 12 insertions(+), 2490 deletions(-) delete mode 100644 {{ cookiecutter.name }}/poetry.lock diff --git a/.github/actions/build/action.yml b/.github/actions/build/action.yml index 88d1ba5d..f04b86bd 100644 --- a/.github/actions/build/action.yml +++ b/.github/actions/build/action.yml @@ -12,7 +12,7 @@ runs: key: poetry-v1-${{ hashFiles('pyproject.toml') }} - name: install poetry - if: steps.cached-poetry.outputs.cache-hit != 'true' + if: steps.cached-poetry.outputs.cache-hit != true uses: snok/install-poetry@v1 with: version: 1.6.1 @@ -21,14 +21,14 @@ runs: id: setup-python uses: actions/setup-python@v4 with: - cache: 'poetry' - python-version-file: 'pyproject.toml' + cache: poetry + python-version-file: pyproject.toml - name: make sure poetry lockfile is up to date run: poetry check --lock shell: bash - name: install deps - if: steps.setup-python.outputs.cache-hit != 'true' + if: steps.setup-python.outputs.cache-hit != true run: poetry install --no-interaction --no-root shell: bash diff --git a/.gitignore b/.gitignore index 632efcf4..33c25fd8 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,8 @@ .vscode **/.DS_Store -**/db.sqlite + +{{ cookiecutter.name }}/db.sqlite +{{ cookiecutter.name }}/poetry.lock testproject diff --git a/{{ cookiecutter.name }}/.github/workflows/ci.yml b/{{ cookiecutter.name }}/.github/workflows/ci.yml index 6f457aeb..5c909314 100644 --- a/{{ cookiecutter.name }}/.github/workflows/ci.yml +++ b/{{ cookiecutter.name }}/.github/workflows/ci.yml @@ -16,22 +16,16 @@ jobs: - name: build uses: ./.github/actions/build - - name: restore mypy cache - uses: actions/cache@v3 - with: - path: .mypy_cache - key: mypy-cache-${{ github.ref_name }} - restore-keys: mypy-cache-master - - name: checks run: make checks test: needs: checks - runs-on: ${{ contains(github.triggering_actor, "[bot]") && "ubuntu-latest" || "ubuntu-8x" }} + runs-on: ubuntu-latest + services: postgres: - image: postgres:13.9-alpine + image: postgres:16.1-alpine env: POSTGRES_PASSWORD: secret options: >- @@ -41,8 +35,9 @@ jobs: --health-retries 5 ports: - 5432:5432 + redis: - image: redis:6.2.10-alpine + image: redis:7.2.3-alpine ports: - 6379:6379 diff --git a/{{ cookiecutter.name }}/poetry.lock b/{{ cookiecutter.name }}/poetry.lock deleted file mode 100644 index 51b91988..00000000 --- a/{{ cookiecutter.name }}/poetry.lock +++ /dev/null @@ -1,2475 +0,0 @@ -# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. - -[[package]] -name = "application-properties" -version = "0.8.1" -description = "A simple, easy to use, unified manner of accessing program properties." -optional = false -python-versions = ">=3.8.0" -files = [ - {file = "application_properties-0.8.1-py3-none-any.whl", hash = "sha256:f442e403ab7c8f97b048cf0ab92845057d595989653f65ced48579ad7cf35607"}, - {file = "application_properties-0.8.1.tar.gz", hash = "sha256:101667125383940651e72a2a9b3aa32225f359050c3be45b4ef4b51009930bb4"}, -] - -[package.dependencies] -pyyaml = ">=6.0" -tomli = ">=2.0.1" -typing-extensions = ">=4.5.0" - -[[package]] -name = "asgiref" -version = "3.7.2" -description = "ASGI specs, helper code, and adapters" -optional = false -python-versions = ">=3.7" -files = [ - {file = "asgiref-3.7.2-py3-none-any.whl", hash = "sha256:89b2ef2247e3b562a16eef663bc0e2e703ec6468e2fa8a5cd61cd449786d4f6e"}, - {file = "asgiref-3.7.2.tar.gz", hash = "sha256:9e0ce3aa93a819ba5b45120216b23878cf6e8525eb3848653452b4192b92afed"}, -] - -[package.extras] -tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] - -[[package]] -name = "astroid" -version = "2.15.8" -description = "An abstract syntax tree for Python with inference support." -optional = false -python-versions = ">=3.7.2" -files = [ - {file = "astroid-2.15.8-py3-none-any.whl", hash = "sha256:1aa149fc5c6589e3d0ece885b4491acd80af4f087baafa3fb5203b113e68cd3c"}, - {file = "astroid-2.15.8.tar.gz", hash = "sha256:6c107453dffee9055899705de3c9ead36e74119cee151e5a9aaf7f0b0e020a6a"}, -] - -[package.dependencies] -lazy-object-proxy = ">=1.4.0" -wrapt = {version = ">=1.14,<2", markers = "python_version >= \"3.11\""} - -[[package]] -name = "asttokens" -version = "2.4.1" -description = "Annotate AST trees with source code positions" -optional = false -python-versions = "*" -files = [ - {file = "asttokens-2.4.1-py2.py3-none-any.whl", hash = "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24"}, - {file = "asttokens-2.4.1.tar.gz", hash = "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0"}, -] - -[package.dependencies] -six = ">=1.12.0" - -[package.extras] -astroid = ["astroid (>=1,<2)", "astroid (>=2,<4)"] -test = ["astroid (>=1,<2)", "astroid (>=2,<4)", "pytest"] - -[[package]] -name = "async-timeout" -version = "4.0.3" -description = "Timeout context manager for asyncio programs" -optional = false -python-versions = ">=3.7" -files = [ - {file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"}, - {file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"}, -] - -[[package]] -name = "attrs" -version = "23.1.0" -description = "Classes Without Boilerplate" -optional = false -python-versions = ">=3.7" -files = [ - {file = "attrs-23.1.0-py3-none-any.whl", hash = "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"}, - {file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"}, -] - -[package.extras] -cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] -dev = ["attrs[docs,tests]", "pre-commit"] -docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] -tests = ["attrs[tests-no-zope]", "zope-interface"] -tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] - -[[package]] -name = "autoflake" -version = "2.2.1" -description = "Removes unused imports and unused variables" -optional = false -python-versions = ">=3.8" -files = [ - {file = "autoflake-2.2.1-py3-none-any.whl", hash = "sha256:265cde0a43c1f44ecfb4f30d95b0437796759d07be7706a2f70e4719234c0f79"}, - {file = "autoflake-2.2.1.tar.gz", hash = "sha256:62b7b6449a692c3c9b0c916919bbc21648da7281e8506bcf8d3f8280e431ebc1"}, -] - -[package.dependencies] -pyflakes = ">=3.0.0" - -[[package]] -name = "bcrypt" -version = "4.0.1" -description = "Modern password hashing for your software and your servers" -optional = false -python-versions = ">=3.6" -files = [ - {file = "bcrypt-4.0.1-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:b1023030aec778185a6c16cf70f359cbb6e0c289fd564a7cfa29e727a1c38f8f"}, - {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:08d2947c490093a11416df18043c27abe3921558d2c03e2076ccb28a116cb6d0"}, - {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0eaa47d4661c326bfc9d08d16debbc4edf78778e6aaba29c1bc7ce67214d4410"}, - {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ae88eca3024bb34bb3430f964beab71226e761f51b912de5133470b649d82344"}, - {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:a522427293d77e1c29e303fc282e2d71864579527a04ddcfda6d4f8396c6c36a"}, - {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:fbdaec13c5105f0c4e5c52614d04f0bca5f5af007910daa8b6b12095edaa67b3"}, - {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:ca3204d00d3cb2dfed07f2d74a25f12fc12f73e606fcaa6975d1f7ae69cacbb2"}, - {file = "bcrypt-4.0.1-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:089098effa1bc35dc055366740a067a2fc76987e8ec75349eb9484061c54f535"}, - {file = "bcrypt-4.0.1-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:e9a51bbfe7e9802b5f3508687758b564069ba937748ad7b9e890086290d2f79e"}, - {file = "bcrypt-4.0.1-cp36-abi3-win32.whl", hash = "sha256:2caffdae059e06ac23fce178d31b4a702f2a3264c20bfb5ff541b338194d8fab"}, - {file = "bcrypt-4.0.1-cp36-abi3-win_amd64.whl", hash = "sha256:8a68f4341daf7522fe8d73874de8906f3a339048ba406be6ddc1b3ccb16fc0d9"}, - {file = "bcrypt-4.0.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf4fa8b2ca74381bb5442c089350f09a3f17797829d958fad058d6e44d9eb83c"}, - {file = "bcrypt-4.0.1-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:67a97e1c405b24f19d08890e7ae0c4f7ce1e56a712a016746c8b2d7732d65d4b"}, - {file = "bcrypt-4.0.1-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b3b85202d95dd568efcb35b53936c5e3b3600c7cdcc6115ba461df3a8e89f38d"}, - {file = "bcrypt-4.0.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbb03eec97496166b704ed663a53680ab57c5084b2fc98ef23291987b525cb7d"}, - {file = "bcrypt-4.0.1-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:5ad4d32a28b80c5fa6671ccfb43676e8c1cc232887759d1cd7b6f56ea4355215"}, - {file = "bcrypt-4.0.1-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b57adba8a1444faf784394de3436233728a1ecaeb6e07e8c22c8848f179b893c"}, - {file = "bcrypt-4.0.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:705b2cea8a9ed3d55b4491887ceadb0106acf7c6387699fca771af56b1cdeeda"}, - {file = "bcrypt-4.0.1-pp39-pypy39_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:2b3ac11cf45161628f1f3733263e63194f22664bf4d0c0f3ab34099c02134665"}, - {file = "bcrypt-4.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:3100851841186c25f127731b9fa11909ab7b1df6fc4b9f8353f4f1fd952fbf71"}, - {file = "bcrypt-4.0.1.tar.gz", hash = "sha256:27d375903ac8261cfe4047f6709d16f7d18d39b1ec92aaf72af989552a650ebd"}, -] - -[package.extras] -tests = ["pytest (>=3.2.1,!=3.3.0)"] -typecheck = ["mypy"] - -[[package]] -name = "black" -version = "23.11.0" -description = "The uncompromising code formatter." -optional = false -python-versions = ">=3.8" -files = [ - {file = "black-23.11.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dbea0bb8575c6b6303cc65017b46351dc5953eea5c0a59d7b7e3a2d2f433a911"}, - {file = "black-23.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:412f56bab20ac85927f3a959230331de5614aecda1ede14b373083f62ec24e6f"}, - {file = "black-23.11.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d136ef5b418c81660ad847efe0e55c58c8208b77a57a28a503a5f345ccf01394"}, - {file = "black-23.11.0-cp310-cp310-win_amd64.whl", hash = "sha256:6c1cac07e64433f646a9a838cdc00c9768b3c362805afc3fce341af0e6a9ae9f"}, - {file = "black-23.11.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cf57719e581cfd48c4efe28543fea3d139c6b6f1238b3f0102a9c73992cbb479"}, - {file = "black-23.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:698c1e0d5c43354ec5d6f4d914d0d553a9ada56c85415700b81dc90125aac244"}, - {file = "black-23.11.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:760415ccc20f9e8747084169110ef75d545f3b0932ee21368f63ac0fee86b221"}, - {file = "black-23.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:58e5f4d08a205b11800332920e285bd25e1a75c54953e05502052738fe16b3b5"}, - {file = "black-23.11.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:45aa1d4675964946e53ab81aeec7a37613c1cb71647b5394779e6efb79d6d187"}, - {file = "black-23.11.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4c44b7211a3a0570cc097e81135faa5f261264f4dfaa22bd5ee2875a4e773bd6"}, - {file = "black-23.11.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a9acad1451632021ee0d146c8765782a0c3846e0e0ea46659d7c4f89d9b212b"}, - {file = "black-23.11.0-cp38-cp38-win_amd64.whl", hash = "sha256:fc7f6a44d52747e65a02558e1d807c82df1d66ffa80a601862040a43ec2e3142"}, - {file = "black-23.11.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7f622b6822f02bfaf2a5cd31fdb7cd86fcf33dab6ced5185c35f5db98260b055"}, - {file = "black-23.11.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:250d7e60f323fcfc8ea6c800d5eba12f7967400eb6c2d21ae85ad31c204fb1f4"}, - {file = "black-23.11.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5133f5507007ba08d8b7b263c7aa0f931af5ba88a29beacc4b2dc23fcefe9c06"}, - {file = "black-23.11.0-cp39-cp39-win_amd64.whl", hash = "sha256:421f3e44aa67138ab1b9bfbc22ee3780b22fa5b291e4db8ab7eee95200726b07"}, - {file = "black-23.11.0-py3-none-any.whl", hash = "sha256:54caaa703227c6e0c87b76326d0862184729a69b73d3b7305b6288e1d830067e"}, - {file = "black-23.11.0.tar.gz", hash = "sha256:4c68855825ff432d197229846f971bc4d6666ce90492e5b02013bcaca4d9ab05"}, -] - -[package.dependencies] -click = ">=8.0.0" -mypy-extensions = ">=0.4.3" -packaging = ">=22.0" -pathspec = ">=0.9.0" -platformdirs = ">=2" - -[package.extras] -colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)"] -jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] -uvloop = ["uvloop (>=0.15.2)"] - -[[package]] -name = "certifi" -version = "2023.11.17" -description = "Python package for providing Mozilla's CA Bundle." -optional = false -python-versions = ">=3.6" -files = [ - {file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"}, - {file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"}, -] - -[[package]] -name = "cffi" -version = "1.16.0" -description = "Foreign Function Interface for Python calling C code." -optional = false -python-versions = ">=3.8" -files = [ - {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, - {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, - {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, - {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, - {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, - {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, - {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, - {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, - {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, - {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, - {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, - {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, - {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"}, - {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"}, - {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"}, - {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"}, - {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"}, - {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"}, - {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"}, - {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"}, - {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, - {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, - {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, - {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, - {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, - {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, - {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, -] - -[package.dependencies] -pycparser = "*" - -[[package]] -name = "charset-normalizer" -version = "3.3.2" -description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -optional = false -python-versions = ">=3.7.0" -files = [ - {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, - {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, -] - -[[package]] -name = "click" -version = "8.1.7" -description = "Composable command line interface toolkit" -optional = false -python-versions = ">=3.7" -files = [ - {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, - {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "platform_system == \"Windows\""} - -[[package]] -name = "click-default-group" -version = "1.2.4" -description = "click_default_group" -optional = false -python-versions = ">=2.7" -files = [ - {file = "click_default_group-1.2.4-py2.py3-none-any.whl", hash = "sha256:9b60486923720e7fc61731bdb32b617039aba820e22e1c88766b1125592eaa5f"}, - {file = "click_default_group-1.2.4.tar.gz", hash = "sha256:eb3f3c99ec0d456ca6cd2a7f08f7d4e91771bef51b01bdd9580cc6450fe1251e"}, -] - -[package.dependencies] -click = "*" - -[package.extras] -test = ["pytest"] - -[[package]] -name = "cognitive-complexity" -version = "1.3.0" -description = "Library to calculate Python functions cognitive complexity via code" -optional = false -python-versions = ">=3.6" -files = [ - {file = "cognitive_complexity-1.3.0.tar.gz", hash = "sha256:a0cfbd47dee0b19f4056f892389f501694b205c3af69fb703cc744541e03dde5"}, -] - -[package.dependencies] -setuptools = "*" - -[[package]] -name = "colorama" -version = "0.4.6" -description = "Cross-platform colored terminal text." -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -files = [ - {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, - {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, -] - -[[package]] -name = "columnar" -version = "1.4.1" -description = "A tool for printing data in a columnar format." -optional = false -python-versions = "*" -files = [ - {file = "Columnar-1.4.1-py3-none-any.whl", hash = "sha256:8efb692a7e6ca07dcc8f4ea889960421331a5dffa8e5af81f0a67ad8ea1fc798"}, - {file = "Columnar-1.4.1.tar.gz", hash = "sha256:c3cb57273333b2ff9cfaafc86f09307419330c97faa88dcfe23df05e6fbb9c72"}, -] - -[package.dependencies] -toolz = "*" -wcwidth = "*" - -[[package]] -name = "cryptography" -version = "41.0.5" -description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." -optional = false -python-versions = ">=3.7" -files = [ - {file = "cryptography-41.0.5-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:da6a0ff8f1016ccc7477e6339e1d50ce5f59b88905585f77193ebd5068f1e797"}, - {file = "cryptography-41.0.5-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:b948e09fe5fb18517d99994184854ebd50b57248736fd4c720ad540560174ec5"}, - {file = "cryptography-41.0.5-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d38e6031e113b7421db1de0c1b1f7739564a88f1684c6b89234fbf6c11b75147"}, - {file = "cryptography-41.0.5-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e270c04f4d9b5671ebcc792b3ba5d4488bf7c42c3c241a3748e2599776f29696"}, - {file = "cryptography-41.0.5-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ec3b055ff8f1dce8e6ef28f626e0972981475173d7973d63f271b29c8a2897da"}, - {file = "cryptography-41.0.5-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:7d208c21e47940369accfc9e85f0de7693d9a5d843c2509b3846b2db170dfd20"}, - {file = "cryptography-41.0.5-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:8254962e6ba1f4d2090c44daf50a547cd5f0bf446dc658a8e5f8156cae0d8548"}, - {file = "cryptography-41.0.5-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:a48e74dad1fb349f3dc1d449ed88e0017d792997a7ad2ec9587ed17405667e6d"}, - {file = "cryptography-41.0.5-cp37-abi3-win32.whl", hash = "sha256:d3977f0e276f6f5bf245c403156673db103283266601405376f075c849a0b936"}, - {file = "cryptography-41.0.5-cp37-abi3-win_amd64.whl", hash = "sha256:73801ac9736741f220e20435f84ecec75ed70eda90f781a148f1bad546963d81"}, - {file = "cryptography-41.0.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3be3ca726e1572517d2bef99a818378bbcf7d7799d5372a46c79c29eb8d166c1"}, - {file = "cryptography-41.0.5-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:e886098619d3815e0ad5790c973afeee2c0e6e04b4da90b88e6bd06e2a0b1b72"}, - {file = "cryptography-41.0.5-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:573eb7128cbca75f9157dcde974781209463ce56b5804983e11a1c462f0f4e88"}, - {file = "cryptography-41.0.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0c327cac00f082013c7c9fb6c46b7cc9fa3c288ca702c74773968173bda421bf"}, - {file = "cryptography-41.0.5-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:227ec057cd32a41c6651701abc0328135e472ed450f47c2766f23267b792a88e"}, - {file = "cryptography-41.0.5-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:22892cc830d8b2c89ea60148227631bb96a7da0c1b722f2aac8824b1b7c0b6b8"}, - {file = "cryptography-41.0.5-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:5a70187954ba7292c7876734183e810b728b4f3965fbe571421cb2434d279179"}, - {file = "cryptography-41.0.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:88417bff20162f635f24f849ab182b092697922088b477a7abd6664ddd82291d"}, - {file = "cryptography-41.0.5-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c707f7afd813478e2019ae32a7c49cd932dd60ab2d2a93e796f68236b7e1fbf1"}, - {file = "cryptography-41.0.5-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:580afc7b7216deeb87a098ef0674d6ee34ab55993140838b14c9b83312b37b86"}, - {file = "cryptography-41.0.5-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fba1e91467c65fe64a82c689dc6cf58151158993b13eb7a7f3f4b7f395636723"}, - {file = "cryptography-41.0.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:0d2a6a598847c46e3e321a7aef8af1436f11c27f1254933746304ff014664d84"}, - {file = "cryptography-41.0.5.tar.gz", hash = "sha256:392cb88b597247177172e02da6b7a63deeff1937fa6fec3bbf902ebd75d97ec7"}, -] - -[package.dependencies] -cffi = ">=1.12" - -[package.extras] -docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"] -docstest = ["pyenchant (>=1.6.11)", "sphinxcontrib-spelling (>=4.0.1)", "twine (>=1.12.0)"] -nox = ["nox"] -pep8test = ["black", "check-sdist", "mypy", "ruff"] -sdist = ["build"] -ssh = ["bcrypt (>=3.1.5)"] -test = ["pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] -test-randomorder = ["pytest-randomly"] - -[[package]] -name = "decorator" -version = "5.1.1" -description = "Decorators for Humans" -optional = false -python-versions = ">=3.5" -files = [ - {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"}, - {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, -] - -[[package]] -name = "django" -version = "4.2.7" -description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." -optional = false -python-versions = ">=3.8" -files = [ - {file = "Django-4.2.7-py3-none-any.whl", hash = "sha256:e1d37c51ad26186de355cbcec16613ebdabfa9689bbade9c538835205a8abbe9"}, - {file = "Django-4.2.7.tar.gz", hash = "sha256:8e0f1c2c2786b5c0e39fe1afce24c926040fad47c8ea8ad30aaf1188df29fc41"}, -] - -[package.dependencies] -asgiref = ">=3.6.0,<4" -sqlparse = ">=0.3.1" -tzdata = {version = "*", markers = "sys_platform == \"win32\""} - -[package.extras] -argon2 = ["argon2-cffi (>=19.1.0)"] -bcrypt = ["bcrypt"] - -[[package]] -name = "django-axes" -version = "6.1.1" -description = "Keep track of failed login attempts in Django-powered sites." -optional = false -python-versions = ">=3.7" -files = [ - {file = "django-axes-6.1.1.tar.gz", hash = "sha256:cd1bc4f7becc8e9243eb4090dffa258d7d7125ca0ce3153b6ffc920bccbf2c3f"}, - {file = "django_axes-6.1.1-py3-none-any.whl", hash = "sha256:29c48ff5f09046afd5e9a16e96d3bbb79f6c11c59f0a7bbd732559e60d0aa9fa"}, -] - -[package.dependencies] -django = ">=3.2" -setuptools = "*" - -[package.extras] -ipware = ["django-ipware (>=3)"] - -[[package]] -name = "django-behaviors" -version = "0.5.1" -description = "Common behaviors for Django Models, e.g. Timestamps, Publishing, Authoring/Editing and more." -optional = false -python-versions = "*" -files = [ - {file = "django-behaviors-0.5.1.tar.gz", hash = "sha256:75e6828573c25ffa71c8ce6c568d294fc659b3b6d572507b012ce70fbb27aaff"}, - {file = "django_behaviors-0.5.1-py2.py3-none-any.whl", hash = "sha256:1ac2ec9c9e919ca4b962f9dee861a53f5af27749c8d13a21077b5a61fb879501"}, -] - -[[package]] -name = "django-environ" -version = "0.11.2" -description = "A package that allows you to utilize 12factor inspired environment variables to configure your Django application." -optional = false -python-versions = ">=3.6,<4" -files = [ - {file = "django-environ-0.11.2.tar.gz", hash = "sha256:f32a87aa0899894c27d4e1776fa6b477e8164ed7f6b3e410a62a6d72caaf64be"}, - {file = "django_environ-0.11.2-py2.py3-none-any.whl", hash = "sha256:0ff95ab4344bfeff693836aa978e6840abef2e2f1145adff7735892711590c05"}, -] - -[package.extras] -develop = ["coverage[toml] (>=5.0a4)", "furo (>=2021.8.17b43,<2021.9.dev0)", "pytest (>=4.6.11)", "sphinx (>=3.5.0)", "sphinx-notfound-page"] -docs = ["furo (>=2021.8.17b43,<2021.9.dev0)", "sphinx (>=3.5.0)", "sphinx-notfound-page"] -testing = ["coverage[toml] (>=5.0a4)", "pytest (>=4.6.11)"] - -[[package]] -name = "django-filter" -version = "23.4" -description = "Django-filter is a reusable Django application for allowing users to filter querysets dynamically." -optional = false -python-versions = ">=3.7" -files = [ - {file = "django-filter-23.4.tar.gz", hash = "sha256:bed070b38359dce7d2dbe057b165d59773057986356cb809ded983b36c77a976"}, - {file = "django_filter-23.4-py3-none-any.whl", hash = "sha256:526954f18bd7d6423f232a9a7974f58fbc6863908b9fc160de075e01adcc2a5f"}, -] - -[package.dependencies] -Django = ">=3.2" - -[[package]] -name = "django-healthchecks" -version = "1.5.0" -description = "Simple Django app/framework to publish health checks" -optional = false -python-versions = "*" -files = [ - {file = "django-healthchecks-1.5.0.tar.gz", hash = "sha256:0f167deaa30bde59552796799abf2a97a118bc190e8601eef713379703cf9f64"}, - {file = "django_healthchecks-1.5.0-py2.py3-none-any.whl", hash = "sha256:25eb021a4a94240b28d996e82775ad6c3b392a2b262360b965a24b88fcfad78d"}, -] - -[package.dependencies] -certifi = ">=2020.6.20" -Django = ">=3.2" -requests = ">=2.24.0" - -[package.extras] -docs = ["sphinx (>=1.4.0)"] -test = ["coverage[toml] (==5.2)", "flake8 (==3.8.3)", "flake8-blind-except (==0.1.1)", "flake8-debugger (==3.2.1)", "freezegun (==0.3.15)", "isort (==5.0.6)", "pytest (==6.2.5)", "pytest-django (==3.9.0)", "requests-mock (==1.8.0)"] - -[[package]] -name = "django-ipware" -version = "6.0.0" -description = "A Django application to retrieve user's IP address" -optional = false -python-versions = ">=3.8" -files = [ - {file = "django-ipware-6.0.0.tar.gz", hash = "sha256:c656805c824449b5171e6f851f6369000fe204ec03ac9977110a9b0aff4825b6"}, - {file = "django_ipware-6.0.0-py2.py3-none-any.whl", hash = "sha256:5595aa3819d6c82c2a09a307dfe58f3d40bff3e098c2e8508118195ac3270465"}, -] - -[package.dependencies] -python-ipware = ">=2.0.0" - -[[package]] -name = "django-split-settings" -version = "1.2.0" -description = "Organize Django settings into multiple files and directories. Easily override and modify settings. Use wildcards and optional settings files." -optional = false -python-versions = ">=3.7,<4.0" -files = [ - {file = "django-split-settings-1.2.0.tar.gz", hash = "sha256:31415a618256b54c5cee8662cbaa72a890683b8b7465d64ba88fdd3affdd6c60"}, - {file = "django_split_settings-1.2.0-py3-none-any.whl", hash = "sha256:4b3be146776d49c61bd9dcf89fad40edb1544f13ab27a87a0b1aecf5a0d636f4"}, -] - -[[package]] -name = "django-storages" -version = "1.14.2" -description = "Support for many storage backends in Django" -optional = false -python-versions = ">=3.7" -files = [ - {file = "django-storages-1.14.2.tar.gz", hash = "sha256:51b36af28cc5813b98d5f3dfe7459af638d84428c8df4a03990c7d74d1bea4e5"}, - {file = "django_storages-1.14.2-py3-none-any.whl", hash = "sha256:1db759346b52ada6c2efd9f23d8241ecf518813eb31db9e2589207174f58f6ad"}, -] - -[package.dependencies] -Django = ">=3.2" - -[package.extras] -azure = ["azure-core (>=1.13)", "azure-storage-blob (>=12)"] -boto3 = ["boto3 (>=1.4.4)"] -dropbox = ["dropbox (>=7.2.1)"] -google = ["google-cloud-storage (>=1.27)"] -libcloud = ["apache-libcloud"] -s3 = ["boto3 (>=1.4.4)"] -sftp = ["paramiko (>=1.15)"] - -[[package]] -name = "django-stubs" -version = "4.2.6" -description = "Mypy stubs for Django" -optional = false -python-versions = ">=3.8" -files = [ - {file = "django-stubs-4.2.6.tar.gz", hash = "sha256:e60b43de662a199db4b15c803c06669e0ac5035614af291cbd3b91591f7dcc94"}, - {file = "django_stubs-4.2.6-py3-none-any.whl", hash = "sha256:2fcd257884a68dfa02de41ee5410ec805264d9b07d9b5b119e4dea82c7b8345e"}, -] - -[package.dependencies] -django = "*" -django-stubs-ext = ">=4.2.5" -types-pytz = "*" -types-PyYAML = "*" -typing-extensions = "*" - -[package.extras] -compatible-mypy = ["mypy (>=1.6.0,<1.7.0)"] - -[[package]] -name = "django-stubs-ext" -version = "4.2.5" -description = "Monkey-patching and extensions for django-stubs" -optional = false -python-versions = ">=3.8" -files = [ - {file = "django-stubs-ext-4.2.5.tar.gz", hash = "sha256:8c4d1fb5f68419b3b2474c659681a189803e27d6a5e5abf5aa0da57601b58633"}, - {file = "django_stubs_ext-4.2.5-py3-none-any.whl", hash = "sha256:921cd7ae4614e74c234bc0fe86ee75537d163addfe1fc6f134bf03e29d86c01e"}, -] - -[package.dependencies] -django = "*" -typing-extensions = "*" - -[[package]] -name = "djangorestframework" -version = "3.14.0" -description = "Web APIs for Django, made easy." -optional = false -python-versions = ">=3.6" -files = [ - {file = "djangorestframework-3.14.0-py3-none-any.whl", hash = "sha256:eb63f58c9f218e1a7d064d17a70751f528ed4e1d35547fdade9aaf4cd103fd08"}, - {file = "djangorestframework-3.14.0.tar.gz", hash = "sha256:579a333e6256b09489cbe0a067e66abe55c6595d8926be6b99423786334350c8"}, -] - -[package.dependencies] -django = ">=3.0" -pytz = "*" - -[[package]] -name = "djangorestframework-camel-case" -version = "1.4.2" -description = "Camel case JSON support for Django REST framework." -optional = false -python-versions = ">=3.5" -files = [ - {file = "djangorestframework-camel-case-1.4.2.tar.gz", hash = "sha256:cdae75846648abb6585c7470639a1d2fb064dc45f8e8b62aaa50be7f1a7a61f4"}, -] - -[[package]] -name = "djangorestframework-stubs" -version = "3.14.4" -description = "PEP-484 stubs for django-rest-framework" -optional = false -python-versions = ">=3.8" -files = [ - {file = "djangorestframework-stubs-3.14.4.tar.gz", hash = "sha256:8ee8719bfeb647b92cc200e15b3cc9813d2e4468c8190777a55a121542a4b2d4"}, - {file = "djangorestframework_stubs-3.14.4-py3-none-any.whl", hash = "sha256:5be8275dd05d6629b3d1688929586ef7b6bc66b4f3f728b5e0389305f07c7a7f"}, -] - -[package.dependencies] -django-stubs = ">=4.2.5" -mypy = ">=0.991" -requests = ">=2.0.0" -types-PyYAML = ">=5.4.3" -types-requests = ">=0.1.12" -typing-extensions = ">=3.10.0" - -[package.extras] -compatible-mypy = ["mypy (>=1.6.0,<1.7.0)"] -coreapi = ["coreapi (>=2.0.0)"] -markdown = ["types-Markdown (>=0.1.5)"] - -[[package]] -name = "dotenv-linter" -version = "0.4.0" -description = "Linting dotenv files like a charm!" -optional = false -python-versions = ">=3.7,<4.0" -files = [ - {file = "dotenv-linter-0.4.0.tar.gz", hash = "sha256:88ea58482d0f4a79822538155b13b31cd54d213197d157ed06fdd532963583c9"}, - {file = "dotenv_linter-0.4.0-py3-none-any.whl", hash = "sha256:2c73f0fc750f5599ad656f5ab9e62561460a533915ee30feb7259ff2393be6f5"}, -] - -[package.dependencies] -attrs = "*" -click = ">=6,<9" -click_default_group = ">=1.2,<2.0" -ply = ">=3.11,<4.0" -typing_extensions = ">=3.6,<5.0" - -[[package]] -name = "drf-jwt" -version = "1.19.2" -description = "JSON Web Token based authentication for Django REST framework" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" -files = [ - {file = "drf-jwt-1.19.2.tar.gz", hash = "sha256:660bc66f992065cef59832adcbbdf871847e9738671c19e5121971e773768235"}, - {file = "drf_jwt-1.19.2-py2.py3-none-any.whl", hash = "sha256:63c3d4ed61a1013958cd63416e2d5c84467d8ae3e6e1be44b1fb58743dbd1582"}, -] - -[package.dependencies] -Django = ">=1.11" -djangorestframework = ">=3.7" -PyJWT = {version = ">=1.5.2,<3.0.0", extras = ["crypto"]} - -[package.extras] -dev = ["tox"] -docs = ["mkdocs (==0.13.2)"] -lint = ["black", "flake8", "isort"] -test = ["mock", "pytest (>=3.0)", "pytest-cov", "pytest-django", "pytest-runner", "six"] - -[[package]] -name = "drf-spectacular" -version = "0.26.5" -description = "Sane and flexible OpenAPI 3 schema generation for Django REST framework" -optional = false -python-versions = ">=3.6" -files = [ - {file = "drf-spectacular-0.26.5.tar.gz", hash = "sha256:aee55330a774ba8a9cbdb125714d1c9ee05a8aafd3ce3be8bfd26527649aeb44"}, - {file = "drf_spectacular-0.26.5-py3-none-any.whl", hash = "sha256:c0002a820b11771fdbf37853deb371947caf0159d1afeeffe7598e964bc1db94"}, -] - -[package.dependencies] -Django = ">=2.2" -djangorestframework = ">=3.10.3" -drf-spectacular-sidecar = {version = "*", optional = true, markers = "extra == \"sidecar\""} -inflection = ">=0.3.1" -jsonschema = ">=2.6.0" -PyYAML = ">=5.1" -uritemplate = ">=2.0.0" - -[package.extras] -offline = ["drf-spectacular-sidecar"] -sidecar = ["drf-spectacular-sidecar"] - -[[package]] -name = "drf-spectacular-sidecar" -version = "2023.10.1" -description = "Serve self-contained distribution builds of Swagger UI and Redoc with Django" -optional = false -python-versions = ">=3.6" -files = [ - {file = "drf-spectacular-sidecar-2023.10.1.tar.gz", hash = "sha256:546a83c173589715e530fad211af60cbcda2db54eb9e0935d44251639332af6d"}, - {file = "drf_spectacular_sidecar-2023.10.1-py3-none-any.whl", hash = "sha256:3d042a6772512f4d238f0385d3430acf5f669f595fd0be2641fe6bbfb4c7b376"}, -] - -[package.dependencies] -Django = ">=2.2" - -[[package]] -name = "eradicate" -version = "2.3.0" -description = "Removes commented-out code." -optional = false -python-versions = "*" -files = [ - {file = "eradicate-2.3.0-py3-none-any.whl", hash = "sha256:2b29b3dd27171f209e4ddd8204b70c02f0682ae95eecb353f10e8d72b149c63e"}, - {file = "eradicate-2.3.0.tar.gz", hash = "sha256:06df115be3b87d0fc1c483db22a2ebb12bcf40585722810d809cc770f5031c37"}, -] - -[[package]] -name = "execnet" -version = "2.0.2" -description = "execnet: rapid multi-Python deployment" -optional = false -python-versions = ">=3.7" -files = [ - {file = "execnet-2.0.2-py3-none-any.whl", hash = "sha256:88256416ae766bc9e8895c76a87928c0012183da3cc4fc18016e6f050e025f41"}, - {file = "execnet-2.0.2.tar.gz", hash = "sha256:cc59bc4423742fd71ad227122eb0dd44db51efb3dc4095b45ac9a08c770096af"}, -] - -[package.extras] -testing = ["hatch", "pre-commit", "pytest", "tox"] - -[[package]] -name = "executing" -version = "2.0.1" -description = "Get the currently executing AST node of a frame, and other information" -optional = false -python-versions = ">=3.5" -files = [ - {file = "executing-2.0.1-py2.py3-none-any.whl", hash = "sha256:eac49ca94516ccc753f9fb5ce82603156e590b27525a8bc32cce8ae302eb61bc"}, - {file = "executing-2.0.1.tar.gz", hash = "sha256:35afe2ce3affba8ee97f2d69927fa823b08b472b7b994e36a52a964b93d16147"}, -] - -[package.extras] -tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich"] - -[[package]] -name = "faker" -version = "12.0.1" -description = "Faker is a Python package that generates fake data for you." -optional = false -python-versions = ">=3.6" -files = [ - {file = "Faker-12.0.1-py3-none-any.whl", hash = "sha256:1dc2811f20e163892fefe7006f2ce00778f8099a40aee265bfa60a13400de63d"}, - {file = "Faker-12.0.1.tar.gz", hash = "sha256:aa7103805ae793277abbb85da9f6f05e76a1a295a9384a8e17c2fba2b3a690cb"}, -] - -[package.dependencies] -python-dateutil = ">=2.4" - -[[package]] -name = "flake8" -version = "6.1.0" -description = "the modular source code checker: pep8 pyflakes and co" -optional = false -python-versions = ">=3.8.1" -files = [ - {file = "flake8-6.1.0-py2.py3-none-any.whl", hash = "sha256:ffdfce58ea94c6580c77888a86506937f9a1a227dfcd15f245d694ae20a6b6e5"}, - {file = "flake8-6.1.0.tar.gz", hash = "sha256:d5b3857f07c030bdb5bf41c7f53799571d75c4491748a3adcd47de929e34cd23"}, -] - -[package.dependencies] -mccabe = ">=0.7.0,<0.8.0" -pycodestyle = ">=2.11.0,<2.12.0" -pyflakes = ">=3.1.0,<3.2.0" - -[[package]] -name = "flake8-absolute-import" -version = "1.0.0.2" -description = "flake8 plugin to require absolute imports" -optional = false -python-versions = ">=3.6" -files = [ - {file = "flake8-absolute-import-1.0.0.2.tar.gz", hash = "sha256:fcb734ac5a9639fa4ffbc6242ae9d6e9d8063f9cd078d6d218597ee883a99d48"}, - {file = "flake8_absolute_import-1.0.0.2-py3-none-any.whl", hash = "sha256:b72142db999ec5e0ac4f4ac57fb8776a2959d07346c4d3742c446f206d45fcef"}, -] - -[package.dependencies] -flake8 = ">=5.0" - -[[package]] -name = "flake8-bugbear" -version = "23.11.26" -description = "A plugin for flake8 finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes and pycodestyle." -optional = false -python-versions = ">=3.8.1" -files = [ - {file = "flake8-bugbear-23.11.26.tar.gz", hash = "sha256:8e36119071bab626b6dab834fadd6d03c06090e9b189e67b4905821df8212fee"}, - {file = "flake8_bugbear-23.11.26-py3-none-any.whl", hash = "sha256:55d00c8a3c48c995c1f0ec0df54f8c9cf530c06035ce53975a03517d2e7f53e5"}, -] - -[package.dependencies] -attrs = ">=19.2.0" -flake8 = ">=6.0.0" - -[package.extras] -dev = ["coverage", "hypothesis", "hypothesmith (>=0.2)", "pre-commit", "pytest", "tox"] - -[[package]] -name = "flake8-cognitive-complexity" -version = "0.1.0" -description = "An extension for flake8 that validates cognitive functions complexity" -optional = false -python-versions = ">=3.6" -files = [ - {file = "flake8_cognitive_complexity-0.1.0.tar.gz", hash = "sha256:f202df054e4f6ff182b659c261922b9c684628a47beb19cb0973c50d6a7831c1"}, -] - -[package.dependencies] -cognitive_complexity = "*" -setuptools = "*" - -[[package]] -name = "flake8-django" -version = "1.4" -description = "Plugin to catch bad style specific to Django Projects." -optional = false -python-versions = ">=3.7.2,<4.0.0" -files = [ - {file = "flake8_django-1.4.tar.gz", hash = "sha256:4debba883084191568e3187416d1d6bdd4abd826da988f197a3c36572e9f30de"}, -] - -[package.dependencies] -astroid = ">=2.15.2,<3.0.0" -flake8 = ">=3.8.4,<7" - -[[package]] -name = "flake8-eradicate" -version = "1.5.0" -description = "Flake8 plugin to find commented out code" -optional = false -python-versions = ">=3.8,<4.0" -files = [ - {file = "flake8_eradicate-1.5.0-py3-none-any.whl", hash = "sha256:18acc922ad7de623f5247c7d5595da068525ec5437dd53b22ec2259b96ce9d22"}, - {file = "flake8_eradicate-1.5.0.tar.gz", hash = "sha256:aee636cb9ecb5594a7cd92d67ad73eb69909e5cc7bd81710cf9d00970f3983a6"}, -] - -[package.dependencies] -attrs = "*" -eradicate = ">=2.0,<3.0" -flake8 = ">5" - -[[package]] -name = "flake8-fixme" -version = "1.1.1" -description = "Check for FIXME, TODO and other temporary developer notes. Plugin for flake8." -optional = false -python-versions = "*" -files = [ - {file = "flake8-fixme-1.1.1.tar.gz", hash = "sha256:50cade07d27a4c30d4f12351478df87339e67640c83041b664724bda6d16f33a"}, - {file = "flake8_fixme-1.1.1-py2.py3-none-any.whl", hash = "sha256:226a6f2ef916730899f29ac140bed5d4a17e5aba79f00a0e3ae1eff1997cb1ac"}, -] - -[[package]] -name = "flake8-pep3101" -version = "2.1.0" -description = "Checks for old string formatting" -optional = false -python-versions = ">=3.8" -files = [ - {file = "flake8_pep3101-2.1.0-py3-none-any.whl", hash = "sha256:2d2b8b997ccf0bf0df91532e861465dcfa32a6a306d1dc98f93889cae49f4231"}, - {file = "flake8_pep3101-2.1.0.tar.gz", hash = "sha256:1b84b61685f1e631f2f710e5d5ed3ca68b5fc45fb9402fa8ae1b8a9a058a3387"}, -] - -[package.dependencies] -flake8 = "*" - -[package.extras] -test = ["pytest"] - -[[package]] -name = "flake8-pie" -version = "0.16.0" -description = "A flake8 extension that implements misc. lints" -optional = false -python-versions = ">=3.7" -files = [ - {file = "flake8-pie-0.16.0.tar.gz", hash = "sha256:b8dcb7b92706fa33d05d92a4b3e49b7a9fd3f0041849166275b646ba50e515ba"}, - {file = "flake8_pie-0.16.0-py3-none-any.whl", hash = "sha256:24cd7849b0eee22e2328b9e9d2a1dea40013b0a3106864bbadd06a4b05dbb71f"}, -] - -[package.dependencies] -typing_extensions = "*" - -[[package]] -name = "flake8-print" -version = "5.0.0" -description = "print statement checker plugin for flake8" -optional = false -python-versions = ">=3.7" -files = [ - {file = "flake8-print-5.0.0.tar.gz", hash = "sha256:76915a2a389cc1c0879636c219eb909c38501d3a43cc8dae542081c9ba48bdf9"}, - {file = "flake8_print-5.0.0-py3-none-any.whl", hash = "sha256:84a1a6ea10d7056b804221ac5e62b1cee1aefc897ce16f2e5c42d3046068f5d8"}, -] - -[package.dependencies] -flake8 = ">=3.0" -pycodestyle = "*" - -[[package]] -name = "flake8-printf-formatting" -version = "1.1.2" -description = "flake8 plugin which forbids printf-style string formatting" -optional = false -python-versions = ">=3.6" -files = [ - {file = "flake8-printf-formatting-1.1.2.tar.gz", hash = "sha256:0f9e1308ac290356e4b271d4f26adfc3f9165680a7b6c221503b0f3e155a2784"}, - {file = "flake8_printf_formatting-1.1.2-py2.py3-none-any.whl", hash = "sha256:d908ffabdf08581043a50572744fd60563d82386630b0335445894120089d2df"}, -] - -[package.dependencies] -flake8 = "*" - -[[package]] -name = "flake8-pyproject" -version = "1.2.3" -description = "Flake8 plug-in loading the configuration from pyproject.toml" -optional = false -python-versions = ">= 3.6" -files = [ - {file = "flake8_pyproject-1.2.3-py3-none-any.whl", hash = "sha256:6249fe53545205af5e76837644dc80b4c10037e73a0e5db87ff562d75fb5bd4a"}, -] - -[package.dependencies] -Flake8 = ">=5" - -[package.extras] -dev = ["pyTest", "pyTest-cov"] - -[[package]] -name = "flake8-variables-names" -version = "0.0.6" -description = "A flake8 extension that helps to make more readable variables names" -optional = false -python-versions = ">=3.7" -files = [ - {file = "flake8_variables_names-0.0.6-py3-none-any.whl", hash = "sha256:4aff935d54b3f7afcd026b4dae55029877bd05a7c507b294b45bc7bf577d7b47"}, - {file = "flake8_variables_names-0.0.6.tar.gz", hash = "sha256:292c50e4813d632aa3adcd02c185e7bb583f5fc8ebe02e70f13c958bfe46ad91"}, -] - -[[package]] -name = "flake8-walrus" -version = "1.2.0" -description = "flake8 plugin which forbids assignment expressions (the walrus operator)" -optional = false -python-versions = ">=3.8" -files = [ - {file = "flake8_walrus-1.2.0-py2.py3-none-any.whl", hash = "sha256:a9f72722188b95a393f8727a0eaeb8f31d9796eeb5a4328c9c4499ccd57e589d"}, - {file = "flake8_walrus-1.2.0.tar.gz", hash = "sha256:5dff966f0cc67abae104349812cd255ef3b5e09a7f768eac39b5a4a39f4d1e73"}, -] - -[package.dependencies] -flake8 = ">=5.0" - -[[package]] -name = "freezegun" -version = "1.2.2" -description = "Let your Python tests travel through time" -optional = false -python-versions = ">=3.6" -files = [ - {file = "freezegun-1.2.2-py3-none-any.whl", hash = "sha256:ea1b963b993cb9ea195adbd893a48d573fda951b0da64f60883d7e988b606c9f"}, - {file = "freezegun-1.2.2.tar.gz", hash = "sha256:cd22d1ba06941384410cd967d8a99d5ae2442f57dfafeff2fda5de8dc5c05446"}, -] - -[package.dependencies] -python-dateutil = ">=2.7" - -[[package]] -name = "idna" -version = "3.6" -description = "Internationalized Domain Names in Applications (IDNA)" -optional = false -python-versions = ">=3.5" -files = [ - {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, - {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, -] - -[[package]] -name = "inflection" -version = "0.5.1" -description = "A port of Ruby on Rails inflector to Python" -optional = false -python-versions = ">=3.5" -files = [ - {file = "inflection-0.5.1-py2.py3-none-any.whl", hash = "sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2"}, - {file = "inflection-0.5.1.tar.gz", hash = "sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417"}, -] - -[[package]] -name = "iniconfig" -version = "2.0.0" -description = "brain-dead simple config-ini parsing" -optional = false -python-versions = ">=3.7" -files = [ - {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, - {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, -] - -[[package]] -name = "ipython" -version = "8.18.0" -description = "IPython: Productive Interactive Computing" -optional = false -python-versions = ">=3.9" -files = [ - {file = "ipython-8.18.0-py3-none-any.whl", hash = "sha256:d538a7a98ad9b7e018926447a5f35856113a85d08fd68a165d7871ab5175f6e0"}, - {file = "ipython-8.18.0.tar.gz", hash = "sha256:4feb61210160f75e229ce932dbf8b719bff37af123c0b985fd038b14233daa16"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "sys_platform == \"win32\""} -decorator = "*" -jedi = ">=0.16" -matplotlib-inline = "*" -pexpect = {version = ">4.3", markers = "sys_platform != \"win32\""} -prompt-toolkit = ">=3.0.30,<3.0.37 || >3.0.37,<3.1.0" -pygments = ">=2.4.0" -stack-data = "*" -traitlets = ">=5" - -[package.extras] -all = ["black", "curio", "docrepr", "exceptiongroup", "ipykernel", "ipyparallel", "ipywidgets", "matplotlib", "matplotlib (!=3.2.0)", "nbconvert", "nbformat", "notebook", "numpy (>=1.22)", "pandas", "pickleshare", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio (<0.22)", "qtconsole", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "trio", "typing-extensions"] -black = ["black"] -doc = ["docrepr", "exceptiongroup", "ipykernel", "matplotlib", "pickleshare", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio (<0.22)", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "typing-extensions"] -kernel = ["ipykernel"] -nbconvert = ["nbconvert"] -nbformat = ["nbformat"] -notebook = ["ipywidgets", "notebook"] -parallel = ["ipyparallel"] -qtconsole = ["qtconsole"] -test = ["pickleshare", "pytest (<7.1)", "pytest-asyncio (<0.22)", "testpath"] -test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.22)", "pandas", "pickleshare", "pytest (<7.1)", "pytest-asyncio (<0.22)", "testpath", "trio"] - -[[package]] -name = "isort" -version = "5.12.0" -description = "A Python utility / library to sort Python imports." -optional = false -python-versions = ">=3.8.0" -files = [ - {file = "isort-5.12.0-py3-none-any.whl", hash = "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6"}, - {file = "isort-5.12.0.tar.gz", hash = "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504"}, -] - -[package.extras] -colors = ["colorama (>=0.4.3)"] -pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"] -plugins = ["setuptools"] -requirements-deprecated-finder = ["pip-api", "pipreqs"] - -[[package]] -name = "jedi" -version = "0.19.1" -description = "An autocompletion tool for Python that can be used for text editors." -optional = false -python-versions = ">=3.6" -files = [ - {file = "jedi-0.19.1-py2.py3-none-any.whl", hash = "sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0"}, - {file = "jedi-0.19.1.tar.gz", hash = "sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd"}, -] - -[package.dependencies] -parso = ">=0.8.3,<0.9.0" - -[package.extras] -docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alabaster (==0.7.12)", "babel (==2.9.1)", "chardet (==4.0.0)", "commonmark (==0.8.1)", "docutils (==0.17.1)", "future (==0.18.2)", "idna (==2.10)", "imagesize (==1.2.0)", "mock (==1.0.1)", "packaging (==20.9)", "pyparsing (==2.4.7)", "pytz (==2021.1)", "readthedocs-sphinx-ext (==2.1.4)", "recommonmark (==0.5.0)", "requests (==2.25.1)", "six (==1.15.0)", "snowballstemmer (==2.1.0)", "sphinx (==1.8.5)", "sphinx-rtd-theme (==0.4.3)", "sphinxcontrib-serializinghtml (==1.1.4)", "sphinxcontrib-websupport (==1.2.4)", "urllib3 (==1.26.4)"] -qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] -testing = ["Django", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] - -[[package]] -name = "jsonschema" -version = "4.20.0" -description = "An implementation of JSON Schema validation for Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "jsonschema-4.20.0-py3-none-any.whl", hash = "sha256:ed6231f0429ecf966f5bc8dfef245998220549cbbcf140f913b7464c52c3b6b3"}, - {file = "jsonschema-4.20.0.tar.gz", hash = "sha256:4f614fd46d8d61258610998997743ec5492a648b33cf478c1ddc23ed4598a5fa"}, -] - -[package.dependencies] -attrs = ">=22.2.0" -jsonschema-specifications = ">=2023.03.6" -referencing = ">=0.28.4" -rpds-py = ">=0.7.1" - -[package.extras] -format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"] -format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=1.11)"] - -[[package]] -name = "jsonschema-specifications" -version = "2023.11.1" -description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" -optional = false -python-versions = ">=3.8" -files = [ - {file = "jsonschema_specifications-2023.11.1-py3-none-any.whl", hash = "sha256:f596778ab612b3fd29f72ea0d990393d0540a5aab18bf0407a46632eab540779"}, - {file = "jsonschema_specifications-2023.11.1.tar.gz", hash = "sha256:c9b234904ffe02f079bf91b14d79987faa685fd4b39c377a0996954c0090b9ca"}, -] - -[package.dependencies] -referencing = ">=0.31.0" - -[[package]] -name = "lazy-object-proxy" -version = "1.9.0" -description = "A fast and thorough lazy object proxy." -optional = false -python-versions = ">=3.7" -files = [ - {file = "lazy-object-proxy-1.9.0.tar.gz", hash = "sha256:659fb5809fa4629b8a1ac5106f669cfc7bef26fbb389dda53b3e010d1ac4ebae"}, - {file = "lazy_object_proxy-1.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b40387277b0ed2d0602b8293b94d7257e17d1479e257b4de114ea11a8cb7f2d7"}, - {file = "lazy_object_proxy-1.9.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8c6cfb338b133fbdbc5cfaa10fe3c6aeea827db80c978dbd13bc9dd8526b7d4"}, - {file = "lazy_object_proxy-1.9.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:721532711daa7db0d8b779b0bb0318fa87af1c10d7fe5e52ef30f8eff254d0cd"}, - {file = "lazy_object_proxy-1.9.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:66a3de4a3ec06cd8af3f61b8e1ec67614fbb7c995d02fa224813cb7afefee701"}, - {file = "lazy_object_proxy-1.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1aa3de4088c89a1b69f8ec0dcc169aa725b0ff017899ac568fe44ddc1396df46"}, - {file = "lazy_object_proxy-1.9.0-cp310-cp310-win32.whl", hash = "sha256:f0705c376533ed2a9e5e97aacdbfe04cecd71e0aa84c7c0595d02ef93b6e4455"}, - {file = "lazy_object_proxy-1.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:ea806fd4c37bf7e7ad82537b0757999264d5f70c45468447bb2b91afdbe73a6e"}, - {file = "lazy_object_proxy-1.9.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:946d27deaff6cf8452ed0dba83ba38839a87f4f7a9732e8f9fd4107b21e6ff07"}, - {file = "lazy_object_proxy-1.9.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79a31b086e7e68b24b99b23d57723ef7e2c6d81ed21007b6281ebcd1688acb0a"}, - {file = "lazy_object_proxy-1.9.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f699ac1c768270c9e384e4cbd268d6e67aebcfae6cd623b4d7c3bfde5a35db59"}, - {file = "lazy_object_proxy-1.9.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bfb38f9ffb53b942f2b5954e0f610f1e721ccebe9cce9025a38c8ccf4a5183a4"}, - {file = "lazy_object_proxy-1.9.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:189bbd5d41ae7a498397287c408617fe5c48633e7755287b21d741f7db2706a9"}, - {file = "lazy_object_proxy-1.9.0-cp311-cp311-win32.whl", hash = "sha256:81fc4d08b062b535d95c9ea70dbe8a335c45c04029878e62d744bdced5141586"}, - {file = "lazy_object_proxy-1.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:f2457189d8257dd41ae9b434ba33298aec198e30adf2dcdaaa3a28b9994f6adb"}, - {file = "lazy_object_proxy-1.9.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d9e25ef10a39e8afe59a5c348a4dbf29b4868ab76269f81ce1674494e2565a6e"}, - {file = "lazy_object_proxy-1.9.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cbf9b082426036e19c6924a9ce90c740a9861e2bdc27a4834fd0a910742ac1e8"}, - {file = "lazy_object_proxy-1.9.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f5fa4a61ce2438267163891961cfd5e32ec97a2c444e5b842d574251ade27d2"}, - {file = "lazy_object_proxy-1.9.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:8fa02eaab317b1e9e03f69aab1f91e120e7899b392c4fc19807a8278a07a97e8"}, - {file = "lazy_object_proxy-1.9.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e7c21c95cae3c05c14aafffe2865bbd5e377cfc1348c4f7751d9dc9a48ca4bda"}, - {file = "lazy_object_proxy-1.9.0-cp37-cp37m-win32.whl", hash = "sha256:f12ad7126ae0c98d601a7ee504c1122bcef553d1d5e0c3bfa77b16b3968d2734"}, - {file = "lazy_object_proxy-1.9.0-cp37-cp37m-win_amd64.whl", hash = "sha256:edd20c5a55acb67c7ed471fa2b5fb66cb17f61430b7a6b9c3b4a1e40293b1671"}, - {file = "lazy_object_proxy-1.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2d0daa332786cf3bb49e10dc6a17a52f6a8f9601b4cf5c295a4f85854d61de63"}, - {file = "lazy_object_proxy-1.9.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cd077f3d04a58e83d04b20e334f678c2b0ff9879b9375ed107d5d07ff160171"}, - {file = "lazy_object_proxy-1.9.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:660c94ea760b3ce47d1855a30984c78327500493d396eac4dfd8bd82041b22be"}, - {file = "lazy_object_proxy-1.9.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:212774e4dfa851e74d393a2370871e174d7ff0ebc980907723bb67d25c8a7c30"}, - {file = "lazy_object_proxy-1.9.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f0117049dd1d5635bbff65444496c90e0baa48ea405125c088e93d9cf4525b11"}, - {file = "lazy_object_proxy-1.9.0-cp38-cp38-win32.whl", hash = "sha256:0a891e4e41b54fd5b8313b96399f8b0e173bbbfc03c7631f01efbe29bb0bcf82"}, - {file = "lazy_object_proxy-1.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:9990d8e71b9f6488e91ad25f322898c136b008d87bf852ff65391b004da5e17b"}, - {file = "lazy_object_proxy-1.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9e7551208b2aded9c1447453ee366f1c4070602b3d932ace044715d89666899b"}, - {file = "lazy_object_proxy-1.9.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f83ac4d83ef0ab017683d715ed356e30dd48a93746309c8f3517e1287523ef4"}, - {file = "lazy_object_proxy-1.9.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7322c3d6f1766d4ef1e51a465f47955f1e8123caee67dd641e67d539a534d006"}, - {file = "lazy_object_proxy-1.9.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:18b78ec83edbbeb69efdc0e9c1cb41a3b1b1ed11ddd8ded602464c3fc6020494"}, - {file = "lazy_object_proxy-1.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:09763491ce220c0299688940f8dc2c5d05fd1f45af1e42e636b2e8b2303e4382"}, - {file = "lazy_object_proxy-1.9.0-cp39-cp39-win32.whl", hash = "sha256:9090d8e53235aa280fc9239a86ae3ea8ac58eff66a705fa6aa2ec4968b95c821"}, - {file = "lazy_object_proxy-1.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:db1c1722726f47e10e0b5fdbf15ac3b8adb58c091d12b3ab713965795036985f"}, -] - -[[package]] -name = "matplotlib-inline" -version = "0.1.6" -description = "Inline Matplotlib backend for Jupyter" -optional = false -python-versions = ">=3.5" -files = [ - {file = "matplotlib-inline-0.1.6.tar.gz", hash = "sha256:f887e5f10ba98e8d2b150ddcf4702c1e5f8b3a20005eb0f74bfdbd360ee6f304"}, - {file = "matplotlib_inline-0.1.6-py3-none-any.whl", hash = "sha256:f1f41aab5328aa5aaea9b16d083b128102f8712542f819fe7e6a420ff581b311"}, -] - -[package.dependencies] -traitlets = "*" - -[[package]] -name = "mccabe" -version = "0.7.0" -description = "McCabe checker, plugin for flake8" -optional = false -python-versions = ">=3.6" -files = [ - {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, - {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, -] - -[[package]] -name = "mixer" -version = "7.2.2" -description = "Mixer -- Is a fixtures replacement. Supported Django ORM, SqlAlchemy ORM, Mongoengine ODM and custom python objects." -optional = false -python-versions = ">=3.7" -files = [ - {file = "mixer-7.2.2-py3-none-any.whl", hash = "sha256:8089b8e2d00288c77e622936198f5dd03c8ac1603a1530a4f870dc213363b2ae"}, - {file = "mixer-7.2.2.tar.gz", hash = "sha256:9b3f1a261b56d8f2394f39955f83adbc7ff3ab4bb1065ebfec19a10d3e8501e0"}, -] - -[package.dependencies] -Faker = ">=5.4.0,<12.1" - -[package.extras] -tests = ["Django (>=3.0)", "Flask (>=1.0)", "Marshmallow (>=3.9)", "SQLAlchemy (>=1.1.4)", "flask-sqlalchemy (>=2.1)", "mongoengine (>=0.10.1)", "peewee (>=3.7.0)", "pony (>=0.7)", "psycopg2-binary (>=2.8.4)", "pytest"] - -[[package]] -name = "mypy" -version = "1.7.1" -description = "Optional static typing for Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "mypy-1.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:12cce78e329838d70a204293e7b29af9faa3ab14899aec397798a4b41be7f340"}, - {file = "mypy-1.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1484b8fa2c10adf4474f016e09d7a159602f3239075c7bf9f1627f5acf40ad49"}, - {file = "mypy-1.7.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31902408f4bf54108bbfb2e35369877c01c95adc6192958684473658c322c8a5"}, - {file = "mypy-1.7.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f2c2521a8e4d6d769e3234350ba7b65ff5d527137cdcde13ff4d99114b0c8e7d"}, - {file = "mypy-1.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:fcd2572dd4519e8a6642b733cd3a8cfc1ef94bafd0c1ceed9c94fe736cb65b6a"}, - {file = "mypy-1.7.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4b901927f16224d0d143b925ce9a4e6b3a758010673eeded9b748f250cf4e8f7"}, - {file = "mypy-1.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2f7f6985d05a4e3ce8255396df363046c28bea790e40617654e91ed580ca7c51"}, - {file = "mypy-1.7.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:944bdc21ebd620eafefc090cdf83158393ec2b1391578359776c00de00e8907a"}, - {file = "mypy-1.7.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9c7ac372232c928fff0645d85f273a726970c014749b924ce5710d7d89763a28"}, - {file = "mypy-1.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:f6efc9bd72258f89a3816e3a98c09d36f079c223aa345c659622f056b760ab42"}, - {file = "mypy-1.7.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6dbdec441c60699288adf051f51a5d512b0d818526d1dcfff5a41f8cd8b4aaf1"}, - {file = "mypy-1.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4fc3d14ee80cd22367caaaf6e014494415bf440980a3045bf5045b525680ac33"}, - {file = "mypy-1.7.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c6e4464ed5f01dc44dc9821caf67b60a4e5c3b04278286a85c067010653a0eb"}, - {file = "mypy-1.7.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:d9b338c19fa2412f76e17525c1b4f2c687a55b156320acb588df79f2e6fa9fea"}, - {file = "mypy-1.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:204e0d6de5fd2317394a4eff62065614c4892d5a4d1a7ee55b765d7a3d9e3f82"}, - {file = "mypy-1.7.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:84860e06ba363d9c0eeabd45ac0fde4b903ad7aa4f93cd8b648385a888e23200"}, - {file = "mypy-1.7.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8c5091ebd294f7628eb25ea554852a52058ac81472c921150e3a61cdd68f75a7"}, - {file = "mypy-1.7.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40716d1f821b89838589e5b3106ebbc23636ffdef5abc31f7cd0266db936067e"}, - {file = "mypy-1.7.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5cf3f0c5ac72139797953bd50bc6c95ac13075e62dbfcc923571180bebb662e9"}, - {file = "mypy-1.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:78e25b2fd6cbb55ddfb8058417df193f0129cad5f4ee75d1502248e588d9e0d7"}, - {file = "mypy-1.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:75c4d2a6effd015786c87774e04331b6da863fc3fc4e8adfc3b40aa55ab516fe"}, - {file = "mypy-1.7.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2643d145af5292ee956aa0a83c2ce1038a3bdb26e033dadeb2f7066fb0c9abce"}, - {file = "mypy-1.7.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75aa828610b67462ffe3057d4d8a4112105ed211596b750b53cbfe182f44777a"}, - {file = "mypy-1.7.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ee5d62d28b854eb61889cde4e1dbc10fbaa5560cb39780c3995f6737f7e82120"}, - {file = "mypy-1.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:72cf32ce7dd3562373f78bd751f73c96cfb441de147cc2448a92c1a308bd0ca6"}, - {file = "mypy-1.7.1-py3-none-any.whl", hash = "sha256:f7c5d642db47376a0cc130f0de6d055056e010debdaf0707cd2b0fc7e7ef30ea"}, - {file = "mypy-1.7.1.tar.gz", hash = "sha256:fcb6d9afb1b6208b4c712af0dafdc650f518836065df0d4fb1d800f5d6773db2"}, -] - -[package.dependencies] -mypy-extensions = ">=1.0.0" -typing-extensions = ">=4.1.0" - -[package.extras] -dmypy = ["psutil (>=4.0)"] -install-types = ["pip"] -mypyc = ["setuptools (>=50)"] -reports = ["lxml"] - -[[package]] -name = "mypy-extensions" -version = "1.0.0" -description = "Type system extensions for programs checked with the mypy type checker." -optional = false -python-versions = ">=3.5" -files = [ - {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, - {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, -] - -[[package]] -name = "packaging" -version = "23.2" -description = "Core utilities for Python packages" -optional = false -python-versions = ">=3.7" -files = [ - {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, - {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, -] - -[[package]] -name = "parso" -version = "0.8.3" -description = "A Python Parser" -optional = false -python-versions = ">=3.6" -files = [ - {file = "parso-0.8.3-py2.py3-none-any.whl", hash = "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"}, - {file = "parso-0.8.3.tar.gz", hash = "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0"}, -] - -[package.extras] -qa = ["flake8 (==3.8.3)", "mypy (==0.782)"] -testing = ["docopt", "pytest (<6.0.0)"] - -[[package]] -name = "pathspec" -version = "0.11.2" -description = "Utility library for gitignore style pattern matching of file paths." -optional = false -python-versions = ">=3.7" -files = [ - {file = "pathspec-0.11.2-py3-none-any.whl", hash = "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"}, - {file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"}, -] - -[[package]] -name = "pexpect" -version = "4.9.0" -description = "Pexpect allows easy control of interactive console applications." -optional = false -python-versions = "*" -files = [ - {file = "pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"}, - {file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"}, -] - -[package.dependencies] -ptyprocess = ">=0.5" - -[[package]] -name = "pillow" -version = "10.1.0" -description = "Python Imaging Library (Fork)" -optional = false -python-versions = ">=3.8" -files = [ - {file = "Pillow-10.1.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1ab05f3db77e98f93964697c8efc49c7954b08dd61cff526b7f2531a22410106"}, - {file = "Pillow-10.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6932a7652464746fcb484f7fc3618e6503d2066d853f68a4bd97193a3996e273"}, - {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5f63b5a68daedc54c7c3464508d8c12075e56dcfbd42f8c1bf40169061ae666"}, - {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0949b55eb607898e28eaccb525ab104b2d86542a85c74baf3a6dc24002edec2"}, - {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:ae88931f93214777c7a3aa0a8f92a683f83ecde27f65a45f95f22d289a69e593"}, - {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b0eb01ca85b2361b09480784a7931fc648ed8b7836f01fb9241141b968feb1db"}, - {file = "Pillow-10.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d27b5997bdd2eb9fb199982bb7eb6164db0426904020dc38c10203187ae2ff2f"}, - {file = "Pillow-10.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7df5608bc38bd37ef585ae9c38c9cd46d7c81498f086915b0f97255ea60c2818"}, - {file = "Pillow-10.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:41f67248d92a5e0a2076d3517d8d4b1e41a97e2df10eb8f93106c89107f38b57"}, - {file = "Pillow-10.1.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1fb29c07478e6c06a46b867e43b0bcdb241b44cc52be9bc25ce5944eed4648e7"}, - {file = "Pillow-10.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2cdc65a46e74514ce742c2013cd4a2d12e8553e3a2563c64879f7c7e4d28bce7"}, - {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50d08cd0a2ecd2a8657bd3d82c71efd5a58edb04d9308185d66c3a5a5bed9610"}, - {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:062a1610e3bc258bff2328ec43f34244fcec972ee0717200cb1425214fe5b839"}, - {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:61f1a9d247317fa08a308daaa8ee7b3f760ab1809ca2da14ecc88ae4257d6172"}, - {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a646e48de237d860c36e0db37ecaecaa3619e6f3e9d5319e527ccbc8151df061"}, - {file = "Pillow-10.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:47e5bf85b80abc03be7455c95b6d6e4896a62f6541c1f2ce77a7d2bb832af262"}, - {file = "Pillow-10.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a92386125e9ee90381c3369f57a2a50fa9e6aa8b1cf1d9c4b200d41a7dd8e992"}, - {file = "Pillow-10.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:0f7c276c05a9767e877a0b4c5050c8bee6a6d960d7f0c11ebda6b99746068c2a"}, - {file = "Pillow-10.1.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:a89b8312d51715b510a4fe9fc13686283f376cfd5abca8cd1c65e4c76e21081b"}, - {file = "Pillow-10.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:00f438bb841382b15d7deb9a05cc946ee0f2c352653c7aa659e75e592f6fa17d"}, - {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d929a19f5469b3f4df33a3df2983db070ebb2088a1e145e18facbc28cae5b27"}, - {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a92109192b360634a4489c0c756364c0c3a2992906752165ecb50544c251312"}, - {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:0248f86b3ea061e67817c47ecbe82c23f9dd5d5226200eb9090b3873d3ca32de"}, - {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:9882a7451c680c12f232a422730f986a1fcd808da0fd428f08b671237237d651"}, - {file = "Pillow-10.1.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1c3ac5423c8c1da5928aa12c6e258921956757d976405e9467c5f39d1d577a4b"}, - {file = "Pillow-10.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:806abdd8249ba3953c33742506fe414880bad78ac25cc9a9b1c6ae97bedd573f"}, - {file = "Pillow-10.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:eaed6977fa73408b7b8a24e8b14e59e1668cfc0f4c40193ea7ced8e210adf996"}, - {file = "Pillow-10.1.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:fe1e26e1ffc38be097f0ba1d0d07fcade2bcfd1d023cda5b29935ae8052bd793"}, - {file = "Pillow-10.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7a7e3daa202beb61821c06d2517428e8e7c1aab08943e92ec9e5755c2fc9ba5e"}, - {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:24fadc71218ad2b8ffe437b54876c9382b4a29e030a05a9879f615091f42ffc2"}, - {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa1d323703cfdac2036af05191b969b910d8f115cf53093125e4058f62012c9a"}, - {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:912e3812a1dbbc834da2b32299b124b5ddcb664ed354916fd1ed6f193f0e2d01"}, - {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:7dbaa3c7de82ef37e7708521be41db5565004258ca76945ad74a8e998c30af8d"}, - {file = "Pillow-10.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9d7bc666bd8c5a4225e7ac71f2f9d12466ec555e89092728ea0f5c0c2422ea80"}, - {file = "Pillow-10.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:baada14941c83079bf84c037e2d8b7506ce201e92e3d2fa0d1303507a8538212"}, - {file = "Pillow-10.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:2ef6721c97894a7aa77723740a09547197533146fba8355e86d6d9a4a1056b14"}, - {file = "Pillow-10.1.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0a026c188be3b443916179f5d04548092e253beb0c3e2ee0a4e2cdad72f66099"}, - {file = "Pillow-10.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:04f6f6149f266a100374ca3cc368b67fb27c4af9f1cc8cb6306d849dcdf12616"}, - {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb40c011447712d2e19cc261c82655f75f32cb724788df315ed992a4d65696bb"}, - {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a8413794b4ad9719346cd9306118450b7b00d9a15846451549314a58ac42219"}, - {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:c9aeea7b63edb7884b031a35305629a7593272b54f429a9869a4f63a1bf04c34"}, - {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b4005fee46ed9be0b8fb42be0c20e79411533d1fd58edabebc0dd24626882cfd"}, - {file = "Pillow-10.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4d0152565c6aa6ebbfb1e5d8624140a440f2b99bf7afaafbdbf6430426497f28"}, - {file = "Pillow-10.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d921bc90b1defa55c9917ca6b6b71430e4286fc9e44c55ead78ca1a9f9eba5f2"}, - {file = "Pillow-10.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:cfe96560c6ce2f4c07d6647af2d0f3c54cc33289894ebd88cfbb3bcd5391e256"}, - {file = "Pillow-10.1.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:937bdc5a7f5343d1c97dc98149a0be7eb9704e937fe3dc7140e229ae4fc572a7"}, - {file = "Pillow-10.1.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1c25762197144e211efb5f4e8ad656f36c8d214d390585d1d21281f46d556ba"}, - {file = "Pillow-10.1.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:afc8eef765d948543a4775f00b7b8c079b3321d6b675dde0d02afa2ee23000b4"}, - {file = "Pillow-10.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:883f216eac8712b83a63f41b76ddfb7b2afab1b74abbb413c5df6680f071a6b9"}, - {file = "Pillow-10.1.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b920e4d028f6442bea9a75b7491c063f0b9a3972520731ed26c83e254302eb1e"}, - {file = "Pillow-10.1.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c41d960babf951e01a49c9746f92c5a7e0d939d1652d7ba30f6b3090f27e412"}, - {file = "Pillow-10.1.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1fafabe50a6977ac70dfe829b2d5735fd54e190ab55259ec8aea4aaea412fa0b"}, - {file = "Pillow-10.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3b834f4b16173e5b92ab6566f0473bfb09f939ba14b23b8da1f54fa63e4b623f"}, - {file = "Pillow-10.1.0.tar.gz", hash = "sha256:e6bf8de6c36ed96c86ea3b6e1d5273c53f46ef518a062464cd7ef5dd2cf92e38"}, -] - -[package.extras] -docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"] -tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] - -[[package]] -name = "platformdirs" -version = "4.0.0" -description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -optional = false -python-versions = ">=3.7" -files = [ - {file = "platformdirs-4.0.0-py3-none-any.whl", hash = "sha256:118c954d7e949b35437270383a3f2531e99dd93cf7ce4dc8340d3356d30f173b"}, - {file = "platformdirs-4.0.0.tar.gz", hash = "sha256:cb633b2bcf10c51af60beb0ab06d2f1d69064b43abf4c185ca6b28865f3f9731"}, -] - -[package.extras] -docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] - -[[package]] -name = "pluggy" -version = "1.3.0" -description = "plugin and hook calling mechanisms for python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, - {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, -] - -[package.extras] -dev = ["pre-commit", "tox"] -testing = ["pytest", "pytest-benchmark"] - -[[package]] -name = "ply" -version = "3.11" -description = "Python Lex & Yacc" -optional = false -python-versions = "*" -files = [ - {file = "ply-3.11-py2.py3-none-any.whl", hash = "sha256:096f9b8350b65ebd2fd1346b12452efe5b9607f7482813ffca50c22722a807ce"}, - {file = "ply-3.11.tar.gz", hash = "sha256:00c7c1aaa88358b9c765b6d3000c6eec0ba42abca5351b095321aef446081da3"}, -] - -[[package]] -name = "prompt-toolkit" -version = "3.0.41" -description = "Library for building powerful interactive command lines in Python" -optional = false -python-versions = ">=3.7.0" -files = [ - {file = "prompt_toolkit-3.0.41-py3-none-any.whl", hash = "sha256:f36fe301fafb7470e86aaf90f036eef600a3210be4decf461a5b1ca8403d3cb2"}, - {file = "prompt_toolkit-3.0.41.tar.gz", hash = "sha256:941367d97fc815548822aa26c2a269fdc4eb21e9ec05fc5d447cf09bad5d75f0"}, -] - -[package.dependencies] -wcwidth = "*" - -[[package]] -name = "psycopg2-binary" -version = "2.9.9" -description = "psycopg2 - Python-PostgreSQL Database Adapter" -optional = false -python-versions = ">=3.7" -files = [ - {file = "psycopg2-binary-2.9.9.tar.gz", hash = "sha256:7f01846810177d829c7692f1f5ada8096762d9172af1b1a28d4ab5b77c923c1c"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c2470da5418b76232f02a2fcd2229537bb2d5a7096674ce61859c3229f2eb202"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c6af2a6d4b7ee9615cbb162b0738f6e1fd1f5c3eda7e5da17861eacf4c717ea7"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:75723c3c0fbbf34350b46a3199eb50638ab22a0228f93fb472ef4d9becc2382b"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83791a65b51ad6ee6cf0845634859d69a038ea9b03d7b26e703f94c7e93dbcf9"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0ef4854e82c09e84cc63084a9e4ccd6d9b154f1dbdd283efb92ecd0b5e2b8c84"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed1184ab8f113e8d660ce49a56390ca181f2981066acc27cf637d5c1e10ce46e"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d2997c458c690ec2bc6b0b7ecbafd02b029b7b4283078d3b32a852a7ce3ddd98"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:b58b4710c7f4161b5e9dcbe73bb7c62d65670a87df7bcce9e1faaad43e715245"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:0c009475ee389757e6e34611d75f6e4f05f0cf5ebb76c6037508318e1a1e0d7e"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8dbf6d1bc73f1d04ec1734bae3b4fb0ee3cb2a493d35ede9badbeb901fb40f6f"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-win32.whl", hash = "sha256:3f78fd71c4f43a13d342be74ebbc0666fe1f555b8837eb113cb7416856c79682"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-win_amd64.whl", hash = "sha256:876801744b0dee379e4e3c38b76fc89f88834bb15bf92ee07d94acd06ec890a0"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ee825e70b1a209475622f7f7b776785bd68f34af6e7a46e2e42f27b659b5bc26"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1ea665f8ce695bcc37a90ee52de7a7980be5161375d42a0b6c6abedbf0d81f0f"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:143072318f793f53819048fdfe30c321890af0c3ec7cb1dfc9cc87aa88241de2"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c332c8d69fb64979ebf76613c66b985414927a40f8defa16cf1bc028b7b0a7b0"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7fc5a5acafb7d6ccca13bfa8c90f8c51f13d8fb87d95656d3950f0158d3ce53"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:977646e05232579d2e7b9c59e21dbe5261f403a88417f6a6512e70d3f8a046be"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b6356793b84728d9d50ead16ab43c187673831e9d4019013f1402c41b1db9b27"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:bc7bb56d04601d443f24094e9e31ae6deec9ccb23581f75343feebaf30423359"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:77853062a2c45be16fd6b8d6de2a99278ee1d985a7bd8b103e97e41c034006d2"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:78151aa3ec21dccd5cdef6c74c3e73386dcdfaf19bced944169697d7ac7482fc"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-win32.whl", hash = "sha256:dc4926288b2a3e9fd7b50dc6a1909a13bbdadfc67d93f3374d984e56f885579d"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-win_amd64.whl", hash = "sha256:b76bedd166805480ab069612119ea636f5ab8f8771e640ae103e05a4aae3e417"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:8532fd6e6e2dc57bcb3bc90b079c60de896d2128c5d9d6f24a63875a95a088cf"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f8544b092a29a6ddd72f3556a9fcf249ec412e10ad28be6a0c0d948924f2212"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2d423c8d8a3c82d08fe8af900ad5b613ce3632a1249fd6a223941d0735fce493"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e5afae772c00980525f6d6ecf7cbca55676296b580c0e6abb407f15f3706996"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e6f98446430fdf41bd36d4faa6cb409f5140c1c2cf58ce0bbdaf16af7d3f119"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c77e3d1862452565875eb31bdb45ac62502feabbd53429fdc39a1cc341d681ba"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:cb16c65dcb648d0a43a2521f2f0a2300f40639f6f8c1ecbc662141e4e3e1ee07"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:911dda9c487075abd54e644ccdf5e5c16773470a6a5d3826fda76699410066fb"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:57fede879f08d23c85140a360c6a77709113efd1c993923c59fde17aa27599fe"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2293b001e319ab0d869d660a704942c9e2cce19745262a8aba2115ef41a0a42a"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:03ef7df18daf2c4c07e2695e8cfd5ee7f748a1d54d802330985a78d2a5a6dca9"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a602ea5aff39bb9fac6308e9c9d82b9a35c2bf288e184a816002c9fae930b77"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8359bf4791968c5a78c56103702000105501adb557f3cf772b2c207284273984"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:275ff571376626195ab95a746e6a04c7df8ea34638b99fc11160de91f2fef503"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f9b5571d33660d5009a8b3c25dc1db560206e2d2f89d3df1cb32d72c0d117d52"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:420f9bbf47a02616e8554e825208cb947969451978dceb77f95ad09c37791dae"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:4154ad09dac630a0f13f37b583eae260c6aa885d67dfbccb5b02c33f31a6d420"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a148c5d507bb9b4f2030a2025c545fccb0e1ef317393eaba42e7eabd28eb6041"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-win32.whl", hash = "sha256:68fc1f1ba168724771e38bee37d940d2865cb0f562380a1fb1ffb428b75cb692"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-win_amd64.whl", hash = "sha256:281309265596e388ef483250db3640e5f414168c5a67e9c665cafce9492eda2f"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:60989127da422b74a04345096c10d416c2b41bd7bf2a380eb541059e4e999980"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:246b123cc54bb5361588acc54218c8c9fb73068bf227a4a531d8ed56fa3ca7d6"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34eccd14566f8fe14b2b95bb13b11572f7c7d5c36da61caf414d23b91fcc5d94"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18d0ef97766055fec15b5de2c06dd8e7654705ce3e5e5eed3b6651a1d2a9a152"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d3f82c171b4ccd83bbaf35aa05e44e690113bd4f3b7b6cc54d2219b132f3ae55"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ead20f7913a9c1e894aebe47cccf9dc834e1618b7aa96155d2091a626e59c972"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ca49a8119c6cbd77375ae303b0cfd8c11f011abbbd64601167ecca18a87e7cdd"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:323ba25b92454adb36fa425dc5cf6f8f19f78948cbad2e7bc6cdf7b0d7982e59"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:1236ed0952fbd919c100bc839eaa4a39ebc397ed1c08a97fc45fee2a595aa1b3"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:729177eaf0aefca0994ce4cffe96ad3c75e377c7b6f4efa59ebf003b6d398716"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-win32.whl", hash = "sha256:804d99b24ad523a1fe18cc707bf741670332f7c7412e9d49cb5eab67e886b9b5"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-win_amd64.whl", hash = "sha256:a6cdcc3ede532f4a4b96000b6362099591ab4a3e913d70bcbac2b56c872446f7"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:72dffbd8b4194858d0941062a9766f8297e8868e1dd07a7b36212aaa90f49472"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:30dcc86377618a4c8f3b72418df92e77be4254d8f89f14b8e8f57d6d43603c0f"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:31a34c508c003a4347d389a9e6fcc2307cc2150eb516462a7a17512130de109e"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:15208be1c50b99203fe88d15695f22a5bed95ab3f84354c494bcb1d08557df67"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1873aade94b74715be2246321c8650cabf5a0d098a95bab81145ffffa4c13876"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a58c98a7e9c021f357348867f537017057c2ed7f77337fd914d0bedb35dace7"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4686818798f9194d03c9129a4d9a702d9e113a89cb03bffe08c6cf799e053291"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:ebdc36bea43063116f0486869652cb2ed7032dbc59fbcb4445c4862b5c1ecf7f"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:ca08decd2697fdea0aea364b370b1249d47336aec935f87b8bbfd7da5b2ee9c1"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ac05fb791acf5e1a3e39402641827780fe44d27e72567a000412c648a85ba860"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-win32.whl", hash = "sha256:9dba73be7305b399924709b91682299794887cbbd88e38226ed9f6712eabee90"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-win_amd64.whl", hash = "sha256:f7ae5d65ccfbebdfa761585228eb4d0df3a8b15cfb53bd953e713e09fbb12957"}, -] - -[[package]] -name = "ptyprocess" -version = "0.7.0" -description = "Run a subprocess in a pseudo terminal" -optional = false -python-versions = "*" -files = [ - {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, - {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, -] - -[[package]] -name = "pure-eval" -version = "0.2.2" -description = "Safely evaluate AST nodes without side effects" -optional = false -python-versions = "*" -files = [ - {file = "pure_eval-0.2.2-py3-none-any.whl", hash = "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350"}, - {file = "pure_eval-0.2.2.tar.gz", hash = "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3"}, -] - -[package.extras] -tests = ["pytest"] - -[[package]] -name = "pycodestyle" -version = "2.11.1" -description = "Python style guide checker" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pycodestyle-2.11.1-py2.py3-none-any.whl", hash = "sha256:44fe31000b2d866f2e41841b18528a505fbd7fef9017b04eff4e2648a0fadc67"}, - {file = "pycodestyle-2.11.1.tar.gz", hash = "sha256:41ba0e7afc9752dfb53ced5489e89f8186be00e599e712660695b7a75ff2663f"}, -] - -[[package]] -name = "pycparser" -version = "2.21" -description = "C parser in Python" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -files = [ - {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, - {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, -] - -[[package]] -name = "pyflakes" -version = "3.1.0" -description = "passive checker of Python programs" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pyflakes-3.1.0-py2.py3-none-any.whl", hash = "sha256:4132f6d49cb4dae6819e5379898f2b8cce3c5f23994194c24b77d5da2e36f774"}, - {file = "pyflakes-3.1.0.tar.gz", hash = "sha256:a0aae034c444db0071aa077972ba4768d40c830d9539fd45bf4cd3f8f6992efc"}, -] - -[[package]] -name = "pygments" -version = "2.17.2" -description = "Pygments is a syntax highlighting package written in Python." -optional = false -python-versions = ">=3.7" -files = [ - {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"}, - {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"}, -] - -[package.extras] -plugins = ["importlib-metadata"] -windows-terminal = ["colorama (>=0.4.6)"] - -[[package]] -name = "pyjwt" -version = "2.8.0" -description = "JSON Web Token implementation in Python" -optional = false -python-versions = ">=3.7" -files = [ - {file = "PyJWT-2.8.0-py3-none-any.whl", hash = "sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320"}, - {file = "PyJWT-2.8.0.tar.gz", hash = "sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de"}, -] - -[package.dependencies] -cryptography = {version = ">=3.4.0", optional = true, markers = "extra == \"crypto\""} - -[package.extras] -crypto = ["cryptography (>=3.4.0)"] -dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"] -docs = ["sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"] -tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] - -[[package]] -name = "pymarkdownlnt" -version = "0.9.14" -description = "A GitHub Flavored Markdown compliant Markdown linter." -optional = false -python-versions = ">=3.8.0" -files = [ - {file = "pymarkdownlnt-0.9.14-py3-none-any.whl", hash = "sha256:7db466fe9170b8144a4101362171d111233dbd5c7710f896c525456e27559efb"}, - {file = "pymarkdownlnt-0.9.14.tar.gz", hash = "sha256:3f75977a812a14b305773167a8774b6930ff30528cd7f75da8c4e865c19a504f"}, -] - -[package.dependencies] -application-properties = ">=0.8.1" -columnar = ">=1.4.0" -typing-extensions = ">=4.7.0" - -[[package]] -name = "pytest" -version = "7.4.3" -description = "pytest: simple powerful testing with Python" -optional = false -python-versions = ">=3.7" -files = [ - {file = "pytest-7.4.3-py3-none-any.whl", hash = "sha256:0d009c083ea859a71b76adf7c1d502e4bc170b80a8ef002da5806527b9591fac"}, - {file = "pytest-7.4.3.tar.gz", hash = "sha256:d989d136982de4e3b29dabcc838ad581c64e8ed52c11fbe86ddebd9da0818cd5"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "sys_platform == \"win32\""} -iniconfig = "*" -packaging = "*" -pluggy = ">=0.12,<2.0" - -[package.extras] -testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] - -[[package]] -name = "pytest-deadfixtures" -version = "2.2.1" -description = "A simple plugin to list unused fixtures in pytest" -optional = false -python-versions = "*" -files = [ - {file = "pytest-deadfixtures-2.2.1.tar.gz", hash = "sha256:ca15938a4e8330993ccec9c6c847383d88b3cd574729530647dc6b492daa9c1e"}, - {file = "pytest_deadfixtures-2.2.1-py2.py3-none-any.whl", hash = "sha256:db71533f2d9456227084e00a1231e732973e299ccb7c37ab92e95032ab6c083e"}, -] - -[package.dependencies] -pytest = ">=3.0.0" - -[[package]] -name = "pytest-django" -version = "4.7.0" -description = "A Django plugin for pytest." -optional = false -python-versions = ">=3.8" -files = [ - {file = "pytest-django-4.7.0.tar.gz", hash = "sha256:92d6fd46b1d79b54fb6b060bbb39428073396cec717d5f2e122a990d4b6aa5e8"}, - {file = "pytest_django-4.7.0-py3-none-any.whl", hash = "sha256:4e1c79d5261ade2dd58d91208017cd8f62cb4710b56e012ecd361d15d5d662a2"}, -] - -[package.dependencies] -pytest = ">=7.0.0" - -[package.extras] -docs = ["sphinx", "sphinx-rtd-theme"] -testing = ["Django", "django-configurations (>=2.0)"] - -[[package]] -name = "pytest-env" -version = "1.1.1" -description = "pytest plugin that allows you to add environment variables." -optional = false -python-versions = ">=3.8" -files = [ - {file = "pytest_env-1.1.1-py3-none-any.whl", hash = "sha256:2b71b37c6810f28bec790a7b373c777af87352b3a359b3de0edb9d24df5cf8b3"}, - {file = "pytest_env-1.1.1.tar.gz", hash = "sha256:1efb8acce1f6431196150f3b30673443ff05a6fabff64539a9495cd2248adf9e"}, -] - -[package.dependencies] -pytest = ">=7.4.3" - -[package.extras] -test = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "pytest-mock (>=3.12)"] - -[[package]] -name = "pytest-freezegun" -version = "0.4.2" -description = "Wrap tests with fixtures in freeze_time" -optional = false -python-versions = "*" -files = [ - {file = "pytest-freezegun-0.4.2.zip", hash = "sha256:19c82d5633751bf3ec92caa481fb5cffaac1787bd485f0df6436fd6242176949"}, - {file = "pytest_freezegun-0.4.2-py2.py3-none-any.whl", hash = "sha256:5318a6bfb8ba4b709c8471c94d0033113877b3ee02da5bfcd917c1889cde99a7"}, -] - -[package.dependencies] -freezegun = ">0.3" -pytest = ">=3.0.0" - -[[package]] -name = "pytest-mock" -version = "3.12.0" -description = "Thin-wrapper around the mock package for easier use with pytest" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pytest-mock-3.12.0.tar.gz", hash = "sha256:31a40f038c22cad32287bb43932054451ff5583ff094bca6f675df2f8bc1a6e9"}, - {file = "pytest_mock-3.12.0-py3-none-any.whl", hash = "sha256:0972719a7263072da3a21c7f4773069bcc7486027d7e8e1f81d98a47e701bc4f"}, -] - -[package.dependencies] -pytest = ">=5.0" - -[package.extras] -dev = ["pre-commit", "pytest-asyncio", "tox"] - -[[package]] -name = "pytest-randomly" -version = "3.15.0" -description = "Pytest plugin to randomly order tests and control random.seed." -optional = false -python-versions = ">=3.8" -files = [ - {file = "pytest_randomly-3.15.0-py3-none-any.whl", hash = "sha256:0516f4344b29f4e9cdae8bce31c4aeebf59d0b9ef05927c33354ff3859eeeca6"}, - {file = "pytest_randomly-3.15.0.tar.gz", hash = "sha256:b908529648667ba5e54723088edd6f82252f540cc340d748d1fa985539687047"}, -] - -[package.dependencies] -pytest = "*" - -[[package]] -name = "pytest-xdist" -version = "3.5.0" -description = "pytest xdist plugin for distributed testing, most importantly across multiple CPUs" -optional = false -python-versions = ">=3.7" -files = [ - {file = "pytest-xdist-3.5.0.tar.gz", hash = "sha256:cbb36f3d67e0c478baa57fa4edc8843887e0f6cfc42d677530a36d7472b32d8a"}, - {file = "pytest_xdist-3.5.0-py3-none-any.whl", hash = "sha256:d075629c7e00b611df89f490a5063944bee7a4362a5ff11c7cc7824a03dfce24"}, -] - -[package.dependencies] -execnet = ">=1.1" -pytest = ">=6.2.0" - -[package.extras] -psutil = ["psutil (>=3.0)"] -setproctitle = ["setproctitle"] -testing = ["filelock"] - -[[package]] -name = "python-dateutil" -version = "2.8.2" -description = "Extensions to the standard Python datetime module" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" -files = [ - {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, - {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, -] - -[package.dependencies] -six = ">=1.5" - -[[package]] -name = "python-ipware" -version = "2.0.0" -description = "A Python package to retrieve user's IP address" -optional = false -python-versions = ">=3.7" -files = [ - {file = "python-ipware-2.0.0.tar.gz", hash = "sha256:a52757123c718342f74b16ab2d9d4a531888d69d10b8197c073164635df0a13b"}, - {file = "python_ipware-2.0.0-py3-none-any.whl", hash = "sha256:802858aa13308d572876d1883edae0eae380fe70a51fdefcb46c8a2099240862"}, -] - -[package.extras] -dev = ["coverage[toml]", "coveralls (>=3.3,<4.0)", "ruff", "twine"] - -[[package]] -name = "pytz" -version = "2023.3.post1" -description = "World timezone definitions, modern and historical" -optional = false -python-versions = "*" -files = [ - {file = "pytz-2023.3.post1-py2.py3-none-any.whl", hash = "sha256:ce42d816b81b68506614c11e8937d3aa9e41007ceb50bfdcb0749b921bf646c7"}, - {file = "pytz-2023.3.post1.tar.gz", hash = "sha256:7b4fddbeb94a1eba4b557da24f19fdf9db575192544270a9101d8509f9f43d7b"}, -] - -[[package]] -name = "pyyaml" -version = "6.0.1" -description = "YAML parser and emitter for Python" -optional = false -python-versions = ">=3.6" -files = [ - {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, - {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, - {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, - {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, - {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, - {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, - {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, - {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, - {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, - {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, - {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, - {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, - {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, - {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, - {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, - {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, - {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, - {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, - {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, - {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, - {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, - {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, -] - -[[package]] -name = "redis" -version = "5.0.1" -description = "Python client for Redis database and key-value store" -optional = false -python-versions = ">=3.7" -files = [ - {file = "redis-5.0.1-py3-none-any.whl", hash = "sha256:ed4802971884ae19d640775ba3b03aa2e7bd5e8fb8dfaed2decce4d0fc48391f"}, - {file = "redis-5.0.1.tar.gz", hash = "sha256:0dab495cd5753069d3bc650a0dde8a8f9edde16fc5691b689a566eda58100d0f"}, -] - -[package.dependencies] -async-timeout = {version = ">=4.0.2", markers = "python_full_version <= \"3.11.2\""} - -[package.extras] -hiredis = ["hiredis (>=1.0.0)"] -ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)"] - -[[package]] -name = "referencing" -version = "0.31.0" -description = "JSON Referencing + Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "referencing-0.31.0-py3-none-any.whl", hash = "sha256:381b11e53dd93babb55696c71cf42aef2d36b8a150c49bf0bc301e36d536c882"}, - {file = "referencing-0.31.0.tar.gz", hash = "sha256:cc28f2c88fbe7b961a7817a0abc034c09a1e36358f82fedb4ffdf29a25398863"}, -] - -[package.dependencies] -attrs = ">=22.2.0" -rpds-py = ">=0.7.0" - -[[package]] -name = "requests" -version = "2.31.0" -description = "Python HTTP for Humans." -optional = false -python-versions = ">=3.7" -files = [ - {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, - {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, -] - -[package.dependencies] -certifi = ">=2017.4.17" -charset-normalizer = ">=2,<4" -idna = ">=2.5,<4" -urllib3 = ">=1.21.1,<3" - -[package.extras] -socks = ["PySocks (>=1.5.6,!=1.5.7)"] -use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] - -[[package]] -name = "rpds-py" -version = "0.13.1" -description = "Python bindings to Rust's persistent data structures (rpds)" -optional = false -python-versions = ">=3.8" -files = [ - {file = "rpds_py-0.13.1-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:83feb0f682d75a09ddc11aa37ba5c07dd9b824b22915207f6176ea458474ff75"}, - {file = "rpds_py-0.13.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fa84bbe22ffa108f91631935c28a623001e335d66e393438258501e618fb0dde"}, - {file = "rpds_py-0.13.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e04f8c76b8d5c70695b4e8f1d0b391d8ef91df00ef488c6c1ffb910176459bc6"}, - {file = "rpds_py-0.13.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:032c242a595629aacace44128f9795110513ad27217b091e834edec2fb09e800"}, - {file = "rpds_py-0.13.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91276caef95556faeb4b8f09fe4439670d3d6206fee78d47ddb6e6de837f0b4d"}, - {file = "rpds_py-0.13.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d22f2cb82e0b40e427a74a93c9a4231335bbc548aed79955dde0b64ea7f88146"}, - {file = "rpds_py-0.13.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63c9e2794329ef070844ff9bfc012004aeddc0468dc26970953709723f76c8a5"}, - {file = "rpds_py-0.13.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c797ea56f36c6f248656f0223b11307fdf4a1886f3555eba371f34152b07677f"}, - {file = "rpds_py-0.13.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:82dbcd6463e580bcfb7561cece35046aaabeac5a9ddb775020160b14e6c58a5d"}, - {file = "rpds_py-0.13.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:736817dbbbd030a69a1faf5413a319976c9c8ba8cdcfa98c022d3b6b2e01eca6"}, - {file = "rpds_py-0.13.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1f36a1e80ef4ed1996445698fd91e0d3e54738bf597c9995118b92da537d7a28"}, - {file = "rpds_py-0.13.1-cp310-none-win32.whl", hash = "sha256:4f13d3f6585bd07657a603780e99beda96a36c86acaba841f131e81393958336"}, - {file = "rpds_py-0.13.1-cp310-none-win_amd64.whl", hash = "sha256:545e94c84575057d3d5c62634611858dac859702b1519b6ffc58eca7fb1adfcf"}, - {file = "rpds_py-0.13.1-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:6bfe72b249264cc1ff2f3629be240d7d2fdc778d9d298087cdec8524c91cd11f"}, - {file = "rpds_py-0.13.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edc91c50e17f5cd945d821f0f1af830522dba0c10267c3aab186dc3dbaab8def"}, - {file = "rpds_py-0.13.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2eca04a365be380ca1f8fa48b334462e19e3382c0bb7386444d8ca43aa01c481"}, - {file = "rpds_py-0.13.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3e3ac5b602fea378243f993d8b707189f9061e55ebb4e56cb9fdef8166060f28"}, - {file = "rpds_py-0.13.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dfb5d2ab183c0efe5e7b8917e4eaa2e837aacafad8a69b89aa6bc81550eed857"}, - {file = "rpds_py-0.13.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d9793d46d3e6522ae58e9321032827c9c0df1e56cbe5d3de965facb311aed6aa"}, - {file = "rpds_py-0.13.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9cd935c0220d012a27c20135c140f9cdcbc6249d5954345c81bfb714071b985c"}, - {file = "rpds_py-0.13.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:37b08df45f02ff1866043b95096cbe91ac99de05936dd09d6611987a82a3306a"}, - {file = "rpds_py-0.13.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ad666a904212aa9a6c77da7dce9d5170008cda76b7776e6731928b3f8a0d40fa"}, - {file = "rpds_py-0.13.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8a6ad8429340e0a4de89353447c6441329def3632e7b2293a7d6e873217d3c2b"}, - {file = "rpds_py-0.13.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7c40851b659d958c5245c1236e34f0d065cc53dca8d978b49a032c8e0adfda6e"}, - {file = "rpds_py-0.13.1-cp311-none-win32.whl", hash = "sha256:4145172ab59b6c27695db6d78d040795f635cba732cead19c78cede74800949a"}, - {file = "rpds_py-0.13.1-cp311-none-win_amd64.whl", hash = "sha256:46a07a258bda12270de02b34c4884f200f864bba3dcd6e3a37fef36a168b859d"}, - {file = "rpds_py-0.13.1-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:ba4432301ad7eeb1b00848cf46fae0e5fecfd18a8cb5fdcf856c67985f79ecc7"}, - {file = "rpds_py-0.13.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d22e0660de24bd8e9ac82f4230a22a5fe4e397265709289d61d5fb333839ba50"}, - {file = "rpds_py-0.13.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76a8374b294e4ccb39ccaf11d39a0537ed107534139c00b4393ca3b542cc66e5"}, - {file = "rpds_py-0.13.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7d152ec7bb431040af2500e01436c9aa0d993f243346f0594a15755016bf0be1"}, - {file = "rpds_py-0.13.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:74a2044b870df7c9360bb3ce7e12f9ddf8e72e49cd3a353a1528cbf166ad2383"}, - {file = "rpds_py-0.13.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:960e7e460fda2d0af18c75585bbe0c99f90b8f09963844618a621b804f8c3abe"}, - {file = "rpds_py-0.13.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37f79f4f1f06cc96151f4a187528c3fd4a7e1065538a4af9eb68c642365957f7"}, - {file = "rpds_py-0.13.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cd4ea56c9542ad0091dfdef3e8572ae7a746e1e91eb56c9e08b8d0808b40f1d1"}, - {file = "rpds_py-0.13.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0290712eb5603a725769b5d857f7cf15cf6ca93dda3128065bbafe6fdb709beb"}, - {file = "rpds_py-0.13.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0b70c1f800059c92479dc94dda41288fd6607f741f9b1b8f89a21a86428f6383"}, - {file = "rpds_py-0.13.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3dd5fb7737224e1497c886fb3ca681c15d9c00c76171f53b3c3cc8d16ccfa7fb"}, - {file = "rpds_py-0.13.1-cp312-none-win32.whl", hash = "sha256:74be3b215a5695690a0f1a9f68b1d1c93f8caad52e23242fcb8ba56aaf060281"}, - {file = "rpds_py-0.13.1-cp312-none-win_amd64.whl", hash = "sha256:f47eef55297799956464efc00c74ae55c48a7b68236856d56183fe1ddf866205"}, - {file = "rpds_py-0.13.1-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:e4a45ba34f904062c63049a760790c6a2fa7a4cc4bd160d8af243b12371aaa05"}, - {file = "rpds_py-0.13.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:20147996376be452cd82cd6c17701daba69a849dc143270fa10fe067bb34562a"}, - {file = "rpds_py-0.13.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42b9535aa22ab023704cfc6533e968f7e420affe802d85e956d8a7b4c0b0b5ea"}, - {file = "rpds_py-0.13.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d4fa1eeb9bea6d9b64ac91ec51ee94cc4fc744955df5be393e1c923c920db2b0"}, - {file = "rpds_py-0.13.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b2415d5a7b7ee96aa3a54d4775c1fec140476a17ee12353806297e900eaeddc"}, - {file = "rpds_py-0.13.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:577d40a72550eac1386b77b43836151cb61ff6700adacda2ad4d883ca5a0b6f2"}, - {file = "rpds_py-0.13.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af2d1648eb625a460eee07d3e1ea3a4a6e84a1fb3a107f6a8e95ac19f7dcce67"}, - {file = "rpds_py-0.13.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5b769396eb358d6b55dbf78f3f7ca631ca1b2fe02136faad5af74f0111b4b6b7"}, - {file = "rpds_py-0.13.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:249c8e0055ca597707d71c5ad85fd2a1c8fdb99386a8c6c257e1b47b67a9bec1"}, - {file = "rpds_py-0.13.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:fe30ef31172bdcf946502a945faad110e8fff88c32c4bec9a593df0280e64d8a"}, - {file = "rpds_py-0.13.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:2647192facf63be9ed2d7a49ceb07efe01dc6cfb083bd2cc53c418437400cb99"}, - {file = "rpds_py-0.13.1-cp38-none-win32.whl", hash = "sha256:4011d5c854aa804c833331d38a2b6f6f2fe58a90c9f615afdb7aa7cf9d31f721"}, - {file = "rpds_py-0.13.1-cp38-none-win_amd64.whl", hash = "sha256:7cfae77da92a20f56cf89739a557b76e5c6edc094f6ad5c090b9e15fbbfcd1a4"}, - {file = "rpds_py-0.13.1-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:e9be1f7c5f9673616f875299339984da9447a40e3aea927750c843d6e5e2e029"}, - {file = "rpds_py-0.13.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:839676475ac2ccd1532d36af3d10d290a2ca149b702ed464131e450a767550df"}, - {file = "rpds_py-0.13.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a90031658805c63fe488f8e9e7a88b260ea121ba3ee9cdabcece9c9ddb50da39"}, - {file = "rpds_py-0.13.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8ba9fbc5d6e36bfeb5292530321cc56c4ef3f98048647fabd8f57543c34174ec"}, - {file = "rpds_py-0.13.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:08832078767545c5ee12561ce980714e1e4c6619b5b1e9a10248de60cddfa1fd"}, - {file = "rpds_py-0.13.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:19f5aa7f5078d35ed8e344bcba40f35bc95f9176dddb33fc4f2084e04289fa63"}, - {file = "rpds_py-0.13.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80080972e1d000ad0341c7cc58b6855c80bd887675f92871221451d13a975072"}, - {file = "rpds_py-0.13.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:181ee352691c4434eb1c01802e9daa5edcc1007ff15023a320e2693fed6a661b"}, - {file = "rpds_py-0.13.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:d20da6b4c7aa9ee75ad0730beaba15d65157f5beeaca54a038bb968f92bf3ce3"}, - {file = "rpds_py-0.13.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:faa12a9f34671a30ea6bb027f04ec4e1fb8fa3fb3ed030893e729d4d0f3a9791"}, - {file = "rpds_py-0.13.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7cf241dbb50ea71c2e628ab2a32b5bfcd36e199152fc44e5c1edb0b773f1583e"}, - {file = "rpds_py-0.13.1-cp39-none-win32.whl", hash = "sha256:dab979662da1c9fbb464e310c0b06cb5f1d174d09a462553af78f0bfb3e01920"}, - {file = "rpds_py-0.13.1-cp39-none-win_amd64.whl", hash = "sha256:a2b3c79586636f1fa69a7bd59c87c15fca80c0d34b5c003d57f2f326e5276575"}, - {file = "rpds_py-0.13.1-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:5967fa631d0ed9f8511dede08bc943a9727c949d05d1efac4ac82b2938024fb7"}, - {file = "rpds_py-0.13.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8308a8d49d1354278d5c068c888a58d7158a419b2e4d87c7839ed3641498790c"}, - {file = "rpds_py-0.13.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0580faeb9def6d0beb7aa666294d5604e569c4e24111ada423cf9936768d95c"}, - {file = "rpds_py-0.13.1-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2da81c1492291c1a90987d76a47c7b2d310661bf7c93a9de0511e27b796a8b46"}, - {file = "rpds_py-0.13.1-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1c9a1dc5e898ce30e2f9c0aa57181cddd4532b22b7780549441d6429d22d3b58"}, - {file = "rpds_py-0.13.1-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4ae6f423cb7d1c6256b7482025ace2825728f53b7ac58bcd574de6ee9d242c2"}, - {file = "rpds_py-0.13.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc3179e0815827cf963e634095ae5715ee73a5af61defbc8d6ca79f1bdae1d1d"}, - {file = "rpds_py-0.13.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0d9f8930092558fd15c9e07198625efb698f7cc00b3dc311c83eeec2540226a8"}, - {file = "rpds_py-0.13.1-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:d1d388d2f5f5a6065cf83c54dd12112b7389095669ff395e632003ae8999c6b8"}, - {file = "rpds_py-0.13.1-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:08b335fb0c45f0a9e2478a9ece6a1bfb00b6f4c4780f9be3cf36479c5d8dd374"}, - {file = "rpds_py-0.13.1-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:d11afdc5992bbd7af60ed5eb519873690d921425299f51d80aa3099ed49f2bcc"}, - {file = "rpds_py-0.13.1-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:8c1f6c8df23be165eb0cb78f305483d00c6827a191e3a38394c658d5b9c80bbd"}, - {file = "rpds_py-0.13.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:528e2afaa56d815d2601b857644aeb395afe7e59212ab0659906dc29ae68d9a6"}, - {file = "rpds_py-0.13.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df2af1180b8eeececf4f819d22cc0668bfadadfd038b19a90bd2fb2ee419ec6f"}, - {file = "rpds_py-0.13.1-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:88956c993a20201744282362e3fd30962a9d86dc4f1dcf2bdb31fab27821b61f"}, - {file = "rpds_py-0.13.1-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee70ee5f4144a45a9e6169000b5b525d82673d5dab9f7587eccc92794814e7ac"}, - {file = "rpds_py-0.13.1-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c5fd099acaee2325f01281a130a39da08d885e4dedf01b84bf156ec2737d78fe"}, - {file = "rpds_py-0.13.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9656a09653b18b80764647d585750df2dff8928e03a706763ab40ec8c4872acc"}, - {file = "rpds_py-0.13.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7ba239bb37663b2b4cd08e703e79e13321512dccd8e5f0e9451d9e53a6b8509a"}, - {file = "rpds_py-0.13.1-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:3f55ae773abd96b1de25fc5c3fb356f491bd19116f8f854ba705beffc1ddc3c5"}, - {file = "rpds_py-0.13.1-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:f4b15a163448ec79241fb2f1bc5a8ae1a4a304f7a48d948d208a2935b26bf8a5"}, - {file = "rpds_py-0.13.1-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:1a3b2583c86bbfbf417304eeb13400ce7f8725376dc7d3efbf35dc5d7052ad48"}, - {file = "rpds_py-0.13.1-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:f1059ca9a51c936c9a8d46fbc2c9a6b4c15ab3f13a97f1ad32f024b39666ba85"}, - {file = "rpds_py-0.13.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:f55601fb58f92e4f4f1d05d80c24cb77505dc42103ddfd63ddfdc51d3da46fa2"}, - {file = "rpds_py-0.13.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fcfd5f91b882eedf8d9601bd21261d6ce0e61a8c66a7152d1f5df08d3f643ab1"}, - {file = "rpds_py-0.13.1-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6574f619e8734140d96c59bfa8a6a6e7a3336820ccd1bfd95ffa610673b650a2"}, - {file = "rpds_py-0.13.1-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a4b9d3f5c48bbe8d9e3758e498b3c34863f2c9b1ac57a4e6310183740e59c980"}, - {file = "rpds_py-0.13.1-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cdd6f8738e1f1d9df5b1603bb03cb30e442710e5672262b95d0f9fcb4edb0dab"}, - {file = "rpds_py-0.13.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8c2bf286e5d755a075e5e97ba56b3de08cccdad6b323ab0b21cc98875176b03"}, - {file = "rpds_py-0.13.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b3d4b390ee70ca9263b331ccfaf9819ee20e90dfd0201a295e23eb64a005dbef"}, - {file = "rpds_py-0.13.1-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:db8d0f0ad92f74feb61c4e4a71f1d573ef37c22ef4dc19cab93e501bfdad8cbd"}, - {file = "rpds_py-0.13.1-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:2abd669a39be69cdfe145927c7eb53a875b157740bf1e2d49e9619fc6f43362e"}, - {file = "rpds_py-0.13.1-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:2c173f529666bab8e3f948b74c6d91afa22ea147e6ebae49a48229d9020a47c4"}, - {file = "rpds_py-0.13.1.tar.gz", hash = "sha256:264f3a5906c62b9df3a00ad35f6da1987d321a053895bd85f9d5c708de5c0fbf"}, -] - -[[package]] -name = "sentry-sdk" -version = "1.37.1" -description = "Python client for Sentry (https://sentry.io)" -optional = false -python-versions = "*" -files = [ - {file = "sentry-sdk-1.37.1.tar.gz", hash = "sha256:7cd324dd2877fdc861f75cba4242bce23a58272a6fea581fcb218bb718bd9cc5"}, - {file = "sentry_sdk-1.37.1-py2.py3-none-any.whl", hash = "sha256:a249c7364827ee89daaa078bb8b56ece0b3d52d9130961bef2302b79bdf7fe70"}, -] - -[package.dependencies] -certifi = "*" -urllib3 = {version = ">=1.26.11", markers = "python_version >= \"3.6\""} - -[package.extras] -aiohttp = ["aiohttp (>=3.5)"] -arq = ["arq (>=0.23)"] -asyncpg = ["asyncpg (>=0.23)"] -beam = ["apache-beam (>=2.12)"] -bottle = ["bottle (>=0.12.13)"] -celery = ["celery (>=3)"] -chalice = ["chalice (>=1.16.0)"] -clickhouse-driver = ["clickhouse-driver (>=0.2.0)"] -django = ["django (>=1.8)"] -falcon = ["falcon (>=1.4)"] -fastapi = ["fastapi (>=0.79.0)"] -flask = ["blinker (>=1.1)", "flask (>=0.11)", "markupsafe"] -grpcio = ["grpcio (>=1.21.1)"] -httpx = ["httpx (>=0.16.0)"] -huey = ["huey (>=2)"] -loguru = ["loguru (>=0.5)"] -opentelemetry = ["opentelemetry-distro (>=0.35b0)"] -opentelemetry-experimental = ["opentelemetry-distro (>=0.40b0,<1.0)", "opentelemetry-instrumentation-aiohttp-client (>=0.40b0,<1.0)", "opentelemetry-instrumentation-django (>=0.40b0,<1.0)", "opentelemetry-instrumentation-fastapi (>=0.40b0,<1.0)", "opentelemetry-instrumentation-flask (>=0.40b0,<1.0)", "opentelemetry-instrumentation-requests (>=0.40b0,<1.0)", "opentelemetry-instrumentation-sqlite3 (>=0.40b0,<1.0)", "opentelemetry-instrumentation-urllib (>=0.40b0,<1.0)"] -pure-eval = ["asttokens", "executing", "pure-eval"] -pymongo = ["pymongo (>=3.1)"] -pyspark = ["pyspark (>=2.4.4)"] -quart = ["blinker (>=1.1)", "quart (>=0.16.1)"] -rq = ["rq (>=0.6)"] -sanic = ["sanic (>=0.8)"] -sqlalchemy = ["sqlalchemy (>=1.2)"] -starlette = ["starlette (>=0.19.1)"] -starlite = ["starlite (>=1.48)"] -tornado = ["tornado (>=5)"] - -[[package]] -name = "setuptools" -version = "69.0.2" -description = "Easily download, build, install, upgrade, and uninstall Python packages" -optional = false -python-versions = ">=3.8" -files = [ - {file = "setuptools-69.0.2-py3-none-any.whl", hash = "sha256:1e8fdff6797d3865f37397be788a4e3cba233608e9b509382a2777d25ebde7f2"}, - {file = "setuptools-69.0.2.tar.gz", hash = "sha256:735896e78a4742605974de002ac60562d286fa8051a7e2299445e8e8fbb01aa6"}, -] - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] - -[[package]] -name = "six" -version = "1.16.0" -description = "Python 2 and 3 compatibility utilities" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" -files = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, -] - -[[package]] -name = "sqlparse" -version = "0.4.4" -description = "A non-validating SQL parser." -optional = false -python-versions = ">=3.5" -files = [ - {file = "sqlparse-0.4.4-py3-none-any.whl", hash = "sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3"}, - {file = "sqlparse-0.4.4.tar.gz", hash = "sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c"}, -] - -[package.extras] -dev = ["build", "flake8"] -doc = ["sphinx"] -test = ["pytest", "pytest-cov"] - -[[package]] -name = "stack-data" -version = "0.6.3" -description = "Extract data from python stack frames and tracebacks for informative displays" -optional = false -python-versions = "*" -files = [ - {file = "stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695"}, - {file = "stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9"}, -] - -[package.dependencies] -asttokens = ">=2.1.0" -executing = ">=1.2.0" -pure-eval = "*" - -[package.extras] -tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] - -[[package]] -name = "toml-sort" -version = "0.23.1" -description = "Toml sorting library" -optional = false -python-versions = ">=3.7,<4.0" -files = [ - {file = "toml_sort-0.23.1-py3-none-any.whl", hash = "sha256:69ae60de9c4d67478533697eb4119092e2b30ddffe5ca09bbad3912905c935a0"}, - {file = "toml_sort-0.23.1.tar.gz", hash = "sha256:833728c48b0f8d509aecd9ae8347768ca3a9332977b32c9fd2002932f0eb9c90"}, -] - -[package.dependencies] -tomlkit = ">=0.11.2" - -[[package]] -name = "tomli" -version = "2.0.1" -description = "A lil' TOML parser" -optional = false -python-versions = ">=3.7" -files = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, -] - -[[package]] -name = "tomlkit" -version = "0.12.3" -description = "Style preserving TOML library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "tomlkit-0.12.3-py3-none-any.whl", hash = "sha256:b0a645a9156dc7cb5d3a1f0d4bab66db287fcb8e0430bdd4664a095ea16414ba"}, - {file = "tomlkit-0.12.3.tar.gz", hash = "sha256:75baf5012d06501f07bee5bf8e801b9f343e7aac5a92581f20f80ce632e6b5a4"}, -] - -[[package]] -name = "toolz" -version = "0.12.0" -description = "List processing tools and functional utilities" -optional = false -python-versions = ">=3.5" -files = [ - {file = "toolz-0.12.0-py3-none-any.whl", hash = "sha256:2059bd4148deb1884bb0eb770a3cde70e7f954cfbbdc2285f1f2de01fd21eb6f"}, - {file = "toolz-0.12.0.tar.gz", hash = "sha256:88c570861c440ee3f2f6037c4654613228ff40c93a6c25e0eba70d17282c6194"}, -] - -[[package]] -name = "traitlets" -version = "5.13.0" -description = "Traitlets Python configuration system" -optional = false -python-versions = ">=3.8" -files = [ - {file = "traitlets-5.13.0-py3-none-any.whl", hash = "sha256:baf991e61542da48fe8aef8b779a9ea0aa38d8a54166ee250d5af5ecf4486619"}, - {file = "traitlets-5.13.0.tar.gz", hash = "sha256:9b232b9430c8f57288c1024b34a8f0251ddcc47268927367a0dd3eeaca40deb5"}, -] - -[package.extras] -docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] -test = ["argcomplete (>=3.0.3)", "mypy (>=1.6.0)", "pre-commit", "pytest (>=7.0,<7.5)", "pytest-mock", "pytest-mypy-testing"] - -[[package]] -name = "types-freezegun" -version = "1.1.10" -description = "Typing stubs for freezegun" -optional = false -python-versions = "*" -files = [ - {file = "types-freezegun-1.1.10.tar.gz", hash = "sha256:cb3a2d2eee950eacbaac0673ab50499823365ceb8c655babb1544a41446409ec"}, - {file = "types_freezegun-1.1.10-py3-none-any.whl", hash = "sha256:fadebe72213e0674036153366205038e1f95c8ca96deb4ef9b71ddc15413543e"}, -] - -[[package]] -name = "types-pillow" -version = "10.1.0.2" -description = "Typing stubs for Pillow" -optional = false -python-versions = ">=3.7" -files = [ - {file = "types-Pillow-10.1.0.2.tar.gz", hash = "sha256:525c1c5ee67b0ac1721c40d2bc618226ef2123c347e527e14e05b920721a13b9"}, - {file = "types_Pillow-10.1.0.2-py3-none-any.whl", hash = "sha256:131078ffa547bf9a201d39ffcdc65633e108148085f4f1b07d4647fcfec6e923"}, -] - -[[package]] -name = "types-pytz" -version = "2023.3.1.1" -description = "Typing stubs for pytz" -optional = false -python-versions = "*" -files = [ - {file = "types-pytz-2023.3.1.1.tar.gz", hash = "sha256:cc23d0192cd49c8f6bba44ee0c81e4586a8f30204970fc0894d209a6b08dab9a"}, - {file = "types_pytz-2023.3.1.1-py3-none-any.whl", hash = "sha256:1999a123a3dc0e39a2ef6d19f3f8584211de9e6a77fe7a0259f04a524e90a5cf"}, -] - -[[package]] -name = "types-pyyaml" -version = "6.0.12.12" -description = "Typing stubs for PyYAML" -optional = false -python-versions = "*" -files = [ - {file = "types-PyYAML-6.0.12.12.tar.gz", hash = "sha256:334373d392fde0fdf95af5c3f1661885fa10c52167b14593eb856289e1855062"}, - {file = "types_PyYAML-6.0.12.12-py3-none-any.whl", hash = "sha256:c05bc6c158facb0676674b7f11fe3960db4f389718e19e62bd2b84d6205cfd24"}, -] - -[[package]] -name = "types-requests" -version = "2.31.0.10" -description = "Typing stubs for requests" -optional = false -python-versions = ">=3.7" -files = [ - {file = "types-requests-2.31.0.10.tar.gz", hash = "sha256:dc5852a76f1eaf60eafa81a2e50aefa3d1f015c34cf0cba130930866b1b22a92"}, - {file = "types_requests-2.31.0.10-py3-none-any.whl", hash = "sha256:b32b9a86beffa876c0c3ac99a4cd3b8b51e973fb8e3bd4e0a6bb32c7efad80fc"}, -] - -[package.dependencies] -urllib3 = ">=2" - -[[package]] -name = "typing-extensions" -version = "4.8.0" -description = "Backported and Experimental Type Hints for Python 3.8+" -optional = false -python-versions = ">=3.8" -files = [ - {file = "typing_extensions-4.8.0-py3-none-any.whl", hash = "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0"}, - {file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"}, -] - -[[package]] -name = "tzdata" -version = "2023.3" -description = "Provider of IANA time zone data" -optional = false -python-versions = ">=2" -files = [ - {file = "tzdata-2023.3-py2.py3-none-any.whl", hash = "sha256:7e65763eef3120314099b6939b5546db7adce1e7d6f2e179e3df563c70511eda"}, - {file = "tzdata-2023.3.tar.gz", hash = "sha256:11ef1e08e54acb0d4f95bdb1be05da659673de4acbd21bf9c69e94cc5e907a3a"}, -] - -[[package]] -name = "uritemplate" -version = "4.1.1" -description = "Implementation of RFC 6570 URI Templates" -optional = false -python-versions = ">=3.6" -files = [ - {file = "uritemplate-4.1.1-py2.py3-none-any.whl", hash = "sha256:830c08b8d99bdd312ea4ead05994a38e8936266f84b9a7878232db50b044e02e"}, - {file = "uritemplate-4.1.1.tar.gz", hash = "sha256:4346edfc5c3b79f694bccd6d6099a322bbeb628dbf2cd86eea55a456ce5124f0"}, -] - -[[package]] -name = "urllib3" -version = "2.1.0" -description = "HTTP library with thread-safe connection pooling, file post, and more." -optional = false -python-versions = ">=3.8" -files = [ - {file = "urllib3-2.1.0-py3-none-any.whl", hash = "sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3"}, - {file = "urllib3-2.1.0.tar.gz", hash = "sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54"}, -] - -[package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] -socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] -zstd = ["zstandard (>=0.18.0)"] - -[[package]] -name = "wcwidth" -version = "0.2.12" -description = "Measures the displayed width of unicode strings in a terminal" -optional = false -python-versions = "*" -files = [ - {file = "wcwidth-0.2.12-py2.py3-none-any.whl", hash = "sha256:f26ec43d96c8cbfed76a5075dac87680124fa84e0855195a6184da9c187f133c"}, - {file = "wcwidth-0.2.12.tar.gz", hash = "sha256:f01c104efdf57971bcb756f054dd58ddec5204dd15fa31d6503ea57947d97c02"}, -] - -[[package]] -name = "whitenoise" -version = "6.6.0" -description = "Radically simplified static file serving for WSGI applications" -optional = false -python-versions = ">=3.8" -files = [ - {file = "whitenoise-6.6.0-py3-none-any.whl", hash = "sha256:b1f9db9bf67dc183484d760b99f4080185633136a273a03f6436034a41064146"}, - {file = "whitenoise-6.6.0.tar.gz", hash = "sha256:8998f7370973447fac1e8ef6e8ded2c5209a7b1f67c1012866dbcd09681c3251"}, -] - -[package.extras] -brotli = ["Brotli"] - -[[package]] -name = "wrapt" -version = "1.16.0" -description = "Module for decorators, wrappers and monkey patching." -optional = false -python-versions = ">=3.6" -files = [ - {file = "wrapt-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4"}, - {file = "wrapt-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020"}, - {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb2dee3874a500de01c93d5c71415fcaef1d858370d405824783e7a8ef5db440"}, - {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a88e6010048489cda82b1326889ec075a8c856c2e6a256072b28eaee3ccf487"}, - {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf"}, - {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:73aa7d98215d39b8455f103de64391cb79dfcad601701a3aa0dddacf74911d72"}, - {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:807cc8543a477ab7422f1120a217054f958a66ef7314f76dd9e77d3f02cdccd0"}, - {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bf5703fdeb350e36885f2875d853ce13172ae281c56e509f4e6eca049bdfb136"}, - {file = "wrapt-1.16.0-cp310-cp310-win32.whl", hash = "sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d"}, - {file = "wrapt-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:decbfa2f618fa8ed81c95ee18a387ff973143c656ef800c9f24fb7e9c16054e2"}, - {file = "wrapt-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09"}, - {file = "wrapt-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d"}, - {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389"}, - {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060"}, - {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1"}, - {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3"}, - {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956"}, - {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d"}, - {file = "wrapt-1.16.0-cp311-cp311-win32.whl", hash = "sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362"}, - {file = "wrapt-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89"}, - {file = "wrapt-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b"}, - {file = "wrapt-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36"}, - {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73"}, - {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809"}, - {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b"}, - {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81"}, - {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9"}, - {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c"}, - {file = "wrapt-1.16.0-cp312-cp312-win32.whl", hash = "sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc"}, - {file = "wrapt-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8"}, - {file = "wrapt-1.16.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d462f28826f4657968ae51d2181a074dfe03c200d6131690b7d65d55b0f360f8"}, - {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a33a747400b94b6d6b8a165e4480264a64a78c8a4c734b62136062e9a248dd39"}, - {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3646eefa23daeba62643a58aac816945cadc0afaf21800a1421eeba5f6cfb9c"}, - {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ebf019be5c09d400cf7b024aa52b1f3aeebeff51550d007e92c3c1c4afc2a40"}, - {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc"}, - {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:1acd723ee2a8826f3d53910255643e33673e1d11db84ce5880675954183ec47e"}, - {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:bc57efac2da352a51cc4658878a68d2b1b67dbe9d33c36cb826ca449d80a8465"}, - {file = "wrapt-1.16.0-cp36-cp36m-win32.whl", hash = "sha256:da4813f751142436b075ed7aa012a8778aa43a99f7b36afe9b742d3ed8bdc95e"}, - {file = "wrapt-1.16.0-cp36-cp36m-win_amd64.whl", hash = "sha256:6f6eac2360f2d543cc875a0e5efd413b6cbd483cb3ad7ebf888884a6e0d2e966"}, - {file = "wrapt-1.16.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a0ea261ce52b5952bf669684a251a66df239ec6d441ccb59ec7afa882265d593"}, - {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bd2d7ff69a2cac767fbf7a2b206add2e9a210e57947dd7ce03e25d03d2de292"}, - {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9159485323798c8dc530a224bd3ffcf76659319ccc7bbd52e01e73bd0241a0c5"}, - {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a86373cf37cd7764f2201b76496aba58a52e76dedfaa698ef9e9688bfd9e41cf"}, - {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:73870c364c11f03ed072dda68ff7aea6d2a3a5c3fe250d917a429c7432e15228"}, - {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b935ae30c6e7400022b50f8d359c03ed233d45b725cfdd299462f41ee5ffba6f"}, - {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:db98ad84a55eb09b3c32a96c576476777e87c520a34e2519d3e59c44710c002c"}, - {file = "wrapt-1.16.0-cp37-cp37m-win32.whl", hash = "sha256:9153ed35fc5e4fa3b2fe97bddaa7cbec0ed22412b85bcdaf54aeba92ea37428c"}, - {file = "wrapt-1.16.0-cp37-cp37m-win_amd64.whl", hash = "sha256:66dfbaa7cfa3eb707bbfcd46dab2bc6207b005cbc9caa2199bcbc81d95071a00"}, - {file = "wrapt-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1dd50a2696ff89f57bd8847647a1c363b687d3d796dc30d4dd4a9d1689a706f0"}, - {file = "wrapt-1.16.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:44a2754372e32ab315734c6c73b24351d06e77ffff6ae27d2ecf14cf3d229202"}, - {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e9723528b9f787dc59168369e42ae1c3b0d3fadb2f1a71de14531d321ee05b0"}, - {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbed418ba5c3dce92619656802cc5355cb679e58d0d89b50f116e4a9d5a9603e"}, - {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:941988b89b4fd6b41c3f0bfb20e92bd23746579736b7343283297c4c8cbae68f"}, - {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6a42cd0cfa8ffc1915aef79cb4284f6383d8a3e9dcca70c445dcfdd639d51267"}, - {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1ca9b6085e4f866bd584fb135a041bfc32cab916e69f714a7d1d397f8c4891ca"}, - {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5e49454f19ef621089e204f862388d29e6e8d8b162efce05208913dde5b9ad6"}, - {file = "wrapt-1.16.0-cp38-cp38-win32.whl", hash = "sha256:c31f72b1b6624c9d863fc095da460802f43a7c6868c5dda140f51da24fd47d7b"}, - {file = "wrapt-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:490b0ee15c1a55be9c1bd8609b8cecd60e325f0575fc98f50058eae366e01f41"}, - {file = "wrapt-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9b201ae332c3637a42f02d1045e1d0cccfdc41f1f2f801dafbaa7e9b4797bfc2"}, - {file = "wrapt-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2076fad65c6736184e77d7d4729b63a6d1ae0b70da4868adeec40989858eb3fb"}, - {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5cd603b575ebceca7da5a3a251e69561bec509e0b46e4993e1cac402b7247b8"}, - {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b47cfad9e9bbbed2339081f4e346c93ecd7ab504299403320bf85f7f85c7d46c"}, - {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a"}, - {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5f15814a33e42b04e3de432e573aa557f9f0f56458745c2074952f564c50e664"}, - {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db2e408d983b0e61e238cf579c09ef7020560441906ca990fe8412153e3b291f"}, - {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:edfad1d29c73f9b863ebe7082ae9321374ccb10879eeabc84ba3b69f2579d537"}, - {file = "wrapt-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed867c42c268f876097248e05b6117a65bcd1e63b779e916fe2e33cd6fd0d3c3"}, - {file = "wrapt-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:eb1b046be06b0fce7249f1d025cd359b4b80fc1c3e24ad9eca33e0dcdb2e4a35"}, - {file = "wrapt-1.16.0-py3-none-any.whl", hash = "sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1"}, - {file = "wrapt-1.16.0.tar.gz", hash = "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d"}, -] - -[metadata] -lock-version = "2.0" -python-versions = "~3.11" -content-hash = "528770c50e5a22550d6d4808bfdd8ec2f7df869927f845cf8d805b1a0375fbfc" From 991f539211a891a833f8a2b1ddc16c6666f507d4 Mon Sep 17 00:00:00 2001 From: hnthh Date: Tue, 5 Dec 2023 23:30:17 +0300 Subject: [PATCH 041/116] fix template proj name in dependabot ci --- .github/dependabot.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index f297c0f1..759cbcb5 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,7 +1,7 @@ version: 2 updates: - package-ecosystem: pip - directory: "/{{cookiecutter.name}}" + directory: "/{{ cookiecutter.name }}" schedule: interval: daily time: "02:00" From 3a6902b652a5679be7256c60d0999b8dcf74374c Mon Sep 17 00:00:00 2001 From: hnthh Date: Wed, 6 Dec 2023 00:36:16 +0300 Subject: [PATCH 042/116] test child project ci run from parent ci --- .github/workflows/child.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .github/workflows/child.yml diff --git a/.github/workflows/child.yml b/.github/workflows/child.yml new file mode 100644 index 00000000..b2e28ba5 --- /dev/null +++ b/.github/workflows/child.yml @@ -0,0 +1,22 @@ +name: child project workflow run + +on: + push: + branches: + - master + pull_request: + +defaults: + run: + working-directory: {{ cookiecutter.name }} + +jobs: + run: + runs-on: ubuntu-latest + + steps: + - name: checkout + uses: actions/checkout@v3 + + - name: run + uses: ./.github/workflows/ci.yml From 1548fa70960a52c4adf5783b0092bddcc6c2d82e Mon Sep 17 00:00:00 2001 From: hnthh Date: Wed, 6 Dec 2023 00:45:08 +0300 Subject: [PATCH 043/116] child ci --- .github/workflows/child.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/child.yml b/.github/workflows/child.yml index b2e28ba5..7b517c64 100644 --- a/.github/workflows/child.yml +++ b/.github/workflows/child.yml @@ -6,10 +6,6 @@ on: - master pull_request: -defaults: - run: - working-directory: {{ cookiecutter.name }} - jobs: run: runs-on: ubuntu-latest @@ -19,4 +15,5 @@ jobs: uses: actions/checkout@v3 - name: run - uses: ./.github/workflows/ci.yml + uses: ./{{ cookiecutter.name }}/.github/workflows/ci.yml + working-directory: {{ cookiecutter.name }} From 1c4ab388bfe0992bff3b4ee788709373cbe3de41 Mon Sep 17 00:00:00 2001 From: hnthh Date: Wed, 6 Dec 2023 00:51:02 +0300 Subject: [PATCH 044/116] child ci --- .github/workflows/child.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/child.yml b/.github/workflows/child.yml index 7b517c64..81c5bede 100644 --- a/.github/workflows/child.yml +++ b/.github/workflows/child.yml @@ -8,6 +8,9 @@ on: jobs: run: + defaults: + run: + working-directory: \{\{\ cookiecutter.name\ \}\}/ runs-on: ubuntu-latest steps: @@ -15,5 +18,4 @@ jobs: uses: actions/checkout@v3 - name: run - uses: ./{{ cookiecutter.name }}/.github/workflows/ci.yml - working-directory: {{ cookiecutter.name }} + uses: ./.github/workflows/ci.yml From 3886c0f9fc3b0e90282e6f773286ef999bcecf89 Mon Sep 17 00:00:00 2001 From: hnthh Date: Wed, 6 Dec 2023 01:13:03 +0300 Subject: [PATCH 045/116] child ci --- .github/workflows/child.yml | 2 +- {{ cookiecutter.name }}/.github/workflows/ci.yml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/child.yml b/.github/workflows/child.yml index 81c5bede..b9d080ee 100644 --- a/.github/workflows/child.yml +++ b/.github/workflows/child.yml @@ -18,4 +18,4 @@ jobs: uses: actions/checkout@v3 - name: run - uses: ./.github/workflows/ci.yml + run: gh workflow run ./.github/workflows/ci.yml diff --git a/{{ cookiecutter.name }}/.github/workflows/ci.yml b/{{ cookiecutter.name }}/.github/workflows/ci.yml index 5c909314..b60464fa 100644 --- a/{{ cookiecutter.name }}/.github/workflows/ci.yml +++ b/{{ cookiecutter.name }}/.github/workflows/ci.yml @@ -9,6 +9,7 @@ on: jobs: checks: runs-on: ubuntu-latest + steps: - name: checkout uses: actions/checkout@v3 From f7d39de9992842f050aa8e884bf0aa857062b142 Mon Sep 17 00:00:00 2001 From: hnthh Date: Wed, 6 Dec 2023 01:14:40 +0300 Subject: [PATCH 046/116] child ci --- .github/workflows/child.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/child.yml b/.github/workflows/child.yml index b9d080ee..9446178d 100644 --- a/.github/workflows/child.yml +++ b/.github/workflows/child.yml @@ -10,7 +10,7 @@ jobs: run: defaults: run: - working-directory: \{\{\ cookiecutter.name\ \}\}/ + working-directory: {{ cookiecutter.name }} runs-on: ubuntu-latest steps: From fc8af5c50002e92c4751c4726659611d022c671c Mon Sep 17 00:00:00 2001 From: hnthh Date: Wed, 6 Dec 2023 01:15:39 +0300 Subject: [PATCH 047/116] child ci --- .github/workflows/child.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/child.yml b/.github/workflows/child.yml index 9446178d..e3b3bae9 100644 --- a/.github/workflows/child.yml +++ b/.github/workflows/child.yml @@ -10,7 +10,7 @@ jobs: run: defaults: run: - working-directory: {{ cookiecutter.name }} + working-directory: '{{ cookiecutter.name }}' runs-on: ubuntu-latest steps: From 7a1d9208877940d3e80b57329773441ebcedf5b6 Mon Sep 17 00:00:00 2001 From: hnthh Date: Wed, 6 Dec 2023 01:17:53 +0300 Subject: [PATCH 048/116] child ci --- .github/workflows/child.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/child.yml b/.github/workflows/child.yml index e3b3bae9..4d6869f5 100644 --- a/.github/workflows/child.yml +++ b/.github/workflows/child.yml @@ -18,4 +18,6 @@ jobs: uses: actions/checkout@v3 - name: run + env: + GH_TOKEN: ${{ github.token }} run: gh workflow run ./.github/workflows/ci.yml From 1603f88e42bc6e1fd5665198a581aada7639d9a2 Mon Sep 17 00:00:00 2001 From: hnthh Date: Wed, 6 Dec 2023 01:27:47 +0300 Subject: [PATCH 049/116] child ci --- .github/workflows/child.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/child.yml b/.github/workflows/child.yml index 4d6869f5..50c63061 100644 --- a/.github/workflows/child.yml +++ b/.github/workflows/child.yml @@ -19,5 +19,5 @@ jobs: - name: run env: - GH_TOKEN: ${{ github.token }} + GH_TOKEN: ${{ secrets.GH_TOKEN }} run: gh workflow run ./.github/workflows/ci.yml From 4751ec4cbb7289172229efaaa4879154253cef80 Mon Sep 17 00:00:00 2001 From: hnthh Date: Wed, 6 Dec 2023 01:33:21 +0300 Subject: [PATCH 050/116] child ci --- .github/workflows/child.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/child.yml b/.github/workflows/child.yml index 50c63061..a18294e4 100644 --- a/.github/workflows/child.yml +++ b/.github/workflows/child.yml @@ -19,5 +19,5 @@ jobs: - name: run env: - GH_TOKEN: ${{ secrets.GH_TOKEN }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: gh workflow run ./.github/workflows/ci.yml From 14d2ecbe631fd45a0e44f3b0101e581b2f7958fd Mon Sep 17 00:00:00 2001 From: hnthh Date: Wed, 6 Dec 2023 01:38:29 +0300 Subject: [PATCH 051/116] child ci --- .github/workflows/child.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/child.yml b/.github/workflows/child.yml index a18294e4..6e4796da 100644 --- a/.github/workflows/child.yml +++ b/.github/workflows/child.yml @@ -14,9 +14,6 @@ jobs: runs-on: ubuntu-latest steps: - - name: checkout - uses: actions/checkout@v3 - - name: run env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 4007f8753f2e73e659da0e80e0c2c5a2df89e36e Mon Sep 17 00:00:00 2001 From: hnthh Date: Wed, 6 Dec 2023 01:40:45 +0300 Subject: [PATCH 052/116] child ci --- .github/workflows/child.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/child.yml b/.github/workflows/child.yml index 6e4796da..8654d1be 100644 --- a/.github/workflows/child.yml +++ b/.github/workflows/child.yml @@ -8,13 +8,10 @@ on: jobs: run: - defaults: - run: - working-directory: '{{ cookiecutter.name }}' runs-on: ubuntu-latest steps: - name: run env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: gh workflow run ./.github/workflows/ci.yml + run: gh workflow run ./{{ cookiecutter.name }}/.github/workflows/ci.yml From c8b2e72be62c1a3f5296fe0c3a4276cf57e4aebe Mon Sep 17 00:00:00 2001 From: hnthh Date: Wed, 6 Dec 2023 01:43:04 +0300 Subject: [PATCH 053/116] child ci --- .github/workflows/child.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/child.yml b/.github/workflows/child.yml index 8654d1be..06bdc280 100644 --- a/.github/workflows/child.yml +++ b/.github/workflows/child.yml @@ -11,6 +11,9 @@ jobs: runs-on: ubuntu-latest steps: + - name: checkout + uses: actions/checkout@v3 + - name: run env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 44815e0b11c1dcd0bf3269662aea06d499200e1c Mon Sep 17 00:00:00 2001 From: hnthh Date: Wed, 6 Dec 2023 01:44:13 +0300 Subject: [PATCH 054/116] child ci --- .github/workflows/child.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/child.yml b/.github/workflows/child.yml index 06bdc280..2c60f8b5 100644 --- a/.github/workflows/child.yml +++ b/.github/workflows/child.yml @@ -17,4 +17,4 @@ jobs: - name: run env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: gh workflow run ./{{ cookiecutter.name }}/.github/workflows/ci.yml + run: gh workflow run ./\{\{\ cookiecutter.name\ \}\}/.github/workflows/ci.yml From 1ac030f14e0a9878ba6be1d588efcbf50c5e3fb4 Mon Sep 17 00:00:00 2001 From: hnthh Date: Wed, 6 Dec 2023 01:46:14 +0300 Subject: [PATCH 055/116] remove child ci --- .github/workflows/child.yml | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100644 .github/workflows/child.yml diff --git a/.github/workflows/child.yml b/.github/workflows/child.yml deleted file mode 100644 index 2c60f8b5..00000000 --- a/.github/workflows/child.yml +++ /dev/null @@ -1,20 +0,0 @@ -name: child project workflow run - -on: - push: - branches: - - master - pull_request: - -jobs: - run: - runs-on: ubuntu-latest - - steps: - - name: checkout - uses: actions/checkout@v3 - - - name: run - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: gh workflow run ./\{\{\ cookiecutter.name\ \}\}/.github/workflows/ci.yml From 0a13a3407ee7e04cdc63a657b5d8a2d8643d36c3 Mon Sep 17 00:00:00 2001 From: hnthh Date: Mon, 25 Dec 2023 15:35:50 +0300 Subject: [PATCH 056/116] uppercase numprocesses env --- {{ cookiecutter.name }}/.github/workflows/ci.yml | 2 +- {{ cookiecutter.name }}/Makefile | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/{{ cookiecutter.name }}/.github/workflows/ci.yml b/{{ cookiecutter.name }}/.github/workflows/ci.yml index b60464fa..39d69278 100644 --- a/{{ cookiecutter.name }}/.github/workflows/ci.yml +++ b/{{ cookiecutter.name }}/.github/workflows/ci.yml @@ -62,4 +62,4 @@ jobs: - name: test env: DATABASE_URL: postgres://postgres:secret@localhost:5432/postgres - run: make test -e numprocesses=${{ steps.cpu-cores.outputs.count }} + run: make test -e NUMPROCESSES=${{ steps.cpu-cores.outputs.count }} diff --git a/{{ cookiecutter.name }}/Makefile b/{{ cookiecutter.name }}/Makefile index 89e85490..dcb9a1ce 100644 --- a/{{ cookiecutter.name }}/Makefile +++ b/{{ cookiecutter.name }}/Makefile @@ -1,5 +1,6 @@ +NUMPROCESSES = 4 + manage = poetry run python src/manage.py -numprocesses = 4 checks: $(manage) check @@ -21,6 +22,6 @@ fmt: test: poetry run pytest --dead-fixtures - poetry run pytest --create-db --exitfirst --numprocesses ${numprocesses} + poetry run pytest --create-db --exitfirst --numprocesses ${NUMPROCESSES} mr: fmt checks test From 456faf0f2e6f921e9cb16f1a81783d498c8f9899 Mon Sep 17 00:00:00 2001 From: hnthh Date: Mon, 25 Dec 2023 15:41:01 +0300 Subject: [PATCH 057/116] drop makefile `mr` cmd --- {{ cookiecutter.name }}/Makefile | 2 -- 1 file changed, 2 deletions(-) diff --git a/{{ cookiecutter.name }}/Makefile b/{{ cookiecutter.name }}/Makefile index dcb9a1ce..c9160609 100644 --- a/{{ cookiecutter.name }}/Makefile +++ b/{{ cookiecutter.name }}/Makefile @@ -23,5 +23,3 @@ fmt: test: poetry run pytest --dead-fixtures poetry run pytest --create-db --exitfirst --numprocesses ${NUMPROCESSES} - -mr: fmt checks test From 43715fe9e2770e5cc467e515b4bfb00e841fd3d8 Mon Sep 17 00:00:00 2001 From: hnthh Date: Mon, 25 Dec 2023 16:12:59 +0300 Subject: [PATCH 058/116] remove `asgi.py` --- {{ cookiecutter.name }}/src/core/asgi.py | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 {{ cookiecutter.name }}/src/core/asgi.py diff --git a/{{ cookiecutter.name }}/src/core/asgi.py b/{{ cookiecutter.name }}/src/core/asgi.py deleted file mode 100644 index d40fe22b..00000000 --- a/{{ cookiecutter.name }}/src/core/asgi.py +++ /dev/null @@ -1,7 +0,0 @@ -import os - -from django.core.asgi import get_asgi_application - -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "core.settings") - -application = get_asgi_application() From 611893dc95eb49cb90449da9fbb3b57ff760fadc Mon Sep 17 00:00:00 2001 From: hnthh Date: Mon, 25 Dec 2023 16:16:07 +0300 Subject: [PATCH 059/116] =?UTF-8?q?`DEFAULT=5FFILE=5FSTORAGE`=20=E2=86=92?= =?UTF-8?q?=20`FILE=5FSTORAGE`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- {{ cookiecutter.name }}/src/core/conf/storage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/{{ cookiecutter.name }}/src/core/conf/storage.py b/{{ cookiecutter.name }}/src/core/conf/storage.py index f90634ca..b7ba04a3 100644 --- a/{{ cookiecutter.name }}/src/core/conf/storage.py +++ b/{{ cookiecutter.name }}/src/core/conf/storage.py @@ -3,7 +3,7 @@ STORAGES = { "default": { "BACKEND": env( - "DEFAULT_FILE_STORAGE", + "FILE_STORAGE", cast=str, default="django.core.files.storage.FileSystemStorage", ), From 5fd69670ff6fc93211dff09a10b7878b6e00a6fe Mon Sep 17 00:00:00 2001 From: hnthh Date: Mon, 25 Dec 2023 16:51:49 +0300 Subject: [PATCH 060/116] fix imports in merged files --- {{ cookiecutter.name }}/src/core/testing/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/{{ cookiecutter.name }}/src/core/testing/api.py b/{{ cookiecutter.name }}/src/core/testing/api.py index ad47d992..dfd46a66 100644 --- a/{{ cookiecutter.name }}/src/core/testing/api.py +++ b/{{ cookiecutter.name }}/src/core/testing/api.py @@ -4,8 +4,8 @@ from typing import Optional from rest_framework.authtoken.models import Token -from rest_framework.test import APIClient as DRFAPIClient from rest_framework.response import Response +from rest_framework.test import APIClient as DRFAPIClient from apps.users.models import User From 1d0a7b843967b97779e73e972431996148151cff Mon Sep 17 00:00:00 2001 From: hnthh Date: Mon, 25 Dec 2023 16:57:40 +0300 Subject: [PATCH 061/116] remove poetry caching from parent proj ci --- .github/actions/build/action.yml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.github/actions/build/action.yml b/.github/actions/build/action.yml index f04b86bd..79341271 100644 --- a/.github/actions/build/action.yml +++ b/.github/actions/build/action.yml @@ -4,15 +4,7 @@ runs: using: composite steps: - - name: load cached poetry installation - id: cached-poetry - uses: actions/cache@v3 - with: - path: ~/.local - key: poetry-v1-${{ hashFiles('pyproject.toml') }} - - name: install poetry - if: steps.cached-poetry.outputs.cache-hit != true uses: snok/install-poetry@v1 with: version: 1.6.1 From 7f2becef02e622c404c34553f74660e886d30747 Mon Sep 17 00:00:00 2001 From: hnthh Date: Mon, 25 Dec 2023 17:44:13 +0300 Subject: [PATCH 062/116] add before push instructions to readme --- {{ cookiecutter.name }}/README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/{{ cookiecutter.name }}/README.md b/{{ cookiecutter.name }}/README.md index d0904351..66b91a23 100644 --- a/{{ cookiecutter.name }}/README.md +++ b/{{ cookiecutter.name }}/README.md @@ -23,6 +23,16 @@ Install requirements: poetry install ``` +Before `git push` remote: + +```bash +git init + +git add --force .github/actions/build/action.yml + +# other git commands +``` + Run the server: ```bash From c5784c00e64d7cd6f7aa8f66eadb1fb4cdab2e3f Mon Sep 17 00:00:00 2001 From: hnthh Date: Wed, 27 Dec 2023 19:19:46 +0300 Subject: [PATCH 063/116] rename makefile `checks` cmd --- hooks/post_gen_project.sh | 2 +- {{ cookiecutter.name }}/Makefile | 14 +++++++------- {{ cookiecutter.name }}/README.md | 16 ++-------------- 3 files changed, 10 insertions(+), 22 deletions(-) diff --git a/hooks/post_gen_project.sh b/hooks/post_gen_project.sh index 6ca02033..d87cc278 100644 --- a/hooks/post_gen_project.sh +++ b/hooks/post_gen_project.sh @@ -8,4 +8,4 @@ poetry run python src/manage.py collectstatic poetry run python src/manage.py startapp some_app poetry run python src/manage.py migrate -make checks test +make lint test diff --git a/{{ cookiecutter.name }}/Makefile b/{{ cookiecutter.name }}/Makefile index c9160609..bbf0662d 100644 --- a/{{ cookiecutter.name }}/Makefile +++ b/{{ cookiecutter.name }}/Makefile @@ -2,7 +2,13 @@ NUMPROCESSES = 4 manage = poetry run python src/manage.py -checks: +fmt: + poetry run autoflake --in-place --remove-all-unused-imports --recursive src tests + poetry run isort src tests + poetry run black src tests + poetry run toml-sort pyproject.toml + +lint: $(manage) check $(manage) makemigrations --check --dry-run --no-input @@ -14,12 +20,6 @@ checks: poetry run pymarkdown scan README.md poetry run dotenv-linter src/core/.env.ci -fmt: - poetry run autoflake --in-place --remove-all-unused-imports --recursive src tests - poetry run isort src tests - poetry run black src tests - poetry run toml-sort pyproject.toml - test: poetry run pytest --dead-fixtures poetry run pytest --create-db --exitfirst --numprocesses ${NUMPROCESSES} diff --git a/{{ cookiecutter.name }}/README.md b/{{ cookiecutter.name }}/README.md index 66b91a23..c3411693 100644 --- a/{{ cookiecutter.name }}/README.md +++ b/{{ cookiecutter.name }}/README.md @@ -23,16 +23,6 @@ Install requirements: poetry install ``` -Before `git push` remote: - -```bash -git init - -git add --force .github/actions/build/action.yml - -# other git commands -``` - Run the server: ```bash @@ -46,13 +36,11 @@ poetry run python src/manage.py runserver Useful commands ```bash -make checks # run code quality checks - make fmt # run code formatters -make test # run tests +make lint # run code quality checks -make mr # run all of above one-by-one +make test # run tests ``` ## Backend code requirements From 263f09dc0e7a7454ca026b9c1e1ea1a4340162b5 Mon Sep 17 00:00:00 2001 From: hnthh Date: Wed, 27 Dec 2023 19:29:53 +0300 Subject: [PATCH 064/116] fix links in readmes --- README.md | 6 +++--- {{ cookiecutter.name }}/README.md | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index d92b082b..8516fdeb 100644 --- a/README.md +++ b/README.md @@ -9,9 +9,9 @@ * API-only django (checkout [this post](https://t.me/pmdaily/257) in Russian) based on Django REST Framework with JWT support. * [poetry](https://python-poetry.org) with separate development-time dependencies. * Strict type checking with mypy, [django-stubs](https://github.com/typeddjango/django-stubs) and [djangorestframework-stubs](https://github.com/typeddjango/djangorestframework-stubs). -* tons of linters and formatters (contact me if something interesting not included, see `Makefile` `check`, `fmt` commands). +* tons of linters and formatters (contact me if something interesting not included, see `Makefile` `fmt`, `lint` commands). * Starter CI configuration on GitHub Actions. -* `pytest` with useful stuff like `freezegun`, `pytest-mock` and super convinient [DRF test client](https://github.com/f213/django/blob/master/%7B%7Bcookiecutter.project_slug%7D%7D/src/tests/core/tests_health.py#L9) +* `pytest` with useful stuff like `freezegun`, `pytest-mock` and super convinient [DRF test client](https://github.com/fandsdev/django/blob/master/%7B%7Bcookiecutter.name%7D%7D/src/tests/core/tests_health.py#L9) * Custom [user model](https://docs.djangoproject.com/en/3.0/topics/auth/customizing/#specifying-a-custom-user-model). * [drf-spectacular](https://github.com/tfranzel/drf-spectacular) for API Schema generation. * [django-axes](https://github.com/jazzband/django-axes) for additional security. @@ -24,7 +24,7 @@ You definetely should consider this steps after installation: -* If you are into docker, check out this [docker-compose.yml](https://github.com/f213/django/blob/master/%7B%7Bcookiecutter.project_slug%7D%7D/docker-compose.yml) to run on your machine. +* If you are into docker, check out this [docker-compose.yml](https://github.com/fandsdev/django/blob/master/%7B%7Bcookiecutter.name%7D%7D/docker-compose.yml) to run on your machine. ## Installation diff --git a/{{ cookiecutter.name }}/README.md b/{{ cookiecutter.name }}/README.md index c3411693..1c1e4b5c 100644 --- a/{{ cookiecutter.name }}/README.md +++ b/{{ cookiecutter.name }}/README.md @@ -6,8 +6,8 @@ This project is bootstrapped using [fandsdev/django](http://github.com/fandsdev/ The main django app is called `core`. It contains `.env` file for django-environ. For examples see `src/core/.env.ci`. Here are some usefull app-wide tools: -* `core.admin` — app-wide django-admin customizations (empty yet), check out usage [examples](https://github.com/f213/django/tree/master/%7B%7Bcookiecutter.project_slug%7D%7D/src/core/admin) -* `core.test.api_client` (available as `api` and `anon` fixtures within pytest) — a [convinient DRF test client](https://github.com/f213/django/blob/master/%7B%7Bcookiecutter.project_slug%7D%7D/src/tests/apps/users/tests_whoami.py#L6-L16). +* `core.admin` — app-wide django-admin customizations (empty yet), check out usage [examples](https://github.com/fandsdev/django/tree/master/%7B%7Bcookiecutter.name%7D%7D/src/core/admin) +* `core.test.api_client` (available as `api` and `anon` fixtures within pytest) — a [convinient DRF test client](https://github.com/fandsdev/django/blob/master/%7B%7Bcookiecutter.name%7D%7D/src/tests/apps/users/tests_whoami.py#L6-L16). Django user model is located in the separate `users` app. From 02b1553dc26a0615fb4ddc7c6c47c50bf2e820ae Mon Sep 17 00:00:00 2001 From: hnthh Date: Wed, 27 Dec 2023 19:30:55 +0300 Subject: [PATCH 065/116] remove optional next steps from readme --- README.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/README.md b/README.md index 8516fdeb..8dc35f2c 100644 --- a/README.md +++ b/README.md @@ -20,12 +20,6 @@ * Sentry. Set `SENTRY_DSN` env var if you need it. * Postgres ready. Set `DATABASE_URL` env var to something like `DATABASE_URL=postgres://postgres@localhost:5432/postgres`. -## Optional next steps - -You definetely should consider this steps after installation: - -* If you are into docker, check out this [docker-compose.yml](https://github.com/fandsdev/django/blob/master/%7B%7Bcookiecutter.name%7D%7D/docker-compose.yml) to run on your machine. - ## Installation ```bash From b61fc65ac8ef9d3fc4e8b46724ee31a0a6f31d8d Mon Sep 17 00:00:00 2001 From: hnthh Date: Wed, 27 Dec 2023 19:31:51 +0300 Subject: [PATCH 066/116] remove random ascii string error FAQ from readme --- README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.md b/README.md index 8dc35f2c..f10013d1 100644 --- a/README.md +++ b/README.md @@ -30,10 +30,6 @@ poetry run cookiecutter gh:fandsdev/django ## FAQ -### I have got an error «'random_ascii_string' is undefined» - -You should upgrade cookiecutter to the latest version: `pip install --upgrade cookiecutter`. - ### I wanna hack this! Thank you so much! Check out our [build pipeline](https://github.com/fandsdev/django/blob/master/Makefile) and pick any free [issue](https://github.com/fandsdev/django/issues). From 1f78d6be9682d6dab40ccf877ff7b0c5e3e7870e Mon Sep 17 00:00:00 2001 From: hnthh Date: Wed, 27 Dec 2023 19:38:41 +0300 Subject: [PATCH 067/116] bump uwsgi ver --- {{ cookiecutter.name }}/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/{{ cookiecutter.name }}/Dockerfile b/{{ cookiecutter.name }}/Dockerfile index 7dc40c8e..1f63a676 100644 --- a/{{ cookiecutter.name }}/Dockerfile +++ b/{{ cookiecutter.name }}/Dockerfile @@ -2,7 +2,7 @@ ARG PYTHON_VERSION FROM python:${PYTHON_VERSION}-slim-bookworm as uwsgi-compile -ENV _UWSGI_VERSION 2.0.22 +ENV _UWSGI_VERSION 2.0.23 RUN apt-get update && apt-get --no-install-recommends install -y build-essential wget && rm -rf /var/lib/apt/lists/* RUN wget -O uwsgi-${_UWSGI_VERSION}.tar.gz https://github.com/unbit/uwsgi/archive/${_UWSGI_VERSION}.tar.gz \ From dcdb5cbd69d09b78d77e847754b1d7eb30943453 Mon Sep 17 00:00:00 2001 From: hnthh Date: Wed, 27 Dec 2023 19:45:40 +0300 Subject: [PATCH 068/116] remove checks cmd from parent proj and cis --- .github/workflows/ci.yml | 6 +++--- Makefile | 8 ++++---- {{ cookiecutter.name }}/.github/workflows/ci.yml | 8 ++++---- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 16776034..0792c9e0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,7 +7,7 @@ on: pull_request: jobs: - check: + lint: runs-on: ubuntu-latest steps: @@ -17,8 +17,8 @@ jobs: - name: build uses: ./.github/actions/build - - name: check - run: make checks + - name: lint + run: make lint bootstrap: needs: check diff --git a/Makefile b/Makefile index fc923d15..3c254bb0 100644 --- a/Makefile +++ b/Makefile @@ -6,9 +6,9 @@ bootstrap: build: docker build --build-arg POETRY_VERSION=1.6.1 --build-arg PYTHON_VERSION=3.11 --tag f213/django testproject -checks: - poetry run toml-sort pyproject.toml --check - poetry run pymarkdown scan README.md - fmt: poetry run toml-sort pyproject.toml + +lint: + poetry run toml-sort pyproject.toml --check + poetry run pymarkdown scan README.md diff --git a/{{ cookiecutter.name }}/.github/workflows/ci.yml b/{{ cookiecutter.name }}/.github/workflows/ci.yml index 39d69278..8f65d4ad 100644 --- a/{{ cookiecutter.name }}/.github/workflows/ci.yml +++ b/{{ cookiecutter.name }}/.github/workflows/ci.yml @@ -7,7 +7,7 @@ on: pull_request: jobs: - checks: + lint: runs-on: ubuntu-latest steps: @@ -17,11 +17,11 @@ jobs: - name: build uses: ./.github/actions/build - - name: checks - run: make checks + - name: lint + run: make lint test: - needs: checks + needs: lint runs-on: ubuntu-latest services: From 54b40e505cd8486ec626971fa962891a19cb919f Mon Sep 17 00:00:00 2001 From: hnthh Date: Wed, 27 Dec 2023 19:47:03 +0300 Subject: [PATCH 069/116] remove depends on check job from parent ci --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0792c9e0..b822b8d6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,7 @@ jobs: run: make lint bootstrap: - needs: check + needs: lint runs-on: ubuntu-latest steps: From 598222e200b79210662dd17e9d0dc4cbabdfc31b Mon Sep 17 00:00:00 2001 From: hnthh Date: Wed, 27 Dec 2023 20:10:03 +0300 Subject: [PATCH 070/116] remove build from `.gitignore` --- .../.github/actions/build/action.yml | 38 +++++++++++++++++++ {{ cookiecutter.name }}/.gitignore | 1 - 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 {{ cookiecutter.name }}/.github/actions/build/action.yml diff --git a/{{ cookiecutter.name }}/.github/actions/build/action.yml b/{{ cookiecutter.name }}/.github/actions/build/action.yml new file mode 100644 index 00000000..3d113e5c --- /dev/null +++ b/{{ cookiecutter.name }}/.github/actions/build/action.yml @@ -0,0 +1,38 @@ +name: build + +runs: + using: composite + + steps: + - name: load cached poetry installation + id: cached-poetry + uses: actions/cache@v3 + with: + path: ~/.local + key: poetry-v1-${{ hashFiles('pyproject.toml') }} + + - name: install poetry + if: steps.cached-poetry.outputs.cache-hit != true + uses: snok/install-poetry@v1 + with: + version: 1.6.1 + + - name: install python + id: setup-python + uses: actions/setup-python@v4 + with: + cache: poetry + python-version-file: pyproject.toml + + - name: make sure poetry lockfile is up to date + run: poetry check --lock + shell: bash + + - name: install deps + if: steps.setup-python.outputs.cache-hit != true + run: poetry install --no-interaction --no-root + shell: bash + + - name: restore default environment + run: cp src/core/.env.ci src/core/.env + shell: bash diff --git a/{{ cookiecutter.name }}/.gitignore b/{{ cookiecutter.name }}/.gitignore index 1c54582e..1e783b44 100644 --- a/{{ cookiecutter.name }}/.gitignore +++ b/{{ cookiecutter.name }}/.gitignore @@ -13,7 +13,6 @@ __pycache__/ # Distribution / packaging .Python -build/ develop-eggs/ dist/ downloads/ From 66f069e7092fbb614b5d699d5eb6e3c4f5f539fa Mon Sep 17 00:00:00 2001 From: hnthh Date: Wed, 27 Dec 2023 20:37:54 +0300 Subject: [PATCH 071/116] add docker image build ci job --- .github/actions/build/action.yml | 4 ++++ .github/workflows/ci.yml | 24 ++++++++++++++++++++++++ Makefile | 2 +- {{ cookiecutter.name }}/Dockerfile | 4 +--- 4 files changed, 30 insertions(+), 4 deletions(-) diff --git a/.github/actions/build/action.yml b/.github/actions/build/action.yml index 79341271..79c176a3 100644 --- a/.github/actions/build/action.yml +++ b/.github/actions/build/action.yml @@ -20,6 +20,10 @@ runs: run: poetry check --lock shell: bash + - name: save python version to the env + run: echo "python-version=${{ steps.setup-python.outputs.python-version }}" >> $GITHUB_ENV + shell: bash + - name: install deps if: steps.setup-python.outputs.cache-hit != true run: poetry install --no-interaction --no-root diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b822b8d6..c47c54b9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,3 +33,27 @@ jobs: - name: bootstrap run: make bootstrap + + build-docker-image: + needs: bootstrap + runs-on: ubuntu-latest + + steps: + - name: checkout + uses: actions/checkout@v3 + + - name: build + uses: ./.github/actions/build + + - name: bootstrap + run: make bootstrap + + - name: make sure docker image is buildable + uses: docker/build-push-action@v3 + with: + build-args: | + PYTHON_VERSION=${{ env.python-version }} + cache-from: type=gha + cache-to: type=gha,mode=max + context: testproject + push: false diff --git a/Makefile b/Makefile index 3c254bb0..d075700e 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ bootstrap: poetry run cookiecutter --no-input ./ build: - docker build --build-arg POETRY_VERSION=1.6.1 --build-arg PYTHON_VERSION=3.11 --tag f213/django testproject + docker build --build-arg PYTHON_VERSION=3.11 --tag f213/django testproject fmt: poetry run toml-sort pyproject.toml diff --git a/{{ cookiecutter.name }}/Dockerfile b/{{ cookiecutter.name }}/Dockerfile index 1f63a676..30d3c3b4 100644 --- a/{{ cookiecutter.name }}/Dockerfile +++ b/{{ cookiecutter.name }}/Dockerfile @@ -15,9 +15,7 @@ FROM python:${PYTHON_VERSION}-slim-bookworm as deps-compile WORKDIR / COPY poetry.lock pyproject.toml / -ARG POETRY_VERSION - -RUN pip install --no-cache-dir poetry==${POETRY_VERSION} +RUN pip install --no-cache-dir poetry==$(cat poetry.lock |head -n1|awk -v FS='(Poetry |and)' '{print $2}') RUN poetry export --format=requirements.txt > requirements.txt FROM python:${PYTHON_VERSION}-slim-bookworm as base From 0bf844f8dfa1dca28842ac138befc8210f3e3bcd Mon Sep 17 00:00:00 2001 From: hnthh Date: Wed, 27 Dec 2023 20:57:02 +0300 Subject: [PATCH 072/116] add qemu, buildx setup steps --- .github/actions/build/action.yml | 2 +- .github/workflows/ci.yml | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/actions/build/action.yml b/.github/actions/build/action.yml index 79c176a3..c7e82e4a 100644 --- a/.github/actions/build/action.yml +++ b/.github/actions/build/action.yml @@ -22,7 +22,7 @@ runs: - name: save python version to the env run: echo "python-version=${{ steps.setup-python.outputs.python-version }}" >> $GITHUB_ENV - shell: bash + shell: bash - name: install deps if: steps.setup-python.outputs.cache-hit != true diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c47c54b9..79077820 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,6 +48,12 @@ jobs: - name: bootstrap run: make bootstrap + - name: setup qemu + uses: docker/setup-qemu-action@v2 + + - name: setup buildx + uses: docker/setup-buildx-action@v2 + - name: make sure docker image is buildable uses: docker/build-push-action@v3 with: From c0666f26ded2a11832c100f338ae3aedf918d006 Mon Sep 17 00:00:00 2001 From: Anya Agarenko Date: Wed, 27 Dec 2023 21:04:56 +0300 Subject: [PATCH 073/116] update .gitignore --- {{ cookiecutter.name }}/.gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/{{ cookiecutter.name }}/.gitignore b/{{ cookiecutter.name }}/.gitignore index 1e783b44..97a35bae 100644 --- a/{{ cookiecutter.name }}/.gitignore +++ b/{{ cookiecutter.name }}/.gitignore @@ -106,7 +106,6 @@ dmypy.json # End of https://www.gitignore.io/api/python # IDE stuff -**.*~ .vscode .idea From 9ce90c473bdc8bc2700283bdb45069ca1a03caf4 Mon Sep 17 00:00:00 2001 From: hnthh Date: Thu, 28 Dec 2023 14:55:13 +0300 Subject: [PATCH 074/116] make bootstrap cmd works locally with postgres --- hooks/post_gen_project.sh | 2 ++ {{ cookiecutter.name }}/src/core/.env.ci | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/hooks/post_gen_project.sh b/hooks/post_gen_project.sh index d87cc278..80e420b4 100644 --- a/hooks/post_gen_project.sh +++ b/hooks/post_gen_project.sh @@ -2,6 +2,8 @@ cp src/core/.env.ci src/core/.env +docker compose up --detach + poetry install poetry run python src/manage.py collectstatic diff --git a/{{ cookiecutter.name }}/src/core/.env.ci b/{{ cookiecutter.name }}/src/core/.env.ci index 9eb2374e..a70e6138 100644 --- a/{{ cookiecutter.name }}/src/core/.env.ci +++ b/{{ cookiecutter.name }}/src/core/.env.ci @@ -1,3 +1,3 @@ -DATABASE_URL=sqlite:///db.sqlite +DATABASE_URL=postgres://postgres:@localhost:5432/postgres DEBUG=off SECRET_KEY=l!@xGb!Jkd]pQsvtU,@y`=%/c}mY;]oYwnsVeU}".VwwClOX From c8a0b1ce99e9ec0d3830b56c2908899dda088876 Mon Sep 17 00:00:00 2001 From: hnthh Date: Thu, 28 Dec 2023 14:58:14 +0300 Subject: [PATCH 075/116] fix readmes --- README.md | 2 +- {{ cookiecutter.name }}/README.md | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index f10013d1..b40b4ad8 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ * [Whitenoise](http://whitenoise.evans.io) for effortless static files hosting. * cloudflare-ready with [django-ipware](https://github.com/un33k/django-ipware). * Sentry. Set `SENTRY_DSN` env var if you need it. -* Postgres ready. Set `DATABASE_URL` env var to something like `DATABASE_URL=postgres://postgres@localhost:5432/postgres`. +* Postgres. ## Installation diff --git a/{{ cookiecutter.name }}/README.md b/{{ cookiecutter.name }}/README.md index 1c1e4b5c..ef6affc0 100644 --- a/{{ cookiecutter.name }}/README.md +++ b/{{ cookiecutter.name }}/README.md @@ -26,8 +26,6 @@ poetry install Run the server: ```bash -cp src/core/.env.ci src/core/.env - poetry run python src/manage.py migrate poetry run python src/manage.py createsuperuser poetry run python src/manage.py runserver From c79ebab2866d6df35de9ddb66d78a76fce56b040 Mon Sep 17 00:00:00 2001 From: hnthh Date: Thu, 28 Dec 2023 15:06:29 +0300 Subject: [PATCH 076/116] add postgres to parent ci except lint --- .github/workflows/ci.yml | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 79077820..92871060 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,6 +24,24 @@ jobs: needs: lint runs-on: ubuntu-latest + services: + postgres: + image: postgres:16.1-alpine + env: + POSTGRES_PASSWORD: secret + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 5432:5432 + + redis: + image: redis:7.2.3-alpine + ports: + - 6379:6379 + steps: - name: checkout uses: actions/checkout@v3 @@ -38,6 +56,24 @@ jobs: needs: bootstrap runs-on: ubuntu-latest + services: + postgres: + image: postgres:16.1-alpine + env: + POSTGRES_PASSWORD: secret + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 5432:5432 + + redis: + image: redis:7.2.3-alpine + ports: + - 6379:6379 + steps: - name: checkout uses: actions/checkout@v3 From b4e5d2c448eda3a47187cff30ed5233b645e4ab8 Mon Sep 17 00:00:00 2001 From: hnthh Date: Thu, 28 Dec 2023 15:09:07 +0300 Subject: [PATCH 077/116] remove services from parent ci --- .github/workflows/ci.yml | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 92871060..79077820 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,24 +24,6 @@ jobs: needs: lint runs-on: ubuntu-latest - services: - postgres: - image: postgres:16.1-alpine - env: - POSTGRES_PASSWORD: secret - options: >- - --health-cmd pg_isready - --health-interval 10s - --health-timeout 5s - --health-retries 5 - ports: - - 5432:5432 - - redis: - image: redis:7.2.3-alpine - ports: - - 6379:6379 - steps: - name: checkout uses: actions/checkout@v3 @@ -56,24 +38,6 @@ jobs: needs: bootstrap runs-on: ubuntu-latest - services: - postgres: - image: postgres:16.1-alpine - env: - POSTGRES_PASSWORD: secret - options: >- - --health-cmd pg_isready - --health-interval 10s - --health-timeout 5s - --health-retries 5 - ports: - - 5432:5432 - - redis: - image: redis:7.2.3-alpine - ports: - - 6379:6379 - steps: - name: checkout uses: actions/checkout@v3 From 65d19b1ee8b1376f6488a3deac05d6178d98400e Mon Sep 17 00:00:00 2001 From: hnthh Date: Thu, 28 Dec 2023 15:16:44 +0300 Subject: [PATCH 078/116] make numprocesses auto --- {{ cookiecutter.name }}/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/{{ cookiecutter.name }}/Makefile b/{{ cookiecutter.name }}/Makefile index bbf0662d..9da49c41 100644 --- a/{{ cookiecutter.name }}/Makefile +++ b/{{ cookiecutter.name }}/Makefile @@ -1,4 +1,4 @@ -NUMPROCESSES = 4 +NUMPROCESSES = auto manage = poetry run python src/manage.py From 9db3d01875d9ac1bdac3f1c14b24dd5bb1fb33bf Mon Sep 17 00:00:00 2001 From: hnthh Date: Thu, 28 Dec 2023 15:24:39 +0300 Subject: [PATCH 079/116] rename numprocesses env --- {{ cookiecutter.name }}/.github/workflows/ci.yml | 2 +- {{ cookiecutter.name }}/Makefile | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/{{ cookiecutter.name }}/.github/workflows/ci.yml b/{{ cookiecutter.name }}/.github/workflows/ci.yml index 8f65d4ad..56382cdd 100644 --- a/{{ cookiecutter.name }}/.github/workflows/ci.yml +++ b/{{ cookiecutter.name }}/.github/workflows/ci.yml @@ -62,4 +62,4 @@ jobs: - name: test env: DATABASE_URL: postgres://postgres:secret@localhost:5432/postgres - run: make test -e NUMPROCESSES=${{ steps.cpu-cores.outputs.count }} + run: make test -e SIMULTANEOS_TEST_JOBS=${{ steps.cpu-cores.outputs.count }} diff --git a/{{ cookiecutter.name }}/Makefile b/{{ cookiecutter.name }}/Makefile index 9da49c41..6f578542 100644 --- a/{{ cookiecutter.name }}/Makefile +++ b/{{ cookiecutter.name }}/Makefile @@ -1,4 +1,4 @@ -NUMPROCESSES = auto +SIMULTANEOS_TEST_JOBS = auto manage = poetry run python src/manage.py @@ -22,4 +22,4 @@ lint: test: poetry run pytest --dead-fixtures - poetry run pytest --create-db --exitfirst --numprocesses ${NUMPROCESSES} + poetry run pytest --create-db --exitfirst --numprocesses ${SIMULTANEOS_TEST_JOBS} From 2a92a4997343e09f5683ed296f5a5971fad65001 Mon Sep 17 00:00:00 2001 From: hnthh Date: Thu, 28 Dec 2023 15:26:27 +0300 Subject: [PATCH 080/116] rename makefile build cmd --- Makefile | 3 --- 1 file changed, 3 deletions(-) diff --git a/Makefile b/Makefile index d075700e..2cbaed77 100644 --- a/Makefile +++ b/Makefile @@ -3,9 +3,6 @@ bootstrap: poetry run cookiecutter --no-input ./ -build: - docker build --build-arg PYTHON_VERSION=3.11 --tag f213/django testproject - fmt: poetry run toml-sort pyproject.toml From 0a3f2bfd2e1fa6e96043f6ccdb8c483ab405c980 Mon Sep 17 00:00:00 2001 From: hnthh Date: Thu, 28 Dec 2023 16:09:40 +0300 Subject: [PATCH 081/116] add build docker image job to child ci and down cmd to pre-hook --- hooks/post_gen_project.sh | 1 + .../.github/actions/build/action.yml | 4 +++ .../.github/workflows/ci.yml | 27 +++++++++++++++++++ 3 files changed, 32 insertions(+) diff --git a/hooks/post_gen_project.sh b/hooks/post_gen_project.sh index 80e420b4..7aa585ee 100644 --- a/hooks/post_gen_project.sh +++ b/hooks/post_gen_project.sh @@ -2,6 +2,7 @@ cp src/core/.env.ci src/core/.env +docker compose down --volumes docker compose up --detach poetry install diff --git a/{{ cookiecutter.name }}/.github/actions/build/action.yml b/{{ cookiecutter.name }}/.github/actions/build/action.yml index 3d113e5c..023a33b5 100644 --- a/{{ cookiecutter.name }}/.github/actions/build/action.yml +++ b/{{ cookiecutter.name }}/.github/actions/build/action.yml @@ -28,6 +28,10 @@ runs: run: poetry check --lock shell: bash + - name: save python version to the env + run: echo 'python-version=${{ steps.setup-python.outputs.python-version }}' >> $GITHUB_ENV + shell: bash + - name: install deps if: steps.setup-python.outputs.cache-hit != true run: poetry install --no-interaction --no-root diff --git a/{{ cookiecutter.name }}/.github/workflows/ci.yml b/{{ cookiecutter.name }}/.github/workflows/ci.yml index 56382cdd..c58ab157 100644 --- a/{{ cookiecutter.name }}/.github/workflows/ci.yml +++ b/{{ cookiecutter.name }}/.github/workflows/ci.yml @@ -63,3 +63,30 @@ jobs: env: DATABASE_URL: postgres://postgres:secret@localhost:5432/postgres run: make test -e SIMULTANEOS_TEST_JOBS=${{ steps.cpu-cores.outputs.count }} + + build-docker-image: + needs: test + runs-on: ubuntu-latest + + steps: + - name: checkout + uses: actions/checkout@v3 + + - name: build + uses: ./.github/actions/build + + - name: setup qemu + uses: docker/setup-qemu-action@v2 + + - name: setup buildx + uses: docker/setup-buildx-action@v2 + + - name: make sure docker image is buildable + uses: docker/build-push-action@v3 + with: + build-args: | + PYTHON_VERSION=${{ env.python-version }} + cache-from: type=gha + cache-to: type=gha,mode=max + context: . + push: false \ No newline at end of file From 25b987059d2aef37724deadc5e387b6b64122cc6 Mon Sep 17 00:00:00 2001 From: hnthh Date: Wed, 10 Jan 2024 13:25:46 +0300 Subject: [PATCH 082/116] remove `core` from installed apps --- {{ cookiecutter.name }}/src/core/conf/installed_apps.py | 1 - 1 file changed, 1 deletion(-) diff --git a/{{ cookiecutter.name }}/src/core/conf/installed_apps.py b/{{ cookiecutter.name }}/src/core/conf/installed_apps.py index ed681b84..3a0e4388 100644 --- a/{{ cookiecutter.name }}/src/core/conf/installed_apps.py +++ b/{{ cookiecutter.name }}/src/core/conf/installed_apps.py @@ -1,7 +1,6 @@ # Application definition APPS = [ - "core", "apps.a12n", "apps.users", ] From 91008355eb095fad58e2c76203d5c225ba7737ce Mon Sep 17 00:00:00 2001 From: hnthh Date: Thu, 11 Jan 2024 17:16:04 +0300 Subject: [PATCH 083/116] back to prev project architecture --- README.md | 2 +- hooks/post_gen_project.sh | 2 +- .../.github/actions/build/action.yml | 2 +- {{ cookiecutter.name }}/Dockerfile | 2 +- {{ cookiecutter.name }}/Makefile | 16 ++++----- {{ cookiecutter.name }}/README.md | 6 ++-- {{ cookiecutter.name }}/conftest.py | 6 ++++ {{ cookiecutter.name }}/mypy.ini | 6 ++-- {{ cookiecutter.name }}/pyproject.toml | 2 +- .../src/{apps => }/a12n/__init__.py | 0 .../src/{apps => }/a12n/api/throttling.py | 2 +- .../src/{apps => }/a12n/api/urls.py | 2 +- .../src/{apps => }/a12n/api/views.py | 2 +- .../{apps => }/a12n/migrations/__init__.py | 0 .../tests}/jwt_views/test_obtain_jwt_view.py | 0 .../jwt_views/test_refresh_jwt_token.py | 2 +- .../src/{apps => }/a12n/utils.py | 2 +- .../src/{core => app}/.env.ci | 0 .../src/{apps/users => app}/__init__.py | 0 .../src/{core => app}/admin/__init__.py | 2 +- .../src/{core => app}/admin/model_admin.py | 0 .../src/{core => app}/api/pagination.py | 0 .../src/{core => app}/api/renderers.py | 0 .../src/{core => app}/api/throttling.py | 0 .../src/{core => app}/api/viewsets.py | 0 .../src/{core => app}/base_config.py | 0 .../src/{core => app}/conf/api.py | 6 ++-- .../src/{core => app}/conf/auth.py | 2 +- .../src/app/conf/boilerplate.py | 10 ++++++ .../src/{core => app}/conf/db.py | 2 +- .../src/{core => app}/conf/environ.py | 2 +- .../src/{core => app}/conf/healthchecks.py | 0 .../src/{core => app}/conf/http.py | 2 +- .../src/{core => app}/conf/i18n.py | 2 +- .../src/{core => app}/conf/installed_apps.py | 4 +-- .../src/{core => app}/conf/media.py | 2 +- .../src/{core => app}/conf/middleware.py | 2 +- .../src/{core => app}/conf/sentry.py | 2 +- .../src/{core => app}/conf/static.py | 2 +- .../src/{core => app}/conf/storage.py | 2 +- .../src/{core => app}/conf/templates.py | 0 .../src/{core => app}/conf/timezone.py | 0 .../{tests/core => src/app}/factory.py | 4 +-- .../src/app/fixtures/__init__.py | 8 +++++ .../src/app/fixtures/api.py | 14 ++++++++ .../src/app/fixtures/factory.py | 8 +++++ .../management/commands/makemigrations.py | 0 .../src/app/management/commands/startapp.py | 14 ++++++++ .../src/{core => app}/middleware/real_ip.py | 0 .../src/{core => app}/models.py | 0 .../src/{core => app}/services.py | 0 .../src/{core => app}/settings.py | 2 +- .../src/app/testing/__init__.py | 8 +++++ .../src/{core => app}/testing/api.py | 2 +- .../src/{core => app}/testing/factory.py | 2 +- .../src/{core => app}/testing/mixer.py | 0 .../src/{core => app}/testing/runner.py | 0 .../src/{core => app}/testing/types.py | 0 .../migrations => app/tests}/__init__.py | 0 .../core => src/app/tests}/test_health.py | 0 .../app/tests}/test_remote_addr_midlleware.py | 4 +-- .../{core => app/tests/testing}/__init__.py | 0 .../app/tests/testing/factory}/__init__.py | 0 .../tests}/testing/factory/test_factory.py | 2 +- .../tests}/testing/factory/test_registry.py | 2 +- .../src/{core => app}/urls/__init__.py | 2 +- .../src/{core => app}/urls/v1.py | 4 +-- .../src/{core => app}/wsgi.py | 2 +- .../src/core/conf/boilerplate.py | 10 ------ .../src/core/management/commands/startapp.py | 34 ------------------- .../src/core/testing/__init__.py | 8 ----- {{ cookiecutter.name }}/src/manage.py | 2 +- .../{tests/core => src/users}/__init__.py | 0 .../src/{apps => }/users/admin.py | 2 +- .../src/{apps => }/users/api/serializers.py | 2 +- .../src/{apps => }/users/api/urls.py | 2 +- .../src/{apps => }/users/api/viewsets.py | 4 +-- .../{tests/apps => src}/users/factory.py | 6 ++-- .../{tests/apps => src}/users/fixtures.py | 4 +-- .../users/migrations/0001_initial.py | 0 .../users/migrations}/__init__.py | 0 .../src/{apps => }/users/models.py | 0 .../users/tests}/test_password_hashing.py | 2 +- .../users => src/users/tests}/test_whoami.py | 0 {{ cookiecutter.name }}/tests/conftest.py | 9 ----- .../tests/core/fixtures.py | 24 ------------- .../tests/core/testing/factory/__init__.py | 0 87 files changed, 133 insertions(+), 150 deletions(-) create mode 100644 {{ cookiecutter.name }}/conftest.py rename {{ cookiecutter.name }}/src/{apps => }/a12n/__init__.py (100%) rename {{ cookiecutter.name }}/src/{apps => }/a12n/api/throttling.py (77%) rename {{ cookiecutter.name }}/src/{apps => }/a12n/api/urls.py (86%) rename {{ cookiecutter.name }}/src/{apps => }/a12n/api/views.py (81%) rename {{ cookiecutter.name }}/src/{apps => }/a12n/migrations/__init__.py (100%) rename {{ cookiecutter.name }}/{tests/apps/a12n => src/a12n/tests}/jwt_views/test_obtain_jwt_view.py (100%) rename {{ cookiecutter.name }}/{tests/apps/a12n => src/a12n/tests}/jwt_views/test_refresh_jwt_token.py (97%) rename {{ cookiecutter.name }}/src/{apps => }/a12n/utils.py (90%) rename {{ cookiecutter.name }}/src/{core => app}/.env.ci (100%) rename {{ cookiecutter.name }}/src/{apps/users => app}/__init__.py (100%) rename {{ cookiecutter.name }}/src/{core => app}/admin/__init__.py (63%) rename {{ cookiecutter.name }}/src/{core => app}/admin/model_admin.py (100%) rename {{ cookiecutter.name }}/src/{core => app}/api/pagination.py (100%) rename {{ cookiecutter.name }}/src/{core => app}/api/renderers.py (100%) rename {{ cookiecutter.name }}/src/{core => app}/api/throttling.py (100%) rename {{ cookiecutter.name }}/src/{core => app}/api/viewsets.py (100%) rename {{ cookiecutter.name }}/src/{core => app}/base_config.py (100%) rename {{ cookiecutter.name }}/src/{core => app}/conf/api.py (93%) rename {{ cookiecutter.name }}/src/{core => app}/conf/auth.py (96%) create mode 100644 {{ cookiecutter.name }}/src/app/conf/boilerplate.py rename {{ cookiecutter.name }}/src/{core => app}/conf/db.py (91%) rename {{ cookiecutter.name }}/src/{core => app}/conf/environ.py (83%) rename {{ cookiecutter.name }}/src/{core => app}/conf/healthchecks.py (100%) rename {{ cookiecutter.name }}/src/{core => app}/conf/http.py (87%) rename {{ cookiecutter.name }}/src/{core => app}/conf/i18n.py (72%) rename {{ cookiecutter.name }}/src/{core => app}/conf/installed_apps.py (93%) rename {{ cookiecutter.name }}/src/{core => app}/conf/media.py (70%) rename {{ cookiecutter.name }}/src/{core => app}/conf/middleware.py (90%) rename {{ cookiecutter.name }}/src/{core => app}/conf/sentry.py (90%) rename {{ cookiecutter.name }}/src/{core => app}/conf/static.py (84%) rename {{ cookiecutter.name }}/src/{core => app}/conf/storage.py (95%) rename {{ cookiecutter.name }}/src/{core => app}/conf/templates.py (100%) rename {{ cookiecutter.name }}/src/{core => app}/conf/timezone.py (100%) rename {{ cookiecutter.name }}/{tests/core => src/app}/factory.py (79%) create mode 100644 {{ cookiecutter.name }}/src/app/fixtures/__init__.py create mode 100644 {{ cookiecutter.name }}/src/app/fixtures/api.py create mode 100644 {{ cookiecutter.name }}/src/app/fixtures/factory.py rename {{ cookiecutter.name }}/src/{core => app}/management/commands/makemigrations.py (100%) create mode 100644 {{ cookiecutter.name }}/src/app/management/commands/startapp.py rename {{ cookiecutter.name }}/src/{core => app}/middleware/real_ip.py (100%) rename {{ cookiecutter.name }}/src/{core => app}/models.py (100%) rename {{ cookiecutter.name }}/src/{core => app}/services.py (100%) rename {{ cookiecutter.name }}/src/{core => app}/settings.py (96%) create mode 100644 {{ cookiecutter.name }}/src/app/testing/__init__.py rename {{ cookiecutter.name }}/src/{core => app}/testing/api.py (98%) rename {{ cookiecutter.name }}/src/{core => app}/testing/factory.py (97%) rename {{ cookiecutter.name }}/src/{core => app}/testing/mixer.py (100%) rename {{ cookiecutter.name }}/src/{core => app}/testing/runner.py (100%) rename {{ cookiecutter.name }}/src/{core => app}/testing/types.py (100%) rename {{ cookiecutter.name }}/src/{apps/users/migrations => app/tests}/__init__.py (100%) rename {{ cookiecutter.name }}/{tests/core => src/app/tests}/test_health.py (100%) rename {{ cookiecutter.name }}/{tests/core => src/app/tests}/test_remote_addr_midlleware.py (91%) rename {{ cookiecutter.name }}/src/{core => app/tests/testing}/__init__.py (100%) rename {{ cookiecutter.name }}/{tests => src/app/tests/testing/factory}/__init__.py (100%) rename {{ cookiecutter.name }}/{tests/core => src/app/tests}/testing/factory/test_factory.py (96%) rename {{ cookiecutter.name }}/{tests/core => src/app/tests}/testing/factory/test_registry.py (90%) rename {{ cookiecutter.name }}/src/{core => app}/urls/__init__.py (74%) rename {{ cookiecutter.name }}/src/{core => app}/urls/v1.py (78%) rename {{ cookiecutter.name }}/src/{core => app}/wsgi.py (60%) delete mode 100644 {{ cookiecutter.name }}/src/core/conf/boilerplate.py delete mode 100644 {{ cookiecutter.name }}/src/core/management/commands/startapp.py delete mode 100644 {{ cookiecutter.name }}/src/core/testing/__init__.py rename {{ cookiecutter.name }}/{tests/core => src/users}/__init__.py (100%) rename {{ cookiecutter.name }}/src/{apps => }/users/admin.py (77%) rename {{ cookiecutter.name }}/src/{apps => }/users/api/serializers.py (92%) rename {{ cookiecutter.name }}/src/{apps => }/users/api/urls.py (76%) rename {{ cookiecutter.name }}/src/{apps => }/users/api/viewsets.py (88%) rename {{ cookiecutter.name }}/{tests/apps => src}/users/factory.py (70%) rename {{ cookiecutter.name }}/{tests/apps => src}/users/fixtures.py (64%) rename {{ cookiecutter.name }}/src/{apps => }/users/migrations/0001_initial.py (100%) rename {{ cookiecutter.name }}/{tests/core/testing => src/users/migrations}/__init__.py (100%) rename {{ cookiecutter.name }}/src/{apps => }/users/models.py (100%) rename {{ cookiecutter.name }}/{tests/apps/users => src/users/tests}/test_password_hashing.py (87%) rename {{ cookiecutter.name }}/{tests/apps/users => src/users/tests}/test_whoami.py (100%) delete mode 100644 {{ cookiecutter.name }}/tests/conftest.py delete mode 100644 {{ cookiecutter.name }}/tests/core/fixtures.py delete mode 100644 {{ cookiecutter.name }}/tests/core/testing/factory/__init__.py diff --git a/README.md b/README.md index b40b4ad8..1a333e5b 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ * Strict type checking with mypy, [django-stubs](https://github.com/typeddjango/django-stubs) and [djangorestframework-stubs](https://github.com/typeddjango/djangorestframework-stubs). * tons of linters and formatters (contact me if something interesting not included, see `Makefile` `fmt`, `lint` commands). * Starter CI configuration on GitHub Actions. -* `pytest` with useful stuff like `freezegun`, `pytest-mock` and super convinient [DRF test client](https://github.com/fandsdev/django/blob/master/%7B%7Bcookiecutter.name%7D%7D/src/tests/core/tests_health.py#L9) +* `pytest` with useful stuff like `freezegun`, `pytest-mock` and super convinient [DRF test client](https://github.com/fandsdev/django/blob/master/%7B%7Bcookiecutter.name%7D%7D/src/app/tests_health.py#L9) * Custom [user model](https://docs.djangoproject.com/en/3.0/topics/auth/customizing/#specifying-a-custom-user-model). * [drf-spectacular](https://github.com/tfranzel/drf-spectacular) for API Schema generation. * [django-axes](https://github.com/jazzband/django-axes) for additional security. diff --git a/hooks/post_gen_project.sh b/hooks/post_gen_project.sh index 7aa585ee..af9626f9 100644 --- a/hooks/post_gen_project.sh +++ b/hooks/post_gen_project.sh @@ -1,6 +1,6 @@ #!/bin/bash -e -cp src/core/.env.ci src/core/.env +cp src/app/.env.ci src/app/.env docker compose down --volumes docker compose up --detach diff --git a/{{ cookiecutter.name }}/.github/actions/build/action.yml b/{{ cookiecutter.name }}/.github/actions/build/action.yml index 023a33b5..d832f686 100644 --- a/{{ cookiecutter.name }}/.github/actions/build/action.yml +++ b/{{ cookiecutter.name }}/.github/actions/build/action.yml @@ -38,5 +38,5 @@ runs: shell: bash - name: restore default environment - run: cp src/core/.env.ci src/core/.env + run: cp src/app/.env.ci src/app/.env shell: bash diff --git a/{{ cookiecutter.name }}/Dockerfile b/{{ cookiecutter.name }}/Dockerfile index 30d3c3b4..1af46bf8 100644 --- a/{{ cookiecutter.name }}/Dockerfile +++ b/{{ cookiecutter.name }}/Dockerfile @@ -45,4 +45,4 @@ RUN ./manage.py compilemessages RUN ./manage.py collectstatic --noinput FROM base as web -CMD ./manage.py migrate && uwsgi --master --http :8000 --module core.wsgi --workers 2 --threads 2 --harakiri 25 --max-requests 1000 --log-x-forwarded-for +CMD ./manage.py migrate && uwsgi --master --http :8000 --module app.wsgi --workers 2 --threads 2 --harakiri 25 --max-requests 1000 --log-x-forwarded-for diff --git a/{{ cookiecutter.name }}/Makefile b/{{ cookiecutter.name }}/Makefile index 6f578542..9c684213 100644 --- a/{{ cookiecutter.name }}/Makefile +++ b/{{ cookiecutter.name }}/Makefile @@ -3,22 +3,22 @@ SIMULTANEOS_TEST_JOBS = auto manage = poetry run python src/manage.py fmt: - poetry run autoflake --in-place --remove-all-unused-imports --recursive src tests - poetry run isort src tests - poetry run black src tests + poetry run autoflake --in-place --remove-all-unused-imports --recursive src + poetry run isort src + poetry run black src poetry run toml-sort pyproject.toml lint: $(manage) check $(manage) makemigrations --check --dry-run --no-input - poetry run isort --check-only src tests - poetry run black --check src tests - poetry run flake8 src tests - poetry run mypy src tests + poetry run isort --check-only src + poetry run black --check src + poetry run flake8 src + poetry run mypy src poetry run toml-sort pyproject.toml --check poetry run pymarkdown scan README.md - poetry run dotenv-linter src/core/.env.ci + poetry run dotenv-linter src/app/.env.ci test: poetry run pytest --dead-fixtures diff --git a/{{ cookiecutter.name }}/README.md b/{{ cookiecutter.name }}/README.md index ef6affc0..b70090a9 100644 --- a/{{ cookiecutter.name }}/README.md +++ b/{{ cookiecutter.name }}/README.md @@ -4,10 +4,10 @@ This project is bootstrapped using [fandsdev/django](http://github.com/fandsdev/ ## Project structure -The main django app is called `core`. It contains `.env` file for django-environ. For examples see `src/core/.env.ci`. Here are some usefull app-wide tools: +The main django app is called `app`. It contains `.env` file for django-environ. For examples see `src/app/.env.ci`. Here are some usefull app-wide tools: -* `core.admin` — app-wide django-admin customizations (empty yet), check out usage [examples](https://github.com/fandsdev/django/tree/master/%7B%7Bcookiecutter.name%7D%7D/src/core/admin) -* `core.test.api_client` (available as `api` and `anon` fixtures within pytest) — a [convinient DRF test client](https://github.com/fandsdev/django/blob/master/%7B%7Bcookiecutter.name%7D%7D/src/tests/apps/users/tests_whoami.py#L6-L16). +* `app.admin` — app-wide django-admin customizations (empty yet), check out usage [examples](https://github.com/fandsdev/django/tree/master/%7B%7Bcookiecutter.name%7D%7D/src/app/admin) +* `app.test.api_client` (available as `api` and `anon` fixtures within pytest) — a [convinient DRF test client](https://github.com/fandsdev/django/blob/master/%7B%7Bcookiecutter.name%7D%7D/src/users/tests/tests_whoami.py#L6-L16). Django user model is located in the separate `users` app. diff --git a/{{ cookiecutter.name }}/conftest.py b/{{ cookiecutter.name }}/conftest.py new file mode 100644 index 00000000..542d1812 --- /dev/null +++ b/{{ cookiecutter.name }}/conftest.py @@ -0,0 +1,6 @@ +pytest_plugins = [ + "app.factory", + "app.fixtures", + "users.factory", + "users.fixtures", +] diff --git a/{{ cookiecutter.name }}/mypy.ini b/{{ cookiecutter.name }}/mypy.ini index 7c220768..605405cd 100644 --- a/{{ cookiecutter.name }}/mypy.ini +++ b/{{ cookiecutter.name }}/mypy.ini @@ -20,15 +20,15 @@ plugins = mypy_django_plugin.main [mypy.plugins.django-stubs] -django_settings_module = "core.settings" +django_settings_module = "app.settings" [mypy-rest_framework_jwt.*] ignore_missing_imports = on -[mypy-core.testing.api.*] +[mypy-app.testing.api.*] disallow_untyped_defs = off -[mypy-tests.*] +[mypy-*.tests.*] disallow_untyped_defs = off [mypy-*.management.*] diff --git a/{{ cookiecutter.name }}/pyproject.toml b/{{ cookiecutter.name }}/pyproject.toml index 0143f3fc..d1f41731 100644 --- a/{{ cookiecutter.name }}/pyproject.toml +++ b/{{ cookiecutter.name }}/pyproject.toml @@ -98,7 +98,7 @@ enabled = false enabled = false [tool.pytest.ini_options] -DJANGO_SETTINGS_MODULE = "core.settings" +DJANGO_SETTINGS_MODULE = "app.settings" addopts = ["--reuse-db"] env = [ "AXES_ENABLED = False", diff --git a/{{ cookiecutter.name }}/src/apps/a12n/__init__.py b/{{ cookiecutter.name }}/src/a12n/__init__.py similarity index 100% rename from {{ cookiecutter.name }}/src/apps/a12n/__init__.py rename to {{ cookiecutter.name }}/src/a12n/__init__.py diff --git a/{{ cookiecutter.name }}/src/apps/a12n/api/throttling.py b/{{ cookiecutter.name }}/src/a12n/api/throttling.py similarity index 77% rename from {{ cookiecutter.name }}/src/apps/a12n/api/throttling.py rename to {{ cookiecutter.name }}/src/a12n/api/throttling.py index 8f636d88..e2a690aa 100644 --- a/{{ cookiecutter.name }}/src/apps/a12n/api/throttling.py +++ b/{{ cookiecutter.name }}/src/a12n/api/throttling.py @@ -1,6 +1,6 @@ from rest_framework.throttling import AnonRateThrottle -from core.api.throttling import ConfigurableThrottlingMixin +from app.api.throttling import ConfigurableThrottlingMixin class AuthAnonRateThrottle(ConfigurableThrottlingMixin, AnonRateThrottle): diff --git a/{{ cookiecutter.name }}/src/apps/a12n/api/urls.py b/{{ cookiecutter.name }}/src/a12n/api/urls.py similarity index 86% rename from {{ cookiecutter.name }}/src/apps/a12n/api/urls.py rename to {{ cookiecutter.name }}/src/a12n/api/urls.py index 1232aa9f..00c6ac72 100644 --- a/{{ cookiecutter.name }}/src/apps/a12n/api/urls.py +++ b/{{ cookiecutter.name }}/src/a12n/api/urls.py @@ -1,6 +1,6 @@ from django.urls import path -from apps.a12n.api import views +from a12n.api import views app_name = "a12n" diff --git a/{{ cookiecutter.name }}/src/apps/a12n/api/views.py b/{{ cookiecutter.name }}/src/a12n/api/views.py similarity index 81% rename from {{ cookiecutter.name }}/src/apps/a12n/api/views.py rename to {{ cookiecutter.name }}/src/a12n/api/views.py index fea82c61..6bf404b3 100644 --- a/{{ cookiecutter.name }}/src/apps/a12n/api/views.py +++ b/{{ cookiecutter.name }}/src/a12n/api/views.py @@ -1,6 +1,6 @@ from rest_framework_jwt import views as jwt -from apps.a12n.api.throttling import AuthAnonRateThrottle +from a12n.api.throttling import AuthAnonRateThrottle class ObtainJSONWebTokenView(jwt.ObtainJSONWebTokenView): diff --git a/{{ cookiecutter.name }}/src/apps/a12n/migrations/__init__.py b/{{ cookiecutter.name }}/src/a12n/migrations/__init__.py similarity index 100% rename from {{ cookiecutter.name }}/src/apps/a12n/migrations/__init__.py rename to {{ cookiecutter.name }}/src/a12n/migrations/__init__.py diff --git a/{{ cookiecutter.name }}/tests/apps/a12n/jwt_views/test_obtain_jwt_view.py b/{{ cookiecutter.name }}/src/a12n/tests/jwt_views/test_obtain_jwt_view.py similarity index 100% rename from {{ cookiecutter.name }}/tests/apps/a12n/jwt_views/test_obtain_jwt_view.py rename to {{ cookiecutter.name }}/src/a12n/tests/jwt_views/test_obtain_jwt_view.py diff --git a/{{ cookiecutter.name }}/tests/apps/a12n/jwt_views/test_refresh_jwt_token.py b/{{ cookiecutter.name }}/src/a12n/tests/jwt_views/test_refresh_jwt_token.py similarity index 97% rename from {{ cookiecutter.name }}/tests/apps/a12n/jwt_views/test_refresh_jwt_token.py rename to {{ cookiecutter.name }}/src/a12n/tests/jwt_views/test_refresh_jwt_token.py index 91fe53d1..a0129a34 100644 --- a/{{ cookiecutter.name }}/tests/apps/a12n/jwt_views/test_refresh_jwt_token.py +++ b/{{ cookiecutter.name }}/src/a12n/tests/jwt_views/test_refresh_jwt_token.py @@ -1,7 +1,7 @@ import pytest from freezegun import freeze_time -from apps.a12n.utils import get_jwt +from a12n.utils import get_jwt pytestmark = [ pytest.mark.django_db, diff --git a/{{ cookiecutter.name }}/src/apps/a12n/utils.py b/{{ cookiecutter.name }}/src/a12n/utils.py similarity index 90% rename from {{ cookiecutter.name }}/src/apps/a12n/utils.py rename to {{ cookiecutter.name }}/src/a12n/utils.py index a018d718..33e68e3a 100644 --- a/{{ cookiecutter.name }}/src/apps/a12n/utils.py +++ b/{{ cookiecutter.name }}/src/a12n/utils.py @@ -1,6 +1,6 @@ from rest_framework_jwt.settings import api_settings -from apps.users.models import User +from users.models import User def get_jwt(user: User) -> str: diff --git a/{{ cookiecutter.name }}/src/core/.env.ci b/{{ cookiecutter.name }}/src/app/.env.ci similarity index 100% rename from {{ cookiecutter.name }}/src/core/.env.ci rename to {{ cookiecutter.name }}/src/app/.env.ci diff --git a/{{ cookiecutter.name }}/src/apps/users/__init__.py b/{{ cookiecutter.name }}/src/app/__init__.py similarity index 100% rename from {{ cookiecutter.name }}/src/apps/users/__init__.py rename to {{ cookiecutter.name }}/src/app/__init__.py diff --git a/{{ cookiecutter.name }}/src/core/admin/__init__.py b/{{ cookiecutter.name }}/src/app/admin/__init__.py similarity index 63% rename from {{ cookiecutter.name }}/src/core/admin/__init__.py rename to {{ cookiecutter.name }}/src/app/admin/__init__.py index 6fabbafa..cb848394 100644 --- a/{{ cookiecutter.name }}/src/core/admin/__init__.py +++ b/{{ cookiecutter.name }}/src/app/admin/__init__.py @@ -1,6 +1,6 @@ from django.contrib import admin -from core.admin.model_admin import ModelAdmin +from app.admin.model_admin import ModelAdmin __all__ = [ "admin", diff --git a/{{ cookiecutter.name }}/src/core/admin/model_admin.py b/{{ cookiecutter.name }}/src/app/admin/model_admin.py similarity index 100% rename from {{ cookiecutter.name }}/src/core/admin/model_admin.py rename to {{ cookiecutter.name }}/src/app/admin/model_admin.py diff --git a/{{ cookiecutter.name }}/src/core/api/pagination.py b/{{ cookiecutter.name }}/src/app/api/pagination.py similarity index 100% rename from {{ cookiecutter.name }}/src/core/api/pagination.py rename to {{ cookiecutter.name }}/src/app/api/pagination.py diff --git a/{{ cookiecutter.name }}/src/core/api/renderers.py b/{{ cookiecutter.name }}/src/app/api/renderers.py similarity index 100% rename from {{ cookiecutter.name }}/src/core/api/renderers.py rename to {{ cookiecutter.name }}/src/app/api/renderers.py diff --git a/{{ cookiecutter.name }}/src/core/api/throttling.py b/{{ cookiecutter.name }}/src/app/api/throttling.py similarity index 100% rename from {{ cookiecutter.name }}/src/core/api/throttling.py rename to {{ cookiecutter.name }}/src/app/api/throttling.py diff --git a/{{ cookiecutter.name }}/src/core/api/viewsets.py b/{{ cookiecutter.name }}/src/app/api/viewsets.py similarity index 100% rename from {{ cookiecutter.name }}/src/core/api/viewsets.py rename to {{ cookiecutter.name }}/src/app/api/viewsets.py diff --git a/{{ cookiecutter.name }}/src/core/base_config.py b/{{ cookiecutter.name }}/src/app/base_config.py similarity index 100% rename from {{ cookiecutter.name }}/src/core/base_config.py rename to {{ cookiecutter.name }}/src/app/base_config.py diff --git a/{{ cookiecutter.name }}/src/core/conf/api.py b/{{ cookiecutter.name }}/src/app/conf/api.py similarity index 93% rename from {{ cookiecutter.name }}/src/core/conf/api.py rename to {{ cookiecutter.name }}/src/app/conf/api.py index 1d76eee0..94d115c6 100644 --- a/{{ cookiecutter.name }}/src/core/conf/api.py +++ b/{{ cookiecutter.name }}/src/app/conf/api.py @@ -1,4 +1,4 @@ -from core.conf.environ import env +from app.conf.environ import env # Django REST Framework # https://www.django-rest-framework.org/api-guide/settings/ @@ -14,7 +14,7 @@ "rest_framework_jwt.authentication.JSONWebTokenAuthentication", ], "DEFAULT_RENDERER_CLASSES": [ - "core.api.renderers.AppJSONRenderer", + "app.api.renderers.AppJSONRenderer", ], "DEFAULT_PARSER_CLASSES": [ "djangorestframework_camel_case.parser.CamelCaseJSONParser", @@ -22,7 +22,7 @@ "djangorestframework_camel_case.parser.CamelCaseFormParser", ], "DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.NamespaceVersioning", - "DEFAULT_PAGINATION_CLASS": "core.api.pagination.AppPagination", + "DEFAULT_PAGINATION_CLASS": "app.api.pagination.AppPagination", "PAGE_SIZE": env("PAGE_SIZE", cast=int, default=20), "DEFAULT_THROTTLE_RATES": { "anon-auth": "10/min", diff --git a/{{ cookiecutter.name }}/src/core/conf/auth.py b/{{ cookiecutter.name }}/src/app/conf/auth.py similarity index 96% rename from {{ cookiecutter.name }}/src/core/conf/auth.py rename to {{ cookiecutter.name }}/src/app/conf/auth.py index 22ae28f7..b69e08d4 100644 --- a/{{ cookiecutter.name }}/src/core/conf/auth.py +++ b/{{ cookiecutter.name }}/src/app/conf/auth.py @@ -1,6 +1,6 @@ from datetime import timedelta -from core.conf.environ import env +from app.conf.environ import env AUTH_USER_MODEL = "users.User" AXES_ENABLED = env("AXES_ENABLED", cast=bool, default=True) diff --git a/{{ cookiecutter.name }}/src/app/conf/boilerplate.py b/{{ cookiecutter.name }}/src/app/conf/boilerplate.py new file mode 100644 index 00000000..f16ff2a1 --- /dev/null +++ b/{{ cookiecutter.name }}/src/app/conf/boilerplate.py @@ -0,0 +1,10 @@ +from pathlib import Path + +BASE_DIR = Path(__file__).resolve().parent.parent + +ROOT_URLCONF = "app.urls" + +# Disable built-in ./manage.py test command in favor of pytest +TEST_RUNNER = "app.test.disable_test_command_runner.DisableTestCommandRunner" + +WSGI_APPLICATION = "app.wsgi.application" diff --git a/{{ cookiecutter.name }}/src/core/conf/db.py b/{{ cookiecutter.name }}/src/app/conf/db.py similarity index 91% rename from {{ cookiecutter.name }}/src/core/conf/db.py rename to {{ cookiecutter.name }}/src/app/conf/db.py index 066c8b3f..935f531e 100644 --- a/{{ cookiecutter.name }}/src/core/conf/db.py +++ b/{{ cookiecutter.name }}/src/app/conf/db.py @@ -1,7 +1,7 @@ # Database # https://docs.djangoproject.com/en/3.0/ref/settings/#databases -from core.conf.environ import env +from app.conf.environ import env DATABASES = { # read os.environ["DATABASE_URL"] and raises ImproperlyConfigured exception if not found diff --git a/{{ cookiecutter.name }}/src/core/conf/environ.py b/{{ cookiecutter.name }}/src/app/conf/environ.py similarity index 83% rename from {{ cookiecutter.name }}/src/core/conf/environ.py rename to {{ cookiecutter.name }}/src/app/conf/environ.py index d59a1587..ad55b162 100644 --- a/{{ cookiecutter.name }}/src/core/conf/environ.py +++ b/{{ cookiecutter.name }}/src/app/conf/environ.py @@ -1,6 +1,6 @@ import environ # type: ignore[import-untyped] -from core.conf.boilerplate import BASE_DIR +from app.conf.boilerplate import BASE_DIR env = environ.Env( DEBUG=(bool, False), diff --git a/{{ cookiecutter.name }}/src/core/conf/healthchecks.py b/{{ cookiecutter.name }}/src/app/conf/healthchecks.py similarity index 100% rename from {{ cookiecutter.name }}/src/core/conf/healthchecks.py rename to {{ cookiecutter.name }}/src/app/conf/healthchecks.py diff --git a/{{ cookiecutter.name }}/src/core/conf/http.py b/{{ cookiecutter.name }}/src/app/conf/http.py similarity index 87% rename from {{ cookiecutter.name }}/src/core/conf/http.py rename to {{ cookiecutter.name }}/src/app/conf/http.py index 87ff3f0f..ff265e4f 100644 --- a/{{ cookiecutter.name }}/src/core/conf/http.py +++ b/{{ cookiecutter.name }}/src/app/conf/http.py @@ -1,4 +1,4 @@ -from core.conf.environ import env +from app.conf.environ import env ALLOWED_HOSTS = ["*"] # host validation is not necessary in 2020 CSRF_TRUSTED_ORIGINS = [ diff --git a/{{ cookiecutter.name }}/src/core/conf/i18n.py b/{{ cookiecutter.name }}/src/app/conf/i18n.py similarity index 72% rename from {{ cookiecutter.name }}/src/core/conf/i18n.py rename to {{ cookiecutter.name }}/src/app/conf/i18n.py index 6b3dc9d7..6318ccc6 100644 --- a/{{ cookiecutter.name }}/src/core/conf/i18n.py +++ b/{{ cookiecutter.name }}/src/app/conf/i18n.py @@ -1,6 +1,6 @@ from pathlib import Path -from core.conf.boilerplate import BASE_DIR +from app.conf.boilerplate import BASE_DIR LANGUAGE_CODE = "ru" diff --git a/{{ cookiecutter.name }}/src/core/conf/installed_apps.py b/{{ cookiecutter.name }}/src/app/conf/installed_apps.py similarity index 93% rename from {{ cookiecutter.name }}/src/core/conf/installed_apps.py rename to {{ cookiecutter.name }}/src/app/conf/installed_apps.py index 3a0e4388..0bc0e14f 100644 --- a/{{ cookiecutter.name }}/src/core/conf/installed_apps.py +++ b/{{ cookiecutter.name }}/src/app/conf/installed_apps.py @@ -1,8 +1,8 @@ # Application definition APPS = [ - "apps.a12n", - "apps.users", + "a12n", + "users", ] THIRD_PARTY_APPS = [ diff --git a/{{ cookiecutter.name }}/src/core/conf/media.py b/{{ cookiecutter.name }}/src/app/conf/media.py similarity index 70% rename from {{ cookiecutter.name }}/src/core/conf/media.py rename to {{ cookiecutter.name }}/src/app/conf/media.py index 85e62198..7c655753 100644 --- a/{{ cookiecutter.name }}/src/core/conf/media.py +++ b/{{ cookiecutter.name }}/src/app/conf/media.py @@ -1,4 +1,4 @@ -from core.conf.environ import env +from app.conf.environ import env MEDIA_URL = "/media/" MEDIA_ROOT = env("MEDIA_ROOT", cast=str, default="media") diff --git a/{{ cookiecutter.name }}/src/core/conf/middleware.py b/{{ cookiecutter.name }}/src/app/conf/middleware.py similarity index 90% rename from {{ cookiecutter.name }}/src/core/conf/middleware.py rename to {{ cookiecutter.name }}/src/app/conf/middleware.py index e7e10025..a59a180e 100644 --- a/{{ cookiecutter.name }}/src/core/conf/middleware.py +++ b/{{ cookiecutter.name }}/src/app/conf/middleware.py @@ -7,6 +7,6 @@ "django.contrib.auth.middleware.AuthenticationMiddleware", "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", - "core.middleware.real_ip.real_ip_middleware", + "app.middleware.real_ip.real_ip_middleware", "axes.middleware.AxesMiddleware", ] diff --git a/{{ cookiecutter.name }}/src/core/conf/sentry.py b/{{ cookiecutter.name }}/src/app/conf/sentry.py similarity index 90% rename from {{ cookiecutter.name }}/src/core/conf/sentry.py rename to {{ cookiecutter.name }}/src/app/conf/sentry.py index 86cc1b0c..3050ea95 100644 --- a/{{ cookiecutter.name }}/src/core/conf/sentry.py +++ b/{{ cookiecutter.name }}/src/app/conf/sentry.py @@ -1,4 +1,4 @@ -from core.conf.environ import env +from app.conf.environ import env # Sentry # https://sentry.io/for/django/ diff --git a/{{ cookiecutter.name }}/src/core/conf/static.py b/{{ cookiecutter.name }}/src/app/conf/static.py similarity index 84% rename from {{ cookiecutter.name }}/src/core/conf/static.py rename to {{ cookiecutter.name }}/src/app/conf/static.py index 89870167..33530c17 100644 --- a/{{ cookiecutter.name }}/src/core/conf/static.py +++ b/{{ cookiecutter.name }}/src/app/conf/static.py @@ -1,4 +1,4 @@ -from core.conf.environ import env +from app.conf.environ import env # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/3.0/howto/static-files/ diff --git a/{{ cookiecutter.name }}/src/core/conf/storage.py b/{{ cookiecutter.name }}/src/app/conf/storage.py similarity index 95% rename from {{ cookiecutter.name }}/src/core/conf/storage.py rename to {{ cookiecutter.name }}/src/app/conf/storage.py index b7ba04a3..d76063f7 100644 --- a/{{ cookiecutter.name }}/src/core/conf/storage.py +++ b/{{ cookiecutter.name }}/src/app/conf/storage.py @@ -1,4 +1,4 @@ -from core.conf.environ import env +from app.conf.environ import env STORAGES = { "default": { diff --git a/{{ cookiecutter.name }}/src/core/conf/templates.py b/{{ cookiecutter.name }}/src/app/conf/templates.py similarity index 100% rename from {{ cookiecutter.name }}/src/core/conf/templates.py rename to {{ cookiecutter.name }}/src/app/conf/templates.py diff --git a/{{ cookiecutter.name }}/src/core/conf/timezone.py b/{{ cookiecutter.name }}/src/app/conf/timezone.py similarity index 100% rename from {{ cookiecutter.name }}/src/core/conf/timezone.py rename to {{ cookiecutter.name }}/src/app/conf/timezone.py diff --git a/{{ cookiecutter.name }}/tests/core/factory.py b/{{ cookiecutter.name }}/src/app/factory.py similarity index 79% rename from {{ cookiecutter.name }}/tests/core/factory.py rename to {{ cookiecutter.name }}/src/app/factory.py index 1c1d022b..cd7338a4 100644 --- a/{{ cookiecutter.name }}/tests/core/factory.py +++ b/{{ cookiecutter.name }}/src/app/factory.py @@ -1,8 +1,8 @@ from django.core.files.uploadedfile import SimpleUploadedFile from faker import Faker -from core.testing import register -from core.testing.types import FactoryProtocol +from app.testing import register +from app.testing.types import FactoryProtocol faker = Faker() diff --git a/{{ cookiecutter.name }}/src/app/fixtures/__init__.py b/{{ cookiecutter.name }}/src/app/fixtures/__init__.py new file mode 100644 index 00000000..24efa781 --- /dev/null +++ b/{{ cookiecutter.name }}/src/app/fixtures/__init__.py @@ -0,0 +1,8 @@ +from app.fixtures.api import as_anon, as_user +from app.fixtures.factory import factory + +__all__ = [ + "as_anon", + "as_user", + "factory", +] diff --git a/{{ cookiecutter.name }}/src/app/fixtures/api.py b/{{ cookiecutter.name }}/src/app/fixtures/api.py new file mode 100644 index 00000000..64be3ec7 --- /dev/null +++ b/{{ cookiecutter.name }}/src/app/fixtures/api.py @@ -0,0 +1,14 @@ +import pytest + +from app.testing import ApiClient +from users.models import User + + +@pytest.fixture +def as_anon() -> ApiClient: + return ApiClient() + + +@pytest.fixture +def as_user(user: User) -> ApiClient: + return ApiClient(user=user) diff --git a/{{ cookiecutter.name }}/src/app/fixtures/factory.py b/{{ cookiecutter.name }}/src/app/fixtures/factory.py new file mode 100644 index 00000000..aa4c777e --- /dev/null +++ b/{{ cookiecutter.name }}/src/app/fixtures/factory.py @@ -0,0 +1,8 @@ +import pytest + +from app.testing.factory import FixtureFactory + + +@pytest.fixture +def factory() -> FixtureFactory: + return FixtureFactory() diff --git a/{{ cookiecutter.name }}/src/core/management/commands/makemigrations.py b/{{ cookiecutter.name }}/src/app/management/commands/makemigrations.py similarity index 100% rename from {{ cookiecutter.name }}/src/core/management/commands/makemigrations.py rename to {{ cookiecutter.name }}/src/app/management/commands/makemigrations.py diff --git a/{{ cookiecutter.name }}/src/app/management/commands/startapp.py b/{{ cookiecutter.name }}/src/app/management/commands/startapp.py new file mode 100644 index 00000000..4f41f201 --- /dev/null +++ b/{{ cookiecutter.name }}/src/app/management/commands/startapp.py @@ -0,0 +1,14 @@ +from os import path + +from django.conf import settings +from django.core.management.commands.startapp import Command as BaseCommand + + +class Command(BaseCommand): + """Set custom template for all newly generated apps""" + + def handle(self, **options): + if "template" not in options or options["template"] is None: + options["template"] = path.join(settings.BASE_DIR, ".django-app-template") + + super().handle(**options) diff --git a/{{ cookiecutter.name }}/src/core/middleware/real_ip.py b/{{ cookiecutter.name }}/src/app/middleware/real_ip.py similarity index 100% rename from {{ cookiecutter.name }}/src/core/middleware/real_ip.py rename to {{ cookiecutter.name }}/src/app/middleware/real_ip.py diff --git a/{{ cookiecutter.name }}/src/core/models.py b/{{ cookiecutter.name }}/src/app/models.py similarity index 100% rename from {{ cookiecutter.name }}/src/core/models.py rename to {{ cookiecutter.name }}/src/app/models.py diff --git a/{{ cookiecutter.name }}/src/core/services.py b/{{ cookiecutter.name }}/src/app/services.py similarity index 100% rename from {{ cookiecutter.name }}/src/core/services.py rename to {{ cookiecutter.name }}/src/app/services.py diff --git a/{{ cookiecutter.name }}/src/core/settings.py b/{{ cookiecutter.name }}/src/app/settings.py similarity index 96% rename from {{ cookiecutter.name }}/src/core/settings.py rename to {{ cookiecutter.name }}/src/app/settings.py index 08fb98e6..f235565d 100644 --- a/{{ cookiecutter.name }}/src/core/settings.py +++ b/{{ cookiecutter.name }}/src/app/settings.py @@ -4,7 +4,7 @@ from split_settings.tools import include -from core.conf.environ import env +from app.conf.environ import env # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = env("SECRET_KEY") diff --git a/{{ cookiecutter.name }}/src/app/testing/__init__.py b/{{ cookiecutter.name }}/src/app/testing/__init__.py new file mode 100644 index 00000000..7652f55f --- /dev/null +++ b/{{ cookiecutter.name }}/src/app/testing/__init__.py @@ -0,0 +1,8 @@ +from app.testing.api import ApiClient +from app.testing.factory import FixtureFactory, register + +__all__ = [ + "ApiClient", + "FixtureFactory", + "register", +] diff --git a/{{ cookiecutter.name }}/src/core/testing/api.py b/{{ cookiecutter.name }}/src/app/testing/api.py similarity index 98% rename from {{ cookiecutter.name }}/src/core/testing/api.py rename to {{ cookiecutter.name }}/src/app/testing/api.py index dfd46a66..dd1f8452 100644 --- a/{{ cookiecutter.name }}/src/core/testing/api.py +++ b/{{ cookiecutter.name }}/src/app/testing/api.py @@ -7,7 +7,7 @@ from rest_framework.response import Response from rest_framework.test import APIClient as DRFAPIClient -from apps.users.models import User +from users.models import User class ApiClient(DRFAPIClient): diff --git a/{{ cookiecutter.name }}/src/core/testing/factory.py b/{{ cookiecutter.name }}/src/app/testing/factory.py similarity index 97% rename from {{ cookiecutter.name }}/src/core/testing/factory.py rename to {{ cookiecutter.name }}/src/app/testing/factory.py index 26b7f3a1..bbe5ae26 100644 --- a/{{ cookiecutter.name }}/src/core/testing/factory.py +++ b/{{ cookiecutter.name }}/src/app/testing/factory.py @@ -1,7 +1,7 @@ from functools import partial from typing import Callable -from core.testing.mixer import mixer +from app.testing.mixer import mixer def register(method: Callable) -> Callable: diff --git a/{{ cookiecutter.name }}/src/core/testing/mixer.py b/{{ cookiecutter.name }}/src/app/testing/mixer.py similarity index 100% rename from {{ cookiecutter.name }}/src/core/testing/mixer.py rename to {{ cookiecutter.name }}/src/app/testing/mixer.py diff --git a/{{ cookiecutter.name }}/src/core/testing/runner.py b/{{ cookiecutter.name }}/src/app/testing/runner.py similarity index 100% rename from {{ cookiecutter.name }}/src/core/testing/runner.py rename to {{ cookiecutter.name }}/src/app/testing/runner.py diff --git a/{{ cookiecutter.name }}/src/core/testing/types.py b/{{ cookiecutter.name }}/src/app/testing/types.py similarity index 100% rename from {{ cookiecutter.name }}/src/core/testing/types.py rename to {{ cookiecutter.name }}/src/app/testing/types.py diff --git a/{{ cookiecutter.name }}/src/apps/users/migrations/__init__.py b/{{ cookiecutter.name }}/src/app/tests/__init__.py similarity index 100% rename from {{ cookiecutter.name }}/src/apps/users/migrations/__init__.py rename to {{ cookiecutter.name }}/src/app/tests/__init__.py diff --git a/{{ cookiecutter.name }}/tests/core/test_health.py b/{{ cookiecutter.name }}/src/app/tests/test_health.py similarity index 100% rename from {{ cookiecutter.name }}/tests/core/test_health.py rename to {{ cookiecutter.name }}/src/app/tests/test_health.py diff --git a/{{ cookiecutter.name }}/tests/core/test_remote_addr_midlleware.py b/{{ cookiecutter.name }}/src/app/tests/test_remote_addr_midlleware.py similarity index 91% rename from {{ cookiecutter.name }}/tests/core/test_remote_addr_midlleware.py rename to {{ cookiecutter.name }}/src/app/tests/test_remote_addr_midlleware.py index c647d05e..7aefd56d 100644 --- a/{{ cookiecutter.name }}/tests/core/test_remote_addr_midlleware.py +++ b/{{ cookiecutter.name }}/src/app/tests/test_remote_addr_midlleware.py @@ -1,7 +1,7 @@ import pytest from django.apps import apps -from core.testing.api import ApiClient +from app.testing.api import ApiClient pytestmark = [pytest.mark.django_db] @@ -9,7 +9,7 @@ @pytest.fixture(autouse=True) def _require_users_app_installed(settings): assert apps.is_installed( - "apps.users" + "users" ), """ Stock f213/django users app should be installed to run this test. diff --git a/{{ cookiecutter.name }}/src/core/__init__.py b/{{ cookiecutter.name }}/src/app/tests/testing/__init__.py similarity index 100% rename from {{ cookiecutter.name }}/src/core/__init__.py rename to {{ cookiecutter.name }}/src/app/tests/testing/__init__.py diff --git a/{{ cookiecutter.name }}/tests/__init__.py b/{{ cookiecutter.name }}/src/app/tests/testing/factory/__init__.py similarity index 100% rename from {{ cookiecutter.name }}/tests/__init__.py rename to {{ cookiecutter.name }}/src/app/tests/testing/factory/__init__.py diff --git a/{{ cookiecutter.name }}/tests/core/testing/factory/test_factory.py b/{{ cookiecutter.name }}/src/app/tests/testing/factory/test_factory.py similarity index 96% rename from {{ cookiecutter.name }}/tests/core/testing/factory/test_factory.py rename to {{ cookiecutter.name }}/src/app/tests/testing/factory/test_factory.py index 58c1206a..465bd1c2 100644 --- a/{{ cookiecutter.name }}/tests/core/testing/factory/test_factory.py +++ b/{{ cookiecutter.name }}/src/app/tests/testing/factory/test_factory.py @@ -1,6 +1,6 @@ import pytest -from core.testing import FixtureFactory, register +from app.testing import FixtureFactory, register @pytest.fixture diff --git a/{{ cookiecutter.name }}/tests/core/testing/factory/test_registry.py b/{{ cookiecutter.name }}/src/app/tests/testing/factory/test_registry.py similarity index 90% rename from {{ cookiecutter.name }}/tests/core/testing/factory/test_registry.py rename to {{ cookiecutter.name }}/src/app/tests/testing/factory/test_registry.py index fee78241..389b7e52 100644 --- a/{{ cookiecutter.name }}/tests/core/testing/factory/test_registry.py +++ b/{{ cookiecutter.name }}/src/app/tests/testing/factory/test_registry.py @@ -1,6 +1,6 @@ import pytest -from core.testing.factory import FixtureRegistry, register +from app.testing.factory import FixtureRegistry, register @pytest.fixture diff --git a/{{ cookiecutter.name }}/src/core/urls/__init__.py b/{{ cookiecutter.name }}/src/app/urls/__init__.py similarity index 74% rename from {{ cookiecutter.name }}/src/core/urls/__init__.py rename to {{ cookiecutter.name }}/src/app/urls/__init__.py index 8a5cba80..659b1bc8 100644 --- a/{{ cookiecutter.name }}/src/core/urls/__init__.py +++ b/{{ cookiecutter.name }}/src/app/urls/__init__.py @@ -2,7 +2,7 @@ from django.urls import include, path api = [ - path("v1/", include("core.urls.v1", namespace="v1")), + path("v1/", include("app.urls.v1", namespace="v1")), ] urlpatterns = [ diff --git a/{{ cookiecutter.name }}/src/core/urls/v1.py b/{{ cookiecutter.name }}/src/app/urls/v1.py similarity index 78% rename from {{ cookiecutter.name }}/src/core/urls/v1.py rename to {{ cookiecutter.name }}/src/app/urls/v1.py index 22d2bbe2..dfd8d18e 100644 --- a/{{ cookiecutter.name }}/src/core/urls/v1.py +++ b/{{ cookiecutter.name }}/src/app/urls/v1.py @@ -4,8 +4,8 @@ app_name = "api_v1" urlpatterns = [ - path("auth/", include("apps.a12n.api.urls")), - path("users/", include("apps.users.api.urls")), + path("auth/", include("a12n.api.urls")), + path("users/", include("users.api.urls")), path("healthchecks/", include("django_healthchecks.urls")), path("docs/schema/", SpectacularAPIView.as_view(), name="schema"), path("docs/swagger/", SpectacularSwaggerView.as_view(url_name="schema")), diff --git a/{{ cookiecutter.name }}/src/core/wsgi.py b/{{ cookiecutter.name }}/src/app/wsgi.py similarity index 60% rename from {{ cookiecutter.name }}/src/core/wsgi.py rename to {{ cookiecutter.name }}/src/app/wsgi.py index 4892961c..d468f8da 100644 --- a/{{ cookiecutter.name }}/src/core/wsgi.py +++ b/{{ cookiecutter.name }}/src/app/wsgi.py @@ -2,6 +2,6 @@ from django.core.wsgi import get_wsgi_application -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "core.settings") +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "app.settings") application = get_wsgi_application() diff --git a/{{ cookiecutter.name }}/src/core/conf/boilerplate.py b/{{ cookiecutter.name }}/src/core/conf/boilerplate.py deleted file mode 100644 index f293b221..00000000 --- a/{{ cookiecutter.name }}/src/core/conf/boilerplate.py +++ /dev/null @@ -1,10 +0,0 @@ -from pathlib import Path - -BASE_DIR = Path(__file__).resolve().parent.parent - -ROOT_URLCONF = "core.urls" - -# Disable built-in ./manage.py test command in favor of pytest -TEST_RUNNER = "core.test.disable_test_command_runner.DisableTestCommandRunner" - -WSGI_APPLICATION = "core.wsgi.application" diff --git a/{{ cookiecutter.name }}/src/core/management/commands/startapp.py b/{{ cookiecutter.name }}/src/core/management/commands/startapp.py deleted file mode 100644 index 092b9426..00000000 --- a/{{ cookiecutter.name }}/src/core/management/commands/startapp.py +++ /dev/null @@ -1,34 +0,0 @@ -from typing import TYPE_CHECKING - -from django.conf import settings -from django.core.management.commands.startapp import Command as BaseCommand - -if TYPE_CHECKING: - from typing import Any - - -class Command(BaseCommand): - def handle(self, **options: "Any") -> None: # type: ignore[override] - app_name = options["name"] - - directory = settings.BASE_DIR.parent / "apps" / app_name # type: ignore[misc] - directory.mkdir() - directory = str(directory) - - if "template" not in options or options["template"] is None: - template = str(settings.BASE_DIR.parent / ".django-app-template") # type: ignore[misc] - - options.update(directory=directory, template=template) - - super().handle(**options) - - self.move_created_tests_directory(app_name=app_name) - - def move_created_tests_directory(self, app_name: str) -> None: - root = settings.BASE_DIR.parent.parent # type: ignore[misc] - - src = root / "src" / "apps" / app_name / "tests" - dst = root / "tests" / "apps" / app_name - - dst.mkdir() - src.rename(dst) diff --git a/{{ cookiecutter.name }}/src/core/testing/__init__.py b/{{ cookiecutter.name }}/src/core/testing/__init__.py deleted file mode 100644 index 55edfa3b..00000000 --- a/{{ cookiecutter.name }}/src/core/testing/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -from core.testing.api import ApiClient -from core.testing.factory import FixtureFactory, register - -__all__ = [ - "ApiClient", - "FixtureFactory", - "register", -] diff --git a/{{ cookiecutter.name }}/src/manage.py b/{{ cookiecutter.name }}/src/manage.py index df71b05a..69525626 100755 --- a/{{ cookiecutter.name }}/src/manage.py +++ b/{{ cookiecutter.name }}/src/manage.py @@ -4,7 +4,7 @@ def main() -> None: - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "core.settings") + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "app.settings") try: from django.core.management import execute_from_command_line diff --git a/{{ cookiecutter.name }}/tests/core/__init__.py b/{{ cookiecutter.name }}/src/users/__init__.py similarity index 100% rename from {{ cookiecutter.name }}/tests/core/__init__.py rename to {{ cookiecutter.name }}/src/users/__init__.py diff --git a/{{ cookiecutter.name }}/src/apps/users/admin.py b/{{ cookiecutter.name }}/src/users/admin.py similarity index 77% rename from {{ cookiecutter.name }}/src/apps/users/admin.py rename to {{ cookiecutter.name }}/src/users/admin.py index bfe68dda..20908271 100644 --- a/{{ cookiecutter.name }}/src/apps/users/admin.py +++ b/{{ cookiecutter.name }}/src/users/admin.py @@ -1,6 +1,6 @@ from django.contrib import admin from django.contrib.auth.admin import UserAdmin -from apps.users.models import User +from users.models import User admin.site.register(User, UserAdmin) diff --git a/{{ cookiecutter.name }}/src/apps/users/api/serializers.py b/{{ cookiecutter.name }}/src/users/api/serializers.py similarity index 92% rename from {{ cookiecutter.name }}/src/apps/users/api/serializers.py rename to {{ cookiecutter.name }}/src/users/api/serializers.py index 822fb5fa..d4786b21 100644 --- a/{{ cookiecutter.name }}/src/apps/users/api/serializers.py +++ b/{{ cookiecutter.name }}/src/users/api/serializers.py @@ -1,6 +1,6 @@ from rest_framework import serializers -from apps.users.models import User +from users.models import User class UserSerializer(serializers.ModelSerializer): diff --git a/{{ cookiecutter.name }}/src/apps/users/api/urls.py b/{{ cookiecutter.name }}/src/users/api/urls.py similarity index 76% rename from {{ cookiecutter.name }}/src/apps/users/api/urls.py rename to {{ cookiecutter.name }}/src/users/api/urls.py index 97528452..4871b5e7 100644 --- a/{{ cookiecutter.name }}/src/apps/users/api/urls.py +++ b/{{ cookiecutter.name }}/src/users/api/urls.py @@ -1,6 +1,6 @@ from django.urls import path -from apps.users.api import viewsets +from users.api import viewsets app_name = "users" diff --git a/{{ cookiecutter.name }}/src/apps/users/api/viewsets.py b/{{ cookiecutter.name }}/src/users/api/viewsets.py similarity index 88% rename from {{ cookiecutter.name }}/src/apps/users/api/viewsets.py rename to {{ cookiecutter.name }}/src/users/api/viewsets.py index 549f1831..3ac03e50 100644 --- a/{{ cookiecutter.name }}/src/apps/users/api/viewsets.py +++ b/{{ cookiecutter.name }}/src/users/api/viewsets.py @@ -4,8 +4,8 @@ from rest_framework.request import Request from rest_framework.response import Response -from apps.users.api.serializers import UserSerializer -from apps.users.models import User +from users.api.serializers import UserSerializer +from users.models import User class SelfView(GenericAPIView): diff --git a/{{ cookiecutter.name }}/tests/apps/users/factory.py b/{{ cookiecutter.name }}/src/users/factory.py similarity index 70% rename from {{ cookiecutter.name }}/tests/apps/users/factory.py rename to {{ cookiecutter.name }}/src/users/factory.py index ecf95ec4..57a1c786 100644 --- a/{{ cookiecutter.name }}/tests/apps/users/factory.py +++ b/{{ cookiecutter.name }}/src/users/factory.py @@ -1,8 +1,8 @@ from django.contrib.auth.models import AnonymousUser -from apps.users.models import User -from core.testing import register -from core.testing.types import FactoryProtocol +from app.testing import register +from app.testing.types import FactoryProtocol +from users.models import User @register diff --git a/{{ cookiecutter.name }}/tests/apps/users/fixtures.py b/{{ cookiecutter.name }}/src/users/fixtures.py similarity index 64% rename from {{ cookiecutter.name }}/tests/apps/users/fixtures.py rename to {{ cookiecutter.name }}/src/users/fixtures.py index 317ebe77..d63e4b8b 100644 --- a/{{ cookiecutter.name }}/tests/apps/users/fixtures.py +++ b/{{ cookiecutter.name }}/src/users/fixtures.py @@ -2,10 +2,10 @@ import pytest -from apps.users.models import User +from users.models import User if TYPE_CHECKING: - from core.testing.factory import FixtureFactory + from app.testing.factory import FixtureFactory @pytest.fixture diff --git a/{{ cookiecutter.name }}/src/apps/users/migrations/0001_initial.py b/{{ cookiecutter.name }}/src/users/migrations/0001_initial.py similarity index 100% rename from {{ cookiecutter.name }}/src/apps/users/migrations/0001_initial.py rename to {{ cookiecutter.name }}/src/users/migrations/0001_initial.py diff --git a/{{ cookiecutter.name }}/tests/core/testing/__init__.py b/{{ cookiecutter.name }}/src/users/migrations/__init__.py similarity index 100% rename from {{ cookiecutter.name }}/tests/core/testing/__init__.py rename to {{ cookiecutter.name }}/src/users/migrations/__init__.py diff --git a/{{ cookiecutter.name }}/src/apps/users/models.py b/{{ cookiecutter.name }}/src/users/models.py similarity index 100% rename from {{ cookiecutter.name }}/src/apps/users/models.py rename to {{ cookiecutter.name }}/src/users/models.py diff --git a/{{ cookiecutter.name }}/tests/apps/users/test_password_hashing.py b/{{ cookiecutter.name }}/src/users/tests/test_password_hashing.py similarity index 87% rename from {{ cookiecutter.name }}/tests/apps/users/test_password_hashing.py rename to {{ cookiecutter.name }}/src/users/tests/test_password_hashing.py index 0afd569a..85c12260 100644 --- a/{{ cookiecutter.name }}/tests/apps/users/test_password_hashing.py +++ b/{{ cookiecutter.name }}/src/users/tests/test_password_hashing.py @@ -2,7 +2,7 @@ import pytest -from apps.users.models import User +from users.models import User pytestmark = [pytest.mark.django_db] diff --git a/{{ cookiecutter.name }}/tests/apps/users/test_whoami.py b/{{ cookiecutter.name }}/src/users/tests/test_whoami.py similarity index 100% rename from {{ cookiecutter.name }}/tests/apps/users/test_whoami.py rename to {{ cookiecutter.name }}/src/users/tests/test_whoami.py diff --git a/{{ cookiecutter.name }}/tests/conftest.py b/{{ cookiecutter.name }}/tests/conftest.py deleted file mode 100644 index c5d58281..00000000 --- a/{{ cookiecutter.name }}/tests/conftest.py +++ /dev/null @@ -1,9 +0,0 @@ -# fmt: off -pytest_plugins = [ - "tests.apps.users.factory", - "tests.core.factory", - - "tests.apps.users.fixtures", - "tests.core.fixtures", -] -# fmt: on diff --git a/{{ cookiecutter.name }}/tests/core/fixtures.py b/{{ cookiecutter.name }}/tests/core/fixtures.py deleted file mode 100644 index 859887c9..00000000 --- a/{{ cookiecutter.name }}/tests/core/fixtures.py +++ /dev/null @@ -1,24 +0,0 @@ -from typing import TYPE_CHECKING - -import pytest - -from core.testing import ApiClient -from core.testing.factory import FixtureFactory - -if TYPE_CHECKING: - from apps.users.models import User - - -@pytest.fixture -def as_anon() -> "ApiClient": - return ApiClient() - - -@pytest.fixture -def as_user(user: "User") -> "ApiClient": - return ApiClient(user=user) - - -@pytest.fixture -def factory() -> "FixtureFactory": - return FixtureFactory() diff --git a/{{ cookiecutter.name }}/tests/core/testing/factory/__init__.py b/{{ cookiecutter.name }}/tests/core/testing/factory/__init__.py deleted file mode 100644 index e69de29b..00000000 From 5122cfd4de58c1200496ce07c41dce36181945cd Mon Sep 17 00:00:00 2001 From: hnthh Date: Thu, 11 Jan 2024 17:18:53 +0300 Subject: [PATCH 084/116] add if cond to child github ci push --- {{ cookiecutter.name }}/.github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/{{ cookiecutter.name }}/.github/workflows/ci.yml b/{{ cookiecutter.name }}/.github/workflows/ci.yml index c58ab157..20325f24 100644 --- a/{{ cookiecutter.name }}/.github/workflows/ci.yml +++ b/{{ cookiecutter.name }}/.github/workflows/ci.yml @@ -89,4 +89,4 @@ jobs: cache-from: type=gha cache-to: type=gha,mode=max context: . - push: false \ No newline at end of file + push: ${{ github.ref == refs/heads/master }} \ No newline at end of file From 265240750a3790df589e4413ab39b14a1e51ed0d Mon Sep 17 00:00:00 2001 From: hnthh Date: Thu, 11 Jan 2024 17:24:02 +0300 Subject: [PATCH 085/116] remove old users migration, create new one in post gen hook --- hooks/post_gen_project.sh | 3 + .../src/users/migrations/0001_initial.py | 90 ------------------- 2 files changed, 3 insertions(+), 90 deletions(-) delete mode 100644 {{ cookiecutter.name }}/src/users/migrations/0001_initial.py diff --git a/hooks/post_gen_project.sh b/hooks/post_gen_project.sh index af9626f9..d77f4234 100644 --- a/hooks/post_gen_project.sh +++ b/hooks/post_gen_project.sh @@ -9,6 +9,9 @@ poetry install poetry run python src/manage.py collectstatic poetry run python src/manage.py startapp some_app +poetry run python src/manage.py makemigrations -n "initial" poetry run python src/manage.py migrate +poetry run isort src/users/migrations/0001_initial.py + make lint test diff --git a/{{ cookiecutter.name }}/src/users/migrations/0001_initial.py b/{{ cookiecutter.name }}/src/users/migrations/0001_initial.py deleted file mode 100644 index 8117842a..00000000 --- a/{{ cookiecutter.name }}/src/users/migrations/0001_initial.py +++ /dev/null @@ -1,90 +0,0 @@ -# Generated by Django 2.2.6 on 2019-10-07 16:27 - -import django.contrib.auth.models -import django.contrib.auth.validators -import django.utils.timezone -from django.db import migrations, models - - -class Migration(migrations.Migration): - initial = True - - dependencies = [ - ("auth", "0012_alter_user_first_name_max_length"), - ] - - operations = [ - migrations.CreateModel( - name="User", - fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ("password", models.CharField(max_length=128, verbose_name="password")), - ("last_login", models.DateTimeField(blank=True, null=True, verbose_name="last login")), - ( - "is_superuser", - models.BooleanField( - default=False, - help_text="Designates that this user has all permissions without explicitly assigning them.", - verbose_name="superuser status", - ), - ), - ( - "username", - models.CharField( - error_messages={"unique": "A user with that username already exists."}, - help_text="Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.", - max_length=150, - unique=True, - validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], - verbose_name="username", - ), - ), - ("first_name", models.CharField(blank=True, max_length=150, verbose_name="first name")), - ("last_name", models.CharField(blank=True, max_length=150, verbose_name="last name")), - ("email", models.EmailField(blank=True, max_length=254, verbose_name="email address")), - ( - "is_staff", - models.BooleanField(default=False, help_text="Designates whether the user can log into this admin site.", verbose_name="staff status"), - ), - ( - "is_active", - models.BooleanField( - default=True, - help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.", - verbose_name="active", - ), - ), - ("date_joined", models.DateTimeField(default=django.utils.timezone.now, verbose_name="date joined")), - ( - "groups", - models.ManyToManyField( - blank=True, - help_text="The groups this user belongs to. A user will get all permissions granted to each of their groups.", - related_name="user_set", - related_query_name="user", - to="auth.Group", - verbose_name="groups", - ), - ), - ( - "user_permissions", - models.ManyToManyField( - blank=True, - help_text="Specific permissions for this user.", - related_name="user_set", - related_query_name="user", - to="auth.Permission", - verbose_name="user permissions", - ), - ), - ], - options={ - "verbose_name": "user", - "verbose_name_plural": "users", - "abstract": False, - }, - managers=[ - ("objects", django.contrib.auth.models.UserManager()), - ], - ), - ] From c47b91225f55b3d2a0dc130c2ed333aa81461aea Mon Sep 17 00:00:00 2001 From: hnthh Date: Thu, 11 Jan 2024 17:27:44 +0300 Subject: [PATCH 086/116] change numprocesses to 4, add random ascii string generation to env --- {{ cookiecutter.name }}/Makefile | 2 +- {{ cookiecutter.name }}/src/app/.env.ci | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/{{ cookiecutter.name }}/Makefile b/{{ cookiecutter.name }}/Makefile index 9c684213..c804626b 100644 --- a/{{ cookiecutter.name }}/Makefile +++ b/{{ cookiecutter.name }}/Makefile @@ -1,4 +1,4 @@ -SIMULTANEOS_TEST_JOBS = auto +SIMULTANEOS_TEST_JOBS = 4 manage = poetry run python src/manage.py diff --git a/{{ cookiecutter.name }}/src/app/.env.ci b/{{ cookiecutter.name }}/src/app/.env.ci index a70e6138..eeb7e951 100644 --- a/{{ cookiecutter.name }}/src/app/.env.ci +++ b/{{ cookiecutter.name }}/src/app/.env.ci @@ -1,3 +1,3 @@ DATABASE_URL=postgres://postgres:@localhost:5432/postgres DEBUG=off -SECRET_KEY=l!@xGb!Jkd]pQsvtU,@y`=%/c}mY;]oYwnsVeU}".VwwClOX +SECRET_KEY={{ random_ascii_string(48, punctuation=True) }} From e73a783431e0fe1fb1dc15664b7a46dfc9c94871 Mon Sep 17 00:00:00 2001 From: hnthh Date: Thu, 11 Jan 2024 17:32:44 +0300 Subject: [PATCH 087/116] remove db.sqlite from gitignore --- .gitignore | 1 - {{ cookiecutter.name }}/.github/workflows/ci.yml | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 33c25fd8..fe20e44b 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,6 @@ **/.DS_Store -{{ cookiecutter.name }}/db.sqlite {{ cookiecutter.name }}/poetry.lock testproject diff --git a/{{ cookiecutter.name }}/.github/workflows/ci.yml b/{{ cookiecutter.name }}/.github/workflows/ci.yml index 20325f24..d145e67c 100644 --- a/{{ cookiecutter.name }}/.github/workflows/ci.yml +++ b/{{ cookiecutter.name }}/.github/workflows/ci.yml @@ -89,4 +89,4 @@ jobs: cache-from: type=gha cache-to: type=gha,mode=max context: . - push: ${{ github.ref == refs/heads/master }} \ No newline at end of file + push: ${{ github.ref == refs/heads/master }} From fc3fc731b71787dd22ad574231e3bd8884cf0748 Mon Sep 17 00:00:00 2001 From: hnthh Date: Thu, 11 Jan 2024 17:35:30 +0300 Subject: [PATCH 088/116] change core to app in app template --- {{ cookiecutter.name }}/src/.django-app-template/admin.py-tpl | 2 +- {{ cookiecutter.name }}/src/.django-app-template/apps.py-tpl | 4 ++-- .../src/.django-app-template/models/app_name.py-tpl | 2 +- .../src/.django-app-template/tests/factory.py-tpl | 0 .../src/.django-app-template/tests/fixtures.py-tpl | 0 5 files changed, 4 insertions(+), 4 deletions(-) delete mode 100644 {{ cookiecutter.name }}/src/.django-app-template/tests/factory.py-tpl delete mode 100644 {{ cookiecutter.name }}/src/.django-app-template/tests/fixtures.py-tpl diff --git a/{{ cookiecutter.name }}/src/.django-app-template/admin.py-tpl b/{{ cookiecutter.name }}/src/.django-app-template/admin.py-tpl index fe7369cf..b1853f8a 100644 --- a/{{ cookiecutter.name }}/src/.django-app-template/admin.py-tpl +++ b/{{ cookiecutter.name }}/src/.django-app-template/admin.py-tpl @@ -1 +1 @@ -from core.admin import ModelAdmin, admin # noqa: F401 +from app.admin import ModelAdmin, admin # noqa: F401 diff --git a/{{ cookiecutter.name }}/src/.django-app-template/apps.py-tpl b/{{ cookiecutter.name }}/src/.django-app-template/apps.py-tpl index 427cdb03..865202f2 100644 --- a/{{ cookiecutter.name }}/src/.django-app-template/apps.py-tpl +++ b/{{ cookiecutter.name }}/src/.django-app-template/apps.py-tpl @@ -1,5 +1,5 @@ -from core.base_config import AppConfig +from app.base_config import AppConfig class {{ camel_case_app_name }}Config(AppConfig): - name = "apps.{{ app_name }}" + name = "{{ app_name }}" diff --git a/{{ cookiecutter.name }}/src/.django-app-template/models/app_name.py-tpl b/{{ cookiecutter.name }}/src/.django-app-template/models/app_name.py-tpl index f423d2ee..033f9b0f 100644 --- a/{{ cookiecutter.name }}/src/.django-app-template/models/app_name.py-tpl +++ b/{{ cookiecutter.name }}/src/.django-app-template/models/app_name.py-tpl @@ -1,3 +1,3 @@ -from core.models import DefaultModel, TimestampedModel, models # noqa: F401 +from app.models import DefaultModel, TimestampedModel, models # noqa: F401 # Rename this file to singular form of your entity, e.g. "orders.py -> order.py". Add your class to __init__.py. diff --git a/{{ cookiecutter.name }}/src/.django-app-template/tests/factory.py-tpl b/{{ cookiecutter.name }}/src/.django-app-template/tests/factory.py-tpl deleted file mode 100644 index e69de29b..00000000 diff --git a/{{ cookiecutter.name }}/src/.django-app-template/tests/fixtures.py-tpl b/{{ cookiecutter.name }}/src/.django-app-template/tests/fixtures.py-tpl deleted file mode 100644 index e69de29b..00000000 From 49072e646f568158e1cadb990c16cbc01d0a9d8a Mon Sep 17 00:00:00 2001 From: hnthh Date: Thu, 11 Jan 2024 17:36:00 +0300 Subject: [PATCH 089/116] replace factories, fixtures from tests dir to app --- {{ cookiecutter.name }}/src/.django-app-template/factory.py-tpl | 0 {{ cookiecutter.name }}/src/.django-app-template/fixtures.py-tpl | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 {{ cookiecutter.name }}/src/.django-app-template/factory.py-tpl create mode 100644 {{ cookiecutter.name }}/src/.django-app-template/fixtures.py-tpl diff --git a/{{ cookiecutter.name }}/src/.django-app-template/factory.py-tpl b/{{ cookiecutter.name }}/src/.django-app-template/factory.py-tpl new file mode 100644 index 00000000..e69de29b diff --git a/{{ cookiecutter.name }}/src/.django-app-template/fixtures.py-tpl b/{{ cookiecutter.name }}/src/.django-app-template/fixtures.py-tpl new file mode 100644 index 00000000..e69de29b From 3da188a9b81d0690a19795f0144c2831adfb2bef Mon Sep 17 00:00:00 2001 From: hnthh Date: Thu, 11 Jan 2024 17:45:15 +0300 Subject: [PATCH 090/116] fix child ci syntax --- {{ cookiecutter.name }}/.github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/{{ cookiecutter.name }}/.github/workflows/ci.yml b/{{ cookiecutter.name }}/.github/workflows/ci.yml index d145e67c..325c14a0 100644 --- a/{{ cookiecutter.name }}/.github/workflows/ci.yml +++ b/{{ cookiecutter.name }}/.github/workflows/ci.yml @@ -89,4 +89,4 @@ jobs: cache-from: type=gha cache-to: type=gha,mode=max context: . - push: ${{ github.ref == refs/heads/master }} + push: ${{ github.ref == 'refs/heads/master' }} From a0ceb84d26e4faff5cf24bc119c38d4381cfb310 Mon Sep 17 00:00:00 2001 From: hnthh Date: Thu, 11 Jan 2024 17:52:00 +0300 Subject: [PATCH 091/116] back to push: false in child ci --- {{ cookiecutter.name }}/.github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/{{ cookiecutter.name }}/.github/workflows/ci.yml b/{{ cookiecutter.name }}/.github/workflows/ci.yml index 325c14a0..388b7c75 100644 --- a/{{ cookiecutter.name }}/.github/workflows/ci.yml +++ b/{{ cookiecutter.name }}/.github/workflows/ci.yml @@ -89,4 +89,4 @@ jobs: cache-from: type=gha cache-to: type=gha,mode=max context: . - push: ${{ github.ref == 'refs/heads/master' }} + push: false From e490dccfdf7fa86b6896add2774e517083bc8069 Mon Sep 17 00:00:00 2001 From: hnthh Date: Fri, 15 Mar 2024 09:40:36 +0300 Subject: [PATCH 092/116] upgrade cache ci action --- .github/workflows/ci.yml | 2 +- {{ cookiecutter.name }}/.github/actions/build/action.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 79077820..5078283c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: steps: - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: build uses: ./.github/actions/build diff --git a/{{ cookiecutter.name }}/.github/actions/build/action.yml b/{{ cookiecutter.name }}/.github/actions/build/action.yml index d832f686..9bb37641 100644 --- a/{{ cookiecutter.name }}/.github/actions/build/action.yml +++ b/{{ cookiecutter.name }}/.github/actions/build/action.yml @@ -6,7 +6,7 @@ runs: steps: - name: load cached poetry installation id: cached-poetry - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.local key: poetry-v1-${{ hashFiles('pyproject.toml') }} From e94d2cf4def0c313e0f4c8d3585d84e0fd195734 Mon Sep 17 00:00:00 2001 From: hnthh Date: Fri, 15 Mar 2024 09:43:53 +0300 Subject: [PATCH 093/116] remove unused dockerfile var --- {{ cookiecutter.name }}/Dockerfile | 1 - 1 file changed, 1 deletion(-) diff --git a/{{ cookiecutter.name }}/Dockerfile b/{{ cookiecutter.name }}/Dockerfile index 1af46bf8..49aa5760 100644 --- a/{{ cookiecutter.name }}/Dockerfile +++ b/{{ cookiecutter.name }}/Dockerfile @@ -25,7 +25,6 @@ LABEL com.datadoghq.ad.logs='[{"service": "django", "source": "uwsgi"}]' ENV DEBIAN_FRONTEND noninteractive ENV PYTHONUNBUFFERED 1 ENV STATIC_ROOT /var/lib/django-static -ENV _WAITFOR_VERSION 2.2.3 RUN apt-get update \ && apt-get --no-install-recommends install -y gettext locales-all tzdata git wait-for-it wget \ From 1ac052938c0968f9d8e184238a2aa921db3c2dca Mon Sep 17 00:00:00 2001 From: hnthh Date: Fri, 15 Mar 2024 09:48:24 +0300 Subject: [PATCH 094/116] try to fix gh inline quotes parser --- {{ cookiecutter.name }}/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/{{ cookiecutter.name }}/pyproject.toml b/{{ cookiecutter.name }}/pyproject.toml index d1f41731..b986f1a0 100644 --- a/{{ cookiecutter.name }}/pyproject.toml +++ b/{{ cookiecutter.name }}/pyproject.toml @@ -82,7 +82,7 @@ ignore = [ "SIM102", # use a single if-statement instead of nested if-statements "SIM113", # use enumerate instead of manually incrementing a counter ] -inline-quotes = "\"" +inline-quotes = '"' [tool.isort] include_trailing_comma = true From 1968fe42be2a79191e8a7b2d0b605f2478793aa5 Mon Sep 17 00:00:00 2001 From: hnthh Date: Fri, 15 Mar 2024 10:07:48 +0300 Subject: [PATCH 095/116] add all to admin, models --- .../src/.django-app-template/admin/__init__.py-tpl | 6 ++++++ .../src/.django-app-template/models/__init__.py-tpl | 6 +++++- .../src/.django-app-template/models/app_name.py-tpl | 3 --- 3 files changed, 11 insertions(+), 4 deletions(-) create mode 100644 {{ cookiecutter.name }}/src/.django-app-template/admin/__init__.py-tpl delete mode 100644 {{ cookiecutter.name }}/src/.django-app-template/models/app_name.py-tpl diff --git a/{{ cookiecutter.name }}/src/.django-app-template/admin/__init__.py-tpl b/{{ cookiecutter.name }}/src/.django-app-template/admin/__init__.py-tpl new file mode 100644 index 00000000..f903ec01 --- /dev/null +++ b/{{ cookiecutter.name }}/src/.django-app-template/admin/__init__.py-tpl @@ -0,0 +1,6 @@ +from app.admin import ModelAdmin, admin + +__all__ = [ + "admin", + "ModelAdmin", +] \ No newline at end of file diff --git a/{{ cookiecutter.name }}/src/.django-app-template/models/__init__.py-tpl b/{{ cookiecutter.name }}/src/.django-app-template/models/__init__.py-tpl index 44f0b885..0d31b3d8 100644 --- a/{{ cookiecutter.name }}/src/.django-app-template/models/__init__.py-tpl +++ b/{{ cookiecutter.name }}/src/.django-app-template/models/__init__.py-tpl @@ -1,3 +1,7 @@ +from app.models import DefaultModel, TimestampedModel, models + __all__ = [ - "", + "models", + "DefaultModel", + "TimestampedModel", ] diff --git a/{{ cookiecutter.name }}/src/.django-app-template/models/app_name.py-tpl b/{{ cookiecutter.name }}/src/.django-app-template/models/app_name.py-tpl deleted file mode 100644 index 033f9b0f..00000000 --- a/{{ cookiecutter.name }}/src/.django-app-template/models/app_name.py-tpl +++ /dev/null @@ -1,3 +0,0 @@ -from app.models import DefaultModel, TimestampedModel, models # noqa: F401 - -# Rename this file to singular form of your entity, e.g. "orders.py -> order.py". Add your class to __init__.py. From c1b8f19c5865a9893d81c3ae35e7e03de437de18 Mon Sep 17 00:00:00 2001 From: Anya Agarenko Date: Sat, 16 Mar 2024 17:49:02 +0300 Subject: [PATCH 096/116] rm `makemessages` from dockerfile, replace pip upgrade cmd --- {{ cookiecutter.name }}/Dockerfile | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/{{ cookiecutter.name }}/Dockerfile b/{{ cookiecutter.name }}/Dockerfile index 49aa5760..20f6116d 100644 --- a/{{ cookiecutter.name }}/Dockerfile +++ b/{{ cookiecutter.name }}/Dockerfile @@ -31,15 +31,14 @@ RUN apt-get update \ && rm -rf /var/lib/apt/lists/* COPY --from=uwsgi-compile /uwsgi /usr/local/bin/ -RUN pip install --no-cache-dir --upgrade pip - COPY --from=deps-compile /requirements.txt / + +RUN pip install --no-cache-dir --upgrade pip RUN pip install --no-cache-dir -r requirements.txt WORKDIR /src COPY src /src -RUN ./manage.py makemessages --locale ru RUN ./manage.py compilemessages RUN ./manage.py collectstatic --noinput From 51c3839009ea1e2354fc4c3c6b0a44d680aa82d7 Mon Sep 17 00:00:00 2001 From: Anya Agarenko Date: Sat, 16 Mar 2024 18:00:27 +0300 Subject: [PATCH 097/116] return `makemessages`, upgrade `uwsgi` --- {{ cookiecutter.name }}/Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/{{ cookiecutter.name }}/Dockerfile b/{{ cookiecutter.name }}/Dockerfile index 20f6116d..c7dd937d 100644 --- a/{{ cookiecutter.name }}/Dockerfile +++ b/{{ cookiecutter.name }}/Dockerfile @@ -2,7 +2,7 @@ ARG PYTHON_VERSION FROM python:${PYTHON_VERSION}-slim-bookworm as uwsgi-compile -ENV _UWSGI_VERSION 2.0.23 +ENV _UWSGI_VERSION 2.0.24 RUN apt-get update && apt-get --no-install-recommends install -y build-essential wget && rm -rf /var/lib/apt/lists/* RUN wget -O uwsgi-${_UWSGI_VERSION}.tar.gz https://github.com/unbit/uwsgi/archive/${_UWSGI_VERSION}.tar.gz \ @@ -39,6 +39,7 @@ RUN pip install --no-cache-dir -r requirements.txt WORKDIR /src COPY src /src +RUN ./manage.py makemessages --locale ru RUN ./manage.py compilemessages RUN ./manage.py collectstatic --noinput From 8e60cd3719795212ea5c9662bc8fb1a7c631ea3d Mon Sep 17 00:00:00 2001 From: Anya Agarenko Date: Sat, 16 Mar 2024 18:08:13 +0300 Subject: [PATCH 098/116] add comment to ci docker image push Co-authored-by: Fedor Borshev <1592663+f213@users.noreply.github.com> --- {{ cookiecutter.name }}/.github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/{{ cookiecutter.name }}/.github/workflows/ci.yml b/{{ cookiecutter.name }}/.github/workflows/ci.yml index 388b7c75..b1619a4f 100644 --- a/{{ cookiecutter.name }}/.github/workflows/ci.yml +++ b/{{ cookiecutter.name }}/.github/workflows/ci.yml @@ -89,4 +89,6 @@ jobs: cache-from: type=gha cache-to: type=gha,mode=max context: . + # make sure you log to the container registry before pushing + # see https://github.com/docker/login-action push: false From 6617ecb2f60cf03592c121aada08de11da61dc7a Mon Sep 17 00:00:00 2001 From: Anya Agarenko Date: Sat, 16 Mar 2024 18:12:39 +0300 Subject: [PATCH 099/116] hash `poetry.lock` instead of `pyproject.toml` in ci --- {{ cookiecutter.name }}/.github/actions/build/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/{{ cookiecutter.name }}/.github/actions/build/action.yml b/{{ cookiecutter.name }}/.github/actions/build/action.yml index 9bb37641..9473ae33 100644 --- a/{{ cookiecutter.name }}/.github/actions/build/action.yml +++ b/{{ cookiecutter.name }}/.github/actions/build/action.yml @@ -9,7 +9,7 @@ runs: uses: actions/cache@v4 with: path: ~/.local - key: poetry-v1-${{ hashFiles('pyproject.toml') }} + key: poetry-v1-${{ hashFiles('poetry.lock') }} - name: install poetry if: steps.cached-poetry.outputs.cache-hit != true From 53b8069489d8bddbd917cf12d255ea6c810d3c04 Mon Sep 17 00:00:00 2001 From: hnthh Date: Sat, 16 Mar 2024 23:29:31 +0300 Subject: [PATCH 100/116] add locale dir with gitkeep --- {{ cookiecutter.name }}/src/locale/.gitkeep | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 {{ cookiecutter.name }}/src/locale/.gitkeep diff --git a/{{ cookiecutter.name }}/src/locale/.gitkeep b/{{ cookiecutter.name }}/src/locale/.gitkeep new file mode 100644 index 00000000..e69de29b From 0b0af16a3d83699842190273788bda30d841f6fc Mon Sep 17 00:00:00 2001 From: Anya Agarenko Date: Sat, 16 Mar 2024 23:33:25 +0300 Subject: [PATCH 101/116] rm `makemessages` --- {{ cookiecutter.name }}/Dockerfile | 1 - 1 file changed, 1 deletion(-) diff --git a/{{ cookiecutter.name }}/Dockerfile b/{{ cookiecutter.name }}/Dockerfile index c7dd937d..c7635339 100644 --- a/{{ cookiecutter.name }}/Dockerfile +++ b/{{ cookiecutter.name }}/Dockerfile @@ -39,7 +39,6 @@ RUN pip install --no-cache-dir -r requirements.txt WORKDIR /src COPY src /src -RUN ./manage.py makemessages --locale ru RUN ./manage.py compilemessages RUN ./manage.py collectstatic --noinput From e65bf1edb3fbe05e9a24c668570912acccae2982 Mon Sep 17 00:00:00 2001 From: hnthh Date: Sat, 16 Mar 2024 23:51:43 +0300 Subject: [PATCH 102/116] add remove-prev-geterated-project-if-exists makefile cmd --- Makefile | 8 ++++++-- hooks/post_gen_project.sh | 1 - 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 2cbaed77..cefffa1b 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,10 @@ -bootstrap: - rm -Rf testproject +remove-prev-generated-project-if-exists: + if [ -d "testproject" ]; then \ + cd testproject && docker compose down --volumes; \ + cd .. && rm -Rf testproject; \ + fi +bootstrap: remove-prev-generated-project-if-exists poetry run cookiecutter --no-input ./ fmt: diff --git a/hooks/post_gen_project.sh b/hooks/post_gen_project.sh index d77f4234..984636f4 100644 --- a/hooks/post_gen_project.sh +++ b/hooks/post_gen_project.sh @@ -2,7 +2,6 @@ cp src/app/.env.ci src/app/.env -docker compose down --volumes docker compose up --detach poetry install From 32b41418b04ddc284eeb6753d29b71708c1855c0 Mon Sep 17 00:00:00 2001 From: Anya Agarenko Date: Sun, 17 Mar 2024 00:02:39 +0300 Subject: [PATCH 103/116] add empty last blank line to tpl file --- .../src/.django-app-template/admin/__init__.py-tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/{{ cookiecutter.name }}/src/.django-app-template/admin/__init__.py-tpl b/{{ cookiecutter.name }}/src/.django-app-template/admin/__init__.py-tpl index f903ec01..4a790127 100644 --- a/{{ cookiecutter.name }}/src/.django-app-template/admin/__init__.py-tpl +++ b/{{ cookiecutter.name }}/src/.django-app-template/admin/__init__.py-tpl @@ -3,4 +3,4 @@ from app.admin import ModelAdmin, admin __all__ = [ "admin", "ModelAdmin", -] \ No newline at end of file +] From ac4fb761f2bf3ed38f86d7eadfcfe52b3e085f31 Mon Sep 17 00:00:00 2001 From: Anya Agarenko Date: Sun, 17 Mar 2024 00:03:30 +0300 Subject: [PATCH 104/116] remove space in .env.ci --- {{ cookiecutter.name }}/src/app/.env.ci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/{{ cookiecutter.name }}/src/app/.env.ci b/{{ cookiecutter.name }}/src/app/.env.ci index eeb7e951..eb1625da 100644 --- a/{{ cookiecutter.name }}/src/app/.env.ci +++ b/{{ cookiecutter.name }}/src/app/.env.ci @@ -1,3 +1,3 @@ DATABASE_URL=postgres://postgres:@localhost:5432/postgres DEBUG=off -SECRET_KEY={{ random_ascii_string(48, punctuation=True) }} +SECRET_KEY={{ random_ascii_string(48, punctuation=True) }} From b314131e60c94fdc2a9810d48d9f8768bd7c9f69 Mon Sep 17 00:00:00 2001 From: hnthh Date: Sun, 17 Mar 2024 00:05:10 +0300 Subject: [PATCH 105/116] upgrade setup-python action to v5 --- .github/actions/build/action.yml | 2 +- {{ cookiecutter.name }}/.github/actions/build/action.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/build/action.yml b/.github/actions/build/action.yml index c7e82e4a..2128ada1 100644 --- a/.github/actions/build/action.yml +++ b/.github/actions/build/action.yml @@ -11,7 +11,7 @@ runs: - name: install python id: setup-python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: cache: poetry python-version-file: pyproject.toml diff --git a/{{ cookiecutter.name }}/.github/actions/build/action.yml b/{{ cookiecutter.name }}/.github/actions/build/action.yml index 9473ae33..c3ebdd03 100644 --- a/{{ cookiecutter.name }}/.github/actions/build/action.yml +++ b/{{ cookiecutter.name }}/.github/actions/build/action.yml @@ -19,7 +19,7 @@ runs: - name: install python id: setup-python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: cache: poetry python-version-file: pyproject.toml From 499eb3b9905efcda9c3dad3f909df7ffabe128cb Mon Sep 17 00:00:00 2001 From: hnthh Date: Sun, 17 Mar 2024 22:00:50 +0300 Subject: [PATCH 106/116] upgrade checkout action to v4 --- .github/workflows/ci.yml | 4 ++-- {{ cookiecutter.name }}/.github/workflows/ci.yml | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5078283c..466aae58 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,7 +26,7 @@ jobs: steps: - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: build uses: ./.github/actions/build @@ -40,7 +40,7 @@ jobs: steps: - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: build uses: ./.github/actions/build diff --git a/{{ cookiecutter.name }}/.github/workflows/ci.yml b/{{ cookiecutter.name }}/.github/workflows/ci.yml index b1619a4f..d0e7e985 100644 --- a/{{ cookiecutter.name }}/.github/workflows/ci.yml +++ b/{{ cookiecutter.name }}/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: steps: - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: build uses: ./.github/actions/build @@ -44,7 +44,7 @@ jobs: steps: - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: build uses: ./.github/actions/build @@ -70,7 +70,7 @@ jobs: steps: - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: build uses: ./.github/actions/build From 215a5b9552fe87e4c38cc27e3b4d144e45bfdb5b Mon Sep 17 00:00:00 2001 From: hnthh Date: Sun, 17 Mar 2024 22:01:56 +0300 Subject: [PATCH 107/116] upgrade setup-qemu-action to v3 --- {{ cookiecutter.name }}/.github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/{{ cookiecutter.name }}/.github/workflows/ci.yml b/{{ cookiecutter.name }}/.github/workflows/ci.yml index d0e7e985..334021aa 100644 --- a/{{ cookiecutter.name }}/.github/workflows/ci.yml +++ b/{{ cookiecutter.name }}/.github/workflows/ci.yml @@ -76,7 +76,7 @@ jobs: uses: ./.github/actions/build - name: setup qemu - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 - name: setup buildx uses: docker/setup-buildx-action@v2 From 2c91acb49882a35151e3d050c3d56d99c7b097f3 Mon Sep 17 00:00:00 2001 From: hnthh Date: Sun, 17 Mar 2024 22:02:54 +0300 Subject: [PATCH 108/116] upgrade setup-buildx-action to v3 --- .github/workflows/ci.yml | 2 +- {{ cookiecutter.name }}/.github/workflows/ci.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 466aae58..7527381f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,7 +52,7 @@ jobs: uses: docker/setup-qemu-action@v2 - name: setup buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 - name: make sure docker image is buildable uses: docker/build-push-action@v3 diff --git a/{{ cookiecutter.name }}/.github/workflows/ci.yml b/{{ cookiecutter.name }}/.github/workflows/ci.yml index 334021aa..9b9cf9d3 100644 --- a/{{ cookiecutter.name }}/.github/workflows/ci.yml +++ b/{{ cookiecutter.name }}/.github/workflows/ci.yml @@ -79,7 +79,7 @@ jobs: uses: docker/setup-qemu-action@v3 - name: setup buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 - name: make sure docker image is buildable uses: docker/build-push-action@v3 From a25efc51f8cd7d2411d30dc79da1d93b35e8f89e Mon Sep 17 00:00:00 2001 From: hnthh Date: Sun, 17 Mar 2024 22:04:02 +0300 Subject: [PATCH 109/116] upgrade build-push-action to v5 --- .github/workflows/ci.yml | 2 +- {{ cookiecutter.name }}/.github/workflows/ci.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7527381f..f926198d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,7 +55,7 @@ jobs: uses: docker/setup-buildx-action@v3 - name: make sure docker image is buildable - uses: docker/build-push-action@v3 + uses: docker/build-push-action@v5 with: build-args: | PYTHON_VERSION=${{ env.python-version }} diff --git a/{{ cookiecutter.name }}/.github/workflows/ci.yml b/{{ cookiecutter.name }}/.github/workflows/ci.yml index 9b9cf9d3..f29d0931 100644 --- a/{{ cookiecutter.name }}/.github/workflows/ci.yml +++ b/{{ cookiecutter.name }}/.github/workflows/ci.yml @@ -82,7 +82,7 @@ jobs: uses: docker/setup-buildx-action@v3 - name: make sure docker image is buildable - uses: docker/build-push-action@v3 + uses: docker/build-push-action@v5 with: build-args: | PYTHON_VERSION=${{ env.python-version }} From b4ae7ad6342188ee79c87d3cc4b0efa8e13aadb1 Mon Sep 17 00:00:00 2001 From: Anya Agarenko Date: Sun, 17 Mar 2024 22:10:50 +0300 Subject: [PATCH 110/116] generate dockerfile maintainer label dynamically Co-authored-by: Fedor Borshev <1592663+f213@users.noreply.github.com> --- {{ cookiecutter.name }}/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/{{ cookiecutter.name }}/Dockerfile b/{{ cookiecutter.name }}/Dockerfile index c7635339..5958e3db 100644 --- a/{{ cookiecutter.name }}/Dockerfile +++ b/{{ cookiecutter.name }}/Dockerfile @@ -19,7 +19,7 @@ RUN pip install --no-cache-dir poetry==$(cat poetry.lock |head -n1|awk -v FS='(P RUN poetry export --format=requirements.txt > requirements.txt FROM python:${PYTHON_VERSION}-slim-bookworm as base -LABEL maintainer="fedor@borshev.com" +LABEL maintainer="{{ cookiecutter.email }}" LABEL com.datadoghq.ad.logs='[{"service": "django", "source": "uwsgi"}]' ENV DEBIAN_FRONTEND noninteractive From 3e909531efb89ef8b53d187e5d1668960d82b0d4 Mon Sep 17 00:00:00 2001 From: hnthh Date: Sun, 17 Mar 2024 22:07:46 +0300 Subject: [PATCH 111/116] squashed commit --- .github/actions/build/action.yml | 2 +- Makefile | 16 ++++++++++------ README.md | 2 ++ hooks/post_gen_project.sh | 5 ++--- pyproject.toml | 1 + .../.github/actions/build/action.yml | 2 +- {{ cookiecutter.name }}/Dockerfile | 12 ++++++++++-- {{ cookiecutter.name }}/pyproject.toml | 1 + 8 files changed, 28 insertions(+), 13 deletions(-) diff --git a/.github/actions/build/action.yml b/.github/actions/build/action.yml index 2128ada1..0188efd3 100644 --- a/.github/actions/build/action.yml +++ b/.github/actions/build/action.yml @@ -7,7 +7,7 @@ runs: - name: install poetry uses: snok/install-poetry@v1 with: - version: 1.6.1 + version: 1.8.2 - name: install python id: setup-python diff --git a/Makefile b/Makefile index cefffa1b..a361c757 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,16 @@ -remove-prev-generated-project-if-exists: - if [ -d "testproject" ]; then \ - cd testproject && docker compose down --volumes; \ - cd .. && rm -Rf testproject; \ - fi +setup-dev-environment: + cp {{\ cookiecutter.name\ }}/docker-compose.yml ./ -bootstrap: remove-prev-generated-project-if-exists + docker-compose down --volumes + docker-compose up --detach + + rm -rf testproject + +bootstrap: setup-dev-environment poetry run cookiecutter --no-input ./ + rm docker-compose.yml + fmt: poetry run toml-sort pyproject.toml diff --git a/README.md b/README.md index 1a333e5b..695ece3b 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,8 @@ ## Installation +First, make sure you have `PostgreSQL` up and running (check the `{{ cookiecutter.name }}/src/app/.env.ci` `DATABASE_URL` and `{{ cookiecutter.name }}/docker-compose.yml` for configuration). After that: + ```bash poetry install diff --git a/hooks/post_gen_project.sh b/hooks/post_gen_project.sh index 984636f4..b5d0f7c2 100644 --- a/hooks/post_gen_project.sh +++ b/hooks/post_gen_project.sh @@ -2,15 +2,14 @@ cp src/app/.env.ci src/app/.env -docker compose up --detach - poetry install poetry run python src/manage.py collectstatic poetry run python src/manage.py startapp some_app poetry run python src/manage.py makemigrations -n "initial" -poetry run python src/manage.py migrate poetry run isort src/users/migrations/0001_initial.py +poetry run python src/manage.py migrate + make lint test diff --git a/pyproject.toml b/pyproject.toml index 12482758..b20f5181 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,6 +6,7 @@ requires = ["poetry-core"] authors = ["Fedor Borshev "] description = "" name = "django-fandsdev" +package-mode = false readme = "README.md" version = "2023.11.29" diff --git a/{{ cookiecutter.name }}/.github/actions/build/action.yml b/{{ cookiecutter.name }}/.github/actions/build/action.yml index c3ebdd03..41a6ed4e 100644 --- a/{{ cookiecutter.name }}/.github/actions/build/action.yml +++ b/{{ cookiecutter.name }}/.github/actions/build/action.yml @@ -15,7 +15,7 @@ runs: if: steps.cached-poetry.outputs.cache-hit != true uses: snok/install-poetry@v1 with: - version: 1.6.1 + version: 1.8.2 - name: install python id: setup-python diff --git a/{{ cookiecutter.name }}/Dockerfile b/{{ cookiecutter.name }}/Dockerfile index 5958e3db..ae69f989 100644 --- a/{{ cookiecutter.name }}/Dockerfile +++ b/{{ cookiecutter.name }}/Dockerfile @@ -1,23 +1,31 @@ ARG PYTHON_VERSION +# +# Compile custom uwsgi, cuz debian's one is weird +# FROM python:${PYTHON_VERSION}-slim-bookworm as uwsgi-compile - ENV _UWSGI_VERSION 2.0.24 - RUN apt-get update && apt-get --no-install-recommends install -y build-essential wget && rm -rf /var/lib/apt/lists/* RUN wget -O uwsgi-${_UWSGI_VERSION}.tar.gz https://github.com/unbit/uwsgi/archive/${_UWSGI_VERSION}.tar.gz \ && tar zxvf uwsgi-*.tar.gz \ && UWSGI_BIN_NAME=/uwsgi make -C uwsgi-${_UWSGI_VERSION} \ && rm -Rf uwsgi-* +# +# Build poetry and export compiled dependecines as plain requirements.txt +# FROM python:${PYTHON_VERSION}-slim-bookworm as deps-compile WORKDIR / COPY poetry.lock pyproject.toml / +# Version is taken from poetry.lock, assuming it is generated with up-to-date version of poetry RUN pip install --no-cache-dir poetry==$(cat poetry.lock |head -n1|awk -v FS='(Poetry |and)' '{print $2}') RUN poetry export --format=requirements.txt > requirements.txt +# +# Base image with django dependecines +# FROM python:${PYTHON_VERSION}-slim-bookworm as base LABEL maintainer="{{ cookiecutter.email }}" LABEL com.datadoghq.ad.logs='[{"service": "django", "source": "uwsgi"}]' diff --git a/{{ cookiecutter.name }}/pyproject.toml b/{{ cookiecutter.name }}/pyproject.toml index b986f1a0..e96048ef 100644 --- a/{{ cookiecutter.name }}/pyproject.toml +++ b/{{ cookiecutter.name }}/pyproject.toml @@ -6,6 +6,7 @@ requires = ["poetry-core"] authors = ["{{ cookiecutter.author }} <{{ cookiecutter.email }}>"] description = "{{ cookiecutter.description }}" name = "{{ cookiecutter.name }}" +package-mode = false readme = "README.md" version = "0.0.0-dev" From 6a56b1ea716ad84a7872f2164c1f153180f78fcf Mon Sep 17 00:00:00 2001 From: Anya Agarenko Date: Fri, 12 Apr 2024 13:50:05 +0300 Subject: [PATCH 112/116] remove docker from makefile --- Makefile | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/Makefile b/Makefile index a361c757..87aaec37 100644 --- a/Makefile +++ b/Makefile @@ -1,16 +1,8 @@ -setup-dev-environment: - cp {{\ cookiecutter.name\ }}/docker-compose.yml ./ - - docker-compose down --volumes - docker-compose up --detach - +bootstrap: rm -rf testproject -bootstrap: setup-dev-environment poetry run cookiecutter --no-input ./ - rm docker-compose.yml - fmt: poetry run toml-sort pyproject.toml From 56ecce1a1bba77f8fedc05bdf87b843df13b94b9 Mon Sep 17 00:00:00 2001 From: Anya Agarenko Date: Fri, 12 Apr 2024 13:51:36 +0300 Subject: [PATCH 113/116] add fmt to makefile --- hooks/post_gen_project.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hooks/post_gen_project.sh b/hooks/post_gen_project.sh index b5d0f7c2..88a846bb 100644 --- a/hooks/post_gen_project.sh +++ b/hooks/post_gen_project.sh @@ -12,4 +12,4 @@ poetry run isort src/users/migrations/0001_initial.py poetry run python src/manage.py migrate -make lint test +make fmt lint test From c7e98f09f3bd8fff6d6f5248270e28de6a32754f Mon Sep 17 00:00:00 2001 From: Anya Agarenko Date: Fri, 12 Apr 2024 13:58:58 +0300 Subject: [PATCH 114/116] add postgres to parent ci --- .github/workflows/ci.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f926198d..978fdf92 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,6 +23,18 @@ jobs: bootstrap: needs: lint runs-on: ubuntu-latest + services: + postgres: + env: + POSTGRES_PASSWORD: secret + image: postgres:16.2-alpine + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-retries 5 + --health-timeout 5s + ports: + - 5432:5432 steps: - name: checkout @@ -33,6 +45,8 @@ jobs: - name: bootstrap run: make bootstrap + env: + DATABASE_URL: postgres://postgres:secret@localhost:5432/postgres build-docker-image: needs: bootstrap From c6983f445efe4670fd2357ad72ed4a2bcf503754 Mon Sep 17 00:00:00 2001 From: Anya Agarenko Date: Fri, 12 Apr 2024 14:03:22 +0300 Subject: [PATCH 115/116] add postgres to build-docker-image job too --- .github/workflows/ci.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 978fdf92..f15910c0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,6 +51,18 @@ jobs: build-docker-image: needs: bootstrap runs-on: ubuntu-latest + services: + postgres: + env: + POSTGRES_PASSWORD: secret + image: postgres:16.2-alpine + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-retries 5 + --health-timeout 5s + ports: + - 5432:5432 steps: - name: checkout @@ -61,6 +73,8 @@ jobs: - name: bootstrap run: make bootstrap + env: + DATABASE_URL: postgres://postgres:secret@localhost:5432/postgres - name: setup qemu uses: docker/setup-qemu-action@v2 From a2dbdfc7dc0cb3c187b955ab7408f20be5a40611 Mon Sep 17 00:00:00 2001 From: Anya Agarenko Date: Mon, 15 Apr 2024 19:29:27 +0300 Subject: [PATCH 116/116] squashed commit --- .github/workflows/ci.yml | 4 ++++ hooks/post_gen_project.sh | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f15910c0..11d94223 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,6 +48,10 @@ jobs: env: DATABASE_URL: postgres://postgres:secret@localhost:5432/postgres + - name: lint generated project (and its template) + run: poetry install && make lint + working-directory: testproject + build-docker-image: needs: bootstrap runs-on: ubuntu-latest diff --git a/hooks/post_gen_project.sh b/hooks/post_gen_project.sh index 88a846bb..e89239cd 100644 --- a/hooks/post_gen_project.sh +++ b/hooks/post_gen_project.sh @@ -12,4 +12,4 @@ poetry run isort src/users/migrations/0001_initial.py poetry run python src/manage.py migrate -make fmt lint test +make test