diff options
author | Diana Clarke <diana.joan.clarke@gmail.com> | 2012-11-19 14:16:39 -0500 |
---|---|---|
committer | Diana Clarke <diana.joan.clarke@gmail.com> | 2012-11-19 14:16:39 -0500 |
commit | 03687b36b78be86c0f2a01eeb658c5b52fbd6c76 (patch) | |
tree | 9b8ccc3fed989ef64d41a53d091e2309836a9992 /lib/sqlalchemy/ext/mutable.py | |
parent | ef326d9fe39ab493dd4aeaf2cecf9052a04d49b7 (diff) | |
download | sqlalchemy-03687b36b78be86c0f2a01eeb658c5b52fbd6c76.tar.gz |
just a pep8 pass of lib/sqlalchemy/ext
Diffstat (limited to 'lib/sqlalchemy/ext/mutable.py')
-rw-r--r-- | lib/sqlalchemy/ext/mutable.py | 101 |
1 files changed, 58 insertions, 43 deletions
diff --git a/lib/sqlalchemy/ext/mutable.py b/lib/sqlalchemy/ext/mutable.py index db05a82b4..36d60d6d5 100644 --- a/lib/sqlalchemy/ext/mutable.py +++ b/lib/sqlalchemy/ext/mutable.py @@ -7,13 +7,13 @@ """Provide support for tracking of in-place changes to scalar values, which are propagated into ORM change events on owning parent objects. -The :mod:`sqlalchemy.ext.mutable` extension replaces SQLAlchemy's legacy approach to in-place -mutations of scalar values, established by the :class:`.types.MutableType` -class as well as the ``mutable=True`` type flag, with a system that allows -change events to be propagated from the value to the owning parent, thereby -removing the need for the ORM to maintain copies of values as well as the very -expensive requirement of scanning through all "mutable" values on each flush -call, looking for changes. +The :mod:`sqlalchemy.ext.mutable` extension replaces SQLAlchemy's legacy +approach to in-place mutations of scalar values, established by the +:class:`.types.MutableType` class as well as the ``mutable=True`` type flag, +with a system that allows change events to be propagated from the value to +the owning parent, thereby removing the need for the ORM to maintain copies +of values as well as the very expensive requirement of scanning through all +"mutable" values on each flush call, looking for changes. .. _mutable_scalars: @@ -43,8 +43,8 @@ JSON strings before being persisted:: value = json.loads(value) return value -The usage of ``json`` is only for the purposes of example. The :mod:`sqlalchemy.ext.mutable` -extension can be used +The usage of ``json`` is only for the purposes of example. The +:mod:`sqlalchemy.ext.mutable` extension can be used with any type whose target Python type may be mutable, including :class:`.PickleType`, :class:`.postgresql.ARRAY`, etc. @@ -86,19 +86,19 @@ The above dictionary class takes the approach of subclassing the Python built-in ``dict`` to produce a dict subclass which routes all mutation events through ``__setitem__``. There are variants on this approach, such as subclassing ``UserDict.UserDict`` or -``collections.MutableMapping``; the part that's important to this -example is that the :meth:`.Mutable.changed` method is called whenever an in-place change to the -datastructure takes place. +``collections.MutableMapping``; the part that's important to this example is +that the :meth:`.Mutable.changed` method is called whenever an in-place +change to the datastructure takes place. We also redefine the :meth:`.Mutable.coerce` method which will be used to convert any values that are not instances of ``MutableDict``, such as the plain dictionaries returned by the ``json`` module, into the -appropriate type. Defining this method is optional; we could just as well created our -``JSONEncodedDict`` such that it always returns an instance of ``MutableDict``, -and additionally ensured that all calling code uses ``MutableDict`` -explicitly. When :meth:`.Mutable.coerce` is not overridden, any values -applied to a parent object which are not instances of the mutable type -will raise a ``ValueError``. +appropriate type. Defining this method is optional; we could just as well +created our ``JSONEncodedDict`` such that it always returns an instance +of ``MutableDict``, and additionally ensured that all calling code +uses ``MutableDict`` explicitly. When :meth:`.Mutable.coerce` is not +overridden, any values applied to a parent object which are not instances +of the mutable type will raise a ``ValueError``. Our new ``MutableDict`` type offers a class method :meth:`~.Mutable.as_mutable` which we can use within column metadata @@ -156,9 +156,10 @@ will flag the attribute as "dirty" on the parent object:: True The ``MutableDict`` can be associated with all future instances -of ``JSONEncodedDict`` in one step, using :meth:`~.Mutable.associate_with`. This -is similar to :meth:`~.Mutable.as_mutable` except it will intercept -all occurrences of ``MutableDict`` in all mappings unconditionally, without +of ``JSONEncodedDict`` in one step, using +:meth:`~.Mutable.associate_with`. This is similar to +:meth:`~.Mutable.as_mutable` except it will intercept all occurrences +of ``MutableDict`` in all mappings unconditionally, without the need to declare it individually:: MutableDict.associate_with(JSONEncodedDict) @@ -330,11 +331,14 @@ from ..orm.attributes import flag_modified from .. import event, types from ..orm import mapper, object_mapper from ..util import memoized_property -from .. import exc import weakref + class MutableBase(object): - """Common base class to :class:`.Mutable` and :class:`.MutableComposite`.""" + """Common base class to :class:`.Mutable` + and :class:`.MutableComposite`. + + """ @memoized_property def _parents(self): @@ -356,7 +360,8 @@ class MutableBase(object): """ if value is None: return None - raise ValueError("Attribute '%s' does not accept objects of type %s" % (key, type(value))) + msg = "Attribute '%s' does not accept objects of type %s" + raise ValueError(msg % (key, type(value))) @classmethod def _listen_on_attribute(cls, attribute, coerce, parent_cls): @@ -414,12 +419,17 @@ class MutableBase(object): for val in state_dict['ext.mutable.values']: val._parents[state.obj()] = key + event.listen(parent_cls, 'load', load, + raw=True, propagate=True) + event.listen(parent_cls, 'refresh', load, + raw=True, propagate=True) + event.listen(attribute, 'set', set, + raw=True, retval=True, propagate=True) + event.listen(parent_cls, 'pickle', pickle, + raw=True, propagate=True) + event.listen(parent_cls, 'unpickle', unpickle, + raw=True, propagate=True) - event.listen(parent_cls, 'load', load, raw=True, propagate=True) - event.listen(parent_cls, 'refresh', load, raw=True, propagate=True) - event.listen(attribute, 'set', set, raw=True, retval=True, propagate=True) - event.listen(parent_cls, 'pickle', pickle, raw=True, propagate=True) - event.listen(parent_cls, 'unpickle', unpickle, raw=True, propagate=True) class Mutable(MutableBase): """Mixin that defines transparent propagation of change @@ -448,15 +458,16 @@ class Mutable(MutableBase): """Associate this wrapper with all future mapped columns of the given type. - This is a convenience method that calls ``associate_with_attribute`` automatically. + This is a convenience method that calls + ``associate_with_attribute`` automatically. .. warning:: The listeners established by this method are *global* to all mappers, and are *not* garbage collected. Only use - :meth:`.associate_with` for types that are permanent to an application, - not with ad-hoc types else this will cause unbounded growth - in memory usage. + :meth:`.associate_with` for types that are permanent to an + application, not with ad-hoc types else this will cause unbounded + growth in memory usage. """ @@ -483,8 +494,8 @@ class Mutable(MutableBase): ) Note that the returned type is always an instance, even if a class - is given, and that only columns which are declared specifically with that - type instance receive additional instrumentation. + is given, and that only columns which are declared specifically with + that type instance receive additional instrumentation. To associate a particular mutable type with all occurrences of a particular type, use the :meth:`.Mutable.associate_with` classmethod @@ -511,11 +522,13 @@ class Mutable(MutableBase): return sqltype + class _MutableCompositeMeta(type): def __init__(cls, classname, bases, dict_): cls._setup_listeners() return type.__init__(cls, classname, bases, dict_) + class MutableComposite(MutableBase): """Mixin that defines transparent propagation of change events on a SQLAlchemy "composite" object to its @@ -526,10 +539,10 @@ class MutableComposite(MutableBase): .. warning:: The listeners established by the :class:`.MutableComposite` - class are *global* to all mappers, and are *not* garbage collected. Only use - :class:`.MutableComposite` for types that are permanent to an application, - not with ad-hoc types else this will cause unbounded growth - in memory usage. + class are *global* to all mappers, and are *not* garbage + collected. Only use :class:`.MutableComposite` for types that are + permanent to an application, not with ad-hoc types else this will + cause unbounded growth in memory usage. """ __metaclass__ = _MutableCompositeMeta @@ -550,19 +563,21 @@ class MutableComposite(MutableBase): """Associate this wrapper with all future mapped composites of the given type. - This is a convenience method that calls ``associate_with_attribute`` automatically. + This is a convenience method that calls ``associate_with_attribute`` + automatically. """ def listen_for_type(mapper, class_): for prop in mapper.iterate_properties: - if hasattr(prop, 'composite_class') and issubclass(prop.composite_class, cls): - cls._listen_on_attribute(getattr(class_, prop.key), False, class_) + if (hasattr(prop, 'composite_class') and + issubclass(prop.composite_class, cls)): + cls._listen_on_attribute( + getattr(class_, prop.key), False, class_) event.listen(mapper, 'mapper_configured', listen_for_type) - class MutableDict(Mutable, dict): """A dictionary type that implements :class:`.Mutable`. |