mirror of https://github.com/django/django.git
Fixed #30116 -- Dropped support for Python 3.5.
This commit is contained in:
parent
5a5c77d55d
commit
7e6b214ed3
2
INSTALL
2
INSTALL
|
@ -1,6 +1,6 @@
|
||||||
Thanks for downloading Django.
|
Thanks for downloading Django.
|
||||||
|
|
||||||
To install it, make sure you have Python 3.5 or greater installed. Then run
|
To install it, make sure you have Python 3.6 or greater installed. Then run
|
||||||
this command from the command prompt:
|
this command from the command prompt:
|
||||||
|
|
||||||
python setup.py install
|
python setup.py install
|
||||||
|
|
|
@ -77,10 +77,8 @@ def _check_lazy_references(apps, ignore=None):
|
||||||
"""
|
"""
|
||||||
operation, args, keywords = obj, [], {}
|
operation, args, keywords = obj, [], {}
|
||||||
while hasattr(operation, 'func'):
|
while hasattr(operation, 'func'):
|
||||||
# The or clauses are redundant but work around a bug (#25945) in
|
args.extend(getattr(operation, 'args', []))
|
||||||
# functools.partial in Python <= 3.5.1.
|
keywords.update(getattr(operation, 'keywords', {}))
|
||||||
args.extend(getattr(operation, 'args', []) or [])
|
|
||||||
keywords.update(getattr(operation, 'keywords', {}) or {})
|
|
||||||
operation = operation.func
|
operation = operation.func
|
||||||
return operation, args, keywords
|
return operation, args, keywords
|
||||||
|
|
||||||
|
|
|
@ -160,10 +160,6 @@ class BaseDatabaseFeatures:
|
||||||
# Support for the DISTINCT ON clause
|
# Support for the DISTINCT ON clause
|
||||||
can_distinct_on_fields = False
|
can_distinct_on_fields = False
|
||||||
|
|
||||||
# Does the backend decide to commit before SAVEPOINT statements
|
|
||||||
# when autocommit is disabled? https://bugs.python.org/issue8145#msg109965
|
|
||||||
autocommits_when_autocommit_is_off = False
|
|
||||||
|
|
||||||
# Does the backend prevent running SQL queries in broken transactions?
|
# Does the backend prevent running SQL queries in broken transactions?
|
||||||
atomic_transactions = True
|
atomic_transactions = True
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
import sys
|
|
||||||
|
|
||||||
from django.db.backends.base.features import BaseDatabaseFeatures
|
from django.db.backends.base.features import BaseDatabaseFeatures
|
||||||
|
|
||||||
from .base import Database
|
from .base import Database
|
||||||
|
@ -15,7 +13,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
||||||
supports_timezones = False
|
supports_timezones = False
|
||||||
max_query_params = 999
|
max_query_params = 999
|
||||||
supports_mixed_date_datetime_comparisons = False
|
supports_mixed_date_datetime_comparisons = False
|
||||||
autocommits_when_autocommit_is_off = sys.version_info < (3, 6)
|
|
||||||
can_introspect_autofield = True
|
can_introspect_autofield = True
|
||||||
can_introspect_decimal_field = False
|
can_introspect_decimal_field = False
|
||||||
can_introspect_duration_field = False
|
can_introspect_duration_field = False
|
||||||
|
|
|
@ -173,14 +173,6 @@ class Atomic(ContextDecorator):
|
||||||
connection.commit_on_exit = True
|
connection.commit_on_exit = True
|
||||||
connection.needs_rollback = False
|
connection.needs_rollback = False
|
||||||
if not connection.get_autocommit():
|
if not connection.get_autocommit():
|
||||||
# sqlite3 in Python < 3.6 doesn't handle transactions and
|
|
||||||
# savepoints properly when autocommit is off.
|
|
||||||
# Turning autocommit back on isn't an option; it would trigger
|
|
||||||
# a premature commit. Give up if that happens.
|
|
||||||
if connection.features.autocommits_when_autocommit_is_off:
|
|
||||||
raise TransactionManagementError(
|
|
||||||
"Your database backend doesn't behave properly when "
|
|
||||||
"autocommit is off. Turn it on before using 'atomic'.")
|
|
||||||
# Pretend we're already in an atomic block to bypass the code
|
# Pretend we're already in an atomic block to bypass the code
|
||||||
# that disables autocommit to enter a transaction, and make a
|
# that disables autocommit to enter a transaction, and make a
|
||||||
# note to deal with this case in __exit__.
|
# note to deal with this case in __exit__.
|
||||||
|
|
|
@ -3,8 +3,6 @@ import itertools
|
||||||
import operator
|
import operator
|
||||||
from functools import total_ordering, wraps
|
from functools import total_ordering, wraps
|
||||||
|
|
||||||
from django.utils.version import PY36, get_docs_version
|
|
||||||
|
|
||||||
|
|
||||||
# You can't trivially replace this with `functools.partial` because this binds
|
# You can't trivially replace this with `functools.partial` because this binds
|
||||||
# to classes and returns bound instances, whereas functools.partial (on
|
# to classes and returns bound instances, whereas functools.partial (on
|
||||||
|
@ -22,8 +20,8 @@ class cached_property:
|
||||||
|
|
||||||
A cached property can be made out of an existing method:
|
A cached property can be made out of an existing method:
|
||||||
(e.g. ``url = cached_property(get_absolute_url)``).
|
(e.g. ``url = cached_property(get_absolute_url)``).
|
||||||
On Python < 3.6, the optional ``name`` argument must be provided, e.g.
|
The optional ``name`` argument is obsolete as of Python 3.6 and will be
|
||||||
``url = cached_property(get_absolute_url, name='url')``.
|
deprecated in Django 4.0 (#30127).
|
||||||
"""
|
"""
|
||||||
name = None
|
name = None
|
||||||
|
|
||||||
|
@ -34,29 +32,8 @@ class cached_property:
|
||||||
'__set_name__() on it.'
|
'__set_name__() on it.'
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _is_mangled(name):
|
|
||||||
return name.startswith('__') and not name.endswith('__')
|
|
||||||
|
|
||||||
def __init__(self, func, name=None):
|
def __init__(self, func, name=None):
|
||||||
if PY36:
|
self.real_func = func
|
||||||
self.real_func = func
|
|
||||||
else:
|
|
||||||
func_name = func.__name__
|
|
||||||
name = name or func_name
|
|
||||||
if not (isinstance(name, str) and name.isidentifier()):
|
|
||||||
raise ValueError(
|
|
||||||
"%r can't be used as the name of a cached_property." % name,
|
|
||||||
)
|
|
||||||
if self._is_mangled(name):
|
|
||||||
raise ValueError(
|
|
||||||
'cached_property does not work with mangled methods on '
|
|
||||||
'Python < 3.6 without the appropriate `name` argument. See '
|
|
||||||
'https://docs.djangoproject.com/en/%s/ref/utils/'
|
|
||||||
'#cached-property-mangled-name' % get_docs_version(),
|
|
||||||
)
|
|
||||||
self.name = name
|
|
||||||
self.func = func
|
|
||||||
self.__doc__ = getattr(func, '__doc__')
|
self.__doc__ = getattr(func, '__doc__')
|
||||||
|
|
||||||
def __set_name__(self, owner, name):
|
def __set_name__(self, owner, name):
|
||||||
|
|
|
@ -72,11 +72,10 @@ def module_has_submodule(package, module_name):
|
||||||
full_module_name = package_name + '.' + module_name
|
full_module_name = package_name + '.' + module_name
|
||||||
try:
|
try:
|
||||||
return importlib_find(full_module_name, package_path) is not None
|
return importlib_find(full_module_name, package_path) is not None
|
||||||
except (ImportError, AttributeError):
|
except (ModuleNotFoundError, AttributeError):
|
||||||
# When module_name is an invalid dotted path, Python raises ImportError
|
# When module_name is an invalid dotted path, Python raises
|
||||||
# (or ModuleNotFoundError in Python 3.6+). AttributeError may be raised
|
# ModuleNotFoundError. AttributeError is raised on PY36 (fixed in PY37)
|
||||||
# if the penultimate part of the path is not a package.
|
# if the penultimate part of the path is not a package.
|
||||||
# (https://bugs.python.org/issue30436)
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
@ -87,7 +86,7 @@ def module_dir(module):
|
||||||
Raise ValueError otherwise, e.g. for namespace packages that are split
|
Raise ValueError otherwise, e.g. for namespace packages that are split
|
||||||
over several directories.
|
over several directories.
|
||||||
"""
|
"""
|
||||||
# Convert to list because _NamespacePath does not support indexing on 3.3.
|
# Convert to list because _NamespacePath does not support indexing.
|
||||||
paths = list(getattr(module, '__path__', []))
|
paths = list(getattr(module, '__path__', []))
|
||||||
if len(paths) == 1:
|
if len(paths) == 1:
|
||||||
return paths[0]
|
return paths[0]
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
How to install Django on Windows
|
How to install Django on Windows
|
||||||
================================
|
================================
|
||||||
|
|
||||||
This document will guide you through installing Python 3.5 and Django on
|
This document will guide you through installing Python 3.7 and Django on
|
||||||
Windows. It also provides instructions for installing `virtualenv`_ and
|
Windows. It also provides instructions for installing `virtualenv`_ and
|
||||||
`virtualenvwrapper`_, which make it easier to work on Python projects. This is
|
`virtualenvwrapper`_, which make it easier to work on Python projects. This is
|
||||||
meant as a beginner's guide for users working on Django projects and does not
|
meant as a beginner's guide for users working on Django projects and does not
|
||||||
|
@ -17,12 +17,12 @@ Install Python
|
||||||
==============
|
==============
|
||||||
|
|
||||||
Django is a Python web framework, thus requiring Python to be installed on your
|
Django is a Python web framework, thus requiring Python to be installed on your
|
||||||
machine. At the time of writing, Python 3.5 is the latest version.
|
machine. At the time of writing, Python 3.7 is the latest version.
|
||||||
|
|
||||||
To install Python on your machine go to https://python.org/downloads/. The
|
To install Python on your machine go to https://python.org/downloads/. The
|
||||||
website should offer you a download button for the latest Python version.
|
website should offer you a download button for the latest Python version.
|
||||||
Download the executable installer and run it. Check the box next to ``Add
|
Download the executable installer and run it. Check the box next to ``Add
|
||||||
Python 3.5 to PATH`` and then click ``Install Now``.
|
Python 3.7 to PATH`` and then click ``Install Now``.
|
||||||
|
|
||||||
After installation, open the command prompt and check that the Python version
|
After installation, open the command prompt and check that the Python version
|
||||||
matches the version you installed by executing::
|
matches the version you installed by executing::
|
||||||
|
|
|
@ -90,12 +90,12 @@ In addition to the default environments, ``tox`` supports running unit tests
|
||||||
for other versions of Python and other database backends. Since Django's test
|
for other versions of Python and other database backends. Since Django's test
|
||||||
suite doesn't bundle a settings file for database backends other than SQLite,
|
suite doesn't bundle a settings file for database backends other than SQLite,
|
||||||
however, you must :ref:`create and provide your own test settings
|
however, you must :ref:`create and provide your own test settings
|
||||||
<running-unit-tests-settings>`. For example, to run the tests on Python 3.5
|
<running-unit-tests-settings>`. For example, to run the tests on Python 3.7
|
||||||
using PostgreSQL::
|
using PostgreSQL::
|
||||||
|
|
||||||
$ tox -e py35-postgres -- --settings=my_postgres_settings
|
$ tox -e py37-postgres -- --settings=my_postgres_settings
|
||||||
|
|
||||||
This command sets up a Python 3.5 virtual environment, installs Django's
|
This command sets up a Python 3.7 virtual environment, installs Django's
|
||||||
test suite dependencies (including those for PostgreSQL), and calls
|
test suite dependencies (including those for PostgreSQL), and calls
|
||||||
``runtests.py`` with the supplied arguments (in this case,
|
``runtests.py`` with the supplied arguments (in this case,
|
||||||
``--settings=my_postgres_settings``).
|
``--settings=my_postgres_settings``).
|
||||||
|
|
|
@ -219,8 +219,8 @@ this. For a small app like polls, this process isn't too difficult.
|
||||||
'License :: OSI Approved :: BSD License', # example license
|
'License :: OSI Approved :: BSD License', # example license
|
||||||
'Operating System :: OS Independent',
|
'Operating System :: OS Independent',
|
||||||
'Programming Language :: Python',
|
'Programming Language :: Python',
|
||||||
'Programming Language :: Python :: 3.5',
|
|
||||||
'Programming Language :: Python :: 3.6',
|
'Programming Language :: Python :: 3.6',
|
||||||
|
'Programming Language :: Python :: 3.7',
|
||||||
'Topic :: Internet :: WWW/HTTP',
|
'Topic :: Internet :: WWW/HTTP',
|
||||||
'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
|
'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
|
||||||
],
|
],
|
||||||
|
|
|
@ -23,7 +23,7 @@ in a shell prompt (indicated by the $ prefix):
|
||||||
If Django is installed, you should see the version of your installation. If it
|
If Django is installed, you should see the version of your installation. If it
|
||||||
isn't, you'll get an error telling "No module named django".
|
isn't, you'll get an error telling "No module named django".
|
||||||
|
|
||||||
This tutorial is written for Django |version|, which supports Python 3.5 and
|
This tutorial is written for Django |version|, which supports Python 3.6 and
|
||||||
later. If the Django version doesn't match, you can refer to the tutorial for
|
later. If the Django version doesn't match, you can refer to the tutorial for
|
||||||
your version of Django by using the version switcher at the bottom right corner
|
your version of Django by using the version switcher at the bottom right corner
|
||||||
of this page, or update Django to the newest version. If you're using an older
|
of this page, or update Django to the newest version. If you're using an older
|
||||||
|
|
|
@ -514,18 +514,6 @@ https://web.archive.org/web/20110718035220/http://diveintomark.org/archives/2004
|
||||||
z = person.friends # does not call
|
z = person.friends # does not call
|
||||||
x is z # is True
|
x is z # is True
|
||||||
|
|
||||||
.. warning::
|
|
||||||
|
|
||||||
.. _cached-property-mangled-name:
|
|
||||||
|
|
||||||
On Python < 3.6, ``cached_property`` doesn't work properly with a
|
|
||||||
mangled__ name unless it's passed a ``name`` of the form
|
|
||||||
``_Class__attribute``::
|
|
||||||
|
|
||||||
__friends = cached_property(get_friends, name='_Person__friends')
|
|
||||||
|
|
||||||
__ https://docs.python.org/faq/programming.html#i-try-to-use-spam-and-i-get-an-error-about-someclassname-spam
|
|
||||||
|
|
||||||
.. function:: keep_lazy(func, *resultclasses)
|
.. function:: keep_lazy(func, *resultclasses)
|
||||||
|
|
||||||
Django offers many utility functions (particularly in ``django.utils``)
|
Django offers many utility functions (particularly in ``django.utils``)
|
||||||
|
|
|
@ -1329,23 +1329,6 @@ The decorator can also be applied to test case classes::
|
||||||
decorator. For a given class, :func:`~django.test.modify_settings` is
|
decorator. For a given class, :func:`~django.test.modify_settings` is
|
||||||
always applied after :func:`~django.test.override_settings`.
|
always applied after :func:`~django.test.override_settings`.
|
||||||
|
|
||||||
.. admonition:: Considerations with Python 3.5
|
|
||||||
|
|
||||||
If using Python 3.5 (or older, if using an older version of Django), avoid
|
|
||||||
mixing ``remove`` with ``append`` and ``prepend`` in
|
|
||||||
:func:`~django.test.modify_settings`. In some cases it matters whether a
|
|
||||||
value is first added and then removed or vice versa, and dictionary key
|
|
||||||
order isn't preserved until Python 3.6. Instead, apply the decorator twice
|
|
||||||
to guarantee the order of operations. For example, to ensure that
|
|
||||||
``SessionMiddleware`` appears first in ``MIDDLEWARE``::
|
|
||||||
|
|
||||||
@modify_settings(MIDDLEWARE={
|
|
||||||
'remove': ['django.contrib.sessions.middleware.SessionMiddleware'],
|
|
||||||
)
|
|
||||||
@modify_settings(MIDDLEWARE={
|
|
||||||
'prepend': ['django.contrib.sessions.middleware.SessionMiddleware'],
|
|
||||||
})
|
|
||||||
|
|
||||||
.. warning::
|
.. warning::
|
||||||
|
|
||||||
The settings file contains some settings that are only consulted during
|
The settings file contains some settings that are only consulted during
|
||||||
|
|
3
setup.py
3
setup.py
|
@ -5,7 +5,7 @@ from distutils.sysconfig import get_python_lib
|
||||||
from setuptools import find_packages, setup
|
from setuptools import find_packages, setup
|
||||||
|
|
||||||
CURRENT_PYTHON = sys.version_info[:2]
|
CURRENT_PYTHON = sys.version_info[:2]
|
||||||
REQUIRED_PYTHON = (3, 5)
|
REQUIRED_PYTHON = (3, 6)
|
||||||
|
|
||||||
# This check and everything above must remain compatible with Python 2.7.
|
# This check and everything above must remain compatible with Python 2.7.
|
||||||
if CURRENT_PYTHON < REQUIRED_PYTHON:
|
if CURRENT_PYTHON < REQUIRED_PYTHON:
|
||||||
|
@ -98,7 +98,6 @@ setup(
|
||||||
'Operating System :: OS Independent',
|
'Operating System :: OS Independent',
|
||||||
'Programming Language :: Python',
|
'Programming Language :: Python',
|
||||||
'Programming Language :: Python :: 3',
|
'Programming Language :: Python :: 3',
|
||||||
'Programming Language :: Python :: 3.5',
|
|
||||||
'Programming Language :: Python :: 3.6',
|
'Programming Language :: Python :: 3.6',
|
||||||
'Programming Language :: Python :: 3.7',
|
'Programming Language :: Python :: 3.7',
|
||||||
'Programming Language :: Python :: 3 :: Only',
|
'Programming Language :: Python :: 3 :: Only',
|
||||||
|
|
|
@ -32,7 +32,6 @@ from django.db.migrations.recorder import MigrationRecorder
|
||||||
from django.test import (
|
from django.test import (
|
||||||
LiveServerTestCase, SimpleTestCase, TestCase, override_settings,
|
LiveServerTestCase, SimpleTestCase, TestCase, override_settings,
|
||||||
)
|
)
|
||||||
from django.utils.version import PY36
|
|
||||||
|
|
||||||
custom_templates_dir = os.path.join(os.path.dirname(__file__), 'custom_templates')
|
custom_templates_dir = os.path.join(os.path.dirname(__file__), 'custom_templates')
|
||||||
|
|
||||||
|
@ -1145,7 +1144,7 @@ class ManageCheck(AdminScriptTestCase):
|
||||||
args = ['check']
|
args = ['check']
|
||||||
out, err = self.run_manage(args)
|
out, err = self.run_manage(args)
|
||||||
self.assertNoOutput(out)
|
self.assertNoOutput(out)
|
||||||
self.assertOutput(err, 'ModuleNotFoundError' if PY36 else 'ImportError')
|
self.assertOutput(err, 'ModuleNotFoundError')
|
||||||
self.assertOutput(err, 'No module named')
|
self.assertOutput(err, 'No module named')
|
||||||
self.assertOutput(err, 'admin_scriptz')
|
self.assertOutput(err, 'admin_scriptz')
|
||||||
|
|
||||||
|
|
|
@ -1211,10 +1211,7 @@ class FakeSMTPServer(smtpd.SMTPServer, threading.Thread):
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
threading.Thread.__init__(self)
|
threading.Thread.__init__(self)
|
||||||
# New kwarg added in Python 3.5; default switching to False in 3.6.
|
smtpd.SMTPServer.__init__(self, *args, decode_data=True, **kwargs)
|
||||||
# Setting a value only silences a deprecation warning in Python 3.5.
|
|
||||||
kwargs['decode_data'] = True
|
|
||||||
smtpd.SMTPServer.__init__(self, *args, **kwargs)
|
|
||||||
self._sink = []
|
self._sink = []
|
||||||
self.active = False
|
self.active = False
|
||||||
self.active_lock = threading.Lock()
|
self.active_lock = threading.Lock()
|
||||||
|
|
|
@ -22,7 +22,6 @@ from django.utils.deconstruct import deconstructible
|
||||||
from django.utils.functional import SimpleLazyObject
|
from django.utils.functional import SimpleLazyObject
|
||||||
from django.utils.timezone import get_default_timezone, get_fixed_timezone, utc
|
from django.utils.timezone import get_default_timezone, get_fixed_timezone, utc
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.utils.version import PY36
|
|
||||||
|
|
||||||
from .models import FoodManager, FoodQuerySet
|
from .models import FoodManager, FoodQuerySet
|
||||||
|
|
||||||
|
@ -413,10 +412,7 @@ class WriterTests(SimpleTestCase):
|
||||||
# Test a string regex with flag
|
# Test a string regex with flag
|
||||||
validator = RegexValidator(r'^[0-9]+$', flags=re.S)
|
validator = RegexValidator(r'^[0-9]+$', flags=re.S)
|
||||||
string = MigrationWriter.serialize(validator)[0]
|
string = MigrationWriter.serialize(validator)[0]
|
||||||
if PY36:
|
self.assertEqual(string, "django.core.validators.RegexValidator('^[0-9]+$', flags=re.RegexFlag(16))")
|
||||||
self.assertEqual(string, "django.core.validators.RegexValidator('^[0-9]+$', flags=re.RegexFlag(16))")
|
|
||||||
else:
|
|
||||||
self.assertEqual(string, "django.core.validators.RegexValidator('^[0-9]+$', flags=16)")
|
|
||||||
self.serialize_round_trip(validator)
|
self.serialize_round_trip(validator)
|
||||||
|
|
||||||
# Test message and code
|
# Test message and code
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
import unittest
|
|
||||||
from operator import attrgetter
|
from operator import attrgetter
|
||||||
|
|
||||||
from django.core.exceptions import FieldError, ValidationError
|
from django.core.exceptions import FieldError, ValidationError
|
||||||
from django.db import connection, models
|
from django.db import connection, models
|
||||||
from django.test import SimpleTestCase, TestCase
|
from django.test import SimpleTestCase, TestCase
|
||||||
from django.test.utils import CaptureQueriesContext, isolate_apps
|
from django.test.utils import CaptureQueriesContext, isolate_apps
|
||||||
from django.utils.version import PY36
|
|
||||||
|
|
||||||
from .models import (
|
from .models import (
|
||||||
Base, Chef, CommonInfo, GrandChild, GrandParent, ItalianRestaurant,
|
Base, Chef, CommonInfo, GrandChild, GrandParent, ItalianRestaurant,
|
||||||
|
@ -176,7 +174,6 @@ class ModelInheritanceTests(TestCase):
|
||||||
|
|
||||||
self.assertIs(C._meta.parents[A], C._meta.get_field('a'))
|
self.assertIs(C._meta.parents[A], C._meta.get_field('a'))
|
||||||
|
|
||||||
@unittest.skipUnless(PY36, 'init_subclass is new in Python 3.6')
|
|
||||||
@isolate_apps('model_inheritance')
|
@isolate_apps('model_inheritance')
|
||||||
def test_init_subclass(self):
|
def test_init_subclass(self):
|
||||||
saved_kwargs = {}
|
saved_kwargs = {}
|
||||||
|
@ -193,7 +190,6 @@ class ModelInheritanceTests(TestCase):
|
||||||
|
|
||||||
self.assertEqual(saved_kwargs, kwargs)
|
self.assertEqual(saved_kwargs, kwargs)
|
||||||
|
|
||||||
@unittest.skipUnless(PY36, '__set_name__ is new in Python 3.6')
|
|
||||||
@isolate_apps('model_inheritance')
|
@isolate_apps('model_inheritance')
|
||||||
def test_set_name(self):
|
def test_set_name(self):
|
||||||
class ClassAttr:
|
class ClassAttr:
|
||||||
|
|
|
@ -234,7 +234,7 @@ def teardown(state):
|
||||||
# Discard the multiprocessing.util finalizer that tries to remove a
|
# Discard the multiprocessing.util finalizer that tries to remove a
|
||||||
# temporary directory that's already removed by this script's
|
# temporary directory that's already removed by this script's
|
||||||
# atexit.register(shutil.rmtree, TMPDIR) handler. Prevents
|
# atexit.register(shutil.rmtree, TMPDIR) handler. Prevents
|
||||||
# FileNotFoundError at the end of a test run on Python 3.6+ (#27890).
|
# FileNotFoundError at the end of a test run (#27890).
|
||||||
from multiprocessing.util import _finalizer_registry
|
from multiprocessing.util import _finalizer_registry
|
||||||
_finalizer_registry.pop((-100, 0), None)
|
_finalizer_registry.pop((-100, 0), None)
|
||||||
|
|
||||||
|
|
|
@ -228,7 +228,6 @@ class AtomicInsideTransactionTests(AtomicTests):
|
||||||
self.atomic.__exit__(*sys.exc_info())
|
self.atomic.__exit__(*sys.exc_info())
|
||||||
|
|
||||||
|
|
||||||
@skipIfDBFeature('autocommits_when_autocommit_is_off')
|
|
||||||
class AtomicWithoutAutocommitTests(AtomicTests):
|
class AtomicWithoutAutocommitTests(AtomicTests):
|
||||||
"""All basic tests for atomic should also pass when autocommit is turned off."""
|
"""All basic tests for atomic should also pass when autocommit is turned off."""
|
||||||
|
|
||||||
|
@ -480,7 +479,6 @@ class AtomicMiscTests(TransactionTestCase):
|
||||||
Reporter.objects.create()
|
Reporter.objects.create()
|
||||||
|
|
||||||
|
|
||||||
@skipIfDBFeature('autocommits_when_autocommit_is_off')
|
|
||||||
class NonAutocommitTests(TransactionTestCase):
|
class NonAutocommitTests(TransactionTestCase):
|
||||||
|
|
||||||
available_apps = []
|
available_apps = []
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
import unittest
|
|
||||||
|
|
||||||
from django.test import SimpleTestCase
|
from django.test import SimpleTestCase
|
||||||
from django.utils.functional import cached_property, lazy
|
from django.utils.functional import cached_property, lazy
|
||||||
from django.utils.version import PY36
|
|
||||||
|
|
||||||
|
|
||||||
class FunctionalTests(SimpleTestCase):
|
class FunctionalTests(SimpleTestCase):
|
||||||
|
@ -104,7 +101,6 @@ class FunctionalTests(SimpleTestCase):
|
||||||
for attr in attrs:
|
for attr in attrs:
|
||||||
self.assertCachedPropertyWorks(attr, Class)
|
self.assertCachedPropertyWorks(attr, Class)
|
||||||
|
|
||||||
@unittest.skipUnless(PY36, '__set_name__ is new in Python 3.6')
|
|
||||||
def test_cached_property_auto_name(self):
|
def test_cached_property_auto_name(self):
|
||||||
"""
|
"""
|
||||||
cached_property caches its value and behaves like a property
|
cached_property caches its value and behaves like a property
|
||||||
|
@ -132,7 +128,6 @@ class FunctionalTests(SimpleTestCase):
|
||||||
obj.other2
|
obj.other2
|
||||||
self.assertFalse(hasattr(obj, 'different_name'))
|
self.assertFalse(hasattr(obj, 'different_name'))
|
||||||
|
|
||||||
@unittest.skipUnless(PY36, '__set_name__ is new in Python 3.6')
|
|
||||||
def test_cached_property_reuse_different_names(self):
|
def test_cached_property_reuse_different_names(self):
|
||||||
"""Disallow this case because the decorated function wouldn't be cached."""
|
"""Disallow this case because the decorated function wouldn't be cached."""
|
||||||
with self.assertRaises(RuntimeError) as ctx:
|
with self.assertRaises(RuntimeError) as ctx:
|
||||||
|
@ -151,7 +146,6 @@ class FunctionalTests(SimpleTestCase):
|
||||||
))
|
))
|
||||||
)
|
)
|
||||||
|
|
||||||
@unittest.skipUnless(PY36, '__set_name__ is new in Python 3.6')
|
|
||||||
def test_cached_property_reuse_same_name(self):
|
def test_cached_property_reuse_same_name(self):
|
||||||
"""
|
"""
|
||||||
Reusing a cached_property on different classes under the same name is
|
Reusing a cached_property on different classes under the same name is
|
||||||
|
@ -177,7 +171,6 @@ class FunctionalTests(SimpleTestCase):
|
||||||
self.assertEqual(b.cp, 2)
|
self.assertEqual(b.cp, 2)
|
||||||
self.assertEqual(a.cp, 1)
|
self.assertEqual(a.cp, 1)
|
||||||
|
|
||||||
@unittest.skipUnless(PY36, '__set_name__ is new in Python 3.6')
|
|
||||||
def test_cached_property_set_name_not_called(self):
|
def test_cached_property_set_name_not_called(self):
|
||||||
cp = cached_property(lambda s: None)
|
cp = cached_property(lambda s: None)
|
||||||
|
|
||||||
|
@ -189,29 +182,6 @@ class FunctionalTests(SimpleTestCase):
|
||||||
with self.assertRaisesMessage(TypeError, msg):
|
with self.assertRaisesMessage(TypeError, msg):
|
||||||
Foo().cp
|
Foo().cp
|
||||||
|
|
||||||
@unittest.skipIf(PY36, '__set_name__ is new in Python 3.6')
|
|
||||||
def test_cached_property_mangled_error(self):
|
|
||||||
msg = (
|
|
||||||
'cached_property does not work with mangled methods on '
|
|
||||||
'Python < 3.6 without the appropriate `name` argument.'
|
|
||||||
)
|
|
||||||
with self.assertRaisesMessage(ValueError, msg):
|
|
||||||
@cached_property
|
|
||||||
def __value(self):
|
|
||||||
pass
|
|
||||||
with self.assertRaisesMessage(ValueError, msg):
|
|
||||||
def func(self):
|
|
||||||
pass
|
|
||||||
cached_property(func, name='__value')
|
|
||||||
|
|
||||||
@unittest.skipIf(PY36, '__set_name__ is new in Python 3.6')
|
|
||||||
def test_cached_property_name_validation(self):
|
|
||||||
msg = "%s can't be used as the name of a cached_property."
|
|
||||||
with self.assertRaisesMessage(ValueError, msg % "'<lambda>'"):
|
|
||||||
cached_property(lambda x: None)
|
|
||||||
with self.assertRaisesMessage(ValueError, msg % 42):
|
|
||||||
cached_property(str, name=42)
|
|
||||||
|
|
||||||
def test_lazy_equality(self):
|
def test_lazy_equality(self):
|
||||||
"""
|
"""
|
||||||
== and != work correctly for Promises.
|
== and != work correctly for Promises.
|
||||||
|
|
|
@ -17,7 +17,6 @@ from django.test.utils import LoggingCaptureMixin
|
||||||
from django.urls import path, reverse
|
from django.urls import path, reverse
|
||||||
from django.utils.functional import SimpleLazyObject
|
from django.utils.functional import SimpleLazyObject
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from django.utils.version import PY36
|
|
||||||
from django.views.debug import (
|
from django.views.debug import (
|
||||||
CLEANSED_SUBSTITUTE, CallableSettingWrapper, ExceptionReporter,
|
CLEANSED_SUBSTITUTE, CallableSettingWrapper, ExceptionReporter,
|
||||||
cleanse_setting, technical_500_response,
|
cleanse_setting, technical_500_response,
|
||||||
|
@ -515,7 +514,7 @@ class ExceptionReporterTests(SimpleTestCase):
|
||||||
exc_type, exc_value, tb = sys.exc_info()
|
exc_type, exc_value, tb = sys.exc_info()
|
||||||
reporter = ExceptionReporter(request, exc_type, exc_value, tb)
|
reporter = ExceptionReporter(request, exc_type, exc_value, tb)
|
||||||
html = reporter.get_traceback_html()
|
html = reporter.get_traceback_html()
|
||||||
self.assertInHTML('<h1>%sError at /test_view/</h1>' % ('ModuleNotFound' if PY36 else 'Import'), html)
|
self.assertInHTML('<h1>ModuleNotFoundError at /test_view/</h1>', html)
|
||||||
|
|
||||||
def test_ignore_traceback_evaluation_exceptions(self):
|
def test_ignore_traceback_evaluation_exceptions(self):
|
||||||
"""
|
"""
|
||||||
|
|
2
tox.ini
2
tox.ini
|
@ -21,7 +21,7 @@ passenv = DJANGO_SETTINGS_MODULE PYTHONPATH HOME DISPLAY
|
||||||
setenv =
|
setenv =
|
||||||
PYTHONDONTWRITEBYTECODE=1
|
PYTHONDONTWRITEBYTECODE=1
|
||||||
deps =
|
deps =
|
||||||
py{3,35,36,37}: -rtests/requirements/py3.txt
|
py{3,36,37}: -rtests/requirements/py3.txt
|
||||||
postgres: -rtests/requirements/postgres.txt
|
postgres: -rtests/requirements/postgres.txt
|
||||||
mysql: -rtests/requirements/mysql.txt
|
mysql: -rtests/requirements/mysql.txt
|
||||||
oracle: -rtests/requirements/oracle.txt
|
oracle: -rtests/requirements/oracle.txt
|
||||||
|
|
Loading…
Reference in New Issue