summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2012-04-23 18:59:17 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2012-04-23 18:59:17 -0400
commit841ea194bd7cf239323ee21320210fd6dc5c551d (patch)
tree0da6b6ae37d5def93b84e06afd451f50716c6caf /lib
parent101da94e1282a410557784272bda58222ac048b4 (diff)
downloadsqlalchemy-841ea194bd7cf239323ee21320210fd6dc5c551d.tar.gz
- [removed] The legacy "mutable" system of the
ORM, including the MutableType class as well as the mutable=True flag on PickleType and postgresql.ARRAY has been removed. In-place mutations are detected by the ORM using the sqlalchemy.ext.mutable extension, introduced in 0.7. The removal of MutableType and associated constructs removes a great deal of complexity from SQLAlchemy's internals. The approach performed poorly as it would incur a scan of the full contents of the Session when in use. [ticket:2442]
Diffstat (limited to 'lib')
-rw-r--r--lib/sqlalchemy/dialects/postgresql/base.py37
-rw-r--r--lib/sqlalchemy/orm/attributes.py59
-rw-r--r--lib/sqlalchemy/orm/identity.py15
-rw-r--r--lib/sqlalchemy/orm/instrumentation.py8
-rw-r--r--lib/sqlalchemy/orm/state.py135
-rw-r--r--lib/sqlalchemy/orm/strategies.py8
-rw-r--r--lib/sqlalchemy/types.py183
7 files changed, 17 insertions, 428 deletions
diff --git a/lib/sqlalchemy/dialects/postgresql/base.py b/lib/sqlalchemy/dialects/postgresql/base.py
index c31c23885..cc1aa7600 100644
--- a/lib/sqlalchemy/dialects/postgresql/base.py
+++ b/lib/sqlalchemy/dialects/postgresql/base.py
@@ -317,7 +317,7 @@ class UUID(sqltypes.TypeEngine):
PGUuid = UUID
-class ARRAY(sqltypes.MutableType, sqltypes.Concatenable, sqltypes.TypeEngine):
+class ARRAY(sqltypes.Concatenable, sqltypes.TypeEngine):
"""Postgresql ARRAY type.
Represents values as Python lists.
@@ -329,7 +329,7 @@ class ARRAY(sqltypes.MutableType, sqltypes.Concatenable, sqltypes.TypeEngine):
"""
__visit_name__ = 'ARRAY'
- def __init__(self, item_type, mutable=False, as_tuple=False):
+ def __init__(self, item_type, as_tuple=False):
"""Construct an ARRAY.
E.g.::
@@ -344,25 +344,10 @@ class ARRAY(sqltypes.MutableType, sqltypes.Concatenable, sqltypes.TypeEngine):
``ARRAY(ARRAY(Integer))`` or such. The type mapping figures out on
the fly
- :param mutable=False: Specify whether lists passed to this
- class should be considered mutable - this enables
- "mutable types" mode in the ORM. Be sure to read the
- notes for :class:`.MutableType` regarding ORM
- performance implications (default changed from ``True`` in
- 0.7.0).
-
- .. note::
-
- This functionality is now superseded by the
- ``sqlalchemy.ext.mutable`` extension described in
- :ref:`mutable_toplevel`.
-
:param as_tuple=False: Specify whether return results
should be converted to tuples from lists. DBAPIs such
as psycopg2 return lists by default. When tuples are
- returned, the results are hashable. This flag can only
- be set to ``True`` when ``mutable`` is set to
- ``False``. (new in 0.6.5)
+ returned, the results are hashable.
"""
if isinstance(item_type, ARRAY):
@@ -371,27 +356,11 @@ class ARRAY(sqltypes.MutableType, sqltypes.Concatenable, sqltypes.TypeEngine):
if isinstance(item_type, type):
item_type = item_type()
self.item_type = item_type
- self.mutable = mutable
- if mutable and as_tuple:
- raise exc.ArgumentError(
- "mutable must be set to False if as_tuple is True."
- )
self.as_tuple = as_tuple
- def copy_value(self, value):
- if value is None:
- return None
- elif self.mutable:
- return list(value)
- else:
- return value
-
def compare_values(self, x, y):
return x == y
- def is_mutable(self):
- return self.mutable
-
def bind_processor(self, dialect):
item_proc = self.item_type.dialect_impl(dialect).bind_processor(dialect)
if item_proc:
diff --git a/lib/sqlalchemy/orm/attributes.py b/lib/sqlalchemy/orm/attributes.py
index fd51e200f..9933a2f4d 100644
--- a/lib/sqlalchemy/orm/attributes.py
+++ b/lib/sqlalchemy/orm/attributes.py
@@ -585,60 +585,6 @@ class ScalarAttributeImpl(AttributeImpl):
self.property.columns[0].type
-class MutableScalarAttributeImpl(ScalarAttributeImpl):
- """represents a scalar value-holding InstrumentedAttribute, which can
- detect changes within the value itself.
-
- """
-
- uses_objects = False
- supports_population = True
-
- def __init__(self, class_, key, callable_, dispatch,
- class_manager, copy_function=None,
- compare_function=None, **kwargs):
- super(ScalarAttributeImpl, self).__init__(
- class_,
- key,
- callable_, dispatch,
- compare_function=compare_function,
- **kwargs)
- class_manager.mutable_attributes.add(key)
- if copy_function is None:
- raise sa_exc.ArgumentError(
- "MutableScalarAttributeImpl requires a copy function")
- self.copy = copy_function
-
- def get_history(self, state, dict_, passive=PASSIVE_OFF):
- if not dict_:
- v = state.committed_state.get(self.key, NO_VALUE)
- else:
- v = dict_.get(self.key, NO_VALUE)
-
- return History.from_scalar_attribute(self, state, v)
-
- def check_mutable_modified(self, state, dict_):
- a, u, d = self.get_history(state, dict_)
- return bool(a or d)
-
- def get(self, state, dict_, passive=PASSIVE_OFF):
- if self.key not in state.mutable_dict:
- ret = ScalarAttributeImpl.get(self, state, dict_, passive=passive)
- if ret is not PASSIVE_NO_RESULT:
- state.mutable_dict[self.key] = ret
- return ret
- else:
- return state.mutable_dict[self.key]
-
- def delete(self, state, dict_):
- ScalarAttributeImpl.delete(self, state, dict_)
- state.mutable_dict.pop(self.key)
-
- def set(self, state, dict_, value, initiator,
- passive=PASSIVE_OFF, check_old=None, pop=False):
- ScalarAttributeImpl.set(self, state, dict_, value,
- initiator, passive, check_old=check_old, pop=pop)
- state.mutable_dict[self.key] = value
class ScalarObjectAttributeImpl(ScalarAttributeImpl):
@@ -1269,7 +1215,7 @@ def register_attribute(class_, key, **kw):
def register_attribute_impl(class_, key,
uselist=False, callable_=None,
- useobject=False, mutable_scalars=False,
+ useobject=False,
impl_class=None, backref=None, **kw):
manager = manager_of_class(class_)
@@ -1290,9 +1236,6 @@ def register_attribute_impl(class_, key,
elif useobject:
impl = ScalarObjectAttributeImpl(class_, key, callable_,
dispatch,**kw)
- elif mutable_scalars:
- impl = MutableScalarAttributeImpl(class_, key, callable_, dispatch,
- class_manager=manager, **kw)
else:
impl = ScalarAttributeImpl(class_, key, callable_, dispatch, **kw)
diff --git a/lib/sqlalchemy/orm/identity.py b/lib/sqlalchemy/orm/identity.py
index 59d121de9..bb5fbb6e8 100644
--- a/lib/sqlalchemy/orm/identity.py
+++ b/lib/sqlalchemy/orm/identity.py
@@ -10,7 +10,6 @@ from sqlalchemy.orm import attributes
class IdentityMap(dict):
def __init__(self):
- self._mutable_attrs = set()
self._modified = set()
self._wr = weakref.ref(self)
@@ -31,28 +30,18 @@ class IdentityMap(dict):
if state.modified:
self._modified.add(state)
- if state.manager.mutable_attributes:
- self._mutable_attrs.add(state)
def _manage_removed_state(self, state):
del state._instance_dict
- self._mutable_attrs.discard(state)
self._modified.discard(state)
def _dirty_states(self):
- return self._modified.union(s for s in self._mutable_attrs.copy()
- if s.modified)
+ return self._modified
def check_modified(self):
"""return True if any InstanceStates present have been marked as 'modified'."""
- if self._modified:
- return True
- else:
- for state in self._mutable_attrs.copy():
- if state.modified:
- return True
- return False
+ return bool(self._modified)
def has_key(self, key):
return key in self
diff --git a/lib/sqlalchemy/orm/instrumentation.py b/lib/sqlalchemy/orm/instrumentation.py
index 1012af67a..e9d1ca36a 100644
--- a/lib/sqlalchemy/orm/instrumentation.py
+++ b/lib/sqlalchemy/orm/instrumentation.py
@@ -86,7 +86,6 @@ class ClassManager(dict):
self.factory = None # where we came from, for inheritance bookkeeping
self.info = {}
self.new_init = None
- self.mutable_attributes = set()
self.local_attrs = {}
self.originals = {}
@@ -155,10 +154,7 @@ class ClassManager(dict):
@util.memoized_property
def _state_constructor(self):
self.dispatch.first_init(self, self.class_)
- if self.mutable_attributes:
- return state.MutableAttrInstanceState
- else:
- return state.InstanceState
+ return state.InstanceState
def manage(self):
"""Mark this instance as the manager for its class."""
@@ -209,8 +205,6 @@ class ClassManager(dict):
del self.local_attrs[key]
self.uninstall_descriptor(key)
del self[key]
- if key in self.mutable_attributes:
- self.mutable_attributes.remove(key)
for cls in self.class_.__subclasses__():
manager = manager_of_class(cls)
if manager:
diff --git a/lib/sqlalchemy/orm/state.py b/lib/sqlalchemy/orm/state.py
index 64fca8715..bb6104762 100644
--- a/lib/sqlalchemy/orm/state.py
+++ b/lib/sqlalchemy/orm/state.py
@@ -33,7 +33,6 @@ class InstanceState(object):
load_options = EMPTY_SET
load_path = ()
insert_order = None
- mutable_dict = None
_strong_obj = None
modified = False
expired = False
@@ -150,9 +149,6 @@ class InstanceState(object):
manager.dispatch.init(self, args, kwargs)
- #if manager.mutable_attributes:
- # assert self.__class__ is MutableAttrInstanceState
-
try:
return manager.original_init(*mixed[1:], **kwargs)
except:
@@ -175,7 +171,7 @@ class InstanceState(object):
d.update(
(k, self.__dict__[k]) for k in (
'committed_state', '_pending_mutations', 'modified', 'expired',
- 'callables', 'key', 'parents', 'load_options', 'mutable_dict',
+ 'callables', 'key', 'parents', 'load_options',
'class_',
) if k in self.__dict__
)
@@ -220,7 +216,7 @@ class InstanceState(object):
self.__dict__.update([
(k, state[k]) for k in (
- 'key', 'load_options', 'mutable_dict'
+ 'key', 'load_options',
) if k in state
])
@@ -275,7 +271,6 @@ class InstanceState(object):
self.committed_state.clear()
self.__dict__.pop('_pending_mutations', None)
- self.__dict__.pop('mutable_dict', None)
# clear out 'parents' collection. not
# entirely clear how we can best determine
@@ -293,7 +288,6 @@ class InstanceState(object):
def expire_attributes(self, dict_, attribute_names):
pending = self.__dict__.get('_pending_mutations', None)
- mutable_dict = self.mutable_dict
for key in attribute_names:
impl = self.manager[key].impl
@@ -302,8 +296,6 @@ class InstanceState(object):
dict_.pop(key, None)
self.committed_state.pop(key, None)
- if mutable_dict:
- mutable_dict.pop(key, None)
if pending:
pending.pop(key, None)
@@ -421,15 +413,8 @@ class InstanceState(object):
"""
class_manager = self.manager
- if class_manager.mutable_attributes:
- for key in keys:
- if key in dict_ and key in class_manager.mutable_attributes:
- self.committed_state[key] = self.manager[key].impl.copy(dict_[key])
- else:
- self.committed_state.pop(key, None)
- else:
- for key in keys:
- self.committed_state.pop(key, None)
+ for key in keys:
+ self.committed_state.pop(key, None)
self.expired = False
@@ -462,10 +447,6 @@ class InstanceState(object):
if key in dict_ and callables[key] is self:
del callables[key]
- for key in self.manager.mutable_attributes:
- if key in dict_:
- self.committed_state[key] = self.manager[key].impl.copy(dict_[key])
-
if instance_dict and self.modified:
instance_dict._modified.discard(self)
@@ -493,114 +474,6 @@ class InspectAttr(object):
return self.state.get_history(self.key,
PASSIVE_NO_INITIALIZE)
-class MutableAttrInstanceState(InstanceState):
- """InstanceState implementation for objects that reference 'mutable'
- attributes.
-
- Has a more involved "cleanup" handler that checks mutable attributes
- for changes upon dereference, resurrecting if needed.
-
- """
-
- @util.memoized_property
- def mutable_dict(self):
- return {}
-
- def _get_modified(self, dict_=None):
- if self.__dict__.get('modified', False):
- return True
- else:
- if dict_ is None:
- dict_ = self.dict
- for key in self.manager.mutable_attributes:
- if self.manager[key].impl.check_mutable_modified(self, dict_):
- return True
- else:
- return False
-
- def _set_modified(self, value):
- self.__dict__['modified'] = value
-
- modified = property(_get_modified, _set_modified)
-
- @property
- def unmodified(self):
- """a set of keys which have no uncommitted changes"""
-
- dict_ = self.dict
-
- return set([
- key for key in self.manager
- if (key not in self.committed_state or
- (key in self.manager.mutable_attributes and
- not self.manager[key].impl.check_mutable_modified(self, dict_)))])
-
- def unmodified_intersection(self, keys):
- """Return self.unmodified.intersection(keys)."""
-
- dict_ = self.dict
-
- return set([
- key for key in keys
- if (key not in self.committed_state or
- (key in self.manager.mutable_attributes and
- not self.manager[key].impl.check_mutable_modified(self, dict_)))])
-
-
- def _is_really_none(self):
- """do a check modified/resurrect.
-
- This would be called in the extremely rare
- race condition that the weakref returned None but
- the cleanup handler had not yet established the
- __resurrect callable as its replacement.
-
- """
- if self.modified:
- self.obj = self.__resurrect
- return self.obj()
- else:
- return None
-
- def reset(self, dict_, key):
- self.mutable_dict.pop(key, None)
- InstanceState.reset(self, dict_, key)
-
- def _cleanup(self, ref):
- """weakref callback.
-
- This method may be called by an asynchronous
- gc.
-
- If the state shows pending changes, the weakref
- is replaced by the __resurrect callable which will
- re-establish an object reference on next access,
- else removes this InstanceState from the owning
- identity map, if any.
-
- """
- if self._get_modified(self.mutable_dict):
- self.obj = self.__resurrect
- else:
- instance_dict = self._instance_dict()
- if instance_dict:
- instance_dict.discard(self)
- self._dispose()
-
- def __resurrect(self):
- """A substitute for the obj() weakref function which resurrects."""
-
- # store strong ref'ed version of the object; will revert
- # to weakref when changes are persisted
- obj = self.manager.new_instance(state=self)
- self.obj = weakref.ref(obj, self._cleanup)
- self._strong_obj = obj
- obj.__dict__.update(self.mutable_dict)
-
- # re-establishes identity attributes from the key
- self.manager.dispatch.resurrect(self)
-
- return obj
class PendingCollection(object):
"""A writable placeholder for an unloaded collection.
diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py
index 06b630076..4cf32335f 100644
--- a/lib/sqlalchemy/orm/strategies.py
+++ b/lib/sqlalchemy/orm/strategies.py
@@ -25,8 +25,6 @@ import itertools
def _register_attribute(strategy, mapper, useobject,
compare_function=None,
typecallable=None,
- copy_function=None,
- mutable_scalars=False,
uselist=False,
callable_=None,
proxy_property=None,
@@ -71,9 +69,7 @@ def _register_attribute(strategy, mapper, useobject,
m.class_,
prop.key,
parent_token=prop,
- mutable_scalars=mutable_scalars,
uselist=uselist,
- copy_function=copy_function,
compare_function=compare_function,
useobject=useobject,
extension=attribute_ext,
@@ -132,8 +128,6 @@ class ColumnLoader(LoaderStrategy):
_register_attribute(self, mapper, useobject=False,
compare_function=coltype.compare_values,
- copy_function=coltype.copy_value,
- mutable_scalars=self.columns[0].type.is_mutable(),
active_history = active_history
)
@@ -193,8 +187,6 @@ class DeferredColumnLoader(LoaderStrategy):
_register_attribute(self, mapper, useobject=False,
compare_function=self.columns[0].type.compare_values,
- copy_function=self.columns[0].type.copy_value,
- mutable_scalars=self.columns[0].type.is_mutable(),
callable_=self._load_for_state,
expire_missing=False
)
diff --git a/lib/sqlalchemy/types.py b/lib/sqlalchemy/types.py
index 512ac6268..c6e3ee3d6 100644
--- a/lib/sqlalchemy/types.py
+++ b/lib/sqlalchemy/types.py
@@ -17,7 +17,7 @@ __all__ = [ 'TypeEngine', 'TypeDecorator', 'AbstractType', 'UserDefinedType',
'CLOB', 'BLOB', 'BOOLEAN', 'SMALLINT', 'INTEGER', 'DATE', 'TIME',
'String', 'Integer', 'SmallInteger', 'BigInteger', 'Numeric',
'Float', 'DateTime', 'Date', 'Time', 'LargeBinary', 'Binary',
- 'Boolean', 'Unicode', 'MutableType', 'Concatenable',
+ 'Boolean', 'Unicode', 'Concatenable',
'UnicodeText','PickleType', 'Interval', 'Enum' ]
import inspect
@@ -83,28 +83,6 @@ class TypeEngine(AbstractType):
return x == y
- def is_mutable(self):
- """Return True if the target Python type is 'mutable'.
-
- This allows systems like the ORM to know if a column value can
- be considered 'not changed' by comparing the identity of
- objects alone. Values such as dicts, lists which
- are serialized into strings are examples of "mutable"
- column structures.
-
- .. note::
-
- This functionality is now superseded by the
- ``sqlalchemy.ext.mutable`` extension described in
- :ref:`mutable_toplevel`.
-
- When this method is overridden, :meth:`copy_value` should
- also be supplied. The :class:`.MutableType` mixin
- is recommended as a helper.
-
- """
- return False
-
def get_dbapi_type(self, dbapi):
"""Return the corresponding type object from the underlying DB-API, if
any.
@@ -710,30 +688,6 @@ class TypeDecorator(TypeEngine):
"""
return self.impl.get_dbapi_type(dbapi)
- def copy_value(self, value):
- """Given a value, produce a copy of it.
-
- By default this calls upon :meth:`.TypeEngine.copy_value`
- of the underlying "impl".
-
- :meth:`.copy_value` will return the object
- itself, assuming "mutability" is not enabled.
- Only the :class:`.MutableType` mixin provides a copy
- function that actually produces a new object.
- The copying function is used by the ORM when
- "mutable" types are used, to memoize the original
- version of an object as loaded from the database,
- which is then compared to the possibly mutated
- version to check for changes.
-
- Modern implementations should use the
- ``sqlalchemy.ext.mutable`` extension described in
- :ref:`mutable_toplevel` for intercepting in-place
- changes to values.
-
- """
- return self.impl.copy_value(value)
-
def compare_values(self, x, y):
"""Given two values, compare them for equality.
@@ -749,24 +703,6 @@ class TypeDecorator(TypeEngine):
"""
return self.impl.compare_values(x, y)
- def is_mutable(self):
- """Return True if the target Python type is 'mutable'.
-
- This allows systems like the ORM to know if a column value can
- be considered 'not changed' by comparing the identity of
- objects alone. Values such as dicts, lists which
- are serialized into strings are examples of "mutable"
- column structures.
-
- .. note::
-
- This functionality is now superseded by the
- ``sqlalchemy.ext.mutable`` extension described in
- :ref:`mutable_toplevel`.
-
- """
- return self.impl.is_mutable()
-
def _adapt_expression(self, op, othertype):
"""
#todo
@@ -828,82 +764,6 @@ class Variant(TypeDecorator):
mapping[dialect_name] = type_
return Variant(self.impl, mapping)
-class MutableType(object):
- """A mixin that marks a :class:`.TypeEngine` as representing
- a mutable Python object type. This functionality is used
- only by the ORM.
-
- .. note::
-
- :class:`.MutableType` is superseded as of SQLAlchemy 0.7
- by the ``sqlalchemy.ext.mutable`` extension described in
- :ref:`mutable_toplevel`. This extension provides an event
- driven approach to in-place mutation detection that does not
- incur the severe performance penalty of the :class:`.MutableType`
- approach.
-
- "mutable" means that changes can occur in place to a value
- of this type. Examples includes Python lists, dictionaries,
- and sets, as well as user-defined objects. The primary
- need for identification of "mutable" types is by the ORM,
- which applies special rules to such values in order to guarantee
- that changes are detected. These rules may have a significant
- performance impact, described below.
-
- A :class:`.MutableType` usually allows a flag called
- ``mutable=False`` to enable/disable the "mutability" flag,
- represented on this class by :meth:`is_mutable`. Examples
- include :class:`.PickleType` and
- :class:`~sqlalchemy.dialects.postgresql.base.ARRAY`. Setting
- this flag to ``True`` enables mutability-specific behavior
- by the ORM.
-
- The :meth:`copy_value` and :meth:`compare_values` functions
- represent a copy and compare function for values of this
- type - implementing subclasses should override these
- appropriately.
-
- .. warning::
-
- The usage of mutable types has significant performance
- implications when using the ORM. In order to detect changes, the
- ORM must create a copy of the value when it is first
- accessed, so that changes to the current value can be compared
- against the "clean" database-loaded value. Additionally, when the
- ORM checks to see if any data requires flushing, it must scan
- through all instances in the session which are known to have
- "mutable" attributes and compare the current value of each
- one to its "clean"
- value. So for example, if the Session contains 6000 objects (a
- fairly large amount) and autoflush is enabled, every individual
- execution of :class:`.Query` will require a full scan of that subset of
- the 6000 objects that have mutable attributes, possibly resulting
- in tens of thousands of additional method calls for every query.
-
- As of SQLAlchemy 0.7, the ``sqlalchemy.ext.mutable`` is provided which
- allows an event driven approach to in-place mutation detection. This
- approach should now be favored over the usage of :class:`.MutableType`
- with ``mutable=True``. ``sqlalchemy.ext.mutable`` is described in
- :ref:`mutable_toplevel`.
-
- """
-
- def is_mutable(self):
- """Return True if the target Python type is 'mutable'.
-
- For :class:`.MutableType`, this method is set to
- return ``True``.
-
- """
- return True
-
- def copy_value(self, value):
- """Unimplemented."""
- raise NotImplementedError()
-
- def compare_values(self, x, y):
- """Compare *x* == *y*."""
- return x == y
def to_instance(typeobj, *arg, **kw):
if typeobj is None:
@@ -1961,7 +1821,7 @@ class Enum(String, SchemaType):
else:
return super(Enum, self).adapt(impltype, **kw)
-class PickleType(MutableType, TypeDecorator):
+class PickleType(TypeDecorator):
"""Holds Python objects, which are serialized using pickle.
PickleType builds upon the Binary type to apply Python's
@@ -1969,12 +1829,15 @@ class PickleType(MutableType, TypeDecorator):
the way out, allowing any pickleable Python object to be stored as
a serialized binary field.
+ To allow ORM change events to propagate for elements associated
+ with :class:`.PickleType`, see :ref:`mutable_toplevel`.
+
"""
impl = LargeBinary
def __init__(self, protocol=pickle.HIGHEST_PROTOCOL,
- pickler=None, mutable=False, comparator=None):
+ pickler=None, comparator=None):
"""
Construct a PickleType.
@@ -1984,21 +1847,6 @@ class PickleType(MutableType, TypeDecorator):
cPickle is not available. May be any object with
pickle-compatible ``dumps` and ``loads`` methods.
- :param mutable: defaults to False; implements
- :meth:`AbstractType.is_mutable`. When ``True``, incoming
- objects will be compared against copies of themselves
- using the Python "equals" operator, unless the
- ``comparator`` argument is present. See
- :class:`.MutableType` for details on "mutable" type
- behavior. (default changed from ``True`` in
- 0.7.0).
-
- .. note::
-
- This functionality is now superseded by the
- ``sqlalchemy.ext.mutable`` extension described in
- :ref:`mutable_toplevel`.
-
:param comparator: a 2-arg callable predicate used
to compare values of this type. If left as ``None``,
the Python "equals" operator is used to compare values.
@@ -2006,14 +1854,12 @@ class PickleType(MutableType, TypeDecorator):
"""
self.protocol = protocol
self.pickler = pickler or pickle
- self.mutable = mutable
self.comparator = comparator
super(PickleType, self).__init__()
def __reduce__(self):
return PickleType, (self.protocol,
None,
- self.mutable,
self.comparator)
def bind_processor(self, dialect):
@@ -2048,29 +1894,12 @@ class PickleType(MutableType, TypeDecorator):
return loads(value)
return process
- def copy_value(self, value):
- if self.mutable:
- return self.pickler.loads(
- self.pickler.dumps(value, self.protocol))
- else:
- return value
-
def compare_values(self, x, y):
if self.comparator:
return self.comparator(x, y)
else:
return x == y
- def is_mutable(self):
- """Return True if the target Python type is 'mutable'.
-
- When this method is overridden, :meth:`copy_value` should
- also be supplied. The :class:`.MutableType` mixin
- is recommended as a helper.
-
- """
- return self.mutable
-
class Boolean(TypeEngine, SchemaType):
"""A bool datatype.