mirror of https://github.com/django/django.git
Fixed #34983 -- Deprecated django.utils.itercompat.is_iterable().
This commit is contained in:
parent
eabfa2d0e3
commit
5e28cd3f2c
|
@ -1,3 +1,5 @@
|
||||||
|
from collections.abc import Iterable
|
||||||
|
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
from django.contrib import auth
|
from django.contrib import auth
|
||||||
from django.contrib.auth.base_user import AbstractBaseUser, BaseUserManager
|
from django.contrib.auth.base_user import AbstractBaseUser, BaseUserManager
|
||||||
|
@ -8,7 +10,6 @@ from django.core.mail import send_mail
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models.manager import EmptyManager
|
from django.db.models.manager import EmptyManager
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.itercompat import is_iterable
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from .validators import UnicodeUsernameValidator
|
from .validators import UnicodeUsernameValidator
|
||||||
|
@ -315,7 +316,7 @@ class PermissionsMixin(models.Model):
|
||||||
Return True if the user has each of the specified permissions. If
|
Return True if the user has each of the specified permissions. If
|
||||||
object is passed, check if the user has all required perms for it.
|
object is passed, check if the user has all required perms for it.
|
||||||
"""
|
"""
|
||||||
if not is_iterable(perm_list) or isinstance(perm_list, str):
|
if not isinstance(perm_list, Iterable) or isinstance(perm_list, str):
|
||||||
raise ValueError("perm_list must be an iterable of permissions.")
|
raise ValueError("perm_list must be an iterable of permissions.")
|
||||||
return all(self.has_perm(perm, obj) for perm in perm_list)
|
return all(self.has_perm(perm, obj) for perm in perm_list)
|
||||||
|
|
||||||
|
@ -480,7 +481,7 @@ class AnonymousUser:
|
||||||
return _user_has_perm(self, perm, obj=obj)
|
return _user_has_perm(self, perm, obj=obj)
|
||||||
|
|
||||||
def has_perms(self, perm_list, obj=None):
|
def has_perms(self, perm_list, obj=None):
|
||||||
if not is_iterable(perm_list) or isinstance(perm_list, str):
|
if not isinstance(perm_list, Iterable) or isinstance(perm_list, str):
|
||||||
raise ValueError("perm_list must be an iterable of permissions.")
|
raise ValueError("perm_list must be an iterable of permissions.")
|
||||||
return all(self.has_perm(perm, obj) for perm in perm_list)
|
return all(self.has_perm(perm, obj) for perm in perm_list)
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
from collections.abc import Iterable
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
|
|
||||||
from django.utils.inspect import func_accepts_kwargs
|
from django.utils.inspect import func_accepts_kwargs
|
||||||
from django.utils.itercompat import is_iterable
|
|
||||||
|
|
||||||
|
|
||||||
class Tags:
|
class Tags:
|
||||||
|
@ -86,7 +86,7 @@ class CheckRegistry:
|
||||||
|
|
||||||
for check in checks:
|
for check in checks:
|
||||||
new_errors = check(app_configs=app_configs, databases=databases)
|
new_errors = check(app_configs=app_configs, databases=databases)
|
||||||
if not is_iterable(new_errors):
|
if not isinstance(new_errors, Iterable):
|
||||||
raise TypeError(
|
raise TypeError(
|
||||||
"The function %r did not return a list. All functions "
|
"The function %r did not return a list. All functions "
|
||||||
"registered with the checks registry must return a list." % check,
|
"registered with the checks registry must return a list." % check,
|
||||||
|
|
|
@ -5,6 +5,7 @@ import operator
|
||||||
import uuid
|
import uuid
|
||||||
import warnings
|
import warnings
|
||||||
from base64 import b64decode, b64encode
|
from base64 import b64decode, b64encode
|
||||||
|
from collections.abc import Iterable
|
||||||
from functools import partialmethod, total_ordering
|
from functools import partialmethod, total_ordering
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
|
@ -31,7 +32,6 @@ from django.utils.dateparse import (
|
||||||
from django.utils.duration import duration_microseconds, duration_string
|
from django.utils.duration import duration_microseconds, duration_string
|
||||||
from django.utils.functional import Promise, cached_property
|
from django.utils.functional import Promise, cached_property
|
||||||
from django.utils.ipv6 import clean_ipv6_address
|
from django.utils.ipv6 import clean_ipv6_address
|
||||||
from django.utils.itercompat import is_iterable
|
|
||||||
from django.utils.text import capfirst
|
from django.utils.text import capfirst
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
@ -317,13 +317,13 @@ class Field(RegisterLookupMixin):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _choices_is_value(cls, value):
|
def _choices_is_value(cls, value):
|
||||||
return isinstance(value, (str, Promise)) or not is_iterable(value)
|
return isinstance(value, (str, Promise)) or not isinstance(value, Iterable)
|
||||||
|
|
||||||
def _check_choices(self):
|
def _check_choices(self):
|
||||||
if not self.choices:
|
if not self.choices:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
if not is_iterable(self.choices) or isinstance(self.choices, str):
|
if not isinstance(self.choices, Iterable) or isinstance(self.choices, str):
|
||||||
return [
|
return [
|
||||||
checks.Error(
|
checks.Error(
|
||||||
"'choices' must be a mapping (e.g. a dictionary) or an iterable "
|
"'choices' must be a mapping (e.g. a dictionary) or an iterable "
|
||||||
|
|
|
@ -3,6 +3,7 @@ import re
|
||||||
import sys
|
import sys
|
||||||
import warnings
|
import warnings
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
from collections.abc import Iterable
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from itertools import cycle as itertools_cycle
|
from itertools import cycle as itertools_cycle
|
||||||
from itertools import groupby
|
from itertools import groupby
|
||||||
|
@ -10,7 +11,6 @@ from itertools import groupby
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.html import conditional_escape, escape, format_html
|
from django.utils.html import conditional_escape, escape, format_html
|
||||||
from django.utils.itercompat import is_iterable
|
|
||||||
from django.utils.lorem_ipsum import paragraphs, words
|
from django.utils.lorem_ipsum import paragraphs, words
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
|
|
||||||
|
@ -1198,7 +1198,7 @@ def query_string(context, query_dict=None, **kwargs):
|
||||||
if value is None:
|
if value is None:
|
||||||
if key in query_dict:
|
if key in query_dict:
|
||||||
del query_dict[key]
|
del query_dict[key]
|
||||||
elif is_iterable(value) and not isinstance(value, str):
|
elif isinstance(value, Iterable) and not isinstance(value, str):
|
||||||
query_dict.setlist(key, value)
|
query_dict.setlist(key, value)
|
||||||
else:
|
else:
|
||||||
query_dict[key] = value
|
query_dict[key] = value
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
|
from collections.abc import Iterable
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
from inspect import getfullargspec, unwrap
|
from inspect import getfullargspec, unwrap
|
||||||
|
|
||||||
from django.utils.html import conditional_escape
|
from django.utils.html import conditional_escape
|
||||||
from django.utils.itercompat import is_iterable
|
|
||||||
|
|
||||||
from .base import Node, Template, token_kwargs
|
from .base import Node, Template, token_kwargs
|
||||||
from .exceptions import TemplateSyntaxError
|
from .exceptions import TemplateSyntaxError
|
||||||
|
@ -263,7 +263,9 @@ class InclusionNode(TagHelperNode):
|
||||||
t = self.filename
|
t = self.filename
|
||||||
elif isinstance(getattr(self.filename, "template", None), Template):
|
elif isinstance(getattr(self.filename, "template", None), Template):
|
||||||
t = self.filename.template
|
t = self.filename.template
|
||||||
elif not isinstance(self.filename, str) and is_iterable(self.filename):
|
elif not isinstance(self.filename, str) and isinstance(
|
||||||
|
self.filename, Iterable
|
||||||
|
):
|
||||||
t = context.template.engine.select_template(self.filename)
|
t = context.template.engine.select_template(self.filename)
|
||||||
else:
|
else:
|
||||||
t = context.template.engine.get_template(self.filename)
|
t = context.template.engine.get_template(self.filename)
|
||||||
|
|
|
@ -2,6 +2,7 @@ import json
|
||||||
import mimetypes
|
import mimetypes
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
from collections.abc import Iterable
|
||||||
from copy import copy
|
from copy import copy
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
|
@ -25,7 +26,6 @@ from django.urls import resolve
|
||||||
from django.utils.encoding import force_bytes
|
from django.utils.encoding import force_bytes
|
||||||
from django.utils.functional import SimpleLazyObject
|
from django.utils.functional import SimpleLazyObject
|
||||||
from django.utils.http import urlencode
|
from django.utils.http import urlencode
|
||||||
from django.utils.itercompat import is_iterable
|
|
||||||
from django.utils.regex_helper import _lazy_re_compile
|
from django.utils.regex_helper import _lazy_re_compile
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
|
@ -303,7 +303,7 @@ def encode_multipart(boundary, data):
|
||||||
)
|
)
|
||||||
elif is_file(value):
|
elif is_file(value):
|
||||||
lines.extend(encode_file(boundary, key, value))
|
lines.extend(encode_file(boundary, key, value))
|
||||||
elif not isinstance(value, str) and is_iterable(value):
|
elif not isinstance(value, str) and isinstance(value, Iterable):
|
||||||
for item in value:
|
for item in value:
|
||||||
if is_file(item):
|
if is_file(item):
|
||||||
lines.extend(encode_file(boundary, key, item))
|
lines.extend(encode_file(boundary, key, item))
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from django.utils.itercompat import is_iterable
|
from collections.abc import Iterable
|
||||||
|
|
||||||
|
|
||||||
def make_hashable(value):
|
def make_hashable(value):
|
||||||
|
@ -19,7 +19,7 @@ def make_hashable(value):
|
||||||
try:
|
try:
|
||||||
hash(value)
|
hash(value)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
if is_iterable(value):
|
if isinstance(value, Iterable):
|
||||||
return tuple(map(make_hashable, value))
|
return tuple(map(make_hashable, value))
|
||||||
# Non-hashable, non-iterable.
|
# Non-hashable, non-iterable.
|
||||||
raise
|
raise
|
||||||
|
|
|
@ -1,5 +1,18 @@
|
||||||
|
# RemovedInDjango60Warning: Remove this entire module.
|
||||||
|
|
||||||
|
import warnings
|
||||||
|
|
||||||
|
from django.utils.deprecation import RemovedInDjango60Warning
|
||||||
|
|
||||||
|
|
||||||
def is_iterable(x):
|
def is_iterable(x):
|
||||||
"An implementation independent way of checking for iterables"
|
"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:
|
try:
|
||||||
iter(x)
|
iter(x)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
|
|
|
@ -59,6 +59,9 @@ details on these changes.
|
||||||
* The ``ModelAdmin.log_deletion()`` and ``LogEntryManager.log_action()``
|
* The ``ModelAdmin.log_deletion()`` and ``LogEntryManager.log_action()``
|
||||||
methods will be removed.
|
methods will be removed.
|
||||||
|
|
||||||
|
* The undocumented ``django.utils.itercompat.is_iterable()`` function and the
|
||||||
|
``django.utils.itercompat`` module will be removed.
|
||||||
|
|
||||||
.. _deprecation-removed-in-5.1:
|
.. _deprecation-removed-in-5.1:
|
||||||
|
|
||||||
5.1
|
5.1
|
||||||
|
|
|
@ -303,6 +303,10 @@ Miscellaneous
|
||||||
``ModelAdmin.log_deletions()`` and ``LogEntryManager.log_actions()``
|
``ModelAdmin.log_deletions()`` and ``LogEntryManager.log_actions()``
|
||||||
instead.
|
instead.
|
||||||
|
|
||||||
|
* The undocumented ``django.utils.itercompat.is_iterable()`` function and the
|
||||||
|
``django.utils.itercompat`` module are deprecated. Use
|
||||||
|
``isinstance(..., collections.abc.Iterable)`` instead.
|
||||||
|
|
||||||
Features removed in 5.1
|
Features removed in 5.1
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
# 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):
|
||||||
|
is_iterable([])
|
Loading…
Reference in New Issue