From f039366bf00e9a7ff72d7421073305e620db6174 Mon Sep 17 00:00:00 2001 From: medmunds Date: Mon, 25 Jan 2021 11:32:02 -0800 Subject: [PATCH] Test against Django 3.2 prerelease * Omit default_app_config under Django 3.2 and later to avoid DeprecationWarning * Also adds testing on Python 3.9, 3.10-alpha * Also updates test matrix to include all supported Python versions (some older Django versions expanded Python support in patch releases) --- .github/workflows/test.yml | 65 +++++++++------ CHANGELOG.rst | 2 + anymail/__init__.py | 4 +- tests/test_settings/settings_4_0.py | 121 ++++++++++++++++++++++++++++ tox.ini | 14 ++-- 5 files changed, 173 insertions(+), 33 deletions(-) create mode 100644 tests/test_settings/settings_4_0.py diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6f04251..94f1a1b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,7 +18,7 @@ jobs: fail-fast: false matrix: config: - - { tox: "lint,docs", python: 3.8 } + - { tox: "lint,docs", python: "3.8" } # Anymail supports the same Python versions as Django, plus PyPy. # https://docs.djangoproject.com/en/dev/faq/install/#what-python-version-can-i-use-with-django @@ -27,36 +27,49 @@ jobs: # combinations, to avoid rapidly consuming the testing accounts' entire send allotments. # Django 2.0: Python 3.5+ - - { tox: django20-py35-all, python: 3.5 } - - { tox: django20-py36-all, python: 3.6 } - - { tox: django20-pypy3-all, python: pypy3 } + - { tox: django20-py35-all, python: "3.5" } + - { tox: django20-py36-all, python: "3.6" } + - { tox: django20-pypy3-all, python: "pypy3" } # Django 2.1: Python 3.5, 3.6, or 3.7 - - { tox: django21-py35-all, python: 3.5 } - - { tox: django21-py36-all, python: 3.6 } - - { tox: django21-py37-all, python: 3.7 } + - { tox: django21-py35-all, python: "3.5" } + - { tox: django21-py36-all, python: "3.6" } + - { tox: django21-py37-all, python: "3.7" } - { tox: django21-pypy3-all, python: pypy3 } - # Django 2.2: Python 3.5, 3.6, or 3.7 - - { tox: django22-py35-all, python: 3.5 } - - { tox: django22-py36-all, python: 3.6 } - - { tox: django22-py37-all, python: 3.7 } - - { tox: django22-pypy3-all, python: pypy3 } - # Django 3.0: Python 3.6, 3.7, or 3.8 - - { tox: django30-py36-all, python: 3.6 } - - { tox: django30-py37-all, python: 3.7 } - - { tox: django30-py38-all, python: 3.8 } - - { tox: django30-pypy3-all, python: pypy3 } - # Django 3.1: Python 3.6, 3.7, or 3.8 - - { tox: django31-py36-all, python: 3.6 } - - { tox: django31-py37-all, python: 3.7 } - - { tox: django31-py38-all, python: 3.8, options: run-live-tests } - - { tox: django31-pypy3-all, python: pypy3 } + # Django 2.2: Python 3.5, 3.6, 3.7, 3.8 (added in 2.2.8), 3.9 (added in 2.2.17) + - { tox: django22-py35-all, python: "3.5" } + - { tox: django22-py36-all, python: "3.6" } + - { tox: django22-py37-all, python: "3.7" } + - { tox: django22-py38-all, python: "3.8" } + - { tox: django22-py39-all, python: "3.9" } + - { tox: django22-pypy3-all, python: "pypy3" } + # Django 3.0: Python 3.6, 3.7, 3.8, 3.9 (added in 3.0.11) + - { tox: django30-py36-all, python: "3.6" } + - { tox: django30-py37-all, python: "3.7" } + - { tox: django30-py38-all, python: "3.8" } + - { tox: django30-py39-all, python: "3.9" } + - { tox: django30-pypy3-all, python: "pypy3" } + # Django 3.1: Python 3.6, 3.7, 3.8, 3.9 (added in 3.1.3) + - { tox: django31-py36-all, python: "3.6" } + - { tox: django31-py37-all, python: "3.7" } + - { tox: django31-py38-all, python: "3.8", options: run-live-tests } + - { tox: django31-py39-all, python: "3.9" } + - { tox: django31-pypy3-all, python: "pypy3" } + # Django 3.2: Python 3.6, 3.7, 3.8, 3.9 + - { tox: django32-py36-all, python: "3.6" } + - { tox: django32-py37-all, python: "3.7" } + - { tox: django32-py38-all, python: "3.8" } + - { tox: django32-py39-all, python: "3.9" } + - { tox: django32-pypy3-all, python: "pypy3" } + # Django 4.0: Python 3.8, 3.9, 3.10 # Django current development (direct from GitHub source) - - { tox: djangoDev-py37-all, python: 3.7, options: allow-failures } + - { tox: djangoDev-py38-all, python: "3.8", options: allow-failures } + - { tox: djangoDev-py39-all, python: "3.9", options: allow-failures } + - { tox: djangoDev-py310-all, python: "3.10.0-alpha - 3.10", options: allow-failures } # Install without optional extras (don't need to cover entire matrix) - - { tox: django31-py37-none, python: 3.7 } - - { tox: django31-py37-amazon_ses, python: 3.7 } + - { tox: django31-py37-none, python: "3.7" } + - { tox: django31-py37-amazon_ses, python: "3.7" } # Test some specific older package versions - - { tox: django22-py37-all-old_urllib3, python: 3.7 } + - { tox: django22-py37-all-old_urllib3, python: "3.7" } steps: - name: Get code diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 97e96b7..e50e8bc 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -40,6 +40,8 @@ Fixes Other ~~~~~ +* Test against Django 3.2 prerelease (including support for Python 3.9) + * Move CI testing to GitHub Actions (and stop using Travis-CI). * Internal: catch invalid recipient status earlier in ESP response parsing diff --git a/anymail/__init__.py b/anymail/__init__.py index 05f1d49..41ebe06 100644 --- a/anymail/__init__.py +++ b/anymail/__init__.py @@ -2,4 +2,6 @@ from ._version import __version__, VERSION # NOQA: F401 -default_app_config = 'anymail.apps.AnymailBaseConfig' +from django import VERSION as DJANGO_VERSION +if DJANGO_VERSION < (3, 2, 0): + default_app_config = 'anymail.apps.AnymailBaseConfig' diff --git a/tests/test_settings/settings_4_0.py b/tests/test_settings/settings_4_0.py new file mode 100644 index 0000000..788eba6 --- /dev/null +++ b/tests/test_settings/settings_4_0.py @@ -0,0 +1,121 @@ +""" +Django settings for Anymail tests. + +Generated by 'django-admin startproject' using Django 3.1. + +For more information on this file, see +https://docs.djangoproject.com/en/dev/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/dev/ref/settings/ +""" + +import os + +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/dev/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = 'NOT_FOR_PRODUCTION_USE' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'anymail', +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = 'tests.test_settings.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'tests.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/dev/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), + } +} + + +# Password validation +# https://docs.djangoproject.com/en/dev/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/dev/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/dev/howto/static-files/ + +STATIC_URL = '/static/' diff --git a/tox.ini b/tox.ini index ed84e55..a316e49 100644 --- a/tox.ini +++ b/tox.ini @@ -3,17 +3,18 @@ envlist = # Factors: django-python-extras # Test these environments first, to catch most errors early... lint - django31-py38-all + django31-py39-all django20-py35-all docs # ... then test all the other supported combinations: - django31-py{36,37,py3}-all - django30-py{36,37,38,py3}-all - django22-py{35,36,37,py3}-all + django31-py{36,37,38,py3}-all + django30-py{36,37,38,39,py3}-all + django22-py{35,36,37,38,39,py3}-all django21-py{35,36,37,py3}-all django20-py{36,py3}-all # ... then prereleases (if available): - djangoDev-py{36,37,38}-all + django32-py{36,37,38,39,py3}-all + djangoDev-py{38,39,310,py3}-all # ... then partial installation (limit extras): django31-py37-{none,amazon_ses} # ... then older versions of some dependencies: @@ -25,7 +26,8 @@ deps = django21: django~=2.1.0 django22: django~=2.2.0 django30: django~=3.0.0 - django31: django>=3.1rc1 + django31: django~=3.1.0 + django32: django>=3.2a1 djangoDev: https://github.com/django/django/tarball/master old_urllib3: urllib3<1.25 # testing dependencies (duplicates setup.py tests_require, less optional extras):