diff --git a/.bandit b/.bandit deleted file mode 100644 index 7db131d..0000000 --- a/.bandit +++ /dev/null @@ -1,2 +0,0 @@ -[bandit] -exclude: tests,.tox diff --git a/.fussyfox.yml b/.fussyfox.yml deleted file mode 100644 index cd2d518..0000000 --- a/.fussyfox.yml +++ /dev/null @@ -1,2 +0,0 @@ -- bandit -- flake8 diff --git a/.gitignore b/.gitignore index 283c869..8c950b9 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ htmlcov/ *.pyc dist/ tests/docs/_build/ +.eggs/ diff --git a/.travis.yml b/.travis.yml index 9ce3e2a..150373b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,87 +1,37 @@ language: python -sudo: false +dist: xenial cache: pip -matrix: - include: - - env: TOXENV=readme-py27 - python: 2.7 - - env: TOXENV=py27-dj111-coverage - python: 2.7 - - env: TOXENV=py35-dj111-coverage - python: 3.5 - - env: TOXENV=py36-dj111-coverage - python: 3.6 - - env: TOXENV=pypy-dj111-coverage - python: pypy - - env: TOXENV=pypy3-dj111-coverage - python: pypy3 - - env: TOXENV=py35-dj20-coverage - python: 3.5 - - env: TOXENV=py36-dj20-coverage - python: 3.6 - - env: TOXENV=py37-dj20-coverage - python: 3.7 - - env: TOXENV=pypy3-dj20-coverage - python: pypy3 - - env: TOXENV=py36-dj21-coverage - python: 3.6 - - env: TOXENV=py37-dj21-coverage - python: 3.7 - - env: TOXENV=pypy3-dj21-coverage - python: pypy3 - - env: TOXENV=py36-dj22-coverage - python: 3.6 - - env: TOXENV=py37-dj22-coverage - python: 3.7 - - env: TOXENV=py38-dj22-coverage - python: 3.8 - - env: TOXENV=pypy3-dj22-coverage - python: pypy3 - - env: TOXENV=py36-dj30-coverage - python: 3.6 - - env: TOXENV=py37-dj30-coverage - python: 3.7 - - env: TOXENV=py38-dj30-coverage - python: 3.8 - - env: TOXENV=pypy3-dj30-coverage - python: pypy3 - - env: TOXENV=py36-djmaster-coverage - python: 3.6 - - env: TOXENV=py37-djmaster-coverage - python: 3.7 - - env: TOXENV=py38-djmaster-coverage - python: 3.8 - - env: TOXENV=pypy3-djmaster-coverage - python: pypy3 - allow_failures: - - env: TOXENV=py36-djmaster-coverage - python: 3.6 - - env: TOXENV=py37-djmaster-coverage - python: 3.7 - - env: TOXENV=py38-djmaster-coverage - python: 3.8 - - env: TOXENV=pypy3-djmaster-coverage - python: pypy3 -install: -- pip install tox +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: -- | - if [[ "${TOXENV%-coverage}" != "$TOXENV" ]]; then - pip install codecov - coverage xml - codecov --required -X gcov fix pycov -f coverage.xml --flags ${TOXENV//-/ } - fi +after_success: codecov --required -X gcov fix pycov -f coverage.xml --flags ${TOXENV//-/ } branches: except: templates/1.5.x templates/1.6.x -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 - condition: "$TOXENV = py36-dj111" +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 5048330..89a0335 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,7 +1,9 @@ include README.rst +include CONTRIBUTING.md include AUTHORS include .travis.yml -include tasks.py +include tox.ini recursive-include tests * recursive-include docs * +recursive-include test_project * include LICENSE diff --git a/configurations/__init__.py b/configurations/__init__.py index 069756e..bd06566 100644 --- a/configurations/__init__.py +++ b/configurations/__init__.py @@ -1,8 +1,8 @@ -# flake8: noqa -from .base import Configuration -from .decorators import pristinemethod +from .base import Configuration # noqa +from .decorators import pristinemethod # noqa +from .version import __version__ # noqa + -__version__ = '2.1' __all__ = ['Configuration', 'pristinemethod'] diff --git a/configurations/base.py b/configurations/base.py index 1f38cf0..07f96df 100644 --- a/configurations/base.py +++ b/configurations/base.py @@ -33,6 +33,10 @@ def __new__(cls, name, bases, attrs): for base in bases[::-1]: settings_vars.update(uppercase_attributes(base)) attrs = dict(settings_vars, **attrs) + # Fix ImproperlyConfigured issue introduced in Django + # 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) def __repr__(self): diff --git a/configurations/importer.py b/configurations/importer.py index 38bddbf..4997380 100644 --- a/configurations/importer.py +++ b/configurations/importer.py @@ -128,8 +128,8 @@ def stylize(text): and os.environ.get('RUN_MAIN') == 'true'): message = ("django-configurations version {0}, using " - "configuration '{1}'".format(__version__, - self.name)) + "configuration {1}".format(__version__ or "", + self.name)) self.logger.debug(stylize(message)) def find_module(self, fullname, path=None): diff --git a/configurations/version.py b/configurations/version.py new file mode 100644 index 0000000..10f8675 --- /dev/null +++ b/configurations/version.py @@ -0,0 +1,7 @@ +from pkg_resources import get_distribution, DistributionNotFound + +try: + __version__ = get_distribution(__name__).version +except DistributionNotFound: + # package is not installed + __version__ = None diff --git a/docs/changes.rst b/docs/changes.rst index 12ed102..2c983e3 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -3,7 +3,7 @@ Changelog --------- -v2.2 (2019-12-02) +v2.2 (2019-12-03) ^^^^^^^^^^^^^^^^^ - **BACKWARD INCOMPATIBLE** Drop support for Python 3.4. @@ -18,6 +18,9 @@ v2.2 (2019-12-02) - Replace ``django.utils.six`` with ``six`` to support Django >= 3. +- Start using tox-travis and setuptools-scm for simplified test harness + and release management. + v2.1 (2018-08-16) ^^^^^^^^^^^^^^^^^ diff --git a/docs/conf.py b/docs/conf.py index 03bebca..5e7bd64 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -14,6 +14,8 @@ import sys import os +from pkg_resources import get_distribution + # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. @@ -48,14 +50,10 @@ # |version| and |release|, also used in various other places throughout the # built documents. # -try: - from configurations import __version__ - # The short X.Y version. - version = '.'.join(__version__.split('.')[:2]) - # The full version, including alpha/beta/rc tags. - release = __version__ -except ImportError: - version = release = 'dev' +# The full version, including alpha/beta/rc tags. +release = get_distribution("django-configurations").version +# The short X.Y version. +version = ".".join(release.split(".")[:2]) # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/setup.cfg b/setup.cfg index 28c24e9..51a5b97 100644 --- a/setup.cfg +++ b/setup.cfg @@ -9,5 +9,5 @@ parallel = 1 include = configurations/*,tests/* [flake8] -exclude = .tox,docs/* +exclude = .tox,docs/*,.eggs ignore = E501,E127,E128,E124,W503 diff --git a/setup.py b/setup.py index 708bd62..aba91f2 100644 --- a/setup.py +++ b/setup.py @@ -1,38 +1,24 @@ from __future__ import print_function -import ast import os import codecs from setuptools import setup -class VersionFinder(ast.NodeVisitor): - def __init__(self): - self.version = None - - def visit_Assign(self, node): - if node.targets[0].id == '__version__': - self.version = node.value.s - - def read(*parts): filename = os.path.join(os.path.dirname(__file__), *parts) with codecs.open(filename, encoding='utf-8') as fp: return fp.read() -def find_version(*parts): - finder = VersionFinder() - finder.visit(ast.parse(read(*parts))) - return finder.version - - setup( name="django-configurations", - version=find_version("configurations", "__init__.py"), + use_scm_version={"version_scheme": "post-release", "local_scheme": "dirty-tag"}, + setup_requires=["setuptools_scm"], url='https://django-configurations.readthedocs.io/', license='BSD', description="A helper for organizing Django settings.", long_description=read('README.rst'), + long_description_content_type='text/x-rst', author='Jannis Leidel', author_email='jannis@leidel.info', packages=['configurations'], diff --git a/tox.ini b/tox.ini index e3e1ac1..e1df12f 100644 --- a/tox.ini +++ b/tox.ini @@ -4,21 +4,28 @@ usedevelop = true minversion = 1.8 whitelist_externals = sphinx-build envlist = - checkqa, - readme-py27, + 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} +[travis] +python = + 2.7: py27 + 3.5: py35 + 3.6: py36,flake8,readme + 3.7: py37 + 3.8: py38 + pypy3: pypy3 + [testenv] usedevelop = true setenv = DJANGO_SETTINGS_MODULE = tests.settings.main DJANGO_CONFIGURATION = Test - coverage: COVERAGE_PROCESS_START = {toxinidir}/setup.cfg - coverage: _TEST_RUN_PREFIX=coverage run + COVERAGE_PROCESS_START = {toxinidir}/setup.cfg deps = dj111: django>=1.11,<2.0 dj20: django>=2.0a1,<2.1 @@ -27,23 +34,23 @@ deps = dj30: django>=3.0a1,<3.1 djmaster: https://github.com/django/django/archive/master.tar.gz#egg=django py27,pypy: mock - coverage: coverage - coverage: coverage_enable_subprocess + coverage + coverage_enable_subprocess extras = testing commands = python --version - {env:_TEST_RUN_PREFIX:} {envbindir}/django-cadmin test -v2 {posargs:tests} - coverage: coverage combine . tests/docs - coverage: coverage report -m --skip-covered - -[testenv:readme-py27] -commands = python setup.py check -r -s -deps = readme_renderer + {envbindir}/coverage run {envbindir}/django-cadmin test -v2 {posargs:tests} + coverage combine . tests/docs + coverage report -m --skip-covered + coverage xml -[testenv:checkqa] +[testenv:py36-checkqa] commands = flake8 {toxinidir} - bandit -r {toxinidir} + check-manifest -v + python setup.py sdist + twine check dist/* deps = flake8 - bandit + twine + check-manifest