summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/util
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2012-07-14 15:41:31 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2012-07-14 15:41:31 -0400
commit800efc75256283770d5c28ddd99f26f341733698 (patch)
tree195206da35d9f2d434e9bd35596038ecaab1e832 /lib/sqlalchemy/util
parent6dad6332cd0b777e4d876f51fada4fdf31299c53 (diff)
downloadsqlalchemy-800efc75256283770d5c28ddd99f26f341733698.tar.gz
- [feature] *Very limited* support for
inheriting mappers to be GC'ed when the class itself is deferenced. The mapper must not have its own table (i.e. single table inh only) without polymorphic attributes in place. This allows for the use case of creating a temporary subclass of a declarative mapped class, with no table or mapping directives of its own, to be garbage collected when dereferenced by a unit test. [ticket:2526]
Diffstat (limited to 'lib/sqlalchemy/util')
-rw-r--r--lib/sqlalchemy/util/__init__.py4
-rw-r--r--lib/sqlalchemy/util/_collections.py34
-rw-r--r--lib/sqlalchemy/util/compat.py21
3 files changed, 47 insertions, 12 deletions
diff --git a/lib/sqlalchemy/util/__init__.py b/lib/sqlalchemy/util/__init__.py
index cf61eb02a..313c6b02c 100644
--- a/lib/sqlalchemy/util/__init__.py
+++ b/lib/sqlalchemy/util/__init__.py
@@ -7,7 +7,7 @@
from compat import callable, cmp, reduce, defaultdict, py25_dict, \
threading, py3k_warning, jython, pypy, win32, set_types, buffer, pickle, \
update_wrapper, partial, md5_hex, decode_slice, dottedgetter,\
- parse_qsl, any, contextmanager, namedtuple, next
+ parse_qsl, any, contextmanager, namedtuple, next, WeakSet
from _collections import NamedTuple, ImmutableContainer, immutabledict, \
Properties, OrderedProperties, ImmutableProperties, OrderedDict, \
@@ -15,7 +15,7 @@ from _collections import NamedTuple, ImmutableContainer, immutabledict, \
column_dict, ordered_column_set, populate_column_dict, unique_list, \
UniqueAppender, PopulateDict, EMPTY_SET, to_list, to_set, \
to_column_set, update_copy, flatten_iterator, \
- LRUCache, ScopedRegistry, ThreadLocalRegistry
+ LRUCache, ScopedRegistry, ThreadLocalRegistry, WeakSequence
from langhelpers import iterate_attributes, class_hierarchy, \
portable_instancemethod, unbound_method_to_callable, \
diff --git a/lib/sqlalchemy/util/_collections.py b/lib/sqlalchemy/util/_collections.py
index d2ed091f4..801a79e9a 100644
--- a/lib/sqlalchemy/util/_collections.py
+++ b/lib/sqlalchemy/util/_collections.py
@@ -210,7 +210,7 @@ class OrderedDict(dict):
try:
self._list.append(key)
except AttributeError:
- # work around Python pickle loads() with
+ # work around Python pickle loads() with
# dict subclass (seems to ignore __setstate__?)
self._list = [key]
dict.__setitem__(self, key, object)
@@ -539,6 +539,20 @@ class IdentitySet(object):
def __repr__(self):
return '%s(%r)' % (type(self).__name__, self._members.values())
+class WeakSequence(object):
+ def __init__(self, elements):
+ self._storage = weakref.WeakValueDictionary(
+ (idx, element) for idx, element in enumerate(elements)
+ )
+
+ def __iter__(self):
+ return self._storage.itervalues()
+
+ def __getitem__(self, index):
+ try:
+ return self._storage[index]
+ except KeyError:
+ raise IndexError("Index %s out of range" % index)
class OrderedIdentitySet(IdentitySet):
class _working_set(OrderedSet):
@@ -585,7 +599,7 @@ else:
self[key] = value = self.creator(key)
return value
-# define collections that are capable of storing
+# define collections that are capable of storing
# ColumnElement objects as hashable keys/elements.
column_set = set
column_dict = dict
@@ -595,12 +609,12 @@ populate_column_dict = PopulateDict
def unique_list(seq, hashfunc=None):
seen = {}
if not hashfunc:
- return [x for x in seq
- if x not in seen
+ return [x for x in seq
+ if x not in seen
and not seen.__setitem__(x, True)]
else:
- return [x for x in seq
- if hashfunc(x) not in seen
+ return [x for x in seq
+ if hashfunc(x) not in seen
and not seen.__setitem__(hashfunc(x), True)]
class UniqueAppender(object):
@@ -716,15 +730,15 @@ class LRUCache(dict):
def _manage_size(self):
while len(self) > self.capacity + self.capacity * self.threshold:
- by_counter = sorted(dict.values(self),
+ by_counter = sorted(dict.values(self),
key=operator.itemgetter(2),
reverse=True)
for item in by_counter[self.capacity:]:
try:
del self[item[0]]
except KeyError:
- # if we couldnt find a key, most
- # likely some other thread broke in
+ # if we couldnt find a key, most
+ # likely some other thread broke in
# on us. loop around and try again
break
@@ -785,7 +799,7 @@ class ScopedRegistry(object):
pass
class ThreadLocalRegistry(ScopedRegistry):
- """A :class:`.ScopedRegistry` that uses a ``threading.local()``
+ """A :class:`.ScopedRegistry` that uses a ``threading.local()``
variable for storage.
"""
diff --git a/lib/sqlalchemy/util/compat.py b/lib/sqlalchemy/util/compat.py
index 5dc59b5c5..215a68e91 100644
--- a/lib/sqlalchemy/util/compat.py
+++ b/lib/sqlalchemy/util/compat.py
@@ -166,6 +166,27 @@ except ImportError:
return 'defaultdict(%s, %s)' % (self.default_factory,
dict.__repr__(self))
+try:
+ from weakref import WeakSet
+except:
+ import weakref
+
+ class WeakSet(object):
+ """Implement the small subset of set() which SQLAlchemy needs
+ here. """
+ def __init__(self, values=None):
+ self._storage = weakref.WeakKeyDictionary()
+ if values is not None:
+ self._storage.update((value, None) for value in values)
+
+ def __iter__(self):
+ return iter(self._storage)
+
+ def union(self, other):
+ return WeakSet(set(self).union(other))
+
+ def add(self, other):
+ self._storage[other] = True
# find or create a dict implementation that supports __missing__
class _probe(dict):