Moved make_hashable() to django.utils and added tests.

This commit is contained in:
aspalding 2018-10-16 10:01:31 -05:00 committed by Tim Graham
parent 6752c2756e
commit 834c4ec8e4
3 changed files with 35 additions and 10 deletions

View File

@ -9,6 +9,7 @@ from django.db.models import fields
from django.db.models.query_utils import Q from django.db.models.query_utils import Q
from django.utils.deconstruct import deconstructible from django.utils.deconstruct import deconstructible
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.hashable import make_hashable
class SQLiteNumericMixin: class SQLiteNumericMixin:
@ -138,16 +139,6 @@ class Combinable:
) )
def make_hashable(value):
if isinstance(value, list):
return tuple(map(make_hashable, value))
if isinstance(value, dict):
return tuple([
(key, make_hashable(nested_value)) for key, nested_value in value.items()
])
return value
@deconstructible @deconstructible
class BaseExpression: class BaseExpression:
"""Base class for all query expressions.""" """Base class for all query expressions."""

9
django/utils/hashable.py Normal file
View File

@ -0,0 +1,9 @@
def make_hashable(value):
if isinstance(value, list):
return tuple(map(make_hashable, value))
if isinstance(value, dict):
return tuple([
(key, make_hashable(nested_value))
for key, nested_value in value.items()
])
return value

View File

@ -0,0 +1,25 @@
from django.test import SimpleTestCase
from django.utils.hashable import make_hashable
class TestHashable(SimpleTestCase):
def test_equal(self):
tests = (
([], ()),
(['a', 1], ('a', 1)),
({}, ()),
({'a'}, {'a'}),
(frozenset({'a'}), {'a'}),
({'a': 1}, (('a', 1),)),
)
for value, expected in tests:
with self.subTest(value=value):
self.assertEqual(make_hashable(value), expected)
def test_count_equal(self):
tests = (
({'a': 1, 'b': ['a', 1]}, (('a', 1), ('b', ('a', 1)))),
)
for value, expected in tests:
with self.subTest(value=value):
self.assertCountEqual(make_hashable(value), expected)