Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 0 additions & 60 deletions .github/workflows/schedule_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ jobs:
strategy:
matrix:
python-version:
- '3.10'
- '3.11'
- '3.12'
- '3.13'
- '3.14-dev'
Expand Down Expand Up @@ -64,64 +62,6 @@ jobs:
- name: Run tests
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:
runs-on: ubuntu-latest
name: JavaScript tests
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/screenshots.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
python-version: '3.13'
cache: 'pip'
cache-dependency-path: 'tests/requirements/py3.txt'
- name: Install and upgrade packaging tools
Expand Down
2 changes: 1 addition & 1 deletion INSTALL
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
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:

python -m pip install .
Expand Down
2 changes: 1 addition & 1 deletion django/db/backends/postgresql/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def assemble_as_sql(self, fields, value_rows):
db_types = [field.db_type(self.connection) for field in fields]
# Abort if any of the fields are arrays as UNNEST indiscriminately
# flatten them instead of reducing their nesting by one.
if any(db_type.endswith("[]") for db_type in db_types):
if any(db_type.endswith("]") for db_type in db_types):
return super().assemble_as_sql(fields, value_rows)
return InsertUnnest(["(%%s)::%s[]" % db_type for db_type in db_types]), [
list(map(list, zip(*value_rows)))
Expand Down
8 changes: 2 additions & 6 deletions django/db/migrations/serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from django.db.migrations.operations.base import Operation
from django.db.migrations.utils import COMPILED_REGEX_TYPE, RegexObject
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)

Expand Down Expand Up @@ -140,11 +140,7 @@ def serialize(self):
enum_class = self.value.__class__
module = enum_class.__module__
if issubclass(enum_class, enum.Flag):
if PY311:
members = list(self.value)
else:
members, _ = enum._decompose(enum_class, self.value)
members = reversed(members)
members = list(self.value)
else:
members = (self.value,)
return (
Expand Down
37 changes: 3 additions & 34 deletions django/db/models/enums.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,8 @@
import enum
from enum import EnumType, IntEnum, StrEnum
from enum import property as enum_property

from django.utils.functional import Promise
from django.utils.version import PY311, PY312

if PY311:
from enum import EnumType, IntEnum, StrEnum
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


__all__ = ["Choices", "IntegerChoices", "TextChoices"]

Expand Down Expand Up @@ -49,14 +32,6 @@ def __new__(metacls, classname, bases, classdict, **kwds):
member._label_ = label
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
def names(cls):
empty = ["__empty__"] if hasattr(cls, "__empty__") else []
Expand All @@ -79,13 +54,7 @@ def values(cls):
class Choices(enum.Enum, metaclass=ChoicesType):
"""Class for creating enumerated choices."""

if PY311:
do_not_call_in_templates = enum.nonmember(True)
else:

@property
def do_not_call_in_templates(self):
return True
do_not_call_in_templates = enum.nonmember(True)

@enum_property
def label(self):
Expand Down
3 changes: 1 addition & 2 deletions django/db/models/fields/files.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
from django.db.models.query_utils import DeferredAttribute
from django.db.models.utils import AltersData
from django.utils.translation import gettext_lazy as _
from django.utils.version import PY311


class FieldFile(File, AltersData):
Expand Down Expand Up @@ -329,7 +328,7 @@ def pre_save(self, model_instance, add):
f"File for {self.name} must have "
"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.")
raise exc

Expand Down
22 changes: 10 additions & 12 deletions django/test/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
from django.test.utils import teardown_databases as _teardown_databases
from django.test.utils import teardown_test_environment
from django.utils.datastructures import OrderedSet
from django.utils.version import PY312, PY313
from django.utils.version import PY313

