From 3b3f5db60dbc85823ca3eff102adca54a60643d3 Mon Sep 17 00:00:00 2001 From: Tim Gates Date: Thu, 12 Mar 2020 06:40:15 +1100 Subject: [PATCH 01/41] docs: Fix simple typo, wheter -> whether There is a small typo in docs/values.rst. Should read `whether` rather than `wheter`. --- docs/values.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/values.rst b/docs/values.rst index 5f5dcea..8f11ae4 100644 --- a/docs/values.rst +++ b/docs/values.rst @@ -162,7 +162,7 @@ the prefix. :param environ: toggle for environment use :param environ_name: name of environment variable to look for :param environ_prefix: prefix to use when looking for environment variable - :param environ_required: wheter or not the value is required to be set as an environment variable + :param environ_required: whether or not the value is required to be set as an environment variable :type environ: bool :type environ_name: capitalized string or None :type environ_prefix: capitalized string From 566af30ce69a627bff8dab872e5698c3f6833e4d Mon Sep 17 00:00:00 2001 From: Baptiste Mispelon Date: Fri, 29 May 2020 12:15:08 +0200 Subject: [PATCH 02/41] Fixed malformed links in documentation --- docs/cookbook.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/cookbook.rst b/docs/cookbook.rst index bb5f048..9184172 100644 --- a/docs/cookbook.rst +++ b/docs/cookbook.rst @@ -332,8 +332,8 @@ Channels -------- If you want to deploy a project that uses the Django channels with -`Daphne ` as the -`interface server ` +`Daphne `_ as the +`interface server `_ you have to use a asgi.py script similar to the following: .. code-block:: python From b9648bddb305c00b3b6391465460bde1b82e5f73 Mon Sep 17 00:00:00 2001 From: Arseny Sokolov Date: Wed, 17 Jun 2020 23:38:48 +0800 Subject: [PATCH 03/41] Add DictValue example --- docs/values.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/values.rst b/docs/values.rst index 5f5dcea..6af72ea 100644 --- a/docs/values.rst +++ b/docs/values.rst @@ -353,6 +353,10 @@ Type values DEPARTMENTS = values.DictValue({ 'it': ['Mike', 'Joe'], }) + + Override using environment variables like this:: + + DJANGO_DEPARTMENTS={'it':['Mike','Joe'],'hr':['Emma','Olivia']} Validator values ^^^^^^^^^^^^^^^^ From 4fb5928a9cb21277c44f515f5df3fc576b6d9e2b Mon Sep 17 00:00:00 2001 From: Nicholas Dujay Date: Mon, 21 Sep 2020 09:43:42 -0400 Subject: [PATCH 04/41] use package name in get_distribution function call --- configurations/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configurations/version.py b/configurations/version.py index 10f8675..137cb24 100644 --- a/configurations/version.py +++ b/configurations/version.py @@ -1,7 +1,7 @@ from pkg_resources import get_distribution, DistributionNotFound try: - __version__ = get_distribution(__name__).version + __version__ = get_distribution("django-configurations").version except DistributionNotFound: # package is not installed __version__ = None From b540ceadb3a44acc5dc0b1827653480288550e3d Mon Sep 17 00:00:00 2001 From: Jannis Leidel Date: Thu, 26 Nov 2020 16:18:58 +0100 Subject: [PATCH 05/41] Add GitHub Actions test workflow. --- .github/workflows/test.yml | 48 ++++++++++++++++++++++++++++++++++++++ tox.ini | 2 +- 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..801122e --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,48 @@ +name: Test + +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + strategy: + fail-fast: false + max-parallel: 5 + matrix: + python-version: ['2.7', '3.5', '3.6', '3.7', '3.8', 'pypy3'] + + steps: + - uses: actions/checkout@v2 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + + - name: Get pip cache dir + id: pip-cache + run: | + echo "::set-output name=dir::$(pip cache dir)" + + - name: Cache + uses: actions/cache@v2 + with: + path: ${{ steps.pip-cache.outputs.dir }} + key: + ${{ matrix.python-version }}-v1-${{ hashFiles('**/setup.py') }} + restore-keys: | + ${{ matrix.python-version }}-v1- + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install --upgrade tox tox-gh-actions + + - name: Tox tests + run: | + tox -v + + - name: Upload coverage + uses: codecov/codecov-action@v1 + with: + name: Python ${{ matrix.python-version }} diff --git a/tox.ini b/tox.ini index e1df12f..bd2f94d 100644 --- a/tox.ini +++ b/tox.ini @@ -11,7 +11,7 @@ envlist = py{35,36,37,38,py3}-dj22 py{36,37,38,py3}-dj{30,master} -[travis] +[gh-actions] python = 2.7: py27 3.5: py35 From 64eefaef1ac493884e36a6b7fb527444275a1617 Mon Sep 17 00:00:00 2001 From: Jannis Leidel Date: Thu, 26 Nov 2020 16:51:15 +0100 Subject: [PATCH 06/41] Fix an issue with an old version of dj-email-url. --- tox.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/tox.ini b/tox.ini index bd2f94d..15eb0cc 100644 --- a/tox.ini +++ b/tox.ini @@ -28,6 +28,7 @@ setenv = COVERAGE_PROCESS_START = {toxinidir}/setup.cfg deps = dj111: django>=1.11,<2.0 + dj111: dj-email-url<1.0.0 dj20: django>=2.0a1,<2.1 dj21: django>=2.1a1,<2.2 dj22: django>=2.2a1,<3.0 From eea5b9ad34011e4e4a72ba6b6865f0f9bdc76295 Mon Sep 17 00:00:00 2001 From: Jannis Leidel Date: Thu, 26 Nov 2020 17:08:14 +0100 Subject: [PATCH 07/41] Remove travis cruft. --- .travis.yml | 37 ------------------------------------- MANIFEST.in | 1 - README.rst | 6 +++--- 3 files changed, 3 insertions(+), 41 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 150373b..0000000 --- a/.travis.yml +++ /dev/null @@ -1,37 +0,0 @@ -language: python -dist: xenial -cache: pip -python: -- '2.7' -- '3.5' -- '3.6' -- '3.7' -- '3.8' -- 'pypy3' -install: travis_retry pip install tox-travis codecov -script: tox -v -after_success: codecov --required -X gcov fix pycov -f coverage.xml --flags ${TOXENV//-/ } -branches: - except: templates/1.5.x templates/1.6.x -stages: -- test -- name: deploy - if: repo = jazzband/django-configurations AND tag IS present -jobs: - include: - - stage: test - - stage: deploy - install: skip - script: skip - python: 3.7 - env: skip - deploy: - provider: pypi - user: jazzband - server: https://jazzband.co/projects/django-configurations/upload - distributions: sdist bdist_wheel - password: - secure: LuserSjUTGSsls9zrvck/FbfL+gFpNU/ywOQ/67ufEbbpGCeDBEgxDzgb0acfHNk8wlAkaPvaAejQBFtcUulhdNT/g0NsmaEAjd6HhCGM+FRJAnYFaj33Js6C+N2tX5wznL7uCBxqgtaaH0hf6ucqC8OXqwoCVGgdxAEnUlC/fY= - on: - tags: true - repo: jazzband/django-configurations diff --git a/MANIFEST.in b/MANIFEST.in index 89a0335..4f06150 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,7 +1,6 @@ include README.rst include CONTRIBUTING.md include AUTHORS -include .travis.yml include tox.ini recursive-include tests * recursive-include docs * diff --git a/README.rst b/README.rst index 545ae17..536b154 100644 --- a/README.rst +++ b/README.rst @@ -13,9 +13,9 @@ Check out the `documentation`_ for more complete examples. .. |latest-version| image:: https://img.shields.io/pypi/v/django-configurations.svg :alt: Latest version on PyPI :target: https://pypi.python.org/pypi/django-configurations -.. |build-status| image:: https://img.shields.io/travis/jazzband/django-configurations/master.svg - :alt: Build status - :target: https://travis-ci.org/jazzband/django-configurations +.. |build-status| image:: https://github.com/jazzband/django-configurations/workflows/Test/badge.svg + :target: https://github.com/jazzband/django-configurations/actions + :alt: GitHub Actions .. |codecov| image:: https://codecov.io/github/jazzband/django-configurations/coverage.svg?branch=master :alt: Codecov :target: https://codecov.io/github/jazzband/django-configurations?branch=master From 5053da43579bc1cc7af4ad3a910a675fd591d273 Mon Sep 17 00:00:00 2001 From: Jannis Leidel Date: Thu, 26 Nov 2020 17:08:22 +0100 Subject: [PATCH 08/41] Add release workflow. --- .github/workflows/release.yml | 53 +++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..707641d --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,53 @@ +name: Release + +on: + push: + tags: + - '*' + +jobs: + build: + if: github.repository == 'jazzband/django-configurations' + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: 3.8 + + - name: Get pip cache dir + id: pip-cache + run: | + echo "::set-output name=dir::$(pip cache dir)" + + - name: Cache + uses: actions/cache@v2 + with: + path: ${{ steps.pip-cache.outputs.dir }} + key: release-${{ hashFiles('**/setup.py') }} + restore-keys: | + release- + + - name: Install dependencies + run: | + python -m pip install -U pip + python -m pip install -U setuptools twine wheel + + - name: Build package + run: | + python setup.py --version + python setup.py sdist --format=gztar bdist_wheel + twine check dist/* + + - name: Upload packages to Jazzband + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') + uses: pypa/gh-action-pypi-publish@master + with: + user: jazzband + password: ${{ secrets.JAZZBAND_RELEASE_KEY }} + repository_url: https://jazzband.co/projects/django-configurations/upload From f5bebd4eccce5d48c3908480cd72a4ae3bbbdf6f Mon Sep 17 00:00:00 2001 From: Jannis Leidel Date: Fri, 27 Nov 2020 09:59:12 +0100 Subject: [PATCH 09/41] Add fail_ci_if_error to test workflow. --- .github/workflows/test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 801122e..792baf8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -46,3 +46,4 @@ jobs: uses: codecov/codecov-action@v1 with: name: Python ${{ matrix.python-version }} + fail_ci_if_error: true From dd5d6974cb9a646cf898ad36ba001b07b2199da1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20K=C3=A4ufl?= Date: Mon, 18 Jan 2021 10:23:23 +0100 Subject: [PATCH 10/41] Drop support for Django < 2.2 LTS, incl. Python 2.7 --- .github/workflows/test.yml | 2 +- configurations/importer.py | 14 ++++---------- docs/changes.rst | 7 +++++++ docs/conf.py | 2 +- setup.cfg | 3 --- setup.py | 4 ---- tox.ini | 13 ++----------- 7 files changed, 15 insertions(+), 30 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 792baf8..7df5943 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -9,7 +9,7 @@ jobs: fail-fast: false max-parallel: 5 matrix: - python-version: ['2.7', '3.5', '3.6', '3.7', '3.8', 'pypy3'] + python-version: ['3.5', '3.6', '3.7', '3.8', 'pypy3'] steps: - uses: actions/checkout@v2 diff --git a/configurations/importer.py b/configurations/importer.py index 4997380..353b589 100644 --- a/configurations/importer.py +++ b/configurations/importer.py @@ -82,16 +82,10 @@ class ConfigurationImporter(object): return os.environ.get(self.namevar) def check_options(self): - try: - parser = base.CommandParser( - usage="%(prog)s subcommand [options] [args]", - add_help=False) - except TypeError: - # Django before 2.1 used a `cmd` argument. - parser = base.CommandParser( - None, - usage="%(prog)s subcommand [options] [args]", - add_help=False) + parser = base.CommandParser( + usage="%(prog)s subcommand [options] [args]", + add_help=False, + ) parser.add_argument('--settings') parser.add_argument('--pythonpath') parser.add_argument(CONFIGURATION_ARGUMENT, diff --git a/docs/changes.rst b/docs/changes.rst index 2c983e3..655250e 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -3,6 +3,13 @@ Changelog --------- +unreleased +^^^^^^^^^^ + +- **BACKWARD INCOMPATIBLE** Drop support for Python 2.7. + +- **BACKWARD INCOMPATIBLE** Drop support for Django < 2.2. + v2.2 (2019-12-03) ^^^^^^^^^^^^^^^^^ diff --git a/docs/conf.py b/docs/conf.py index 5e7bd64..00b1c69 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -290,7 +290,7 @@ epub_copyright = u'2012, Jannis Leidel' # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = { - 'python': ('http://docs.python.org/2.7', None), + 'python': ('http://docs.python.org/3', None), 'sphinx': ('http://sphinx.pocoo.org/', None), 'django': ('http://docs.djangoproject.com/en/dev/', 'http://docs.djangoproject.com/en/dev/_objects/'), diff --git a/setup.cfg b/setup.cfg index 51a5b97..4c03348 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,3 @@ -[wheel] -universal = 1 - [coverage:run] source = . branch = 1 diff --git a/setup.py b/setup.py index add1cff..80c22e5 100644 --- a/setup.py +++ b/setup.py @@ -46,16 +46,12 @@ setup( classifiers=[ 'Development Status :: 5 - Production/Stable', 'Framework :: Django', - 'Framework :: Django :: 1.11', - 'Framework :: Django :: 2.0', - 'Framework :: Django :: 2.1', 'Framework :: Django :: 2.2', 'Framework :: Django :: 3.0', 'Intended Audience :: Developers', 'License :: OSI Approved :: BSD License', 'Operating System :: OS Independent', 'Programming Language :: Python', - 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', diff --git a/tox.ini b/tox.ini index 15eb0cc..782207e 100644 --- a/tox.ini +++ b/tox.ini @@ -5,15 +5,11 @@ minversion = 1.8 whitelist_externals = sphinx-build envlist = py36-checkqa, - py{27,35,36,py}-dj111 - py{35,36,37,py3}-dj20 - py{35,36,37,py3}-dj21 py{35,36,37,38,py3}-dj22 py{36,37,38,py3}-dj{30,master} [gh-actions] python = - 2.7: py27 3.5: py35 3.6: py36,flake8,readme 3.7: py37 @@ -27,14 +23,9 @@ setenv = DJANGO_CONFIGURATION = Test COVERAGE_PROCESS_START = {toxinidir}/setup.cfg deps = - dj111: django>=1.11,<2.0 - dj111: dj-email-url<1.0.0 - dj20: django>=2.0a1,<2.1 - dj21: django>=2.1a1,<2.2 - dj22: django>=2.2a1,<3.0 - dj30: django>=3.0a1,<3.1 + dj22: django>=2.2,<3.0 + dj30: django>=3.0,<3.1 djmaster: https://github.com/django/django/archive/master.tar.gz#egg=django - py27,pypy: mock coverage coverage_enable_subprocess extras = testing From fcdbfc0bcb9078db0dca29c9ea1ed7607c72e856 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20K=C3=A4ufl?= Date: Mon, 18 Jan 2021 10:55:05 +0100 Subject: [PATCH 11/41] Drop support for Python 3.5 It has reached its EOL in September 2020, see https://www.python.org/dev/peps/pep-0478/#release-schedule --- .github/workflows/test.yml | 2 +- docs/changes.rst | 2 +- setup.py | 1 - tox.ini | 4 +--- 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7df5943..fb42593 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -9,7 +9,7 @@ jobs: fail-fast: false max-parallel: 5 matrix: - python-version: ['3.5', '3.6', '3.7', '3.8', 'pypy3'] + python-version: ['3.6', '3.7', '3.8', 'pypy3'] steps: - uses: actions/checkout@v2 diff --git a/docs/changes.rst b/docs/changes.rst index 655250e..6c06269 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -6,7 +6,7 @@ Changelog unreleased ^^^^^^^^^^ -- **BACKWARD INCOMPATIBLE** Drop support for Python 2.7. +- **BACKWARD INCOMPATIBLE** Drop support for Python 2.7 and 3.5. - **BACKWARD INCOMPATIBLE** Drop support for Django < 2.2. diff --git a/setup.py b/setup.py index 80c22e5..5c78d1b 100644 --- a/setup.py +++ b/setup.py @@ -52,7 +52,6 @@ setup( 'License :: OSI Approved :: BSD License', 'Operating System :: OS Independent', 'Programming Language :: Python', - 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', diff --git a/tox.ini b/tox.ini index 782207e..bcaf187 100644 --- a/tox.ini +++ b/tox.ini @@ -5,12 +5,10 @@ minversion = 1.8 whitelist_externals = sphinx-build envlist = py36-checkqa, - py{35,36,37,38,py3}-dj22 - py{36,37,38,py3}-dj{30,master} + py{36,37,38,py3}-dj{22,30,master} [gh-actions] python = - 3.5: py35 3.6: py36,flake8,readme 3.7: py37 3.8: py38 From 6cb932e47f1763f0dcdd0c1f838236997772b351 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20K=C3=A4ufl?= Date: Mon, 18 Jan 2021 10:56:47 +0100 Subject: [PATCH 12/41] Run pyupgrade on the code But don't touch string formatting. https://pypi.org/project/pyupgrade/ --- configurations/base.py | 9 +-- configurations/importer.py | 4 +- configurations/utils.py | 103 ++++++++----------------- configurations/values.py | 58 +++++++------- docs/conf.py | 26 +++---- docs/patterns.rst | 2 +- setup.py | 3 +- tests/docs/conf.py | 1 - tests/settings/main.py | 2 +- tests/settings/mixin_inheritance.py | 10 +-- tests/settings/multiple_inheritance.py | 2 +- tests/settings/single_inheritance.py | 2 +- tests/setup_test.py | 5 +- tests/test_env.py | 2 +- tests/test_inheritance.py | 2 +- tests/test_main.py | 2 +- tests/test_sphinx.py | 1 - tests/test_values.py | 12 +-- 18 files changed, 97 insertions(+), 149 deletions(-) diff --git a/configurations/base.py b/configurations/base.py index 07f96df..b1bc1e9 100644 --- a/configurations/base.py +++ b/configurations/base.py @@ -1,6 +1,5 @@ import os import re -import six from django.conf import global_settings from django.core.exceptions import ImproperlyConfigured @@ -37,14 +36,14 @@ class ConfigurationBase(type): # https://github.com/django/django/commit/226ebb17290b604ef29e82fb5c1fbac3594ac163#diff-ec2bed07bb264cb95a80f08d71a47c06R163-R170 if "PASSWORD_RESET_TIMEOUT_DAYS" in attrs and "PASSWORD_RESET_TIMEOUT" in attrs: attrs.pop("PASSWORD_RESET_TIMEOUT_DAYS") - return super(ConfigurationBase, cls).__new__(cls, name, bases, attrs) + return super().__new__(cls, name, bases, attrs) def __repr__(self): return "".format(self.__module__, self.__name__) -class Configuration(six.with_metaclass(ConfigurationBase)): +class Configuration(metaclass=ConfigurationBase): """ The base configuration class to inherit from. @@ -91,10 +90,10 @@ class Configuration(six.with_metaclass(ConfigurationBase)): try: with open(dotenv, 'r') as f: content = f.read() - except IOError as e: + except OSError as e: raise ImproperlyConfigured("Couldn't read .env file " "with the path {}. Error: " - "{}".format(dotenv, e)) + "{}".format(dotenv, e)) from e else: for line in content.splitlines(): m1 = re.match(r'\A([A-Za-z_0-9]+)=(.*)\Z', line) diff --git a/configurations/importer.py b/configurations/importer.py index 353b589..e3573f4 100644 --- a/configurations/importer.py +++ b/configurations/importer.py @@ -51,7 +51,7 @@ def install(check_options=False): installed = True -class ConfigurationImporter(object): +class ConfigurationImporter: modvar = SETTINGS_ENVIRONMENT_VARIABLE namevar = CONFIGURATION_ENVIRONMENT_VARIABLE error_msg = ("Configuration cannot be imported, " @@ -134,7 +134,7 @@ class ConfigurationImporter(object): return None -class ConfigurationLoader(object): +class ConfigurationLoader: def __init__(self, name, location): self.name = name diff --git a/configurations/utils.py b/configurations/utils.py index 7f972e7..da57a3f 100644 --- a/configurations/utils.py +++ b/configurations/utils.py @@ -1,7 +1,7 @@ import inspect -import six import sys +from functools import partial from importlib import import_module from django.core.exceptions import ImproperlyConfigured @@ -12,8 +12,7 @@ def isuppercase(name): def uppercase_attributes(obj): - return dict((name, getattr(obj, name)) - for name in filter(isuppercase, dir(obj))) + return {name: getattr(obj, name) for name in dir(obj) if isuppercase(name)} def import_by_path(dotted_path, error_prefix=''): @@ -36,8 +35,7 @@ def import_by_path(dotted_path, error_prefix=''): msg = '{0}Error importing module {1}: "{2}"'.format(error_prefix, module_path, err) - six.reraise(ImproperlyConfigured, ImproperlyConfigured(msg), - sys.exc_info()[2]) + raise ImproperlyConfigured(msg).with_traceback(sys.exc_info()[2]) try: attr = getattr(module, class_name) except AttributeError: @@ -61,77 +59,40 @@ def reraise(exc, prefix=None, suffix=None): elif not (suffix.startswith('(') and suffix.endswith(')')): suffix = '(' + suffix + ')' exc.args = ('{0} {1} {2}'.format(prefix, args[0], suffix),) + args[1:] - raise + raise exc # Copied over from Sphinx -if sys.version_info >= (3, 0): - from functools import partial - - def getargspec(func): - """Like inspect.getargspec but supports functools.partial as well.""" - if inspect.ismethod(func): - func = func.__func__ - if type(func) is partial: - orig_func = func.func - argspec = getargspec(orig_func) - args = list(argspec[0]) - defaults = list(argspec[3] or ()) - kwoargs = list(argspec[4]) - kwodefs = dict(argspec[5] or {}) - if func.args: - args = args[len(func.args):] - for arg in func.keywords or (): - try: - i = args.index(arg) - len(args) - del args[i] - try: - del defaults[i] - except IndexError: - pass - except ValueError: # must be a kwonly arg - i = kwoargs.index(arg) - del kwoargs[i] - del kwodefs[arg] - return inspect.FullArgSpec(args, argspec[1], argspec[2], - tuple(defaults), kwoargs, - kwodefs, argspec[6]) - while hasattr(func, '__wrapped__'): - func = func.__wrapped__ - if not inspect.isfunction(func): - raise TypeError('%r is not a Python function' % func) - return inspect.getfullargspec(func) - -else: # 2.6, 2.7 - from functools import partial - - def getargspec(func): - """Like inspect.getargspec but supports functools.partial as well.""" - if inspect.ismethod(func): - func = func.im_func - parts = 0, () - if type(func) is partial: - keywords = func.keywords - if keywords is None: - keywords = {} - parts = len(func.args), keywords.keys() - func = func.func - if not inspect.isfunction(func): - raise TypeError('%r is not a Python function' % func) - args, varargs, varkw = inspect.getargs(func.func_code) - func_defaults = func.func_defaults - if func_defaults is None: - func_defaults = [] - else: - func_defaults = list(func_defaults) - if parts[0]: - args = args[parts[0]:] - if parts[1]: - for arg in parts[1]: +def getargspec(func): + """Like inspect.getargspec but supports functools.partial as well.""" + if inspect.ismethod(func): + func = func.__func__ + if type(func) is partial: + orig_func = func.func + argspec = getargspec(orig_func) + args = list(argspec[0]) + defaults = list(argspec[3] or ()) + kwoargs = list(argspec[4]) + kwodefs = dict(argspec[5] or {}) + if func.args: + args = args[len(func.args):] + for arg in func.keywords or (): + try: i = args.index(arg) - len(args) del args[i] try: - del func_defaults[i] + del defaults[i] except IndexError: pass - return inspect.ArgSpec(args, varargs, varkw, func_defaults) + except ValueError: # must be a kwonly arg + i = kwoargs.index(arg) + del kwoargs[i] + del kwodefs[arg] + return inspect.FullArgSpec(args, argspec[1], argspec[2], + tuple(defaults), kwoargs, + kwodefs, argspec[6]) + while hasattr(func, '__wrapped__'): + func = func.__wrapped__ + if not inspect.isfunction(func): + raise TypeError('%r is not a Python function' % func) + return inspect.getfullargspec(func) diff --git a/configurations/values.py b/configurations/values.py index 8f10338..0761c5d 100644 --- a/configurations/values.py +++ b/configurations/values.py @@ -2,7 +2,6 @@ import ast import copy import decimal import os -import six import sys from django.core import validators @@ -20,7 +19,7 @@ def setup_value(target, name, value): setattr(target, multiple_name, multiple_value) -class Value(object): +class Value: """ A single settings value that is able to interpret env variables and implements a simple validation scheme. @@ -117,7 +116,7 @@ class Value(object): return value -class MultipleMixin(object): +class MultipleMixin: multiple = True @@ -126,7 +125,7 @@ class BooleanValue(Value): false_values = ('no', 'n', 'false', '0', '') def __init__(self, *args, **kwargs): - super(BooleanValue, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) if self.default not in (True, False): raise ValueError('Default value {0!r} is not a ' 'boolean value'.format(self.default)) @@ -142,13 +141,13 @@ class BooleanValue(Value): 'boolean value {0!r}'.format(value)) -class CastingMixin(object): +class CastingMixin: exception = (TypeError, ValueError) message = 'Cannot interpret value {0!r}' def __init__(self, *args, **kwargs): - super(CastingMixin, self).__init__(*args, **kwargs) - if isinstance(self.caster, six.string_types): + super().__init__(*args, **kwargs) + if isinstance(self.caster, str): self._caster = import_by_path(self.caster) elif callable(self.caster): self._caster = self.caster @@ -158,9 +157,7 @@ class CastingMixin(object): raise ValueError(error) try: arg_names = getargspec(self._caster)[0] - self._params = dict((name, kwargs[name]) - for name in arg_names - if name in kwargs) + self._params = {name: kwargs[name] for name in arg_names if name in kwargs} except TypeError: self._params = {} @@ -181,7 +178,7 @@ class IntegerValue(CastingMixin, Value): class PositiveIntegerValue(IntegerValue): def to_python(self, value): - int_value = super(PositiveIntegerValue, self).to_python(value) + int_value = super().to_python(value) if int_value < 0: raise ValueError(self.message.format(value)) return int_value @@ -213,7 +210,7 @@ class SequenceValue(Value): converter = kwargs.pop('converter', None) if converter is not None: self.converter = converter - super(SequenceValue, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) # make sure the default is the correct sequence type if self.default is None: self.default = self.sequence_type() @@ -257,7 +254,7 @@ class SingleNestedSequenceValue(SequenceValue): def __init__(self, *args, **kwargs): self.seq_separator = kwargs.pop('seq_separator', ';') - super(SingleNestedSequenceValue, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) def _convert(self, items): # This could receive either a bare or nested sequence @@ -266,8 +263,7 @@ class SingleNestedSequenceValue(SequenceValue): super(SingleNestedSequenceValue, self)._convert(i) for i in items ] return self.sequence_type(converted_sequences) - return self.sequence_type( - super(SingleNestedSequenceValue, self)._convert(items)) + return self.sequence_type(super()._convert(items)) def to_python(self, value): split_value = [ @@ -295,7 +291,7 @@ class BackendsValue(ListValue): try: import_by_path(value) except ImproperlyConfigured as err: - six.reraise(ValueError, ValueError(err), sys.exc_info()[2]) + raise ValueError(err).with_traceback(sys.exc_info()[2]) return value @@ -303,28 +299,28 @@ class SetValue(ListValue): message = 'Cannot interpret set item {0!r} in set {1!r}' def __init__(self, *args, **kwargs): - super(SetValue, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) if self.default is None: self.default = set() else: self.default = set(self.default) def to_python(self, value): - return set(super(SetValue, self).to_python(value)) + return set(super().to_python(value)) class DictValue(Value): message = 'Cannot interpret dict value {0!r}' def __init__(self, *args, **kwargs): - super(DictValue, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) if self.default is None: self.default = {} else: self.default = dict(self.default) def to_python(self, value): - value = super(DictValue, self).to_python(value) + value = super().to_python(value) if not value: return {} try: @@ -336,11 +332,11 @@ class DictValue(Value): return evaled_value -class ValidationMixin(object): +class ValidationMixin: def __init__(self, *args, **kwargs): - super(ValidationMixin, self).__init__(*args, **kwargs) - if isinstance(self.validator, six.string_types): + super().__init__(*args, **kwargs) + if isinstance(self.validator, str): self._validator = import_by_path(self.validator) elif callable(self.validator): self._validator = self.validator @@ -380,16 +376,16 @@ class RegexValue(ValidationMixin, Value): def __init__(self, *args, **kwargs): regex = kwargs.pop('regex', None) self.validator = validators.RegexValidator(regex=regex) - super(RegexValue, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) class PathValue(Value): def __init__(self, *args, **kwargs): self.check_exists = kwargs.pop('check_exists', True) - super(PathValue, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) def setup(self, name): - value = super(PathValue, self).setup(name) + value = super().setup(name) value = os.path.expanduser(value) if self.check_exists and not os.path.exists(value): raise ValueError('Path {0!r} does not exist.'.format(value)) @@ -401,13 +397,13 @@ class SecretValue(Value): def __init__(self, *args, **kwargs): kwargs['environ'] = True kwargs['environ_required'] = True - super(SecretValue, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) if self.default is not None: raise ValueError('Secret values are only allowed to ' 'be set as environment variables') def setup(self, name): - value = super(SecretValue, self).setup(name) + value = super().setup(name) if not value: raise ValueError('Secret value {0!r} is not set'.format(name)) return value @@ -422,7 +418,7 @@ class EmailURLValue(CastingMixin, MultipleMixin, Value): kwargs.setdefault('environ', True) kwargs.setdefault('environ_prefix', None) kwargs.setdefault('environ_name', 'EMAIL_URL') - super(EmailURLValue, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) if self.default is None: self.default = {} else: @@ -437,14 +433,14 @@ class DictBackendMixin(Value): kwargs.setdefault('environ', True) kwargs.setdefault('environ_prefix', None) kwargs.setdefault('environ_name', self.environ_name) - super(DictBackendMixin, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) if self.default is None: self.default = {} else: self.default = self.to_python(self.default) def to_python(self, value): - value = super(DictBackendMixin, self).to_python(value) + value = super().to_python(value) return {self.alias: value} diff --git a/docs/conf.py b/docs/conf.py index 00b1c69..a0613cc 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- -# # django-configurations documentation build configuration file, created by # sphinx-quickstart on Sat Jul 21 15:03:23 2012. # @@ -43,8 +41,8 @@ source_suffix = '.rst' master_doc = 'index' # General information about the project. -project = u'django-configurations' -copyright = u'2012-2014, Jannis Leidel and other contributors' +project = 'django-configurations' +copyright = '2012-2014, Jannis Leidel and other contributors' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -186,8 +184,8 @@ latex_elements = { # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ - ('index', 'django-configurations.tex', u'django-configurations Documentation', - u'Jannis Leidel', 'manual'), + ('index', 'django-configurations.tex', 'django-configurations Documentation', + 'Jannis Leidel', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of @@ -216,8 +214,8 @@ latex_documents = [ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - ('index', 'django-configurations', u'django-configurations Documentation', - [u'Jannis Leidel'], 1) + ('index', 'django-configurations', 'django-configurations Documentation', + ['Jannis Leidel'], 1) ] # If true, show URL addresses after external links. @@ -230,8 +228,8 @@ man_pages = [ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - ('index', 'django-configurations', u'django-configurations Documentation', - u'Jannis Leidel', 'django-configurations', 'One line description of project.', + ('index', 'django-configurations', 'django-configurations Documentation', + 'Jannis Leidel', 'django-configurations', 'One line description of project.', 'Miscellaneous'), ] @@ -248,10 +246,10 @@ texinfo_documents = [ # -- Options for Epub output --------------------------------------------------- # Bibliographic Dublin Core info. -epub_title = u'django-configurations' -epub_author = u'Jannis Leidel' -epub_publisher = u'Jannis Leidel' -epub_copyright = u'2012, Jannis Leidel' +epub_title = 'django-configurations' +epub_author = 'Jannis Leidel' +epub_publisher = 'Jannis Leidel' +epub_copyright = '2012, Jannis Leidel' # The language of the text. It defaults to the language option # or en if the language is not set. diff --git a/docs/patterns.rst b/docs/patterns.rst index 6811f98..d2070b8 100644 --- a/docs/patterns.rst +++ b/docs/patterns.rst @@ -91,7 +91,7 @@ a few mixin you re-use multiple times: .. code-block:: python - class FullPageCaching(object): + class FullPageCaching: USE_ETAGS = True Then import that mixin class in your site settings module and use it with diff --git a/setup.py b/setup.py index 5c78d1b..e479db9 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,3 @@ -from __future__ import print_function import os import codecs from setuptools import setup @@ -27,7 +26,7 @@ setup( 'django-cadmin = configurations.management:execute_from_command_line', ], }, - install_requires=['six'], + install_requires=[], extras_require={ 'cache': ['django-cache-url'], 'database': ['dj-database-url'], diff --git a/tests/docs/conf.py b/tests/docs/conf.py index 4025988..66ce758 100644 --- a/tests/docs/conf.py +++ b/tests/docs/conf.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import os import sys diff --git a/tests/settings/main.py b/tests/settings/main.py index 90e252f..9ea2091 100644 --- a/tests/settings/main.py +++ b/tests/settings/main.py @@ -41,7 +41,7 @@ class Test(Configuration): @property def ALLOWED_HOSTS(self): - allowed_hosts = super(Test, self).ALLOWED_HOSTS[:] + allowed_hosts = super().ALLOWED_HOSTS[:] allowed_hosts.append('base') return allowed_hosts diff --git a/tests/settings/mixin_inheritance.py b/tests/settings/mixin_inheritance.py index 88b4cb6..6018ac2 100644 --- a/tests/settings/mixin_inheritance.py +++ b/tests/settings/mixin_inheritance.py @@ -1,19 +1,19 @@ from configurations import Configuration -class Mixin1(object): +class Mixin1: @property def ALLOWED_HOSTS(self): - allowed_hosts = super(Mixin1, self).ALLOWED_HOSTS[:] + allowed_hosts = super().ALLOWED_HOSTS[:] allowed_hosts.append('test1') return allowed_hosts -class Mixin2(object): +class Mixin2: @property def ALLOWED_HOSTS(self): - allowed_hosts = super(Mixin2, self).ALLOWED_HOSTS[:] + allowed_hosts = super().ALLOWED_HOSTS[:] allowed_hosts.append('test2') return allowed_hosts @@ -21,6 +21,6 @@ class Mixin2(object): class Inheritance(Mixin2, Mixin1, Configuration): def ALLOWED_HOSTS(self): - allowed_hosts = super(Inheritance, self).ALLOWED_HOSTS[:] + allowed_hosts = super().ALLOWED_HOSTS[:] allowed_hosts.append('test3') return allowed_hosts diff --git a/tests/settings/multiple_inheritance.py b/tests/settings/multiple_inheritance.py index 6eb29f3..6152e0a 100644 --- a/tests/settings/multiple_inheritance.py +++ b/tests/settings/multiple_inheritance.py @@ -4,6 +4,6 @@ from .single_inheritance import Inheritance as BaseInheritance class Inheritance(BaseInheritance): def ALLOWED_HOSTS(self): - allowed_hosts = super(Inheritance, self).ALLOWED_HOSTS[:] + allowed_hosts = super().ALLOWED_HOSTS[:] allowed_hosts.append('test-test') return allowed_hosts diff --git a/tests/settings/single_inheritance.py b/tests/settings/single_inheritance.py index 34d4852..5364346 100644 --- a/tests/settings/single_inheritance.py +++ b/tests/settings/single_inheritance.py @@ -5,6 +5,6 @@ class Inheritance(Base): @property def ALLOWED_HOSTS(self): - allowed_hosts = super(Inheritance, self).ALLOWED_HOSTS[:] + allowed_hosts = super().ALLOWED_HOSTS[:] allowed_hosts.append('test') return allowed_hosts diff --git a/tests/setup_test.py b/tests/setup_test.py index cb156e6..59f15b1 100644 --- a/tests/setup_test.py +++ b/tests/setup_test.py @@ -1,9 +1,6 @@ """Used by tests to ensure logging is kept when calling setup() twice.""" -try: - from unittest import mock -except ImportError: - from mock import mock +from unittest import mock import configurations diff --git a/tests/test_env.py b/tests/test_env.py index 47286d0..8066eea 100644 --- a/tests/test_env.py +++ b/tests/test_env.py @@ -1,6 +1,6 @@ import os from django.test import TestCase -from mock import patch +from unittest.mock import patch class DotEnvLoadingTests(TestCase): diff --git a/tests/test_inheritance.py b/tests/test_inheritance.py index b40bfd3..0fe4a28 100644 --- a/tests/test_inheritance.py +++ b/tests/test_inheritance.py @@ -2,7 +2,7 @@ import os from django.test import TestCase -from mock import patch +from unittest.mock import patch class InheritanceTests(TestCase): diff --git a/tests/test_main.py b/tests/test_main.py index fe0e6ce..7cbedbe 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -5,7 +5,7 @@ import sys from django.test import TestCase from django.core.exceptions import ImproperlyConfigured -from mock import patch +from unittest.mock import patch from configurations.importer import ConfigurationImporter diff --git a/tests/test_sphinx.py b/tests/test_sphinx.py index 47519c4..6dc300c 100644 --- a/tests/test_sphinx.py +++ b/tests/test_sphinx.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import subprocess import os diff --git a/tests/test_values.py b/tests/test_values.py index 853b4be..2547e50 100644 --- a/tests/test_values.py +++ b/tests/test_values.py @@ -5,7 +5,7 @@ from contextlib import contextmanager from django.test import TestCase from django.core.exceptions import ImproperlyConfigured -from mock import patch +from unittest.mock import patch from configurations.values import (Value, BooleanValue, IntegerValue, FloatValue, DecimalValue, ListValue, @@ -270,9 +270,9 @@ class ValueTests(TestCase): def test_set_values_default(self): value = SetValue() with env(DJANGO_TEST='2,2'): - self.assertEqual(value.setup('TEST'), set(['2', '2'])) + self.assertEqual(value.setup('TEST'), {'2', '2'}) with env(DJANGO_TEST='2, 2 ,'): - self.assertEqual(value.setup('TEST'), set(['2', '2'])) + self.assertEqual(value.setup('TEST'), {'2', '2'}) with env(DJANGO_TEST=''): self.assertEqual(value.setup('TEST'), set()) @@ -485,12 +485,12 @@ class ValueTests(TestCase): self.assertEqual(value.value, set()) value = SetValue([1, 2]) - self.assertEqual(value.default, set([1, 2])) - self.assertEqual(value.value, set([1, 2])) + self.assertEqual(value.default, {1, 2}) + self.assertEqual(value.value, {1, 2}) def test_setup_value(self): - class Target(object): + class Target: pass value = EmailURLValue() From add9b3ce80ad074030cb00f007fda83497dd4e09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20K=C3=A4ufl?= Date: Mon, 18 Jan 2021 10:36:34 +0100 Subject: [PATCH 13/41] Add support for Django 3.1 and 3.2 --- docs/changes.rst | 2 ++ setup.py | 2 ++ tox.ini | 4 +++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/changes.rst b/docs/changes.rst index 6c06269..cd21b01 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -10,6 +10,8 @@ unreleased - **BACKWARD INCOMPATIBLE** Drop support for Django < 2.2. +- Add support for Django 3.1 and 3.2. + v2.2 (2019-12-03) ^^^^^^^^^^^^^^^^^ diff --git a/setup.py b/setup.py index e479db9..2b638c3 100644 --- a/setup.py +++ b/setup.py @@ -47,6 +47,8 @@ setup( 'Framework :: Django', 'Framework :: Django :: 2.2', 'Framework :: Django :: 3.0', + 'Framework :: Django :: 3.1', + 'Framework :: Django :: 3.2', 'Intended Audience :: Developers', 'License :: OSI Approved :: BSD License', 'Operating System :: OS Independent', diff --git a/tox.ini b/tox.ini index bcaf187..be6bc5e 100644 --- a/tox.ini +++ b/tox.ini @@ -5,7 +5,7 @@ minversion = 1.8 whitelist_externals = sphinx-build envlist = py36-checkqa, - py{36,37,38,py3}-dj{22,30,master} + py{36,37,38,py3}-dj{22,30,31,32,master} [gh-actions] python = @@ -23,6 +23,8 @@ setenv = deps = dj22: django>=2.2,<3.0 dj30: django>=3.0,<3.1 + dj31: django>=3.1,<3.2 + dj32: https://github.com/django/django/archive/stable/3.2.x.tar.gz#egg=django djmaster: https://github.com/django/django/archive/master.tar.gz#egg=django coverage coverage_enable_subprocess From c3d5b4b7156e680c37b9780af120002f7e0af2ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20K=C3=A4ufl?= Date: Mon, 18 Jan 2021 10:58:23 +0100 Subject: [PATCH 14/41] Add support for Python 3.9 --- .github/workflows/test.yml | 2 +- docs/changes.rst | 2 ++ setup.py | 1 + tox.ini | 9 +++++---- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fb42593..755bc27 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -9,7 +9,7 @@ jobs: fail-fast: false max-parallel: 5 matrix: - python-version: ['3.6', '3.7', '3.8', 'pypy3'] + python-version: ['3.6', '3.7', '3.8', '3.9', 'pypy3'] steps: - uses: actions/checkout@v2 diff --git a/docs/changes.rst b/docs/changes.rst index cd21b01..b2cc925 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -12,6 +12,8 @@ unreleased - Add support for Django 3.1 and 3.2. +- Add suppport for Python 3.9. + v2.2 (2019-12-03) ^^^^^^^^^^^^^^^^^ diff --git a/setup.py b/setup.py index 2b638c3..7a578e2 100644 --- a/setup.py +++ b/setup.py @@ -56,6 +56,7 @@ setup( 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: Implementation :: PyPy', 'Topic :: Utilities', ], diff --git a/tox.ini b/tox.ini index be6bc5e..8ee43af 100644 --- a/tox.ini +++ b/tox.ini @@ -5,13 +5,14 @@ minversion = 1.8 whitelist_externals = sphinx-build envlist = py36-checkqa, - py{36,37,38,py3}-dj{22,30,31,32,master} + py{36,37,38,39,py3}-dj{22,30,31,32,master} [gh-actions] python = 3.6: py36,flake8,readme 3.7: py37 3.8: py38 + 3.9: py39 pypy3: pypy3 [testenv] @@ -21,9 +22,9 @@ setenv = DJANGO_CONFIGURATION = Test COVERAGE_PROCESS_START = {toxinidir}/setup.cfg deps = - dj22: django>=2.2,<3.0 - dj30: django>=3.0,<3.1 - dj31: django>=3.1,<3.2 + dj22: django~=2.2.17 + dj30: django~=3.0.11 + dj31: django~=3.1.3 dj32: https://github.com/django/django/archive/stable/3.2.x.tar.gz#egg=django djmaster: https://github.com/django/django/archive/master.tar.gz#egg=django coverage From 9b9ff4c0a2313a8d6bb725b604278b947744865c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20K=C3=A4ufl?= Date: Mon, 18 Jan 2021 10:48:03 +0100 Subject: [PATCH 15/41] Deprecate utils.import_by_path in favor of django.utils.module_loading.import_string --- configurations/utils.py | 3 +++ configurations/values.py | 19 ++++++++++++++----- docs/changes.rst | 3 +++ 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/configurations/utils.py b/configurations/utils.py index da57a3f..1f618ee 100644 --- a/configurations/utils.py +++ b/configurations/utils.py @@ -1,5 +1,6 @@ import inspect import sys +import warnings from functools import partial from importlib import import_module @@ -23,6 +24,8 @@ def import_by_path(dotted_path, error_prefix=''): Backported from Django 1.6. """ + warnings.warn("Function utils.import_by_path is deprecated in favor of " + "django.utils.module_loading.import_string.", DeprecationWarning) try: module_path, class_name = dotted_path.rsplit('.', 1) except ValueError: diff --git a/configurations/values.py b/configurations/values.py index 0761c5d..2413a1a 100644 --- a/configurations/values.py +++ b/configurations/values.py @@ -6,8 +6,9 @@ import sys from django.core import validators from django.core.exceptions import ValidationError, ImproperlyConfigured +from django.utils.module_loading import import_string -from .utils import import_by_path, getargspec +from .utils import getargspec def setup_value(target, name, value): @@ -148,7 +149,11 @@ class CastingMixin: def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) if isinstance(self.caster, str): - self._caster = import_by_path(self.caster) + try: + self._caster = import_string(self.caster) + except ImportError as err: + msg = "Could not import {!r}".format(self.caster) + raise ImproperlyConfigured(msg) from err elif callable(self.caster): self._caster = self.caster else: @@ -289,8 +294,8 @@ class BackendsValue(ListValue): def converter(self, value): try: - import_by_path(value) - except ImproperlyConfigured as err: + import_string(value) + except ImportError as err: raise ValueError(err).with_traceback(sys.exc_info()[2]) return value @@ -337,7 +342,11 @@ class ValidationMixin: def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) if isinstance(self.validator, str): - self._validator = import_by_path(self.validator) + try: + self._validator = import_string(self.validator) + except ImportError as err: + msg = "Could not import {!r}".format(self.validator) + raise ImproperlyConfigured(msg) from err elif callable(self.validator): self._validator = self.validator else: diff --git a/docs/changes.rst b/docs/changes.rst index b2cc925..67abf0e 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -14,6 +14,9 @@ unreleased - Add suppport for Python 3.9. +- Deprecate ``utils.import_by_path`` in favor of + ``django.utils.module_loading.import_string``. + v2.2 (2019-12-03) ^^^^^^^^^^^^^^^^^ From 184df10a66ade08502f6a78e8515368fc157c9bb Mon Sep 17 00:00:00 2001 From: Jannis Leidel Date: Tue, 19 Jan 2021 14:48:20 +0100 Subject: [PATCH 16/41] Add code owner for workflows. --- .github/CODEOWNERS | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..012f63f --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,2 @@ +*CODEOWNERS @jazzband/roadies +.github/workflows/ @jazzband/roadies From 58575bfb844e9e71636e385984560164cc3e5f9e Mon Sep 17 00:00:00 2001 From: Jannis Leidel Date: Tue, 19 Jan 2021 14:54:47 +0100 Subject: [PATCH 17/41] Minor update. --- .github/CODEOWNERS | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 012f63f..910ff1e 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,2 +1,4 @@ -*CODEOWNERS @jazzband/roadies +CODEOWNERS @jazzband/roadies +docs/CODEOWNERS @jazzband/roadies +.github/CODEOWNERS @jazzband/roadies .github/workflows/ @jazzband/roadies From 6fa45aba1b9decdbc91d16dc25a4bbaf8d4caf26 Mon Sep 17 00:00:00 2001 From: Jannis Leidel <15129087+jannisleidel@users.noreply.github.com> Date: Tue, 19 Jan 2021 14:55:46 +0100 Subject: [PATCH 18/41] Update release.yml --- .github/workflows/release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 707641d..f4ba9c9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,3 +1,4 @@ +# something silly name: Release on: From 3da6af02fb4f78a7c8a442f92f5932c4b21edd58 Mon Sep 17 00:00:00 2001 From: Jannis Leidel Date: Tue, 19 Jan 2021 16:40:19 +0100 Subject: [PATCH 19/41] Codeowners update. --- .github/CODEOWNERS | 4 ---- CODEOWNERS | 2 ++ 2 files changed, 2 insertions(+), 4 deletions(-) delete mode 100644 .github/CODEOWNERS create mode 100644 CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS deleted file mode 100644 index 910ff1e..0000000 --- a/.github/CODEOWNERS +++ /dev/null @@ -1,4 +0,0 @@ -CODEOWNERS @jazzband/roadies -docs/CODEOWNERS @jazzband/roadies -.github/CODEOWNERS @jazzband/roadies -.github/workflows/ @jazzband/roadies diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 0000000..81e700c --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,2 @@ +CODEOWNERS @jazzband/roadies +.github/workflows/ @jazzband/roadies From d89fe5a2cbd2830b3ca7f37bc104166513d73084 Mon Sep 17 00:00:00 2001 From: Jannis Leidel Date: Tue, 9 Mar 2021 19:20:31 +0100 Subject: [PATCH 20/41] Rename Django's dev branch to main. (#279) * Rename Django's dev branch to main. More information: https://groups.google.com/g/django-developers/c/tctDuKUGosc/ Refs: https://github.com/django/django/pull/14048 * Fix test matrix. * Remove CODEOWNERS again. * Fix name of tox env. * Fix test matrix. --- CODEOWNERS | 2 -- tox.ini | 9 +++++---- 2 files changed, 5 insertions(+), 6 deletions(-) delete mode 100644 CODEOWNERS diff --git a/CODEOWNERS b/CODEOWNERS deleted file mode 100644 index 81e700c..0000000 --- a/CODEOWNERS +++ /dev/null @@ -1,2 +0,0 @@ -CODEOWNERS @jazzband/roadies -.github/workflows/ @jazzband/roadies diff --git a/tox.ini b/tox.ini index 8ee43af..57e0dde 100644 --- a/tox.ini +++ b/tox.ini @@ -4,8 +4,9 @@ usedevelop = true minversion = 1.8 whitelist_externals = sphinx-build envlist = - py36-checkqa, - py{36,37,38,39,py3}-dj{22,30,31,32,master} + py36-checkqa + py{36,37,38,39,py3}-dj{22,30,31,32} + py{38,39}-djmain [gh-actions] python = @@ -25,8 +26,8 @@ deps = dj22: django~=2.2.17 dj30: django~=3.0.11 dj31: django~=3.1.3 - dj32: https://github.com/django/django/archive/stable/3.2.x.tar.gz#egg=django - djmaster: https://github.com/django/django/archive/master.tar.gz#egg=django + dj32: https://github.com/django/django/archive/stable/3.2.x.tar.gz + djmain: https://github.com/django/django/archive/main.tar.gz coverage coverage_enable_subprocess extras = testing From f85ec1fb89b622c165c0198ce4b77da0fe450dd3 Mon Sep 17 00:00:00 2001 From: Brian Helba Date: Fri, 9 Apr 2021 00:20:36 -0400 Subject: [PATCH 21/41] Prevent an ImproperlyConfigured warning from DEFAULT_HASHING_ALGORITHM --- configurations/base.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/configurations/base.py b/configurations/base.py index b1bc1e9..1d7e488 100644 --- a/configurations/base.py +++ b/configurations/base.py @@ -36,6 +36,9 @@ class ConfigurationBase(type): # https://github.com/django/django/commit/226ebb17290b604ef29e82fb5c1fbac3594ac163#diff-ec2bed07bb264cb95a80f08d71a47c06R163-R170 if "PASSWORD_RESET_TIMEOUT_DAYS" in attrs and "PASSWORD_RESET_TIMEOUT" in attrs: attrs.pop("PASSWORD_RESET_TIMEOUT_DAYS") + # https://docs.djangoproject.com/en/3.1/releases/3.1/#default-hashing-algorithm-settings + if "DEFAULT_HASHING_ALGORITHM" in attrs: + attrs.pop("DEFAULT_HASHING_ALGORITHM") return super().__new__(cls, name, bases, attrs) def __repr__(self): From 58a4f689ff4be35e4863ef0b87a1dbb35da536e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Mon, 12 Apr 2021 21:53:16 +0200 Subject: [PATCH 22/41] Require setuptools, configurations/version.py imports pkg_resources --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 7a578e2..ebaa589 100644 --- a/setup.py +++ b/setup.py @@ -26,7 +26,7 @@ setup( 'django-cadmin = configurations.management:execute_from_command_line', ], }, - install_requires=[], + install_requires=["setuptools"], extras_require={ 'cache': ['django-cache-url'], 'database': ['dj-database-url'], From d715a719a4e0ec43dc3c28e56d11f74df39c8777 Mon Sep 17 00:00:00 2001 From: Brian Helba Date: Tue, 31 Aug 2021 21:28:16 -0400 Subject: [PATCH 23/41] Use a more general structure for removing deprecated settings --- configurations/base.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/configurations/base.py b/configurations/base.py index 1d7e488..24de460 100644 --- a/configurations/base.py +++ b/configurations/base.py @@ -32,13 +32,22 @@ class ConfigurationBase(type): for base in bases[::-1]: settings_vars.update(uppercase_attributes(base)) attrs = dict(settings_vars, **attrs) - # Fix ImproperlyConfigured issue introduced in Django + + deprecated_settings = { + # DEFAULT_HASHING_ALGORITHM is always deprecated, as it's a + # transitional setting + # https://docs.djangoproject.com/en/3.1/releases/3.1/#default-hashing-algorithm-settings + "DEFAULT_HASHING_ALGORITHM", + } + # PASSWORD_RESET_TIMEOUT_DAYS is deprecated in favor of + # PASSWORD_RESET_TIMEOUT in Django 3.1 # https://github.com/django/django/commit/226ebb17290b604ef29e82fb5c1fbac3594ac163#diff-ec2bed07bb264cb95a80f08d71a47c06R163-R170 - if "PASSWORD_RESET_TIMEOUT_DAYS" in attrs and "PASSWORD_RESET_TIMEOUT" in attrs: - attrs.pop("PASSWORD_RESET_TIMEOUT_DAYS") - # https://docs.djangoproject.com/en/3.1/releases/3.1/#default-hashing-algorithm-settings - if "DEFAULT_HASHING_ALGORITHM" in attrs: - attrs.pop("DEFAULT_HASHING_ALGORITHM") + if "PASSWORD_RESET_TIMEOUT" in attrs: + deprecated_settings.add("PASSWORD_RESET_TIMEOUT_DAYS") + for deprecated_setting in deprecated_settings: + if deprecated_setting in attrs: + del attrs[deprecated_setting] + return super().__new__(cls, name, bases, attrs) def __repr__(self): From 271f6fb5bb9d29cedae3f5c6a52d23988b109ad6 Mon Sep 17 00:00:00 2001 From: Brian Helba Date: Tue, 31 Aug 2021 22:01:34 -0400 Subject: [PATCH 24/41] Replace references to MIDDLEWARE_CLASSES with MIDDLEWARE MIDDLEWARE_CLASSES was removed in Django 2.0. --- docs/values.rst | 2 +- test_project/test_project/settings.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/values.rst b/docs/values.rst index 5f5dcea..1d6aab4 100644 --- a/docs/values.rst +++ b/docs/values.rst @@ -547,7 +547,7 @@ Other values :: - MIDDLEWARE_CLASSES = values.BackendsValue([ + MIDDLEWARE = values.BackendsValue([ 'django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', diff --git a/test_project/test_project/settings.py b/test_project/test_project/settings.py index 295981c..5d89812 100644 --- a/test_project/test_project/settings.py +++ b/test_project/test_project/settings.py @@ -95,7 +95,7 @@ class Base(Configuration): 'django.template.loaders.app_directories.Loader', ) - MIDDLEWARE_CLASSES = ( + MIDDLEWARE = ( 'django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', From 1ada7d14f769744efdfd19c207a83ff3a850f177 Mon Sep 17 00:00:00 2001 From: Richard de Wit Date: Tue, 14 Jan 2020 16:27:23 +0100 Subject: [PATCH 25/41] Add ASGI support Then in your project's `asgi.py` file use this: ```python from configurations.asgi import get_asgi_application application = get_asgi_application() ``` --- configurations/asgi.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 configurations/asgi.py diff --git a/configurations/asgi.py b/configurations/asgi.py new file mode 100644 index 0000000..b257d60 --- /dev/null +++ b/configurations/asgi.py @@ -0,0 +1,14 @@ +from . import importer + +importer.install() + +try: + from django.core.asgi import get_asgi_application +except ImportError: # pragma: no cover + from django.core.handlers.asgi import ASGIHandler + + def get_asgi_application(): # noqa + return ASGIHandler() + +# this is just for the crazy ones +application = get_asgi_application() From c1cb3874f24378d99d1f460eed7e73ab82be325c Mon Sep 17 00:00:00 2001 From: Finn-Thorben Sell Date: Thu, 9 Sep 2021 15:01:11 +0200 Subject: [PATCH 26/41] remove fallback onto ASGIHandler ASGIHandler is considered a django internal api with get_asgi_application being the public counterpart. get_asgi_application is also present since the introduction of django's asgi support so the ImportError should never occur anyways. --- configurations/asgi.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/configurations/asgi.py b/configurations/asgi.py index b257d60..7a28d29 100644 --- a/configurations/asgi.py +++ b/configurations/asgi.py @@ -2,13 +2,7 @@ from . import importer importer.install() -try: - from django.core.asgi import get_asgi_application -except ImportError: # pragma: no cover - from django.core.handlers.asgi import ASGIHandler - - def get_asgi_application(): # noqa - return ASGIHandler() +from django.core.asgi import get_asgi_application # this is just for the crazy ones application = get_asgi_application() From 2cae9838b559049efc979fb8b5f03765a1517abf Mon Sep 17 00:00:00 2001 From: Finn-Thorben Sell Date: Thu, 9 Sep 2021 15:08:42 +0200 Subject: [PATCH 27/41] add documentation to README about get_asgi_application --- README.rst | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 536b154..7b9ac9f 100644 --- a/README.rst +++ b/README.rst @@ -120,5 +120,18 @@ The same applies to your **wsgi.py** file, e.g.: Here we don't use the default ``django.core.wsgi.get_wsgi_application`` function but instead ``configurations.wsgi.get_wsgi_application``. +Or if you are not serving your app via WSGI but ASGI instead, you need to modify your **asgi.py** file too.: + +.. code-block:: python + + import os + + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings') + os.environ.setdefault('DJANGO_CONFIGURATION', 'DEV') + + from configurations.asgi import get_asgi_application + + application = get_asgi_application() + That's it! You can now use your project with ``manage.py`` and your favorite -WSGI enabled server. +WSGI/ASGI enabled server. From 6a4a620891cf2dfd6733a0cf63566d86d0d62507 Mon Sep 17 00:00:00 2001 From: Finn-Thorben Sell Date: Thu, 9 Sep 2021 15:11:49 +0200 Subject: [PATCH 28/41] add additional documentation references to asgi.py --- README.rst | 2 +- docs/cookbook.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 7b9ac9f..0716754 100644 --- a/README.rst +++ b/README.rst @@ -81,7 +81,7 @@ command line option, e.g. python manage.py runserver --settings=mysite.settings --configuration=Dev To enable Django to use your configuration you now have to modify your -**manage.py** or **wsgi.py** script to use django-configurations's versions +**manage.py**, **wsgi.py** or **asgi.py** script to use django-configurations's versions of the appropriate starter functions, e.g. a typical **manage.py** using django-configurations would look like this: diff --git a/docs/cookbook.rst b/docs/cookbook.rst index bb5f048..c34cae1 100644 --- a/docs/cookbook.rst +++ b/docs/cookbook.rst @@ -182,7 +182,7 @@ probably just add the following to the **beginning** of your settings module: import configurations configurations.setup() -That has the same effect as using the ``manage.py`` or ``wsgi.py`` utilities. +That has the same effect as using the ``manage.py``, ``wsgi.py`` or ``asgi.py`` utilities. This will also call ``django.setup()``. >= 3.1 From 68cbb437cf3560127d887169137b0c8b986d98f0 Mon Sep 17 00:00:00 2001 From: jazzband-bot Date: Mon, 25 Oct 2021 11:14:26 +0000 Subject: [PATCH 29/41] Jazzband: Created local 'CODE_OF_CONDUCT.md' from remote 'CODE_OF_CONDUCT.md' --- CODE_OF_CONDUCT.md | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 CODE_OF_CONDUCT.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..e0d5efa --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,46 @@ +# Code of Conduct + +As contributors and maintainers of the Jazzband projects, and in the interest of +fostering an open and welcoming community, we pledge to respect all people who +contribute through reporting issues, posting feature requests, updating documentation, +submitting pull requests or patches, and other activities. + +We are committed to making participation in the Jazzband a harassment-free experience +for everyone, regardless of the level of experience, gender, gender identity and +expression, sexual orientation, disability, personal appearance, body size, race, +ethnicity, age, religion, or nationality. + +Examples of unacceptable behavior by participants include: + +- The use of sexualized language or imagery +- Personal attacks +- Trolling or insulting/derogatory comments +- Public or private harassment +- Publishing other's private information, such as physical or electronic addresses, + without explicit permission +- Other unethical or unprofessional conduct + +The Jazzband roadies have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are not +aligned to this Code of Conduct, or to ban temporarily or permanently any contributor +for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +By adopting this Code of Conduct, the roadies commit themselves to fairly and +consistently applying these principles to every aspect of managing the jazzband +projects. Roadies who do not follow or enforce the Code of Conduct may be permanently +removed from the Jazzband roadies. + +This code of conduct applies both within project spaces and in public spaces when an +individual is representing the project or its community. + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by +contacting the roadies at `roadies@jazzband.co`. All complaints will be reviewed and +investigated and will result in a response that is deemed necessary and appropriate to +the circumstances. Roadies are obligated to maintain confidentiality with regard to the +reporter of an incident. + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version +1.3.0, available at [https://contributor-covenant.org/version/1/3/0/][version] + +[homepage]: https://contributor-covenant.org +[version]: https://contributor-covenant.org/version/1/3/0/ From fa026af595e55da32acedb28390c9e7d4ba2f5ae Mon Sep 17 00:00:00 2001 From: Brian Helba Date: Mon, 25 Oct 2021 08:29:53 -0400 Subject: [PATCH 30/41] Add a pre-commit configuration --- .pre-commit-config.yaml | 1 + MANIFEST.in | 1 + 2 files changed, 2 insertions(+) create mode 100644 .pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..4e6a92c --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1 @@ +repos: [] diff --git a/MANIFEST.in b/MANIFEST.in index 4f06150..9b4420f 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -6,3 +6,4 @@ recursive-include tests * recursive-include docs * recursive-include test_project * include LICENSE +include .pre-commit-config.yaml From 12e033ed1e424ca57dd7c75e22410f2defe6e90c Mon Sep 17 00:00:00 2001 From: Brian Helba Date: Mon, 25 Oct 2021 08:57:16 -0400 Subject: [PATCH 31/41] Add CODE_OF_CONDUCT.md to the sdist --- MANIFEST.in | 1 + 1 file changed, 1 insertion(+) diff --git a/MANIFEST.in b/MANIFEST.in index 9b4420f..c13d839 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -7,3 +7,4 @@ recursive-include docs * recursive-include test_project * include LICENSE include .pre-commit-config.yaml +include CODE_OF_CONDUCT.md From 7e4b425ea31b53331c9ef3945893bc503494d381 Mon Sep 17 00:00:00 2001 From: Brian Helba Date: Mon, 25 Oct 2021 09:02:06 -0400 Subject: [PATCH 32/41] Don't run duplicate CI tasks on every PR The "pull_request" action already runs on pushes to any branch with an open PR, so only run the "push" action on the "master" branch. --- .github/workflows/test.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 755bc27..8a8e8d4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,6 +1,10 @@ name: Test -on: [push, pull_request] +on: + pull_request: + push: + branches: + - master jobs: build: From 09dfa471e0dbc81bfff7780a471156a4e7949d4c Mon Sep 17 00:00:00 2001 From: Brian Helba Date: Mon, 25 Oct 2021 09:12:15 -0400 Subject: [PATCH 33/41] Sort MANIFEST.in --- MANIFEST.in | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/MANIFEST.in b/MANIFEST.in index c13d839..3757d2b 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,10 +1,10 @@ -include README.rst -include CONTRIBUTING.md +include .pre-commit-config.yaml include AUTHORS +include CODE_OF_CONDUCT.md +include CONTRIBUTING.md +include LICENSE +include README.rst include tox.ini -recursive-include tests * recursive-include docs * recursive-include test_project * -include LICENSE -include .pre-commit-config.yaml -include CODE_OF_CONDUCT.md +recursive-include tests * From 3ac97e539f377b2eff15dd270b8386c8ede20085 Mon Sep 17 00:00:00 2001 From: Brian Helba Date: Tue, 31 Aug 2021 21:46:38 -0400 Subject: [PATCH 34/41] Require Django as an install_requires Since "import django" occurs in the code, it is an explicit requirement. --- setup.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index ebaa589..5590ea9 100644 --- a/setup.py +++ b/setup.py @@ -26,7 +26,10 @@ setup( 'django-cadmin = configurations.management:execute_from_command_line', ], }, - install_requires=["setuptools"], + install_requires=[ + 'django>=2.2', + 'setuptools', + ], extras_require={ 'cache': ['django-cache-url'], 'database': ['dj-database-url'], From 7c9ac5e53f728a8c7cd7a00c471d68de17e40e5f Mon Sep 17 00:00:00 2001 From: Brian Helba Date: Mon, 25 Oct 2021 09:34:42 -0400 Subject: [PATCH 35/41] Suppress import ordering style error --- configurations/asgi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configurations/asgi.py b/configurations/asgi.py index 7a28d29..da9401b 100644 --- a/configurations/asgi.py +++ b/configurations/asgi.py @@ -2,7 +2,7 @@ from . import importer importer.install() -from django.core.asgi import get_asgi_application +from django.core.asgi import get_asgi_application # noqa: E402 # this is just for the crazy ones application = get_asgi_application() From 91ef9fd8adc49d4d3863cf3582241c53dc9313ab Mon Sep 17 00:00:00 2001 From: Brian Helba Date: Mon, 25 Oct 2021 09:50:51 -0400 Subject: [PATCH 36/41] Fix a double space typo in a string --- configurations/values.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configurations/values.py b/configurations/values.py index 2413a1a..8eb3bbc 100644 --- a/configurations/values.py +++ b/configurations/values.py @@ -397,7 +397,7 @@ class PathValue(Value): value = super().setup(name) value = os.path.expanduser(value) if self.check_exists and not os.path.exists(value): - raise ValueError('Path {0!r} does not exist.'.format(value)) + raise ValueError('Path {0!r} does not exist.'.format(value)) return os.path.abspath(value) From ec1282887765b5d3f0c48f08e18d33d6aa1f8c0e Mon Sep 17 00:00:00 2001 From: Brian Helba Date: Mon, 25 Oct 2021 09:52:21 -0400 Subject: [PATCH 37/41] Simplify import of django.core.wsgi.get_wsgi_application This has been available since Django 1.4. The import guard is no longer necessary. --- configurations/wsgi.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/configurations/wsgi.py b/configurations/wsgi.py index 54ab753..ea157a3 100644 --- a/configurations/wsgi.py +++ b/configurations/wsgi.py @@ -2,13 +2,7 @@ from . import importer importer.install() -try: - from django.core.wsgi import get_wsgi_application -except ImportError: # pragma: no cover - from django.core.handlers.wsgi import WSGIHandler - - def get_wsgi_application(): # noqa - return WSGIHandler() +from django.core.wsgi import get_wsgi_application # noqa: E402 # this is just for the crazy ones application = get_wsgi_application() From 40bdab3f4ad3324a079e6bbeb1f1efee1469fede Mon Sep 17 00:00:00 2001 From: Brian Helba Date: Tue, 31 Aug 2021 21:42:20 -0400 Subject: [PATCH 38/41] Preserve Django warnings when DEFAULT_AUTO_FIELD is not set Fixes #286. --- configurations/base.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/configurations/base.py b/configurations/base.py index 24de460..e54fcb4 100644 --- a/configurations/base.py +++ b/configurations/base.py @@ -38,6 +38,11 @@ class ConfigurationBase(type): # transitional setting # https://docs.djangoproject.com/en/3.1/releases/3.1/#default-hashing-algorithm-settings "DEFAULT_HASHING_ALGORITHM", + # When DEFAULT_AUTO_FIELD is not explicitly set, Django's emits a + # system check warning models.W042. This warning should not be + # suppressed, as downstream users are expected to make a decision. + # https://docs.djangoproject.com/en/3.2/releases/3.2/#customizing-type-of-auto-created-primary-keys + "DEFAULT_AUTO_FIELD", } # PASSWORD_RESET_TIMEOUT_DAYS is deprecated in favor of # PASSWORD_RESET_TIMEOUT in Django 3.1 From 6da8420635f968a028cf5d7523c981e3c2f32896 Mon Sep 17 00:00:00 2001 From: Brian Helba Date: Tue, 31 Aug 2021 22:07:33 -0400 Subject: [PATCH 39/41] Prevent warnings for settings deprecated in Django 2.2 Fixes #233. --- configurations/base.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/configurations/base.py b/configurations/base.py index e54fcb4..a09af41 100644 --- a/configurations/base.py +++ b/configurations/base.py @@ -38,6 +38,10 @@ class ConfigurationBase(type): # transitional setting # https://docs.djangoproject.com/en/3.1/releases/3.1/#default-hashing-algorithm-settings "DEFAULT_HASHING_ALGORITHM", + # DEFAULT_CONTENT_TYPE and FILE_CHARSET are deprecated in + # Django 2.2 and are removed in Django 3.0 + "DEFAULT_CONTENT_TYPE", + "FILE_CHARSET", # When DEFAULT_AUTO_FIELD is not explicitly set, Django's emits a # system check warning models.W042. This warning should not be # suppressed, as downstream users are expected to make a decision. From df967f4d76bfd760381ea56ca587de944bbfe6a2 Mon Sep 17 00:00:00 2001 From: Brian Helba Date: Mon, 25 Oct 2021 11:21:06 -0400 Subject: [PATCH 40/41] Remove an obsolete command used for testing The test using this was removed in a04560993468e427e608ee1a848b43d7b6b80756. --- tests/management/__init__.py | 0 tests/management/commands/__init__.py | 0 .../management/commands/old_optparse_command.py | 16 ---------------- 3 files changed, 16 deletions(-) delete mode 100644 tests/management/__init__.py delete mode 100644 tests/management/commands/__init__.py delete mode 100644 tests/management/commands/old_optparse_command.py diff --git a/tests/management/__init__.py b/tests/management/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/management/commands/__init__.py b/tests/management/commands/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/management/commands/old_optparse_command.py b/tests/management/commands/old_optparse_command.py deleted file mode 100644 index d7844e5..0000000 --- a/tests/management/commands/old_optparse_command.py +++ /dev/null @@ -1,16 +0,0 @@ -from optparse import make_option -from django.core.management.base import BaseCommand - - -class Command(BaseCommand): - - # Used by a specific test to see how unupgraded - # management commands play with configurations. - # See the test code for more details. - - option_list = BaseCommand.option_list + ( - make_option('--arg1', action='store_true'), - ) - - def handle(self, *args, **options): - pass From b75c8d7a7ab066693271cde9e1c07503c2013081 Mon Sep 17 00:00:00 2001 From: Brian Helba Date: Mon, 25 Oct 2021 12:18:19 -0400 Subject: [PATCH 41/41] Remove references to TEMPLATE_DEBUG This setting is deprecated since Django 1.8. --- docs/patterns.rst | 1 - docs/values.rst | 1 - test_project/test_project/settings.py | 1 - 3 files changed, 3 deletions(-) diff --git a/docs/patterns.rst b/docs/patterns.rst index d2070b8..eff644a 100644 --- a/docs/patterns.rst +++ b/docs/patterns.rst @@ -21,7 +21,6 @@ file: class Dev(Base): DEBUG = True - TEMPLATE_DEBUG = DEBUG class Prod(Base): TIME_ZONE = 'America/New_York' diff --git a/docs/values.rst b/docs/values.rst index b0a5fe5..380bb04 100644 --- a/docs/values.rst +++ b/docs/values.rst @@ -46,7 +46,6 @@ value: class Dev(Configuration): DEBUG = values.BooleanValue(True) - TEMPLATE_DEBUG = values.BooleanValue(DEBUG) See the list of :ref:`built-in value classes` for more information. diff --git a/test_project/test_project/settings.py b/test_project/test_project/settings.py index 5d89812..879a3b8 100644 --- a/test_project/test_project/settings.py +++ b/test_project/test_project/settings.py @@ -5,7 +5,6 @@ class Base(Configuration): # Django settings for test_project project. DEBUG = values.BooleanValue(True, environ=True) - TEMPLATE_DEBUG = DEBUG ADMINS = ( # ('Your Name', 'your_email@example.com'),