summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/sql
diff options
context:
space:
mode:
authorAlex Grönholm <alex.gronholm@nextday.fi>2016-02-02 14:20:17 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2016-02-02 14:21:54 -0500
commit5401c4d8514aa42e8ac4b5579454e68151e78a93 (patch)
treeb7506b8c050afc39bb724a55a476c23c94f779ee /lib/sqlalchemy/sql
parent86660fef7ee16578330334abfba58be1304e3f97 (diff)
downloadsqlalchemy-5401c4d8514aa42e8ac4b5579454e68151e78a93.tar.gz
- Initial implementation of support for PEP-435 enumerated types
within the Enum type.
Diffstat (limited to 'lib/sqlalchemy/sql')
-rw-r--r--lib/sqlalchemy/sql/sqltypes.py77
1 files changed, 72 insertions, 5 deletions
diff --git a/lib/sqlalchemy/sql/sqltypes.py b/lib/sqlalchemy/sql/sqltypes.py
index d198d3912..21e57d519 100644
--- a/lib/sqlalchemy/sql/sqltypes.py
+++ b/lib/sqlalchemy/sql/sqltypes.py
@@ -1103,7 +1103,8 @@ class Enum(String, SchemaType):
Keyword arguments which don't apply to a specific backend are ignored
by that backend.
- :param \*enums: string or unicode enumeration labels. If unicode
+ :param \*enums: either exactly one PEP 435 compliant enumerated type
+ or one or more string or unicode enumeration labels. If unicode
labels are present, the `convert_unicode` flag is auto-enabled.
:param convert_unicode: Enable unicode-aware bind parameter and
@@ -1124,7 +1125,9 @@ class Enum(String, SchemaType):
:param name: The name of this type. This is required for Postgresql
and any future supported database which requires an explicitly
named type, or an explicitly named constraint in order to generate
- the type and/or a table that uses it.
+ the type and/or a table that uses it. If an :class:`~enum.Enum`
+ class was used, its name (converted to lower case) is used by
+ default.
:param native_enum: Use the database's native ENUM type when
available. Defaults to True. When False, uses VARCHAR + check
@@ -1153,11 +1156,20 @@ class Enum(String, SchemaType):
.. versionadded:: 0.8
"""
- self.enums = enums
+ if len(enums) == 1 and hasattr(enums[0], '__members__'):
+ self.enums = list(enums[0].__members__)
+ self.enum_class = enums[0]
+ kw.setdefault('name', enums[0].__name__.lower())
+ self.key_lookup = dict((value, key) for key, value in enums[0].__members__.items())
+ self.value_lookup = enums[0].__members__.copy()
+ else:
+ self.enums = enums
+ self.enum_class = self.key_lookup = self.value_lookup = None
+
self.native_enum = kw.pop('native_enum', True)
convert_unicode = kw.pop('convert_unicode', None)
if convert_unicode is None:
- for e in enums:
+ for e in self.enums:
if isinstance(e, util.text_type):
convert_unicode = True
break
@@ -1203,6 +1215,7 @@ class Enum(String, SchemaType):
metadata = kw.pop('metadata', self.metadata)
_create_events = kw.pop('_create_events', False)
if issubclass(impltype, Enum):
+ args = [self.enum_class] if self.enum_class is not None else self.enums
return impltype(name=self.name,
schema=schema,
metadata=metadata,
@@ -1210,12 +1223,66 @@ class Enum(String, SchemaType):
native_enum=self.native_enum,
inherit_schema=self.inherit_schema,
_create_events=_create_events,
- *self.enums,
+ *args,
**kw)
else:
# TODO: why would we be here?
return super(Enum, self).adapt(impltype, **kw)
+ def literal_processor(self, dialect):
+ parent_processor = super(Enum, self).literal_processor(dialect)
+ if self.key_lookup:
+ def process(value):
+ value = self.key_lookup.get(value, value)
+ if parent_processor:
+ return parent_processor(value)
+
+ return process
+ else:
+ return parent_processor
+
+ def bind_processor(self, dialect):
+ def process(value):
+ if isinstance(value, util.string_types):
+ if value not in self.enums:
+ raise LookupError(
+ '"%s" is not among the defined enum values' %
+ value)
+ elif self.key_lookup and value in self.key_lookup:
+ value = self.key_lookup[value]
+
+ if parent_processor:
+ value = parent_processor(value)
+ return value
+
+ parent_processor = super(Enum, self).bind_processor(dialect)
+ return process
+
+ def result_processor(self, dialect, coltype):
+ parent_processor = super(Enum, self).result_processor(dialect,
+ coltype)
+ if self.value_lookup:
+ def process(value):
+ if parent_processor:
+ value = parent_processor(value)
+
+ try:
+ return self.value_lookup[value]
+ except KeyError:
+ raise LookupError('No such member in enum class %s: %s' %
+ (self.enum_class.__name__, value))
+
+ return process
+ else:
+ return parent_processor
+
+ @property
+ def python_type(self):
+ if self.enum_class:
+ return self.enum_class
+ else:
+ return super(Enum, self).python_type
+
class PickleType(TypeDecorator):