Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UUID object has no attribute replace error in sync_enum_values command #84

Open
lotruheawea opened this issue Sep 16, 2024 · 4 comments

Comments

@lotruheawea
Copy link

lotruheawea commented Sep 16, 2024

Hi I try to reduce my problem to the most relevant bits. My ORM looks like this:

class UnitORM(Base):
    __tablename__ = "unit"
    __table_args__ = (UniqueConstraint("identifier", "identifier_type"),)

    id = Column(BigInteger, primary_key=True, autoincrement=True)
    resource_id: Mapped[uuid.UUID] = Column(
        UUID(as_uuid=True), nullable=False, unique=True
    )
    identifier_type: Mapped[IdentifierType] = Column(
        Enum(IdentifierType, name="identifier_type_enum"), nullable=False
    )
    identifier: Mapped[int] = Column(BigInteger, nullable=False)

I have updated the IdentifierType Enum like so:

class IdentifierType(enum.StrEnum):
    A = "a"
    B = "b"
    # this is new
    C = "c"

and got these migrations:

def upgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    op.sync_enum_values(
        "public",
        "identifier_type_enum",
        ["A", "B", "C"],
        [
            TableReference(
                table_schema="public", table_name="unit", column_name="identifier_type"
            )
        ],
        enum_values_to_rename=[],
    )
    # ### end Alembic commands ###


def downgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    op.sync_enum_values(
        "public",
        "identifier_type_enum",
        ["A", "B"],
        [
            TableReference(
                table_schema="public", table_name="unit", column_name="identifier_type"
            )
        ],
        enum_values_to_rename=[],
    )
    # ### end Alembic commands ###

And I get this error in my pytest-alembic.tests.test_up_down_consistency:

...
E               pytest_alembic.plugin.error.AlembicTestFailure: Failed to upgrade through each revision individually after performing a roundtrip upgrade -> downgrade -> upgrade cycle.
E               
E               Failing Revision:
E                   XXX
E               
E               Alembic Error:
E                   (builtins.AttributeError) 'UUID' object has no attribute 'replace'
E                   [SQL: INSERT INTO unit (id, resource_id, identifier_type, identifier) VALUES (%(id)s, %(resource_id)s, %(identifier_type)s, %(identifier)s)]

How can this be solved? Thank you very much for your support!

@RustyGuard
Copy link
Member

I have tried to reproduce your issue in a test case. It passes. Either you have a problem with your test or I am missing something that you have in it.

@lotruheawea
Copy link
Author

Mmh, we use sqlalchemy v1.4.52 and alembic v.1.13.2. Maybe it is because we use the old version of sqlalchemy?

@RustyGuard
Copy link
Member

Our tests run with different sqlalchemy versions. sync_enum_values does not use insert under the hood. I'm inclined to think that something is wrong in your test

@lotruheawea
Copy link
Author

I tried to do some research, but also found this dead end: https://stackoverflow.com/questions/59082387/attributeerror-uuid-object-has-no-attribute-replace. I am not sure, if this is helpful.
In the end, my test is the native pytest-alembic.tests.test_up_down_consistency (version v0.11.0)... I can also post the initial migration, if helpful:

def upgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    op.create_table(
        "unit",
        sa.Column("id", sa.BigInteger(), autoincrement=True, nullable=False),
        sa.Column("resource_id", postgresql.UUID(as_uuid=True), nullable=False),
        sa.Column(
            "identifier_type",
            sa.Enum(
                "A",
                "B",
                name="identifier_type_enum",
            ),
            nullable=False,
        ),
        sa.Column("identifier", sa.BigInteger(), nullable=False),
        sa.Column(
            "created",
            sa.DateTime(timezone=True),
            server_default=sa.text("now()"),
            nullable=False,
        ),
        sa.PrimaryKeyConstraint("id", name=op.f("pk_unit")),
        sa.UniqueConstraint(
            "identifier", "identifier_type", name=op.f("uq_unit_identifier")
        ),
        sa.UniqueConstraint("resource_id", name=op.f("uq_unit_resource_id")),
    )
    # ### end Alembic commands ###


def downgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_table("unit")
    # ### end Alembic commands ###

    # Manually added commands to drop enums
    sa.Enum(name="identifier_type_enum").drop(op.get_bind(), checkfirst=False)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants