diff options
| author | mike bayer <mike_mp@zzzcomputing.com> | 2020-12-09 14:33:27 +0000 |
|---|---|---|
| committer | Gerrit Code Review <gerrit@bbpush.zzzcomputing.com> | 2020-12-09 14:33:27 +0000 |
| commit | 2672466b3a761949f146d26adbab12a58900e46d (patch) | |
| tree | 6b6f3926fc01fad1e2322606c3000c23ff8e21b9 /lib/sqlalchemy/sql | |
| parent | c736eef8b35841af89ec19469aa496585efd3865 (diff) | |
| parent | b71e46f0470964358d44aec08f940260f78691f0 (diff) | |
| download | sqlalchemy-2672466b3a761949f146d26adbab12a58900e46d.tar.gz | |
Merge "Implement `TypeEngine.as_generic`"
Diffstat (limited to 'lib/sqlalchemy/sql')
| -rw-r--r-- | lib/sqlalchemy/sql/events.py | 3 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/sqltypes.py | 12 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/type_api.py | 101 |
3 files changed, 85 insertions, 31 deletions
diff --git a/lib/sqlalchemy/sql/events.py b/lib/sqlalchemy/sql/events.py index 58d04f7aa..797ca697f 100644 --- a/lib/sqlalchemy/sql/events.py +++ b/lib/sqlalchemy/sql/events.py @@ -314,4 +314,7 @@ class DDLEvents(event.Events): :ref:`automap_intercepting_columns` - in the :ref:`automap_toplevel` documentation + :ref:`metadata_reflection_dbagnostic_types` - in + the :ref:`metadata_reflection_toplevel` documentation + """ diff --git a/lib/sqlalchemy/sql/sqltypes.py b/lib/sqlalchemy/sql/sqltypes.py index 45d4f0b7f..581573d17 100644 --- a/lib/sqlalchemy/sql/sqltypes.py +++ b/lib/sqlalchemy/sql/sqltypes.py @@ -1607,6 +1607,18 @@ class Enum(Emulated, String, SchemaType): to_inspect=[Enum, SchemaType], ) + def as_generic(self, allow_nulltype=False): + if hasattr(self, "enums"): + args = self.enums + else: + raise NotImplementedError( + "TypeEngine.as_generic() heuristic " + "is undefined for types that inherit Enum but do not have " + "an `enums` attribute." + ) + + return util.constructor_copy(self, self._generic_type_affinity, *args) + def adapt_to_emulated(self, impltype, **kw): kw.setdefault("_expect_unicode", self._expect_unicode) kw.setdefault("validate_strings", self.validate_strings) diff --git a/lib/sqlalchemy/sql/type_api.py b/lib/sqlalchemy/sql/type_api.py index bca6e9020..b48886cca 100644 --- a/lib/sqlalchemy/sql/type_api.py +++ b/lib/sqlalchemy/sql/type_api.py @@ -17,7 +17,6 @@ from .visitors import TraversibleType from .. import exc from .. import util - # these are back-assigned by sqltypes. BOOLEANTYPE = None INTEGERTYPE = None @@ -372,10 +371,7 @@ class TypeEngine(Traversible): """ - return ( - self.__class__.bind_expression.__code__ - is not TypeEngine.bind_expression.__code__ - ) + return util.method_is_overridden(self, TypeEngine.bind_expression) @staticmethod def _to_instance(cls_or_self): @@ -456,12 +452,13 @@ class TypeEngine(Traversible): else: return self.__class__ - @classmethod - def _is_generic_type(cls): - n = cls.__name__ - return n.upper() != n - + @util.memoized_property def _generic_type_affinity(self): + best_camelcase = None + best_uppercase = None + + if not isinstance(self, (TypeEngine, UserDefinedType)): + return self.__class__ for t in self.__class__.__mro__: if ( @@ -470,13 +467,56 @@ class TypeEngine(Traversible): "sqlalchemy.sql.sqltypes", "sqlalchemy.sql.type_api", ) - and t._is_generic_type() + and issubclass(t, TypeEngine) + and t is not TypeEngine + and t.__name__[0] != "_" ): - if t in (TypeEngine, UserDefinedType): - return NULLTYPE.__class__ - return t - else: - return self.__class__ + if t.__name__.isupper() and not best_uppercase: + best_uppercase = t + elif not t.__name__.isupper() and not best_camelcase: + best_camelcase = t + + return best_camelcase or best_uppercase or NULLTYPE.__class__ + + def as_generic(self, allow_nulltype=False): + """ + Return an instance of the generic type corresponding to this type + using heuristic rule. The method may be overridden if this + heuristic rule is not sufficient. + + >>> from sqlalchemy.dialects.mysql import INTEGER + >>> INTEGER(display_width=4).as_generic() + Integer() + + >>> from sqlalchemy.dialects.mysql import NVARCHAR + >>> NVARCHAR(length=100).as_generic() + Unicode(length=100) + + .. versionadded:: 1.4.0b2 + + + .. seealso:: + + :ref:`metadata_reflection_dbagnostic_types` - describes the + use of :meth:`_types.TypeEngine.as_generic` in conjunction with + the :meth:`_sql.DDLEvents.column_reflect` event, which is its + intended use. + + """ + if ( + not allow_nulltype + and self._generic_type_affinity == NULLTYPE.__class__ + ): + raise NotImplementedError( + "Default TypeEngine.as_generic() " + "heuristic method was unsuccessful for {}. A custom " + "as_generic() method must be implemented for this " + "type class.".format( + self.__class__.__module__ + "." + self.__class__.__name__ + ) + ) + + return util.constructor_copy(self, self._generic_type_affinity) def dialect_impl(self, dialect): """Return a dialect-specific implementation for this @@ -1171,18 +1211,16 @@ class TypeDecorator(SchemaEventTarget, TypeEngine): """ - return ( - self.__class__.process_bind_param.__code__ - is not TypeDecorator.process_bind_param.__code__ + return util.method_is_overridden( + self, TypeDecorator.process_bind_param ) @util.memoized_property def _has_literal_processor(self): """memoized boolean, check if process_literal_param is implemented.""" - return ( - self.__class__.process_literal_param.__code__ - is not TypeDecorator.process_literal_param.__code__ + return util.method_is_overridden( + self, TypeDecorator.process_literal_param ) def literal_processor(self, dialect): @@ -1278,9 +1316,9 @@ class TypeDecorator(SchemaEventTarget, TypeEngine): exception throw. """ - return ( - self.__class__.process_result_value.__code__ - is not TypeDecorator.process_result_value.__code__ + + return util.method_is_overridden( + self, TypeDecorator.process_result_value ) def result_processor(self, dialect, coltype): @@ -1322,10 +1360,11 @@ class TypeDecorator(SchemaEventTarget, TypeEngine): @util.memoized_property def _has_bind_expression(self): + return ( - self.__class__.bind_expression.__code__ - is not TypeDecorator.bind_expression.__code__ - ) or self.impl._has_bind_expression + util.method_is_overridden(self, TypeDecorator.bind_expression) + or self.impl._has_bind_expression + ) def bind_expression(self, bindparam): return self.impl.bind_expression(bindparam) @@ -1340,9 +1379,9 @@ class TypeDecorator(SchemaEventTarget, TypeEngine): """ return ( - self.__class__.column_expression.__code__ - is not TypeDecorator.column_expression.__code__ - ) or self.impl._has_column_expression + util.method_is_overridden(self, TypeDecorator.column_expression) + or self.impl._has_column_expression + ) def column_expression(self, column): return self.impl.column_expression(column) |
