question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

alembic migrations giving nullable wrongly at times

See original GitHub issue

This seems to be a weird issue.

When I add __versioned__ for the first time to a model and create an alembic migration with:

alembic migrate -m "test"

It gives:

op.create_table('mytable_version',
    sa.Column('mycol', sa.BigInteger(), autoincrement=False, nullable=False),
    ....
)

Then when I run:

alembic upgrade
alembic migrate -m "test"

I was expecting it to say “no changes found” But it does detect changes and is saying that nullable=True now:

with op.batch_alter_table('mytable_version', schema=None) as batch_op:
        batch_op.alter_column('mycol', existing_type=sa.BigInteger(), nullable=True, autoincrement=False)

This seems to be consistently reproducible - the first time alembic is generating nullable=False. Then second time alembic is generating nullable=True

Versions I use:

$ venv/bin/pip list | grep -i sqla
Flask-SQLAlchemy           2.5.1
marshmallow-sqlalchemy     0.28.1
SQLAlchemy                 1.4.40
SQLAlchemy-Continuum       1.3.12
SQLAlchemy-Utils           0.38.3
sqlalchemy2-stubs          0.0.2a24

Issue Analytics

  • State:open
  • Created a year ago
  • Comments:5 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
AbdealiLoKocommented, Sep 7, 2022

Found that this was happenign because of the col._copy() function in sqlalchemy After we “copy” the column - we are setting the nullable = True/False But the value for _user_defined_nullable is still the previous value from the parent table. So, when we COPY - the parent table’s nullable is used.

https://github.com/sqlalchemy/sqlalchemy/blob/rel_1_4_41/lib/sqlalchemy/sql/schema.py#L2018

0reactions
indiVar0508commented, Aug 29, 2022

Adding the column_copy.nullable in condition makes sure that if for a non-PK Column nullable is set to False, the versioned col also follow that property.

to reproduce the above issue mentioned in thread i created below shown demo model.

from sqlalchemy import Column, BigInteger, Integer
from sqlalchemy.orm import declarative_base, configure_mappers
from sqlalchemy_continuum import make_versioned

Base = declarative_base()
make_versioned(user_cls=None)

class myTable(Base):
    __versioned__ = {}
    __tablename__='my_table'
    id = Column(Integer, primary_key=True, autoincrement=True)
    myCol = Column(BigInteger, autoincrement=True, nullable=False)

configure_mappers()

and used below mentioned command(s) to generate issue

  1. alembic revision --autogenerate -m "first_commit"
  2. alembic upgrade head
  3. alembic revision --autogenerate -m "without_change_commit"

alembic revision --autogenerate -m “without_change_commit” INFO [alembic.runtime.migration] Context impl SQLiteImpl. INFO [alembic.runtime.migration] Will assume non-transactional DDL. INFO [alembic.autogenerate.compare] Detected NULL on column ‘my_table_version.myCol’ Generating /home/sqlalchemy- continuum/tracker_with_change/versions/4a48e12e7a8d_without_change_commit.py … done

and after that alembic generated upgrade and downgrade methods post commit without_change_commit as shown below

def upgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    op.alter_column('my_table_version', 'myCol',
               existing_type=sa.INTEGER(), # In my case even column type changed, i am assuming it happened because there was no data in table(s)
               nullable=True,
               autoincrement=False)
    # ### end Alembic commands ###


def downgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    op.alter_column('my_table_version', 'myCol',
               existing_type=sa.INTEGER(),
               nullable=False,
               autoincrement=False)
    # ### end Alembic commands ###

but after adding that condition to add a condn that non-PK col can also have nullable=False when i ran for new sqlite file with new alembic init and then second commit without_change_commit it generated empty upgrade and downgrade methods with no changes detected

alembic revision --autogenerate -m “without_change_commit” INFO [alembic.runtime.migration] Context impl SQLiteImpl. INFO [alembic.runtime.migration] Will assume non-transactional DDL. Generating /home/sqlalchemy- continuum/tracker_with_change/versions/19acafbbcbfc_without_change_commit.py … done

def upgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    pass
    # ### end Alembic commands ###


def downgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    pass
    # ### end Alembic commands ###

i might be wrong also here as later i saw that a testcase is there specific for this behavior.

version i had while trying to replicate the issue

Flask-SQLAlchemy       2.5.1   
marshmallow-sqlalchemy 0.28.1  
SQLAlchemy             1.4.40  
SQLAlchemy-Continuum   1.3.12  
SQLAlchemy-i18n        1.1.0   
SQLAlchemy-Utils       0.38.3  
sqlalchemy2-stubs      0.0.2a24
Read more comments on GitHub >

github_iconTop Results From Across the Web

MSSQL needs "NOT NULL" sent explicitly for a change in type ...
Looks like in alembic when we do an alter_column() to change the type of a column type_= it is ignoring the existing_nullable=True and...
Read more >
No changes detected in Alembic autogeneration of migrations ...
Excerpt from the Alembic documentation: Autogenerate will by default detect: Table additions, removals. Column additions, removals. Change of nullable status on ...
Read more >
Alembic: How to Add a Non-Nullable Field to a Populated Table
It is quite easy to add a non-nullable field to an empty table. Any migration tool, including Alembic, can automatically generate a migration...
Read more >
alter_column Issue (Attempting to Change Column Type)
I'm attempting to use alembic to convert a SQLAlchemy DateTime() field to a SQLAlchemy ... However, running this migration gives me the following...
Read more >
Alembic: setting a column to nullable=False if it already has ...
Instead of having to manually make the right changes by hand in the database every time you upgrade your code, you can keep...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found