Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion django_mysqlpool/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from functools import wraps


__version__ = "0.2.1"
__version__ = "0.3.0"


def auto_close_db(f):
Expand Down
58 changes: 39 additions & 19 deletions django_mysqlpool/backends/mysqlpool/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,9 @@
from __future__ import (absolute_import, print_function, unicode_literals,
division)

# Make ``Foo()`` work the same in Python 2 as it does in Python 3.
__metaclass__ = type


import collections
import os


from django.conf import settings
from django.db.backends.mysql import base
from django.core.exceptions import ImproperlyConfigured
Expand All @@ -22,6 +18,10 @@
raise ImproperlyConfigured("Error loading SQLAlchemy module: %s" % e)


# Make ``Foo()`` work the same in Python 2 as it does in Python 3.
__metaclass__ = type


# Global variable to hold the actual connection pool.
MYSQLPOOL = None
# Default pool type (QueuePool, SingletonThreadPool, AssertionPool, NullPool,
Expand All @@ -32,15 +32,6 @@
DEFAULT_POOL_TIMEOUT = 119


def isiterable(value):
"""Determine whether ``value`` is iterable."""
try:
iter(value)
return True
except TypeError:
return False


class OldDatabaseProxy():

"""Saves a reference to the old connect function.
Expand All @@ -58,22 +49,51 @@ def connect(self, **kwargs):
return self.old_connect(**kwargs)


class HashableDict(dict):
class HashableDict(collections.OrderedDict):

"""A dictionary that is hashable.

This is not generally useful, but created specifically to hold the ``conv``
parameter that needs to be passed to MySQLdb.

HT to `Alex Martelli`_ for the idea of using a shared ``__key`` function.

.. _Alex Martelli: https://stackoverflow.com/a/1151686
"""

@staticmethod
def _is_iterable(test_me):
"""Determine whether ``test_me`` is iterable."""
try:
iter(test_me)
return True
except TypeError:
return False

@staticmethod
def _tuplefy_as_needed(val):
return tuple(val) if HashableDict._is_iterable(val) else val

def __key(self):
return tuple((k, HashableDict._tuplefy_as_needed(v))
for k, v in self.items())

def __hash__(self):
"""Calculate the hash of this ``dict``.

The hash is determined by converting to a sorted tuple of key-value
pairs and hashing that.
The hash is determined by converting to a sorted tuple of
key-value pairs and hashing that.
"""
return hash(self.__key())

def __eq__(self, other):
"""Determine whether ``other`` is equal to this ``dict``.

The implementation of this comparison uses the same underlying
mechanism as ``__hash__``, in order to guarantee that ``==`` and
``.hash`` are in sync.
"""
items = [(n, tuple(v)) for n, v in self.items() if isiterable(v)]
return hash(tuple(items))
return self.__key() == other.__key()


# Define this here so Django can import it.
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@


REQUIRES = [
"sqlalchemy >=0.7, <1.0",
"SQLAlchemy >=1.0, <2.0",
]


Expand Down