diff --git a/.github/workflows/strings.yml b/.github/workflows/strings.yml index 34484e0685..bc6b5c8342 100644 --- a/.github/workflows/strings.yml +++ b/.github/workflows/strings.yml @@ -38,7 +38,6 @@ jobs: run: sudo apt update && sudo apt install gettext - name: Install Dependencies run: pip3 install -e ".[dev]" - working-directory: ./src - name: Compile messages run: python manage.py compilemessages working-directory: ./src @@ -64,7 +63,6 @@ jobs: run: sudo apt update && sudo apt install enchant-2 hunspell hunspell-de-de aspell-en aspell-de - name: Install Dependencies run: pip3 install -e ".[dev]" - working-directory: ./src - name: Spellcheck translations run: potypo working-directory: ./src diff --git a/.github/workflows/style.yml b/.github/workflows/style.yml index c78ed6f941..9e5d3cddc6 100644 --- a/.github/workflows/style.yml +++ b/.github/workflows/style.yml @@ -36,7 +36,6 @@ jobs: ${{ runner.os }}-pip- - name: Install Dependencies run: pip3 install -e ".[dev]" mysqlclient psycopg2-binary - working-directory: ./src - name: Run isort run: isort -c . working-directory: ./src @@ -57,7 +56,6 @@ jobs: ${{ runner.os }}-pip- - name: Install Dependencies run: pip3 install -e ".[dev]" mysqlclient psycopg2-binary - working-directory: ./src - name: Run flake8 run: flake8 . working-directory: ./src diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 8b05bb6bc0..1538c3c8cb 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -64,7 +64,6 @@ jobs: run: sudo apt update && sudo apt install gettext mariadb-client - name: Install Python dependencies run: pip3 install --ignore-requires-python -e ".[dev]" mysqlclient psycopg2-binary # We ignore that flake8 needs newer python as we don't run flake8 during tests - working-directory: ./src - name: Run checks run: python manage.py check working-directory: ./src diff --git a/.gitignore b/.gitignore index bc3718523c..7a1321ee43 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ env/ +build/ +dist/ .coverage htmlcov/ .ropeproject diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6573d4dbe8..e00ffe9b3e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -5,8 +5,8 @@ tests: - virtualenv env - source env/bin/activate - pip install -U pip wheel setuptools - - cd src - XDG_CACHE_HOME=/cache pip3 install -e ".[dev]" + - cd src - python manage.py check - make all compress - py.test --reruns 3 -n 3 tests @@ -21,8 +21,8 @@ pypi: - virtualenv env - source env/bin/activate - pip install -U pip wheel setuptools check-manifest twine - - cd src - XDG_CACHE_HOME=/cache pip3 install -e ".[dev]" + - cd src - python setup.py sdist - pip install dist/pretix-*.tar.gz - python -m pretix migrate diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000000..1d41212f8c --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,33 @@ +include LICENSE +include README.rst +global-include *.proto +recursive-include src/pretix/static * +recursive-include src/pretix/static.dist * +recursive-include src/pretix/locale * +recursive-include src/pretix/helpers/locale * +recursive-include src/pretix/base/templates * +recursive-include src/pretix/control/templates * +recursive-include src/pretix/presale/templates * +recursive-include src/pretix/plugins/banktransfer/templates * +recursive-include src/pretix/plugins/banktransfer/static * +recursive-include src/pretix/plugins/manualpayment/templates * +recursive-include src/pretix/plugins/manualpayment/static * +recursive-include src/pretix/plugins/paypal/templates * +recursive-include src/pretix/plugins/paypal/static * +recursive-include src/pretix/plugins/paypal2/templates * +recursive-include src/pretix/plugins/paypal2/static * +recursive-include src/pretix/plugins/src/pretixdroid/templates * +recursive-include src/pretix/plugins/src/pretixdroid/static * +recursive-include src/pretix/plugins/sendmail/templates * +recursive-include src/pretix/plugins/statistics/templates * +recursive-include src/pretix/plugins/statistics/static * +recursive-include src/pretix/plugins/stripe/templates * +recursive-include src/pretix/plugins/stripe/static * +recursive-include src/pretix/plugins/ticketoutputpdf/templates * +recursive-include src/pretix/plugins/ticketoutputpdf/static * +recursive-include src/pretix/plugins/badges/templates * +recursive-include src/pretix/plugins/badges/static * +recursive-include src/pretix/plugins/returnurl/templates * +recursive-include src/pretix/plugins/returnurl/static * +recursive-include src/pretix/plugins/webcheckin/templates * +recursive-include src/pretix/plugins/webcheckin/static * diff --git a/doc/admin/installation/dev_version.rst b/doc/admin/installation/dev_version.rst index e0fa3bc755..d56d5d96e4 100644 --- a/doc/admin/installation/dev_version.rst +++ b/doc/admin/installation/dev_version.rst @@ -16,7 +16,7 @@ Manual installation You can use ``pip`` to update pretix directly to the development branch. Then, upgrade as usual:: $ source /var/pretix/venv/bin/activate - (venv)$ pip3 install -U "git+https://github.com/pretix/pretix.git#egg=pretix&subdirectory=src" + (venv)$ pip3 install -U "git+https://github.com/pretix/pretix.git#egg=pretix" (venv)$ python -m pretix migrate (venv)$ python -m pretix rebuild (venv)$ python -m pretix updatestyles diff --git a/doc/requirements.txt b/doc/requirements.txt index 49c9ac7962..43da5334d2 100644 --- a/doc/requirements.txt +++ b/doc/requirements.txt @@ -1,4 +1,4 @@ --e ../src/ +-e ../ sphinx==6.1.* jinja2==3.1.* sphinx-rtd-theme diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000000..bfe18de74b --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,185 @@ +[project] +name = "pretix" +dynamic = ["version"] +description = "Reinventing presales, one ticket at a time" +readme = "README.rst" +requires-python = ">=3.9" +license = {file = "LICENSE"} +keywords = ["tickets", "web", "shop", "ecommerce"] +authors = [ + {name = "pretix team", email = "support@pretix.eu"}, +] +maintainers = [ + {name = "pretix team", email = "support@pretix.eu"}, +] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "Intended Audience :: Other Audience", + "Topic :: Internet :: WWW/HTTP :: Dynamic Content", + "Environment :: Web Environment", + "License :: OSI Approved :: GNU Affero General Public License v3", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Framework :: Django :: 3.2", +] + +dependencies = [ + # Note that many of these are repeated as build-time dependencies down below -- change them too in case of updates! + "arabic-reshaper==3.0.0", # Support for Arabic in reportlab + "babel", + "BeautifulSoup4==4.12.*", + "bleach==5.0.*", + "celery==5.2.*", + "chardet==5.1.*", + "cryptography>=3.4.2", + "css-inline==0.8.*", + "defusedcsv>=1.1.0", + "dj-static", + "Django==3.2.*,>=3.2.18", + "django-bootstrap3==23.1.*", + "django-compressor==4.3.*", + "django-countries==7.5.*", + "django-filter==23.1", + "django-formset-js-improved==0.5.0.3", + "django-formtools==2.4", + "django-hierarkey==1.1.*", + "django-hijack==3.3.*", + "django-i18nfield==1.9.*,>=1.9.4", + "django-libsass==0.9", + "django-localflavor==3.1", + "django-markup", + "django-mysql", + "django-oauth-toolkit==2.2.*", + "django-otp==1.1.*", + "django-phonenumber-field==7.0.*", + "django-redis==5.2.*", + "django-scopes==1.2.*", + "django-statici18n==2.3.*", + "djangorestframework==3.14.*", + "dnspython==2.2.*", + "drf_ujson2==1.7.*", + "geoip2==4.*", + "importlib_metadata==6.5.*", # Polyfill, we can probably drop this once we require Python 3.10+ + "isoweek", + "jsonschema", + "kombu==5.2.*", + "libsass==0.22.*", + "lxml", + "markdown==3.3.4", # 3.3.5 requires importlib-metadata>=4.4, but django-bootstrap3 requires importlib-metadata<3. + # We can upgrade markdown again once django-bootstrap3 upgrades or once we drop Python 3.6 and 3.7 + "mt-940==4.23.*", + "oauthlib==3.2.*", + "openpyxl==3.1.*", + "packaging", + "paypalrestsdk==1.13.*", + "paypal-checkout-serversdk==1.0.*", + "PyJWT==2.6.*", + "phonenumberslite==8.13.*", + "Pillow==9.5.*", + "protobuf==4.22.*", + "psycopg2-binary", + "pycountry", + "pycparser==2.21", + "pycryptodome==3.17.*", + "pypdf==3.8.*", + "python-bidi==0.4.*", # Support for Arabic in reportlab + "python-dateutil==2.8.*", + "python-u2flib-server==4.*", + "pytz", + "pyuca", + "qrcode==7.4.*", + "redis==4.5.*,>=4.5.4", + "reportlab==3.6.*", + "requests==2.28.*", + "sentry-sdk==1.15.*", + "sepaxml==2.6.*", + "slimit", + "static3==0.7.*", + "stripe==5.4.*", + "text-unidecode==1.*", + "tlds>=2020041600", + "tqdm==4.*", + "vat_moss_forked==2020.3.20.0.11.0", + "vobject==0.9.*", + "webauthn==0.4.*", + "zeep==4.2.*" +] + +[project.optional-dependencies] +memcached = ["pylibmc"] +mysql = ["mysqlclient"] +dev = [ + "coverage", + "coveralls", + "django-debug-toolbar==4.0.*", + "django-formset-js-improved==0.5.0.3", + "django-oauth-toolkit==2.2.*", + "flake8==6.0.*", + "freezegun", + "isort==5.12.*", + "oauthlib==3.2.*", + "pep8-naming==0.12.*", + "potypo", + "pycodestyle==2.10.*", + "pyflakes==3.0.*", + "pytest-cache", + "pytest-cov", + "pytest-django==4.*", + "pytest-mock==3.10.*", + "pytest-rerunfailures==11.*", + "pytest-sugar", + "pytest-xdist==3.2.*", + "pytest==7.3.*", + "responses", +] + +[project.entry-points."distutils.commands"] +build = "pretix._build:CustomBuild" +build_ext = "pretix._build:CustomBuildExt" + +[build-system] +requires = [ + "setuptools", + "setuptools-rust", + "wheel", + "importlib_metadata", + + # These are runtime dependencies that we unfortunately need to be import in the step that generates + # all CSS and JS asset files. We should keep their versions in sync with the definition above. + "babel", + "Django==3.2.*,>=3.2.18", + "django-bootstrap3==23.1.*", + "django-compressor==4.3.*", + "django-countries==7.5.*", + "django-formtools==2.4", + "django-hierarkey==1.1.*", + "django-i18nfield==1.9.*,>=1.9.4", + "django-libsass==0.9", + "django-phonenumber-field==7.0.*", + "django-statici18n==2.3.*", + "djangorestframework==3.14.*", + "libsass==0.22.*", + "phonenumberslite==8.13.*", + "pycountry", + "pyuca", + "slimit", +] + +[project.urls] +homepage = "https://pretix.eu" +documentation = "https://docs.pretix.eu" +repository = "https://github.com/pretix/pretix.git" +changelog = "https://pretix.eu/about/en/blog/" + +[tool.setuptools] +include-package-data = true + +[tool.setuptools.dynamic] +version = {attr = "pretix.__version__"} + +[tool.setuptools.packages.find] +where = ["src"] +include = ["pretix*"] +namespaces = false \ No newline at end of file diff --git a/setup.py b/setup.py new file mode 100644 index 0000000000..a03f676654 --- /dev/null +++ b/setup.py @@ -0,0 +1,26 @@ +# +# This file is part of pretix (Community Edition). +# +# Copyright (C) 2014-2020 Raphael Michel and contributors +# Copyright (C) 2020-2021 rami.io GmbH and contributors +# +# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General +# Public License as published by the Free Software Foundation in version 3 of the License. +# +# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are +# applicable granting you additional permissions and placing additional restrictions on your usage of this software. +# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive +# this file, see . +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +# details. +# +# You should have received a copy of the GNU Affero General Public License along with this program. If not, see +# . +# + +import setuptools + +if __name__ == "__main__": + setuptools.setup() diff --git a/src/MANIFEST.in b/src/MANIFEST.in deleted file mode 100644 index 5b8a9899b0..0000000000 --- a/src/MANIFEST.in +++ /dev/null @@ -1,33 +0,0 @@ -include LICENSE -include README.rst -global-include *.proto -recursive-include pretix/static * -recursive-include pretix/static.dist * -recursive-include pretix/locale * -recursive-include pretix/helpers/locale * -recursive-include pretix/base/templates * -recursive-include pretix/control/templates * -recursive-include pretix/presale/templates * -recursive-include pretix/plugins/banktransfer/templates * -recursive-include pretix/plugins/banktransfer/static * -recursive-include pretix/plugins/manualpayment/templates * -recursive-include pretix/plugins/manualpayment/static * -recursive-include pretix/plugins/paypal/templates * -recursive-include pretix/plugins/paypal/static * -recursive-include pretix/plugins/paypal2/templates * -recursive-include pretix/plugins/paypal2/static * -recursive-include pretix/plugins/pretixdroid/templates * -recursive-include pretix/plugins/pretixdroid/static * -recursive-include pretix/plugins/sendmail/templates * -recursive-include pretix/plugins/statistics/templates * -recursive-include pretix/plugins/statistics/static * -recursive-include pretix/plugins/stripe/templates * -recursive-include pretix/plugins/stripe/static * -recursive-include pretix/plugins/ticketoutputpdf/templates * -recursive-include pretix/plugins/ticketoutputpdf/static * -recursive-include pretix/plugins/badges/templates * -recursive-include pretix/plugins/badges/static * -recursive-include pretix/plugins/returnurl/templates * -recursive-include pretix/plugins/returnurl/static * -recursive-include pretix/plugins/webcheckin/templates * -recursive-include pretix/plugins/webcheckin/static * diff --git a/src/pretix/_base_settings.py b/src/pretix/_base_settings.py new file mode 100644 index 0000000000..e4b592f893 --- /dev/null +++ b/src/pretix/_base_settings.py @@ -0,0 +1,251 @@ +# +# This file is part of pretix (Community Edition). +# +# Copyright (C) 2014-2020 Raphael Michel and contributors +# Copyright (C) 2020-2021 rami.io GmbH and contributors +# +# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General +# Public License as published by the Free Software Foundation in version 3 of the License. +# +# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are +# applicable granting you additional permissions and placing additional restrictions on your usage of this software. +# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive +# this file, see . +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +# details. +# +# You should have received a copy of the GNU Affero General Public License along with this program. If not, see +# . +# + +import os + +import django.conf.locale +from pycountry import currencies + +from django.utils.translation import gettext_lazy as _ # NOQA + +BASE_DIR = os.path.dirname(os.path.dirname(__file__)) + +USE_I18N = True +USE_L10N = True +USE_TZ = True + +INSTALLED_APPS = [ + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'django.contrib.humanize', + 'pretix.base', + 'pretix.control', + 'pretix.presale', + 'pretix.multidomain', + 'pretix.api', + 'pretix.helpers', + 'rest_framework', + 'djangoformsetjs', + 'compressor', + 'bootstrap3', + 'pretix.plugins.banktransfer', + 'pretix.plugins.stripe', + 'pretix.plugins.paypal', + 'pretix.plugins.paypal2', + 'pretix.plugins.ticketoutputpdf', + 'pretix.plugins.sendmail', + 'pretix.plugins.statistics', + 'pretix.plugins.reports', + 'pretix.plugins.checkinlists', + 'pretix.plugins.pretixdroid', + 'pretix.plugins.badges', + 'pretix.plugins.manualpayment', + 'pretix.plugins.returnurl', + 'pretix.plugins.webcheckin', + 'django_countries', + 'oauth2_provider', + 'phonenumber_field', + 'statici18n', +] + +FORMAT_MODULE_PATH = [ + 'pretix.helpers.formats', +] + +ALL_LANGUAGES = [ + ('en', _('English')), + ('de', _('German')), + ('de-informal', _('German (informal)')), + ('ar', _('Arabic')), + ('zh-hans', _('Chinese (simplified)')), + ('cs', _('Czech')), + ('da', _('Danish')), + ('nl', _('Dutch')), + ('nl-informal', _('Dutch (informal)')), + ('fr', _('French')), + ('fi', _('Finnish')), + ('gl', _('Galician')), + ('el', _('Greek')), + ('it', _('Italian')), + ('lv', _('Latvian')), + ('pl', _('Polish')), + ('pt-pt', _('Portuguese (Portugal)')), + ('pt-br', _('Portuguese (Brazil)')), + ('ro', _('Romanian')), + ('ru', _('Russian')), + ('es', _('Spanish')), + ('tr', _('Turkish')), + ('uk', _('Ukrainian')), +] +LANGUAGES_OFFICIAL = { + 'en', 'de', 'de-informal' +} +LANGUAGES_RTL = { + 'ar', 'hw' +} +LANGUAGES_INCUBATING = { + 'pl', 'fi', 'pt-br', 'gl', +} +LOCALE_PATHS = [ + os.path.join(os.path.dirname(__file__), 'locale'), +] + +EXTRA_LANG_INFO = { + 'de-informal': { + 'bidi': False, + 'code': 'de-informal', + 'name': 'German (informal)', + 'name_local': 'Deutsch', + 'public_code': 'de', + }, + 'nl-informal': { + 'bidi': False, + 'code': 'nl-informal', + 'name': 'Dutch (informal)', + 'name_local': 'Nederlands', + 'public_code': 'nl', + }, + 'fr': { + 'bidi': False, + 'code': 'fr', + 'name': 'French', + 'name_local': 'Français' + }, + 'lv': { + 'bidi': False, + 'code': 'lv', + 'name': 'Latvian', + 'name_local': 'Latviešu' + }, + 'pt-pt': { + 'bidi': False, + 'code': 'pt-pt', + 'name': 'Portuguese', + 'name_local': 'Português', + }, +} + +django.conf.locale.LANG_INFO.update(EXTRA_LANG_INFO) + +template_loaders = ( + 'django.template.loaders.filesystem.Loader', + 'pretix.helpers.template_loaders.AppLoader', +) + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [ + os.path.join(BASE_DIR, 'templates'), + ], + 'OPTIONS': { + 'context_processors': [ + 'django.contrib.auth.context_processors.auth', + 'django.template.context_processors.debug', + 'django.template.context_processors.i18n', + 'django.template.context_processors.media', + "django.template.context_processors.request", + 'django.template.context_processors.static', + 'django.template.context_processors.tz', + 'django.contrib.messages.context_processors.messages', + 'pretix.base.context.contextprocessor', + 'pretix.control.context.contextprocessor', + 'pretix.presale.context.contextprocessor', + ], + 'loaders': template_loaders + }, + }, +] + +STATIC_ROOT = os.path.join(os.path.dirname(__file__), 'static.dist') + +STATICFILES_FINDERS = ( + 'django.contrib.staticfiles.finders.FileSystemFinder', + 'django.contrib.staticfiles.finders.AppDirectoriesFinder', + 'compressor.finders.CompressorFinder', +) + +STATICFILES_DIRS = [ + os.path.join(BASE_DIR, 'pretix/static') +] if os.path.exists(os.path.join(BASE_DIR, 'pretix/static')) else [] + +STATICI18N_ROOT = os.path.join(BASE_DIR, "pretix/static") + +STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage' + +# if os.path.exists(os.path.join(DATA_DIR, 'static')): +# STATICFILES_DIRS.insert(0, os.path.join(DATA_DIR, 'static')) + +COMPRESS_PRECOMPILERS = ( + ('text/x-scss', 'django_libsass.SassCompiler'), + ('text/vue', 'pretix.helpers.compressor.VueCompiler'), +) + +COMPRESS_OFFLINE_CONTEXT = { + 'basetpl': 'empty.html', +} + +COMPRESS_ENABLED = True +COMPRESS_OFFLINE = True + +COMPRESS_FILTERS = { + 'css': ( + # CssAbsoluteFilter is incredibly slow, especially when dealing with our _flags.scss + # However, we don't need it if we consequently use the static() function in Sass + # 'compressor.filters.css_default.CssAbsoluteFilter', + 'compressor.filters.cssmin.rCSSMinFilter', + ), + 'js': ( + 'compressor.filters.jsmin.JSMinFilter', + ) +} + +CURRENCIES = list(currencies) +CURRENCY_PLACES = { + # default is 2 + 'BIF': 0, + 'CLP': 0, + 'DJF': 0, + 'GNF': 0, + 'JPY': 0, + 'KMF': 0, + 'KRW': 0, + 'MGA': 0, + 'PYG': 0, + 'RWF': 0, + 'VND': 0, + 'VUV': 0, + 'XAF': 0, + 'XOF': 0, + 'XPF': 0, +} + +PRETIX_EMAIL_NONE_VALUE = 'none@well-known.pretix.eu' +PRETIX_PRIMARY_COLOR = '#8E44B3' + +# pretix includes caching options for some special situations where full HTML responses are cached. This might be +# stressful for some cache setups so it is enabled by default and currently can't be enabled through pretix.cfg +CACHE_LARGE_VALUES_ALLOWED = False +CACHE_LARGE_VALUES_ALIAS = 'default' diff --git a/src/pretix/_build.py b/src/pretix/_build.py new file mode 100644 index 0000000000..f64f0f0c99 --- /dev/null +++ b/src/pretix/_build.py @@ -0,0 +1,74 @@ +# +# This file is part of pretix (Community Edition). +# +# Copyright (C) 2014-2020 Raphael Michel and contributors +# Copyright (C) 2020-2021 rami.io GmbH and contributors +# +# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General +# Public License as published by the Free Software Foundation in version 3 of the License. +# +# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are +# applicable granting you additional permissions and placing additional restrictions on your usage of this software. +# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive +# this file, see . +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +# details. +# +# You should have received a copy of the GNU Affero General Public License along with this program. If not, see +# . +# + +import os +import shutil +import subprocess + +from setuptools.command.build import build +from setuptools.command.build_ext import build_ext + +here = os.path.abspath(os.path.dirname(__file__)) +npm_installed = False + + +def npm_install(): + global npm_installed + + if not npm_installed: + # keep this in sync with Makefile! + node_prefix = os.path.join(here, 'static.dist', 'node_prefix') + os.makedirs(node_prefix, exist_ok=True) + shutil.copytree(os.path.join(here, 'static', 'npm_dir'), node_prefix, dirs_exist_ok=True) + subprocess.check_call('npm install', shell=True, cwd=node_prefix) + npm_installed = True + + +class CustomBuild(build): + def run(self): + if "PRETIX_DOCKER_BUILD" in os.environ: + return # this is a hack to allow calling this file early in our docker build to make use of caching + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pretix._build_settings") + os.environ.setdefault("PRETIX_IGNORE_CONFLICTS", "True") + import django + django.setup() + from django.conf import settings + from django.core import management + + settings.COMPRESS_ENABLED = True + settings.COMPRESS_OFFLINE = True + + npm_install() + management.call_command('compilemessages', verbosity=1) + management.call_command('compilejsi18n', verbosity=1) + management.call_command('collectstatic', verbosity=1, interactive=False) + management.call_command('compress', verbosity=1) + + build.run(self) + + +class CustomBuildExt(build_ext): + def run(self): + if "PRETIX_DOCKER_BUILD" in os.environ: + return # this is a hack to allow calling this file early in our docker build to make use of caching + npm_install() + build_ext.run(self) diff --git a/src/pretix/_build_settings.py b/src/pretix/_build_settings.py new file mode 100644 index 0000000000..54d839da2d --- /dev/null +++ b/src/pretix/_build_settings.py @@ -0,0 +1,48 @@ +# +# This file is part of pretix (Community Edition). +# +# Copyright (C) 2014-2020 Raphael Michel and contributors +# Copyright (C) 2020-2021 rami.io GmbH and contributors +# +# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General +# Public License as published by the Free Software Foundation in version 3 of the License. +# +# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are +# applicable granting you additional permissions and placing additional restrictions on your usage of this software. +# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive +# this file, see . +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +# details. +# +# You should have received a copy of the GNU Affero General Public License along with this program. If not, see +# . +# + +""" +This file contains settings that we need at wheel require time. All settings that we only need at runtime are set +in settings.py. +""" +from ._base_settings import * # NOQA + +ENTROPY = { + 'order_code': 5, + 'customer_identifier': 7, + 'ticket_secret': 32, + 'voucher_code': 16, + 'giftcard_secret': 12, +} + +MAIL_FROM_ORGANIZERS = 'invalid@invalid' +FILE_UPLOAD_MAX_SIZE_EMAIL_AUTO_ATTACHMENT = 10 +FILE_UPLOAD_MAX_SIZE_EMAIL_ATTACHMENT = 10 +FILE_UPLOAD_MAX_SIZE_IMAGE = 10 +DEFAULT_CURRENCY = 'EUR' +SECRET_KEY = "build-time-secret-key" +HAS_REDIS = False +STATIC_URL = '/static/' +HAS_MEMCACHED = False +HAS_CELERY = False +HAS_GEOIP = False +SENTRY_ENABLED = False diff --git a/src/pretix/base/management/commands/shell_scoped.py b/src/pretix/base/management/commands/shell_scoped.py index b0f472e75a..4029fa081e 100644 --- a/src/pretix/base/management/commands/shell_scoped.py +++ b/src/pretix/base/management/commands/shell_scoped.py @@ -49,6 +49,7 @@ class Command(BaseCommand): except ImportError: cmd = 'shell' del options['skip_checks'] + del options['print_sql'] if options['print_sql']: connection.force_debug_cursor = True diff --git a/src/pretix/helpers/logs.py b/src/pretix/helpers/logs.py index e1e322322f..175b34250a 100644 --- a/src/pretix/helpers/logs.py +++ b/src/pretix/helpers/logs.py @@ -21,7 +21,6 @@ # import logging -import sentry_sdk from django.core.signals import request_finished from django.dispatch import receiver @@ -56,6 +55,7 @@ class RequestIdMiddleware: local.request_id = request.request_id = request.headers[settings.REQUEST_ID_HEADER] if settings.SENTRY_ENABLED: + import sentry_sdk sentry_sdk.set_tag("request_id", request.request_id) else: local.request_id = request.request_id = None diff --git a/src/pretix/settings.py b/src/pretix/settings.py index bd907e697c..63939e2d4e 100644 --- a/src/pretix/settings.py +++ b/src/pretix/settings.py @@ -37,18 +37,19 @@ import configparser import logging import os import sys -from urllib.parse import urlparse from json import loads +from urllib.parse import urlparse -import django.conf.locale import importlib_metadata as metadata from django.utils.crypto import get_random_string from kombu import Queue -from pycountry import currencies from . import __version__ from .helpers.config import EnvOrParserConfig +# Pull in all settings that we also need at wheel require time +from ._base_settings import * # NOQA + from django.contrib.messages import constants as messages # NOQA from django.utils.translation import gettext_lazy as _ # NOQA @@ -62,7 +63,6 @@ else: config = EnvOrParserConfig(_config) CONFIG_FILE = config -BASE_DIR = os.path.dirname(os.path.dirname(__file__)) DATA_DIR = config.get('pretix', 'datadir', fallback=os.environ.get('DATA_DIR', 'data')) LOG_DIR = os.path.join(DATA_DIR, 'logs') MEDIA_ROOT = os.path.join(DATA_DIR, 'media') @@ -169,7 +169,6 @@ PRETIX_ADMIN_AUDIT_COMMENTS = config.getboolean('pretix', 'audit_comments', fall PRETIX_OBLIGATORY_2FA = config.getboolean('pretix', 'obligatory_2fa', fallback=False) PRETIX_SESSION_TIMEOUT_RELATIVE = 3600 * 3 PRETIX_SESSION_TIMEOUT_ABSOLUTE = 3600 * 12 -PRETIX_PRIMARY_COLOR = '#8E44B3' SITE_URL = config.get('pretix', 'url', fallback='http://localhost:8000') if SITE_URL.endswith('/'): @@ -194,25 +193,6 @@ PRETIX_PLUGINS_SHOW_META = config.getboolean('pretix', 'plugins_show_meta', fall FETCH_ECB_RATES = config.getboolean('pretix', 'ecb_rates', fallback=True) DEFAULT_CURRENCY = config.get('pretix', 'currency', fallback='EUR') -CURRENCIES = list(currencies) -CURRENCY_PLACES = { - # default is 2 - 'BIF': 0, - 'CLP': 0, - 'DJF': 0, - 'GNF': 0, - 'JPY': 0, - 'KMF': 0, - 'KRW': 0, - 'MGA': 0, - 'PYG': 0, - 'RWF': 0, - 'VND': 0, - 'VUV': 0, - 'XAF': 0, - 'XOF': 0, - 'XPF': 0, -} ALLOWED_HOSTS = ['*'] @@ -248,11 +228,6 @@ CACHES = { REAL_CACHE_USED = False SESSION_ENGINE = None -# pretix includes caching options for some special situations where full HTML responses are cached. This might be -# stressful for some cache setups so it is enabled by default and currently can't be enabled through pretix.cfg -CACHE_LARGE_VALUES_ALLOWED = False -CACHE_LARGE_VALUES_ALIAS = 'default' - HAS_MEMCACHED = config.has_option('memcached', 'location') if HAS_MEMCACHED: REAL_CACHE_USED = True @@ -337,57 +312,19 @@ if config.has_option('geoip', 'path'): GEOIP_COUNTRY = config.get('geoip', 'filename_country', fallback='GeoLite2-Country.mmdb') # Internal settings -PRETIX_EMAIL_NONE_VALUE = 'none@well-known.pretix.eu' - -STATIC_ROOT = os.path.join(os.path.dirname(__file__), 'static.dist') - SESSION_COOKIE_NAME = 'pretix_session' LANGUAGE_COOKIE_NAME = 'pretix_language' CSRF_COOKIE_NAME = 'pretix_csrftoken' SESSION_COOKIE_HTTPONLY = True -INSTALLED_APPS = [ - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - 'django.contrib.humanize', - 'pretix.base', - 'pretix.control', - 'pretix.presale', - 'pretix.multidomain', - 'pretix.api', - 'pretix.helpers', - 'rest_framework', +INSTALLED_APPS += [ # noqa 'django_filters', - 'compressor', - 'bootstrap3', - 'djangoformsetjs', - 'pretix.plugins.banktransfer', - 'pretix.plugins.stripe', - 'pretix.plugins.paypal', - 'pretix.plugins.paypal2', - 'pretix.plugins.ticketoutputpdf', - 'pretix.plugins.sendmail', - 'pretix.plugins.statistics', - 'pretix.plugins.reports', - 'pretix.plugins.checkinlists', - 'pretix.plugins.pretixdroid', - 'pretix.plugins.badges', - 'pretix.plugins.manualpayment', - 'pretix.plugins.returnurl', - 'pretix.plugins.webcheckin', 'django_markup', 'django_otp', 'django_otp.plugins.otp_totp', 'django_otp.plugins.otp_static', - 'statici18n', - 'django_countries', 'hijack', - 'oauth2_provider', 'localflavor', - 'phonenumber_field' ] if db_backend == 'postgresql': @@ -504,57 +441,13 @@ ROOT_URLCONF = 'pretix.multidomain.maindomain_urlconf' WSGI_APPLICATION = 'pretix.wsgi.application' -USE_I18N = True -USE_L10N = True -USE_TZ = True - -LOCALE_PATHS = [ - os.path.join(os.path.dirname(__file__), 'locale'), -] if config.has_option('languages', 'path'): - LOCALE_PATHS.insert(0, config.get('languages', 'path')) + LOCALE_PATHS.insert(0, config.get('languages', 'path')) # noqa -FORMAT_MODULE_PATH = [ - 'pretix.helpers.formats', -] - -ALL_LANGUAGES = [ - ('en', _('English')), - ('de', _('German')), - ('de-informal', _('German (informal)')), - ('ar', _('Arabic')), - ('zh-hans', _('Chinese (simplified)')), - ('cs', _('Czech')), - ('da', _('Danish')), - ('nl', _('Dutch')), - ('nl-informal', _('Dutch (informal)')), - ('fr', _('French')), - ('fi', _('Finnish')), - ('gl', _('Galician')), - ('el', _('Greek')), - ('it', _('Italian')), - ('lv', _('Latvian')), - ('pl', _('Polish')), - ('pt-pt', _('Portuguese (Portugal)')), - ('pt-br', _('Portuguese (Brazil)')), - ('ro', _('Romanian')), - ('ru', _('Russian')), - ('es', _('Spanish')), - ('tr', _('Turkish')), - ('uk', _('Ukrainian')), -] -LANGUAGES_OFFICIAL = { - 'en', 'de', 'de-informal' -} -LANGUAGES_INCUBATING = { - 'pl', 'fi', 'pt-br', 'gl', -} - set(config.get('languages', 'allow_incubating', fallback='').split(',')) -LANGUAGES_RTL = { - 'ar', 'hw' -} +LANGUAGES_INCUBATING = LANGUAGES_INCUBATING - set(config.get('languages', 'allow_incubating', fallback='').split(',')) # noqa LANGUAGES = [] LANGUAGES_ENABLED = [lang for lang in config.get("languages", "enabled", fallback='').split(',') if lang] -for k, v in ALL_LANGUAGES: +for k, v in ALL_LANGUAGES: # noqa if not DEBUG and k in LANGUAGES_INCUBATING: continue if LANGUAGES_ENABLED and k not in LANGUAGES_ENABLED: @@ -562,44 +455,6 @@ for k, v in ALL_LANGUAGES: LANGUAGES.append((k, v)) -EXTRA_LANG_INFO = { - 'de-informal': { - 'bidi': False, - 'code': 'de-informal', - 'name': 'German (informal)', - 'name_local': 'Deutsch', - 'public_code': 'de', - }, - 'nl-informal': { - 'bidi': False, - 'code': 'nl-informal', - 'name': 'Dutch (informal)', - 'name_local': 'Nederlands', - 'public_code': 'nl', - }, - 'fr': { - 'bidi': False, - 'code': 'fr', - 'name': 'French', - 'name_local': 'Français' - }, - 'lv': { - 'bidi': False, - 'code': 'lv', - 'name': 'Latvian', - 'name_local': 'Latviešu' - }, - 'pt-pt': { - 'bidi': False, - 'code': 'pt-pt', - 'name': 'Portuguese', - 'name_local': 'Português', - }, -} - -django.conf.locale.LANG_INFO.update(EXTRA_LANG_INFO) - - AUTH_USER_MODEL = 'pretixbase.User' LOGIN_URL = 'control:auth.login' LOGIN_URL_CONTROL = 'control:auth.login' @@ -610,75 +465,10 @@ template_loaders = ( 'pretix.helpers.template_loaders.AppLoader', ) if not DEBUG: - template_loaders = ( + TEMPLATES[0]['OPTIONS']['loaders'] = ( # noqa ('django.template.loaders.cached.Loader', template_loaders), ) - -TEMPLATES = [ - { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [ - os.path.join(DATA_DIR, 'templates'), - os.path.join(BASE_DIR, 'templates'), - ], - 'OPTIONS': { - 'context_processors': [ - 'django.contrib.auth.context_processors.auth', - 'django.template.context_processors.debug', - 'django.template.context_processors.i18n', - 'django.template.context_processors.media', - "django.template.context_processors.request", - 'django.template.context_processors.static', - 'django.template.context_processors.tz', - 'django.contrib.messages.context_processors.messages', - 'pretix.base.context.contextprocessor', - 'pretix.control.context.contextprocessor', - 'pretix.presale.context.contextprocessor', - ], - 'loaders': template_loaders - }, - }, -] - -STATICFILES_FINDERS = ( - 'django.contrib.staticfiles.finders.FileSystemFinder', - 'django.contrib.staticfiles.finders.AppDirectoriesFinder', - 'compressor.finders.CompressorFinder', -) - -STATICFILES_DIRS = [ - os.path.join(BASE_DIR, 'pretix/static') -] if os.path.exists(os.path.join(BASE_DIR, 'pretix/static')) else [] - -STATICI18N_ROOT = os.path.join(BASE_DIR, "pretix/static") - -STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage' - -# if os.path.exists(os.path.join(DATA_DIR, 'static')): -# STATICFILES_DIRS.insert(0, os.path.join(DATA_DIR, 'static')) - -COMPRESS_PRECOMPILERS = ( - ('text/x-scss', 'django_libsass.SassCompiler'), - ('text/vue', 'pretix.helpers.compressor.VueCompiler'), -) - -COMPRESS_OFFLINE_CONTEXT = { - 'basetpl': 'empty.html', -} - -COMPRESS_ENABLED = COMPRESS_OFFLINE = not debug_fallback - -COMPRESS_FILTERS = { - 'css': ( - # CssAbsoluteFilter is incredibly slow, especially when dealing with our _flags.scss - # However, we don't need it if we consequently use the static() function in Sass - # 'compressor.filters.css_default.CssAbsoluteFilter', - 'compressor.filters.cssmin.rCSSMinFilter', - ), - 'js': ( - 'compressor.filters.jsmin.JSMinFilter', - ) -} +TEMPLATES[0]['DIRS'].insert(0, os.path.join(DATA_DIR, 'templates')) # noqa INTERNAL_IPS = ('127.0.0.1', '::1') @@ -692,6 +482,8 @@ MESSAGE_STORAGE = 'django.contrib.messages.storage.session.SessionStorage' loglevel = 'DEBUG' if DEBUG else config.get('pretix', 'loglevel', fallback='INFO') +COMPRESS_ENABLED = COMPRESS_OFFLINE = not debug_fallback + LOGGING = { 'version': 1, 'disable_existing_loggers': False, diff --git a/src/setup.py b/src/setup.py deleted file mode 100644 index 4ac14716ee..0000000000 --- a/src/setup.py +++ /dev/null @@ -1,270 +0,0 @@ -# -# This file is part of pretix (Community Edition). -# -# Copyright (C) 2014-2020 Raphael Michel and contributors -# Copyright (C) 2020-2021 rami.io GmbH and contributors -# -# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General -# Public License as published by the Free Software Foundation in version 3 of the License. -# -# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are -# applicable granting you additional permissions and placing additional restrictions on your usage of this software. -# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive -# this file, see . -# -# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied -# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more -# details. -# -# You should have received a copy of the GNU Affero General Public License along with this program. If not, see -# . -# - -# This file is based on an earlier version of pretix which was released under the Apache License 2.0. The full text of -# the Apache License 2.0 can be obtained at . -# -# This file may have since been changed and any changes are released under the terms of AGPLv3 as described above. A -# full history of changes and contributors is available at . -# -# This file contains Apache-licensed contributions copyrighted by: Claudio Luck, FlaviaBastos, Katharina Bogad, Laura -# Klünder, Lukas Bockstaller, Matthew Emerson, Tobias Kunze, jasonwaiting@live.hk -# -# Unless required by applicable law or agreed to in writing, software distributed under the Apache License 2.0 is -# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations under the License. - -import os -import subprocess -import sys -from codecs import open -from distutils.command.build import build -from distutils.command.build_ext import build_ext -from distutils.dir_util import copy_tree -from os import path - -from setuptools import find_packages, setup - -try: - from pretix import __version__ -except: - if "PRETIX_DOCKER_BUILD" in os.environ: - __version__ = "0.0.0" # this is a hack to allow calling this file early in our docker build to make use of caching - else: - raise - -CURRENT_PYTHON = sys.version_info[:2] -REQUIRED_PYTHON = (3, 9) -if CURRENT_PYTHON < REQUIRED_PYTHON: - sys.stderr.write(""" -========================== -Unsupported Python version -========================== -This version of pretix requires Python {}.{}, but you're trying to -install it on Python {}.{}. -This may be because you are using a version of pip that doesn't -understand the python_requires classifier. Make sure you -have pip >= 9.0 and setuptools >= 24.2, then try again: - $ python -m pip install --upgrade pip setuptools - $ python -m pip install pretix -This will install the latest version of pretix which works on your -version of Python. If you can't upgrade your pip (or Python), request -an older version of pretix: - $ python -m pip install "pretix<2" -""".format(*(REQUIRED_PYTHON + CURRENT_PYTHON))) - sys.exit(1) - -here = path.abspath(path.dirname(__file__)) -npm_installed = False - -# Get the long description from the relevant file -try: - with open(path.join(here, '../README.rst'), encoding='utf-8') as f: - long_description = f.read() -except: - long_description = '' - - -def npm_install(): - global npm_installed - - if not npm_installed: - # keep this in sync with Makefile! - node_prefix = os.path.join(here, 'pretix', 'static.dist', 'node_prefix') - os.makedirs(node_prefix, exist_ok=True) - copy_tree(os.path.join(here, 'pretix', 'static', 'npm_dir'), node_prefix) - subprocess.check_call('npm install', shell=True, cwd=node_prefix) - npm_installed = True - - -class CustomBuild(build): - def run(self): - if "PRETIX_DOCKER_BUILD" in os.environ: - return # this is a hack to allow calling this file early in our docker build to make use of caching - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pretix.settings") - os.environ.setdefault("PRETIX_IGNORE_CONFLICTS", "True") - import django - django.setup() - from django.conf import settings - from django.core import management - - settings.COMPRESS_ENABLED = True - settings.COMPRESS_OFFLINE = True - - npm_install() - management.call_command('compilemessages', verbosity=1) - management.call_command('compilejsi18n', verbosity=1) - management.call_command('collectstatic', verbosity=1, interactive=False) - management.call_command('compress', verbosity=1) - - build.run(self) - - -class CustomBuildExt(build_ext): - def run(self): - if "PRETIX_DOCKER_BUILD" in os.environ: - return # this is a hack to allow calling this file early in our docker build to make use of caching - npm_install() - build_ext.run(self) - - -cmdclass = { - 'build': CustomBuild, - 'build_ext': CustomBuildExt, -} - - -setup( - name='pretix', - version=__version__, - python_requires='>={}.{}'.format(*REQUIRED_PYTHON), - description='Reinventing presales, one ticket at a time', - long_description=long_description, - url='https://pretix.eu', - author='Raphael Michel', - author_email='support@pretix.eu', - license='GNU Affero General Public License v3 with Additional Terms', - classifiers=[ - 'Development Status :: 5 - Production/Stable', - 'Intended Audience :: Developers', - 'Intended Audience :: Other Audience', - 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', - 'Environment :: Web Environment', - 'License :: OSI Approved :: GNU Affero General Public License v3', - 'Programming Language :: Python :: 3.9', - 'Programming Language :: Python :: 3.10', - 'Programming Language :: Python :: 3.11', - 'Framework :: Django :: 3.2' - ], - - keywords='tickets web shop ecommerce', - install_requires=[ - 'arabic-reshaper==3.0.0', # Support for Arabic in reportlab - 'babel', - 'BeautifulSoup4==4.12.*', - 'bleach==5.0.*', - 'celery==5.2.*', - 'chardet==5.1.*', - 'cryptography>=3.4.2', - 'css-inline==0.8.*', - 'defusedcsv>=1.1.0', - 'dj-static', - 'Django==3.2.*,>=3.2.18', - 'django-bootstrap3==23.1.*', - 'django-compressor==4.3.*', - 'django-countries==7.5.*', - 'django-filter==23.1', - 'django-formset-js-improved==0.5.0.3', - 'django-formtools==2.4', - 'django-hierarkey==1.1.*', - 'django-hijack==3.3.*', - 'django-i18nfield==1.9.*,>=1.9.4', - 'django-libsass==0.9', - 'django-localflavor==3.1', - 'django-markup', - 'django-mysql', - 'django-oauth-toolkit==2.2.*', - 'django-otp==1.1.*', - 'django-phonenumber-field==7.0.*', - 'django-redis==5.2.*', - 'django-scopes==1.2.*', - 'django-statici18n==2.3.*', - 'djangorestframework==3.14.*', - 'dnspython==2.2.*', - 'drf_ujson2==1.7.*', - 'geoip2==4.*', - 'importlib-metadata==6.5.*', # Polyfill, we can probably drop this once we require Python 3.10+ - 'isoweek', - 'jsonschema', - 'kombu==5.2.*', - 'libsass==0.22.*', - 'lxml', - 'markdown==3.3.4', # 3.3.5 requires importlib-metadata>=4.4, but django-bootstrap3 requires importlib-metadata<3. - # We can upgrade markdown again once django-bootstrap3 upgrades or once we drop Python 3.6 and 3.7 - 'mt-940==4.23.*', - 'oauthlib==3.2.*', - 'openpyxl==3.1.*', - 'packaging', - 'paypalrestsdk==1.13.*', - 'paypal-checkout-serversdk==1.0.*', - 'PyJWT==2.6.*', - 'phonenumberslite==8.13.*', - 'Pillow==9.5.*', - 'protobuf==4.22.*', - 'psycopg2-binary', - 'pycountry', - 'pycparser==2.21', - 'pycryptodome==3.17.*', - 'pypdf==3.8.*', - 'python-bidi==0.4.*', # Support for Arabic in reportlab - 'python-dateutil==2.8.*', - 'python-u2flib-server==4.*', - 'pytz', - 'pyuca', - 'qrcode==7.4.*', - 'redis==4.5.*,>=4.5.4', - 'reportlab==3.6.*', - 'requests==2.28.*', - 'sentry-sdk==1.15.*', - 'sepaxml==2.6.*', - 'slimit', - 'static3==0.7.*', - 'stripe==5.4.*', - 'text-unidecode==1.*', - 'tlds>=2020041600', - 'tqdm==4.*', - 'vat_moss_forked==2020.3.20.0.11.0', - 'vobject==0.9.*', - 'webauthn==0.4.*', - 'zeep==4.2.*' - ], - extras_require={ - 'dev': [ - 'coverage', - 'coveralls', - 'django-debug-toolbar==4.0.*', - 'flake8==6.0.*', - 'freezegun', - 'isort==5.12.*', - 'pep8-naming==0.12.*', - 'potypo', - 'pycodestyle==2.10.*', - 'pyflakes==3.0.*', - 'pytest-cache', - 'pytest-cov', - 'pytest-django==4.*', - 'pytest-mock==3.10.*', - 'pytest-rerunfailures==11.*', - 'pytest-sugar', - 'pytest-xdist==3.2.*', - 'pytest==7.3.*', - 'responses', - ], - 'memcached': ['pylibmc'], - 'mysql': ['mysqlclient'], - }, - setup_requires=['setuptools-rust'], - - packages=find_packages(exclude=['tests', 'tests.*']), - include_package_data=True, - cmdclass=cmdclass, -)