Failing to create revision using alembics "Offline Mode"
Closed this issue · 6 comments
Thanks for this tool. Enums were always a pain to manage in my revisions.
A big part of my application relies on alembics "Offline Mode" (https://alembic.sqlalchemy.org/en/latest/offline.html) to generate revisions as SQL file e.g. alembic upgrade base:head --sql > test.sql
. Unfortunately this currently does not work with alembic-postgresql-enum.
The issue is that an offline migration can not contain any statement that pulls some results into memory via a SELECT
.
therefore throws 'NoneType' object has no attribute 'scalar'
error when using --sql
option.
I was able to get it working by changing the linked lines to
default_value = None
if context.is_offline_mode():
connection.execute(...)
else:
default_value = connection.execute(...).scalar()
However, I guess this might interfere with the correct handling of default values, but for my use case where I don't have any default values it seems to work fine. Maybe you want to consider adding support for offline revisions (or if that is not an option, then a note to the readme mentioning that offline revisions are currently not possible could be helpful)
I'll explore alternatives for handling default values
Thanks for the quick action. Unfortunately, this issue is not solved. None of the linked changes addresses my initial problem.
The get_column_default
function still fetches columns which will not work in Offline Mode.
The same error still persists ( 'NoneType' object has no attribute 'scalar'
) as a result of this section:
This update tweaked the way migrations generate. Have you tried generating a new one?
I am pretty sure that your update did not touch anything related to alembics offline mode.
You can introduce the following test case to see the error yourself. Notice the optional parameter in MigrationContext.configure(connection, opts={'as_sql': True})
which is passed by alembic to the migration context when offline mode is used (e.g. when using the --sql
flag on the command line).
This test case will currently fail.
def test_sync_enum_values_offline(connection: 'Connection'):
old_enum_variants = ["active", "passive"]
database_schema = get_schema_with_enum_variants(old_enum_variants)
database_schema.create_all(connection)
new_enum_variants = old_enum_variants.copy()
new_enum_variants.append('banned')
mc = MigrationContext.configure(connection, opts={'as_sql': True})
ops = Operations(mc)
ops.sync_enum_values(DEFAULT_SCHEMA, USER_STATUS_ENUM_NAME, new_enum_variants,
((USER_TABLE_NAME, USER_STATUS_COLUMN_NAME),))
New migrations will contain:
ops.sync_enum_values(DEFAULT_SCHEMA, USER_STATUS_ENUM_NAME, new_enum_variants,
[TableReference(USER_TABLE_NAME, USER_STATUS_COLUMN_NAME)])
There is TableReference object instead of tuple. The change was that default value is now saved during migration generation not execution.
When tuple is passed to the function it works the old way to maintain backward compatibility
okay I got it now. Thanks for your help!