summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy')
-rw-r--r--lib/sqlalchemy/attributes.py30
-rw-r--r--lib/sqlalchemy/orm/dependency.py20
-rw-r--r--lib/sqlalchemy/orm/properties.py3
-rw-r--r--lib/sqlalchemy/orm/unitofwork.py5
4 files changed, 33 insertions, 25 deletions
diff --git a/lib/sqlalchemy/attributes.py b/lib/sqlalchemy/attributes.py
index 2bf336398..5e2226e9d 100644
--- a/lib/sqlalchemy/attributes.py
+++ b/lib/sqlalchemy/attributes.py
@@ -10,6 +10,9 @@ import weakref
class InstrumentedAttribute(object):
"""a property object that instruments attribute access on object instances. All methods correspond to
a single attribute on a particular class."""
+
+ PASSIVE_NORESULT = object()
+
def __init__(self, manager, key, uselist, callable_, typecallable, trackparent=False, extension=None, **kwargs):
self.manager = manager
self.key = key
@@ -40,9 +43,16 @@ class InstrumentedAttribute(object):
item._state[('hasparent', self)] = value
def get_history(self, obj, passive=False):
- """returns a new AttributeHistory object for the given object for this
- InstrumentedAttribute's attribute."""
- return AttributeHistory(self, obj, passive=passive)
+ """return a new AttributeHistory object for the given object/this attribute's key.
+
+ if passive is True, then dont execute any callables; if the attribute's value
+ can only be achieved via executing a callable, then return None."""
+ # get the current state. this may trigger a lazy load if
+ # passive is False.
+ current = self.get(obj, passive=passive, raiseerr=False)
+ if current is InstrumentedAttribute.PASSIVE_NORESULT:
+ return None
+ return AttributeHistory(self, obj, current, passive=passive)
def set_callable(self, obj, callable_):
"""sets a callable function on the given object which will be executed when this attribute
@@ -123,7 +133,7 @@ class InstrumentedAttribute(object):
callable_ = self._get_callable(obj)
if callable_ is not None:
if passive:
- return None
+ return InstrumentedAttribute.PASSIVE_NORESULT
l = InstrumentedList(self, obj, self._adapt_list(callable_()), init=False)
# if a callable was executed, then its part of the "committed state"
# if any, so commit the newly loaded data
@@ -141,7 +151,7 @@ class InstrumentedAttribute(object):
callable_ = self._get_callable(obj)
if callable_ is not None:
if passive:
- return None
+ return InstrumentedAttribute.PASSIVE_NORESULT
obj.__dict__[self.key] = callable_()
# if a callable was executed, then its part of the "committed state"
# if any, so commit the newly loaded data
@@ -473,12 +483,9 @@ class CommittedState(object):
class AttributeHistory(object):
"""calculates the "history" of a particular attribute on a particular instance, based on the CommittedState
associated with the instance, if any."""
- def __init__(self, attr, obj, passive=False):
+ def __init__(self, attr, obj, current, passive=False):
self.attr = attr
- # get the current state. this may trigger a lazy load if
- # passive is False.
- current = attr.get(obj, passive=passive, raiseerr=False)
-
+
# get the "original" value. if a lazy load was fired when we got
# the 'current' value, this "original" was also populated just
# now as well (therefore we have to get it second)
@@ -492,7 +499,6 @@ class AttributeHistory(object):
self._current = current
else:
self._current = [current]
-
if attr.uselist:
s = util.Set(original or [])
self._added_items = []
@@ -592,7 +598,7 @@ class AttributeManager(object):
"""
attr = getattr(obj.__class__, key)
x = attr.get(obj, passive=passive)
- if x is None:
+ if x is InstrumentedAttribute.PASSIVE_NORESULT:
return []
elif attr.uselist:
return x
diff --git a/lib/sqlalchemy/orm/dependency.py b/lib/sqlalchemy/orm/dependency.py
index 6eca75ae1..8970dab50 100644
--- a/lib/sqlalchemy/orm/dependency.py
+++ b/lib/sqlalchemy/orm/dependency.py
@@ -118,9 +118,9 @@ class OneToManyDP(DependencyProcessor):
self._synchronize(obj, child, None, False)
if child is not None and self.post_update:
uowcommit.register_object(child, postupdate=True)
- for child in childlist.deleted_items():
- if not self.cascade.delete_orphan:
- self._synchronize(obj, child, None, True)
+ for child in childlist.deleted_items():
+ if not self.cascade.delete_orphan:
+ self._synchronize(obj, child, None, True)
def preprocess_dependencies(self, task, deplist, uowcommit, delete = False):
#print self.mapper.mapped_table.name + " " + self.key + " " + repr(len(deplist)) + " preprocess_dep isdelete " + repr(delete) + " direction " + repr(self.direction)
@@ -161,13 +161,13 @@ class OneToManyDP(DependencyProcessor):
for child in childlist.added_items():
if child is not None:
uowcommit.register_object(child)
- for child in childlist.deleted_items():
- if not self.cascade.delete_orphan:
- uowcommit.register_object(child, isdelete=False)
- elif childlist.hasparent(child) is False:
- uowcommit.register_object(child, isdelete=True)
- for c in self.mapper.cascade_iterator('delete', child):
- uowcommit.register_object(c, isdelete=True)
+ for child in childlist.deleted_items():
+ if not self.cascade.delete_orphan:
+ uowcommit.register_object(child, isdelete=False)
+ elif childlist.hasparent(child) is False:
+ uowcommit.register_object(child, isdelete=True)
+ for c in self.mapper.cascade_iterator('delete', child):
+ uowcommit.register_object(c, isdelete=True)
def _synchronize(self, obj, child, associationrow, clearkeys):
source = obj
diff --git a/lib/sqlalchemy/orm/properties.py b/lib/sqlalchemy/orm/properties.py
index f0ec8f556..705d53363 100644
--- a/lib/sqlalchemy/orm/properties.py
+++ b/lib/sqlalchemy/orm/properties.py
@@ -157,7 +157,8 @@ class PropertyLoader(mapper.MapperProperty):
if not type in self.cascade:
return
childlist = sessionlib.attribute_manager.get_history(object, self.key, passive=True)
-
+ if childlist is None:
+ return
mapper = self.mapper.primary_mapper()
for c in childlist.added_items() + childlist.deleted_items() + childlist.unchanged_items():
if c is not None and c not in recursive:
diff --git a/lib/sqlalchemy/orm/unitofwork.py b/lib/sqlalchemy/orm/unitofwork.py
index e243b3b31..92cf825d5 100644
--- a/lib/sqlalchemy/orm/unitofwork.py
+++ b/lib/sqlalchemy/orm/unitofwork.py
@@ -803,8 +803,9 @@ class UOWTask(object):
isdelete = taskelement.isdelete
# list of dependent objects from this object
- childlist = dep.get_object_dependencies(obj, trans, passive = True)
-
+ childlist = dep.get_object_dependencies(obj, trans, passive=True)
+ if childlist is None:
+ continue
# the task corresponding to saving/deleting of those dependent objects
childtask = trans.get_task_by_mapper(processor.mapper.primary_mapper())