mirror of
https://github.com/django/django.git
synced 2025-03-13 02:40:47 +00:00
Fixed #36005 -- Dropped support for Python 3.10 and 3.11.
This commit is contained in:
parent
61dae11df5
commit
f5772de696
60
.github/workflows/schedule_tests.yml
vendored
60
.github/workflows/schedule_tests.yml
vendored
@ -16,8 +16,6 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
python-version:
|
python-version:
|
||||||
- '3.10'
|
|
||||||
- '3.11'
|
|
||||||
- '3.12'
|
- '3.12'
|
||||||
- '3.13'
|
- '3.13'
|
||||||
- '3.14-dev'
|
- '3.14-dev'
|
||||||
@ -64,64 +62,6 @@ jobs:
|
|||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: python -Wall tests/runtests.py --verbosity=2
|
run: python -Wall tests/runtests.py --verbosity=2
|
||||||
|
|
||||||
pypy-sqlite:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
name: Ubuntu, SQLite, PyPy3.10
|
|
||||||
continue-on-error: true
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
- name: Set up Python
|
|
||||||
uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version: pypy-3.10-nightly
|
|
||||||
cache: 'pip'
|
|
||||||
cache-dependency-path: 'tests/requirements/py3.txt'
|
|
||||||
- name: Install libmemcached-dev for pylibmc
|
|
||||||
run: sudo apt-get install libmemcached-dev
|
|
||||||
- name: Install and upgrade packaging tools
|
|
||||||
run: python -m pip install --upgrade pip setuptools wheel
|
|
||||||
- run: python -m pip install -r tests/requirements/py3.txt -e .
|
|
||||||
- name: Run tests
|
|
||||||
run: python -Wall tests/runtests.py --verbosity=2
|
|
||||||
|
|
||||||
pypy-postgresql:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
name: Ubuntu, PostgreSQL, PyPy3.10
|
|
||||||
continue-on-error: true
|
|
||||||
services:
|
|
||||||
postgres:
|
|
||||||
image: postgres:14-alpine
|
|
||||||
env:
|
|
||||||
POSTGRES_DB: django
|
|
||||||
POSTGRES_USER: user
|
|
||||||
POSTGRES_PASSWORD: postgres
|
|
||||||
ports:
|
|
||||||
- 5432:5432
|
|
||||||
options: >-
|
|
||||||
--health-cmd pg_isready
|
|
||||||
--health-interval 10s
|
|
||||||
--health-timeout 5s
|
|
||||||
--health-retries 5
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
- name: Set up Python
|
|
||||||
uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version: pypy-3.10-nightly
|
|
||||||
cache: 'pip'
|
|
||||||
cache-dependency-path: 'tests/requirements/py3.txt'
|
|
||||||
- name: Install libmemcached-dev for pylibmc
|
|
||||||
run: sudo apt-get install libmemcached-dev
|
|
||||||
- name: Install and upgrade packaging tools
|
|
||||||
run: python -m pip install --upgrade pip setuptools wheel
|
|
||||||
- run: python -m pip install -r tests/requirements/py3.txt -r tests/requirements/postgres.txt -e .
|
|
||||||
- name: Create PostgreSQL settings file
|
|
||||||
run: mv ./.github/workflows/data/test_postgres.py.tpl ./tests/test_postgres.py
|
|
||||||
- name: Run tests
|
|
||||||
run: python -Wall tests/runtests.py --settings=test_postgres --verbosity=2
|
|
||||||
|
|
||||||
javascript-tests:
|
javascript-tests:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
name: JavaScript tests
|
name: JavaScript tests
|
||||||
|
2
.github/workflows/screenshots.yml
vendored
2
.github/workflows/screenshots.yml
vendored
@ -24,7 +24,7 @@ jobs:
|
|||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v5
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: '3.11'
|
python-version: '3.13'
|
||||||
cache: 'pip'
|
cache: 'pip'
|
||||||
cache-dependency-path: 'tests/requirements/py3.txt'
|
cache-dependency-path: 'tests/requirements/py3.txt'
|
||||||
- name: Install and upgrade packaging tools
|
- name: Install and upgrade packaging tools
|
||||||
|
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.10 or greater installed. Then run
|
To install it, make sure you have Python 3.12 or greater installed. Then run
|
||||||
this command from the command prompt:
|
this command from the command prompt:
|
||||||
|
|
||||||
python -m pip install .
|
python -m pip install .
|
||||||
|
@ -16,7 +16,7 @@ from django.db import models
|
|||||||
from django.db.migrations.operations.base import Operation
|
from django.db.migrations.operations.base import Operation
|
||||||
from django.db.migrations.utils import COMPILED_REGEX_TYPE, RegexObject
|
from django.db.migrations.utils import COMPILED_REGEX_TYPE, RegexObject
|
||||||
from django.utils.functional import LazyObject, Promise
|
from django.utils.functional import LazyObject, Promise
|
||||||
from django.utils.version import PY311, get_docs_version
|
from django.utils.version import get_docs_version
|
||||||
|
|
||||||
FUNCTION_TYPES = (types.FunctionType, types.BuiltinFunctionType, types.MethodType)
|
FUNCTION_TYPES = (types.FunctionType, types.BuiltinFunctionType, types.MethodType)
|
||||||
|
|
||||||
@ -140,11 +140,7 @@ class EnumSerializer(BaseSerializer):
|
|||||||
enum_class = self.value.__class__
|
enum_class = self.value.__class__
|
||||||
module = enum_class.__module__
|
module = enum_class.__module__
|
||||||
if issubclass(enum_class, enum.Flag):
|
if issubclass(enum_class, enum.Flag):
|
||||||
if PY311:
|
|
||||||
members = list(self.value)
|
members = list(self.value)
|
||||||
else:
|
|
||||||
members, _ = enum._decompose(enum_class, self.value)
|
|
||||||
members = reversed(members)
|
|
||||||
else:
|
else:
|
||||||
members = (self.value,)
|
members = (self.value,)
|
||||||
return (
|
return (
|
||||||
|
@ -1,25 +1,8 @@
|
|||||||
import enum
|
import enum
|
||||||
|
|
||||||
from django.utils.functional import Promise
|
|
||||||
from django.utils.version import PY311, PY312
|
|
||||||
|
|
||||||
if PY311:
|
|
||||||
from enum import EnumType, IntEnum, StrEnum
|
from enum import EnumType, IntEnum, StrEnum
|
||||||
from enum import property as enum_property
|
from enum import property as enum_property
|
||||||
else:
|
|
||||||
from enum import EnumMeta as EnumType
|
|
||||||
from types import DynamicClassAttribute as enum_property
|
|
||||||
|
|
||||||
class ReprEnum(enum.Enum):
|
|
||||||
def __str__(self):
|
|
||||||
return str(self.value)
|
|
||||||
|
|
||||||
class IntEnum(int, ReprEnum):
|
|
||||||
pass
|
|
||||||
|
|
||||||
class StrEnum(str, ReprEnum):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
from django.utils.functional import Promise
|
||||||
|
|
||||||
__all__ = ["Choices", "IntegerChoices", "TextChoices"]
|
__all__ = ["Choices", "IntegerChoices", "TextChoices"]
|
||||||
|
|
||||||
@ -49,14 +32,6 @@ class ChoicesType(EnumType):
|
|||||||
member._label_ = label
|
member._label_ = label
|
||||||
return enum.unique(cls)
|
return enum.unique(cls)
|
||||||
|
|
||||||
if not PY312:
|
|
||||||
|
|
||||||
def __contains__(cls, member):
|
|
||||||
if not isinstance(member, enum.Enum):
|
|
||||||
# Allow non-enums to match against member values.
|
|
||||||
return any(x.value == member for x in cls)
|
|
||||||
return super().__contains__(member)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def names(cls):
|
def names(cls):
|
||||||
empty = ["__empty__"] if hasattr(cls, "__empty__") else []
|
empty = ["__empty__"] if hasattr(cls, "__empty__") else []
|
||||||
@ -79,13 +54,7 @@ class ChoicesType(EnumType):
|
|||||||
class Choices(enum.Enum, metaclass=ChoicesType):
|
class Choices(enum.Enum, metaclass=ChoicesType):
|
||||||
"""Class for creating enumerated choices."""
|
"""Class for creating enumerated choices."""
|
||||||
|
|
||||||
if PY311:
|
|
||||||
do_not_call_in_templates = enum.nonmember(True)
|
do_not_call_in_templates = enum.nonmember(True)
|
||||||
else:
|
|
||||||
|
|
||||||
@property
|
|
||||||
def do_not_call_in_templates(self):
|
|
||||||
return True
|
|
||||||
|
|
||||||
@enum_property
|
@enum_property
|
||||||
def label(self):
|
def label(self):
|
||||||
|
@ -14,7 +14,6 @@ from django.db.models.fields import Field
|
|||||||
from django.db.models.query_utils import DeferredAttribute
|
from django.db.models.query_utils import DeferredAttribute
|
||||||
from django.db.models.utils import AltersData
|
from django.db.models.utils import AltersData
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.utils.version import PY311
|
|
||||||
|
|
||||||
|
|
||||||
class FieldFile(File, AltersData):
|
class FieldFile(File, AltersData):
|
||||||
@ -329,7 +328,7 @@ class FileField(Field):
|
|||||||
f"File for {self.name} must have "
|
f"File for {self.name} must have "
|
||||||
"the name attribute specified to be saved."
|
"the name attribute specified to be saved."
|
||||||
)
|
)
|
||||||
if PY311 and isinstance(file._file, ContentFile):
|
if isinstance(file._file, ContentFile):
|
||||||
exc.add_note("Pass a 'name' argument to ContentFile.")
|
exc.add_note("Pass a 'name' argument to ContentFile.")
|
||||||
raise exc
|
raise exc
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ from django.test.utils import setup_test_environment
|
|||||||
from django.test.utils import teardown_databases as _teardown_databases
|
from django.test.utils import teardown_databases as _teardown_databases
|
||||||
from django.test.utils import teardown_test_environment
|
from django.test.utils import teardown_test_environment
|
||||||
from django.utils.datastructures import OrderedSet
|
from django.utils.datastructures import OrderedSet
|
||||||
from django.utils.version import PY312, PY313
|
from django.utils.version import PY313
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import ipdb as pdb
|
import ipdb as pdb
|
||||||
@ -829,7 +829,6 @@ class DiscoverRunner:
|
|||||||
"unittest -k option."
|
"unittest -k option."
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
if PY312:
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--durations",
|
"--durations",
|
||||||
dest="durations",
|
dest="durations",
|
||||||
@ -1005,9 +1004,8 @@ class DiscoverRunner:
|
|||||||
"resultclass": self.get_resultclass(),
|
"resultclass": self.get_resultclass(),
|
||||||
"verbosity": self.verbosity,
|
"verbosity": self.verbosity,
|
||||||
"buffer": self.buffer,
|
"buffer": self.buffer,
|
||||||
|
"durations": self.durations,
|
||||||
}
|
}
|
||||||
if PY312:
|
|
||||||
kwargs["durations"] = self.durations
|
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
def run_checks(self, databases):
|
def run_checks(self, databases):
|
||||||
|
@ -54,7 +54,6 @@ from django.test.utils import (
|
|||||||
override_settings,
|
override_settings,
|
||||||
)
|
)
|
||||||
from django.utils.functional import classproperty
|
from django.utils.functional import classproperty
|
||||||
from django.utils.version import PY311
|
|
||||||
from django.views.static import serve
|
from django.views.static import serve
|
||||||
|
|
||||||
logger = logging.getLogger("django.test")
|
logger = logging.getLogger("django.test")
|
||||||
@ -71,24 +70,6 @@ __all__ = (
|
|||||||
__unittest = True
|
__unittest = True
|
||||||
|
|
||||||
|
|
||||||
if not PY311:
|
|
||||||
# Backport of unittest.case._enter_context() from Python 3.11.
|
|
||||||
def _enter_context(cm, addcleanup):
|
|
||||||
# Look up the special methods on the type to match the with statement.
|
|
||||||
cls = type(cm)
|
|
||||||
try:
|
|
||||||
enter = cls.__enter__
|
|
||||||
exit = cls.__exit__
|
|
||||||
except AttributeError:
|
|
||||||
raise TypeError(
|
|
||||||
f"'{cls.__module__}.{cls.__qualname__}' object does not support the "
|
|
||||||
f"context manager protocol"
|
|
||||||
) from None
|
|
||||||
result = enter(cm)
|
|
||||||
addcleanup(exit, cm, None, None, None)
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def to_list(value):
|
def to_list(value):
|
||||||
"""Put value into a list if it's not already one."""
|
"""Put value into a list if it's not already one."""
|
||||||
if not isinstance(value, list):
|
if not isinstance(value, list):
|
||||||
@ -398,12 +379,6 @@ class SimpleTestCase(unittest.TestCase):
|
|||||||
"""Perform post-test things."""
|
"""Perform post-test things."""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if not PY311:
|
|
||||||
# Backport of unittest.TestCase.enterClassContext() from Python 3.11.
|
|
||||||
@classmethod
|
|
||||||
def enterClassContext(cls, cm):
|
|
||||||
return _enter_context(cm, cls.addClassCleanup)
|
|
||||||
|
|
||||||
def settings(self, **kwargs):
|
def settings(self, **kwargs):
|
||||||
"""
|
"""
|
||||||
A context manager that temporarily sets a setting and reverts to the
|
A context manager that temporarily sets a setting and reverts to the
|
||||||
|
@ -17,7 +17,7 @@ from django.utils.datastructures import MultiValueDict
|
|||||||
from django.utils.encoding import force_str
|
from django.utils.encoding import force_str
|
||||||
from django.utils.module_loading import import_string
|
from django.utils.module_loading import import_string
|
||||||
from django.utils.regex_helper import _lazy_re_compile
|
from django.utils.regex_helper import _lazy_re_compile
|
||||||
from django.utils.version import PY311, get_docs_version
|
from django.utils.version import get_docs_version
|
||||||
from django.views.decorators.debug import coroutine_functions_to_sensitive_variables
|
from django.views.decorators.debug import coroutine_functions_to_sensitive_variables
|
||||||
|
|
||||||
# Minimal Django templates engine to render the error templates
|
# Minimal Django templates engine to render the error templates
|
||||||
@ -567,7 +567,6 @@ class ExceptionReporter:
|
|||||||
post_context = []
|
post_context = []
|
||||||
|
|
||||||
colno = tb_area_colno = ""
|
colno = tb_area_colno = ""
|
||||||
if PY311:
|
|
||||||
_, _, start_column, end_column = next(
|
_, _, start_column, end_column = next(
|
||||||
itertools.islice(
|
itertools.islice(
|
||||||
tb.tb_frame.f_code.co_positions(), tb.tb_lasti // 2, None
|
tb.tb_frame.f_code.co_positions(), tb.tb_lasti // 2, None
|
||||||
@ -578,9 +577,7 @@ class ExceptionReporter:
|
|||||||
spaces = " " * (start_column + len(str(lineno + 1)) + 2)
|
spaces = " " * (start_column + len(str(lineno + 1)) + 2)
|
||||||
colno = f"\n{spaces}{underline}"
|
colno = f"\n{spaces}{underline}"
|
||||||
tb_area_spaces = " " * (
|
tb_area_spaces = " " * (
|
||||||
4
|
4 + start_column - (len(context_line) - len(context_line.lstrip()))
|
||||||
+ start_column
|
|
||||||
- (len(context_line) - len(context_line.lstrip()))
|
|
||||||
)
|
)
|
||||||
tb_area_colno = f"\n{tb_area_spaces}{underline}"
|
tb_area_colno = f"\n{tb_area_spaces}{underline}"
|
||||||
yield {
|
yield {
|
||||||
|
@ -92,14 +92,14 @@ 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.10
|
<running-unit-tests-settings>`. For example, to run the tests on Python 3.12
|
||||||
using PostgreSQL:
|
using PostgreSQL:
|
||||||
|
|
||||||
.. console::
|
.. console::
|
||||||
|
|
||||||
$ tox -e py310-postgres -- --settings=my_postgres_settings
|
$ tox -e py312-postgres -- --settings=my_postgres_settings
|
||||||
|
|
||||||
This command sets up a Python 3.10 virtual environment, installs Django's
|
This command sets up a Python 3.12 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``).
|
||||||
@ -114,14 +114,14 @@ above:
|
|||||||
|
|
||||||
.. code-block:: console
|
.. code-block:: console
|
||||||
|
|
||||||
$ DJANGO_SETTINGS_MODULE=my_postgres_settings tox -e py310-postgres
|
$ DJANGO_SETTINGS_MODULE=my_postgres_settings tox -e py312-postgres
|
||||||
|
|
||||||
Windows users should use:
|
Windows users should use:
|
||||||
|
|
||||||
.. code-block:: doscon
|
.. code-block:: doscon
|
||||||
|
|
||||||
...\> set DJANGO_SETTINGS_MODULE=my_postgres_settings
|
...\> set DJANGO_SETTINGS_MODULE=my_postgres_settings
|
||||||
...\> tox -e py310-postgres
|
...\> tox -e py312-postgres
|
||||||
|
|
||||||
Running the JavaScript tests
|
Running the JavaScript tests
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
@ -220,7 +220,7 @@ this. For a small app like polls, this process isn't too difficult.
|
|||||||
]
|
]
|
||||||
description = "A Django app to conduct web-based polls."
|
description = "A Django app to conduct web-based polls."
|
||||||
readme = "README.rst"
|
readme = "README.rst"
|
||||||
requires-python = ">= 3.10"
|
requires-python = ">= 3.12"
|
||||||
authors = [
|
authors = [
|
||||||
{name = "Your Name", email = "yourname@example.com"},
|
{name = "Your Name", email = "yourname@example.com"},
|
||||||
]
|
]
|
||||||
@ -234,8 +234,6 @@ this. For a small app like polls, this process isn't too difficult.
|
|||||||
"Programming Language :: Python",
|
"Programming Language :: Python",
|
||||||
"Programming Language :: Python :: 3",
|
"Programming Language :: Python :: 3",
|
||||||
"Programming Language :: Python :: 3 :: Only",
|
"Programming Language :: Python :: 3 :: Only",
|
||||||
"Programming Language :: Python :: 3.10",
|
|
||||||
"Programming Language :: Python :: 3.11",
|
|
||||||
"Programming Language :: Python :: 3.12",
|
"Programming Language :: Python :: 3.12",
|
||||||
"Programming Language :: Python :: 3.13",
|
"Programming Language :: Python :: 3.13",
|
||||||
"Topic :: Internet :: WWW/HTTP",
|
"Topic :: Internet :: WWW/HTTP",
|
||||||
|
@ -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.10 and
|
This tutorial is written for Django |version|, which supports Python 3.12 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
|
||||||
|
@ -1583,10 +1583,6 @@ Outputs timings, including database setup and total run time.
|
|||||||
|
|
||||||
Shows the N slowest test cases (N=0 for all).
|
Shows the N slowest test cases (N=0 for all).
|
||||||
|
|
||||||
.. admonition:: Python 3.12 and later
|
|
||||||
|
|
||||||
This feature is only available for Python 3.12 and later.
|
|
||||||
|
|
||||||
``testserver``
|
``testserver``
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
|
@ -21,6 +21,8 @@ Python compatibility
|
|||||||
Django 6.0 supports Python 3.12 and 3.13. We **highly recommend** and only
|
Django 6.0 supports Python 3.12 and 3.13. We **highly recommend** and only
|
||||||
officially support the latest release of each series.
|
officially support the latest release of each series.
|
||||||
|
|
||||||
|
The Django 5.2.x series is the last to support Python 3.10 and 3.11.
|
||||||
|
|
||||||
Third-party library support for older version of Django
|
Third-party library support for older version of Django
|
||||||
=======================================================
|
=======================================================
|
||||||
|
|
||||||
|
@ -419,7 +419,8 @@ performance gains, typically for heavyweight applications.
|
|||||||
|
|
||||||
A key aim of the PyPy project is `compatibility
|
A key aim of the PyPy project is `compatibility
|
||||||
<https://www.pypy.org/compat.html>`_ with existing Python APIs and libraries.
|
<https://www.pypy.org/compat.html>`_ with existing Python APIs and libraries.
|
||||||
Django is compatible, but you will need to check the compatibility of other
|
Django is compatible with versions of PyPy corresponding to the supported
|
||||||
|
Python versions, but you will need to check the compatibility of other
|
||||||
libraries you rely on.
|
libraries you rely on.
|
||||||
|
|
||||||
C implementations of Python libraries
|
C implementations of Python libraries
|
||||||
|
@ -608,7 +608,6 @@ and tear down the test suite.
|
|||||||
|
|
||||||
``durations`` will show a list of the N slowest test cases. Setting this
|
``durations`` will show a list of the N slowest test cases. Setting this
|
||||||
option to ``0`` will result in the duration for all tests being shown.
|
option to ``0`` will result in the duration for all tests being shown.
|
||||||
Requires Python 3.12+.
|
|
||||||
|
|
||||||
Django may, from time to time, extend the capabilities of the test runner
|
Django may, from time to time, extend the capabilities of the test runner
|
||||||
by adding new arguments. The ``**kwargs`` declaration allows for this
|
by adding new arguments. The ``**kwargs`` declaration allows for this
|
||||||
|
@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
|
|||||||
[project]
|
[project]
|
||||||
name = "Django"
|
name = "Django"
|
||||||
dynamic = ["version"]
|
dynamic = ["version"]
|
||||||
requires-python = ">= 3.10"
|
requires-python = ">= 3.12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"asgiref>=3.8.1",
|
"asgiref>=3.8.1",
|
||||||
"sqlparse>=0.3.1",
|
"sqlparse>=0.3.1",
|
||||||
@ -27,8 +27,6 @@ classifiers = [
|
|||||||
"Programming Language :: Python",
|
"Programming Language :: Python",
|
||||||
"Programming Language :: Python :: 3",
|
"Programming Language :: Python :: 3",
|
||||||
"Programming Language :: Python :: 3 :: Only",
|
"Programming Language :: Python :: 3 :: Only",
|
||||||
"Programming Language :: Python :: 3.10",
|
|
||||||
"Programming Language :: Python :: 3.11",
|
|
||||||
"Programming Language :: Python :: 3.12",
|
"Programming Language :: Python :: 3.12",
|
||||||
"Programming Language :: Python :: 3.13",
|
"Programming Language :: Python :: 3.13",
|
||||||
"Topic :: Internet :: WWW/HTTP",
|
"Topic :: Internet :: WWW/HTTP",
|
||||||
@ -54,7 +52,7 @@ Source = "https://github.com/django/django"
|
|||||||
Tracker = "https://code.djangoproject.com/"
|
Tracker = "https://code.djangoproject.com/"
|
||||||
|
|
||||||
[tool.black]
|
[tool.black]
|
||||||
target-version = ["py310"]
|
target-version = ["py312"]
|
||||||
force-exclude = "tests/test_runner_apps/tagged/tests_syntax_error.py"
|
force-exclude = "tests/test_runner_apps/tagged/tests_syntax_error.py"
|
||||||
|
|
||||||
[tool.isort]
|
[tool.isort]
|
||||||
|
@ -184,7 +184,7 @@ class MailTests(MailTestsMixin, SimpleTestCase):
|
|||||||
"""Line length check should encode the payload supporting `surrogateescape`.
|
"""Line length check should encode the payload supporting `surrogateescape`.
|
||||||
|
|
||||||
Following https://github.com/python/cpython/issues/76511, newer
|
Following https://github.com/python/cpython/issues/76511, newer
|
||||||
versions of Python (3.11.9, 3.12.3 and 3.13) ensure that a message's
|
versions of Python (3.12.3 and 3.13) ensure that a message's
|
||||||
payload is encoded with the provided charset and `surrogateescape` is
|
payload is encoded with the provided charset and `surrogateescape` is
|
||||||
used as the error handling strategy.
|
used as the error handling strategy.
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@ from django.template import Context, Template
|
|||||||
from django.test import SimpleTestCase
|
from django.test import SimpleTestCase
|
||||||
from django.utils.functional import Promise
|
from django.utils.functional import Promise
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.utils.version import PY311
|
|
||||||
|
|
||||||
|
|
||||||
class Suit(models.IntegerChoices):
|
class Suit(models.IntegerChoices):
|
||||||
@ -200,13 +199,7 @@ class ChoicesTests(SimpleTestCase):
|
|||||||
|
|
||||||
def test_do_not_call_in_templates_nonmember(self):
|
def test_do_not_call_in_templates_nonmember(self):
|
||||||
self.assertNotIn("do_not_call_in_templates", Suit.__members__)
|
self.assertNotIn("do_not_call_in_templates", Suit.__members__)
|
||||||
if PY311:
|
|
||||||
self.assertIs(Suit.do_not_call_in_templates, True)
|
self.assertIs(Suit.do_not_call_in_templates, True)
|
||||||
else:
|
|
||||||
# Using @property on an enum does not behave as expected.
|
|
||||||
self.assertTrue(Suit.do_not_call_in_templates)
|
|
||||||
self.assertIsNot(Suit.do_not_call_in_templates, True)
|
|
||||||
self.assertIsInstance(Suit.do_not_call_in_templates, property)
|
|
||||||
|
|
||||||
|
|
||||||
class Separator(bytes, models.Choices):
|
class Separator(bytes, models.Choices):
|
||||||
|
@ -12,7 +12,6 @@ from django.core.files.uploadedfile import TemporaryUploadedFile
|
|||||||
from django.db import IntegrityError, models
|
from django.db import IntegrityError, models
|
||||||
from django.test import TestCase, override_settings
|
from django.test import TestCase, override_settings
|
||||||
from django.test.utils import isolate_apps
|
from django.test.utils import isolate_apps
|
||||||
from django.utils.version import PY311
|
|
||||||
|
|
||||||
from .models import Document
|
from .models import Document
|
||||||
|
|
||||||
@ -80,7 +79,6 @@ class FileFieldTests(TestCase):
|
|||||||
with self.assertRaisesMessage(FieldError, msg) as cm:
|
with self.assertRaisesMessage(FieldError, msg) as cm:
|
||||||
d.save()
|
d.save()
|
||||||
|
|
||||||
if PY311:
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
cm.exception.__notes__, ["Pass a 'name' argument to ContentFile."]
|
cm.exception.__notes__, ["Pass a 'name' argument to ContentFile."]
|
||||||
)
|
)
|
||||||
|
@ -34,7 +34,7 @@ else:
|
|||||||
)
|
)
|
||||||
from django.utils.functional import classproperty
|
from django.utils.functional import classproperty
|
||||||
from django.utils.log import DEFAULT_LOGGING
|
from django.utils.log import DEFAULT_LOGGING
|
||||||
from django.utils.version import PY312, PYPY
|
from django.utils.version import PYPY
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -691,7 +691,6 @@ if __name__ == "__main__":
|
|||||||
"Same as unittest -k option. Can be used multiple times."
|
"Same as unittest -k option. Can be used multiple times."
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
if PY312:
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--durations",
|
"--durations",
|
||||||
dest="durations",
|
dest="durations",
|
||||||
|
@ -4,7 +4,6 @@ from io import StringIO
|
|||||||
from django.db import connection
|
from django.db import connection
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.test.runner import DiscoverRunner
|
from django.test.runner import DiscoverRunner
|
||||||
from django.utils.version import PY311
|
|
||||||
|
|
||||||
from .models import Person
|
from .models import Person
|
||||||
|
|
||||||
@ -114,17 +113,15 @@ class TestDebugSQL(unittest.TestCase):
|
|||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
# Python 3.11 uses fully qualified test name in the output.
|
|
||||||
method_name = ".runTest" if PY311 else ""
|
|
||||||
test_class_path = "test_runner.test_debug_sql.TestDebugSQL"
|
test_class_path = "test_runner.test_debug_sql.TestDebugSQL"
|
||||||
verbose_expected_outputs = [
|
verbose_expected_outputs = [
|
||||||
f"runTest ({test_class_path}.FailingTest{method_name}) ... FAIL",
|
f"runTest ({test_class_path}.FailingTest.runTest) ... FAIL",
|
||||||
f"runTest ({test_class_path}.ErrorTest{method_name}) ... ERROR",
|
f"runTest ({test_class_path}.ErrorTest.runTest) ... ERROR",
|
||||||
f"runTest ({test_class_path}.PassingTest{method_name}) ... ok",
|
f"runTest ({test_class_path}.PassingTest.runTest) ... ok",
|
||||||
# If there are errors/failures in subtests but not in test itself,
|
# If there are errors/failures in subtests but not in test itself,
|
||||||
# the status is not written. That behavior comes from Python.
|
# the status is not written. That behavior comes from Python.
|
||||||
f"runTest ({test_class_path}.FailingSubTest{method_name}) ...",
|
f"runTest ({test_class_path}.FailingSubTest.runTest) ...",
|
||||||
f"runTest ({test_class_path}.ErrorSubTest{method_name}) ...",
|
f"runTest ({test_class_path}.ErrorSubTest.runTest) ...",
|
||||||
(
|
(
|
||||||
"""SELECT COUNT(*) AS "__count"\n"""
|
"""SELECT COUNT(*) AS "__count"\n"""
|
||||||
"""FROM "test_runner_person"\nWHERE """
|
"""FROM "test_runner_person"\nWHERE """
|
||||||
|
@ -16,7 +16,6 @@ from django.test.utils import (
|
|||||||
captured_stderr,
|
captured_stderr,
|
||||||
captured_stdout,
|
captured_stdout,
|
||||||
)
|
)
|
||||||
from django.utils.version import PY312
|
|
||||||
|
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
@ -768,7 +767,6 @@ class DiscoverRunnerTests(SimpleTestCase):
|
|||||||
failures = runner.suite_result(suite, result)
|
failures = runner.suite_result(suite, result)
|
||||||
self.assertEqual(failures, expected_failures)
|
self.assertEqual(failures, expected_failures)
|
||||||
|
|
||||||
@unittest.skipUnless(PY312, "unittest --durations option requires Python 3.12")
|
|
||||||
def test_durations(self):
|
def test_durations(self):
|
||||||
with captured_stderr() as stderr, captured_stdout():
|
with captured_stderr() as stderr, captured_stdout():
|
||||||
runner = DiscoverRunner(durations=10)
|
runner = DiscoverRunner(durations=10)
|
||||||
@ -776,7 +774,6 @@ class DiscoverRunnerTests(SimpleTestCase):
|
|||||||
runner.run_suite(suite)
|
runner.run_suite(suite)
|
||||||
self.assertIn("Slowest test durations", stderr.getvalue())
|
self.assertIn("Slowest test durations", stderr.getvalue())
|
||||||
|
|
||||||
@unittest.skipUnless(PY312, "unittest --durations option requires Python 3.12")
|
|
||||||
def test_durations_debug_sql(self):
|
def test_durations_debug_sql(self):
|
||||||
with captured_stderr() as stderr, captured_stdout():
|
with captured_stderr() as stderr, captured_stdout():
|
||||||
runner = DiscoverRunner(durations=10, debug_sql=True)
|
runner = DiscoverRunner(durations=10, debug_sql=True)
|
||||||
|
@ -7,7 +7,6 @@ from unittest.suite import TestSuite, _ErrorHolder
|
|||||||
|
|
||||||
from django.test import SimpleTestCase
|
from django.test import SimpleTestCase
|
||||||
from django.test.runner import ParallelTestSuite, RemoteTestResult
|
from django.test.runner import ParallelTestSuite, RemoteTestResult
|
||||||
from django.utils.version import PY311, PY312
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import tblib.pickling_support
|
import tblib.pickling_support
|
||||||
@ -193,27 +192,21 @@ class RemoteTestResultTest(SimpleTestCase):
|
|||||||
subtest_test.run(result=result)
|
subtest_test.run(result=result)
|
||||||
|
|
||||||
events = result.events
|
events = result.events
|
||||||
# addDurations added in Python 3.12.
|
|
||||||
if PY312:
|
|
||||||
self.assertEqual(len(events), 5)
|
self.assertEqual(len(events), 5)
|
||||||
else:
|
|
||||||
self.assertEqual(len(events), 4)
|
|
||||||
self.assertIs(result.wasSuccessful(), False)
|
self.assertIs(result.wasSuccessful(), False)
|
||||||
|
|
||||||
event = events[1]
|
event = events[1]
|
||||||
self.assertEqual(event[0], "addSubTest")
|
self.assertEqual(event[0], "addSubTest")
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
str(event[2]),
|
str(event[2]),
|
||||||
"dummy_test (test_runner.test_parallel.SampleFailingSubtest%s) (index=0)"
|
"dummy_test (test_runner.test_parallel.SampleFailingSubtest.dummy_test) "
|
||||||
# Python 3.11 uses fully qualified test name in the output.
|
"(index=0)",
|
||||||
% (".dummy_test" if PY311 else ""),
|
|
||||||
)
|
)
|
||||||
self.assertEqual(repr(event[3][1]), "AssertionError('0 != 1')")
|
self.assertEqual(repr(event[3][1]), "AssertionError('0 != 1')")
|
||||||
|
|
||||||
event = events[2]
|
event = events[2]
|
||||||
self.assertEqual(repr(event[3][1]), "AssertionError('2 != 1')")
|
self.assertEqual(repr(event[3][1]), "AssertionError('2 != 1')")
|
||||||
|
|
||||||
@unittest.skipUnless(PY312, "unittest --durations option requires Python 3.12")
|
|
||||||
def test_add_duration(self):
|
def test_add_duration(self):
|
||||||
result = RemoteTestResult()
|
result = RemoteTestResult()
|
||||||
result.addDuration(None, 2.3)
|
result.addDuration(None, 2.3)
|
||||||
|
@ -15,7 +15,7 @@ from django import db
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.core.management import call_command
|
from django.core.management import call_command
|
||||||
from django.core.management.base import CommandError, SystemCheckError
|
from django.core.management.base import SystemCheckError
|
||||||
from django.test import SimpleTestCase, TransactionTestCase, skipUnlessDBFeature
|
from django.test import SimpleTestCase, TransactionTestCase, skipUnlessDBFeature
|
||||||
from django.test.runner import (
|
from django.test.runner import (
|
||||||
DiscoverRunner,
|
DiscoverRunner,
|
||||||
@ -32,7 +32,6 @@ from django.test.utils import (
|
|||||||
get_unique_databases_and_mirrors,
|
get_unique_databases_and_mirrors,
|
||||||
iter_test_cases,
|
iter_test_cases,
|
||||||
)
|
)
|
||||||
from django.utils.version import PY312
|
|
||||||
|
|
||||||
from .models import B, Person, Through
|
from .models import B, Person, Through
|
||||||
|
|
||||||
@ -479,7 +478,6 @@ class ManageCommandTests(unittest.TestCase):
|
|||||||
)
|
)
|
||||||
self.assertIn("Total run took", stderr.getvalue())
|
self.assertIn("Total run took", stderr.getvalue())
|
||||||
|
|
||||||
@unittest.skipUnless(PY312, "unittest --durations option requires Python 3.12")
|
|
||||||
def test_durations(self):
|
def test_durations(self):
|
||||||
with captured_stderr() as stderr:
|
with captured_stderr() as stderr:
|
||||||
call_command(
|
call_command(
|
||||||
@ -490,17 +488,6 @@ class ManageCommandTests(unittest.TestCase):
|
|||||||
)
|
)
|
||||||
self.assertIn("durations=10", stderr.getvalue())
|
self.assertIn("durations=10", stderr.getvalue())
|
||||||
|
|
||||||
@unittest.skipIf(PY312, "unittest --durations option requires Python 3.12")
|
|
||||||
def test_durations_lt_py312(self):
|
|
||||||
msg = "Error: unrecognized arguments: --durations=10"
|
|
||||||
with self.assertRaises(CommandError, msg=msg):
|
|
||||||
call_command(
|
|
||||||
"test",
|
|
||||||
"--durations=10",
|
|
||||||
"sites",
|
|
||||||
testrunner="test_runner.tests.MockTestRunner",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# Isolate from the real environment.
|
# Isolate from the real environment.
|
||||||
@mock.patch.dict(os.environ, {}, clear=True)
|
@mock.patch.dict(os.environ, {}, clear=True)
|
||||||
|
@ -49,7 +49,6 @@ from django.test.utils import (
|
|||||||
)
|
)
|
||||||
from django.urls import NoReverseMatch, path, reverse, reverse_lazy
|
from django.urls import NoReverseMatch, path, reverse, reverse_lazy
|
||||||
from django.utils.html import VOID_ELEMENTS
|
from django.utils.html import VOID_ELEMENTS
|
||||||
from django.utils.version import PY311
|
|
||||||
|
|
||||||
from .models import Car, Person, PossessedCar
|
from .models import Car, Person, PossessedCar
|
||||||
from .views import empty_response
|
from .views import empty_response
|
||||||
@ -103,11 +102,9 @@ class SkippingTestCase(SimpleTestCase):
|
|||||||
SkipTestCase("test_foo").test_foo,
|
SkipTestCase("test_foo").test_foo,
|
||||||
ValueError,
|
ValueError,
|
||||||
"skipUnlessDBFeature cannot be used on test_foo (test_utils.tests."
|
"skipUnlessDBFeature cannot be used on test_foo (test_utils.tests."
|
||||||
"SkippingTestCase.test_skip_unless_db_feature.<locals>.SkipTestCase%s) "
|
"SkippingTestCase.test_skip_unless_db_feature.<locals>.SkipTestCase."
|
||||||
"as SkippingTestCase.test_skip_unless_db_feature.<locals>.SkipTestCase "
|
"test_foo) as SkippingTestCase.test_skip_unless_db_feature.<locals>."
|
||||||
"doesn't allow queries against the 'default' database."
|
"SkipTestCase doesn't allow queries against the 'default' database.",
|
||||||
# Python 3.11 uses fully qualified test name in the output.
|
|
||||||
% (".test_foo" if PY311 else ""),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_skip_if_db_feature(self):
|
def test_skip_if_db_feature(self):
|
||||||
@ -150,11 +147,9 @@ class SkippingTestCase(SimpleTestCase):
|
|||||||
SkipTestCase("test_foo").test_foo,
|
SkipTestCase("test_foo").test_foo,
|
||||||
ValueError,
|
ValueError,
|
||||||
"skipIfDBFeature cannot be used on test_foo (test_utils.tests."
|
"skipIfDBFeature cannot be used on test_foo (test_utils.tests."
|
||||||
"SkippingTestCase.test_skip_if_db_feature.<locals>.SkipTestCase%s) "
|
"SkippingTestCase.test_skip_if_db_feature.<locals>.SkipTestCase.test_foo) "
|
||||||
"as SkippingTestCase.test_skip_if_db_feature.<locals>.SkipTestCase "
|
"as SkippingTestCase.test_skip_if_db_feature.<locals>.SkipTestCase "
|
||||||
"doesn't allow queries against the 'default' database."
|
"doesn't allow queries against the 'default' database.",
|
||||||
# Python 3.11 uses fully qualified test name in the output.
|
|
||||||
% (".test_foo" if PY311 else ""),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@ from django.utils.dateparse import (
|
|||||||
parse_time,
|
parse_time,
|
||||||
)
|
)
|
||||||
from django.utils.timezone import get_fixed_timezone
|
from django.utils.timezone import get_fixed_timezone
|
||||||
from django.utils.version import PY311
|
|
||||||
|
|
||||||
|
|
||||||
class DateParseTests(unittest.TestCase):
|
class DateParseTests(unittest.TestCase):
|
||||||
@ -16,7 +15,6 @@ class DateParseTests(unittest.TestCase):
|
|||||||
# Valid inputs
|
# Valid inputs
|
||||||
self.assertEqual(parse_date("2012-04-23"), date(2012, 4, 23))
|
self.assertEqual(parse_date("2012-04-23"), date(2012, 4, 23))
|
||||||
self.assertEqual(parse_date("2012-4-9"), date(2012, 4, 9))
|
self.assertEqual(parse_date("2012-4-9"), date(2012, 4, 9))
|
||||||
if PY311:
|
|
||||||
self.assertEqual(parse_date("20120423"), date(2012, 4, 23))
|
self.assertEqual(parse_date("20120423"), date(2012, 4, 23))
|
||||||
# Invalid inputs
|
# Invalid inputs
|
||||||
self.assertIsNone(parse_date("2012423"))
|
self.assertIsNone(parse_date("2012423"))
|
||||||
@ -26,7 +24,6 @@ class DateParseTests(unittest.TestCase):
|
|||||||
def test_parse_time(self):
|
def test_parse_time(self):
|
||||||
# Valid inputs
|
# Valid inputs
|
||||||
self.assertEqual(parse_time("09:15:00"), time(9, 15))
|
self.assertEqual(parse_time("09:15:00"), time(9, 15))
|
||||||
if PY311:
|
|
||||||
self.assertEqual(parse_time("091500"), time(9, 15))
|
self.assertEqual(parse_time("091500"), time(9, 15))
|
||||||
self.assertEqual(parse_time("10:10"), time(10, 10))
|
self.assertEqual(parse_time("10:10"), time(10, 10))
|
||||||
self.assertEqual(parse_time("10:20:30.400"), time(10, 20, 30, 400000))
|
self.assertEqual(parse_time("10:20:30.400"), time(10, 20, 30, 400000))
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
from django.test import SimpleTestCase
|
from django.test import SimpleTestCase
|
||||||
from django.utils.functional import cached_property, classproperty, lazy
|
from django.utils.functional import cached_property, classproperty, lazy
|
||||||
from django.utils.version import PY312
|
|
||||||
|
|
||||||
|
|
||||||
class FunctionalTests(SimpleTestCase):
|
class FunctionalTests(SimpleTestCase):
|
||||||
@ -133,14 +132,10 @@ class FunctionalTests(SimpleTestCase):
|
|||||||
"Cannot assign the same cached_property to two different names ('a' and "
|
"Cannot assign the same cached_property to two different names ('a' and "
|
||||||
"'b')."
|
"'b')."
|
||||||
)
|
)
|
||||||
if PY312:
|
|
||||||
error_type = TypeError
|
error_type = TypeError
|
||||||
msg = type_msg
|
msg = type_msg
|
||||||
else:
|
|
||||||
error_type = RuntimeError
|
|
||||||
msg = "Error calling __set_name__"
|
|
||||||
|
|
||||||
with self.assertRaisesMessage(error_type, msg) as ctx:
|
with self.assertRaisesMessage(error_type, msg):
|
||||||
|
|
||||||
class ReusedCachedProperty:
|
class ReusedCachedProperty:
|
||||||
@cached_property
|
@cached_property
|
||||||
@ -149,9 +144,6 @@ class FunctionalTests(SimpleTestCase):
|
|||||||
|
|
||||||
b = a
|
b = a
|
||||||
|
|
||||||
if not PY312:
|
|
||||||
self.assertEqual(str(ctx.exception.__context__), str(TypeError(type_msg)))
|
|
||||||
|
|
||||||
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
|
||||||
|
@ -7,7 +7,7 @@ import tempfile
|
|||||||
import threading
|
import threading
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from unittest import mock, skipIf, skipUnless
|
from unittest import mock, skipIf
|
||||||
|
|
||||||
from asgiref.sync import async_to_sync, iscoroutinefunction
|
from asgiref.sync import async_to_sync, iscoroutinefunction
|
||||||
|
|
||||||
@ -24,7 +24,6 @@ from django.urls.converters import IntConverter
|
|||||||
from django.utils.functional import SimpleLazyObject
|
from django.utils.functional import SimpleLazyObject
|
||||||
from django.utils.regex_helper import _lazy_re_compile
|
from django.utils.regex_helper import _lazy_re_compile
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from django.utils.version import PY311
|
|
||||||
from django.views.debug import (
|
from django.views.debug import (
|
||||||
CallableSettingWrapper,
|
CallableSettingWrapper,
|
||||||
ExceptionCycleWarning,
|
ExceptionCycleWarning,
|
||||||
@ -695,7 +694,6 @@ class ExceptionReporterTests(SimpleTestCase):
|
|||||||
text,
|
text,
|
||||||
)
|
)
|
||||||
|
|
||||||
@skipUnless(PY311, "Exception notes were added in Python 3.11.")
|
|
||||||
def test_exception_with_notes(self):
|
def test_exception_with_notes(self):
|
||||||
request = self.rf.get("/test_view/")
|
request = self.rf.get("/test_view/")
|
||||||
try:
|
try:
|
||||||
@ -806,7 +804,6 @@ class ExceptionReporterTests(SimpleTestCase):
|
|||||||
or os.environ.get("PYTHONNODEBUGRANGES", False),
|
or os.environ.get("PYTHONNODEBUGRANGES", False),
|
||||||
"Fine-grained error locations are disabled.",
|
"Fine-grained error locations are disabled.",
|
||||||
)
|
)
|
||||||
@skipUnless(PY311, "Fine-grained error locations were added in Python 3.11.")
|
|
||||||
def test_highlight_error_position(self):
|
def test_highlight_error_position(self):
|
||||||
request = self.rf.get("/test_view/")
|
request = self.rf.get("/test_view/")
|
||||||
try:
|
try:
|
||||||
|
2
tox.ini
2
tox.ini
@ -26,7 +26,7 @@ setenv =
|
|||||||
PYTHONDONTWRITEBYTECODE=1
|
PYTHONDONTWRITEBYTECODE=1
|
||||||
deps =
|
deps =
|
||||||
-e .
|
-e .
|
||||||
py{3,310,311,312,313,py3}: -rtests/requirements/py3.txt
|
py{3,312,313}: -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…
x
Reference in New Issue
Block a user