diff --git a/.gitignore b/.gitignore index c76bc7e..ab9d703 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,9 @@ # docker-compose usage: volumes +# Django +secret.txt + # Coverage HTML Report files: htmlcov diff --git a/Makefile b/Makefile index 1a36a86..7162bf1 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,6 @@ SHELL := /bin/bash MAX_LINE_LENGTH := 119 +export DJANGO_SETTINGS_MODULE ?= inventory_project.settings.local help: ## List all commands @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z0-9 -]+:.*?## / {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) @@ -75,6 +76,8 @@ publish: ## Release new version to PyPi run-dev-server: ## Run the django dev server in endless loop. + ./manage.sh collectstatic --noinput --link + ./manage.sh migrate ./manage.sh runserver messages: ## Make and compile locales message files @@ -93,7 +96,6 @@ create-starter: ## Create starter file. ############################################################################## # docker-compose usage - check-compose: @if [[ "$(shell poetry run docker-compose --version 2>/dev/null)" = *"docker-compose version"* ]] ; \ then \ @@ -134,6 +136,14 @@ shell_inventory: ## Go into bash shell in inventory container shell_postgres: ## Go into bash shell in postgres container ./compose.sh exec postgres /bin/bash +shell_caddy: ## Go into bash shell in caddy container + ./compose.sh exec caddy /bin/ash + +############################################################################## + +caddy_environ: ## Prints the caddy environment + ./compose.sh exec caddy /usr/bin/caddy environ + ############################################################################## logs: ## Display docker logs from all containers @@ -142,9 +152,12 @@ logs: ## Display docker logs from all containers logs_postgres: ## Display docker logs from postgres container ./compose.sh logs --tail=500 --follow postgres -logs_inventory: ## Display docker logs from postgres container +logs_inventory: ## Display docker logs from inventory container ./compose.sh logs --tail=500 --follow inventory +logs_caddy: ## Display docker logs from caddy container + ./compose.sh logs --tail=500 --follow caddy + ############################################################################## dbbackup: ## Backup database @@ -172,4 +185,8 @@ reload_inventory: ## Reload server in "inventory" container ./compose.sh exec inventory ./docker/kill_python.sh ./compose.sh logs --tail=500 --follow inventory +restart_caddy: ## Restart caddy container + ./compose.sh stop caddy + $(MAKE) up + .PHONY: help install lint fix test publish \ No newline at end of file diff --git a/README.creole b/README.creole index 54a5781..04b5e44 100644 --- a/README.creole +++ b/README.creole @@ -42,7 +42,7 @@ any many more... ;) There exists two kind of installation/usage: * local virtualenv (without docker) -* docker-compose +* production use with docker-compose see below @@ -84,15 +84,6 @@ restart Restart all containers }}} -=== .env - -Create a {{{.env}}} file, for some settings, e.g.: -{{{ -# enable Django-Debug-Toolbar: -ENABLE_DJDT=1 -}}} - - === local install without docker {{{ @@ -123,15 +114,33 @@ Install docker, e.g.: https://docs.docker.com/engine/install/ubuntu/ {{{ # Install "docker-compose" via poetry extras: ~/PyInventory$ make install-compose +}}} -# Start containers via docker-compose: +Create a {{{.env}}} file with these content, e.g.: +{{{ +# Public domain or "localhost" for local testing: +HOSTNAME=localhost + +# eMail address for Let's encrypt (Use "internal" for self signed https certificates): +LETSENCRYPT_EMAIL=internal +}}} +e.g. in production: +{{{ +HOSTNAME=domain.tld +LETSENCRYPT_EMAIL=webmaster@domain.tld +}}} + +Start containers via docker-compose: +{{{ ~/PyInventory$ make up }}} -Notes: +Notes: At the first start it takes a little while until the database is created -* at the first start it takes a little while until the database is created -* The web page is available via: {{{http://localhost:8000/}}} +Create first super user: +{{{ +~/PyInventory$ make docker_createsuperuser +}}} == Screenshots @@ -179,6 +188,8 @@ Nothing, yet ;) == history * [[https://github.com/jedie/PyInventory/compare/v0.2.0...master|compare v0.2.0...master]] **dev** +** Remove usage of {{{.env}}} file +** split settings for local development and production use ** tbc * [[https://github.com/jedie/PyInventory/compare/v0.1.0...v0.2.0|v0.2.0 - 24.10.2020]] ** Simplify item change list by nested item diff --git a/README.rst b/README.rst index 6d48987..8c89da8 100644 --- a/README.rst +++ b/README.rst @@ -77,7 +77,7 @@ There exists two kind of installation/usage: * local virtualenv (without docker) -* docker-compose +* production use with docker-compose see below @@ -119,16 +119,6 @@ prepare dbrestore Restore a database backup restart Restart all containers -.env -==== - -Create a ``.env`` file, for some settings, e.g.: - -:: - - # enable Django-Debug-Toolbar: - ENABLE_DJDT=1 - local install without docker ============================ @@ -161,15 +151,37 @@ Install docker, e.g.: `https://docs.docker.com/engine/install/ubuntu/ `_ **dev** + * Remove usage of ``.env`` file + + * split settings for local development and production use + * tbc * `v0.2.0 - 24.10.2020 `_ @@ -288,4 +304,4 @@ donation ------------ -``Note: this file is generated from README.creole 2020-10-24 19:34:25 with "python-creole"`` \ No newline at end of file +``Note: this file is generated from README.creole 2020-10-25 19:34:37 with "python-creole"`` \ No newline at end of file diff --git a/compose.sh b/compose.sh index 56ad999..72e9c9d 100755 --- a/compose.sh +++ b/compose.sh @@ -1,5 +1,12 @@ -#!/bin/sh +#!/bin/bash -set -ex +set -e + +if [[ -f .env ]]; then + echo "Read '.env' file..." + source .env +fi + +set -x exec poetry run docker-compose "$@" diff --git a/docker-compose.yml b/docker-compose.yml index 9f8a908..c32d7a8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,21 +1,36 @@ version: "3.7" services: + caddy: # https://hub.docker.com/_/caddy + image: caddy:2-alpine + restart: unless-stopped + ports: + - "80:80" + - "443:443" + volumes: + - ./docker/Caddyfile:/etc/caddy/Caddyfile + - ./volumes/static/:/srv/:ro + environment: + - HOSTNAME=${HOSTNAME:-localhost} + - LETSENCRYPT_EMAIL=${LETSENCRYPT_EMAIL:-internal} + inventory: build: context: . dockerfile: Dockerfile - restart: "no" + restart: unless-stopped hostname: inventory ports: - - "8000:8000" + - "8000" env_file: ./docker/common.env environment: - - ENABLE_DJDT=$ENABLE_DJDT + - DJANGO_SETTINGS_MODULE=inventory_project.settings.docker + - HOSTNAME=${HOSTNAME:-localhost} links: - postgres:postgres depends_on: - postgres + - caddy volumes: - .:/PyInventory - ./volumes/static/:/PyInventory/static/:rw @@ -26,10 +41,10 @@ services: postgres: # https://hub.docker.com/_/postgres image: postgres:11-alpine - restart: "no" + restart: unless-stopped hostname: postgres ports: - - "5432:5432" + - "5432" env_file: ./docker/common.env environment: - POSTGRES_HOST_AUTH_METHOD=trust diff --git a/docker/Caddyfile b/docker/Caddyfile new file mode 100644 index 0000000..2956583 --- /dev/null +++ b/docker/Caddyfile @@ -0,0 +1,9 @@ +# https://caddyserver.com/docs/caddyfile +{ + admin off +} + +{$HOSTNAME} { + tls {$LETSENCRYPT_EMAIL} + reverse_proxy inventory:8000 +} diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index 3ccf076..eb5a194 100755 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -27,8 +27,20 @@ echo "$(date +%c) - ${0}" ./manage.sh makemigrations ./manage.sh migrate - ./manage.sh runserver 0.0.0.0:8000 - echo "runserver terminated with exit code: $?" + exec poetry run uwsgi \ + --http inventory:8000 \ + --chdir /PyInventory \ + --wsgi-file /PyInventory/inventory_project/wsgi.py \ + --static-map /static=/PyInventory/static \ + --master \ + --processes 2 \ + --threads 2 \ + --ignore-sigpipe \ + --ignore-write-errors \ + --disable-write-exception \ + --http-auto-chunked \ + --http-keepalive + echo "uwsgi terminated with exit code: $?" sleep 3 exit 1 ) diff --git a/inventory/apps.py b/inventory/apps.py index 8f8b12f..0908901 100644 --- a/inventory/apps.py +++ b/inventory/apps.py @@ -15,5 +15,4 @@ class InventoryConfig(AppConfig): verbose_name = "Inventory" def ready(self): - import inventory.checks # noqa import inventory.signals # noqa diff --git a/inventory/checks.py b/inventory/checks.py deleted file mode 100644 index 5d83730..0000000 --- a/inventory/checks.py +++ /dev/null @@ -1,17 +0,0 @@ -from pathlib import Path - -from django.core.checks import Error, register - - -@register() -def inventory_checks(app_configs, **kwargs): - errors = [] - if not Path('.env').is_file(): - errors.append( - Error( - 'No ".env" file found!', - hint='Create a ".env" file. See README for details', - id='pyinventory.E001', - ) - ) - return errors diff --git a/inventory_project/__init__.py b/inventory_project/__init__.py index a9a2faa..00cc14a 100644 --- a/inventory_project/__init__.py +++ b/inventory_project/__init__.py @@ -1,7 +1,7 @@ """ Just print version line on every call from commandline ;) """ - +import os import sys from django import __version__ as django_version @@ -12,3 +12,4 @@ from inventory import __version__ if __name__ == 'inventory_project': if '--version' not in sys.argv: print(f'PyInventory v{__version__} (Django v{django_version})', file=sys.stderr) + print(f'DJANGO_SETTINGS_MODULE={os.environ["DJANGO_SETTINGS_MODULE"]!r}', file=sys.stderr) diff --git a/inventory_project/settings/__init__.py b/inventory_project/settings/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/inventory_project/settings.py b/inventory_project/settings/base.py similarity index 67% rename from inventory_project/settings.py rename to inventory_project/settings/base.py index 1ced0e8..6eedd76 100644 --- a/inventory_project/settings.py +++ b/inventory_project/settings/base.py @@ -1,31 +1,25 @@ """ - Django settings + Base Django settings """ import logging -import os as __os -import sys as __sys from pathlib import Path as __Path from django.utils.translation import ugettext_lazy as _ -print(f'Use settings: {__file__!r}', file=__sys.stderr) - - # Build paths inside the project: -BASE_PATH = __Path(__file__).resolve().parent.parent +BASE_PATH = __Path(__file__).resolve().parent.parent.parent + # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = 'TODO: Read secret.txt ;)' +__SECRET_FILE = __Path(BASE_PATH, 'secret.txt').resolve() +if not __SECRET_FILE.is_file(): + print(f'Generate {__SECRET_FILE}') + from secrets import token_urlsafe as __token_urlsafe + __SECRET_FILE.open('w').write(__token_urlsafe(128)) -# SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True - -# Required for the debug toolbar to be displayed: -INTERNAL_IPS = ('127.0.0.1', '0.0.0.0', 'localhost') - -ALLOWED_HOSTS = INTERNAL_IPS +SECRET_KEY = __SECRET_FILE.open('r').read().strip() # Application definition @@ -84,42 +78,6 @@ TEMPLATES = [ }, ] -if DEBUG: - # Disable caches: - CACHES = {'default': {'BACKEND': 'django.core.cache.backends.dummy.DummyCache'}} - - -# Database -# https://docs.djangoproject.com/en/1.8/ref/settings/#databases - - -if 'DB_HOST' in __os.environ: - # docker-compose usage with postgres database - DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.postgresql', - 'NAME': __os.environ['DB_NAME'], - 'USER': __os.environ['DB_USER'], - 'PASSWORD': __os.environ['DB_PASS'], - 'HOST': __os.environ['DB_HOST'], - 'PORT': __os.environ['DB_PORT'], - 'DEBUG_NAME': 'default', - 'CONN_MAX_AGE': 600, - }, - } -else: - # local run with SQLite - DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': str(__Path(BASE_PATH.parent, 'PyInventory-database.sqlite3')), - # 'NAME': ':memory:' - # https://docs.djangoproject.com/en/dev/ref/databases/#database-is-locked-errors - 'timeout': 30, - } - } -print(f'Use Database: {DATABASES["default"]["NAME"]!r}', file=__sys.stderr) - # _____________________________________________________________________________ # Internationalization @@ -152,29 +110,6 @@ MEDIA_ROOT = str(__Path(BASE_PATH, 'media')) DBBACKUP_STORAGE = 'django.core.files.storage.FileSystemStorage' DBBACKUP_STORAGE_OPTIONS = {'location': str(__Path(BASE_PATH, 'backups'))} -# _____________________________________________________________________________ -# Django-Debug-Toolbar - -ENABLE_DJDT = __os.environ.get('ENABLE_DJDT') in ('true', '1') -if ENABLE_DJDT: - print('Enable Django-Debug-Toolbar') - INSTALLED_APPS += ['debug_toolbar'] - MIDDLEWARE += ['debug_toolbar.middleware.DebugToolbarMiddleware'] - - DEBUG_TOOLBAR_PATCH_SETTINGS = True - from debug_toolbar.settings import CONFIG_DEFAULTS as DEBUG_TOOLBAR_CONFIG # noqa - - # Disable some more panels that will slow down the page: - DEBUG_TOOLBAR_CONFIG['DISABLE_PANELS'].add('debug_toolbar.panels.sql.SQLPanel') - DEBUG_TOOLBAR_CONFIG['DISABLE_PANELS'].add('debug_toolbar.panels.cache.CachePanel') - - # don't load jquery from ajax.googleapis.com, just use django's version: - DEBUG_TOOLBAR_CONFIG['JQUERY_URL'] = STATIC_URL + 'admin/js/vendor/jquery/jquery.min.js' - - DEBUG_TOOLBAR_CONFIG['SHOW_TEMPLATE_CONTEXT'] = True - DEBUG_TOOLBAR_CONFIG['SHOW_COLLAPSED'] = True # Show toolbar collapsed by default. - DEBUG_TOOLBAR_CONFIG['SHOW_TOOLBAR_CALLBACK'] = 'inventory_project.middlewares.djdt_show' - # _____________________________________________________________________________ # django-ckeditor @@ -218,10 +153,10 @@ TAGULOUS_SLUG_TRUNCATE_UNIQUE = 5 TAGULOUS_SLUG_ALLOW_UNICODE = False SERIALIZATION_MODULES = { - 'xml': 'tagulous.serializers.xml_serializer', - 'json': 'tagulous.serializers.json', + 'xml': 'tagulous.serializers.xml_serializer', + 'json': 'tagulous.serializers.json', 'python': 'tagulous.serializers.python', - 'yaml': 'tagulous.serializers.pyyaml', + 'yaml': 'tagulous.serializers.pyyaml', } # _____________________________________________________________________________ diff --git a/inventory_project/settings/docker.py b/inventory_project/settings/docker.py new file mode 100644 index 0000000..e7e14c3 --- /dev/null +++ b/inventory_project/settings/docker.py @@ -0,0 +1,35 @@ +""" + Django settings for docker usage (local and production) +""" +import os as __os + +from inventory_project.settings.base import * # noqa + + +HOSTNAME = __os.environ['HOSTNAME'] + +if HOSTNAME != 'localhost': + print(f'Production mode on domain: {HOSTNAME!r}') + DEBUG = False + INTERNAL_IPS = () +else: + print('Local development mode') + DEBUG = True + INTERNAL_IPS = ('127.0.0.1', '0.0.0.0', 'localhost') + + +ALLOWED_HOSTS = (HOSTNAME,) + + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.postgresql', + 'NAME': __os.environ['DB_NAME'], + 'USER': __os.environ['DB_USER'], + 'PASSWORD': __os.environ['DB_PASS'], + 'HOST': __os.environ['DB_HOST'], + 'PORT': __os.environ['DB_PORT'], + 'DEBUG_NAME': 'default', + 'CONN_MAX_AGE': 600, + }, +} diff --git a/inventory_project/settings/local.py b/inventory_project/settings/local.py new file mode 100644 index 0000000..cbe8163 --- /dev/null +++ b/inventory_project/settings/local.py @@ -0,0 +1,51 @@ +""" + Django settings for local development +""" +import sys as __sys +from pathlib import Path as __Path + +from inventory_project.settings.base import * # noqa + + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +# Disable caches: +CACHES = {'default': {'BACKEND': 'django.core.cache.backends.dummy.DummyCache'}} + +# Required for the debug toolbar to be displayed: +INTERNAL_IPS = ('127.0.0.1', '0.0.0.0', 'localhost') + +ALLOWED_HOSTS = INTERNAL_IPS + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': str(__Path(BASE_PATH.parent, 'PyInventory-database.sqlite3')), + # 'NAME': ':memory:' + # https://docs.djangoproject.com/en/dev/ref/databases/#database-is-locked-errors + 'timeout': 30, + } +} +print(f'Use Database: {DATABASES["default"]["NAME"]!r}', file=__sys.stderr) + +# _____________________________________________________________________________ +# Django-Debug-Toolbar + +INSTALLED_APPS += ['debug_toolbar'] +MIDDLEWARE += ['debug_toolbar.middleware.DebugToolbarMiddleware'] + +DEBUG_TOOLBAR_PATCH_SETTINGS = True +from debug_toolbar.settings import CONFIG_DEFAULTS as DEBUG_TOOLBAR_CONFIG # noqa + + +# Disable some more panels that will slow down the page: +DEBUG_TOOLBAR_CONFIG['DISABLE_PANELS'].add('debug_toolbar.panels.sql.SQLPanel') +DEBUG_TOOLBAR_CONFIG['DISABLE_PANELS'].add('debug_toolbar.panels.cache.CachePanel') + +# don't load jquery from ajax.googleapis.com, just use django's version: +DEBUG_TOOLBAR_CONFIG['JQUERY_URL'] = STATIC_URL + 'admin/js/vendor/jquery/jquery.min.js' + +DEBUG_TOOLBAR_CONFIG['SHOW_TEMPLATE_CONTEXT'] = True +DEBUG_TOOLBAR_CONFIG['SHOW_COLLAPSED'] = True # Show toolbar collapsed by default. +DEBUG_TOOLBAR_CONFIG['SHOW_TOOLBAR_CALLBACK'] = 'inventory_project.middlewares.djdt_show' diff --git a/inventory_project/urls.py b/inventory_project/urls.py index a718e6d..006a18f 100644 --- a/inventory_project/urls.py +++ b/inventory_project/urls.py @@ -1,10 +1,9 @@ +from django.conf import settings from django.conf.urls import include, static, url from django.contrib import admin from django.urls import path from django.views.generic import RedirectView -from inventory_project import settings - admin.autodiscover() diff --git a/inventory_project/wsgi.py b/inventory_project/wsgi.py index f68c3e5..d9598cf 100644 --- a/inventory_project/wsgi.py +++ b/inventory_project/wsgi.py @@ -2,11 +2,8 @@ WSGI config """ -import os from django.core.wsgi import get_wsgi_application -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "inventory_project.settings") - application = get_wsgi_application() diff --git a/manage.py b/manage.py index 6f6e161..d2eb2d9 100644 --- a/manage.py +++ b/manage.py @@ -5,7 +5,7 @@ import sys def main(): - os.environ['DJANGO_SETTINGS_MODULE'] = 'inventory_project.settings' + assert 'DJANGO_SETTINGS_MODULE' in os.environ, 'No "DJANGO_SETTINGS_MODULE" in environment!' try: from django.core.management import execute_from_command_line except ImportError as exc: diff --git a/poetry.lock b/poetry.lock index c427c37..936daeb 100644 --- a/poetry.lock +++ b/poetry.lock @@ -471,20 +471,6 @@ python-versions = ">=3.6" [package.dependencies] astor = "*" -[[package]] -name = "gunicorn" -version = "20.0.4" -description = "WSGI HTTP Server for UNIX" -category = "main" -optional = false -python-versions = ">=3.4" - -[package.extras] -eventlet = ["eventlet (>=0.9.7)"] -gevent = ["gevent (>=0.13)"] -setproctitle = ["setproctitle"] -tornado = ["tornado (>=0.2)"] - [[package]] name = "icdiff" version = "1.9.1" @@ -749,7 +735,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "pygments" -version = "2.7.1" +version = "2.7.2" description = "Pygments is a syntax highlighting package written in Python." category = "dev" optional = false @@ -1118,9 +1104,17 @@ brotli = ["brotlipy (>=0.6.0)"] secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"] +[[package]] +name = "uwsgi" +version = "2.0.19.1" +description = "The uWSGI server" +category = "main" +optional = false +python-versions = "*" + [[package]] name = "virtualenv" -version = "20.0.35" +version = "20.1.0" description = "Virtual Python Environment builder" category = "dev" optional = false @@ -1191,7 +1185,7 @@ postgres = ["psycopg2-binary"] [metadata] lock-version = "1.1" python-versions = ">=3.7,<4.0.0" -content-hash = "d07f05b3cb200bb30974923869838af5e96a1935fdcbaa2e536f03f046583d90" +content-hash = "0ab17efa6bba93be2850b753353a4dcf990d0b89cec16a508701a42011fe5862" [metadata.files] appdirs = [ @@ -1441,10 +1435,6 @@ flynt = [ {file = "flynt-0.55-py3-none-any.whl", hash = "sha256:df62c89d34e1318fa40b865343a70dcdc970be849f610c9b79af43cdbc40877b"}, {file = "flynt-0.55.tar.gz", hash = "sha256:2e24775b15b8cc4965703e1f9b21e4658533a8bfb57a4782125dff2faa124e83"}, ] -gunicorn = [ - {file = "gunicorn-20.0.4-py2.py3-none-any.whl", hash = "sha256:cd4a810dd51bf497552cf3f863b575dabd73d6ad6a91075b65936b151cbf4f9c"}, - {file = "gunicorn-20.0.4.tar.gz", hash = "sha256:1904bb2b8a43658807108d59c3f3d56c2b6121a701161de0ddf9ad140073c626"}, -] icdiff = [ {file = "icdiff-1.9.1.tar.gz", hash = "sha256:66972dd03318da55280991db375d3ef6b66d948c67af96c1ebdb21587e86655e"}, ] @@ -1570,8 +1560,8 @@ pyflakes = [ {file = "pyflakes-2.2.0.tar.gz", hash = "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"}, ] pygments = [ - {file = "Pygments-2.7.1-py3-none-any.whl", hash = "sha256:307543fe65c0947b126e83dd5a61bd8acbd84abec11f43caebaf5534cbc17998"}, - {file = "Pygments-2.7.1.tar.gz", hash = "sha256:926c3f319eda178d1bd90851e4317e6d8cdb5e292a3386aac9bd75eca29cf9c7"}, + {file = "Pygments-2.7.2-py3-none-any.whl", hash = "sha256:88a0bbcd659fcb9573703957c6b9cff9fab7295e6e76db54c9d00ae42df32773"}, + {file = "Pygments-2.7.2.tar.gz", hash = "sha256:381985fcc551eb9d37c52088a32914e00517e57f4a21609f48141ba08e193fa0"}, ] pynacl = [ {file = "PyNaCl-1.4.0-cp27-cp27m-macosx_10_10_x86_64.whl", hash = "sha256:ea6841bc3a76fa4942ce00f3bda7d436fda21e2d91602b9e21b7ca9ecab8f3ff"}, @@ -1723,9 +1713,12 @@ urllib3 = [ {file = "urllib3-1.25.11-py2.py3-none-any.whl", hash = "sha256:f5321fbe4bf3fefa0efd0bfe7fb14e90909eb62a48ccda331726b4319897dd5e"}, {file = "urllib3-1.25.11.tar.gz", hash = "sha256:8d7eaa5a82a1cac232164990f04874c594c9453ec55eef02eab885aa02fc17a2"}, ] +uwsgi = [ + {file = "uWSGI-2.0.19.1.tar.gz", hash = "sha256:faa85e053c0b1be4d5585b0858d3a511d2cd10201802e8676060fd0a109e5869"}, +] virtualenv = [ - {file = "virtualenv-20.0.35-py2.py3-none-any.whl", hash = "sha256:0ebc633426d7468664067309842c81edab11ae97fcaf27e8ad7f5748c89b431b"}, - {file = "virtualenv-20.0.35.tar.gz", hash = "sha256:2a72c80fa2ad8f4e2985c06e6fc12c3d60d060e410572f553c90619b0f6efaf3"}, + {file = "virtualenv-20.1.0-py2.py3-none-any.whl", hash = "sha256:b0011228208944ce71052987437d3843e05690b2f23d1c7da4263fde104c97a2"}, + {file = "virtualenv-20.1.0.tar.gz", hash = "sha256:b8d6110f493af256a40d65e29846c69340a947669eec8ce784fcf3dd3af28380"}, ] webencodings = [ {file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"}, diff --git a/pyproject.toml b/pyproject.toml index 536d59c..3dcf3b5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,7 +38,7 @@ readme='README.rst' python = ">=3.7,<4.0.0" colorama = "*" # Console colors under windows: https://pypi.org/project/colorama/ colorlog = "*" # https://github.com/borntyping/python-colorlog -gunicorn = "*" # https://gunicorn.org/ +uWSGI = "*" # # https://www.djangoproject.com/download/#supported-versions # v2.2 LTS - extended support until April 2022