diff --git a/django/__init__.py b/django/__init__.py index 67d6ecc45d1d..19d8b64198a2 100644 --- a/django/__init__.py +++ b/django/__init__.py @@ -1,6 +1,6 @@ from django.utils.version import get_version -VERSION = (5, 2, 0, "alpha", 0) +VERSION = (6, 0, 0, "alpha", 0) __version__ = get_version(VERSION) diff --git a/django/conf/__init__.py b/django/conf/__init__.py index 5568d7cc83cf..6b5f044e3449 100644 --- a/django/conf/__init__.py +++ b/django/conf/__init__.py @@ -16,18 +16,12 @@ import django from django.conf import global_settings from django.core.exceptions import ImproperlyConfigured -from django.utils.deprecation import RemovedInDjango60Warning from django.utils.functional import LazyObject, empty ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE" DEFAULT_STORAGE_ALIAS = "default" STATICFILES_STORAGE_ALIAS = "staticfiles" -# RemovedInDjango60Warning. -FORMS_URLFIELD_ASSUME_HTTPS_DEPRECATED_MSG = ( - "The FORMS_URLFIELD_ASSUME_HTTPS transitional setting is deprecated." -) - class SettingsReference(str): """ @@ -186,12 +180,6 @@ def __init__(self, settings_module): setattr(self, setting, setting_value) self._explicit_settings.add(setting) - if self.is_overridden("FORMS_URLFIELD_ASSUME_HTTPS"): - warnings.warn( - FORMS_URLFIELD_ASSUME_HTTPS_DEPRECATED_MSG, - RemovedInDjango60Warning, - ) - if hasattr(time, "tzset") and self.TIME_ZONE: # When we can, attempt to validate the timezone. If we can't find # this file, no check happens and it's harmless. @@ -236,11 +224,6 @@ def __getattr__(self, name): def __setattr__(self, name, value): self._deleted.discard(name) - if name == "FORMS_URLFIELD_ASSUME_HTTPS": - warnings.warn( - FORMS_URLFIELD_ASSUME_HTTPS_DEPRECATED_MSG, - RemovedInDjango60Warning, - ) super().__setattr__(name, value) def __delattr__(self, name): diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py index f4535acb09c9..536bbb7c45e5 100644 --- a/django/conf/global_settings.py +++ b/django/conf/global_settings.py @@ -218,11 +218,6 @@ def gettext_noop(s): # Default form rendering class. FORM_RENDERER = "django.forms.renderers.DjangoTemplates" -# RemovedInDjango60Warning: It's a transitional setting helpful in early -# adoption of "https" as the new default value of forms.URLField.assume_scheme. -# Set to True to assume "https" during the Django 5.x release cycle. -FORMS_URLFIELD_ASSUME_HTTPS = False - # Default email address to use for various automated correspondence from # the site managers. DEFAULT_FROM_EMAIL = "webmaster@localhost" diff --git a/django/contrib/admin/models.py b/django/contrib/admin/models.py index bb81be829768..5723ebff7f36 100644 --- a/django/contrib/admin/models.py +++ b/django/contrib/admin/models.py @@ -1,5 +1,4 @@ import json -import warnings from django.conf import settings from django.contrib.admin.utils import quote @@ -7,7 +6,6 @@ from django.db import models from django.urls import NoReverseMatch, reverse from django.utils import timezone -from django.utils.deprecation import RemovedInDjango60Warning from django.utils.text import get_text_list from django.utils.translation import gettext from django.utils.translation import gettext_lazy as _ @@ -26,56 +24,9 @@ class LogEntryManager(models.Manager): use_in_migrations = True - def log_action( - self, - user_id, - content_type_id, - object_id, - object_repr, - action_flag, - change_message="", - ): - warnings.warn( - "LogEntryManager.log_action() is deprecated. Use log_actions() instead.", - RemovedInDjango60Warning, - stacklevel=2, - ) - if isinstance(change_message, list): - change_message = json.dumps(change_message) - return self.model.objects.create( - user_id=user_id, - content_type_id=content_type_id, - object_id=str(object_id), - object_repr=object_repr[:200], - action_flag=action_flag, - change_message=change_message, - ) - def log_actions( self, user_id, queryset, action_flag, change_message="", *, single_object=False ): - # RemovedInDjango60Warning. - if type(self).log_action != LogEntryManager.log_action: - warnings.warn( - "The usage of log_action() is deprecated. Implement log_actions() " - "instead.", - RemovedInDjango60Warning, - stacklevel=2, - ) - return [ - self.log_action( - user_id=user_id, - content_type_id=ContentType.objects.get_for_model( - obj, for_concrete_model=False - ).id, - object_id=obj.pk, - object_repr=str(obj), - action_flag=action_flag, - change_message=change_message, - ) - for obj in queryset - ] - if isinstance(change_message, list): change_message = json.dumps(change_message) diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py index 69b0cc037325..3c2cf9d13061 100644 --- a/django/contrib/admin/options.py +++ b/django/contrib/admin/options.py @@ -2,7 +2,6 @@ import enum import json import re -import warnings from functools import partial, update_wrapper from urllib.parse import parse_qsl from urllib.parse import quote as urlquote @@ -56,7 +55,6 @@ from django.template.response import SimpleTemplateResponse, TemplateResponse from django.urls import reverse from django.utils.decorators import method_decorator -from django.utils.deprecation import RemovedInDjango60Warning from django.utils.html import format_html from django.utils.http import urlencode from django.utils.safestring import mark_safe @@ -448,9 +446,7 @@ def get_sortable_by(self, request): else self.get_list_display(request) ) - # RemovedInDjango60Warning: when the deprecation ends, replace with: - # def lookup_allowed(self, lookup, value, request): - def lookup_allowed(self, lookup, value, request=None): + def lookup_allowed(self, lookup, value, request): from django.contrib.admin.filters import SimpleListFilter model = self.model @@ -498,12 +494,7 @@ def lookup_allowed(self, lookup, value, request=None): # Either a local field filter, or no fields at all. return True valid_lookups = {self.date_hierarchy} - # RemovedInDjango60Warning: when the deprecation ends, replace with: - # for filter_item in self.get_list_filter(request): - list_filter = ( - self.get_list_filter(request) if request is not None else self.list_filter - ) - for filter_item in list_filter: + for filter_item in self.get_list_filter(request): if isinstance(filter_item, type) and issubclass( filter_item, SimpleListFilter ): @@ -974,28 +965,6 @@ def log_change(self, request, obj, message): single_object=True, ) - def log_deletion(self, request, obj, object_repr): - """ - Log that an object will be deleted. Note that this method must be - called before the deletion. - - The default implementation creates an admin LogEntry object. - """ - warnings.warn( - "ModelAdmin.log_deletion() is deprecated. Use log_deletions() instead.", - RemovedInDjango60Warning, - stacklevel=2, - ) - from django.contrib.admin.models import DELETION, LogEntry - - return LogEntry.objects.log_action( - user_id=request.user.pk, - content_type_id=get_content_type_for_model(obj).pk, - object_id=obj.pk, - object_repr=object_repr, - action_flag=DELETION, - ) - def log_deletions(self, request, queryset): """ Log that objects will be deleted. Note that this method must be called @@ -1005,16 +974,6 @@ def log_deletions(self, request, queryset): """ from django.contrib.admin.models import DELETION, LogEntry - # RemovedInDjango60Warning. - if type(self).log_deletion != ModelAdmin.log_deletion: - warnings.warn( - "The usage of log_deletion() is deprecated. Implement log_deletions() " - "instead.", - RemovedInDjango60Warning, - stacklevel=2, - ) - return [self.log_deletion(request, obj, str(obj)) for obj in queryset] - return LogEntry.objects.log_actions( user_id=request.user.pk, queryset=queryset, diff --git a/django/contrib/admin/views/main.py b/django/contrib/admin/views/main.py index ada8ce39fc38..ed6c6f92194a 100644 --- a/django/contrib/admin/views/main.py +++ b/django/contrib/admin/views/main.py @@ -1,4 +1,3 @@ -import warnings from datetime import datetime, timedelta from django import forms @@ -33,9 +32,7 @@ from django.db.models.constants import LOOKUP_SEP from django.db.models.expressions import Combinable from django.urls import reverse -from django.utils.deprecation import RemovedInDjango60Warning from django.utils.http import urlencode -from django.utils.inspect import func_supports_parameter from django.utils.timezone import make_aware from django.utils.translation import gettext @@ -178,19 +175,9 @@ def get_filters(self, request): may_have_duplicates = False has_active_filters = False - supports_request = func_supports_parameter( - self.model_admin.lookup_allowed, "request" - ) - if not supports_request: - warnings.warn( - f"`request` must be added to the signature of " - f"{self.model_admin.__class__.__qualname__}.lookup_allowed().", - RemovedInDjango60Warning, - ) for key, value_list in lookup_params.items(): for value in value_list: - params = (key, value, request) if supports_request else (key, value) - if not self.model_admin.lookup_allowed(*params): + if not self.model_admin.lookup_allowed(key, value, request): raise DisallowedModelAdminLookup(f"Filtering by {key} not allowed") filter_specs = [] diff --git a/django/contrib/auth/admin.py b/django/contrib/auth/admin.py index e977d3ded549..ab1432fa0980 100644 --- a/django/contrib/auth/admin.py +++ b/django/contrib/auth/admin.py @@ -106,9 +106,7 @@ def get_urls(self): ), ] + super().get_urls() - # RemovedInDjango60Warning: when the deprecation ends, replace with: - # def lookup_allowed(self, lookup, value, request): - def lookup_allowed(self, lookup, value, request=None): + def lookup_allowed(self, lookup, value, request): # Don't allow lookups involving passwords. return not lookup.startswith("password") and super().lookup_allowed( lookup, value, request diff --git a/django/contrib/auth/base_user.py b/django/contrib/auth/base_user.py index 5bb88ac4dd29..f19b2d89b963 100644 --- a/django/contrib/auth/base_user.py +++ b/django/contrib/auth/base_user.py @@ -58,11 +58,8 @@ class Meta: def __str__(self): return self.get_username() - # RemovedInDjango60Warning: When the deprecation ends, replace with: - # def save(self, **kwargs): - # super().save(**kwargs) - def save(self, *args, **kwargs): - super().save(*args, **kwargs) + def save(self, **kwargs): + super().save(**kwargs) if self._password is not None: password_validation.password_changed(self._password, self) self._password = None diff --git a/django/contrib/auth/hashers.py b/django/contrib/auth/hashers.py index b8a8246ac70d..3c886928454f 100644 --- a/django/contrib/auth/hashers.py +++ b/django/contrib/auth/hashers.py @@ -318,7 +318,7 @@ class PBKDF2PasswordHasher(BasePasswordHasher): """ algorithm = "pbkdf2_sha256" - iterations = 1_000_000 + iterations = 1_200_000 digest = hashlib.sha256 def encode(self, password, salt, iterations=None): diff --git a/django/contrib/contenttypes/fields.py b/django/contrib/contenttypes/fields.py index a3e87f6ed45e..0e68c2eef069 100644 --- a/django/contrib/contenttypes/fields.py +++ b/django/contrib/contenttypes/fields.py @@ -1,6 +1,5 @@ import functools import itertools -import warnings from collections import defaultdict from asgiref.sync import sync_to_async @@ -21,7 +20,6 @@ from django.db.models.sql import AND from django.db.models.sql.where import WhereNode from django.db.models.utils import AltersData -from django.utils.deprecation import RemovedInDjango60Warning from django.utils.functional import cached_property @@ -159,17 +157,6 @@ def get_content_type(self, obj=None, id=None, using=None, model=None): # This should never happen. I love comments like this, don't you? raise Exception("Impossible arguments to GFK.get_content_type!") - def get_prefetch_queryset(self, instances, queryset=None): - warnings.warn( - "get_prefetch_queryset() is deprecated. Use get_prefetch_querysets() " - "instead.", - RemovedInDjango60Warning, - stacklevel=2, - ) - if queryset is None: - return self.get_prefetch_querysets(instances) - return self.get_prefetch_querysets(instances, [queryset]) - def get_prefetch_querysets(self, instances, querysets=None): custom_queryset_dict = {} if querysets is not None: @@ -626,17 +613,6 @@ def get_queryset(self): queryset = super().get_queryset() return self._apply_rel_filters(queryset) - def get_prefetch_queryset(self, instances, queryset=None): - warnings.warn( - "get_prefetch_queryset() is deprecated. Use get_prefetch_querysets() " - "instead.", - RemovedInDjango60Warning, - stacklevel=2, - ) - if queryset is None: - return self.get_prefetch_querysets(instances) - return self.get_prefetch_querysets(instances, [queryset]) - def get_prefetch_querysets(self, instances, querysets=None): if querysets and len(querysets) != 1: raise ValueError( diff --git a/django/contrib/gis/db/backends/oracle/adapter.py b/django/contrib/gis/db/backends/oracle/adapter.py index 0bf11648d9da..bd52b1bf21a8 100644 --- a/django/contrib/gis/db/backends/oracle/adapter.py +++ b/django/contrib/gis/db/backends/oracle/adapter.py @@ -1,6 +1,7 @@ +import oracledb + from django.contrib.gis.db.backends.base.adapter import WKTAdapter from django.contrib.gis.geos import GeometryCollection, Polygon -from django.db.backends.oracle.oracledb_any import oracledb class OracleSpatialAdapter(WKTAdapter): diff --git a/django/contrib/gis/db/backends/oracle/introspection.py b/django/contrib/gis/db/backends/oracle/introspection.py index bf299b12ff72..8e1a5e7a8ce4 100644 --- a/django/contrib/gis/db/backends/oracle/introspection.py +++ b/django/contrib/gis/db/backends/oracle/introspection.py @@ -1,5 +1,6 @@ +import oracledb + from django.db.backends.oracle.introspection import DatabaseIntrospection -from django.db.backends.oracle.oracledb_any import oracledb from django.utils.functional import cached_property diff --git a/django/contrib/gis/gdal/geometries.py b/django/contrib/gis/gdal/geometries.py index 9e712037c0aa..b65d35bc4405 100644 --- a/django/contrib/gis/gdal/geometries.py +++ b/django/contrib/gis/gdal/geometries.py @@ -40,7 +40,6 @@ """ import sys -import warnings from binascii import b2a_hex from ctypes import byref, c_char_p, c_double, c_ubyte, c_void_p, string_at @@ -52,7 +51,6 @@ from django.contrib.gis.gdal.prototypes import srs as srs_api from django.contrib.gis.gdal.srs import CoordTransform, SpatialReference from django.contrib.gis.geometry import hex_regex, json_regex, wkt_regex -from django.utils.deprecation import RemovedInDjango60Warning from django.utils.encoding import force_bytes @@ -215,16 +213,6 @@ def coord_dim(self): "Return the coordinate dimension of the Geometry." return capi.get_coord_dim(self.ptr) - # RemovedInDjango60Warning - @coord_dim.setter - def coord_dim(self, dim): - "Set the coordinate dimension of this Geometry." - msg = "coord_dim setter is deprecated. Use set_3d() instead." - warnings.warn(msg, RemovedInDjango60Warning, stacklevel=2) - if dim not in (2, 3): - raise ValueError("Geometry dimension must be either 2 or 3") - capi.set_coord_dim(self.ptr, dim) - @property def geom_count(self): "Return the number of elements in this Geometry." diff --git a/django/contrib/gis/geoip2.py b/django/contrib/gis/geoip2.py index 5b510dee7f96..1e4a464068b6 100644 --- a/django/contrib/gis/geoip2.py +++ b/django/contrib/gis/geoip2.py @@ -14,13 +14,11 @@ import ipaddress import socket -import warnings from django.conf import settings from django.core.exceptions import ValidationError from django.core.validators import validate_ipv46_address from django.utils._os import to_path -from django.utils.deprecation import RemovedInDjango60Warning from django.utils.functional import cached_property __all__ = ["HAS_GEOIP2"] @@ -214,15 +212,6 @@ def country(self, query): "is_in_european_union": response.country.is_in_european_union, } - def coords(self, query, ordering=("longitude", "latitude")): - warnings.warn( - "GeoIP2.coords() is deprecated. Use GeoIP2.lon_lat() instead.", - RemovedInDjango60Warning, - stacklevel=2, - ) - data = self.city(query) - return tuple(data[o] for o in ordering) - def lon_lat(self, query): "Return a tuple of the (longitude, latitude) for the given query." data = self.city(query) @@ -239,12 +228,3 @@ def geos(self, query): from django.contrib.gis.geos import Point return Point(self.lon_lat(query), srid=4326) - - @classmethod - def open(cls, full_path, cache): - warnings.warn( - "GeoIP2.open() is deprecated. Use GeoIP2() instead.", - RemovedInDjango60Warning, - stacklevel=2, - ) - return GeoIP2(full_path, cache) diff --git a/django/core/files/storage/filesystem.py b/django/core/files/storage/filesystem.py index bf2b9caad4d1..b8de9b0a589b 100644 --- a/django/core/files/storage/filesystem.py +++ b/django/core/files/storage/filesystem.py @@ -1,5 +1,4 @@ import os -import warnings from datetime import datetime, timezone from urllib.parse import urljoin @@ -9,7 +8,6 @@ from django.core.signals import setting_changed from django.utils._os import safe_join from django.utils.deconstruct import deconstructible -from django.utils.deprecation import RemovedInDjango60Warning from django.utils.encoding import filepath_to_uri from django.utils.functional import cached_property @@ -23,9 +21,6 @@ class FileSystemStorage(Storage, StorageSettingsMixin): Standard filesystem storage """ - # RemovedInDjango60Warning: remove OS_OPEN_FLAGS. - OS_OPEN_FLAGS = os.O_WRONLY | os.O_CREAT | os.O_EXCL | getattr(os, "O_BINARY", 0) - def __init__( self, location=None, @@ -40,16 +35,6 @@ def __init__( self._directory_permissions_mode = directory_permissions_mode self._allow_overwrite = allow_overwrite setting_changed.connect(self._clear_cached_properties) - # RemovedInDjango60Warning: remove this warning. - if self.OS_OPEN_FLAGS != os.O_WRONLY | os.O_CREAT | os.O_EXCL | getattr( - os, "O_BINARY", 0 - ): - warnings.warn( - "Overriding OS_OPEN_FLAGS is deprecated. Use " - "the allow_overwrite parameter instead.", - RemovedInDjango60Warning, - stacklevel=2, - ) @cached_property def base_location(self): @@ -127,12 +112,7 @@ def _save(self, name, content): | os.O_EXCL | getattr(os, "O_BINARY", 0) ) - # RemovedInDjango60Warning: when the deprecation ends, replace with: - # if self._allow_overwrite: - # open_flags = open_flags & ~os.O_EXCL - if self.OS_OPEN_FLAGS != open_flags: - open_flags = self.OS_OPEN_FLAGS - elif self._allow_overwrite: + if self._allow_overwrite: open_flags = open_flags & ~os.O_EXCL fd = os.open(full_path, open_flags, 0o666) _file = None diff --git a/django/db/backends/base/operations.py b/django/db/backends/base/operations.py index 60de2d6c79f8..8f2660d92882 100644 --- a/django/db/backends/base/operations.py +++ b/django/db/backends/base/operations.py @@ -1,7 +1,6 @@ import datetime import decimal import json -import warnings from importlib import import_module import sqlparse @@ -10,7 +9,6 @@ from django.db import NotSupportedError, transaction from django.db.models.expressions import Col from django.utils import timezone -from django.utils.deprecation import RemovedInDjango60Warning from django.utils.encoding import force_str @@ -214,23 +212,6 @@ def fetch_returned_insert_columns(self, cursor, returning_params): """ return cursor.fetchone() - def field_cast_sql(self, db_type, internal_type): - """ - Given a column type (e.g. 'BLOB', 'VARCHAR') and an internal type - (e.g. 'GenericIPAddressField'), return the SQL to cast it before using - it in a WHERE statement. The resulting string should contain a '%s' - placeholder for the column being searched against. - """ - warnings.warn( - ( - "DatabaseOperations.field_cast_sql() is deprecated use " - "DatabaseOperations.lookup_cast() instead." - ), - RemovedInDjango60Warning, - stacklevel=2, - ) - return "%s" - def force_group_by(self): """ Return a GROUP BY clause to use with a HAVING clause when no grouping diff --git a/django/db/backends/oracle/base.py b/django/db/backends/oracle/base.py index 3b37c38f9723..9fd82dd705a1 100644 --- a/django/db/backends/oracle/base.py +++ b/django/db/backends/oracle/base.py @@ -14,7 +14,6 @@ from django.core.exceptions import ImproperlyConfigured from django.db import IntegrityError from django.db.backends.base.base import BaseDatabaseWrapper -from django.db.backends.oracle.oracledb_any import is_oracledb from django.db.backends.utils import debug_transaction from django.utils.asyncio import async_unsafe from django.utils.encoding import force_bytes, force_str @@ -22,7 +21,7 @@ from django.utils.version import get_version_tuple try: - from django.db.backends.oracle.oracledb_any import oracledb as Database + import oracledb as Database except ImportError as e: raise ImproperlyConfigured(f"Error loading oracledb module: {e}") @@ -286,11 +285,6 @@ def get_database_version(self): return self.oracle_version def get_connection_params(self): - # Pooling feature is only supported for oracledb. - if self.is_pool and not is_oracledb: - raise ImproperlyConfigured( - "Pooling isn't supported by cx_Oracle. Use python-oracledb instead." - ) conn_params = self.settings_dict["OPTIONS"].copy() if "use_returning_into" in conn_params: del conn_params["use_returning_into"] diff --git a/django/db/backends/oracle/features.py b/django/db/backends/oracle/features.py index ad9ab8da55bb..bf47577ed63d 100644 --- a/django/db/backends/oracle/features.py +++ b/django/db/backends/oracle/features.py @@ -1,6 +1,5 @@ from django.db import DatabaseError, InterfaceError from django.db.backends.base.features import BaseDatabaseFeatures -from django.db.backends.oracle.oracledb_any import is_oracledb from django.utils.functional import cached_property @@ -158,16 +157,6 @@ def django_test_skips(self): }, } ) - if is_oracledb and self.connection.oracledb_version >= (2, 1, 2): - skips.update( - { - "python-oracledb 2.1.2+ no longer hides 'ORA-1403: no data found' " - "exceptions raised in database triggers.": { - "backends.oracle.tests.TransactionalTests." - "test_hidden_no_data_found_exception" - }, - }, - ) return skips @cached_property diff --git a/django/db/backends/oracle/introspection.py b/django/db/backends/oracle/introspection.py index 07c2d9bded81..393e6c66d779 100644 --- a/django/db/backends/oracle/introspection.py +++ b/django/db/backends/oracle/introspection.py @@ -1,10 +1,11 @@ from collections import namedtuple +import oracledb + from django.db import models from django.db.backends.base.introspection import BaseDatabaseIntrospection from django.db.backends.base.introspection import FieldInfo as BaseFieldInfo from django.db.backends.base.introspection import TableInfo as BaseTableInfo -from django.db.backends.oracle.oracledb_any import oracledb FieldInfo = namedtuple( "FieldInfo", BaseFieldInfo._fields + ("is_autofield", "is_json", "comment") diff --git a/django/db/backends/oracle/operations.py b/django/db/backends/oracle/operations.py index 79c6da994edd..aa67f28a79d0 100644 --- a/django/db/backends/oracle/operations.py +++ b/django/db/backends/oracle/operations.py @@ -3,7 +3,7 @@ from functools import lru_cache from django.conf import settings -from django.db import DatabaseError, NotSupportedError +from django.db import NotSupportedError from django.db.backends.base.operations import BaseDatabaseOperations from django.db.backends.utils import split_tzname_delta, strip_quotes, truncate_name from django.db.models import AutoField, Exists, ExpressionWrapper, Lookup @@ -295,15 +295,6 @@ def fetch_returned_insert_columns(self, cursor, returning_params): columns = [] for param in returning_params: value = param.get_value() - # Can be removed when cx_Oracle is no longer supported and - # python-oracle 2.1.2 becomes the minimum supported version. - if value == []: - raise DatabaseError( - "The database did not return a new row id. Probably " - '"ORA-1403: no data found" was raised internally but was ' - "hidden by the Oracle OCI library (see " - "https://code.djangoproject.com/ticket/28859)." - ) columns.append(value[0]) return tuple(columns) diff --git a/django/db/backends/oracle/oracledb_any.py b/django/db/backends/oracle/oracledb_any.py deleted file mode 100644 index 22a9b78be81e..000000000000 --- a/django/db/backends/oracle/oracledb_any.py +++ /dev/null @@ -1,20 +0,0 @@ -import warnings - -from django.utils.deprecation import RemovedInDjango60Warning - -try: - import oracledb - - is_oracledb = True -except ImportError as e: - try: - import cx_Oracle as oracledb # NOQA - - warnings.warn( - "cx_Oracle is deprecated. Use oracledb instead.", - RemovedInDjango60Warning, - stacklevel=2, - ) - is_oracledb = False - except ImportError: - raise e from None diff --git a/django/db/models/base.py b/django/db/models/base.py index d7d207901b90..575365e11c73 100644 --- a/django/db/models/base.py +++ b/django/db/models/base.py @@ -50,7 +50,6 @@ pre_save, ) from django.db.models.utils import AltersData, make_model_tuple -from django.utils.deprecation import RemovedInDjango60Warning from django.utils.encoding import force_str from django.utils.hashable import make_hashable from django.utils.text import capfirst, get_text_list @@ -786,50 +785,9 @@ def serializable_value(self, field_name): return getattr(self, field_name) return getattr(self, field.attname) - # RemovedInDjango60Warning: When the deprecation ends, remove completely. - def _parse_save_params(self, *args, method_name, **kwargs): - defaults = { - "force_insert": False, - "force_update": False, - "using": None, - "update_fields": None, - } - - warnings.warn( - f"Passing positional arguments to {method_name}() is deprecated", - RemovedInDjango60Warning, - stacklevel=3, - ) - total_len_args = len(args) + 1 # include self - max_len_args = len(defaults) + 1 - if total_len_args > max_len_args: - # Recreate the proper TypeError message from Python. - raise TypeError( - f"Model.{method_name}() takes from 1 to {max_len_args} positional " - f"arguments but {total_len_args} were given" - ) - - def get_param(param_name, param_value, arg_index): - if arg_index < len(args): - if param_value is not defaults[param_name]: - # Recreate the proper TypeError message from Python. - raise TypeError( - f"Model.{method_name}() got multiple values for argument " - f"'{param_name}'" - ) - return args[arg_index] - - return param_value - - return [get_param(k, v, i) for i, (k, v) in enumerate(kwargs.items())] - - # RemovedInDjango60Warning: When the deprecation ends, replace with: - # def save( - # self, *, force_insert=False, force_update=False, using=None, update_fields=None, - # ): def save( self, - *args, + *, force_insert=False, force_update=False, using=None, @@ -843,16 +801,6 @@ def save( that the "save" must be an SQL insert or update (or equivalent for non-SQL backends), respectively. Normally, they should not be set. """ - # RemovedInDjango60Warning. - if args: - force_insert, force_update, using, update_fields = self._parse_save_params( - *args, - method_name="save", - force_insert=force_insert, - force_update=force_update, - using=using, - update_fields=update_fields, - ) self._prepare_related_fields_for_save(operation_name="save") @@ -908,28 +856,14 @@ def save( save.alters_data = True - # RemovedInDjango60Warning: When the deprecation ends, replace with: - # async def asave( - # self, *, force_insert=False, force_update=False, using=None, update_fields=None, - # ): async def asave( self, - *args, + *, force_insert=False, force_update=False, using=None, update_fields=None, ): - # RemovedInDjango60Warning. - if args: - force_insert, force_update, using, update_fields = self._parse_save_params( - *args, - method_name="asave", - force_insert=force_insert, - force_update=force_update, - using=using, - update_fields=update_fields, - ) return await sync_to_async(self.save)( force_insert=force_insert, force_update=force_update, diff --git a/django/db/models/constraints.py b/django/db/models/constraints.py index 1601fc993390..16606e18984e 100644 --- a/django/db/models/constraints.py +++ b/django/db/models/constraints.py @@ -1,4 +1,3 @@ -import warnings from enum import Enum from types import NoneType @@ -12,7 +11,6 @@ from django.db.models.query_utils import Q from django.db.models.sql.query import Query from django.db.utils import DEFAULT_DB_ALIAS -from django.utils.deprecation import RemovedInDjango60Warning from django.utils.translation import gettext_lazy as _ __all__ = ["BaseConstraint", "CheckConstraint", "Deferrable", "UniqueConstraint"] @@ -25,19 +23,9 @@ class BaseConstraint: non_db_attrs = ("violation_error_code", "violation_error_message") - # RemovedInDjango60Warning: When the deprecation ends, replace with: - # def __init__( - # self, *, name, violation_error_code=None, violation_error_message=None - # ): def __init__( - self, *args, name=None, violation_error_code=None, violation_error_message=None + self, *, name, violation_error_code=None, violation_error_message=None ): - # RemovedInDjango60Warning. - if name is None and not args: - raise TypeError( - f"{self.__class__.__name__}.__init__() missing 1 required keyword-only " - f"argument: 'name'" - ) self.name = name if violation_error_code is not None: self.violation_error_code = violation_error_code @@ -45,17 +33,6 @@ def __init__( self.violation_error_message = violation_error_message else: self.violation_error_message = self.default_violation_error_message - # RemovedInDjango60Warning. - if args: - warnings.warn( - f"Passing positional arguments to {self.__class__.__name__} is " - f"deprecated.", - RemovedInDjango60Warning, - stacklevel=2, - ) - for arg, attr in zip(args, ["name", "violation_error_message"]): - if arg: - setattr(self, attr, arg) @property def contains_expressions(self): @@ -151,26 +128,14 @@ def clone(self): class CheckConstraint(BaseConstraint): - # RemovedInDjango60Warning: when the deprecation ends, replace with - # def __init__( - # self, *, condition, name, violation_error_code=None, violation_error_message=None - # ) def __init__( self, *, + condition, name, - condition=None, - check=None, violation_error_code=None, violation_error_message=None, ): - if check is not None: - warnings.warn( - "CheckConstraint.check is deprecated in favor of `.condition`.", - RemovedInDjango60Warning, - stacklevel=2, - ) - condition = check self.condition = condition if not getattr(condition, "conditional", False): raise TypeError( @@ -182,24 +147,6 @@ def __init__( violation_error_message=violation_error_message, ) - def _get_check(self): - warnings.warn( - "CheckConstraint.check is deprecated in favor of `.condition`.", - RemovedInDjango60Warning, - stacklevel=2, - ) - return self.condition - - def _set_check(self, value): - warnings.warn( - "CheckConstraint.check is deprecated in favor of `.condition`.", - RemovedInDjango60Warning, - stacklevel=2, - ) - self.condition = value - - check = property(_get_check, _set_check) - def _check(self, model, connection): errors = [] if not ( diff --git a/django/db/models/enums.py b/django/db/models/enums.py index bdc669bff08d..54e8bf8fadd4 100644 --- a/django/db/models/enums.py +++ b/django/db/models/enums.py @@ -1,7 +1,5 @@ import enum -import warnings -from django.utils.deprecation import RemovedInDjango60Warning from django.utils.functional import Promise from django.utils.version import PY311, PY312 @@ -110,14 +108,3 @@ class TextChoices(Choices, StrEnum): @staticmethod def _generate_next_value_(name, start, count, last_values): return name - - -def __getattr__(name): - if name == "ChoicesMeta": - warnings.warn( - "ChoicesMeta is deprecated in favor of ChoicesType.", - RemovedInDjango60Warning, - stacklevel=2, - ) - return ChoicesType - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/django/db/models/fields/mixins.py b/django/db/models/fields/mixins.py index 677430377397..7de4120a1e5f 100644 --- a/django/db/models/fields/mixins.py +++ b/django/db/models/fields/mixins.py @@ -1,7 +1,4 @@ -import warnings - from django.core import checks -from django.utils.deprecation import RemovedInDjango60Warning from django.utils.functional import cached_property NOT_PROVIDED = object() @@ -15,22 +12,9 @@ class FieldCacheMixin: typically the field’s name. """ - # RemovedInDjango60Warning. - def get_cache_name(self): - raise NotImplementedError - @cached_property def cache_name(self): - # RemovedInDjango60Warning: when the deprecation ends, replace with: - # raise NotImplementedError - cache_name = self.get_cache_name() - warnings.warn( - f"Override {self.__class__.__qualname__}.cache_name instead of " - "get_cache_name().", - RemovedInDjango60Warning, - stacklevel=3, - ) - return cache_name + raise NotImplementedError def get_cached_value(self, instance, default=NOT_PROVIDED): try: diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py index de8fe9c339fa..2f12f993e829 100644 --- a/django/db/models/fields/related.py +++ b/django/db/models/fields/related.py @@ -1,6 +1,5 @@ import functools import inspect -import warnings from functools import partial from django import forms @@ -14,7 +13,6 @@ from django.db.models.deletion import CASCADE, SET_DEFAULT, SET_NULL from django.db.models.query_utils import PathInfo from django.db.models.utils import make_model_tuple -from django.utils.deprecation import RemovedInDjango60Warning from django.utils.functional import cached_property from django.utils.translation import gettext_lazy as _ @@ -817,27 +815,6 @@ def get_attname_column(self): attname, column = super().get_attname_column() return attname, None - def get_joining_columns(self, reverse_join=False): - warnings.warn( - "ForeignObject.get_joining_columns() is deprecated. Use " - "get_joining_fields() instead.", - RemovedInDjango60Warning, - stacklevel=2, - ) - source = self.reverse_related_fields if reverse_join else self.related_fields - return tuple( - (lhs_field.column, rhs_field.column) for lhs_field, rhs_field in source - ) - - def get_reverse_joining_columns(self): - warnings.warn( - "ForeignObject.get_reverse_joining_columns() is deprecated. Use " - "get_reverse_joining_fields() instead.", - RemovedInDjango60Warning, - stacklevel=2, - ) - return self.get_joining_columns(reverse_join=True) - def get_joining_fields(self, reverse_join=False): return tuple( self.reverse_related_fields if reverse_join else self.related_fields diff --git a/django/db/models/fields/related_descriptors.py b/django/db/models/fields/related_descriptors.py index 66c978d42e8d..bbbcc07990ba 100644 --- a/django/db/models/fields/related_descriptors.py +++ b/django/db/models/fields/related_descriptors.py @@ -63,8 +63,6 @@ class Child(Model): ``ReverseManyToManyDescriptor``, use ``ManyToManyDescriptor`` instead. """ -import warnings - from asgiref.sync import sync_to_async from django.core.exceptions import FieldError @@ -81,7 +79,6 @@ class Child(Model): from django.db.models.query import QuerySet from django.db.models.query_utils import DeferredAttribute from django.db.models.utils import AltersData, resolve_callables -from django.utils.deprecation import RemovedInDjango60Warning from django.utils.functional import cached_property @@ -155,17 +152,6 @@ def is_cached(self, instance): def get_queryset(self, **hints): return self.field.remote_field.model._base_manager.db_manager(hints=hints).all() - def get_prefetch_queryset(self, instances, queryset=None): - warnings.warn( - "get_prefetch_queryset() is deprecated. Use get_prefetch_querysets() " - "instead.", - RemovedInDjango60Warning, - stacklevel=2, - ) - if queryset is None: - return self.get_prefetch_querysets(instances) - return self.get_prefetch_querysets(instances, [queryset]) - def get_prefetch_querysets(self, instances, querysets=None): if querysets and len(querysets) != 1: raise ValueError( @@ -447,17 +433,6 @@ def is_cached(self, instance): def get_queryset(self, **hints): return self.related.related_model._base_manager.db_manager(hints=hints).all() - def get_prefetch_queryset(self, instances, queryset=None): - warnings.warn( - "get_prefetch_queryset() is deprecated. Use get_prefetch_querysets() " - "instead.", - RemovedInDjango60Warning, - stacklevel=2, - ) - if queryset is None: - return self.get_prefetch_querysets(instances) - return self.get_prefetch_querysets(instances, [queryset]) - def get_prefetch_querysets(self, instances, querysets=None): if querysets and len(querysets) != 1: raise ValueError( @@ -765,17 +740,6 @@ def get_queryset(self): queryset = super().get_queryset() return self._apply_rel_filters(queryset) - def get_prefetch_queryset(self, instances, queryset=None): - warnings.warn( - "get_prefetch_queryset() is deprecated. Use get_prefetch_querysets() " - "instead.", - RemovedInDjango60Warning, - stacklevel=2, - ) - if queryset is None: - return self.get_prefetch_querysets(instances) - return self.get_prefetch_querysets(instances, [queryset]) - def get_prefetch_querysets(self, instances, querysets=None): if querysets and len(querysets) != 1: raise ValueError( @@ -1145,17 +1109,6 @@ def get_queryset(self): queryset = super().get_queryset() return self._apply_rel_filters(queryset) - def get_prefetch_queryset(self, instances, queryset=None): - warnings.warn( - "get_prefetch_queryset() is deprecated. Use get_prefetch_querysets() " - "instead.", - RemovedInDjango60Warning, - stacklevel=2, - ) - if queryset is None: - return self.get_prefetch_querysets(instances) - return self.get_prefetch_querysets(instances, [queryset]) - def get_prefetch_querysets(self, instances, querysets=None): if querysets and len(querysets) != 1: raise ValueError( diff --git a/django/db/models/fields/reverse_related.py b/django/db/models/fields/reverse_related.py index 85378431a78f..c1a4d8e79644 100644 --- a/django/db/models/fields/reverse_related.py +++ b/django/db/models/fields/reverse_related.py @@ -9,10 +9,7 @@ they're the closest concept currently available. """ -import warnings - from django.core import exceptions -from django.utils.deprecation import RemovedInDjango60Warning from django.utils.functional import cached_property from django.utils.hashable import make_hashable @@ -192,15 +189,6 @@ def get_choices( qs = qs.order_by(*ordering) return (blank_choice if include_blank else []) + [(x.pk, str(x)) for x in qs] - def get_joining_columns(self): - warnings.warn( - "ForeignObjectRel.get_joining_columns() is deprecated. Use " - "get_joining_fields() instead.", - RemovedInDjango60Warning, - stacklevel=2, - ) - return self.field.get_reverse_joining_columns() - def get_joining_fields(self): return self.field.get_reverse_joining_fields() diff --git a/django/db/models/lookups.py b/django/db/models/lookups.py index 56dbdabac1e2..860488794c6e 100644 --- a/django/db/models/lookups.py +++ b/django/db/models/lookups.py @@ -1,9 +1,7 @@ import itertools import math -import warnings from django.core.exceptions import EmptyResultSet, FullResultSet -from django.db.backends.base.operations import BaseDatabaseOperations from django.db.models.expressions import Case, ColPairs, Expression, Func, Value, When from django.db.models.fields import ( BooleanField, @@ -15,7 +13,6 @@ ) from django.db.models.query_utils import RegisterLookupMixin from django.utils.datastructures import OrderedSet -from django.utils.deprecation import RemovedInDjango60Warning from django.utils.functional import cached_property from django.utils.hashable import make_hashable @@ -224,22 +221,6 @@ class BuiltinLookup(Lookup): def process_lhs(self, compiler, connection, lhs=None): lhs_sql, params = super().process_lhs(compiler, connection, lhs) field_internal_type = self.lhs.output_field.get_internal_type() - if ( - hasattr(connection.ops.__class__, "field_cast_sql") - and connection.ops.__class__.field_cast_sql - is not BaseDatabaseOperations.field_cast_sql - ): - warnings.warn( - ( - "The usage of DatabaseOperations.field_cast_sql() is deprecated. " - "Implement DatabaseOperations.lookup_cast() instead." - ), - RemovedInDjango60Warning, - ) - db_type = self.lhs.output_field.db_type(connection=connection) - lhs_sql = ( - connection.ops.field_cast_sql(db_type, field_internal_type) % lhs_sql - ) lhs_sql = ( connection.ops.lookup_cast(self.lookup_name, field_internal_type) % lhs_sql ) diff --git a/django/db/models/query.py b/django/db/models/query.py index 25995b0d8372..eb17624bf108 100644 --- a/django/db/models/query.py +++ b/django/db/models/query.py @@ -33,7 +33,6 @@ resolve_callables, ) from django.utils import timezone -from django.utils.deprecation import RemovedInDjango60Warning from django.utils.functional import cached_property, partition # The maximum number of results to fetch in a get() query. @@ -2239,16 +2238,6 @@ def get_current_to_attr(self, level): as_attr = self.to_attr and level == len(parts) - 1 return to_attr, as_attr - def get_current_queryset(self, level): - warnings.warn( - "Prefetch.get_current_queryset() is deprecated. Use " - "get_current_querysets() instead.", - RemovedInDjango60Warning, - stacklevel=2, - ) - querysets = self.get_current_querysets(level) - return querysets[0] if querysets is not None else None - def get_current_querysets(self, level): if ( self.get_current_prefetch_to(level) == self.prefetch_to @@ -2480,11 +2469,7 @@ def has_to_attr_attribute(instance): if rel_obj_descriptor: # singly related object, descriptor object has the # get_prefetch_querysets() method. - if ( - hasattr(rel_obj_descriptor, "get_prefetch_querysets") - # RemovedInDjango60Warning. - or hasattr(rel_obj_descriptor, "get_prefetch_queryset") - ): + if hasattr(rel_obj_descriptor, "get_prefetch_querysets"): prefetcher = rel_obj_descriptor # If to_attr is set, check if the value has already been set, # which is done with has_to_attr_attribute(). Do not use the @@ -2497,11 +2482,7 @@ def has_to_attr_attribute(instance): # the attribute on the instance rather than the class to # support many related managers rel_obj = getattr(instance, through_attr) - if ( - hasattr(rel_obj, "get_prefetch_querysets") - # RemovedInDjango60Warning. - or hasattr(rel_obj, "get_prefetch_queryset") - ): + if hasattr(rel_obj, "get_prefetch_querysets"): prefetcher = rel_obj if through_attr == to_attr: @@ -2534,36 +2515,16 @@ def prefetch_one_level(instances, prefetcher, lookup, level): # The 'values to be matched' must be hashable as they will be used # in a dictionary. - - if hasattr(prefetcher, "get_prefetch_querysets"): - ( - rel_qs, - rel_obj_attr, - instance_attr, - single, - cache_name, - is_descriptor, - ) = prefetcher.get_prefetch_querysets( - instances, lookup.get_current_querysets(level) - ) - else: - warnings.warn( - "The usage of get_prefetch_queryset() in prefetch_related_objects() is " - "deprecated. Implement get_prefetch_querysets() instead.", - RemovedInDjango60Warning, - stacklevel=2, - ) - queryset = None - if querysets := lookup.get_current_querysets(level): - queryset = querysets[0] - ( - rel_qs, - rel_obj_attr, - instance_attr, - single, - cache_name, - is_descriptor, - ) = prefetcher.get_prefetch_queryset(instances, queryset) + ( + rel_qs, + rel_obj_attr, + instance_attr, + single, + cache_name, + is_descriptor, + ) = prefetcher.get_prefetch_querysets( + instances, lookup.get_current_querysets(level) + ) # We have to handle the possibility that the QuerySet we just got back # contains some prefetch_related lookups. We don't want to trigger the # prefetch_related functionality by evaluating the query. Rather, we need diff --git a/django/db/models/sql/datastructures.py b/django/db/models/sql/datastructures.py index 7c0c14a46e87..be6934485ccc 100644 --- a/django/db/models/sql/datastructures.py +++ b/django/db/models/sql/datastructures.py @@ -3,11 +3,8 @@ the SQL domain. """ -import warnings - from django.core.exceptions import FullResultSet from django.db.models.sql.constants import INNER, LOUTER -from django.utils.deprecation import RemovedInDjango60Warning class MultiJoin(Exception): @@ -65,20 +62,11 @@ def __init__( self.join_type = join_type # A list of 2-tuples to use in the ON clause of the JOIN. # Each 2-tuple will create one join condition in the ON clause. - if hasattr(join_field, "get_joining_fields"): - self.join_fields = join_field.get_joining_fields() - self.join_cols = tuple( - (lhs_field.column, rhs_field.column) - for lhs_field, rhs_field in self.join_fields - ) - else: - warnings.warn( - "The usage of get_joining_columns() in Join is deprecated. Implement " - "get_joining_fields() instead.", - RemovedInDjango60Warning, - ) - self.join_fields = None - self.join_cols = join_field.get_joining_columns() + self.join_fields = join_field.get_joining_fields() + self.join_cols = tuple( + (lhs_field.column, rhs_field.column) + for lhs_field, rhs_field in self.join_fields + ) # Along which field (or ForeignObjectRel in the reverse join case) self.join_field = join_field # Is this join nullabled? @@ -94,25 +82,15 @@ def as_sql(self, compiler, connection): join_conditions = [] params = [] qn = compiler.quote_name_unless_alias - qn2 = connection.ops.quote_name # Add a join condition for each pair of joining columns. - # RemovedInDjango60Warning: when the depraction ends, replace with: - # for lhs, rhs in self.join_field: - join_fields = self.join_fields or self.join_cols - for lhs, rhs in join_fields: - if isinstance(lhs, str): - # RemovedInDjango60Warning: when the depraction ends, remove - # the branch for strings. - lhs_full_name = "%s.%s" % (qn(self.parent_alias), qn2(lhs)) - rhs_full_name = "%s.%s" % (qn(self.table_alias), qn2(rhs)) - else: - lhs, rhs = connection.ops.prepare_join_on_clause( - self.parent_alias, lhs, self.table_alias, rhs - ) - lhs_sql, lhs_params = compiler.compile(lhs) - lhs_full_name = lhs_sql % lhs_params - rhs_sql, rhs_params = compiler.compile(rhs) - rhs_full_name = rhs_sql % rhs_params + for lhs, rhs in self.join_fields: + lhs, rhs = connection.ops.prepare_join_on_clause( + self.parent_alias, lhs, self.table_alias, rhs + ) + lhs_sql, lhs_params = compiler.compile(lhs) + lhs_full_name = lhs_sql % lhs_params + rhs_sql, rhs_params = compiler.compile(rhs) + rhs_full_name = rhs_sql % rhs_params join_conditions.append(f"{lhs_full_name} = {rhs_full_name}") # Add a single condition inside parentheses for whatever diff --git a/django/forms/fields.py b/django/forms/fields.py index 202a6d72c878..bde048aebf0c 100644 --- a/django/forms/fields.py +++ b/django/forms/fields.py @@ -10,12 +10,10 @@ import os import re import uuid -import warnings from decimal import Decimal, DecimalException from io import BytesIO from urllib.parse import urlsplit, urlunsplit -from django.conf import settings from django.core import validators from django.core.exceptions import ValidationError from django.forms.boundfield import BoundField @@ -44,7 +42,6 @@ from django.utils import formats from django.utils.choices import normalize_choices from django.utils.dateparse import parse_datetime, parse_duration -from django.utils.deprecation import RemovedInDjango60Warning from django.utils.duration import duration_string from django.utils.ipv6 import MAX_IPV6_ADDRESS_LENGTH, clean_ipv6_address from django.utils.regex_helper import _lazy_re_compile @@ -770,23 +767,7 @@ class URLField(CharField): default_validators = [validators.URLValidator()] def __init__(self, *, assume_scheme=None, **kwargs): - if assume_scheme is None: - if settings.FORMS_URLFIELD_ASSUME_HTTPS: - assume_scheme = "https" - else: - warnings.warn( - "The default scheme will be changed from 'http' to 'https' in " - "Django 6.0. Pass the forms.URLField.assume_scheme argument to " - "silence this warning, or set the FORMS_URLFIELD_ASSUME_HTTPS " - "transitional setting to True to opt into using 'https' as the new " - "default scheme.", - RemovedInDjango60Warning, - stacklevel=2, - ) - assume_scheme = "http" - # RemovedInDjango60Warning: When the deprecation ends, replace with: - # self.assume_scheme = assume_scheme or "https" - self.assume_scheme = assume_scheme + self.assume_scheme = assume_scheme or "https" super().__init__(strip=True, **kwargs) def to_python(self, value): diff --git a/django/forms/renderers.py b/django/forms/renderers.py index baf8f7450765..8df29ad0d3db 100644 --- a/django/forms/renderers.py +++ b/django/forms/renderers.py @@ -1,11 +1,9 @@ import functools -import warnings from pathlib import Path from django.conf import settings from django.template.backends.django import DjangoTemplates from django.template.loader import get_template -from django.utils.deprecation import RemovedInDjango60Warning from django.utils.functional import cached_property from django.utils.module_loading import import_string @@ -67,41 +65,6 @@ def backend(self): return Jinja2 -# RemovedInDjango60Warning. -class DjangoDivFormRenderer(DjangoTemplates): - """ - Load Django templates from django/forms/templates and from apps' - 'templates' directory and use the 'div.html' template to render forms and - formsets. - """ - - def __init__(self, *args, **kwargs): - warnings.warn( - "The DjangoDivFormRenderer transitional form renderer is deprecated. Use " - "DjangoTemplates instead.", - RemovedInDjango60Warning, - stacklevel=2, - ) - super().__init__(*args, **kwargs) - - -# RemovedInDjango60Warning. -class Jinja2DivFormRenderer(Jinja2): - """ - Load Jinja2 templates from the built-in widget templates in - django/forms/jinja2 and from apps' 'jinja2' directory. - """ - - def __init__(self, *args, **kwargs): - warnings.warn( - "The Jinja2DivFormRenderer transitional form renderer is deprecated. Use " - "Jinja2 instead.", - RemovedInDjango60Warning, - stacklevel=2, - ) - super().__init__(*args, **kwargs) - - class TemplatesSetting(BaseRenderer): """ Load templates using template.loader.get_template() which is configured diff --git a/django/urls/converters.py b/django/urls/converters.py index b36cde1497b0..d44588174e03 100644 --- a/django/urls/converters.py +++ b/django/urls/converters.py @@ -1,8 +1,5 @@ import functools import uuid -import warnings - -from django.utils.deprecation import RemovedInDjango60Warning class IntConverter: @@ -57,14 +54,7 @@ class PathConverter(StringConverter): def register_converter(converter, type_name): if type_name in REGISTERED_CONVERTERS or type_name in DEFAULT_CONVERTERS: - # RemovedInDjango60Warning: when the deprecation ends, replace with - # raise ValueError(f"Converter {type_name} is already registered.") - warnings.warn( - f"Converter {type_name!r} is already registered. Support for overriding " - "registered converters is deprecated and will be removed in Django 6.0.", - RemovedInDjango60Warning, - stacklevel=2, - ) + raise ValueError(f"Converter {type_name!r} is already registered.") REGISTERED_CONVERTERS[type_name] = converter() get_converters.cache_clear() diff --git a/django/utils/deprecation.py b/django/utils/deprecation.py index d690dc5d5682..6f3852cc04f9 100644 --- a/django/utils/deprecation.py +++ b/django/utils/deprecation.py @@ -4,16 +4,16 @@ from asgiref.sync import iscoroutinefunction, markcoroutinefunction, sync_to_async -class RemovedInDjango60Warning(DeprecationWarning): +class RemovedInDjango61Warning(DeprecationWarning): pass -class RemovedInDjango61Warning(PendingDeprecationWarning): +class RemovedInDjango70Warning(PendingDeprecationWarning): pass -RemovedInNextVersionWarning = RemovedInDjango60Warning -RemovedAfterNextVersionWarning = RemovedInDjango61Warning +RemovedInNextVersionWarning = RemovedInDjango61Warning +RemovedAfterNextVersionWarning = RemovedInDjango70Warning class warn_about_renamed_method: diff --git a/django/utils/html.py b/django/utils/html.py index 10036c38c479..310742afe1fe 100644 --- a/django/utils/html.py +++ b/django/utils/html.py @@ -3,13 +3,11 @@ import html import json import re -import warnings from collections.abc import Mapping from html.parser import HTMLParser from urllib.parse import parse_qsl, quote, unquote, urlencode, urlsplit, urlunsplit from django.core.exceptions import SuspiciousOperation -from django.utils.deprecation import RemovedInDjango60Warning from django.utils.encoding import punycode from django.utils.functional import Promise, cached_property, keep_lazy, keep_lazy_text from django.utils.http import RFC3986_GENDELIMS, RFC3986_SUBDELIMS @@ -131,13 +129,7 @@ def format_html(format_string, *args, **kwargs): of str.format or % interpolation to build up small HTML fragments. """ if not (args or kwargs): - # RemovedInDjango60Warning: when the deprecation ends, replace with: - # raise TypeError("args or kwargs must be provided.") - warnings.warn( - "Calling format_html() without passing args or kwargs is deprecated.", - RemovedInDjango60Warning, - stacklevel=2, - ) + raise TypeError("args or kwargs must be provided.") args_safe = map(conditional_escape, args) kwargs_safe = {k: conditional_escape(v) for (k, v) in kwargs.items()} return mark_safe(format_string.format(*args_safe, **kwargs_safe)) diff --git a/django/utils/itercompat.py b/django/utils/itercompat.py deleted file mode 100644 index e4b34cd5342b..000000000000 --- a/django/utils/itercompat.py +++ /dev/null @@ -1,21 +0,0 @@ -# RemovedInDjango60Warning: Remove this entire module. - -import warnings - -from django.utils.deprecation import RemovedInDjango60Warning - - -def is_iterable(x): - "An implementation independent way of checking for iterables" - warnings.warn( - "django.utils.itercompat.is_iterable() is deprecated. " - "Use isinstance(..., collections.abc.Iterable) instead.", - RemovedInDjango60Warning, - stacklevel=2, - ) - try: - iter(x) - except TypeError: - return False - else: - return True diff --git a/docs/conf.py b/docs/conf.py index 9289e821faa7..24f44b24740f 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -118,7 +118,7 @@ # built documents. # # The short X.Y version. -version = "5.2" +version = "6.0" # The full version, including alpha/beta/rc tags. try: from django import VERSION, get_version @@ -135,7 +135,7 @@ def django_release(): release = django_release() # The "development version" of Django -django_next_version = "5.2" +django_next_version = "6.0" extlinks = { "bpo": ("https://bugs.python.org/issue?@action=redirect&bpo=%s", "bpo-%s"), diff --git a/docs/faq/install.txt b/docs/faq/install.txt index 9928e2c4c016..b483d30f5e24 100644 --- a/docs/faq/install.txt +++ b/docs/faq/install.txt @@ -54,6 +54,7 @@ Django version Python versions 5.0 3.10, 3.11, 3.12 5.1 3.10, 3.11, 3.12, 3.13 (added in 5.1.3) 5.2 3.10, 3.11, 3.12, 3.13 +6.0 3.12, 3.13 ============== =============== For each version of Python, only the latest micro release (A.B.C) is officially diff --git a/docs/internals/contributing/writing-code/unit-tests.txt b/docs/internals/contributing/writing-code/unit-tests.txt index 76f4a9e7542d..446d896abecc 100644 --- a/docs/internals/contributing/writing-code/unit-tests.txt +++ b/docs/internals/contributing/writing-code/unit-tests.txt @@ -298,11 +298,6 @@ screen, one for a mobile screen, one for right-to-left languages on desktop, one for the dark mode on desktop, and one for high contrast mode on desktop when using chrome. -.. versionchanged:: 5.1 - - The ``--screenshots`` option and ``@screenshot_cases`` decorator were - added. - .. _running-unit-tests-dependencies: Running all the tests diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt index 71e4e19cd827..e29c554f95c9 100644 --- a/docs/internals/deprecation.txt +++ b/docs/internals/deprecation.txt @@ -7,6 +7,14 @@ in a backward incompatible way, following their deprecation, as per the :ref:`deprecation policy `. More details about each item can often be found in the release notes of two versions prior. +.. _deprecation-removed-in-7.0: + +7.0 +--- + +See the :ref:`Django 6.0 release notes ` for more +details on these changes. + .. _deprecation-removed-in-6.1: 6.1 diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt index 1b02b7d4037b..311b21ec6e39 100644 --- a/docs/ref/contrib/admin/index.txt +++ b/docs/ref/contrib/admin/index.txt @@ -432,11 +432,6 @@ subclass:: collapsed, using an expandable widget with a toggle for switching their visibility. - .. versionchanged:: 5.1 - - ``fieldsets`` using the ``collapse`` class now use ``
`` - and ```` elements, provided they define a ``name``. - * ``description`` A string of optional extra text to be displayed at the top of each fieldset, under the heading of the fieldset. @@ -639,11 +634,6 @@ subclass:: class PersonAdmin(admin.ModelAdmin): list_display = ["name", "decade_born_in"] - .. versionchanged:: 5.1 - - Support for using ``__`` lookups was added, when targeting related - fields. - A few special cases to note about ``list_display``: * If the field is a ``ForeignKey``, Django will display the @@ -2337,11 +2327,6 @@ The ``InlineModelAdmin`` class adds or customizes: configured in :attr:`~ModelAdmin.fieldsets`, inlines with a ``collapse`` class will be initially collapsed using an expandable widget. - .. versionchanged:: 5.1 - - ``fieldsets`` using the ``collapse`` class now use ``
`` and - ```` elements, provided they define a ``name``. - .. attribute:: InlineModelAdmin.extra This controls the number of extra forms the formset will display in diff --git a/docs/ref/contrib/contenttypes.txt b/docs/ref/contrib/contenttypes.txt index 18eaff43b296..d8f4b2475303 100644 --- a/docs/ref/contrib/contenttypes.txt +++ b/docs/ref/contrib/contenttypes.txt @@ -115,10 +115,6 @@ model it represents, or to retrieve objects from that model: on that model, returning the corresponding object. The ``using`` argument can be used to specify a different database than the default one. - .. versionchanged:: 5.1 - - The ``using`` argument was added. - .. method:: ContentType.model_class() Returns the model class represented by this diff --git a/docs/ref/contrib/gis/functions.txt b/docs/ref/contrib/gis/functions.txt index ff62c17580ef..055c5217f70c 100644 --- a/docs/ref/contrib/gis/functions.txt +++ b/docs/ref/contrib/gis/functions.txt @@ -238,10 +238,6 @@ polygon that can fully contain the geometry. The ``num_seg`` parameter is used only on PostGIS. -.. versionchanged:: 5.1 - - SpatiaLite 5.1+ support was added. - ``Centroid`` ============ @@ -367,10 +363,6 @@ Creates geometry from `Well-known binary (WKB)`_ representation. The optional ``srid`` argument allows to specify the SRID of the resulting geometry. ``srid`` is ignored on Oracle. -.. versionchanged:: 5.1 - - The ``srid`` argument was added. - ``FromWKT`` =========== @@ -384,10 +376,6 @@ Creates geometry from `Well-known text (WKT)`_ representation. The optional ``srid`` argument allows to specify the SRID of the resulting geometry. ``srid`` is ignored on Oracle. -.. versionchanged:: 5.1 - - The ``srid`` argument was added. - ``GeoHash`` =========== diff --git a/docs/ref/contrib/gis/gdal.txt b/docs/ref/contrib/gis/gdal.txt index 726cd83756b3..b7e617cfec77 100644 --- a/docs/ref/contrib/gis/gdal.txt +++ b/docs/ref/contrib/gis/gdal.txt @@ -551,25 +551,12 @@ coordinate transformation: >>> polygon.dimension 2 - .. attribute:: coord_dim - - Returns the coordinate dimension of this geometry. For example, the value - would be 2 for two-dimensional geometries. - - .. deprecated:: 5.1 - - The ``coord_dim`` setter is deprecated. Use :meth:`.set_3d` instead. - .. attribute:: is_3d - .. versionadded:: 5.1 - A boolean indicating if this geometry has Z coordinates. .. method:: set_3d(value) - .. versionadded:: 5.1 - A method that adds or removes the Z coordinate dimension. .. code-block:: pycon @@ -583,14 +570,10 @@ coordinate transformation: .. attribute:: is_measured - .. versionadded:: 5.1 - A boolean indicating if this geometry has M coordinates. .. method:: set_measured(value) - .. versionadded:: 5.1 - A method to add or remove the M coordinate dimension. .. code-block:: pycon @@ -863,11 +846,6 @@ coordinate transformation: Returns a :class:`Point` representing the centroid of this geometry. - .. versionchanged:: 5.1 - - ``centroid`` was promoted from a :class:`.Polygon` only attribute to - being available on all geometry types. - .. attribute:: tuple Returns the coordinates of a point geometry as a tuple, the @@ -916,8 +894,6 @@ coordinate transformation: .. attribute:: m - .. versionadded:: 5.1 - Returns the M coordinate of this point, or ``None`` if the Point does not have an M coordinate: @@ -958,8 +934,6 @@ coordinate transformation: .. attribute:: m - .. versionadded:: 5.1 - Returns a list of M coordinates in this line or ``None`` if the line does not have M coordinates: diff --git a/docs/ref/contrib/gis/geoip2.txt b/docs/ref/contrib/gis/geoip2.txt index 2d0fafa8ef60..70f8120fc5a7 100644 --- a/docs/ref/contrib/gis/geoip2.txt +++ b/docs/ref/contrib/gis/geoip2.txt @@ -99,18 +99,6 @@ Keyword Arguments Description Methods ======= -Instantiating -------------- - -.. classmethod:: GeoIP2.open(path, cache) - -This classmethod instantiates the GeoIP object from the given database path -and given cache setting. - -.. deprecated:: 5.1 - - Use the :class:`GeoIP2()` constructor instead. - Querying -------- @@ -141,14 +129,6 @@ Returns the country name corresponding to the query. Coordinate Retrieval -------------------- -.. method:: GeoIP2.coords(query) - -Returns a coordinate tuple of (longitude, latitude). - -.. deprecated:: 5.1 - - Use :meth:`.GeoIP2.lon_lat` instead. - .. method:: GeoIP2.lon_lat(query) Returns a coordinate tuple of (longitude, latitude). diff --git a/docs/ref/contrib/gis/geoquerysets.txt b/docs/ref/contrib/gis/geoquerysets.txt index 19411b730429..cf50af2c9fd1 100644 --- a/docs/ref/contrib/gis/geoquerysets.txt +++ b/docs/ref/contrib/gis/geoquerysets.txt @@ -894,10 +894,6 @@ aggregate, except it can be several orders of magnitude faster than performing a union because it rolls up geometries into a collection or multi object, not caring about dissolving boundaries. -.. versionchanged:: 5.1 - - MySQL 8.0.24+ support was added. - .. versionchanged:: 5.2 MariaDB 11.7+ support was added. diff --git a/docs/ref/contrib/gis/measure.txt b/docs/ref/contrib/gis/measure.txt index cee421122064..1d88ba129d2d 100644 --- a/docs/ref/contrib/gis/measure.txt +++ b/docs/ref/contrib/gis/measure.txt @@ -125,10 +125,6 @@ Unit Attribute Full name or alias(es) ``ha`` Hectare ================================= ======================================== -.. versionchanged:: 5.1 - - Support for the ``ha`` unit was added. - Measurement API =============== diff --git a/docs/ref/contrib/postgres/indexes.txt b/docs/ref/contrib/postgres/indexes.txt index 107d9c278d43..f001fd0063f2 100644 --- a/docs/ref/contrib/postgres/indexes.txt +++ b/docs/ref/contrib/postgres/indexes.txt @@ -57,10 +57,6 @@ available from the ``django.contrib.postgres.indexes`` module. whether deduplication is enabled. PostgreSQL enables deduplication by default. - .. versionchanged:: 5.1 - - The ``deduplicate_items`` parameter was added. - .. _fillfactor: https://www.postgresql.org/docs/current/sql-createindex.html#SQL-CREATEINDEX-STORAGE-PARAMETERS .. _deduplicate_items: https://www.postgresql.org/docs/current/btree-implementation.html#BTREE-DEDUPLICATION diff --git a/docs/ref/databases.txt b/docs/ref/databases.txt index d19c78b9ec63..217be1972826 100644 --- a/docs/ref/databases.txt +++ b/docs/ref/databases.txt @@ -250,8 +250,6 @@ database configuration in :setting:`DATABASES`:: Connection pool --------------- -.. versionadded:: 5.1 - To use a connection pool with `psycopg`_, you can either set ``"pool"`` in the :setting:`OPTIONS` part of your database configuration in :setting:`DATABASES` to be a dict to be passed to :class:`~psycopg:psycopg_pool.ConnectionPool`, or @@ -898,8 +896,6 @@ If you're getting this error, you can solve it by: Transactions behavior ~~~~~~~~~~~~~~~~~~~~~ -.. versionadded:: 5.1 - SQLite supports three transaction modes: ``DEFERRED``, ``IMMEDIATE``, and ``EXCLUSIVE``. @@ -969,8 +965,6 @@ To enable the JSON1 extension you can follow the instruction on Setting pragma options ---------------------- -.. versionadded:: 5.1 - `Pragma options`_ can be set upon connection by using the ``init_command`` in the :setting:`OPTIONS` part of your database configuration in :setting:`DATABASES`. The example below shows how to enable extra durability of @@ -996,10 +990,6 @@ Oracle notes Django supports `Oracle Database Server`_ versions 19c and higher. Version 2.3.0 or higher of the `oracledb`_ Python driver is required. -.. deprecated:: 5.0 - - Support for ``cx_Oracle`` is deprecated. - .. _`Oracle Database Server`: https://www.oracle.com/ .. _`oracledb`: https://oracle.github.io/python-oracledb/ diff --git a/docs/ref/files/storage.txt b/docs/ref/files/storage.txt index 52c8f90427d5..228025fe3a88 100644 --- a/docs/ref/files/storage.txt +++ b/docs/ref/files/storage.txt @@ -80,8 +80,6 @@ The ``FileSystemStorage`` class .. attribute:: allow_overwrite - .. versionadded:: 5.1 - Flag to control allowing saving a new file over an existing one. Defaults to ``False``. diff --git a/docs/ref/forms/fields.txt b/docs/ref/forms/fields.txt index c0ab4f2434c5..db912bff51ee 100644 --- a/docs/ref/forms/fields.txt +++ b/docs/ref/forms/fields.txt @@ -320,10 +320,6 @@ inside ``aria-describedby``: >>> print(f["username"]) -.. versionchanged:: 5.1 - - ``aria-describedby`` support was added for ``
``. - ``error_messages`` ------------------ @@ -789,10 +785,6 @@ For each field, we describe the default widget used if you don't specify Defaults to 39, and behaves the same way as it does for :class:`CharField`. - .. versionchanged:: 4.2.18 - - The default value for ``max_length`` was set to 39 characters. - ``ImageField`` -------------- @@ -1144,13 +1136,6 @@ For each field, we describe the default widget used if you don't specify provided value is ``"example.com"``, the normalized value will be ``"https://example.com"``. - .. deprecated:: 5.0 - - The default value for ``assume_scheme`` will change from ``"http"`` to - ``"https"`` in Django 6.0. Set :setting:`FORMS_URLFIELD_ASSUME_HTTPS` - transitional setting to ``True`` to opt into using ``"https"`` during - the Django 5.x release cycle. - ``UUIDField`` ------------- diff --git a/docs/ref/forms/renderers.txt b/docs/ref/forms/renderers.txt index e527a70c5771..f7d78cfa7210 100644 --- a/docs/ref/forms/renderers.txt +++ b/docs/ref/forms/renderers.txt @@ -97,12 +97,6 @@ If you want to render templates with customizations from your :setting:`TEMPLATES` setting, such as context processors for example, use the :class:`TemplatesSetting` renderer. -.. class:: DjangoDivFormRenderer - -.. deprecated:: 5.0 - -The alias of :class:`DjangoTemplates`. - ``Jinja2`` ---------- @@ -119,12 +113,6 @@ templates for widgets that don't have any, you can't use this renderer. For example, :mod:`django.contrib.admin` doesn't include Jinja2 templates for its widgets due to their usage of Django template tags. -.. class:: Jinja2DivFormRenderer - -.. deprecated:: 5.0 - -The alias of :class:`Jinja2`. - ``TemplatesSetting`` -------------------- diff --git a/docs/ref/logging.txt b/docs/ref/logging.txt index 24ab5d97f379..a045d4d7d7ef 100644 --- a/docs/ref/logging.txt +++ b/docs/ref/logging.txt @@ -214,8 +214,6 @@ messages during filesystem inspection and event subscription processes. ``django.contrib.auth`` ~~~~~~~~~~~~~~~~~~~~~~~ -.. versionadded:: 4.2.16 - Log messages related to :doc:`contrib/auth`, particularly ``ERROR`` messages are generated when a :class:`~django.contrib.auth.forms.PasswordResetForm` is successfully submitted but the password reset email cannot be delivered due to diff --git a/docs/ref/middleware.txt b/docs/ref/middleware.txt index b5534ce8f64f..e09df637f109 100644 --- a/docs/ref/middleware.txt +++ b/docs/ref/middleware.txt @@ -523,8 +523,6 @@ every incoming ``HttpRequest`` object. See :ref:`Authentication in web requests ``None``), or :attr:`redirect_field_name`. If ``None`` is returned, a query parameter won't be added. -.. versionadded:: 5.1 - Redirects all unauthenticated requests to a login page, except for views excluded with :func:`~.django.contrib.auth.decorators.login_not_required`. The login page defaults to :setting:`settings.LOGIN_URL `, but can be @@ -682,8 +680,6 @@ Here are some hints about the ordering of various Django middleware classes: #. :class:`~django.contrib.auth.middleware.LoginRequiredMiddleware` - .. versionadded:: 5.1 - After ``AuthenticationMiddleware``: uses user object. #. :class:`~django.contrib.messages.middleware.MessageMiddleware` diff --git a/docs/ref/migration-operations.txt b/docs/ref/migration-operations.txt index b969b3dbfdb7..f4d4ae96ddf5 100644 --- a/docs/ref/migration-operations.txt +++ b/docs/ref/migration-operations.txt @@ -498,8 +498,6 @@ For an example using ``SeparateDatabaseAndState``, see Operation category ================== -.. versionadded:: 5.1 - .. currentmodule:: django.db.migrations.operations.base .. class:: OperationCategory diff --git a/docs/ref/models/constraints.txt b/docs/ref/models/constraints.txt index c1f140c265fa..99e5332ca30a 100644 --- a/docs/ref/models/constraints.txt +++ b/docs/ref/models/constraints.txt @@ -43,10 +43,6 @@ option. ``constraint_sql()``, ``create_sql()``, ``remove_sql()`` and ``validate()`` methods. - .. deprecated:: 5.0 - - Support for passing positional arguments is deprecated. - All constraints have the following parameters in common: ``name`` @@ -127,10 +123,6 @@ ensures the age field is never less than 18. CheckConstraint(condition=Q(age__gte=18) | Q(age__isnull=True), name="age_gte_18") -.. deprecated:: 5.1 - - The ``check`` attribute is deprecated in favor of ``condition``. - ``UniqueConstraint`` ==================== diff --git a/docs/ref/models/expressions.txt b/docs/ref/models/expressions.txt index 5d5504dbe7cd..6a6356b3bbcd 100644 --- a/docs/ref/models/expressions.txt +++ b/docs/ref/models/expressions.txt @@ -188,8 +188,6 @@ the field value of each one, and saving each one back to the database:: Slicing ``F()`` expressions ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. versionadded:: 5.1 - For string-based fields, text-based fields, and :class:`~django.contrib.postgres.fields.ArrayField`, you can use Python's array-slicing syntax. The indices are 0-based and the ``step`` argument to @@ -920,20 +918,12 @@ ordinary sequence of rows. the standard start and end points, such as ``CURRENT ROW`` and ``UNBOUNDED FOLLOWING``. - .. versionchanged:: 5.1 - - The ``exclusion`` argument was added. - .. class:: RowRange(start=None, end=None, exclusion=None) .. attribute:: frame_type This attribute is set to ``'ROWS'``. - .. versionchanged:: 5.1 - - The ``exclusion`` argument was added. - Both classes return SQL with the template: .. code-block:: sql @@ -942,8 +932,6 @@ Both classes return SQL with the template: .. class:: WindowFrameExclusion - .. versionadded:: 5.1 - .. attribute:: CURRENT_ROW .. attribute:: GROUP @@ -1024,11 +1012,6 @@ released between twelve months before and twelve months after each movie: ... ), ... ) -.. versionchanged:: 5.1 - - Support for positive integer ``start`` and negative integer ``end`` was - added for ``RowRange``. - .. currentmodule:: django.db.models Technical Information @@ -1059,8 +1042,6 @@ calling the appropriate methods on the wrapped expression. .. attribute:: constraint_validation_compatible - .. versionadded:: 5.1 - Tells Django that this expression can be used during a constraint validation. Expressions with ``constraint_validation_compatible`` set to ``False`` must have only one source expression. Defaults to diff --git a/docs/ref/models/instances.txt b/docs/ref/models/instances.txt index 7482b98a663f..be4ad4a4f4cf 100644 --- a/docs/ref/models/instances.txt +++ b/docs/ref/models/instances.txt @@ -214,10 +214,6 @@ values:: obj.refresh_from_db(from_queryset=MyModel.objects.select_for_update()) -.. versionchanged:: 5.1 - - The ``from_queryset`` argument was added. - .. method:: Model.get_deferred_fields() A helper method that returns a set containing the attribute names of all those @@ -434,10 +430,6 @@ method. See :ref:`overriding-model-methods` for more details. The model save process also has some subtleties; see the sections below. -.. deprecated:: 5.1 - - Support for positional arguments is deprecated. - Auto-incrementing primary keys ------------------------------ diff --git a/docs/ref/models/querysets.txt b/docs/ref/models/querysets.txt index ec27936cdb59..8bf83838c080 100644 --- a/docs/ref/models/querysets.txt +++ b/docs/ref/models/querysets.txt @@ -3106,10 +3106,6 @@ adverse effects on your database. For example, the ``ANALYZE`` flag supported by MariaDB, MySQL 8.0.18+, and PostgreSQL could result in changes to data if there are triggers or if a function is called, even for a ``SELECT`` query. -.. versionchanged:: 5.1 - - Support for the ``generic_plan`` option on PostgreSQL 16+ was added. - .. versionchanged:: 5.2 Support for the ``memory`` and ``serialize`` options on PostgreSQL 17+ was diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt index e3a0f6d32ae8..9bd5aedbed24 100644 --- a/docs/ref/settings.txt +++ b/docs/ref/settings.txt @@ -1684,19 +1684,6 @@ renderers are: * ``'``:class:`django.forms.renderers.Jinja2`\ ``'`` * ``'``:class:`django.forms.renderers.TemplatesSetting`\ ``'`` -.. setting:: FORMS_URLFIELD_ASSUME_HTTPS - -``FORMS_URLFIELD_ASSUME_HTTPS`` -------------------------------- - -.. deprecated:: 5.0 - -Default: ``False`` - -Set this transitional setting to ``True`` to opt into using ``"https"`` as the -new default value of :attr:`URLField.assume_scheme -` during the Django 5.x release cycle. - .. setting:: FORMAT_MODULE_PATH ``FORMAT_MODULE_PATH`` @@ -3664,7 +3651,6 @@ File uploads Forms ----- * :setting:`FORM_RENDERER` -* :setting:`FORMS_URLFIELD_ASSUME_HTTPS` Globalization (``i18n``/``l10n``) --------------------------------- diff --git a/docs/ref/templates/builtins.txt b/docs/ref/templates/builtins.txt index 867372786164..f35935c160d5 100644 --- a/docs/ref/templates/builtins.txt +++ b/docs/ref/templates/builtins.txt @@ -957,8 +957,6 @@ output (as a string) inside a variable. This is useful if you want to use ``querystring`` ---------------- -.. versionadded:: 5.1 - Outputs a URL-encoded formatted query string based on the provided parameters. This tag requires a :class:`~django.http.QueryDict` instance, which defaults to diff --git a/docs/ref/urls.txt b/docs/ref/urls.txt index 95eb03f35ae9..ac55bde5757c 100644 --- a/docs/ref/urls.txt +++ b/docs/ref/urls.txt @@ -150,10 +150,6 @@ The ``converter`` argument is a converter class, and ``type_name`` is the converter name to use in path patterns. See :ref:`registering-custom-path-converters` for an example. -.. deprecated:: 5.1 - - Overriding existing converters is deprecated. - ================================================== ``django.conf.urls`` functions for use in URLconfs ================================================== diff --git a/docs/ref/utils.txt b/docs/ref/utils.txt index 438a38cea056..3f72672622e5 100644 --- a/docs/ref/utils.txt +++ b/docs/ref/utils.txt @@ -687,11 +687,6 @@ escaping HTML. through :func:`conditional_escape` which (ultimately) calls :func:`~django.utils.encoding.force_str` on the values. - .. deprecated:: 5.0 - - Support for calling ``format_html()`` without passing args or kwargs is - deprecated. - .. function:: format_html_join(sep, format_string, args_generator) A wrapper of :func:`format_html`, for the common case of a group of @@ -1179,11 +1174,6 @@ For a complete discussion on the usage of the following see the Raises :exc:`LookupError` if nothing is found. - .. versionchanged:: 4.2.15 - - In older versions, ``lang_code`` values over 500 characters were - processed without raising a :exc:`LookupError`. - .. function:: to_locale(language) Turns a language name (en-us) into a locale name (en_US). diff --git a/docs/ref/validators.txt b/docs/ref/validators.txt index 846a3c71574b..349336342026 100644 --- a/docs/ref/validators.txt +++ b/docs/ref/validators.txt @@ -162,8 +162,6 @@ to, or in lieu of custom ``field.clean()`` methods. ``DomainNameValidator`` ----------------------- -.. versionadded:: 5.1 - .. class:: DomainNameValidator(accept_idna=True, message=None, code=None) A :class:`RegexValidator` subclass that ensures a value looks like a domain @@ -223,8 +221,6 @@ to, or in lieu of custom ``field.clean()`` methods. ``validate_domain_name`` ------------------------ -.. versionadded:: 5.1 - .. data:: validate_domain_name A :class:`DomainNameValidator` instance without any customizations. diff --git a/docs/releases/5.0.txt b/docs/releases/5.0.txt index 303ee8807851..1cc5695d5a14 100644 --- a/docs/releases/5.0.txt +++ b/docs/releases/5.0.txt @@ -622,9 +622,9 @@ Miscellaneous * The ``ForeignObject.get_reverse_joining_columns()`` method is deprecated. * The default scheme for ``forms.URLField`` will change from ``"http"`` to - ``"https"`` in Django 6.0. Set :setting:`FORMS_URLFIELD_ASSUME_HTTPS` - transitional setting to ``True`` to opt into assuming ``"https"`` during the - Django 5.x release cycle. + ``"https"`` in Django 6.0. Set ``FORMS_URLFIELD_ASSUME_HTTPS`` transitional + setting to ``True`` to opt into assuming ``"https"`` during the Django 5.x + release cycle. * ``FORMS_URLFIELD_ASSUME_HTTPS`` transitional setting is deprecated. diff --git a/docs/releases/6.0.txt b/docs/releases/6.0.txt new file mode 100644 index 000000000000..ccb01d2d1a3f --- /dev/null +++ b/docs/releases/6.0.txt @@ -0,0 +1,324 @@ +============================================ +Django 6.0 release notes - UNDER DEVELOPMENT +============================================ + +*Expected December 2025* + +Welcome to Django 6.0! + +These release notes cover the :ref:`new features `, as well as +some :ref:`backwards incompatible changes ` you'll +want to be aware of when upgrading from Django 5.2 or earlier. We've +:ref:`begun the deprecation process for some features +`. + +See the :doc:`/howto/upgrade-version` guide if you're updating an existing +project. + +Python compatibility +==================== + +Django 6.0 supports Python 3.12 and 3.13. We **highly recommend** and only +officially support the latest release of each series. + +Third-party library support for older version of Django +======================================================= + +Following the release of Django 6.0, we suggest that third-party app authors +drop support for all versions of Django prior to 5.2. At that time, you should +be able to run your package's tests using ``python -Wd`` so that deprecation +warnings appear. After making the deprecation warning fixes, your app should be +compatible with Django 6.0. + +.. _whats-new-6.0: + +What's new in Django 6.0 +======================== + +Minor features +-------------- + +:mod:`django.contrib.admin` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* ... + +:mod:`django.contrib.admindocs` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* ... + +:mod:`django.contrib.auth` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* The default iteration count for the PBKDF2 password hasher is increased from + 1,000,000 to 1,200,000. + +:mod:`django.contrib.contenttypes` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* ... + +:mod:`django.contrib.gis` +~~~~~~~~~~~~~~~~~~~~~~~~~ + +* ... + +:mod:`django.contrib.messages` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* ... + +:mod:`django.contrib.postgres` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* ... + +:mod:`django.contrib.redirects` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* ... + +:mod:`django.contrib.sessions` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* ... + +:mod:`django.contrib.sitemaps` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* ... + +:mod:`django.contrib.sites` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* ... + +:mod:`django.contrib.staticfiles` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* ... + +:mod:`django.contrib.syndication` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* ... + +Cache +~~~~~ + +* ... + +CSRF +~~~~ + +* ... + +Decorators +~~~~~~~~~~ + +* ... + +Email +~~~~~ + +* ... + +Error Reporting +~~~~~~~~~~~~~~~ + +* ... + +File Storage +~~~~~~~~~~~~ + +* ... + +File Uploads +~~~~~~~~~~~~ + +* ... + +Forms +~~~~~ + +* ... + +Generic Views +~~~~~~~~~~~~~ + +* ... + +Internationalization +~~~~~~~~~~~~~~~~~~~~ + +* ... + +Logging +~~~~~~~ + +* ... + +Management Commands +~~~~~~~~~~~~~~~~~~~ + +* ... + +Migrations +~~~~~~~~~~ + +* ... + +Models +~~~~~~ + +* ... + +Requests and Responses +~~~~~~~~~~~~~~~~~~~~~~ + +* ... + +Security +~~~~~~~~ + +* ... + +Serialization +~~~~~~~~~~~~~ + +* ... + +Signals +~~~~~~~ + +* ... + +Templates +~~~~~~~~~ + +* ... + +Tests +~~~~~ + +* ... + +URLs +~~~~ + +* ... + +Utilities +~~~~~~~~~ + +* ... + +Validators +~~~~~~~~~~ + +* ... + +.. _backwards-incompatible-6.0: + +Backwards incompatible changes in 6.0 +===================================== + +Database backend API +-------------------- + +This section describes changes that may be needed in third-party database +backends. + +* ... + +Miscellaneous +------------- + +* ... + +.. _deprecated-features-6.0: + +Features deprecated in 6.0 +========================== + +Miscellaneous +------------- + +* ... + +Features removed in 6.0 +======================= + +These features have reached the end of their deprecation cycle and are removed +in Django 6.0. + +See :ref:`deprecated-features-5.0` for details on these changes, including how +to remove usage of these features. + +* Support for passing positional arguments to ``BaseConstraint`` is removed. + +* The ``DjangoDivFormRenderer`` and ``Jinja2DivFormRenderer`` transitional form + renderers are removed. + +* ``BaseDatabaseOperations.field_cast_sql()`` is removed. + +* ``request`` is required in the signature of ``ModelAdmin.lookup_allowed()`` + subclasses. + +* Support for calling ``format_html()`` without passing args or kwargs is + removed. + +* The default scheme for ``forms.URLField`` changed from ``"http"`` to + ``"https"``. + +* The ``FORMS_URLFIELD_ASSUME_HTTPS`` transitional setting is removed. + +* The ``django.db.models.sql.datastructures.Join`` no longer fallback to + ``get_joining_columns()``. + +* The ``get_joining_columns()`` method of ``ForeignObject`` and + ``ForeignObjectRel`` is removed. + +* The ``ForeignObject.get_reverse_joining_columns()`` method is be removed. + +* Support for ``cx_Oracle`` is removed. + +* The ``ChoicesMeta`` alias to ``django.db.models.enums.ChoicesType`` is + removed. + +* The ``Prefetch.get_current_queryset()`` method is removed. + +* The ``get_prefetch_queryset()`` method of related managers and descriptors is + removed. + +* ``get_prefetcher()`` and ``prefetch_related_objects()`` no longer fallback to + ``get_prefetch_queryset()``. + +See :ref:`deprecated-features-5.1` for details on these changes, including how +to remove usage of these features. + +* ``django.urls.register_converter()`` no longer allows overriding existing + converters. + +* The ``ModelAdmin.log_deletion()`` and ``LogEntryManager.log_action()`` + methods are removed. + +* The undocumented ``django.utils.itercompat.is_iterable()`` function and the + ``django.utils.itercompat`` module is removed. + +* The ``django.contrib.gis.geoip2.GeoIP2.coords()`` method is removed. + +* The ``django.contrib.gis.geoip2.GeoIP2.open()`` method is removed. + +* Support for passing positional arguments to ``Model.save()`` and + ``Model.asave()`` is removed. + +* The setter for ``django.contrib.gis.gdal.OGRGeometry.coord_dim`` is removed. + +* The ``check`` keyword argument of ``CheckConstraint`` is removed. + +* The ``get_cache_name()`` method of ``FieldCacheMixin`` is removed. + +* The ``OS_OPEN_FLAGS`` attribute of + :class:`~django.core.files.storage.FileSystemStorage` is removed. diff --git a/docs/releases/index.txt b/docs/releases/index.txt index 11059e5da20c..3cafeefb9d56 100644 --- a/docs/releases/index.txt +++ b/docs/releases/index.txt @@ -20,6 +20,13 @@ versions of the documentation contain the release notes for any later releases. .. _development_release_notes: +6.0 release +----------- +.. toctree:: + :maxdepth: 1 + + 6.0 + 5.2 release ----------- .. toctree:: diff --git a/docs/topics/auth/default.txt b/docs/topics/auth/default.txt index a22cebbf15a6..06d7c2fc26b2 100644 --- a/docs/topics/auth/default.txt +++ b/docs/topics/auth/default.txt @@ -601,10 +601,6 @@ The ``login_required`` decorator :func:`django.contrib.admin.views.decorators.staff_member_required` decorator a useful alternative to ``login_required()``. -.. versionchanged:: 5.1 - - Support for wrapping asynchronous view functions was added. - .. currentmodule:: django.contrib.auth.mixins The ``LoginRequiredMixin`` mixin @@ -647,8 +643,6 @@ inheritance list. The ``login_not_required`` decorator ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. versionadded:: 5.1 - When :class:`~django.contrib.auth.middleware.LoginRequiredMiddleware` is installed, all views require authentication by default. Some views, such as the login view, may need to disable this behavior. @@ -719,11 +713,6 @@ email in the desired domain and if not, redirects to the login page:: @user_passes_test(email_check, login_url="/login/") def my_view(request): ... - .. versionchanged:: 5.1 - - Support for wrapping asynchronous view functions and using asynchronous - test callables was added. - .. currentmodule:: django.contrib.auth.mixins .. class:: UserPassesTestMixin @@ -828,10 +817,6 @@ The ``permission_required`` decorator ``redirect_authenticated_user=True`` and the logged-in user doesn't have all of the required permissions. -.. versionchanged:: 5.1 - - Support for wrapping asynchronous view functions was added. - .. currentmodule:: django.contrib.auth.mixins The ``PermissionRequiredMixin`` mixin @@ -1640,15 +1625,8 @@ provides several built-in forms located in :mod:`django.contrib.auth.forms`: Takes the ``user`` as the first positional argument. - .. versionchanged:: 5.1 - - Option to disable (or reenable) password-based authentication was - added. - .. class:: AdminUserCreationForm - .. versionadded:: 5.1.1 - A form used in the admin interface to create a new user. Inherits from :class:`UserCreationForm`. diff --git a/docs/topics/checks.txt b/docs/topics/checks.txt index 94ba66f0db9a..b0e8c2987f6d 100644 --- a/docs/topics/checks.txt +++ b/docs/topics/checks.txt @@ -195,10 +195,6 @@ the only difference is that the check is a classmethod, not an instance method:: # ... your own checks ... return errors -.. versionchanged:: 5.1 - - In older versions, template engines didn't implement a ``check()`` method. - Writing tests ------------- diff --git a/docs/topics/http/sessions.txt b/docs/topics/http/sessions.txt index e670292ca86c..03559da3edcd 100644 --- a/docs/topics/http/sessions.txt +++ b/docs/topics/http/sessions.txt @@ -81,10 +81,6 @@ writing to the cache fails, the exception is handled and logged via the :ref:`sessions logger `, to avoid failing an otherwise successful write operation. -.. versionchanged:: 5.1 - - Handling and logging of exceptions when writing to the cache was added. - Session reads use the cache, or the database if the data has been evicted from the cache. To use this backend, set :setting:`SESSION_ENGINE` to ``"django.contrib.sessions.backends.cached_db"``, and follow the configuration @@ -202,14 +198,8 @@ You can edit it multiple times. Example: ``fav_color = request.session.get('fav_color', 'red')`` - .. versionchanged:: 5.1 - - ``aget()`` function was added. - .. method:: aset(key, value) - .. versionadded:: 5.1 - Example: ``await request.session.aset('fav_color', 'red')`` .. method:: update(dict) @@ -219,10 +209,6 @@ You can edit it multiple times. Example: ``request.session.update({'fav_color': 'red'})`` - .. versionchanged:: 5.1 - - ``aupdate()`` function was added. - .. method:: pop(key, default=__not_given) .. method:: apop(key, default=__not_given) @@ -230,55 +216,31 @@ You can edit it multiple times. Example: ``fav_color = request.session.pop('fav_color', 'blue')`` - .. versionchanged:: 5.1 - - ``apop()`` function was added. - .. method:: keys() .. method:: akeys() *Asynchronous version*: ``akeys()`` - .. versionchanged:: 5.1 - - ``akeys()`` function was added. - .. method:: values() .. method:: avalues() *Asynchronous version*: ``avalues()`` - .. versionchanged:: 5.1 - - ``avalues()`` function was added. - .. method:: has_key(key) .. method:: ahas_key(key) *Asynchronous version*: ``ahas_key()`` - .. versionchanged:: 5.1 - - ``ahas_key()`` function was added. - .. method:: items() .. method:: aitems() *Asynchronous version*: ``aitems()`` - .. versionchanged:: 5.1 - - ``aitems()`` function was added. - .. method:: setdefault() .. method:: asetdefault() *Asynchronous version*: ``asetdefault()`` - .. versionchanged:: 5.1 - - ``asetdefault()`` function was added. - .. method:: clear() It also has these methods: @@ -293,10 +255,6 @@ You can edit it multiple times. can't be accessed again from the user's browser (for example, the :func:`django.contrib.auth.logout()` function calls it). - .. versionchanged:: 5.1 - - ``aflush()`` function was added. - .. method:: set_test_cookie() .. method:: aset_test_cookie() @@ -307,10 +265,6 @@ You can edit it multiple times. until the user's next page request. See `Setting test cookies`_ below for more information. - .. versionchanged:: 5.1 - - ``aset_test_cookie()`` function was added. - .. method:: test_cookie_worked() .. method:: atest_cookie_worked() @@ -322,10 +276,6 @@ You can edit it multiple times. previous, separate page request. See `Setting test cookies`_ below for more information. - .. versionchanged:: 5.1 - - ``atest_cookie_worked()`` function was added. - .. method:: delete_test_cookie() .. method:: adelete_test_cookie() @@ -333,10 +283,6 @@ You can edit it multiple times. Deletes the test cookie. Use this to clean up after yourself. - .. versionchanged:: 5.1 - - ``adelete_test_cookie()`` function was added. - .. method:: get_session_cookie_age() Returns the value of the setting :setting:`SESSION_COOKIE_AGE`. This can @@ -368,10 +314,6 @@ You can edit it multiple times. purposes. Session expiration is computed from the last time the session was *modified*. - .. versionchanged:: 5.1 - - ``aset_expiry()`` function was added. - .. method:: get_expiry_age() .. method:: aget_expiry_age() @@ -404,10 +346,6 @@ You can edit it multiple times. expires_at = modification + timedelta(seconds=settings.SESSION_COOKIE_AGE) - .. versionchanged:: 5.1 - - ``aget_expiry_age()`` function was added. - .. method:: get_expiry_date() .. method:: aget_expiry_date() @@ -420,10 +358,6 @@ You can edit it multiple times. This function accepts the same keyword arguments as :meth:`get_expiry_age`, and similar notes on usage apply. - .. versionchanged:: 5.1 - - ``aget_expiry_date()`` function was added. - .. method:: get_expire_at_browser_close() .. method:: aget_expire_at_browser_close() @@ -432,10 +366,6 @@ You can edit it multiple times. Returns either ``True`` or ``False``, depending on whether the user's session cookie will expire when the user's web browser is closed. - .. versionchanged:: 5.1 - - ``aget_expire_at_browser_close()`` function was added. - .. method:: clear_expired() .. method:: aclear_expired() @@ -444,10 +374,6 @@ You can edit it multiple times. Removes expired sessions from the session store. This class method is called by :djadmin:`clearsessions`. - .. versionchanged:: 5.1 - - ``aclear_expired()`` function was added. - .. method:: cycle_key() .. method:: acycle_key() @@ -457,10 +383,6 @@ You can edit it multiple times. :func:`django.contrib.auth.login()` calls this method to mitigate against session fixation. - .. versionchanged:: 5.1 - - ``acycle_key()`` function was added. - .. _session_serialization: Session serialization @@ -616,10 +538,6 @@ Here's a typical usage example:: request.session.set_test_cookie() return render(request, "foo/login_form.html") -.. versionchanged:: 5.1 - - Support for setting test cookies in asynchronous view functions was added. - Using sessions out of views =========================== @@ -868,11 +786,6 @@ You can extend the session engines, but doing so with database-backed session engines generally requires some extra effort (see the next section for details). -.. versionchanged:: 5.1 - - ``aexists()``, ``acreate()``, ``asave()``, ``adelete()``, ``aload()``, and - ``aclear_expired()`` methods were added. - .. _extending-database-backed-session-engines: Extending database-backed session engines diff --git a/docs/topics/http/urls.txt b/docs/topics/http/urls.txt index 8e57732725a8..d8de9635ec2a 100644 --- a/docs/topics/http/urls.txt +++ b/docs/topics/http/urls.txt @@ -183,11 +183,6 @@ Register custom converter classes in your URLconf using ..., ] -.. deprecated:: 5.1 - - Overriding existing converters with ``django.urls.register_converter()`` is - deprecated. - Using regular expressions ========================= diff --git a/docs/topics/testing/advanced.txt b/docs/topics/testing/advanced.txt index 6b03f0f82b46..1b0c172ef9f2 100644 --- a/docs/topics/testing/advanced.txt +++ b/docs/topics/testing/advanced.txt @@ -32,10 +32,6 @@ restricted subset of the test client API: attributes must be supplied by the test itself if required for the view to function properly. -.. versionchanged:: 5.1 - - The ``query_params`` parameter was added. - Example ------- @@ -89,10 +85,6 @@ difference being that it returns ``ASGIRequest`` instances rather than Arbitrary keyword arguments in ``defaults`` are added directly into the ASGI scope. -.. versionchanged:: 5.1 - - The ``query_params`` parameter was added. - Testing class-based views ========================= diff --git a/docs/topics/testing/tools.txt b/docs/topics/testing/tools.txt index dba2a9cce8a1..a03ad7da786d 100644 --- a/docs/topics/testing/tools.txt +++ b/docs/topics/testing/tools.txt @@ -158,10 +158,6 @@ Use the ``django.test.Client`` class to make requests. The ``json_encoder`` argument allows setting a custom JSON encoder for the JSON serialization that's described in :meth:`post`. - .. versionchanged:: 5.1 - - The ``query_params`` argument was added. - Once you have a ``Client`` instance, you can call any of the following methods: @@ -241,10 +237,6 @@ Use the ``django.test.Client`` class to make requests. If you set ``secure`` to ``True`` the client will emulate an HTTPS request. - .. versionchanged:: 5.1 - - The ``query_params`` argument was added. - .. method:: Client.post(path, data=None, content_type=MULTIPART_CONTENT, follow=False, secure=False, *, headers=None, query_params=None, **extra) Makes a POST request on the provided ``path`` and returns a @@ -360,10 +352,6 @@ Use the ``django.test.Client`` class to make requests. If you set ``secure`` to ``True`` the client will emulate an HTTPS request. - .. versionchanged:: 5.1 - - The ``query_params`` argument was added. - .. method:: Client.head(path, data=None, follow=False, secure=False, *, headers=None, query_params=None, **extra) Makes a HEAD request on the provided ``path`` and returns a @@ -371,10 +359,6 @@ Use the ``django.test.Client`` class to make requests. including the ``follow``, ``secure``, ``headers``, ``query_params``, and ``extra`` parameters, except it does not return a message body. - .. versionchanged:: 5.1 - - The ``query_params`` argument was added. - .. method:: Client.options(path, data='', content_type='application/octet-stream', follow=False, secure=False, *, headers=None, query_params=None, **extra) Makes an OPTIONS request on the provided ``path`` and returns a @@ -386,10 +370,6 @@ Use the ``django.test.Client`` class to make requests. The ``follow``, ``secure``, ``headers``, ``query_params``, and ``extra`` parameters act the same as for :meth:`Client.get`. - .. versionchanged:: 5.1 - - The ``query_params`` argument was added. - .. method:: Client.put(path, data='', content_type='application/octet-stream', follow=False, secure=False, *, headers=None, query_params=None, **extra) Makes a PUT request on the provided ``path`` and returns a @@ -401,10 +381,6 @@ Use the ``django.test.Client`` class to make requests. The ``follow``, ``secure``, ``headers``, ``query_params``, and ``extra`` parameters act the same as for :meth:`Client.get`. - .. versionchanged:: 5.1 - - The ``query_params`` argument was added. - .. method:: Client.patch(path, data='', content_type='application/octet-stream', follow=False, secure=False, *, headers=None, query_params=None, **extra) Makes a PATCH request on the provided ``path`` and returns a @@ -413,10 +389,6 @@ Use the ``django.test.Client`` class to make requests. The ``follow``, ``secure``, ``headers``, ``query_params``, and ``extra`` parameters act the same as for :meth:`Client.get`. - .. versionchanged:: 5.1 - - The ``query_params`` argument was added. - .. method:: Client.delete(path, data='', content_type='application/octet-stream', follow=False, secure=False, *, headers=None, query_params=None, **extra) Makes a DELETE request on the provided ``path`` and returns a @@ -428,10 +400,6 @@ Use the ``django.test.Client`` class to make requests. The ``follow``, ``secure``, ``headers``, ``query_params``, and ``extra`` parameters act the same as for :meth:`Client.get`. - .. versionchanged:: 5.1 - - The ``query_params`` argument was added. - .. method:: Client.trace(path, follow=False, secure=False, *, headers=None, query_params=None, **extra) Makes a TRACE request on the provided ``path`` and returns a @@ -444,10 +412,6 @@ Use the ``django.test.Client`` class to make requests. The ``follow``, ``secure``, ``headers``, ``query_params``, and ``extra`` parameters act the same as for :meth:`Client.get`. - .. versionchanged:: 5.1 - - The ``query_params`` argument was added. - .. method:: Client.login(**credentials) .. method:: Client.alogin(**credentials) @@ -1548,11 +1512,6 @@ LOCALE_PATHS, LANGUAGE_CODE Default translation and loaded translations STATIC_ROOT, STATIC_URL, STORAGES Storages configuration ================================= ======================== -.. versionchanged:: 5.1 - - Resetting the default renderer when the ``FORM_RENDERER`` setting is - changed was added. - Isolating apps -------------- @@ -1740,10 +1699,6 @@ your test suite. attribute ordering is not significant. See :meth:`~SimpleTestCase.assertHTMLEqual` for more details. - .. versionchanged:: 5.1 - - In older versions, error messages didn't contain the response content. - .. method:: SimpleTestCase.assertNotContains(response, text, status_code=200, msg_prefix='', html=False) Asserts that a :class:`response ` produced the @@ -1756,10 +1711,6 @@ your test suite. attribute ordering is not significant. See :meth:`~SimpleTestCase.assertHTMLEqual` for more details. - .. versionchanged:: 5.1 - - In older versions, error messages didn't contain the response content. - .. method:: SimpleTestCase.assertTemplateUsed(response, template_name, msg_prefix='', count=None) Asserts that the template with the given name was used in rendering the @@ -1896,14 +1847,8 @@ your test suite. Whitespace in most cases is ignored, and attribute ordering is not significant. See :meth:`~SimpleTestCase.assertHTMLEqual` for more details. - .. versionchanged:: 5.1 - - In older versions, error messages didn't contain the ``haystack``. - .. method:: SimpleTestCase.assertNotInHTML(needle, haystack, msg_prefix="") - .. versionadded:: 5.1 - Asserts that the HTML fragment ``needle`` is *not* contained in the ``haystack``. @@ -2058,10 +2003,6 @@ test client, with the following exceptions: >>> c = AsyncClient() >>> c.get("/customers/details/", {"name": "fred", "age": 7}, ACCEPT="application/json") -.. versionchanged:: 5.1 - - The ``query_params`` argument was added. - Using ``AsyncClient`` any method that makes a request must be awaited:: async def test_my_thing(self): diff --git a/tests/admin_utils/models.py b/tests/admin_utils/models.py index 8e812e27eb23..243f314b0329 100644 --- a/tests/admin_utils/models.py +++ b/tests/admin_utils/models.py @@ -1,5 +1,4 @@ from django.contrib import admin -from django.contrib.admin.models import LogEntry, LogEntryManager from django.db import models from django.utils.translation import gettext_lazy as _ @@ -87,26 +86,3 @@ class Meta: class Car(VehicleMixin): pass - - -class InheritedLogEntryManager(LogEntryManager): - model = LogEntry - - def log_action( - self, - user_id, - content_type_id, - object_id, - object_repr, - action_flag, - change_message="", - ): - return LogEntry.objects.create( - user_id=user_id, - content_type_id=content_type_id, - object_id=str(object_id), - # Changing actual repr to test repr - object_repr="Test Repr", - action_flag=action_flag, - change_message=change_message, - ) diff --git a/tests/admin_utils/test_logentry.py b/tests/admin_utils/test_logentry.py index e97441eb2e5f..491a2201995a 100644 --- a/tests/admin_utils/test_logentry.py +++ b/tests/admin_utils/test_logentry.py @@ -8,10 +8,9 @@ from django.test import TestCase, override_settings from django.urls import reverse from django.utils import translation -from django.utils.deprecation import RemovedInDjango60Warning from django.utils.html import escape -from .models import Article, ArticleProxy, Car, InheritedLogEntryManager, Site +from .models import Article, ArticleProxy, Car, Site @override_settings(ROOT_URLCONF="admin_utils.urls") @@ -236,22 +235,6 @@ def test_logentry_repr(self): logentry = LogEntry.objects.first() self.assertEqual(repr(logentry), str(logentry.action_time)) - # RemovedInDjango60Warning. - def test_log_action(self): - msg = "LogEntryManager.log_action() is deprecated. Use log_actions() instead." - content_type_val = ContentType.objects.get_for_model(Article).pk - with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx: - log_entry = LogEntry.objects.log_action( - self.user.pk, - content_type_val, - self.a1.pk, - repr(self.a1), - CHANGE, - change_message="Changed something else", - ) - self.assertEqual(log_entry, LogEntry.objects.latest("id")) - self.assertEqual(ctx.filename, __file__) - def test_log_actions(self): queryset = Article.objects.all().order_by("-id") msg = "Deleted Something" @@ -289,46 +272,6 @@ def test_log_actions(self): ] self.assertSequenceEqual(logs, expected_log_values) - # RemovedInDjango60Warning. - def test_log_action_fallback(self): - LogEntry.objects2 = InheritedLogEntryManager() - queryset = Article.objects.all().order_by("-id") - content_type = ContentType.objects.get_for_model(self.a1) - self.assertEqual(len(queryset), 3) - msg = ( - "The usage of log_action() is deprecated. Implement log_actions() instead." - ) - with ( - self.assertNumQueries(3), - self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx, - ): - LogEntry.objects2.log_actions(self.user.pk, queryset, DELETION) - self.assertEqual(ctx.filename, __file__) - log_values = ( - LogEntry.objects.filter(action_flag=DELETION) - .order_by("id") - .values_list( - "user", - "content_type", - "object_id", - "object_repr", - "action_flag", - "change_message", - ) - ) - expected_log_values = [ - ( - self.user.pk, - content_type.id, - str(obj.pk), - "Test Repr", - DELETION, - "", - ) - for obj in queryset - ] - self.assertSequenceEqual(log_values, expected_log_values) - def test_recentactions_without_content_type(self): """ If a LogEntry is missing content_type it will not display it in span diff --git a/tests/admin_views/tests.py b/tests/admin_views/tests.py index 8e2c55804bee..7642a186c03d 100644 --- a/tests/admin_views/tests.py +++ b/tests/admin_views/tests.py @@ -29,7 +29,6 @@ from django.test import ( RequestFactory, TestCase, - ignore_warnings, modify_settings, override_settings, skipUnlessDBFeature, @@ -39,7 +38,6 @@ from django.urls import NoReverseMatch, resolve, reverse from django.utils import formats, translation from django.utils.cache import get_max_age -from django.utils.deprecation import RemovedInDjango60Warning from django.utils.encoding import iri_to_uri from django.utils.html import escape from django.utils.http import urlencode @@ -6873,7 +6871,6 @@ def setUpTestData(cls): def setUp(self): self.client.force_login(self.superuser) - @ignore_warnings(category=RemovedInDjango60Warning) def test_readonly_get(self): response = self.client.get(reverse("admin:admin_views_post_add")) self.assertNotContains(response, 'name="posted"') @@ -6934,7 +6931,6 @@ def test_readonly_get(self): ) self.assertContains(response, "%d amount of cool" % p.pk) - @ignore_warnings(category=RemovedInDjango60Warning) def test_readonly_text_field(self): p = Post.objects.create( title="Readonly test", @@ -6954,7 +6950,6 @@ def test_readonly_text_field(self): # Checking readonly field in inline. self.assertContains(response, "test
link") - @ignore_warnings(category=RemovedInDjango60Warning) def test_readonly_post(self): data = { "title": "Django Got Readonly Fields", @@ -7100,7 +7095,6 @@ def test_readonly_unsaved_generated_field(self): response = self.client.get(reverse("admin:admin_views_square_add")) self.assertContains(response, '
-
') - @ignore_warnings(category=RemovedInDjango60Warning) def test_readonly_field_overrides(self): """ Regression test for #22087 - ModelForm Meta overrides are ignored by @@ -7558,7 +7552,6 @@ def setUpTestData(cls): def setUp(self): self.client.force_login(self.superuser) - @ignore_warnings(category=RemovedInDjango60Warning) def test_field_prefix_css_classes(self): """ Fields have a CSS class name with a 'field-' prefix. diff --git a/tests/admin_widgets/tests.py b/tests/admin_widgets/tests.py index 0cf1324623c1..fb296c8655fa 100644 --- a/tests/admin_widgets/tests.py +++ b/tests/admin_widgets/tests.py @@ -22,12 +22,11 @@ ManyToManyField, UUIDField, ) -from django.test import SimpleTestCase, TestCase, ignore_warnings, override_settings +from django.test import SimpleTestCase, TestCase, override_settings from django.test.selenium import screenshot_cases from django.test.utils import requires_tz_support from django.urls import reverse from django.utils import translation -from django.utils.deprecation import RemovedInDjango60Warning from .models import ( Advisor, @@ -109,7 +108,6 @@ def test_TimeField(self): def test_TextField(self): self.assertFormfield(Event, "description", widgets.AdminTextareaWidget) - @ignore_warnings(category=RemovedInDjango60Warning) def test_URLField(self): self.assertFormfield(Event, "link", widgets.AdminURLFieldWidget) @@ -324,7 +322,6 @@ class AdminForeignKeyRawIdWidget(TestDataMixin, TestCase): def setUp(self): self.client.force_login(self.superuser) - @ignore_warnings(category=RemovedInDjango60Warning) def test_nonexistent_target_id(self): band = Band.objects.create(name="Bogey Blues") pk = band.pk @@ -340,7 +337,6 @@ def test_nonexistent_target_id(self): "Select a valid choice. That choice is not one of the available choices.", ) - @ignore_warnings(category=RemovedInDjango60Warning) def test_invalid_target_id(self): for test_str in ("Iñtërnâtiônàlizætiøn", "1234'", -1234): # This should result in an error message, not a server exception. @@ -1738,7 +1734,6 @@ def test_refresh_page(self): self.assertCountSeleniumElements("#id_students_to > option", 2) -@ignore_warnings(category=RemovedInDjango60Warning) class AdminRawIdWidgetSeleniumTests(AdminWidgetSeleniumTestCase): def setUp(self): super().setUp() diff --git a/tests/auth_tests/test_hashers.py b/tests/auth_tests/test_hashers.py index 77242bca4fa1..8c00a8e64474 100644 --- a/tests/auth_tests/test_hashers.py +++ b/tests/auth_tests/test_hashers.py @@ -84,8 +84,8 @@ def test_pbkdf2(self): encoded = make_password("lètmein", "seasalt", "pbkdf2_sha256") self.assertEqual( encoded, - "pbkdf2_sha256$1000000$" - "seasalt$r1uLUxoxpP2Ued/qxvmje7UH9PUJBkRrvf9gGPL7Cps=", + "pbkdf2_sha256$1200000$" + "seasalt$6sTlFi4QohxXLuZigqDIUNX8xG9NxrTmV8+flFQdBqE=", ) self.assertTrue(is_password_usable(encoded)) self.assertTrue(check_password("lètmein", encoded)) @@ -278,8 +278,8 @@ def test_low_level_pbkdf2(self): encoded = hasher.encode("lètmein", "seasalt2") self.assertEqual( encoded, - "pbkdf2_sha256$1000000$" - "seasalt2$egbhFghgsJVDo5Tpg/k9ZnfbySKQ1UQnBYXhR97a7sk=", + "pbkdf2_sha256$1200000$" + "seasalt2$hPlIUc6GqWsws6cZV1K8OuOARm1UrbZ3vLGFoHkH0ZI=", ) self.assertTrue(hasher.verify("lètmein", encoded)) @@ -287,7 +287,7 @@ def test_low_level_pbkdf2_sha1(self): hasher = PBKDF2SHA1PasswordHasher() encoded = hasher.encode("lètmein", "seasalt2") self.assertEqual( - encoded, "pbkdf2_sha1$1000000$seasalt2$3R9hvSAiAy5ARspAFy5GJ/2rjXo=" + encoded, "pbkdf2_sha1$1200000$seasalt2$RGU4BAy93u+JDPtuMamdllndh+c=" ) self.assertTrue(hasher.verify("lètmein", encoded)) diff --git a/tests/backends/base/test_operations.py b/tests/backends/base/test_operations.py index 322355044610..a0bd50351ccd 100644 --- a/tests/backends/base/test_operations.py +++ b/tests/backends/base/test_operations.py @@ -1,12 +1,10 @@ import decimal -from unittest import mock from django.core.management.color import no_style from django.db import NotSupportedError, connection, transaction from django.db.backends.base.operations import BaseDatabaseOperations from django.db.models import DurationField from django.db.models.expressions import Col -from django.db.models.lookups import Exact from django.test import ( SimpleTestCase, TestCase, @@ -15,7 +13,6 @@ skipIfDBFeature, ) from django.utils import timezone -from django.utils.deprecation import RemovedInDjango60Warning from ..models import Author, Book @@ -224,25 +221,3 @@ def test_execute_sql_flush_statements(self): self.assertEqual(author.pk, 1) book = Book.objects.create(author=author) self.assertEqual(book.pk, 1) - - -class DeprecationTests(TestCase): - def test_field_cast_sql_warning(self): - base_ops = BaseDatabaseOperations(connection=connection) - msg = ( - "DatabaseOperations.field_cast_sql() is deprecated use " - "DatabaseOperations.lookup_cast() instead." - ) - with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx: - base_ops.field_cast_sql("integer", "IntegerField") - self.assertEqual(ctx.filename, __file__) - - def test_field_cast_sql_usage_warning(self): - compiler = Author.objects.all().query.get_compiler(connection.alias) - msg = ( - "The usage of DatabaseOperations.field_cast_sql() is deprecated. Implement " - "DatabaseOperations.lookup_cast() instead." - ) - with mock.patch.object(connection.ops.__class__, "field_cast_sql"): - with self.assertRaisesMessage(RemovedInDjango60Warning, msg): - Exact("name", "book__author__name").as_sql(compiler, connection) diff --git a/tests/backends/oracle/tests.py b/tests/backends/oracle/tests.py index 0c4dbce8baf6..aa5555fa2ece 100644 --- a/tests/backends/oracle/tests.py +++ b/tests/backends/oracle/tests.py @@ -3,16 +3,11 @@ from unittest import mock from django.core.exceptions import ImproperlyConfigured -from django.db import DatabaseError, NotSupportedError, ProgrammingError, connection +from django.db import NotSupportedError, ProgrammingError, connection from django.db.models import BooleanField from django.test import TestCase, TransactionTestCase -from ..models import Square, VeryLongModelNameZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ - -try: - from django.db.backends.oracle.oracledb_any import is_oracledb -except ImportError: - is_oracledb = False +from ..models import VeryLongModelNameZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ def no_pool_connection(alias=None): @@ -85,7 +80,6 @@ def test_check_database_version_supported(self, mocked_get_database_version): connection.check_database_version_supported() self.assertTrue(mocked_get_database_version.called) - @unittest.skipUnless(is_oracledb, "Pool specific tests") def test_pool_set_to_true(self): new_connection = no_pool_connection(alias="default_pool") new_connection.settings_dict["OPTIONS"]["pool"] = True @@ -94,7 +88,6 @@ def test_pool_set_to_true(self): finally: new_connection.close_pool() - @unittest.skipUnless(is_oracledb, "Pool specific tests") def test_pool_reuse(self): new_connection = no_pool_connection(alias="default_pool") new_connection.settings_dict["OPTIONS"]["pool"] = { @@ -128,7 +121,6 @@ def get_connection(): conn.close() new_connection.close_pool() - @unittest.skipUnless(is_oracledb, "Pool specific tests") def test_cannot_open_new_connection_in_atomic_block(self): new_connection = no_pool_connection(alias="default_pool") new_connection.settings_dict["OPTIONS"]["pool"] = True @@ -138,7 +130,6 @@ def test_cannot_open_new_connection_in_atomic_block(self): with self.assertRaisesMessage(ProgrammingError, msg): new_connection.ensure_connection() - @unittest.skipUnless(is_oracledb, "Pool specific tests") def test_pooling_not_support_persistent_connections(self): new_connection = no_pool_connection(alias="default_pool") new_connection.settings_dict["OPTIONS"]["pool"] = True @@ -147,48 +138,11 @@ def test_pooling_not_support_persistent_connections(self): with self.assertRaisesMessage(ImproperlyConfigured, msg): new_connection.pool - @unittest.skipIf(is_oracledb, "cx_oracle specific tests") - def test_cx_Oracle_not_support_pooling(self): - new_connection = no_pool_connection() - new_connection.settings_dict["OPTIONS"]["pool"] = True - msg = "Pooling isn't supported by cx_Oracle. Use python-oracledb instead." - with self.assertRaisesMessage(ImproperlyConfigured, msg): - new_connection.connect() - @unittest.skipUnless(connection.vendor == "oracle", "Oracle tests") class TransactionalTests(TransactionTestCase): available_apps = ["backends"] - def test_hidden_no_data_found_exception(self): - # "ORA-1403: no data found" exception is hidden by Oracle OCI library - # when an INSERT statement is used with a RETURNING clause (see #28859). - with connection.cursor() as cursor: - # Create trigger that raises "ORA-1403: no data found". - cursor.execute( - """ - CREATE OR REPLACE TRIGGER "TRG_NO_DATA_FOUND" - AFTER INSERT ON "BACKENDS_SQUARE" - FOR EACH ROW - BEGIN - RAISE NO_DATA_FOUND; - END; - """ - ) - try: - with self.assertRaisesMessage( - DatabaseError, - ( - 'The database did not return a new row id. Probably "ORA-1403: no ' - 'data found" was raised internally but was hidden by the Oracle ' - "OCI library (see https://code.djangoproject.com/ticket/28859)." - ), - ): - Square.objects.create(root=2, square=4) - finally: - with connection.cursor() as cursor: - cursor.execute('DROP TRIGGER "TRG_NO_DATA_FOUND"') - def test_password_with_at_sign(self): from django.db.backends.oracle.base import Database diff --git a/tests/basic/tests.py b/tests/basic/tests.py index 6c2f9f2bd226..f6eabfaed7e8 100644 --- a/tests/basic/tests.py +++ b/tests/basic/tests.py @@ -20,9 +20,8 @@ TransactionTestCase, skipUnlessDBFeature, ) -from django.test.utils import CaptureQueriesContext, ignore_warnings +from django.test.utils import CaptureQueriesContext from django.utils.connection import ConnectionDoesNotExist -from django.utils.deprecation import RemovedInDjango60Warning from django.utils.translation import gettext_lazy from .models import ( @@ -213,144 +212,6 @@ def test_save_primary_with_falsey_db_default(self): with self.assertNumQueries(1): PrimaryKeyWithFalseyDbDefault().save() - def test_save_deprecation(self): - a = Article(headline="original", pub_date=datetime(2014, 5, 16)) - msg = "Passing positional arguments to save() is deprecated" - with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx: - a.save(False, False, None, None) - self.assertEqual(Article.objects.count(), 1) - self.assertEqual(ctx.filename, __file__) - - def test_save_deprecation_positional_arguments_used(self): - a = Article() - fields = ["headline"] - with ( - self.assertWarns(RemovedInDjango60Warning), - mock.patch.object(a, "save_base") as mock_save_base, - ): - a.save(None, 1, 2, fields) - self.assertEqual( - mock_save_base.mock_calls, - [ - mock.call( - using=2, - force_insert=None, - force_update=1, - update_fields=frozenset(fields), - ) - ], - ) - - def test_save_too_many_positional_arguments(self): - a = Article() - msg = "Model.save() takes from 1 to 5 positional arguments but 6 were given" - with ( - self.assertWarns(RemovedInDjango60Warning), - self.assertRaisesMessage(TypeError, msg), - ): - a.save(False, False, None, None, None) - - def test_save_conflicting_positional_and_named_arguments(self): - a = Article() - cases = [ - ("force_insert", True, [42]), - ("force_update", None, [42, 41]), - ("using", "some-db", [42, 41, 40]), - ("update_fields", ["foo"], [42, 41, 40, 39]), - ] - for param_name, param_value, args in cases: - with self.subTest(param_name=param_name): - msg = f"Model.save() got multiple values for argument '{param_name}'" - with ( - self.assertWarns(RemovedInDjango60Warning), - self.assertRaisesMessage(TypeError, msg), - ): - a.save(*args, **{param_name: param_value}) - - async def test_asave_deprecation(self): - a = Article(headline="original", pub_date=datetime(2014, 5, 16)) - msg = "Passing positional arguments to asave() is deprecated" - with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx: - await a.asave(False, False, None, None) - self.assertEqual(await Article.objects.acount(), 1) - self.assertEqual(ctx.filename, __file__) - - async def test_asave_deprecation_positional_arguments_used(self): - a = Article() - fields = ["headline"] - with ( - self.assertWarns(RemovedInDjango60Warning), - mock.patch.object(a, "save_base") as mock_save_base, - ): - await a.asave(None, 1, 2, fields) - self.assertEqual( - mock_save_base.mock_calls, - [ - mock.call( - using=2, - force_insert=None, - force_update=1, - update_fields=frozenset(fields), - ) - ], - ) - - async def test_asave_too_many_positional_arguments(self): - a = Article() - msg = "Model.asave() takes from 1 to 5 positional arguments but 6 were given" - with ( - self.assertWarns(RemovedInDjango60Warning), - self.assertRaisesMessage(TypeError, msg), - ): - await a.asave(False, False, None, None, None) - - async def test_asave_conflicting_positional_and_named_arguments(self): - a = Article() - cases = [ - ("force_insert", True, [42]), - ("force_update", None, [42, 41]), - ("using", "some-db", [42, 41, 40]), - ("update_fields", ["foo"], [42, 41, 40, 39]), - ] - for param_name, param_value, args in cases: - with self.subTest(param_name=param_name): - msg = f"Model.asave() got multiple values for argument '{param_name}'" - with ( - self.assertWarns(RemovedInDjango60Warning), - self.assertRaisesMessage(TypeError, msg), - ): - await a.asave(*args, **{param_name: param_value}) - - @ignore_warnings(category=RemovedInDjango60Warning) - def test_save_positional_arguments(self): - a = Article.objects.create(headline="original", pub_date=datetime(2014, 5, 16)) - a.headline = "changed" - - a.save(False, False, None, ["pub_date"]) - a.refresh_from_db() - self.assertEqual(a.headline, "original") - - a.headline = "changed" - a.save(False, False, None, ["pub_date", "headline"]) - a.refresh_from_db() - self.assertEqual(a.headline, "changed") - - @ignore_warnings(category=RemovedInDjango60Warning) - async def test_asave_positional_arguments(self): - a = await Article.objects.acreate( - headline="original", pub_date=datetime(2014, 5, 16) - ) - a.headline = "changed" - - await a.asave(False, False, None, ["pub_date"]) - await a.arefresh_from_db() - self.assertEqual(a.headline, "original") - - a.headline = "changed" - await a.asave(False, False, None, ["pub_date", "headline"]) - await a.arefresh_from_db() - self.assertEqual(a.headline, "changed") - class ModelTest(TestCase): def test_objects_attribute_is_only_available_on_the_class_itself(self): diff --git a/tests/constraints/tests.py b/tests/constraints/tests.py index 90477100981a..51f09f293740 100644 --- a/tests/constraints/tests.py +++ b/tests/constraints/tests.py @@ -7,8 +7,6 @@ from django.db.models.functions import Abs, Lower, Sqrt, Upper from django.db.transaction import atomic from django.test import SimpleTestCase, TestCase, skipIfDBFeature, skipUnlessDBFeature -from django.test.utils import ignore_warnings -from django.utils.deprecation import RemovedInDjango60Warning from .models import ( ChildModel, @@ -103,11 +101,6 @@ def test_deconstruction(self): }, ) - def test_deprecation(self): - msg = "Passing positional arguments to BaseConstraint is deprecated." - with self.assertRaisesMessage(RemovedInDjango60Warning, msg): - BaseConstraint("name", "violation error message") - def test_name_required(self): msg = ( "BaseConstraint.__init__() missing 1 required keyword-only argument: 'name'" @@ -115,11 +108,6 @@ def test_name_required(self): with self.assertRaisesMessage(TypeError, msg): BaseConstraint() - @ignore_warnings(category=RemovedInDjango60Warning) - def test_positional_arguments(self): - c = BaseConstraint("name", "custom %(name)s message") - self.assertEqual(c.get_violation_error_message(), "custom name message") - class CheckConstraintTests(TestCase): def test_eq(self): @@ -409,23 +397,6 @@ def assertGeneratedFieldIsValidated(self, model): constraint.validate(model, invalid_product, exclude={"price"}) constraint.validate(model, invalid_product, exclude={"rebate"}) - def test_check_deprecation(self): - msg = "CheckConstraint.check is deprecated in favor of `.condition`." - condition = models.Q(foo="bar") - with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx: - constraint = models.CheckConstraint(name="constraint", check=condition) - self.assertEqual(ctx.filename, __file__) - with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx: - self.assertIs(constraint.check, condition) - self.assertEqual(ctx.filename, __file__) - other_condition = models.Q(something="else") - with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx: - constraint.check = other_condition - self.assertEqual(ctx.filename, __file__) - with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx: - self.assertIs(constraint.check, other_condition) - self.assertEqual(ctx.filename, __file__) - def test_database_default(self): models.CheckConstraint( condition=models.Q(field_with_db_default="field_with_db_default"), diff --git a/tests/contenttypes_tests/test_fields.py b/tests/contenttypes_tests/test_fields.py index fc49d59b2775..764b9fa7dbeb 100644 --- a/tests/contenttypes_tests/test_fields.py +++ b/tests/contenttypes_tests/test_fields.py @@ -5,7 +5,6 @@ from django.db import models from django.test import TestCase from django.test.utils import isolate_apps -from django.utils.deprecation import RemovedInDjango60Warning from .models import Answer, Post, Question @@ -99,29 +98,6 @@ def test_only_not_clear_cached_private_relations(self): obj.question -class GetPrefetchQuerySetDeprecation(TestCase): - def test_generic_relation_warning(self): - Question.objects.create(text="test") - questions = Question.objects.all() - msg = ( - "get_prefetch_queryset() is deprecated. Use get_prefetch_querysets() " - "instead." - ) - with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx: - questions[0].answer_set.get_prefetch_queryset(questions) - self.assertEqual(ctx.filename, __file__) - - def test_generic_foreign_key_warning(self): - answers = Answer.objects.all() - msg = ( - "get_prefetch_queryset() is deprecated. Use get_prefetch_querysets() " - "instead." - ) - with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx: - Answer.question.get_prefetch_queryset(answers) - self.assertEqual(ctx.filename, __file__) - - class GetPrefetchQuerySetsTests(TestCase): def test_duplicate_querysets(self): question = Question.objects.create(text="What is your name?") diff --git a/tests/file_storage/tests.py b/tests/file_storage/tests.py index 5f0024b81aa5..c048b8f0719c 100644 --- a/tests/file_storage/tests.py +++ b/tests/file_storage/tests.py @@ -25,18 +25,11 @@ ) from django.db.models import FileField from django.db.models.fields.files import FileDescriptor -from django.test import ( - LiveServerTestCase, - SimpleTestCase, - TestCase, - ignore_warnings, - override_settings, -) +from django.test import LiveServerTestCase, SimpleTestCase, TestCase, override_settings from django.test.utils import requires_tz_support from django.urls import NoReverseMatch, reverse_lazy from django.utils import timezone from django.utils._os import symlinks_supported -from django.utils.deprecation import RemovedInDjango60Warning from .models import ( Storage, @@ -609,69 +602,6 @@ def test_custom_get_available_name(self): self.storage.delete(second) -# RemovedInDjango60Warning: Remove this class. -class OverwritingStorage(FileSystemStorage): - """ - Overwrite existing files instead of appending a suffix to generate an - unused name. - """ - - # Mask out O_EXCL so os.open() doesn't raise OSError if the file exists. - OS_OPEN_FLAGS = FileSystemStorage.OS_OPEN_FLAGS & ~os.O_EXCL - - def get_available_name(self, name, max_length=None): - """Override the effort to find an used name.""" - return name - - -# RemovedInDjango60Warning: Remove this test class. -class OverwritingStorageOSOpenFlagsWarningTests(SimpleTestCase): - storage_class = OverwritingStorage - - def setUp(self): - self.temp_dir = tempfile.mkdtemp() - self.addCleanup(shutil.rmtree, self.temp_dir) - - def test_os_open_flags_deprecation_warning(self): - msg = "Overriding OS_OPEN_FLAGS is deprecated. Use the allow_overwrite " - msg += "parameter instead." - with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx: - self.storage = self.storage_class( - location=self.temp_dir, base_url="/test_media_url/" - ) - self.assertEqual(ctx.filename, __file__) - - -# RemovedInDjango60Warning: Remove this test class. -@ignore_warnings(category=RemovedInDjango60Warning) -class OverwritingStorageOSOpenFlagsTests(FileStorageTests): - storage_class = OverwritingStorage - - def test_save_overwrite_behavior(self): - """Saving to same file name twice overwrites the first file.""" - name = "test.file" - self.assertFalse(self.storage.exists(name)) - content_1 = b"content one" - content_2 = b"second content" - f_1 = ContentFile(content_1) - f_2 = ContentFile(content_2) - stored_name_1 = self.storage.save(name, f_1) - try: - self.assertEqual(stored_name_1, name) - self.assertTrue(self.storage.exists(name)) - self.assertTrue(os.path.exists(os.path.join(self.temp_dir, name))) - with self.storage.open(name) as fp: - self.assertEqual(fp.read(), content_1) - stored_name_2 = self.storage.save(name, f_2) - self.assertEqual(stored_name_2, name) - self.assertTrue(self.storage.exists(name)) - self.assertTrue(os.path.exists(os.path.join(self.temp_dir, name))) - with self.storage.open(name) as fp: - self.assertEqual(fp.read(), content_2) - finally: - self.storage.delete(name) - - class OverwritingStorageTests(FileStorageTests): storage_class = FileSystemStorage diff --git a/tests/foreign_object/tests.py b/tests/foreign_object/tests.py index e288ecd7d4d5..23ad546cd86b 100644 --- a/tests/foreign_object/tests.py +++ b/tests/foreign_object/tests.py @@ -8,7 +8,6 @@ from django.test import SimpleTestCase, TestCase, skipUnlessDBFeature from django.test.utils import isolate_apps from django.utils import translation -from django.utils.deprecation import RemovedInDjango60Warning from .models import ( Article, @@ -712,52 +711,3 @@ def test_pickling_foreignobject(self): foreign_object_restored = pickle.loads(pickle.dumps(foreign_object)) self.assertIn("path_infos", foreign_object_restored.__dict__) self.assertIn("reverse_path_infos", foreign_object_restored.__dict__) - - -class GetJoiningDeprecationTests(TestCase): - def test_foreign_object_get_joining_columns_warning(self): - msg = ( - "ForeignObject.get_joining_columns() is deprecated. Use " - "get_joining_fields() instead." - ) - with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx: - Membership.person.field.get_joining_columns() - self.assertEqual(ctx.filename, __file__) - - def test_foreign_object_get_reverse_joining_columns_warning(self): - msg = ( - "ForeignObject.get_reverse_joining_columns() is deprecated. Use " - "get_reverse_joining_fields() instead." - ) - with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx: - Membership.person.field.get_reverse_joining_columns() - self.assertEqual(ctx.filename, __file__) - - def test_foreign_object_rel_get_joining_columns_warning(self): - msg = ( - "ForeignObjectRel.get_joining_columns() is deprecated. Use " - "get_joining_fields() instead." - ) - with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx: - Membership.person.field.remote_field.get_joining_columns() - self.assertEqual(ctx.filename, __file__) - - def test_join_get_joining_columns_warning(self): - class CustomForeignKey(models.ForeignKey): - def __getattribute__(self, attr): - if attr == "get_joining_fields": - raise AttributeError - return super().__getattribute__(attr) - - class CustomParent(models.Model): - value = models.CharField(max_length=255) - - class CustomChild(models.Model): - links = CustomForeignKey(CustomParent, models.CASCADE) - - msg = ( - "The usage of get_joining_columns() in Join is deprecated. Implement " - "get_joining_fields() instead." - ) - with self.assertWarnsMessage(RemovedInDjango60Warning, msg): - CustomChild.objects.filter(links__value="value") diff --git a/tests/forms_tests/field_tests/test_urlfield.py b/tests/forms_tests/field_tests/test_urlfield.py index 54bc7c5e46b5..f7d318fdc940 100644 --- a/tests/forms_tests/field_tests/test_urlfield.py +++ b/tests/forms_tests/field_tests/test_urlfield.py @@ -1,16 +1,10 @@ -import sys -from types import ModuleType - -from django.conf import FORMS_URLFIELD_ASSUME_HTTPS_DEPRECATED_MSG, Settings, settings from django.core.exceptions import ValidationError from django.forms import URLField -from django.test import SimpleTestCase, ignore_warnings -from django.utils.deprecation import RemovedInDjango60Warning +from django.test import SimpleTestCase from . import FormFieldAssertionsMixin -@ignore_warnings(category=RemovedInDjango60Warning) class URLFieldTest(FormFieldAssertionsMixin, SimpleTestCase): def test_urlfield_widget(self): f = URLField() @@ -32,9 +26,7 @@ def test_urlfield_widget_max_min_length(self): f.clean("http://abcdefghijklmnopqrstuvwxyz.com") def test_urlfield_clean(self): - # RemovedInDjango60Warning: When the deprecation ends, remove the - # assume_scheme argument. - f = URLField(required=False, assume_scheme="https") + f = URLField(required=False) tests = [ ("http://localhost", "http://localhost"), ("http://example.com", "http://example.com"), @@ -146,55 +138,8 @@ def test_urlfield_unable_to_set_strip_kwarg(self): def test_urlfield_assume_scheme(self): f = URLField() - # RemovedInDjango60Warning: When the deprecation ends, replace with: - # "https://example.com" - self.assertEqual(f.clean("example.com"), "http://example.com") + self.assertEqual(f.clean("example.com"), "https://example.com") f = URLField(assume_scheme="http") self.assertEqual(f.clean("example.com"), "http://example.com") f = URLField(assume_scheme="https") self.assertEqual(f.clean("example.com"), "https://example.com") - - -class URLFieldAssumeSchemeDeprecationTest(FormFieldAssertionsMixin, SimpleTestCase): - def test_urlfield_raises_warning(self): - msg = ( - "The default scheme will be changed from 'http' to 'https' in Django 6.0. " - "Pass the forms.URLField.assume_scheme argument to silence this warning, " - "or set the FORMS_URLFIELD_ASSUME_HTTPS transitional setting to True to " - "opt into using 'https' as the new default scheme." - ) - with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx: - f = URLField() - self.assertEqual(f.clean("example.com"), "http://example.com") - self.assertEqual(ctx.filename, __file__) - - @ignore_warnings(category=RemovedInDjango60Warning) - def test_urlfield_forms_urlfield_assume_https(self): - with self.settings(FORMS_URLFIELD_ASSUME_HTTPS=True): - f = URLField() - self.assertEqual(f.clean("example.com"), "https://example.com") - f = URLField(assume_scheme="http") - self.assertEqual(f.clean("example.com"), "http://example.com") - - def test_override_forms_urlfield_assume_https_setting_warning(self): - msg = FORMS_URLFIELD_ASSUME_HTTPS_DEPRECATED_MSG - with self.assertRaisesMessage(RemovedInDjango60Warning, msg): - # Changing FORMS_URLFIELD_ASSUME_HTTPS via self.settings() raises a - # deprecation warning. - with self.settings(FORMS_URLFIELD_ASSUME_HTTPS=True): - pass - - def test_settings_init_forms_urlfield_assume_https_warning(self): - settings_module = ModuleType("fake_settings_module") - settings_module.FORMS_URLFIELD_ASSUME_HTTPS = True - sys.modules["fake_settings_module"] = settings_module - msg = FORMS_URLFIELD_ASSUME_HTTPS_DEPRECATED_MSG - try: - with self.assertRaisesMessage(RemovedInDjango60Warning, msg): - Settings("fake_settings_module") - finally: - del sys.modules["fake_settings_module"] - - def test_access_forms_urlfield_assume_https(self): - # Warning is not raised on access. - self.assertEqual(settings.FORMS_URLFIELD_ASSUME_HTTPS, False) diff --git a/tests/forms_tests/tests/test_error_messages.py b/tests/forms_tests/tests/test_error_messages.py index f4f570010718..e6bfa35dfb90 100644 --- a/tests/forms_tests/tests/test_error_messages.py +++ b/tests/forms_tests/tests/test_error_messages.py @@ -23,8 +23,7 @@ utils, ) from django.template import Context, Template -from django.test import SimpleTestCase, TestCase, ignore_warnings -from django.utils.deprecation import RemovedInDjango60Warning +from django.test import SimpleTestCase, TestCase from django.utils.safestring import mark_safe from ..models import ChoiceModel @@ -168,12 +167,11 @@ def test_urlfield(self): "invalid": "INVALID", "max_length": '"%(value)s" has more than %(limit_value)d characters.', } - with ignore_warnings(category=RemovedInDjango60Warning): - f = URLField(error_messages=e, max_length=17) + f = URLField(error_messages=e, max_length=17) self.assertFormErrors(["REQUIRED"], f.clean, "") self.assertFormErrors(["INVALID"], f.clean, "abc.c") self.assertFormErrors( - ['"http://djangoproject.com" has more than 17 characters.'], + ['"https://djangoproject.com" has more than 17 characters.'], f.clean, "djangoproject.com", ) diff --git a/tests/forms_tests/tests/test_renderers.py b/tests/forms_tests/tests/test_renderers.py index 3c1d8bb8eadf..3e973ad8fc0e 100644 --- a/tests/forms_tests/tests/test_renderers.py +++ b/tests/forms_tests/tests/test_renderers.py @@ -3,14 +3,11 @@ from django.forms.renderers import ( BaseRenderer, - DjangoDivFormRenderer, DjangoTemplates, Jinja2, - Jinja2DivFormRenderer, TemplatesSetting, ) -from django.test import SimpleTestCase, ignore_warnings -from django.utils.deprecation import RemovedInDjango60Warning +from django.test import SimpleTestCase try: import jinja2 @@ -56,31 +53,3 @@ class Jinja2Tests(SharedTests, SimpleTestCase): class TemplatesSettingTests(SharedTests, SimpleTestCase): renderer = TemplatesSetting - - -class DeprecationTests(SimpleTestCase): - def test_django_div_renderer_warning(self): - msg = ( - "The DjangoDivFormRenderer transitional form renderer is deprecated. Use " - "DjangoTemplates instead." - ) - with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx: - DjangoDivFormRenderer() - self.assertEqual(ctx.filename, __file__) - - def test_jinja2_div_renderer_warning(self): - msg = ( - "The Jinja2DivFormRenderer transitional form renderer is deprecated. Use " - "Jinja2 instead." - ) - with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx: - Jinja2DivFormRenderer() - self.assertEqual(ctx.filename, __file__) - - @ignore_warnings(category=RemovedInDjango60Warning) - def test_deprecation_renderers_can_be_instantiated(self): - tests = [DjangoDivFormRenderer, Jinja2DivFormRenderer] - for cls in tests: - with self.subTest(renderer_class=cls): - renderer = cls() - self.assertIsInstance(renderer, cls) diff --git a/tests/generic_inline_admin/tests.py b/tests/generic_inline_admin/tests.py index 13819725d6a1..dfc8f4f7cf18 100644 --- a/tests/generic_inline_admin/tests.py +++ b/tests/generic_inline_admin/tests.py @@ -5,15 +5,8 @@ from django.contrib.contenttypes.models import ContentType from django.forms.formsets import DEFAULT_MAX_NUM from django.forms.models import ModelForm -from django.test import ( - RequestFactory, - SimpleTestCase, - TestCase, - ignore_warnings, - override_settings, -) +from django.test import RequestFactory, SimpleTestCase, TestCase, override_settings from django.urls import reverse -from django.utils.deprecation import RemovedInDjango60Warning from .admin import MediaInline, MediaPermanentInline from .admin import site as admin_site @@ -28,7 +21,6 @@ def setUpTestData(cls): ) -@ignore_warnings(category=RemovedInDjango60Warning) @override_settings(ROOT_URLCONF="generic_inline_admin.urls") class GenericAdminViewTest(TestDataMixin, TestCase): def setUp(self): @@ -103,7 +95,6 @@ def test_basic_edit_POST(self): self.assertEqual(response.status_code, 302) # redirect somewhere -@ignore_warnings(category=RemovedInDjango60Warning) @override_settings(ROOT_URLCONF="generic_inline_admin.urls") class GenericInlineAdminParametersTest(TestDataMixin, TestCase): factory = RequestFactory() @@ -305,7 +296,6 @@ def test_delete(self): @override_settings(ROOT_URLCONF="generic_inline_admin.urls") class NoInlineDeletionTest(SimpleTestCase): - @ignore_warnings(category=RemovedInDjango60Warning) def test_no_deletion(self): inline = MediaPermanentInline(EpisodePermanent, admin_site) fake_request = object() @@ -331,7 +321,6 @@ class GenericInlineModelAdminTest(SimpleTestCase): def setUp(self): self.site = AdminSite() - @ignore_warnings(category=RemovedInDjango60Warning) def test_get_formset_kwargs(self): media_inline = MediaInline(Media, AdminSite()) @@ -371,7 +360,6 @@ class EpisodeAdmin(admin.ModelAdmin): ["keywords", "id", "DELETE"], ) - @ignore_warnings(category=RemovedInDjango60Warning) def test_custom_form_meta_exclude(self): """ The custom ModelForm's `Meta.exclude` is respected by @@ -415,7 +403,6 @@ class EpisodeAdmin(admin.ModelAdmin): ["description", "keywords", "id", "DELETE"], ) - @ignore_warnings(category=RemovedInDjango60Warning) def test_get_fieldsets(self): # get_fieldsets is called when figuring out form fields. # Refs #18681. diff --git a/tests/gis_tests/gdal_tests/test_geom.py b/tests/gis_tests/gdal_tests/test_geom.py index 6c551d080480..919e54751102 100644 --- a/tests/gis_tests/gdal_tests/test_geom.py +++ b/tests/gis_tests/gdal_tests/test_geom.py @@ -13,7 +13,6 @@ from django.template import Context from django.template.engine import Engine from django.test import SimpleTestCase -from django.utils.deprecation import RemovedInDjango60Warning from ..test_data import TestDataMixin @@ -1063,13 +1062,3 @@ def test_curvepolygon_has_polygon_features(self): ) self.assertIsInstance(geom, CurvePolygon) self.assertIsInstance(geom.shell, CircularString) - - -class DeprecationTests(SimpleTestCase): - def test_coord_setter_deprecation(self): - geom = OGRGeometry("POINT (1 2)") - msg = "coord_dim setter is deprecated. Use set_3d() instead." - with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx: - geom.coord_dim = 3 - self.assertEqual(geom.coord_dim, 3) - self.assertEqual(ctx.filename, __file__) diff --git a/tests/gis_tests/test_geoip2.py b/tests/gis_tests/test_geoip2.py index 61b3565d1c72..1d4a5e5351ca 100644 --- a/tests/gis_tests/test_geoip2.py +++ b/tests/gis_tests/test_geoip2.py @@ -7,7 +7,6 @@ from django.contrib.gis.geoip2 import HAS_GEOIP2 from django.contrib.gis.geos import GEOSGeometry from django.test import SimpleTestCase, override_settings -from django.utils.deprecation import RemovedInDjango60Warning if HAS_GEOIP2: import geoip2 @@ -201,22 +200,6 @@ def test_repr(self): version = f"{m.binary_format_major_version}.{m.binary_format_minor_version}" self.assertEqual(repr(g), f"") - def test_coords_deprecation_warning(self): - g = GeoIP2() - msg = "GeoIP2.coords() is deprecated. Use GeoIP2.lon_lat() instead." - with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx: - e1, e2 = g.coords(self.ipv4_str) - self.assertIsInstance(e1, float) - self.assertIsInstance(e2, float) - self.assertEqual(ctx.filename, __file__) - - def test_open_deprecation_warning(self): - msg = "GeoIP2.open() is deprecated. Use GeoIP2() instead." - with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx: - g = GeoIP2.open(settings.GEOIP_PATH, GeoIP2.MODE_AUTO) - self.assertTrue(g._reader) - self.assertEqual(ctx.filename, __file__) - @skipUnless(HAS_GEOIP2, "GeoIP2 is required.") @override_settings( diff --git a/tests/many_to_many/tests.py b/tests/many_to_many/tests.py index c17ed0258c2e..1535ef4105c2 100644 --- a/tests/many_to_many/tests.py +++ b/tests/many_to_many/tests.py @@ -2,7 +2,6 @@ from django.db import connection, transaction from django.test import TestCase, skipIfDBFeature, skipUnlessDBFeature -from django.utils.deprecation import RemovedInDjango60Warning from .models import ( Article, @@ -577,16 +576,6 @@ def test_custom_default_manager_exists_count(self): ) self.assertIn("JOIN", ctx.captured_queries[0]["sql"]) - def test_get_prefetch_queryset_warning(self): - articles = Article.objects.all() - msg = ( - "get_prefetch_queryset() is deprecated. Use get_prefetch_querysets() " - "instead." - ) - with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx: - self.a1.publications.get_prefetch_queryset(articles) - self.assertEqual(ctx.filename, __file__) - def test_get_prefetch_querysets_invalid_querysets_length(self): articles = Article.objects.all() msg = ( diff --git a/tests/many_to_one/tests.py b/tests/many_to_one/tests.py index e7dd0f229f9d..5e31ea17601c 100644 --- a/tests/many_to_one/tests.py +++ b/tests/many_to_one/tests.py @@ -4,7 +4,6 @@ from django.core.exceptions import FieldError, MultipleObjectsReturned from django.db import IntegrityError, models, transaction from django.test import TestCase -from django.utils.deprecation import RemovedInDjango60Warning from django.utils.translation import gettext_lazy from .models import ( @@ -887,29 +886,6 @@ def test_add_remove_set_by_pk_raises(self): with self.assertRaisesMessage(TypeError, msg): usa.cities.set([chicago.pk]) - def test_get_prefetch_queryset_warning(self): - City.objects.create(name="Chicago") - cities = City.objects.all() - msg = ( - "get_prefetch_queryset() is deprecated. Use get_prefetch_querysets() " - "instead." - ) - with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx: - City.country.get_prefetch_queryset(cities) - self.assertEqual(ctx.filename, __file__) - - def test_get_prefetch_queryset_reverse_warning(self): - usa = Country.objects.create(name="United States") - City.objects.create(name="Chicago") - countries = Country.objects.all() - msg = ( - "get_prefetch_queryset() is deprecated. Use get_prefetch_querysets() " - "instead." - ) - with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx: - usa.cities.get_prefetch_queryset(countries) - self.assertEqual(ctx.filename, __file__) - def test_get_prefetch_querysets_invalid_querysets_length(self): City.objects.create(name="Chicago") cities = City.objects.all() diff --git a/tests/model_enums/tests.py b/tests/model_enums/tests.py index ee9dc369f6f1..e60df7c24be4 100644 --- a/tests/model_enums/tests.py +++ b/tests/model_enums/tests.py @@ -6,7 +6,6 @@ from django.db import models from django.template import Context, Template from django.test import SimpleTestCase -from django.utils.deprecation import RemovedInDjango60Warning from django.utils.functional import Promise from django.utils.translation import gettext_lazy as _ from django.utils.version import PY311 @@ -321,13 +320,3 @@ def test_uuid_unsupported(self): class Identifier(uuid.UUID, models.Choices): A = "972ce4eb-a95f-4a56-9339-68c208a76f18" - - -class ChoicesMetaDeprecationTests(SimpleTestCase): - def test_deprecation_warning(self): - from django.db.models import enums - - msg = "ChoicesMeta is deprecated in favor of ChoicesType." - with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx: - enums.ChoicesMeta - self.assertEqual(ctx.filename, __file__) diff --git a/tests/model_fields/test_mixins.py b/tests/model_fields/test_mixins.py index 8847f25987fb..f3412eed3aa3 100644 --- a/tests/model_fields/test_mixins.py +++ b/tests/model_fields/test_mixins.py @@ -1,17 +1,10 @@ from django.db.models.fields.mixins import FieldCacheMixin from django.test import SimpleTestCase -from django.utils.deprecation import RemovedInDjango60Warning from django.utils.functional import cached_property from .models import Foo -# RemovedInDjango60Warning. -class ExampleOld(FieldCacheMixin): - def get_cache_name(self): - return "example" - - class Example(FieldCacheMixin): @cached_property def cache_name(self): @@ -23,21 +16,9 @@ def setUp(self): self.instance = Foo() self.field = Example() - # RemovedInDjango60Warning: when the deprecation ends, replace with: - # def test_cache_name_not_implemented(self): - # with self.assertRaises(NotImplementedError): - # FieldCacheMixin().cache_name - def test_get_cache_name_not_implemented(self): + def test_cache_name_not_implemented(self): with self.assertRaises(NotImplementedError): - FieldCacheMixin().get_cache_name() - - # RemovedInDjango60Warning. - def test_get_cache_name_deprecated(self): - msg = "Override ExampleOld.cache_name instead of get_cache_name()." - with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx: - result = ExampleOld().cache_name - self.assertEqual(result, "example") - self.assertEqual(ctx.filename, __file__) + FieldCacheMixin().cache_name def test_cache_name(self): result = Example().cache_name diff --git a/tests/model_forms/tests.py b/tests/model_forms/tests.py index fd043d3d0316..a432f6ce430d 100644 --- a/tests/model_forms/tests.py +++ b/tests/model_forms/tests.py @@ -22,10 +22,9 @@ modelform_factory, ) from django.template import Context, Template -from django.test import SimpleTestCase, TestCase, ignore_warnings, skipUnlessDBFeature +from django.test import SimpleTestCase, TestCase, skipUnlessDBFeature from django.test.utils import isolate_apps from django.utils.choices import BlankChoiceIterator -from django.utils.deprecation import RemovedInDjango60Warning from django.utils.version import PY314, PYPY from .models import ( @@ -374,7 +373,6 @@ def test_save_blank_false_with_required_false(self): obj = form.save() self.assertEqual(obj.name, "") - @ignore_warnings(category=RemovedInDjango60Warning) def test_save_blank_null_unique_charfield_saves_null(self): form_class = modelform_factory( model=NullableUniqueCharFieldModel, fields="__all__" @@ -913,13 +911,6 @@ class Meta: self.assertEqual(m2.date_published, datetime.date(2010, 1, 1)) -# RemovedInDjango60Warning. -# It's a temporary workaround for the deprecation period. -class HttpsURLField(forms.URLField): - def __init__(self, **kwargs): - super().__init__(assume_scheme="https", **kwargs) - - class FieldOverridesByFormMetaForm(forms.ModelForm): class Meta: model = Category @@ -943,7 +934,7 @@ class Meta: } } field_classes = { - "url": HttpsURLField, + "url": forms.URLField, } @@ -2918,7 +2909,6 @@ def test_big_integer_field(self): }, ) - @ignore_warnings(category=RemovedInDjango60Warning) def test_url_on_modelform(self): "Check basic URL field validation on model forms" @@ -2943,32 +2933,6 @@ class Meta: ) self.assertTrue(HomepageForm({"url": "http://example.com/foo/bar"}).is_valid()) - def test_url_modelform_assume_scheme_warning(self): - msg = ( - "The default scheme will be changed from 'http' to 'https' in Django " - "6.0. Pass the forms.URLField.assume_scheme argument to silence this " - "warning, or set the FORMS_URLFIELD_ASSUME_HTTPS transitional setting to " - "True to opt into using 'https' as the new default scheme." - ) - with self.assertWarnsMessage(RemovedInDjango60Warning, msg): - - class HomepageForm(forms.ModelForm): - class Meta: - model = Homepage - fields = "__all__" - - def test_url_modelform_assume_scheme_early_adopt_https(self): - msg = "The FORMS_URLFIELD_ASSUME_HTTPS transitional setting is deprecated." - with ( - self.assertWarnsMessage(RemovedInDjango60Warning, msg), - self.settings(FORMS_URLFIELD_ASSUME_HTTPS=True), - ): - - class HomepageForm(forms.ModelForm): - class Meta: - model = Homepage - fields = "__all__" - def test_modelform_non_editable_field(self): """ When explicitly including a non-editable field in a ModelForm, the @@ -2995,9 +2959,6 @@ def test_https_prefixing(self): """ class HomepageForm(forms.ModelForm): - # RemovedInDjango60Warning. - url = forms.URLField(assume_scheme="https") - class Meta: model = Homepage fields = "__all__" diff --git a/tests/modeladmin/tests.py b/tests/modeladmin/tests.py index 062368d94e98..3d2e8d00fb26 100644 --- a/tests/modeladmin/tests.py +++ b/tests/modeladmin/tests.py @@ -21,7 +21,6 @@ from django.forms.widgets import Select from django.test import RequestFactory, SimpleTestCase, TestCase from django.test.utils import isolate_apps -from django.utils.deprecation import RemovedInDjango60Warning from .models import Band, Concert, Song @@ -275,36 +274,6 @@ def get_list_filter(self, request): True, ) - def test_lookup_allowed_without_request_deprecation(self): - class ConcertAdmin(ModelAdmin): - list_filter = ["main_band__sign_date"] - - def get_list_filter(self, request): - return self.list_filter + ["main_band__name"] - - def lookup_allowed(self, lookup, value): - return True - - model_admin = ConcertAdmin(Concert, self.site) - msg = ( - "`request` must be added to the signature of ModelAdminTests." - "test_lookup_allowed_without_request_deprecation.." - "ConcertAdmin.lookup_allowed()." - ) - request_band_name_filter = RequestFactory().get( - "/", {"main_band__name": "test"} - ) - request_band_name_filter.user = User.objects.create_superuser( - username="bob", email="bob@test.com", password="test" - ) - with self.assertWarnsMessage(RemovedInDjango60Warning, msg): - changelist = model_admin.get_changelist_instance(request_band_name_filter) - filterspec = changelist.get_filters(request_band_name_filter)[0][0] - self.assertEqual(filterspec.title, "sign date") - filterspec = changelist.get_filters(request_band_name_filter)[0][1] - self.assertEqual(filterspec.title, "name") - self.assertSequenceEqual(filterspec.lookup_choices, [self.band.name]) - def test_field_arguments(self): # If fields is specified, fieldsets_add and fieldsets_change should # just stick the fields into a formsets structure and return it. @@ -921,80 +890,6 @@ def test_log_deletions(self): ] self.assertSequenceEqual(logs, expected_log_values) - # RemovedInDjango60Warning. - def test_log_deletion(self): - ma = ModelAdmin(Band, self.site) - mock_request = MockRequest() - mock_request.user = User.objects.create(username="bill") - content_type = get_content_type_for_model(self.band) - msg = "ModelAdmin.log_deletion() is deprecated. Use log_deletions() instead." - with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx: - created = ma.log_deletion(mock_request, self.band, str(self.band)) - self.assertEqual(ctx.filename, __file__) - fetched = LogEntry.objects.filter(action_flag=DELETION).latest("id") - self.assertEqual(created, fetched) - self.assertEqual(fetched.action_flag, DELETION) - self.assertEqual(fetched.content_type, content_type) - self.assertEqual(fetched.object_id, str(self.band.pk)) - self.assertEqual(fetched.user, mock_request.user) - self.assertEqual(fetched.change_message, "") - self.assertEqual(fetched.object_repr, str(self.band)) - - # RemovedInDjango60Warning. - def test_log_deletion_fallback(self): - class InheritedModelAdmin(ModelAdmin): - def log_deletion(self, request, obj, object_repr): - return super().log_deletion(request, obj, object_repr) - - ima = InheritedModelAdmin(Band, self.site) - mock_request = MockRequest() - mock_request.user = User.objects.create(username="akash") - content_type = get_content_type_for_model(self.band) - Band.objects.create( - name="The Beatles", - bio="A legendary rock band from Liverpool.", - sign_date=date(1962, 1, 1), - ) - Band.objects.create( - name="Mohiner Ghoraguli", - bio="A progressive rock band from Calcutta.", - sign_date=date(1975, 1, 1), - ) - queryset = Band.objects.all().order_by("-id")[:3] - self.assertEqual(len(queryset), 3) - msg = ( - "The usage of log_deletion() is deprecated. Implement log_deletions() " - "instead." - ) - with self.assertNumQueries(3): - with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx: - ima.log_deletions(mock_request, queryset) - self.assertEqual(ctx.filename, __file__) - logs = ( - LogEntry.objects.filter(action_flag=DELETION) - .order_by("id") - .values_list( - "user_id", - "content_type", - "object_id", - "object_repr", - "action_flag", - "change_message", - ) - ) - expected_log_values = [ - ( - mock_request.user.id, - content_type.id, - str(obj.pk), - str(obj), - DELETION, - "", - ) - for obj in queryset - ] - self.assertSequenceEqual(logs, expected_log_values) - def test_get_autocomplete_fields(self): class NameAdmin(ModelAdmin): search_fields = ["name"] diff --git a/tests/one_to_one/tests.py b/tests/one_to_one/tests.py index 0d30dd8f2758..451e97c2745f 100644 --- a/tests/one_to_one/tests.py +++ b/tests/one_to_one/tests.py @@ -1,6 +1,5 @@ from django.db import IntegrityError, connection, transaction from django.test import TestCase -from django.utils.deprecation import RemovedInDjango60Warning from .models import ( Bar, @@ -606,16 +605,6 @@ def test_cached_relation_invalidated_on_save(self): self.b1.save() self.assertEqual(self.b1.place, self.p2) - def test_get_prefetch_queryset_warning(self): - places = Place.objects.all() - msg = ( - "get_prefetch_queryset() is deprecated. Use get_prefetch_querysets() " - "instead." - ) - with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx: - Place.bar.get_prefetch_queryset(places) - self.assertEqual(ctx.filename, __file__) - def test_get_prefetch_querysets_invalid_querysets_length(self): places = Place.objects.all() msg = ( diff --git a/tests/prefetch_related/tests.py b/tests/prefetch_related/tests.py index 856f766d3073..b44a34c456c4 100644 --- a/tests/prefetch_related/tests.py +++ b/tests/prefetch_related/tests.py @@ -4,18 +4,15 @@ from django.core.exceptions import ObjectDoesNotExist from django.db import NotSupportedError, connection from django.db.models import Prefetch, QuerySet, prefetch_related_objects -from django.db.models.fields.related import ForwardManyToOneDescriptor -from django.db.models.query import get_prefetcher, prefetch_one_level +from django.db.models.query import get_prefetcher from django.db.models.sql import Query from django.test import ( TestCase, - ignore_warnings, override_settings, skipIfDBFeature, skipUnlessDBFeature, ) from django.test.utils import CaptureQueriesContext -from django.utils.deprecation import RemovedInDjango60Warning from .models import ( Article, @@ -2013,59 +2010,3 @@ def test_empty_order(self): with self.subTest(book=book): self.assertEqual(len(book.authors_sliced), 1) self.assertIn(book.authors_sliced[0], list(book.authors.all())) - - -class DeprecationTests(TestCase): - def test_get_current_queryset_warning(self): - msg = ( - "Prefetch.get_current_queryset() is deprecated. Use " - "get_current_querysets() instead." - ) - authors = Author.objects.all() - with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx: - self.assertEqual( - Prefetch("authors", authors).get_current_queryset(1), - authors, - ) - self.assertEqual(ctx.filename, __file__) - with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx: - self.assertIsNone(Prefetch("authors").get_current_queryset(1)) - self.assertEqual(ctx.filename, __file__) - - @ignore_warnings(category=RemovedInDjango60Warning) - def test_prefetch_one_level_fallback(self): - class NoGetPrefetchQuerySetsDescriptor(ForwardManyToOneDescriptor): - def get_prefetch_queryset(self, instances, queryset=None): - if queryset is None: - return super().get_prefetch_querysets(instances) - return super().get_prefetch_querysets(instances, [queryset]) - - def __getattribute__(self, name): - if name == "get_prefetch_querysets": - raise AttributeError - return super().__getattribute__(name) - - house = House.objects.create() - room = Room.objects.create(house=house) - house.main_room = room - house.save() - - # prefetch_one_level() fallbacks to get_prefetch_queryset(). - prefetcher = NoGetPrefetchQuerySetsDescriptor(Room._meta.get_field("house")) - obj_list, additional_lookups = prefetch_one_level( - [room], - prefetcher, - Prefetch("house", House.objects.all()), - 0, - ) - self.assertEqual(obj_list, [house]) - self.assertEqual(additional_lookups, []) - - obj_list, additional_lookups = prefetch_one_level( - [room], - prefetcher, - Prefetch("house"), - 0, - ) - self.assertEqual(obj_list, [house]) - self.assertEqual(additional_lookups, []) diff --git a/tests/runtests.py b/tests/runtests.py index 57d4fcea721d..adf9e1bc29d5 100755 --- a/tests/runtests.py +++ b/tests/runtests.py @@ -29,8 +29,8 @@ from django.test.selenium import SeleniumTestCase, SeleniumTestCaseBase from django.test.utils import NullTimeKeeper, TimeKeeper, get_runner from django.utils.deprecation import ( - RemovedInDjango60Warning, RemovedInDjango61Warning, + RemovedInDjango70Warning, ) from django.utils.functional import classproperty from django.utils.log import DEFAULT_LOGGING @@ -46,7 +46,7 @@ warnings.filterwarnings("ignore", r"\(1003, *", category=MySQLdb.Warning) # Make deprecation warnings errors to ensure no usage of deprecated features. -warnings.simplefilter("error", RemovedInDjango60Warning) +warnings.simplefilter("error", RemovedInDjango70Warning) warnings.simplefilter("error", RemovedInDjango61Warning) # Make resource and runtime warning errors to ensure no usage of error prone # patterns. diff --git a/tests/update_only_fields/tests.py b/tests/update_only_fields/tests.py index 43f3e1fd16ec..2c8699579966 100644 --- a/tests/update_only_fields/tests.py +++ b/tests/update_only_fields/tests.py @@ -1,6 +1,5 @@ from django.db.models.signals import post_save, pre_save from django.test import TestCase -from django.utils.deprecation import RemovedInDjango60Warning from .models import Account, Employee, Person, Profile, ProxyEmployee @@ -257,31 +256,6 @@ def post_save_receiver(**kwargs): pre_save.disconnect(pre_save_receiver) post_save.disconnect(post_save_receiver) - def test_empty_update_fields_positional_save(self): - s = Person.objects.create(name="Sara", gender="F") - - msg = "Passing positional arguments to save() is deprecated" - with ( - self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx, - self.assertNumQueries(0), - ): - s.save(False, False, None, []) - self.assertEqual(ctx.filename, __file__) - - async def test_empty_update_fields_positional_asave(self): - s = await Person.objects.acreate(name="Sara", gender="F") - # Workaround for a lack of async assertNumQueries. - s.name = "Other" - - msg = "Passing positional arguments to asave() is deprecated" - with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx: - await s.asave(False, False, None, []) - self.assertEqual(ctx.filename, __file__) - - # No save occurred for an empty update_fields. - await s.arefresh_from_db() - self.assertEqual(s.name, "Sara") - def test_num_queries_inheritance(self): s = Employee.objects.create(name="Sara", gender="F") s.employee_num = 1 diff --git a/tests/urlpatterns/tests.py b/tests/urlpatterns/tests.py index 6c8d6470c0e5..5f1a45ba1fa8 100644 --- a/tests/urlpatterns/tests.py +++ b/tests/urlpatterns/tests.py @@ -13,8 +13,7 @@ resolve, reverse, ) -from django.urls.converters import REGISTERED_CONVERTERS, IntConverter -from django.utils.deprecation import RemovedInDjango60Warning +from django.urls.converters import IntConverter from django.views import View from .converters import Base64Converter, DynamicConverter @@ -204,35 +203,14 @@ def test_invalid_converter(self): path("foo//", empty_view) def test_warning_override_default_converter(self): - # RemovedInDjango60Warning: when the deprecation ends, replace with - # msg = "Converter 'int' is already registered." - # with self.assertRaisesMessage(ValueError, msg): - msg = ( - "Converter 'int' is already registered. Support for overriding registered " - "converters is deprecated and will be removed in Django 6.0." - ) - try: - with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx: - register_converter(IntConverter, "int") - finally: - REGISTERED_CONVERTERS.pop("int", None) - self.assertEqual(ctx.filename, __file__) + msg = "Converter 'int' is already registered." + with self.assertRaisesMessage(ValueError, msg): + register_converter(IntConverter, "int") def test_warning_override_converter(self): - # RemovedInDjango60Warning: when the deprecation ends, replace with - # msg = "Converter 'base64' is already registered." - # with self.assertRaisesMessage(ValueError, msg): - msg = ( - "Converter 'base64' is already registered. Support for overriding " - "registered converters is deprecated and will be removed in Django 6.0." - ) - try: - with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx: - register_converter(Base64Converter, "base64") - register_converter(Base64Converter, "base64") - finally: - REGISTERED_CONVERTERS.pop("base64", None) - self.assertEqual(ctx.filename, __file__) + msg = "Converter 'base64' is already registered." + with self.assertRaisesMessage(ValueError, msg): + register_converter(Base64Converter, "base64") def test_invalid_view(self): msg = "view must be a callable or a list/tuple in the case of include()." diff --git a/tests/utils_tests/test_html.py b/tests/utils_tests/test_html.py index 0beaf98bff2b..88bfa249253f 100644 --- a/tests/utils_tests/test_html.py +++ b/tests/utils_tests/test_html.py @@ -4,7 +4,6 @@ from django.core.exceptions import SuspiciousOperation from django.core.serializers.json import DjangoJSONEncoder from django.test import SimpleTestCase -from django.utils.deprecation import RemovedInDjango60Warning from django.utils.functional import lazystr from django.utils.html import ( conditional_escape, @@ -69,14 +68,10 @@ def test_format_html(self): ) def test_format_html_no_params(self): - msg = "Calling format_html() without passing args or kwargs is deprecated." - # RemovedInDjango60Warning: when the deprecation ends, replace with: - # msg = "args or kwargs must be provided." - # with self.assertRaisesMessage(TypeError, msg): - with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx: + msg = "args or kwargs must be provided." + with self.assertRaisesMessage(TypeError, msg): name = "Adam" self.assertEqual(format_html(f"{name}"), "Adam") - self.assertEqual(ctx.filename, __file__) def test_format_html_join_with_positional_arguments(self): self.assertEqual( diff --git a/tests/utils_tests/test_itercompat.py b/tests/utils_tests/test_itercompat.py deleted file mode 100644 index a95867c621c4..000000000000 --- a/tests/utils_tests/test_itercompat.py +++ /dev/null @@ -1,16 +0,0 @@ -# RemovedInDjango60Warning: Remove this entire module. - -from django.test import SimpleTestCase -from django.utils.deprecation import RemovedInDjango60Warning -from django.utils.itercompat import is_iterable - - -class TestIterCompat(SimpleTestCase): - def test_is_iterable_deprecation(self): - msg = ( - "django.utils.itercompat.is_iterable() is deprecated. " - "Use isinstance(..., collections.abc.Iterable) instead." - ) - with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx: - is_iterable([]) - self.assertEqual(ctx.filename, __file__)