summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2011-03-30 14:07:27 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2011-03-30 14:07:27 -0400
commitb99cd60cb893220d025bca1d40b916f0d7a4754e (patch)
treee7257f5bdb043da18b6ef2c8f72a7e5985b37a6c /lib/sqlalchemy
parent218c3cb365e7354a312bc3e24e1cb21a2487459c (diff)
downloadsqlalchemy-b99cd60cb893220d025bca1d40b916f0d7a4754e.tar.gz
- beef up the "augmenting existing types" section
- add docstirngs for everything TypeDecorator [ticket:2086]
Diffstat (limited to 'lib/sqlalchemy')
-rw-r--r--lib/sqlalchemy/types.py126
1 files changed, 125 insertions, 1 deletions
diff --git a/lib/sqlalchemy/types.py b/lib/sqlalchemy/types.py
index de74b2031..1a894ce63 100644
--- a/lib/sqlalchemy/types.py
+++ b/lib/sqlalchemy/types.py
@@ -184,6 +184,13 @@ class TypeEngine(AbstractType):
return dialect.type_descriptor(self)
def adapt(self, cls, **kw):
+ """Produce an "adapted" form of this type, given an "impl" class
+ to work with.
+
+ This method is used internally to associate generic
+ types with "implementation" types that are specific to a particular
+ dialect.
+ """
return util.constructor_copy(self, cls, **kw)
def _coerce_compared_value(self, op, value):
@@ -216,6 +223,14 @@ class TypeEngine(AbstractType):
return self._type_affinity is other._type_affinity
def compile(self, dialect=None):
+ """Produce a string-compiled form of this :class:`.TypeEngine`.
+
+ When called with no arguments, uses a "default" dialect
+ to produce a string result.
+
+ :param dialect: a :class:`.Dialect` instance.
+
+ """
# arg, return value is inconsistent with
# ClauseElement.compile()....this is a mistake.
@@ -391,6 +406,19 @@ class TypeDecorator(TypeEngine):
__visit_name__ = "type_decorator"
def __init__(self, *args, **kwargs):
+ """Construct a :class:`.TypeDecorator`.
+
+ Arguments sent here are passed to the constructor
+ of the class assigned to the ``impl`` class level attribute,
+ where the ``self.impl`` attribute is assigned an instance
+ of the implementation type. If ``impl`` at the class level
+ is already an instance, then it's assigned to ``self.impl``
+ as is.
+
+ Subclasses can override this to customize the generation
+ of ``self.impl``.
+
+ """
if not hasattr(self.__class__, 'impl'):
raise AssertionError("TypeDecorator implementations "
"require a class-level variable "
@@ -422,7 +450,10 @@ class TypeDecorator(TypeEngine):
return self.impl._type_affinity
def type_engine(self, dialect):
- """Return a TypeEngine instance for this TypeDecorator.
+ """Return a dialect-specific :class:`.TypeEngine` instance for this :class:`.TypeDecorator`.
+
+ In most cases this returns a dialect-adapted form of
+ the :class:`.TypeEngine` type represented by ``self.impl``.
"""
adapted = dialect.type_descriptor(self)
@@ -449,12 +480,47 @@ class TypeDecorator(TypeEngine):
return getattr(self.impl, key)
def process_bind_param(self, value, dialect):
+ """Receive a bound parameter value to be converted.
+
+ Subclasses override this method to return the
+ value that should be passed along to the underlying
+ :class:`.TypeEngine` object, and from there to the
+ DBAPI ``execute()`` method.
+
+ :param value: the value. Can be None.
+ :param dialect: the :class:`.Dialect` in use.
+
+ """
raise NotImplementedError()
def process_result_value(self, value, dialect):
+ """Receive a result-row column value to be converted.
+
+ Subclasses override this method to return the
+ value that should be passed back to the application,
+ given a value that is already processed by
+ the underlying :class:`.TypeEngine` object, originally
+ from the DBAPI cursor method ``fetchone()`` or similar.
+
+ :param value: the value. Can be None.
+ :param dialect: the :class:`.Dialect` in use.
+
+ """
raise NotImplementedError()
def bind_processor(self, dialect):
+ """Provide a bound value processing function for the given :class:`.Dialect`.
+
+ This is the method that fulfills the :class:`.TypeEngine`
+ contract for bound value conversion. :class:`.TypeDecorator`
+ will wrap a user-defined implementation of
+ :meth:`process_bind_param` here.
+
+ User-defined code can override this method directly,
+ though its likely best to use :meth:`process_bind_param` so that
+ the processing provided by ``self.impl`` is maintained.
+
+ """
if self.__class__.process_bind_param.func_code \
is not TypeDecorator.process_bind_param.func_code:
process_param = self.process_bind_param
@@ -472,6 +538,18 @@ class TypeDecorator(TypeEngine):
return self.impl.bind_processor(dialect)
def result_processor(self, dialect, coltype):
+ """Provide a result value processing function for the given :class:`.Dialect`.
+
+ This is the method that fulfills the :class:`.TypeEngine`
+ contract for result value conversion. :class:`.TypeDecorator`
+ will wrap a user-defined implementation of
+ :meth:`process_result_value` here.
+
+ User-defined code can override this method directly,
+ though its likely best to use :meth:`process_result_value` so that
+ the processing provided by ``self.impl`` is maintained.
+
+ """
if self.__class__.process_result_value.func_code \
is not TypeDecorator.process_result_value.func_code:
process_value = self.process_result_value
@@ -513,17 +591,63 @@ class TypeDecorator(TypeEngine):
return self.coerce_compared_value(op, value)
def copy(self):
+ """Produce a copy of this :class:`.TypeDecorator` instance.
+
+ This is a shallow copy and is provided to fulfill part of
+ the :class:`.TypeEngine` contract. It usually does not
+ need to be overridden unless the user-defined :class:`.TypeDecorator`
+ has local state that should be deep-copied.
+
+ """
instance = self.__class__.__new__(self.__class__)
instance.__dict__.update(self.__dict__)
return instance
def get_dbapi_type(self, dbapi):
+ """Return the DBAPI type object represented by this :class:`.TypeDecorator`.
+
+ By default this calls upon :meth:`.TypeEngine.get_dbapi_type` of the
+ underlying "impl".
+ """
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.
+
+ By default this calls upon :meth:`.TypeEngine.compare_values`
+ of the underlying "impl", which in turn usually
+ uses the Python equals operator ``==``.
+
+ This function is used by the ORM to compare
+ an original-loaded value with an intercepted
+ "changed" value, to determine if a net change
+ has occurred.
+
+ """
return self.impl.compare_values(x, y)
def is_mutable(self):