try:
import ipdb as pdb
Expand Down Expand Up @@ -829,15 +829,14 @@ def add_arguments(cls, parser):
"unittest -k option."
),
)
if PY312:
parser.add_argument(
"--durations",
dest="durations",
type=int,
default=None,
metavar="N",
help="Show the N slowest test cases (N=0 for all).",
)
parser.add_argument(
"--durations",
dest="durations",
type=int,
default=None,
metavar="N",
help="Show the N slowest test cases (N=0 for all).",
)

@property
def shuffle_seed(self):
Expand Down Expand Up @@ -1005,9 +1004,8 @@ def get_test_runner_kwargs(self):
"resultclass": self.get_resultclass(),
"verbosity": self.verbosity,
"buffer": self.buffer,
"durations": self.durations,
}
if PY312:
kwargs["durations"] = self.durations
return kwargs

def run_checks(self, databases):
Expand Down
25 changes: 0 additions & 25 deletions django/test/testcases.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@
override_settings,
)
from django.utils.functional import classproperty
from django.utils.version import PY311
from django.views.static import serve

logger = logging.getLogger("django.test")
Expand All @@ -71,24 +70,6 @@
__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):
"""Put value into a list if it's not already one."""
if not isinstance(value, list):
Expand Down Expand Up @@ -398,12 +379,6 @@ def _post_teardown(self):
"""Perform post-test things."""
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):
"""
A context manager that temporarily sets a setting and reverts to the
Expand Down
29 changes: 13 additions & 16 deletions django/views/debug.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from django.utils.encoding import force_str
from django.utils.module_loading import import_string
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

# Minimal Django templates engine to render the error templates
Expand Down Expand Up @@ -567,22 +567,19 @@ def get_exception_traceback_frames(self, exc_value, tb):
post_context = []

colno = tb_area_colno = ""
if PY311:
_, _, start_column, end_column = next(
itertools.islice(
tb.tb_frame.f_code.co_positions(), tb.tb_lasti // 2, None
)
_, _, start_column, end_column = next(
itertools.islice(
tb.tb_frame.f_code.co_positions(), tb.tb_lasti // 2, None
)
if start_column and end_column:
underline = "^" * (end_column - start_column)
spaces = " " * (start_column + len(str(lineno + 1)) + 2)
colno = f"\n{spaces}{underline}"
tb_area_spaces = " " * (
4
+ start_column
- (len(context_line) - len(context_line.lstrip()))
)
tb_area_colno = f"\n{tb_area_spaces}{underline}"
)
if start_column and end_column:
underline = "^" * (end_column - start_column)
spaces = " " * (start_column + len(str(lineno + 1)) + 2)
colno = f"\n{spaces}{underline}"
tb_area_spaces = " " * (
4 + start_column - (len(context_line) - len(context_line.lstrip()))
)
tb_area_colno = f"\n{tb_area_spaces}{underline}"
yield {
"exc_cause": exc_cause,
"exc_cause_explicit": exc_cause_explicit,
Expand Down
10 changes: 5 additions & 5 deletions docs/internals/contributing/writing-code/unit-tests.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
suite doesn't bundle a settings file for database backends other than SQLite,
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:

.. 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
``runtests.py`` with the supplied arguments (in this case,
``--settings=my_postgres_settings``).
Expand All @@ -114,14 +114,14 @@ above:

.. 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:

.. code-block:: doscon

...\> set DJANGO_SETTINGS_MODULE=my_postgres_settings
...\> tox -e py310-postgres
...\> tox -e py312-postgres

Running the JavaScript tests
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down
4 changes: 1 addition & 3 deletions docs/intro/reusable-apps.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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."
readme = "README.rst"
requires-python = ">= 3.10"
requires-python = ">= 3.12"
authors = [
{name = "Your Name", email = "yourname@example.com"},
]
Expand All @@ -234,8 +234,6 @@ this. For a small app like polls, this process isn't too difficult.
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Internet :: WWW/HTTP",
Expand Down
2 changes: 1 addition & 1 deletion docs/intro/tutorial01.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
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
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
Expand Down
Loading
Loading