summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/orm/attributes.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2012-07-18 14:13:18 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2012-07-18 14:13:18 -0400
commitdff7c2ad2c913ed0ec5979ff9470dd5dd5813483 (patch)
tree6f1c6483f8bac9ac68820984ae9a3f8137e418b0 /lib/sqlalchemy/orm/attributes.py
parent643a9afa86328ca6038d00543700dbe0f51af5e6 (diff)
downloadsqlalchemy-dff7c2ad2c913ed0ec5979ff9470dd5dd5813483.tar.gz
- document the inspection system
Diffstat (limited to 'lib/sqlalchemy/orm/attributes.py')
-rw-r--r--lib/sqlalchemy/orm/attributes.py202
1 files changed, 108 insertions, 94 deletions
diff --git a/lib/sqlalchemy/orm/attributes.py b/lib/sqlalchemy/orm/attributes.py
index 0bf9ea438..9a1c60aa7 100644
--- a/lib/sqlalchemy/orm/attributes.py
+++ b/lib/sqlalchemy/orm/attributes.py
@@ -52,7 +52,7 @@ indicating that the attribute had not been assigned to previously.
"""
)
-NO_CHANGE = util.symbol("NO_CHANGE",
+NO_CHANGE = util.symbol("NO_CHANGE",
"""No callables or SQL should be emitted on attribute access
and no state should change""", canonical=0
)
@@ -80,29 +80,42 @@ value can be obtained.
)
NON_PERSISTENT_OK = util.symbol("NON_PERSISTENT_OK",
-"""callables can be emitted if the parent is not persistent.""",
+"""callables can be emitted if the parent is not persistent.""",
canonical=16
)
-
# pre-packaged sets of flags used as inputs
-PASSIVE_OFF = RELATED_OBJECT_OK | \
- NON_PERSISTENT_OK | \
- INIT_OK | \
- CALLABLES_OK | \
- SQL_OK
-
-PASSIVE_RETURN_NEVER_SET = PASSIVE_OFF ^ INIT_OK
-PASSIVE_NO_INITIALIZE = PASSIVE_RETURN_NEVER_SET ^ CALLABLES_OK
-PASSIVE_NO_FETCH = PASSIVE_OFF ^ SQL_OK
-PASSIVE_NO_FETCH_RELATED = PASSIVE_OFF ^ RELATED_OBJECT_OK
-PASSIVE_ONLY_PERSISTENT = PASSIVE_OFF ^ NON_PERSISTENT_OK
+PASSIVE_OFF = util.symbol("PASSIVE_OFF",
+ "Callables can be emitted in all cases.",
+ canonical=(RELATED_OBJECT_OK | NON_PERSISTENT_OK |
+ INIT_OK | CALLABLES_OK | SQL_OK)
+)
+PASSIVE_RETURN_NEVER_SET = util.symbol("PASSIVE_RETURN_NEVER_SET",
+ """PASSIVE_OFF ^ INIT_OK""",
+ canonical=PASSIVE_OFF ^ INIT_OK
+)
+PASSIVE_NO_INITIALIZE = util.symbol("PASSIVE_NO_INITIALIZE",
+ "PASSIVE_RETURN_NEVER_SET ^ CALLABLES_OK",
+ canonical=PASSIVE_RETURN_NEVER_SET ^ CALLABLES_OK
+)
+PASSIVE_NO_FETCH = util.symbol("PASSIVE_NO_FETCH",
+ "PASSIVE_OFF ^ SQL_OK",
+ canonical=PASSIVE_OFF ^ SQL_OK
+)
+PASSIVE_NO_FETCH_RELATED = util.symbol("PASSIVE_NO_FETCH_RELATED",
+ "PASSIVE_OFF ^ RELATED_OBJECT_OK",
+ canonical=PASSIVE_OFF ^ RELATED_OBJECT_OK
+)
+PASSIVE_ONLY_PERSISTENT = util.symbol("PASSIVE_ONLY_PERSISTENT",
+ "PASSIVE_OFF ^ NON_PERSISTENT_OK",
+ canonical=PASSIVE_OFF ^ NON_PERSISTENT_OK
+)
class QueryableAttribute(interfaces.PropComparator):
"""Base class for class-bound attributes. """
- def __init__(self, class_, key, impl=None,
+ def __init__(self, class_, key, impl=None,
comparator=None, parententity=None,
of_type=None):
self.class_ = class_
@@ -115,7 +128,7 @@ class QueryableAttribute(interfaces.PropComparator):
manager = manager_of_class(class_)
# manager is None in the case of AliasedClass
if manager:
- # propagate existing event listeners from
+ # propagate existing event listeners from
# immediate superclass
for base in manager._bases:
if key in base:
@@ -166,8 +179,8 @@ class QueryableAttribute(interfaces.PropComparator):
except AttributeError:
raise AttributeError(
'Neither %r object nor %r object has an attribute %r' % (
- type(self).__name__,
- type(self.comparator).__name__,
+ type(self).__name__,
+ type(self.comparator).__name__,
key)
)
@@ -187,7 +200,7 @@ class InstrumentedAttribute(QueryableAttribute):
"""Class bound instrumented attribute which adds descriptor methods."""
def __set__(self, instance, value):
- self.impl.set(instance_state(instance),
+ self.impl.set(instance_state(instance),
instance_dict(instance), value, None)
def __delete__(self, instance):
@@ -215,13 +228,13 @@ def create_proxied_attribute(descriptor):
class Proxy(QueryableAttribute):
"""Presents the :class:`.QueryableAttribute` interface as a
- proxy on top of a Python descriptor / :class:`.PropComparator`
+ proxy on top of a Python descriptor / :class:`.PropComparator`
combination.
"""
- def __init__(self, class_, key, descriptor,
- comparator,
+ def __init__(self, class_, key, descriptor,
+ comparator,
adapter=None, doc=None,
original_property=None):
self.class_ = class_
@@ -272,8 +285,8 @@ def create_proxied_attribute(descriptor):
except AttributeError:
raise AttributeError(
'Neither %r object nor %r object has an attribute %r' % (
- type(descriptor).__name__,
- type(self.comparator).__name__,
+ type(descriptor).__name__,
+ type(self.comparator).__name__,
attribute)
)
@@ -289,7 +302,7 @@ class AttributeImpl(object):
def __init__(self, class_, key,
callable_, dispatch, trackparent=False, extension=None,
- compare_function=None, active_history=False,
+ compare_function=None, active_history=False,
parent_token=None, expire_missing=True,
**kwargs):
"""Construct an AttributeImpl.
@@ -326,12 +339,12 @@ class AttributeImpl(object):
parent_token
Usually references the MapperProperty, used as a key for
the hasparent() function to identify an "owning" attribute.
- Allows multiple AttributeImpls to all match a single
+ Allows multiple AttributeImpls to all match a single
owner attribute.
expire_missing
if False, don't add an "expiry" callable to this attribute
- during state.expire_attributes(None), if no value is present
+ during state.expire_attributes(None), if no value is present
for this key.
"""
@@ -370,7 +383,7 @@ class AttributeImpl(object):
def hasparent(self, state, optimistic=False):
- """Return the boolean value of a `hasparent` flag attached to
+ """Return the boolean value of a `hasparent` flag attached to
the given state.
The `optimistic` flag determines what the default return value
@@ -414,8 +427,8 @@ class AttributeImpl(object):
"state %s along attribute '%s', "
"but the parent record "
"has gone stale, can't be sure this "
- "is the most recent parent." %
- (orm_util.state_str(state),
+ "is the most recent parent." %
+ (orm_util.state_str(state),
orm_util.state_str(parent_state),
self.key))
@@ -445,8 +458,8 @@ class AttributeImpl(object):
raise NotImplementedError()
def get_all_pending(self, state, dict_):
- """Return a list of tuples of (state, obj)
- for all objects in this attribute's current state
+ """Return a list of tuples of (state, obj)
+ for all objects in this attribute's current state
+ history.
Only applies to object-based attributes.
@@ -455,8 +468,8 @@ class AttributeImpl(object):
which roughly corresponds to:
get_state_history(
- state,
- key,
+ state,
+ key,
passive=PASSIVE_NO_INITIALIZE).sum()
"""
@@ -517,14 +530,14 @@ class AttributeImpl(object):
self.set(state, dict_, value, initiator, passive=passive)
def remove(self, state, dict_, value, initiator, passive=PASSIVE_OFF):
- self.set(state, dict_, None, initiator,
+ self.set(state, dict_, None, initiator,
passive=passive, check_old=value)
def pop(self, state, dict_, value, initiator, passive=PASSIVE_OFF):
- self.set(state, dict_, None, initiator,
+ self.set(state, dict_, None, initiator,
passive=passive, check_old=value, pop=True)
- def set(self, state, dict_, value, initiator,
+ def set(self, state, dict_, value, initiator,
passive=PASSIVE_OFF, check_old=None, pop=False):
raise NotImplementedError()
@@ -571,7 +584,7 @@ class ScalarAttributeImpl(AttributeImpl):
return History.from_scalar_attribute(
self, state, dict_.get(self.key, NO_VALUE))
- def set(self, state, dict_, value, initiator,
+ def set(self, state, dict_, value, initiator,
passive=PASSIVE_OFF, check_old=None, pop=False):
if initiator and initiator.parent_token is self.parent_token:
return
@@ -582,7 +595,7 @@ class ScalarAttributeImpl(AttributeImpl):
old = dict_.get(self.key, NO_VALUE)
if self.dispatch.set:
- value = self.fire_replace_event(state, dict_,
+ value = self.fire_replace_event(state, dict_,
value, old, initiator)
state._modified_event(dict_, self, old)
dict_[self.key] = value
@@ -604,7 +617,7 @@ class ScalarAttributeImpl(AttributeImpl):
class ScalarObjectAttributeImpl(ScalarAttributeImpl):
- """represents a scalar-holding InstrumentedAttribute,
+ """represents a scalar-holding InstrumentedAttribute,
where the target object is also instrumented.
Adds events to delete/set operations.
@@ -650,7 +663,7 @@ class ScalarObjectAttributeImpl(ScalarAttributeImpl):
else:
return []
- def set(self, state, dict_, value, initiator,
+ def set(self, state, dict_, value, initiator,
passive=PASSIVE_OFF, check_old=None, pop=False):
"""Set a value on the given InstanceState.
@@ -729,12 +742,12 @@ class CollectionAttributeImpl(AttributeImpl):
typecallable=None, trackparent=False, extension=None,
copy_function=None, compare_function=None, **kwargs):
super(CollectionAttributeImpl, self).__init__(
- class_,
- key,
+ class_,
+ key,
callable_, dispatch,
trackparent=trackparent,
extension=extension,
- compare_function=compare_function,
+ compare_function=compare_function,
**kwargs)
if copy_function is None:
@@ -762,11 +775,11 @@ class CollectionAttributeImpl(AttributeImpl):
if self.key in state.committed_state:
original = state.committed_state[self.key]
if original is not NO_VALUE:
- current_states = [((c is not None) and
- instance_state(c) or None, c)
+ current_states = [((c is not None) and
+ instance_state(c) or None, c)
for c in current]
- original_states = [((c is not None) and
- instance_state(c) or None, c)
+ original_states = [((c is not None) and
+ instance_state(c) or None, c)
for c in original]
current_set = dict(current_states)
@@ -853,13 +866,13 @@ class CollectionAttributeImpl(AttributeImpl):
def pop(self, state, dict_, value, initiator, passive=PASSIVE_OFF):
try:
# TODO: better solution here would be to add
- # a "popper" role to collections.py to complement
+ # a "popper" role to collections.py to complement
# "remover".
self.remove(state, dict_, value, initiator, passive=passive)
except (ValueError, KeyError, IndexError):
pass
- def set(self, state, dict_, value, initiator,
+ def set(self, state, dict_, value, initiator,
passive=PASSIVE_OFF, pop=False):
"""Set a value on the given object.
@@ -938,7 +951,7 @@ class CollectionAttributeImpl(AttributeImpl):
return user_data
- def get_collection(self, state, dict_,
+ def get_collection(self, state, dict_,
user_data=None, passive=PASSIVE_OFF):
"""Retrieve the CollectionAdapter associated with the given state.
@@ -967,19 +980,19 @@ def backref_listeners(attribute, key, uselist):
old_state, old_dict = instance_state(oldchild),\
instance_dict(oldchild)
impl = old_state.manager[key].impl
- impl.pop(old_state,
- old_dict,
- state.obj(),
+ impl.pop(old_state,
+ old_dict,
+ state.obj(),
initiator, passive=PASSIVE_NO_FETCH)
if child is not None:
child_state, child_dict = instance_state(child),\
instance_dict(child)
child_state.manager[key].impl.append(
- child_state,
- child_dict,
- state.obj(),
- initiator,
+ child_state,
+ child_dict,
+ state.obj(),
+ initiator,
passive=PASSIVE_NO_FETCH)
return child
@@ -987,10 +1000,10 @@ def backref_listeners(attribute, key, uselist):
child_state, child_dict = instance_state(child), \
instance_dict(child)
child_state.manager[key].impl.append(
- child_state,
- child_dict,
- state.obj(),
- initiator,
+ child_state,
+ child_dict,
+ state.obj(),
+ initiator,
passive=PASSIVE_NO_FETCH)
return child
@@ -999,29 +1012,29 @@ def backref_listeners(attribute, key, uselist):
child_state, child_dict = instance_state(child),\
instance_dict(child)
child_state.manager[key].impl.pop(
- child_state,
- child_dict,
- state.obj(),
+ child_state,
+ child_dict,
+ state.obj(),
initiator,
passive=PASSIVE_NO_FETCH)
if uselist:
- event.listen(attribute, "append",
- emit_backref_from_collection_append_event,
+ event.listen(attribute, "append",
+ emit_backref_from_collection_append_event,
retval=True, raw=True)
else:
- event.listen(attribute, "set",
- emit_backref_from_scalar_set_event,
+ event.listen(attribute, "set",
+ emit_backref_from_scalar_set_event,
retval=True, raw=True)
# TODO: need coverage in test/orm/ of remove event
- event.listen(attribute, "remove",
- emit_backref_from_collection_remove_event,
+ event.listen(attribute, "remove",
+ emit_backref_from_collection_remove_event,
retval=True, raw=True)
_NO_HISTORY = util.symbol('NO_HISTORY')
_NO_STATE_SYMBOLS = frozenset([
- id(PASSIVE_NO_RESULT),
- id(NO_VALUE),
+ id(PASSIVE_NO_RESULT),
+ id(NO_VALUE),
id(NEVER_SET)])
class History(tuple):
"""A 3-tuple of added, unchanged and deleted values,
@@ -1062,7 +1075,7 @@ class History(tuple):
return not bool(
(self.added or self.deleted)
or self.unchanged and self.unchanged != [None]
- )
+ )
def sum(self):
"""Return a collection of added + unchanged + deleted."""
@@ -1114,7 +1127,7 @@ class History(tuple):
elif attribute.is_equal(current, original) is True:
return cls((), [current], ())
else:
- # current convention on native scalars is to not
+ # current convention on native scalars is to not
# include information
# about missing previous value in "deleted", but
# we do include None, which helps in some primary
@@ -1140,11 +1153,11 @@ class History(tuple):
elif current is original:
return cls((), [current], ())
else:
- # current convention on related objects is to not
+ # current convention on related objects is to not
# include information
# about missing previous value in "deleted", and
# to also not include None - the dependency.py rules
- # ignore the None in any case.
+ # ignore the None in any case.
if id(original) in _NO_STATE_SYMBOLS or original is None:
deleted = ()
else:
@@ -1165,11 +1178,11 @@ class History(tuple):
return cls((), list(current), ())
else:
- current_states = [((c is not None) and instance_state(c) or None, c)
- for c in current
+ current_states = [((c is not None) and instance_state(c) or None, c)
+ for c in current
]
- original_states = [((c is not None) and instance_state(c) or None, c)
- for c in original
+ original_states = [((c is not None) and instance_state(c) or None, c)
+ for c in original
]
current_set = dict(current_states)
@@ -1184,7 +1197,7 @@ class History(tuple):
HISTORY_BLANK = History(None, None, None)
def get_history(obj, key, passive=PASSIVE_OFF):
- """Return a :class:`.History` record for the given object
+ """Return a :class:`.History` record for the given object
and attribute key.
:param obj: an object whose class is instrumented by the
@@ -1192,10 +1205,11 @@ def get_history(obj, key, passive=PASSIVE_OFF):
:param key: string attribute name.
- :param passive: indicates if the attribute should be
- loaded from the database if not already present (:attr:`.PASSIVE_NO_FETCH`), and
- if the attribute should be not initialized to a blank value otherwise
- (:attr:`.PASSIVE_NO_INITIALIZE`). Default is :attr:`PASSIVE_OFF`.
+ :param passive: indicates loading behavior for the attribute
+ if the value is not already present. This is a
+ bitflag attribute, which defaults to the symbol
+ :attr:`.PASSIVE_OFF` indicating all necessary SQL
+ should be emitted.
"""
if passive is True:
@@ -1223,14 +1237,14 @@ def register_attribute(class_, key, **kw):
comparator = kw.pop('comparator', None)
parententity = kw.pop('parententity', None)
doc = kw.pop('doc', None)
- desc = register_descriptor(class_, key,
+ desc = register_descriptor(class_, key,
comparator, parententity, doc=doc)
register_attribute_impl(class_, key, **kw)
return desc
def register_attribute_impl(class_, key,
- uselist=False, callable_=None,
- useobject=False,
+ uselist=False, callable_=None,
+ useobject=False,
impl_class=None, backref=None, **kw):
manager = manager_of_class(class_)
@@ -1262,7 +1276,7 @@ def register_attribute_impl(class_, key,
manager.post_configure_attribute(key)
return manager[key]
-def register_descriptor(class_, key, comparator=None,
+def register_descriptor(class_, key, comparator=None,
parententity=None, doc=None):
manager = manager_of_class(class_)
@@ -1288,10 +1302,10 @@ def init_collection(obj, key):
collection_adapter.append_without_event(elem)
For an easier way to do the above, see
- :func:`~sqlalchemy.orm.attributes.set_committed_value`.
+ :func:`~sqlalchemy.orm.attributes.set_committed_value`.
obj is an instrumented object instance. An InstanceState
- is accepted directly for backwards compatibility but
+ is accepted directly for backwards compatibility but
this usage is deprecated.
"""
@@ -1309,7 +1323,7 @@ def init_state_collection(state, dict_, key):
def set_committed_value(instance, key, value):
"""Set the value of an attribute with no history events.
- Cancels any previous history present. The value should be
+ Cancels any previous history present. The value should be
a scalar value for scalar-holding attributes, or
an iterable for any collection-holding attribute.
@@ -1366,7 +1380,7 @@ def del_attribute(instance, key):
def flag_modified(instance, key):
"""Mark an attribute on an instance as 'modified'.
- This sets the 'modified' flag on the instance and
+ This sets the 'modified' flag on the instance and
establishes an unconditional change event for the given attribute.
"""