summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/util
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2015-01-05 19:02:08 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2015-01-05 19:02:08 -0500
commit1104dcaa67062f27bf7519c8589f550bd5d5b4af (patch)
tree702802bd3f0e5db235a109ba48707ea262f1782b /lib/sqlalchemy/util
parent41ae0270d99793608ce563b84e7befb3aa39252e (diff)
downloadsqlalchemy-1104dcaa67062f27bf7519c8589f550bd5d5b4af.tar.gz
- add MemoizedSlots, a generalized solution to using __getattr__
for memoization on a class that uses slots. - apply many more __slots__. mem use for nova now at 46% savings
Diffstat (limited to 'lib/sqlalchemy/util')
-rw-r--r--lib/sqlalchemy/util/__init__.py2
-rw-r--r--lib/sqlalchemy/util/_collections.py17
-rw-r--r--lib/sqlalchemy/util/langhelpers.py43
3 files changed, 58 insertions, 4 deletions
diff --git a/lib/sqlalchemy/util/__init__.py b/lib/sqlalchemy/util/__init__.py
index 7c85ef94b..c23b0196f 100644
--- a/lib/sqlalchemy/util/__init__.py
+++ b/lib/sqlalchemy/util/__init__.py
@@ -36,7 +36,7 @@ from .langhelpers import iterate_attributes, class_hierarchy, \
generic_repr, counter, PluginLoader, hybridproperty, hybridmethod, \
safe_reraise,\
get_callable_argspec, only_once, attrsetter, ellipses_string, \
- warn_limited, map_bits
+ warn_limited, map_bits, MemoizedSlots
from .deprecations import warn_deprecated, warn_pending_deprecation, \
deprecated, pending_deprecation, inject_docstring_text
diff --git a/lib/sqlalchemy/util/_collections.py b/lib/sqlalchemy/util/_collections.py
index d36852698..0f05e3427 100644
--- a/lib/sqlalchemy/util/_collections.py
+++ b/lib/sqlalchemy/util/_collections.py
@@ -179,8 +179,10 @@ class immutabledict(ImmutableContainer, dict):
class Properties(object):
"""Provide a __getattr__/__setattr__ interface over a dict."""
+ __slots__ = '_data',
+
def __init__(self, data):
- self.__dict__['_data'] = data
+ object.__setattr__(self, '_data', data)
def __len__(self):
return len(self._data)
@@ -200,8 +202,8 @@ class Properties(object):
def __delitem__(self, key):
del self._data[key]
- def __setattr__(self, key, object):
- self._data[key] = object
+ def __setattr__(self, key, obj):
+ self._data[key] = obj
def __getstate__(self):
return {'_data': self.__dict__['_data']}
@@ -252,6 +254,8 @@ class OrderedProperties(Properties):
"""Provide a __getattr__/__setattr__ interface with an OrderedDict
as backing store."""
+ __slots__ = ()
+
def __init__(self):
Properties.__init__(self, OrderedDict())
@@ -259,10 +263,17 @@ class OrderedProperties(Properties):
class ImmutableProperties(ImmutableContainer, Properties):
"""Provide immutable dict/object attribute to an underlying dictionary."""
+ __slots__ = ()
+
class OrderedDict(dict):
"""A dict that returns keys/values/items in the order they were added."""
+ __slots__ = '_list',
+
+ def __reduce__(self):
+ return OrderedDict, (self.items(),)
+
def __init__(self, ____sequence=None, **kwargs):
self._list = []
if ____sequence is None:
diff --git a/lib/sqlalchemy/util/langhelpers.py b/lib/sqlalchemy/util/langhelpers.py
index b708665f9..22b6ad4ca 100644
--- a/lib/sqlalchemy/util/langhelpers.py
+++ b/lib/sqlalchemy/util/langhelpers.py
@@ -522,6 +522,15 @@ class portable_instancemethod(object):
"""
+ __slots__ = 'target', 'name', '__weakref__'
+
+ def __getstate__(self):
+ return {'target': self.target, 'name': self.name}
+
+ def __setstate__(self, state):
+ self.target = state['target']
+ self.name = state['name']
+
def __init__(self, meth):
self.target = meth.__self__
self.name = meth.__name__
@@ -800,6 +809,40 @@ class group_expirable_memoized_property(object):
return memoized_instancemethod(fn)
+class MemoizedSlots(object):
+ """Apply memoized items to an object using a __getattr__ scheme.
+
+ This allows the functionality of memoized_property and
+ memoized_instancemethod to be available to a class using __slots__.
+
+ """
+
+ def _fallback_getattr(self, key):
+ raise AttributeError(key)
+
+ def __getattr__(self, key):
+ if key.startswith('_memoized'):
+ raise AttributeError(key)
+ elif hasattr(self, '_memoized_attr_%s' % key):
+ value = getattr(self, '_memoized_attr_%s' % key)()
+ setattr(self, key, value)
+ return value
+ elif hasattr(self, '_memoized_method_%s' % key):
+ fn = getattr(self, '_memoized_method_%s' % key)
+
+ def oneshot(*args, **kw):
+ result = fn(*args, **kw)
+ memo = lambda *a, **kw: result
+ memo.__name__ = fn.__name__
+ memo.__doc__ = fn.__doc__
+ setattr(self, key, memo)
+ return result
+ oneshot.__doc__ = fn.__doc__
+ return oneshot
+ else:
+ return self._fallback_getattr(key)
+
+
def dependency_for(modulename):
def decorate(obj):
# TODO: would be nice to improve on this import silliness,