From cfc59b17136922addfca28624ec7474147a1d03b Mon Sep 17 00:00:00 2001 From: Jason Kirtland Date: Wed, 21 May 2008 15:43:00 +0000 Subject: [PATCH] - Removed deprecated append(val, **kw) - dict/set/list proxies are now docstring'd like their python counterparts --- lib/sqlalchemy/ext/associationproxy.py | 239 ++++++++++++++----------- 1 file changed, 132 insertions(+), 107 deletions(-) diff --git a/lib/sqlalchemy/ext/associationproxy.py b/lib/sqlalchemy/ext/associationproxy.py index 4d54f6072d..89db1323c6 100644 --- a/lib/sqlalchemy/ext/associationproxy.py +++ b/lib/sqlalchemy/ext/associationproxy.py @@ -4,8 +4,8 @@ The ``AssociationProxy`` is a Python property object which provides transparent proxied access to the endpoint of an association object. See the example ``examples/association/proxied_association.py``. -""" +""" import itertools import weakref from sqlalchemy import exceptions @@ -14,31 +14,32 @@ from sqlalchemy import util from sqlalchemy.orm import collections -def association_proxy(targetcollection, attr, **kw): - """Convenience function for use in mapped classes. Implements a Python - property representing a relation as a collection of simpler values. The - proxied property will mimic the collection type of the target (list, dict - or set), or in the case of a one to one relation, a simple scalar value. +def association_proxy(target_collection, attr, **kw): + """Convenience function for use in mapped classes. - targetcollection + Implements a Python property representing a relation as a collection of + simpler values. The proxied property will mimic the collection type of + the target (list, dict or set), or, in the case of a one to one relation, + a simple scalar value. + + target_collection Name of the relation attribute we'll proxy to, usually created with 'relation()' in a mapper setup. attr Attribute on the associated 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)] + property would look like [getattr(obj1, attr), getattr(obj2, attr)] If the relation is one-to-one or otherwise uselist=False, then simply: getattr(obj, attr) 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. + 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. @@ -47,69 +48,68 @@ def association_proxy(targetcollection, attr, **kw): If the target is present, set operations are proxied to setattr() on the associated object. - If you have an associated object with multiple attributes, you may set up - multiple association proxies mapping to different attributes. See the - unit tests for examples, and for examples of how creator() functions can - be used to construct the scalar relation on-demand in this situation. + If you have an associated object with multiple attributes, you may set + up multiple association proxies mapping to different attributes. See + the unit tests for examples, and for examples of how creator() functions + can be used to construct the scalar relation on-demand in this + situation. Passes along any other arguments to AssociationProxy - """ - return AssociationProxy(targetcollection, attr, **kw) + """ + return AssociationProxy(target_collection, attr, **kw) class AssociationProxy(object): - """A property object that automatically sets up `AssociationLists` - on an object.""" + """A descriptor that presents a read/write view of an object attribute.""" - def __init__(self, targetcollection, attr, creator=None, + def __init__(self, target_collection, attr, creator=None, getset_factory=None, proxy_factory=None, proxy_bulk_set=None): """Arguments are: - targetcollection - Name of the collection we'll proxy to, usually created with - 'relation()' in a mapper setup. - - 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)] - - 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. - - 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. - - 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 relations. - - proxy_bulk_set - Optional, use with proxy_factory. See the _set() method for - details. - """ + target_collection + Name of the collection we'll proxy to, usually created with + 'relation()' in a mapper setup. + + 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)] - self.target_collection = targetcollection # backwards compat name... + 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. + + 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. + + 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 relations. + + proxy_bulk_set + Optional, use with proxy_factory. See the _set() method for + details. + + """ + self.target_collection = target_collection self.value_attr = attr self.creator = creator self.getset_factory = getset_factory @@ -118,12 +118,13 @@ class AssociationProxy(object): self.scalar = None self.owning_class = None - self.key = '_%s_%s_%s' % (type(self).__name__, - targetcollection, id(self)) + self.key = '_%s_%s_%s' % ( + type(self).__name__, target_collection, id(self)) self.collection_class = None def _get_property(self): - return orm.class_mapper(self.owning_class).get_property(self.target_collection) + return (orm.class_mapper(self.owning_class). + get_property(self.target_collection)) def _target_class(self): return self._get_property().mapper.class_ @@ -250,20 +251,21 @@ class AssociationProxy(object): 'no proxy_bulk_set supplied for custom ' 'collection_class implementation') + class _AssociationList(object): - """Generic proxying list which proxies list operations to a another list, - converting association objects to and from a simplified value. - """ + """Generic, converting, list-to-list proxy.""" def __init__(self, lazy_collection, creator, getter, setter): - """ + """Constructs an _AssociationList. + lazy_collection - A callable returning a list-based collection of entities (usually - an object attribute managed by a SQLAlchemy relation()) + A callable returning a list-based collection of entities (usually an + object attribute managed by a SQLAlchemy relation()) creator A function that creates new target entities. Given one parameter: - value. The assertion is assumed: + value. This assertion is assumed:: + obj = creator(somevalue) assert getter(obj) == somevalue @@ -271,10 +273,10 @@ class _AssociationList(object): A function. Given an associated object, return the 'value'. setter - A function. Given an associated object and a value, store - that value on the object. - """ + A function. Given an associated object and a value, store that + value on the object. + """ self.lazy_collection = lazy_collection self.creator = creator self.getter = getter @@ -282,10 +284,8 @@ class _AssociationList(object): col = property(lambda self: self.lazy_collection()) - # For compatibility with 0.3.1 through 0.3.7- pass kw through to creator. - # (see append() below) - def _create(self, value, **kw): - return self.creator(value, **kw) + def _create(self, value): + return self.creator(value) def _get(self, object): return self.getter(object) @@ -366,10 +366,8 @@ class _AssociationList(object): yield self._get(member) raise StopIteration - # For compatibility with 0.3.1 through 0.3.7- pass kw through to creator - # on append() only. (Can't on __setitem__, __contains__, etc., obviously.) - def append(self, value, **kw): - item = self._create(value, **kw) + def append(self, value): + item = self._create(value) self.col.append(item) def count(self, value): @@ -473,32 +471,39 @@ class _AssociationList(object): def __hash__(self): raise TypeError("%s objects are unhashable" % type(self).__name__) + for func_name, func in locals().items(): + if (callable(func) and func.func_name == func_name and + not func.__doc__ and hasattr(list, func_name)): + func.__doc__ = getattr(list, func_name).__doc__ + + _NotProvided = util.symbol('_NotProvided') class _AssociationDict(object): - """Generic proxying list which proxies dict operations to a another dict, - converting association objects to and from a simplified value. - """ + """Generic, converting, dict-to-dict proxy.""" def __init__(self, lazy_collection, creator, getter, setter): - """ + """Constructs an _AssociationDict. + lazy_collection - A callable returning a dict-based collection of entities (usually - an object attribute managed by a SQLAlchemy relation()) + A callable returning a dict-based collection of entities (usually an + object attribute managed by a SQLAlchemy relation()) creator A function that creates new target entities. Given two parameters: - key and value. The assertion is assumed: + key and value. The assertion is assumed:: + obj = creator(somekey, somevalue) assert getter(somekey) == somevalue getter - A function. Given an associated object and a key, return the 'value'. + A function. Given an associated object and a key, return the + 'value'. setter A function. Given an associated object, a key and a value, store that value on the object. - """ + """ self.lazy_collection = lazy_collection self.creator = creator self.getter = getter @@ -539,7 +544,10 @@ class _AssociationDict(object): def __contains__(self, key): # testlib.pragma exempt:__hash__ return key in self.col - has_key = __contains__ + + def has_key(self, key): + # testlib.pragma exempt:__hash__ + return key in self.col def __iter__(self): return self.col.iterkeys() @@ -586,11 +594,13 @@ class _AssociationDict(object): def keys(self): return self.col.keys() + def iterkeys(self): return self.col.iterkeys() def values(self): return [ self._get(member) for member in self.col.values() ] + def itervalues(self): for key in self.col: yield self._get(self.col[key]) @@ -598,6 +608,7 @@ class _AssociationDict(object): def items(self): return [(k, self._get(self.col[k])) for k in self] + def iteritems(self): for key in self.col: yield (key, self._get(self.col[key])) @@ -635,20 +646,26 @@ class _AssociationDict(object): def __hash__(self): raise TypeError("%s objects are unhashable" % type(self).__name__) + for func_name, func in locals().items(): + if (callable(func) and func.func_name == func_name and + not func.__doc__ and hasattr(dict, func_name)): + func.__doc__ = getattr(dict, func_name).__doc__ + + class _AssociationSet(object): - """Generic proxying list which proxies set operations to a another set, - converting association objects to and from a simplified value. - """ + """Generic, converting, set-to-set proxy.""" def __init__(self, lazy_collection, creator, getter, setter): - """ + """Constructs an _AssociationSet. + collection A callable returning a set-based collection of entities (usually an object attribute managed by a SQLAlchemy relation()) creator A function that creates new target entities. Given one parameter: - value. The assertion is assumed: + value. The assertion is assumed:: + obj = creator(somevalue) assert getter(obj) == somevalue @@ -656,10 +673,10 @@ class _AssociationSet(object): A function. Given an associated object, return the 'value'. setter - A function. Given an associated object and a value, store - that value on the object. - """ + A function. Given an associated object and a value, store that + value on the object. + """ self.lazy_collection = lazy_collection self.creator = creator self.getter = getter @@ -693,9 +710,12 @@ class _AssociationSet(object): return False def __iter__(self): - """Iterate over proxied values. For the actual domain objects, - iterate over .col instead or just use the underlying collection - directly from its property on the parent.""" + """Iterate over proxied values. + + For the actual domain objects, iterate over .col instead or just use + the underlying collection directly from its property on the parent. + + """ for member in self.col: yield self._get(member) raise StopIteration @@ -851,3 +871,8 @@ class _AssociationSet(object): def __hash__(self): raise TypeError("%s objects are unhashable" % type(self).__name__) + + for func_name, func in locals().items(): + if (callable(func) and func.func_name == func_name and + not func.__doc__ and hasattr(util.Set, func_name)): + func.__doc__ = getattr(util.Set, func_name).__doc__ -- 2.47.3