- fixed expression translation of text() clauses; this repairs various
ORM scenarios where literal text is used for SQL expressions
-
+
- sqlite will reflect "DECIMAL" as a numeric column.
- fixed INSERT statements w.r.t. primary key columns that have SQL-expression
based default generators on them; SQL expression executes inline as normal
but will not trigger a "postfetch" condition for the column, for those DB's
who provide it via cursor.lastrowid
-
+
- Renamed the Dialect attribute 'preexecute_sequences' to
'preexecute_pk_sequences'. An attribute proxy is in place for out-of-tree
dialects using the old name.
- it's an error to session.save() an object which is already persistent
[ticket:840]
-
+
- behavior of query.options() is now fully based on paths, i.e. an option
such as eagerload_all('x.y.z.y.x') will apply eagerloading to only
those paths, i.e. and not 'x.y.x'; eagerload('children.children') applies
only to exactly two-levels deep, etc. [ticket:777]
-- Made access dao dection more reliable [ticket:828]
+- Made access dao detection more reliable [ticket:828]
+
+- Removed unused util.hash().
+
+- Fixed __hash__ for association proxy- these collections are unhashable,
+ just like their mutable Python counterparts.
0.4.0
-----
Optional, use with proxy_factory. See the _set() method for
details.
"""
-
+
self.target_collection = targetcollection # backwards compat name...
self.value_attr = attr
self.creator = creator
"scope")
return getattr(obj, target)
return lazy_collection
-
+
def __get__(self, obj, class_):
if obj is None:
self.owning_class = class_
if self.proxy_factory:
return self.proxy_factory(lazy_collection, creator, self.value_attr)
-
+
if self.getset_factory:
getter, setter = self.getset_factory(self.collection_class, self)
else:
getter, setter = self._default_getset(self.collection_class)
-
+
if self.collection_class is list:
return _AssociationList(lazy_collection, creator, getter, setter)
elif self.collection_class is dict:
lazy_collection
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:
def __getitem__(self, index):
return self._get(self.col[index])
-
+
def __setitem__(self, index, value):
if not isinstance(index, slice):
self._set(self.col[index], value)
def __repr__(self):
return repr(list(self))
- def hash(self):
+ def __hash__(self):
raise TypeError("%s objects are unhashable" % type(self).__name__)
_NotProvided = object()
lazy_collection
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:
def __getitem__(self, key):
return self._get(self.col[key])
-
+
def __setitem__(self, key, value):
if key in self.col:
self._set(self.col[key], key, value)
def popitem(self):
item = self.col.popitem()
return (item[0], self._get(item[1]))
-
+
def update(self, *a, **kw):
if len(a) > 1:
raise TypeError('update expected at most 1 arguments, got %i' %
def copy(self):
return dict(self.items())
- def hash(self):
+ def __hash__(self):
raise TypeError("%s objects are unhashable" % type(self).__name__)
class _AssociationSet(object):
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:
def issubset(self, other):
return util.Set(self).issubset(other)
-
+
def issuperset(self, other):
return util.Set(self).issuperset(other)
-
+
def clear(self):
self.col.clear()
def __repr__(self):
return repr(util.Set(self))
- def hash(self):
+ def __hash__(self):
raise TypeError("%s objects are unhashable" % type(self).__name__)
collection_class = self.collection_class
metadata = MetaData(testbase.db)
-
+
parents_table = Table('Parent', metadata,
Column('id', Integer, primary_key=True),
Column('name', String))
class Parent(object):
children = association_proxy('_children', 'name')
-
+
def __init__(self, name):
self.name = name
def _test_sequence_ops(self):
Parent, Child = self.Parent, self.Child
-
+
p1 = Parent('P1')
self.assert_(not p1._children)
self.assert_(p1._children[0].name == 'regular')
self.assert_(p1._children[1].name == 'proxied')
-
+
del p1._children[1]
self.assert_(len(p1._children) == 1)
self.assert_(len(p1._children) == 0)
self.assert_(len(p1.children) == 0)
-
+
p1.children = ['a','b','c']
self.assert_(len(p1._children) == 3)
self.assert_(len(p1.children) == 3)
p1.children.append('changed-in-place')
self.assert_(p1.children.count('changed-in-place') == 2)
-
+
p1.children.remove('changed-in-place')
self.assert_(p1.children.count('changed-in-place') == 1)
self.assert_(p1.children == after)
self.assert_([c.name for c in p1._children] == after)
-
+ self.assertRaises(TypeError, set, [p1.children])
+
+
class DefaultTest(_CollectionOperations):
def __init__(self, *args, **kw):
super(DefaultTest, self).__init__(*args, **kw)
def test_sequence_ops(self):
self._test_sequence_ops()
+
class ListTest(_CollectionOperations):
def __init__(self, *args, **kw):
super(ListTest, self).__init__(*args, **kw)
self.assert_(p1._children['a'].name == 'regular')
self.assert_(p1._children['b'].name == 'proxied')
-
+
del p1._children['b']
self.assert_(len(p1._children) == 1)
p1._children = {}
self.assert_(len(p1.children) == 0)
-
+
try:
p1._children = []
self.assert_(False)
except exceptions.ArgumentError:
self.assert_(True)
+ self.assertRaises(TypeError, set, [p1.children])
+
+
class SetTest(_CollectionOperations):
def __init__(self, *args, **kw):
super(SetTest, self).__init__(*args, **kw)
self.assert_(len(p1._children) == 0)
self.assert_(len(p1.children) == 0)
-
+
p1.children = ['a','b','c']
self.assert_(len(p1._children) == 3)
self.assert_(len(p1.children) == 3)
p1 = self.roundtrip(p1)
self.assert_(len(p1.children) == 2)
self.assert_(popped not in p1.children)
-
+
p1.children = ['a','b','c']
p1 = self.roundtrip(p1)
self.assert_(p1.children == set(['a','b','c']))
-
+
p1.children.discard('b')
p1 = self.roundtrip(p1)
self.assert_(p1.children == set(['a', 'c']))
except exceptions.ArgumentError:
self.assert_(True)
+ self.assertRaises(TypeError, set, [p1.children])
+
def test_set_comparisons(self):
Parent, Child = self.Parent, self.Child
control.issubset(other))
self.assertEqual(p1.children.issuperset(other),
control.issuperset(other))
-
+
self.assert_((p1.children == other) == (control == other))
self.assert_((p1.children != other) == (control != other))
self.assert_((p1.children < other) == (control < other))
class ScalarTest(PersistTest):
def test_scalar_proxy(self):
metadata = MetaData(testbase.db)
-
+
parents_table = Table('Parent', metadata,
Column('id', Integer, primary_key=True),
Column('name', String))
creator=lambda v: Child(bar=v))
baz = association_proxy('child', 'baz',
creator=lambda v: Child(baz=v))
-
+
def __init__(self, name):
self.name = name
id, type_ = obj.id, type(obj)
session.clear()
return session.query(type_).get(id)
-
+
p = Parent('p')
# No child
self.assert_(p.foo == 'a')
self.assert_(p.bar == 'x')
self.assert_(p.baz == 'c')
-
+
p = roundtrip(p)
self.assert_(p.foo == 'a')
# Ensure an immediate __set__ works.
p2 = Parent('p2')
p2.bar = 'quux'
-
+
class LazyLoadTest(PersistTest):
def setUp(self):
metadata = MetaData(testbase.db)
-
+
parents_table = Table('Parent', metadata,
Column('id', Integer, primary_key=True),
Column('name', String))
class Parent(object):
children = association_proxy('_children', 'name')
-
+
def __init__(self, name):
self.name = name
self.assert_('_children' in p.__dict__)
self.assert_(p._children is not None)
-
+
if __name__ == "__main__":
- testbase.main()
+ testbase.main()