diff --git a/django/http/response.py b/django/http/response.py index 929129342f..ab7158f7e0 100644 --- a/django/http/response.py +++ b/django/http/response.py @@ -5,7 +5,6 @@ import os import re import sys import time -from collections.abc import Mapping from email.header import Header from http.client import responses from urllib.parse import quote, urlparse @@ -16,9 +15,7 @@ from django.core.exceptions import DisallowedRedirect from django.core.serializers.json import DjangoJSONEncoder from django.http.cookie import SimpleCookie from django.utils import timezone -from django.utils.datastructures import ( - CaseInsensitiveMapping, _destruct_iterable_mapping_values, -) +from django.utils.datastructures import CaseInsensitiveMapping from django.utils.encoding import iri_to_uri from django.utils.http import http_date from django.utils.regex_helper import _lazy_re_compile @@ -32,10 +29,8 @@ class ResponseHeaders(CaseInsensitiveMapping): Populate the initial data using __setitem__ to ensure values are correctly encoded. """ - if not isinstance(data, Mapping): - data = {k: v for k, v in _destruct_iterable_mapping_values(data)} self._store = {} - for header, value in data.items(): + for header, value in self._unpack_items(data): self[header] = value def _convert_to_charset(self, value, charset, mime_encode=False): diff --git a/django/utils/datastructures.py b/django/utils/datastructures.py index f1e9986ca1..18c91aa5e8 100644 --- a/django/utils/datastructures.py +++ b/django/utils/datastructures.py @@ -284,18 +284,6 @@ class DictWrapper(dict): return value -def _destruct_iterable_mapping_values(data): - for i, elem in enumerate(data): - if len(elem) != 2: - raise ValueError( - 'dictionary update sequence element #{} has ' - 'length {}; 2 is required.'.format(i, len(elem)) - ) - if not isinstance(elem[0], str): - raise ValueError('Element key %r invalid, only strings are allowed' % elem[0]) - yield tuple(elem) - - class CaseInsensitiveMapping(Mapping): """ Mapping allowing case-insensitive key lookups. Original case of keys is @@ -315,9 +303,7 @@ class CaseInsensitiveMapping(Mapping): """ def __init__(self, data): - if not isinstance(data, Mapping): - data = {k: v for k, v in _destruct_iterable_mapping_values(data)} - self._store = {k.lower(): (k, v) for k, v in data.items()} + self._store = {k.lower(): (k, v) for k, v in self._unpack_items(data)} def __getitem__(self, key): return self._store[key.lower()][1] @@ -340,3 +326,20 @@ class CaseInsensitiveMapping(Mapping): def copy(self): return self + + @staticmethod + def _unpack_items(data): + if isinstance(data, Mapping): + yield from data.items() + return + for i, elem in enumerate(data): + if len(elem) != 2: + raise ValueError( + 'dictionary update sequence element #{} has length {}; ' + '2 is required.'.format(i, len(elem)) + ) + if not isinstance(elem[0], str): + raise ValueError( + 'Element key %r invalid, only strings are allowed' % elem[0] + ) + yield elem