sqlalchemy / sqlalchemy/alembic
document this workaround for custom SchemaType + per-type CheckConstraint
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 4.4k
- Forks
- 375
- PR merge metrics
- No merged PRs in 30d
Description
Migrated issue, originally created by Adrian (@thiefmaster)
I'm using this custom type in SQLAlchemy:
class PyIntEnum(TypeDecorator, SchemaType):
"""Custom type which handles values from a PEP-435 Enum.
In addition to the Python-side validation this also creates a
CHECK constraint to ensure only valid enum members are stored.
:param enum: the Enum repesented by this type's values
:raise ValueError: when using/loading a value not in the Enum.
"""
impl = SmallInteger
def __init__(self, enum=None):
self.enum = enum
TypeDecorator.__init__(self)
SchemaType.__init__(self)
def process_bind_param(self, value, dialect):
if value is None:
return None
if not isinstance(value, self.enum):
# Convert plain (int) value to enum member
value = self.enum(value)
return _EnumIntWrapper(value)
def process_result_value(self, value, dialect):
if value is None:
return None
# Note: This raises a ValueError if `value` is not in the Enum.
return self.enum(value)
def _set_table(self, column, table):
e = CheckConstraint(type_coerce(column, self).in_(x.value for x in self.enum))
assert e.table is table
def alembic_render_type(self, autogen_context):
imports = autogen_context['imports']
imports.add('from indico.core.db.sqlalchemy import PyIntEnum')
imports.add('from {} import {}'.format(self.enum.__module__, self.enum.__name__))
return '{}({})'.format(type(self).__name__, self.enum.__name__)
The alembic_render_type is called from a render_item function.
Everything works fine, but when autogenerating a revision I end up with this in the op.create_table call (unrelated columns etc. omitted when pasting it here):
op.create_table('foobar',
sa.Column('state', PyIntEnum(RequestState), nullable=False),
sa.CheckConstraint('foobar.state IN (%(param_1)s, %(param_2)s, %(param_3)s)'))
There are no check constraints defined manually, only the one added by the custom type.
I believe Alembic shouldn't add a CheckConstraint for this. Is there any way to indicate that the constraint is handled by the type and thus doesn't belong into the table definition?
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the custom PyIntEnum example and the alembic_render_type/render_item path described in the issue. Determine how the generated CheckConstraint should be handled, then document the workaround and the expected autogenerate output. Done means the behavior and workaround are clear to users; no documentation file is named in the issue.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python, sqlalchemy
- Domain
- database, documentation
- Issue type
- Documentation
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100