Coverage for /home/martinb/.local/share/virtualenvs/camcops/lib/python3.6/site-packages/sqlalchemy/sql/type_api.py : 65%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# sql/types_api.py
2# Copyright (C) 2005-2020 the SQLAlchemy authors and contributors
3# <see AUTHORS file>
4#
5# This module is part of SQLAlchemy and is released under
6# the MIT License: http://www.opensource.org/licenses/mit-license.php
8"""Base types API.
10"""
13from . import operators
14from .base import SchemaEventTarget
15from .visitors import Visitable
16from .visitors import VisitableType
17from .. import exc
18from .. import util
21# these are back-assigned by sqltypes.
22BOOLEANTYPE = None
23INTEGERTYPE = None
24NULLTYPE = None
25STRINGTYPE = None
26MATCHTYPE = None
27INDEXABLE = None
28_resolve_value_to_type = None
31class TypeEngine(Visitable):
32 """The ultimate base class for all SQL datatypes.
34 Common subclasses of :class:`.TypeEngine` include
35 :class:`.String`, :class:`.Integer`, and :class:`.Boolean`.
37 For an overview of the SQLAlchemy typing system, see
38 :ref:`types_toplevel`.
40 .. seealso::
42 :ref:`types_toplevel`
44 """
46 _sqla_type = True
47 _isnull = False
49 class Comparator(operators.ColumnOperators):
50 """Base class for custom comparison operations defined at the
51 type level. See :attr:`.TypeEngine.comparator_factory`.
54 """
56 __slots__ = "expr", "type"
58 default_comparator = None
60 def __init__(self, expr):
61 self.expr = expr
62 self.type = expr.type
64 @util.dependencies("sqlalchemy.sql.default_comparator")
65 def operate(self, default_comparator, op, *other, **kwargs):
66 o = default_comparator.operator_lookup[op.__name__]
67 return o[0](self.expr, op, *(other + o[1:]), **kwargs)
69 @util.dependencies("sqlalchemy.sql.default_comparator")
70 def reverse_operate(self, default_comparator, op, other, **kwargs):
71 o = default_comparator.operator_lookup[op.__name__]
72 return o[0](self.expr, op, other, reverse=True, *o[1:], **kwargs)
74 def _adapt_expression(self, op, other_comparator):
75 """evaluate the return type of <self> <op> <othertype>,
76 and apply any adaptations to the given operator.
78 This method determines the type of a resulting binary expression
79 given two source types and an operator. For example, two
80 :class:`_schema.Column` objects, both of the type
81 :class:`.Integer`, will
82 produce a :class:`.BinaryExpression` that also has the type
83 :class:`.Integer` when compared via the addition (``+``) operator.
84 However, using the addition operator with an :class:`.Integer`
85 and a :class:`.Date` object will produce a :class:`.Date`, assuming
86 "days delta" behavior by the database (in reality, most databases
87 other than PostgreSQL don't accept this particular operation).
89 The method returns a tuple of the form <operator>, <type>.
90 The resulting operator and type will be those applied to the
91 resulting :class:`.BinaryExpression` as the final operator and the
92 right-hand side of the expression.
94 Note that only a subset of operators make usage of
95 :meth:`._adapt_expression`,
96 including math operators and user-defined operators, but not
97 boolean comparison or special SQL keywords like MATCH or BETWEEN.
99 """
101 return op, self.type
103 def __reduce__(self):
104 return _reconstitute_comparator, (self.expr,)
106 hashable = True
107 """Flag, if False, means values from this type aren't hashable.
109 Used by the ORM when uniquing result lists.
111 """
113 comparator_factory = Comparator
114 """A :class:`.TypeEngine.Comparator` class which will apply
115 to operations performed by owning :class:`_expression.ColumnElement`
116 objects.
118 The :attr:`.comparator_factory` attribute is a hook consulted by
119 the core expression system when column and SQL expression operations
120 are performed. When a :class:`.TypeEngine.Comparator` class is
121 associated with this attribute, it allows custom re-definition of
122 all existing operators, as well as definition of new operators.
123 Existing operators include those provided by Python operator overloading
124 such as :meth:`.operators.ColumnOperators.__add__` and
125 :meth:`.operators.ColumnOperators.__eq__`,
126 those provided as standard
127 attributes of :class:`.operators.ColumnOperators` such as
128 :meth:`.operators.ColumnOperators.like`
129 and :meth:`.operators.ColumnOperators.in_`.
131 Rudimentary usage of this hook is allowed through simple subclassing
132 of existing types, or alternatively by using :class:`.TypeDecorator`.
133 See the documentation section :ref:`types_operators` for examples.
135 """
137 sort_key_function = None
138 """A sorting function that can be passed as the key to sorted.
140 The default value of ``None`` indicates that the values stored by
141 this type are self-sorting.
143 .. versionadded:: 1.3.8
145 """
147 should_evaluate_none = False
148 """If True, the Python constant ``None`` is considered to be handled
149 explicitly by this type.
151 The ORM uses this flag to indicate that a positive value of ``None``
152 is passed to the column in an INSERT statement, rather than omitting
153 the column from the INSERT statement which has the effect of firing
154 off column-level defaults. It also allows types which have special
155 behavior for Python None, such as a JSON type, to indicate that
156 they'd like to handle the None value explicitly.
158 To set this flag on an existing type, use the
159 :meth:`.TypeEngine.evaluates_none` method.
161 .. seealso::
163 :meth:`.TypeEngine.evaluates_none`
165 .. versionadded:: 1.1
168 """
170 def evaluates_none(self):
171 """Return a copy of this type which has the :attr:`.should_evaluate_none`
172 flag set to True.
174 E.g.::
176 Table(
177 'some_table', metadata,
178 Column(
179 String(50).evaluates_none(),
180 nullable=True,
181 server_default='no value')
182 )
184 The ORM uses this flag to indicate that a positive value of ``None``
185 is passed to the column in an INSERT statement, rather than omitting
186 the column from the INSERT statement which has the effect of firing
187 off column-level defaults. It also allows for types which have
188 special behavior associated with the Python None value to indicate
189 that the value doesn't necessarily translate into SQL NULL; a
190 prime example of this is a JSON type which may wish to persist the
191 JSON value ``'null'``.
193 In all cases, the actual NULL SQL value can be always be
194 persisted in any column by using
195 the :obj:`_expression.null` SQL construct in an INSERT statement
196 or associated with an ORM-mapped attribute.
198 .. note::
200 The "evaluates none" flag does **not** apply to a value
201 of ``None`` passed to :paramref:`_schema.Column.default` or
202 :paramref:`_schema.Column.server_default`; in these cases,
203 ``None``
204 still means "no default".
206 .. versionadded:: 1.1
208 .. seealso::
210 :ref:`session_forcing_null` - in the ORM documentation
212 :paramref:`.postgresql.JSON.none_as_null` - PostgreSQL JSON
213 interaction with this flag.
215 :attr:`.TypeEngine.should_evaluate_none` - class-level flag
217 """
218 typ = self.copy()
219 typ.should_evaluate_none = True
220 return typ
222 def copy(self, **kw):
223 return self.adapt(self.__class__)
225 def compare_against_backend(self, dialect, conn_type):
226 """Compare this type against the given backend type.
228 This function is currently not implemented for SQLAlchemy
229 types, and for all built in types will return ``None``. However,
230 it can be implemented by a user-defined type
231 where it can be consumed by schema comparison tools such as
232 Alembic autogenerate.
234 A future release of SQLAlchemy will potentially implement this method
235 for builtin types as well.
237 The function should return True if this type is equivalent to the
238 given type; the type is typically reflected from the database
239 so should be database specific. The dialect in use is also
240 passed. It can also return False to assert that the type is
241 not equivalent.
243 :param dialect: a :class:`.Dialect` that is involved in the comparison.
245 :param conn_type: the type object reflected from the backend.
247 .. versionadded:: 1.0.3
249 """
250 return None
252 def copy_value(self, value):
253 return value
255 def literal_processor(self, dialect):
256 """Return a conversion function for processing literal values that are
257 to be rendered directly without using binds.
259 This function is used when the compiler makes use of the
260 "literal_binds" flag, typically used in DDL generation as well
261 as in certain scenarios where backends don't accept bound parameters.
263 .. versionadded:: 0.9.0
265 """
266 return None
268 def bind_processor(self, dialect):
269 """Return a conversion function for processing bind values.
271 Returns a callable which will receive a bind parameter value
272 as the sole positional argument and will return a value to
273 send to the DB-API.
275 If processing is not necessary, the method should return ``None``.
277 :param dialect: Dialect instance in use.
279 """
280 return None
282 def result_processor(self, dialect, coltype):
283 """Return a conversion function for processing result row values.
285 Returns a callable which will receive a result row column
286 value as the sole positional argument and will return a value
287 to return to the user.
289 If processing is not necessary, the method should return ``None``.
291 :param dialect: Dialect instance in use.
293 :param coltype: DBAPI coltype argument received in cursor.description.
295 """
296 return None
298 def column_expression(self, colexpr):
299 """Given a SELECT column expression, return a wrapping SQL expression.
301 This is typically a SQL function that wraps a column expression
302 as rendered in the columns clause of a SELECT statement.
303 It is used for special data types that require
304 columns to be wrapped in some special database function in order
305 to coerce the value before being sent back to the application.
306 It is the SQL analogue of the :meth:`.TypeEngine.result_processor`
307 method.
309 The method is evaluated at statement compile time, as opposed
310 to statement construction time.
312 .. seealso::
314 :ref:`types_sql_value_processing`
316 """
318 return None
320 @util.memoized_property
321 def _has_column_expression(self):
322 """memoized boolean, check if column_expression is implemented.
324 Allows the method to be skipped for the vast majority of expression
325 types that don't use this feature.
327 """
329 return (
330 self.__class__.column_expression.__code__
331 is not TypeEngine.column_expression.__code__
332 )
334 def bind_expression(self, bindvalue):
335 """"Given a bind value (i.e. a :class:`.BindParameter` instance),
336 return a SQL expression in its place.
338 This is typically a SQL function that wraps the existing bound
339 parameter within the statement. It is used for special data types
340 that require literals being wrapped in some special database function
341 in order to coerce an application-level value into a database-specific
342 format. It is the SQL analogue of the
343 :meth:`.TypeEngine.bind_processor` method.
345 The method is evaluated at statement compile time, as opposed
346 to statement construction time.
348 Note that this method, when implemented, should always return
349 the exact same structure, without any conditional logic, as it
350 may be used in an executemany() call against an arbitrary number
351 of bound parameter sets.
353 .. seealso::
355 :ref:`types_sql_value_processing`
357 """
358 return None
360 @util.memoized_property
361 def _has_bind_expression(self):
362 """memoized boolean, check if bind_expression is implemented.
364 Allows the method to be skipped for the vast majority of expression
365 types that don't use this feature.
367 """
369 return (
370 self.__class__.bind_expression.__code__
371 is not TypeEngine.bind_expression.__code__
372 )
374 @staticmethod
375 def _to_instance(cls_or_self):
376 return to_instance(cls_or_self)
378 def compare_values(self, x, y):
379 """Compare two values for equality."""
381 return x == y
383 def get_dbapi_type(self, dbapi):
384 """Return the corresponding type object from the underlying DB-API, if
385 any.
387 This can be useful for calling ``setinputsizes()``, for example.
389 """
390 return None
392 @property
393 def python_type(self):
394 """Return the Python type object expected to be returned
395 by instances of this type, if known.
397 Basically, for those types which enforce a return type,
398 or are known across the board to do such for all common
399 DBAPIs (like ``int`` for example), will return that type.
401 If a return type is not defined, raises
402 ``NotImplementedError``.
404 Note that any type also accommodates NULL in SQL which
405 means you can also get back ``None`` from any type
406 in practice.
408 """
409 raise NotImplementedError()
411 def with_variant(self, type_, dialect_name):
412 r"""Produce a new type object that will utilize the given
413 type when applied to the dialect of the given name.
415 e.g.::
417 from sqlalchemy.types import String
418 from sqlalchemy.dialects import mysql
420 s = String()
422 s = s.with_variant(mysql.VARCHAR(collation='foo'), 'mysql')
424 The construction of :meth:`.TypeEngine.with_variant` is always
425 from the "fallback" type to that which is dialect specific.
426 The returned type is an instance of :class:`.Variant`, which
427 itself provides a :meth:`.Variant.with_variant`
428 that can be called repeatedly.
430 :param type\_: a :class:`.TypeEngine` that will be selected
431 as a variant from the originating type, when a dialect
432 of the given name is in use.
433 :param dialect_name: base name of the dialect which uses
434 this type. (i.e. ``'postgresql'``, ``'mysql'``, etc.)
436 """
437 return Variant(self, {dialect_name: to_instance(type_)})
439 @util.memoized_property
440 def _type_affinity(self):
441 """Return a rudimental 'affinity' value expressing the general class
442 of type."""
444 typ = None
445 for t in self.__class__.__mro__:
446 if t in (TypeEngine, UserDefinedType):
447 return typ
448 elif issubclass(t, (TypeEngine, UserDefinedType)):
449 typ = t
450 else:
451 return self.__class__
453 def dialect_impl(self, dialect):
454 """Return a dialect-specific implementation for this
455 :class:`.TypeEngine`.
457 """
458 try:
459 return dialect._type_memos[self]["impl"]
460 except KeyError:
461 return self._dialect_info(dialect)["impl"]
463 def _unwrapped_dialect_impl(self, dialect):
464 """Return the 'unwrapped' dialect impl for this type.
466 For a type that applies wrapping logic (e.g. TypeDecorator), give
467 us the real, actual dialect-level type that is used.
469 This is used by TypeDecorator itself as well at least one case where
470 dialects need to check that a particular specific dialect-level
471 type is in use, within the :meth:`.DefaultDialect.set_input_sizes`
472 method.
474 """
475 return self.dialect_impl(dialect)
477 def _cached_literal_processor(self, dialect):
478 """Return a dialect-specific literal processor for this type."""
479 try:
480 return dialect._type_memos[self]["literal"]
481 except KeyError:
482 pass
483 # avoid KeyError context coming into literal_processor() function
484 # raises
485 d = self._dialect_info(dialect)
486 d["literal"] = lp = d["impl"].literal_processor(dialect)
487 return lp
489 def _cached_bind_processor(self, dialect):
490 """Return a dialect-specific bind processor for this type."""
492 try:
493 return dialect._type_memos[self]["bind"]
494 except KeyError:
495 pass
496 # avoid KeyError context coming into bind_processor() function
497 # raises
498 d = self._dialect_info(dialect)
499 d["bind"] = bp = d["impl"].bind_processor(dialect)
500 return bp
502 def _cached_result_processor(self, dialect, coltype):
503 """Return a dialect-specific result processor for this type."""
505 try:
506 return dialect._type_memos[self][coltype]
507 except KeyError:
508 pass
509 # avoid KeyError context coming into result_processor() function
510 # raises
511 d = self._dialect_info(dialect)
512 # key assumption: DBAPI type codes are
513 # constants. Else this dictionary would
514 # grow unbounded.
515 d[coltype] = rp = d["impl"].result_processor(dialect, coltype)
516 return rp
518 def _cached_custom_processor(self, dialect, key, fn):
519 try:
520 return dialect._type_memos[self][key]
521 except KeyError:
522 pass
523 # avoid KeyError context coming into fn() function
524 # raises
525 d = self._dialect_info(dialect)
526 impl = d["impl"]
527 d[key] = result = fn(impl)
528 return result
530 def _dialect_info(self, dialect):
531 """Return a dialect-specific registry which
532 caches a dialect-specific implementation, bind processing
533 function, and one or more result processing functions."""
535 if self in dialect._type_memos:
536 return dialect._type_memos[self]
537 else:
538 impl = self._gen_dialect_impl(dialect)
539 if impl is self:
540 impl = self.adapt(type(self))
541 # this can't be self, else we create a cycle
542 assert impl is not self
543 dialect._type_memos[self] = d = {"impl": impl}
544 return d
546 def _gen_dialect_impl(self, dialect):
547 return dialect.type_descriptor(self)
549 def adapt(self, cls, **kw):
550 """Produce an "adapted" form of this type, given an "impl" class
551 to work with.
553 This method is used internally to associate generic
554 types with "implementation" types that are specific to a particular
555 dialect.
556 """
557 return util.constructor_copy(self, cls, **kw)
559 def coerce_compared_value(self, op, value):
560 """Suggest a type for a 'coerced' Python value in an expression.
562 Given an operator and value, gives the type a chance
563 to return a type which the value should be coerced into.
565 The default behavior here is conservative; if the right-hand
566 side is already coerced into a SQL type based on its
567 Python type, it is usually left alone.
569 End-user functionality extension here should generally be via
570 :class:`.TypeDecorator`, which provides more liberal behavior in that
571 it defaults to coercing the other side of the expression into this
572 type, thus applying special Python conversions above and beyond those
573 needed by the DBAPI to both ides. It also provides the public method
574 :meth:`.TypeDecorator.coerce_compared_value` which is intended for
575 end-user customization of this behavior.
577 """
578 _coerced_type = _resolve_value_to_type(value)
579 if (
580 _coerced_type is NULLTYPE
581 or _coerced_type._type_affinity is self._type_affinity
582 ):
583 return self
584 else:
585 return _coerced_type
587 def _compare_type_affinity(self, other):
588 return self._type_affinity is other._type_affinity
590 def compile(self, dialect=None):
591 """Produce a string-compiled form of this :class:`.TypeEngine`.
593 When called with no arguments, uses a "default" dialect
594 to produce a string result.
596 :param dialect: a :class:`.Dialect` instance.
598 """
599 # arg, return value is inconsistent with
600 # ClauseElement.compile()....this is a mistake.
602 if not dialect:
603 dialect = self._default_dialect()
605 return dialect.type_compiler.process(self)
607 @util.dependencies("sqlalchemy.engine.default")
608 def _default_dialect(self, default):
609 if self.__class__.__module__.startswith("sqlalchemy.dialects"):
610 tokens = self.__class__.__module__.split(".")[0:3]
611 mod = ".".join(tokens)
612 return getattr(__import__(mod).dialects, tokens[-1]).dialect()
613 else:
614 return default.DefaultDialect()
616 def __str__(self):
617 if util.py2k:
618 return unicode(self.compile()).encode( # noqa
619 "ascii", "backslashreplace"
620 ) # noqa
621 else:
622 return str(self.compile())
624 def __repr__(self):
625 return util.generic_repr(self)
628class VisitableCheckKWArg(util.EnsureKWArgType, VisitableType):
629 pass
632class UserDefinedType(util.with_metaclass(VisitableCheckKWArg, TypeEngine)):
633 """Base for user defined types.
635 This should be the base of new types. Note that
636 for most cases, :class:`.TypeDecorator` is probably
637 more appropriate::
639 import sqlalchemy.types as types
641 class MyType(types.UserDefinedType):
642 def __init__(self, precision = 8):
643 self.precision = precision
645 def get_col_spec(self, **kw):
646 return "MYTYPE(%s)" % self.precision
648 def bind_processor(self, dialect):
649 def process(value):
650 return value
651 return process
653 def result_processor(self, dialect, coltype):
654 def process(value):
655 return value
656 return process
658 Once the type is made, it's immediately usable::
660 table = Table('foo', meta,
661 Column('id', Integer, primary_key=True),
662 Column('data', MyType(16))
663 )
665 The ``get_col_spec()`` method will in most cases receive a keyword
666 argument ``type_expression`` which refers to the owning expression
667 of the type as being compiled, such as a :class:`_schema.Column` or
668 :func:`.cast` construct. This keyword is only sent if the method
669 accepts keyword arguments (e.g. ``**kw``) in its argument signature;
670 introspection is used to check for this in order to support legacy
671 forms of this function.
673 .. versionadded:: 1.0.0 the owning expression is passed to
674 the ``get_col_spec()`` method via the keyword argument
675 ``type_expression``, if it receives ``**kw`` in its signature.
677 """
679 __visit_name__ = "user_defined"
681 ensure_kwarg = "get_col_spec"
683 class Comparator(TypeEngine.Comparator):
684 __slots__ = ()
686 def _adapt_expression(self, op, other_comparator):
687 if hasattr(self.type, "adapt_operator"):
688 util.warn_deprecated(
689 "UserDefinedType.adapt_operator is deprecated. Create "
690 "a UserDefinedType.Comparator subclass instead which "
691 "generates the desired expression constructs, given a "
692 "particular operator."
693 )
694 return self.type.adapt_operator(op), self.type
695 else:
696 return super(
697 UserDefinedType.Comparator, self
698 )._adapt_expression(op, other_comparator)
700 comparator_factory = Comparator
702 def coerce_compared_value(self, op, value):
703 """Suggest a type for a 'coerced' Python value in an expression.
705 Default behavior for :class:`.UserDefinedType` is the
706 same as that of :class:`.TypeDecorator`; by default it returns
707 ``self``, assuming the compared value should be coerced into
708 the same type as this one. See
709 :meth:`.TypeDecorator.coerce_compared_value` for more detail.
711 """
713 return self
716class Emulated(object):
717 """Mixin for base types that emulate the behavior of a DB-native type.
719 An :class:`.Emulated` type will use an available database type
720 in conjunction with Python-side routines and/or database constraints
721 in order to approximate the behavior of a database type that is provided
722 natively by some backends. When a native-providing backend is in
723 use, the native version of the type is used. This native version
724 should include the :class:`.NativeForEmulated` mixin to allow it to be
725 distinguished from :class:`.Emulated`.
727 Current examples of :class:`.Emulated` are: :class:`.Interval`,
728 :class:`.Enum`, :class:`.Boolean`.
730 .. versionadded:: 1.2.0b3
732 """
734 def adapt_to_emulated(self, impltype, **kw):
735 """Given an impl class, adapt this type to the impl assuming "emulated".
737 The impl should also be an "emulated" version of this type,
738 most likely the same class as this type itself.
740 e.g.: sqltypes.Enum adapts to the Enum class.
742 """
743 return super(Emulated, self).adapt(impltype, **kw)
745 def adapt(self, impltype, **kw):
746 if hasattr(impltype, "adapt_emulated_to_native"):
748 if self.native:
749 # native support requested, dialect gave us a native
750 # implementor, pass control over to it
751 return impltype.adapt_emulated_to_native(self, **kw)
752 else:
753 # impltype adapts to native, and we are not native,
754 # so reject the impltype in favor of "us"
755 impltype = self.__class__
757 if issubclass(impltype, self.__class__):
758 return self.adapt_to_emulated(impltype, **kw)
759 else:
760 return super(Emulated, self).adapt(impltype, **kw)
763class NativeForEmulated(object):
764 """Indicates DB-native types supported by an :class:`.Emulated` type.
766 .. versionadded:: 1.2.0b3
768 """
770 @classmethod
771 def adapt_emulated_to_native(cls, impl, **kw):
772 """Given an impl, adapt this type's class to the impl assuming "native".
774 The impl will be an :class:`.Emulated` class but not a
775 :class:`.NativeForEmulated`.
777 e.g.: postgresql.ENUM produces a type given an Enum instance.
779 """
780 return cls(**kw)
783class TypeDecorator(SchemaEventTarget, TypeEngine):
784 """Allows the creation of types which add additional functionality
785 to an existing type.
787 This method is preferred to direct subclassing of SQLAlchemy's
788 built-in types as it ensures that all required functionality of
789 the underlying type is kept in place.
791 Typical usage::
793 import sqlalchemy.types as types
795 class MyType(types.TypeDecorator):
796 '''Prefixes Unicode values with "PREFIX:" on the way in and
797 strips it off on the way out.
798 '''
800 impl = types.Unicode
802 def process_bind_param(self, value, dialect):
803 return "PREFIX:" + value
805 def process_result_value(self, value, dialect):
806 return value[7:]
808 def copy(self, **kw):
809 return MyType(self.impl.length)
811 The class-level "impl" attribute is required, and can reference any
812 TypeEngine class. Alternatively, the load_dialect_impl() method
813 can be used to provide different type classes based on the dialect
814 given; in this case, the "impl" variable can reference
815 ``TypeEngine`` as a placeholder.
817 Types that receive a Python type that isn't similar to the ultimate type
818 used may want to define the :meth:`TypeDecorator.coerce_compared_value`
819 method. This is used to give the expression system a hint when coercing
820 Python objects into bind parameters within expressions. Consider this
821 expression::
823 mytable.c.somecol + datetime.date(2009, 5, 15)
825 Above, if "somecol" is an ``Integer`` variant, it makes sense that
826 we're doing date arithmetic, where above is usually interpreted
827 by databases as adding a number of days to the given date.
828 The expression system does the right thing by not attempting to
829 coerce the "date()" value into an integer-oriented bind parameter.
831 However, in the case of ``TypeDecorator``, we are usually changing an
832 incoming Python type to something new - ``TypeDecorator`` by default will
833 "coerce" the non-typed side to be the same type as itself. Such as below,
834 we define an "epoch" type that stores a date value as an integer::
836 class MyEpochType(types.TypeDecorator):
837 impl = types.Integer
839 epoch = datetime.date(1970, 1, 1)
841 def process_bind_param(self, value, dialect):
842 return (value - self.epoch).days
844 def process_result_value(self, value, dialect):
845 return self.epoch + timedelta(days=value)
847 Our expression of ``somecol + date`` with the above type will coerce the
848 "date" on the right side to also be treated as ``MyEpochType``.
850 This behavior can be overridden via the
851 :meth:`~TypeDecorator.coerce_compared_value` method, which returns a type
852 that should be used for the value of the expression. Below we set it such
853 that an integer value will be treated as an ``Integer``, and any other
854 value is assumed to be a date and will be treated as a ``MyEpochType``::
856 def coerce_compared_value(self, op, value):
857 if isinstance(value, int):
858 return Integer()
859 else:
860 return self
862 .. warning::
864 Note that the **behavior of coerce_compared_value is not inherited
865 by default from that of the base type**.
866 If the :class:`.TypeDecorator` is augmenting a
867 type that requires special logic for certain types of operators,
868 this method **must** be overridden. A key example is when decorating
869 the :class:`_postgresql.JSON` and :class:`_postgresql.JSONB` types;
870 the default rules of :meth:`.TypeEngine.coerce_compared_value` should
871 be used in order to deal with operators like index operations::
873 class MyJsonType(TypeDecorator):
874 impl = postgresql.JSON
876 def coerce_compared_value(self, op, value):
877 return self.impl.coerce_compared_value(op, value)
879 Without the above step, index operations such as ``mycol['foo']``
880 will cause the index value ``'foo'`` to be JSON encoded.
882 """
884 __visit_name__ = "type_decorator"
886 def __init__(self, *args, **kwargs):
887 """Construct a :class:`.TypeDecorator`.
889 Arguments sent here are passed to the constructor
890 of the class assigned to the ``impl`` class level attribute,
891 assuming the ``impl`` is a callable, and the resulting
892 object is assigned to the ``self.impl`` instance attribute
893 (thus overriding the class attribute of the same name).
895 If the class level ``impl`` is not a callable (the unusual case),
896 it will be assigned to the same instance attribute 'as-is',
897 ignoring those arguments passed to the constructor.
899 Subclasses can override this to customize the generation
900 of ``self.impl`` entirely.
902 """
904 if not hasattr(self.__class__, "impl"):
905 raise AssertionError(
906 "TypeDecorator implementations "
907 "require a class-level variable "
908 "'impl' which refers to the class of "
909 "type being decorated"
910 )
911 self.impl = to_instance(self.__class__.impl, *args, **kwargs)
913 coerce_to_is_types = (util.NoneType,)
914 """Specify those Python types which should be coerced at the expression
915 level to "IS <constant>" when compared using ``==`` (and same for
916 ``IS NOT`` in conjunction with ``!=``.
918 For most SQLAlchemy types, this includes ``NoneType``, as well as
919 ``bool``.
921 :class:`.TypeDecorator` modifies this list to only include ``NoneType``,
922 as typedecorator implementations that deal with boolean types are common.
924 Custom :class:`.TypeDecorator` classes can override this attribute to
925 return an empty tuple, in which case no values will be coerced to
926 constants.
928 """
930 class Comparator(TypeEngine.Comparator):
931 """A :class:`.TypeEngine.Comparator` that is specific to
932 :class:`.TypeDecorator`.
934 User-defined :class:`.TypeDecorator` classes should not typically
935 need to modify this.
938 """
940 __slots__ = ()
942 def operate(self, op, *other, **kwargs):
943 kwargs["_python_is_types"] = self.expr.type.coerce_to_is_types
944 return super(TypeDecorator.Comparator, self).operate(
945 op, *other, **kwargs
946 )
948 def reverse_operate(self, op, other, **kwargs):
949 kwargs["_python_is_types"] = self.expr.type.coerce_to_is_types
950 return super(TypeDecorator.Comparator, self).reverse_operate(
951 op, other, **kwargs
952 )
954 @property
955 def comparator_factory(self):
956 if TypeDecorator.Comparator in self.impl.comparator_factory.__mro__:
957 return self.impl.comparator_factory
958 else:
959 return type(
960 "TDComparator",
961 (TypeDecorator.Comparator, self.impl.comparator_factory),
962 {},
963 )
965 def _gen_dialect_impl(self, dialect):
966 """
967 #todo
968 """
969 adapted = dialect.type_descriptor(self)
970 if adapted is not self:
971 return adapted
973 # otherwise adapt the impl type, link
974 # to a copy of this TypeDecorator and return
975 # that.
976 typedesc = self._unwrapped_dialect_impl(dialect)
977 tt = self.copy()
978 if not isinstance(tt, self.__class__):
979 raise AssertionError(
980 "Type object %s does not properly "
981 "implement the copy() method, it must "
982 "return an object of type %s" % (self, self.__class__)
983 )
984 tt.impl = typedesc
985 return tt
987 @property
988 def _type_affinity(self):
989 """
990 #todo
991 """
992 return self.impl._type_affinity
994 def _set_parent(self, column):
995 """Support SchemaEventTarget"""
997 super(TypeDecorator, self)._set_parent(column)
999 if isinstance(self.impl, SchemaEventTarget):
1000 self.impl._set_parent(column)
1002 def _set_parent_with_dispatch(self, parent):
1003 """Support SchemaEventTarget"""
1005 super(TypeDecorator, self)._set_parent_with_dispatch(parent)
1007 if isinstance(self.impl, SchemaEventTarget):
1008 self.impl._set_parent_with_dispatch(parent)
1010 def type_engine(self, dialect):
1011 """Return a dialect-specific :class:`.TypeEngine` instance
1012 for this :class:`.TypeDecorator`.
1014 In most cases this returns a dialect-adapted form of
1015 the :class:`.TypeEngine` type represented by ``self.impl``.
1016 Makes usage of :meth:`dialect_impl` but also traverses
1017 into wrapped :class:`.TypeDecorator` instances.
1018 Behavior can be customized here by overriding
1019 :meth:`load_dialect_impl`.
1021 """
1022 adapted = dialect.type_descriptor(self)
1023 if not isinstance(adapted, type(self)):
1024 return adapted
1025 elif isinstance(self.impl, TypeDecorator):
1026 return self.impl.type_engine(dialect)
1027 else:
1028 return self.load_dialect_impl(dialect)
1030 def load_dialect_impl(self, dialect):
1031 """Return a :class:`.TypeEngine` object corresponding to a dialect.
1033 This is an end-user override hook that can be used to provide
1034 differing types depending on the given dialect. It is used
1035 by the :class:`.TypeDecorator` implementation of :meth:`type_engine`
1036 to help determine what type should ultimately be returned
1037 for a given :class:`.TypeDecorator`.
1039 By default returns ``self.impl``.
1041 """
1042 return self.impl
1044 def _unwrapped_dialect_impl(self, dialect):
1045 """Return the 'unwrapped' dialect impl for this type.
1047 For a type that applies wrapping logic (e.g. TypeDecorator), give
1048 us the real, actual dialect-level type that is used.
1050 This is used by TypeDecorator itself as well at least one case where
1051 dialects need to check that a particular specific dialect-level
1052 type is in use, within the :meth:`.DefaultDialect.set_input_sizes`
1053 method.
1055 """
1056 return self.load_dialect_impl(dialect).dialect_impl(dialect)
1058 def __getattr__(self, key):
1059 """Proxy all other undefined accessors to the underlying
1060 implementation."""
1061 return getattr(self.impl, key)
1063 def process_literal_param(self, value, dialect):
1064 """Receive a literal parameter value to be rendered inline within
1065 a statement.
1067 This method is used when the compiler renders a
1068 literal value without using binds, typically within DDL
1069 such as in the "server default" of a column or an expression
1070 within a CHECK constraint.
1072 The returned string will be rendered into the output string.
1074 .. versionadded:: 0.9.0
1076 """
1077 raise NotImplementedError()
1079 def process_bind_param(self, value, dialect):
1080 """Receive a bound parameter value to be converted.
1082 Subclasses override this method to return the
1083 value that should be passed along to the underlying
1084 :class:`.TypeEngine` object, and from there to the
1085 DBAPI ``execute()`` method.
1087 The operation could be anything desired to perform custom
1088 behavior, such as transforming or serializing data.
1089 This could also be used as a hook for validating logic.
1091 This operation should be designed with the reverse operation
1092 in mind, which would be the process_result_value method of
1093 this class.
1095 :param value: Data to operate upon, of any type expected by
1096 this method in the subclass. Can be ``None``.
1097 :param dialect: the :class:`.Dialect` in use.
1099 """
1101 raise NotImplementedError()
1103 def process_result_value(self, value, dialect):
1104 """Receive a result-row column value to be converted.
1106 Subclasses should implement this method to operate on data
1107 fetched from the database.
1109 Subclasses override this method to return the
1110 value that should be passed back to the application,
1111 given a value that is already processed by
1112 the underlying :class:`.TypeEngine` object, originally
1113 from the DBAPI cursor method ``fetchone()`` or similar.
1115 The operation could be anything desired to perform custom
1116 behavior, such as transforming or serializing data.
1117 This could also be used as a hook for validating logic.
1119 :param value: Data to operate upon, of any type expected by
1120 this method in the subclass. Can be ``None``.
1121 :param dialect: the :class:`.Dialect` in use.
1123 This operation should be designed to be reversible by
1124 the "process_bind_param" method of this class.
1126 """
1128 raise NotImplementedError()
1130 @util.memoized_property
1131 def _has_bind_processor(self):
1132 """memoized boolean, check if process_bind_param is implemented.
1134 Allows the base process_bind_param to raise
1135 NotImplementedError without needing to test an expensive
1136 exception throw.
1138 """
1140 return (
1141 self.__class__.process_bind_param.__code__
1142 is not TypeDecorator.process_bind_param.__code__
1143 )
1145 @util.memoized_property
1146 def _has_literal_processor(self):
1147 """memoized boolean, check if process_literal_param is implemented.
1150 """
1152 return (
1153 self.__class__.process_literal_param.__code__
1154 is not TypeDecorator.process_literal_param.__code__
1155 )
1157 def literal_processor(self, dialect):
1158 """Provide a literal processing function for the given
1159 :class:`.Dialect`.
1161 Subclasses here will typically override
1162 :meth:`.TypeDecorator.process_literal_param` instead of this method
1163 directly.
1165 By default, this method makes use of
1166 :meth:`.TypeDecorator.process_bind_param` if that method is
1167 implemented, where :meth:`.TypeDecorator.process_literal_param` is
1168 not. The rationale here is that :class:`.TypeDecorator` typically
1169 deals with Python conversions of data that are above the layer of
1170 database presentation. With the value converted by
1171 :meth:`.TypeDecorator.process_bind_param`, the underlying type will
1172 then handle whether it needs to be presented to the DBAPI as a bound
1173 parameter or to the database as an inline SQL value.
1175 .. versionadded:: 0.9.0
1177 """
1178 if self._has_literal_processor:
1179 process_param = self.process_literal_param
1180 elif self._has_bind_processor:
1181 # the bind processor should normally be OK
1182 # for TypeDecorator since it isn't doing DB-level
1183 # handling, the handling here won't be different for bound vs.
1184 # literals.
1185 process_param = self.process_bind_param
1186 else:
1187 process_param = None
1189 if process_param:
1190 impl_processor = self.impl.literal_processor(dialect)
1191 if impl_processor:
1193 def process(value):
1194 return impl_processor(process_param(value, dialect))
1196 else:
1198 def process(value):
1199 return process_param(value, dialect)
1201 return process
1202 else:
1203 return self.impl.literal_processor(dialect)
1205 def bind_processor(self, dialect):
1206 """Provide a bound value processing function for the
1207 given :class:`.Dialect`.
1209 This is the method that fulfills the :class:`.TypeEngine`
1210 contract for bound value conversion. :class:`.TypeDecorator`
1211 will wrap a user-defined implementation of
1212 :meth:`process_bind_param` here.
1214 User-defined code can override this method directly,
1215 though its likely best to use :meth:`process_bind_param` so that
1216 the processing provided by ``self.impl`` is maintained.
1218 :param dialect: Dialect instance in use.
1220 This method is the reverse counterpart to the
1221 :meth:`result_processor` method of this class.
1223 """
1224 if self._has_bind_processor:
1225 process_param = self.process_bind_param
1226 impl_processor = self.impl.bind_processor(dialect)
1227 if impl_processor:
1229 def process(value):
1230 return impl_processor(process_param(value, dialect))
1232 else:
1234 def process(value):
1235 return process_param(value, dialect)
1237 return process
1238 else:
1239 return self.impl.bind_processor(dialect)
1241 @util.memoized_property
1242 def _has_result_processor(self):
1243 """memoized boolean, check if process_result_value is implemented.
1245 Allows the base process_result_value to raise
1246 NotImplementedError without needing to test an expensive
1247 exception throw.
1249 """
1250 return (
1251 self.__class__.process_result_value.__code__
1252 is not TypeDecorator.process_result_value.__code__
1253 )
1255 def result_processor(self, dialect, coltype):
1256 """Provide a result value processing function for the given
1257 :class:`.Dialect`.
1259 This is the method that fulfills the :class:`.TypeEngine`
1260 contract for result value conversion. :class:`.TypeDecorator`
1261 will wrap a user-defined implementation of
1262 :meth:`process_result_value` here.
1264 User-defined code can override this method directly,
1265 though its likely best to use :meth:`process_result_value` so that
1266 the processing provided by ``self.impl`` is maintained.
1268 :param dialect: Dialect instance in use.
1269 :param coltype: A SQLAlchemy data type
1271 This method is the reverse counterpart to the
1272 :meth:`bind_processor` method of this class.
1274 """
1275 if self._has_result_processor:
1276 process_value = self.process_result_value
1277 impl_processor = self.impl.result_processor(dialect, coltype)
1278 if impl_processor:
1280 def process(value):
1281 return process_value(impl_processor(value), dialect)
1283 else:
1285 def process(value):
1286 return process_value(value, dialect)
1288 return process
1289 else:
1290 return self.impl.result_processor(dialect, coltype)
1292 @util.memoized_property
1293 def _has_bind_expression(self):
1294 return (
1295 self.__class__.bind_expression.__code__
1296 is not TypeDecorator.bind_expression.__code__
1297 ) or self.impl._has_bind_expression
1299 def bind_expression(self, bindparam):
1300 return self.impl.bind_expression(bindparam)
1302 @util.memoized_property
1303 def _has_column_expression(self):
1304 """memoized boolean, check if column_expression is implemented.
1306 Allows the method to be skipped for the vast majority of expression
1307 types that don't use this feature.
1309 """
1311 return (
1312 self.__class__.column_expression.__code__
1313 is not TypeDecorator.column_expression.__code__
1314 ) or self.impl._has_column_expression
1316 def column_expression(self, column):
1317 return self.impl.column_expression(column)
1319 def coerce_compared_value(self, op, value):
1320 """Suggest a type for a 'coerced' Python value in an expression.
1322 By default, returns self. This method is called by
1323 the expression system when an object using this type is
1324 on the left or right side of an expression against a plain Python
1325 object which does not yet have a SQLAlchemy type assigned::
1327 expr = table.c.somecolumn + 35
1329 Where above, if ``somecolumn`` uses this type, this method will
1330 be called with the value ``operator.add``
1331 and ``35``. The return value is whatever SQLAlchemy type should
1332 be used for ``35`` for this particular operation.
1334 """
1335 return self
1337 def copy(self, **kw):
1338 """Produce a copy of this :class:`.TypeDecorator` instance.
1340 This is a shallow copy and is provided to fulfill part of
1341 the :class:`.TypeEngine` contract. It usually does not
1342 need to be overridden unless the user-defined :class:`.TypeDecorator`
1343 has local state that should be deep-copied.
1345 """
1347 instance = self.__class__.__new__(self.__class__)
1348 instance.__dict__.update(self.__dict__)
1349 return instance
1351 def get_dbapi_type(self, dbapi):
1352 """Return the DBAPI type object represented by this
1353 :class:`.TypeDecorator`.
1355 By default this calls upon :meth:`.TypeEngine.get_dbapi_type` of the
1356 underlying "impl".
1357 """
1358 return self.impl.get_dbapi_type(dbapi)
1360 def compare_values(self, x, y):
1361 """Given two values, compare them for equality.
1363 By default this calls upon :meth:`.TypeEngine.compare_values`
1364 of the underlying "impl", which in turn usually
1365 uses the Python equals operator ``==``.
1367 This function is used by the ORM to compare
1368 an original-loaded value with an intercepted
1369 "changed" value, to determine if a net change
1370 has occurred.
1372 """
1373 return self.impl.compare_values(x, y)
1375 @property
1376 def sort_key_function(self):
1377 return self.impl.sort_key_function
1379 def __repr__(self):
1380 return util.generic_repr(self, to_inspect=self.impl)
1383class Variant(TypeDecorator):
1384 """A wrapping type that selects among a variety of
1385 implementations based on dialect in use.
1387 The :class:`.Variant` type is typically constructed
1388 using the :meth:`.TypeEngine.with_variant` method.
1390 .. seealso:: :meth:`.TypeEngine.with_variant` for an example of use.
1392 """
1394 def __init__(self, base, mapping):
1395 """Construct a new :class:`.Variant`.
1397 :param base: the base 'fallback' type
1398 :param mapping: dictionary of string dialect names to
1399 :class:`.TypeEngine` instances.
1401 """
1402 self.impl = base
1403 self.mapping = mapping
1405 def coerce_compared_value(self, operator, value):
1406 result = self.impl.coerce_compared_value(operator, value)
1407 if result is self.impl:
1408 return self
1409 else:
1410 return result
1412 def load_dialect_impl(self, dialect):
1413 if dialect.name in self.mapping:
1414 return self.mapping[dialect.name]
1415 else:
1416 return self.impl
1418 def _set_parent(self, column):
1419 """Support SchemaEventTarget"""
1421 if isinstance(self.impl, SchemaEventTarget):
1422 self.impl._set_parent(column)
1423 for impl in self.mapping.values():
1424 if isinstance(impl, SchemaEventTarget):
1425 impl._set_parent(column)
1427 def _set_parent_with_dispatch(self, parent):
1428 """Support SchemaEventTarget"""
1430 if isinstance(self.impl, SchemaEventTarget):
1431 self.impl._set_parent_with_dispatch(parent)
1432 for impl in self.mapping.values():
1433 if isinstance(impl, SchemaEventTarget):
1434 impl._set_parent_with_dispatch(parent)
1436 def with_variant(self, type_, dialect_name):
1437 r"""Return a new :class:`.Variant` which adds the given
1438 type + dialect name to the mapping, in addition to the
1439 mapping present in this :class:`.Variant`.
1441 :param type\_: a :class:`.TypeEngine` that will be selected
1442 as a variant from the originating type, when a dialect
1443 of the given name is in use.
1444 :param dialect_name: base name of the dialect which uses
1445 this type. (i.e. ``'postgresql'``, ``'mysql'``, etc.)
1447 """
1449 if dialect_name in self.mapping:
1450 raise exc.ArgumentError(
1451 "Dialect '%s' is already present in "
1452 "the mapping for this Variant" % dialect_name
1453 )
1454 mapping = self.mapping.copy()
1455 mapping[dialect_name] = type_
1456 return Variant(self.impl, mapping)
1458 @property
1459 def comparator_factory(self):
1460 """express comparison behavior in terms of the base type"""
1461 return self.impl.comparator_factory
1464def _reconstitute_comparator(expression):
1465 return expression.comparator
1468def to_instance(typeobj, *arg, **kw):
1469 if typeobj is None:
1470 return NULLTYPE
1472 if util.callable(typeobj):
1473 return typeobj(*arg, **kw)
1474 else:
1475 return typeobj
1478def adapt_type(typeobj, colspecs):
1479 if isinstance(typeobj, type):
1480 typeobj = typeobj()
1481 for t in typeobj.__class__.__mro__[0:-1]:
1482 try:
1483 impltype = colspecs[t]
1484 break
1485 except KeyError:
1486 pass
1487 else:
1488 # couldn't adapt - so just return the type itself
1489 # (it may be a user-defined type)
1490 return typeobj
1491 # if we adapted the given generic type to a database-specific type,
1492 # but it turns out the originally given "generic" type
1493 # is actually a subclass of our resulting type, then we were already
1494 # given a more specific type than that required; so use that.
1495 if issubclass(typeobj.__class__, impltype):
1496 return typeobj
1497 return typeobj.adapt(impltype)