summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIllia Volochii <illia.volochii@gmail.com>2021-09-20 22:33:42 +0300
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2021-09-22 09:26:21 +0200
commitbc4c7e5d68e01207268c868932eb14ae4206f02c (patch)
tree7af7b0aa55c53dfc837867147cb734041c399e34
parente0a56ad3c86c1b5c3d5842783bf6b20e96304770 (diff)
Optimized handling case-insensitive mappings.
Elements yielded by _destruct_iterable_mapping_values are always unpacked. Since unpacking can be done with any iterable, there is no need to convert elements to tuples. Also, such elements can be used directly in for loops, creating a dictionary of them is excessive. Co-authored-by: Nick Pope <nick@nickpope.me.uk>
-rw-r--r--django/http/response.py9
-rw-r--r--django/utils/datastructures.py33
2 files changed, 20 insertions, 22 deletions
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