]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- beef up the "augmenting existing types" section
authorMike Bayer <mike_mp@zzzcomputing.com>
Wed, 30 Mar 2011 18:22:25 +0000 (14:22 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Wed, 30 Mar 2011 18:22:25 +0000 (14:22 -0400)
- add docstirngs for everything TypeDecorator [ticket:2086]

doc/build/core/types.rst
lib/sqlalchemy/types.py

index cedfc8c6c26dbaf0513b75052c49ab04179011b5..3ba9ad42894d607627839f0384b5adc8edde8c04 100644 (file)
@@ -245,10 +245,29 @@ as well as to provide new ones.
 Overriding Type Compilation
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-The string produced by any type object, when rendered in a CREATE TABLE 
-statement or other SQL function like CAST, can be changed.  See the
-section :ref:`type_compilation_extension`, a subsection of 
-:ref:`sqlalchemy.ext.compiler_toplevel`, for a short example.
+A frequent need is to force the "string" version of a type, that is
+the one rendered in a CREATE TABLE statement or other SQL function 
+like CAST, to be changed.   For example, an application may want
+to force the rendering of ``BINARY`` for all platforms
+except for one, in which is wants ``BLOB`` to be rendered.  Usage 
+of an existing generic type, in this case :class:`.LargeBinary`, is
+preferred for most use cases.  But to control
+types more accurately, a compilation directive that is per-dialect
+can be associated with any type::
+
+    from sqlalchemy.ext.compiler import compiles
+    from sqlalchemy.types import BINARY
+
+    @compiles(BINARY, "sqlite")
+    def compile_binary_sqlite(type_, compiler, **kw):
+        return "BLOB"
+
+The above code allows the usage of :class:`.types.BINARY`, which
+will produce the string ``BINARY`` against all backends except SQLite, 
+in which case it will produce ``BLOB``.
+
+See the section :ref:`type_compilation_extension`, a subsection of 
+:ref:`sqlalchemy.ext.compiler_toplevel`, for additional examples.
 
 Augmenting Existing Types
 ~~~~~~~~~~~~~~~~~~~~~~~~~
index c4266089b251b16981eb72f7287fbecd992fbe65..46c33eb33f36f833684b1d3dbaf9aeba4df6770d 100644 (file)
@@ -147,6 +147,14 @@ class AbstractType(Visitable):
         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.
 
@@ -191,6 +199,8 @@ class TypeEngine(AbstractType):
         return {}
 
     def dialect_impl(self, dialect, **kwargs):
+        """Return a dialect-specific implementation for this :class:`.TypeEngine`."""
+
         key = dialect.__class__, dialect.server_version_info
         try:
             return self._impl_dict[key]
@@ -367,6 +377,19 @@ class TypeDecorator(AbstractType):
     __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 "
@@ -375,9 +398,24 @@ class TypeDecorator(AbstractType):
         self.impl = to_instance(self.__class__.impl, *args, **kwargs)
 
     def adapt(self, cls):
+        """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 cls()
 
     def dialect_impl(self, dialect):
+        """Return a dialect-specific implementation for this :class:`.TypeEngine`.
+        
+        See also :meth:`type_engine`, :meth:`load_dialect_impl`.
+        :meth:`load_dialect_impl` is an end-user overrideable
+        hook.
+        
+        """
+
         key = (dialect.__class__, dialect.server_version_info)
 
         try:
@@ -413,7 +451,14 @@ class TypeDecorator(AbstractType):
         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``.
+        Makes usage of :meth:`dialect_impl` but also traverses
+        into wrapped :class:`.TypeDecorator` instances.
+        Behavior can be customized here by overriding :meth:`load_dialect_impl`.
 
         """
         adapted = dialect.type_descriptor(self)
@@ -425,10 +470,15 @@ class TypeDecorator(AbstractType):
             return self.load_dialect_impl(dialect)
 
     def load_dialect_impl(self, dialect):
-        """User hook which can be overridden to provide a different 'impl'
-        type per-dialect.
+        """Return a :class:`.TypeEngine` object corresponding to a dialect.
+        
+        This is an end-user override hook that can be used to provide
+        differing types depending on the given dialect.  It is used
+        by the :class:`.TypeDecorator` implementation of :meth:`type_engine` 
+        and :meth:`dialect_impl` to help determine what type should ultimately be returned
+        for a given :class:`.TypeDecorator`.
 
-        by default returns self.impl.
+        By default returns ``self.impl``.
 
         """
         return self.impl
@@ -440,12 +490,47 @@ class TypeDecorator(AbstractType):
         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
@@ -463,6 +548,18 @@ class TypeDecorator(AbstractType):
             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
@@ -504,18 +601,59 @@ class TypeDecorator(AbstractType):
         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__)
         instance._impl_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.
+        
+        """
         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):