diff options
Diffstat (limited to 'lib/sqlalchemy/ext/associationproxy.py')
-rw-r--r-- | lib/sqlalchemy/ext/associationproxy.py | 83 |
1 files changed, 48 insertions, 35 deletions
diff --git a/lib/sqlalchemy/ext/associationproxy.py b/lib/sqlalchemy/ext/associationproxy.py index 27c76eb6b..f6c0764e4 100644 --- a/lib/sqlalchemy/ext/associationproxy.py +++ b/lib/sqlalchemy/ext/associationproxy.py @@ -27,24 +27,25 @@ def association_proxy(target_collection, attr, **kw): The returned value is an instance of :class:`.AssociationProxy`. - Implements a Python property representing a relationship as a collection of - simpler values, or a scalar value. The proxied property will mimic the collection type of - the target (list, dict or set), or, in the case of a one to one relationship, - a simple scalar value. + Implements a Python property representing a relationship as a collection + of simpler values, or a scalar value. The proxied property will mimic + the collection type of the target (list, dict or set), or, in the case of + a one to one relationship, a simple scalar value. :param target_collection: Name of the attribute we'll proxy to. This attribute is typically mapped by :func:`~sqlalchemy.orm.relationship` to link to a target collection, but can also be a many-to-one or non-scalar relationship. - :param attr: Attribute on the associated instance or instances we'll proxy for. + :param attr: Attribute on the associated instance or instances we'll + proxy for. For example, given a target collection of [obj1, obj2], a list created by this proxy property would look like [getattr(obj1, *attr*), getattr(obj2, *attr*)] - If the relationship is one-to-one or otherwise uselist=False, then simply: - getattr(obj, *attr*) + If the relationship is one-to-one or otherwise uselist=False, then + simply: getattr(obj, *attr*) :param creator: optional. @@ -89,34 +90,36 @@ class AssociationProxy(object): :param target_collection: Name of the collection we'll proxy to, usually created with :func:`.relationship`. - :param attr: Attribute on the collected instances we'll proxy for. For example, - given a target collection of [obj1, obj2], a list created by this - proxy property would look like [getattr(obj1, attr), getattr(obj2, - attr)] + :param attr: Attribute on the collected instances we'll proxy + for. For example, given a target collection of [obj1, obj2], a + list created by this proxy property would look like + [getattr(obj1, attr), getattr(obj2, attr)] - :param creator: Optional. When new items are added to this proxied collection, new - instances of the class collected by the target collection will be - created. For list and set collections, the target class constructor - will be called with the 'value' for the new instance. For dict - types, two arguments are passed: key and value. + :param creator: Optional. When new items are added to this proxied + collection, new instances of the class collected by the target + collection will be created. For list and set collections, the + target class constructor will be called with the 'value' for the + new instance. For dict types, two arguments are passed: + key and value. If you want to construct instances differently, supply a 'creator' function that takes arguments as above and returns instances. - :param getset_factory: Optional. Proxied attribute access is automatically handled by - routines that get and set values based on the `attr` argument for - this proxy. + :param getset_factory: Optional. Proxied attribute access is + automatically handled by routines that get and set values based on + the `attr` argument for this proxy. If you would like to customize this behavior, you may supply a `getset_factory` callable that produces a tuple of `getter` and `setter` functions. The factory is called with two arguments, the abstract type of the underlying collection and this proxy instance. - :param proxy_factory: Optional. The type of collection to emulate is determined by - sniffing the target collection. If your collection type can't be - determined by duck typing or you'd like to use a different - collection implementation, you may supply a factory function to - produce those collections. Only applicable to non-scalar relationships. + :param proxy_factory: Optional. The type of collection to emulate is + determined by sniffing the target collection. If your collection + type can't be determined by duck typing or you'd like to use a + different collection implementation, you may supply a factory + function to produce those collections. Only applicable to + non-scalar relationships. :param proxy_bulk_set: Optional, use with proxy_factory. See the _set() method for details. @@ -279,7 +282,8 @@ class AssociationProxy(object): self.collection_class = util.duck_type_collection(lazy_collection()) if self.proxy_factory: - return self.proxy_factory(lazy_collection, creator, self.value_attr, self) + return self.proxy_factory( + lazy_collection, creator, self.value_attr, self) if self.getset_factory: getter, setter = self.getset_factory(self.collection_class, self) @@ -287,11 +291,14 @@ class AssociationProxy(object): getter, setter = self._default_getset(self.collection_class) if self.collection_class is list: - return _AssociationList(lazy_collection, creator, getter, setter, self) + return _AssociationList( + lazy_collection, creator, getter, setter, self) elif self.collection_class is dict: - return _AssociationDict(lazy_collection, creator, getter, setter, self) + return _AssociationDict( + lazy_collection, creator, getter, setter, self) elif self.collection_class is set: - return _AssociationSet(lazy_collection, creator, getter, setter, self) + return _AssociationSet( + lazy_collection, creator, getter, setter, self) else: raise exc.ArgumentError( 'could not guess which interface to use for ' @@ -340,9 +347,11 @@ class AssociationProxy(object): """ if self._value_is_scalar: - value_expr = getattr(self.target_class, self.value_attr).has(criterion, **kwargs) + value_expr = getattr( + self.target_class, self.value_attr).has(criterion, **kwargs) else: - value_expr = getattr(self.target_class, self.value_attr).any(criterion, **kwargs) + value_expr = getattr( + self.target_class, self.value_attr).any(criterion, **kwargs) # check _value_is_scalar here, otherwise # we're scalar->scalar - call .any() so that @@ -409,12 +418,13 @@ class _lazy_collection(object): return getattr(obj, self.target) def __getstate__(self): - return {'obj':self.ref(), 'target':self.target} + return {'obj': self.ref(), 'target': self.target} def __setstate__(self, state): self.ref = weakref.ref(state['obj']) self.target = state['target'] + class _AssociationCollection(object): def __init__(self, lazy_collection, creator, getter, setter, parent): """Constructs an _AssociationCollection. @@ -456,13 +466,14 @@ class _AssociationCollection(object): return bool(self.col) def __getstate__(self): - return {'parent':self.parent, 'lazy_collection':self.lazy_collection} + return {'parent': self.parent, 'lazy_collection': self.lazy_collection} def __setstate__(self, state): self.parent = state['parent'] self.lazy_collection = state['lazy_collection'] self.parent._inflate(self) + class _AssociationList(_AssociationCollection): """Generic, converting, list-to-list proxy.""" @@ -652,6 +663,8 @@ class _AssociationList(_AssociationCollection): _NotProvided = util.symbol('_NotProvided') + + class _AssociationDict(_AssociationCollection): """Generic, converting, dict-to-dict proxy.""" @@ -734,7 +747,7 @@ class _AssociationDict(_AssociationCollection): return self.col.iterkeys() def values(self): - return [ self._get(member) for member in self.col.values() ] + return [self._get(member) for member in self.col.values()] def itervalues(self): for key in self.col: @@ -766,8 +779,8 @@ class _AssociationDict(_AssociationCollection): len(a)) elif len(a) == 1: seq_or_map = a[0] - # discern dict from sequence - took the advice - # from http://www.voidspace.org.uk/python/articles/duck_typing.shtml + # discern dict from sequence - took the advice from + # http://www.voidspace.org.uk/python/articles/duck_typing.shtml # still not perfect :( if hasattr(seq_or_map, 'keys'): for item in seq_or_map: |