summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAymeric Augustin <aymeric.augustin@m4x.org>2013-02-25 22:53:08 +0100
committerAymeric Augustin <aymeric.augustin@m4x.org>2013-02-25 23:05:20 +0100
commite76147a83a7306d6d83057b982207ddab37eb942 (patch)
tree76208c6cd41b050c119c733bbce3f5541c66d8e0
parent0836670c5cd8bb17322504c46e07d3944add63c3 (diff)
Fixed #19634 -- Added proper __hash__ methods.
Classes overriding __eq__ need a __hash__ such that equal objects have the same hash. Thanks akaariai for the report and regebro for the patch.
-rw-r--r--django/db/backends/__init__.py3
-rw-r--r--django/db/models/fields/__init__.py3
-rw-r--r--django/db/models/fields/files.py1
-rw-r--r--django/dispatch/saferef.py3
-rw-r--r--django/test/html.py3
-rw-r--r--django/utils/functional.py3
-rw-r--r--tests/regressiontests/backends/tests.py24
7 files changed, 24 insertions, 16 deletions
diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py
index 958982bdae..b77455e6e1 100644
--- a/django/db/backends/__init__.py
+++ b/django/db/backends/__init__.py
@@ -51,7 +51,8 @@ class BaseDatabaseWrapper(object):
def __ne__(self, other):
return not self == other
- __hash__ = object.__hash__
+ def __hash__(self):
+ return hash(self.alias)
def get_connection_params(self):
raise NotImplementedError
diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py
index 279c712a98..2702876397 100644
--- a/django/db/models/fields/__init__.py
+++ b/django/db/models/fields/__init__.py
@@ -135,7 +135,8 @@ class Field(object):
return self.creation_counter < other.creation_counter
return NotImplemented
- __hash__ = object.__hash__
+ def __hash__(self):
+ return hash(self.creation_counter)
def __deepcopy__(self, memodict):
# We don't have to deepcopy very much here, since most things are not
diff --git a/django/db/models/fields/files.py b/django/db/models/fields/files.py
index e0cc27a081..e631f177e9 100644
--- a/django/db/models/fields/files.py
+++ b/django/db/models/fields/files.py
@@ -30,7 +30,6 @@ class FieldFile(File):
return not self.__eq__(other)
def __hash__(self):
- # Required because we defined a custom __eq__.
return hash(self.name)
# The standard File contains most of the necessary properties, but
diff --git a/django/dispatch/saferef.py b/django/dispatch/saferef.py
index 7423669c96..c7731d41fe 100644
--- a/django/dispatch/saferef.py
+++ b/django/dispatch/saferef.py
@@ -152,7 +152,8 @@ class BoundMethodWeakref(object):
__repr__ = __str__
- __hash__ = object.__hash__
+ def __hash__(self):
+ return hash(self.key)
def __bool__( self ):
"""Whether we are still a valid reference"""
diff --git a/django/test/html.py b/django/test/html.py
index 2f6e4c9481..cda9dfab27 100644
--- a/django/test/html.py
+++ b/django/test/html.py
@@ -85,7 +85,8 @@ class Element(object):
return False
return True
- __hash__ = object.__hash__
+ def __hash__(self):
+ return hash((self.name,) + tuple(a for a in self.attributes))
def __ne__(self, element):
return not self.__eq__(element)
diff --git a/django/utils/functional.py b/django/utils/functional.py
index 51001ea655..69a32b101a 100644
--- a/django/utils/functional.py
+++ b/django/utils/functional.py
@@ -152,7 +152,8 @@ def lazy(func, *resultclasses):
other = other.__cast()
return self.__cast() < other
- __hash__ = object.__hash__
+ def __hash__(self):
+ return hash(self.__cast())
def __mod__(self, rhs):
if self._delegate_bytes and not six.PY3:
diff --git a/tests/regressiontests/backends/tests.py b/tests/regressiontests/backends/tests.py
index 0e1700b36e..b0413b1ebc 100644
--- a/tests/regressiontests/backends/tests.py
+++ b/tests/regressiontests/backends/tests.py
@@ -576,9 +576,11 @@ class ThreadTests(TestCase):
different for each thread.
Refs #17258.
"""
- connections_set = set()
+ # Map connections by id because connections with identical aliases
+ # have the same hash.
+ connections_dict = {}
connection.cursor()
- connections_set.add(connection)
+ connections_dict[id(connection)] = connection
def runner():
# Passing django.db.connection between threads doesn't work while
# connections[DEFAULT_DB_ALIAS] does.
@@ -588,19 +590,19 @@ class ThreadTests(TestCase):
# main thread.
connection.allow_thread_sharing = True
connection.cursor()
- connections_set.add(connection)
+ connections_dict[id(connection)] = connection
for x in range(2):
t = threading.Thread(target=runner)
t.start()
t.join()
# Check that each created connection got different inner connection.
self.assertEqual(
- len(set([conn.connection for conn in connections_set])),
+ len(set(conn.connection for conn in connections_dict.values())),
3)
# Finish by closing the connections opened by the other threads (the
# connection opened in the main thread will automatically be closed on
# teardown).
- for conn in connections_set:
+ for conn in connections_dict.values() :
if conn is not connection:
conn.close()
@@ -609,25 +611,27 @@ class ThreadTests(TestCase):
Ensure that the connections are different for each thread.
Refs #17258.
"""
- connections_set = set()
+ # Map connections by id because connections with identical aliases
+ # have the same hash.
+ connections_dict = {}
for conn in connections.all():
- connections_set.add(conn)
+ connections_dict[id(conn)] = conn
def runner():
from django.db import connections
for conn in connections.all():
# Allow thread sharing so the connection can be closed by the
# main thread.
conn.allow_thread_sharing = True
- connections_set.add(conn)
+ connections_dict[id(conn)] = conn
for x in range(2):
t = threading.Thread(target=runner)
t.start()
t.join()
- self.assertEqual(len(connections_set), 6)
+ self.assertEqual(len(connections_dict), 6)
# Finish by closing the connections opened by the other threads (the
# connection opened in the main thread will automatically be closed on
# teardown).
- for conn in connections_set:
+ for conn in connections_dict.values():
if conn is not connection:
conn.close()