From 9645938138e998190d20bbd6c955eeca6a024d4d Mon Sep 17 00:00:00 2001 From: Jonathan Wadin Date: Tue, 30 Sep 2025 22:24:19 +0200 Subject: [PATCH] Fix AttributeError with Sequence defaults in instant_defaults_listener The instant_defaults_listener was raising AttributeError when encountering columns with Sequence defaults, as it attempted to access the 'arg' attribute which doesn't exist on Sequence objects (only on ColumnDefault objects). This occurred when using force_instant_defaults() with models that have database sequences for primary keys or other columns, causing failures in scenarios like Celery task result storage. Resolution: - Add hasattr check for 'arg' attribute before accessing it - This generic approach handles Sequence and any other default types that don't have an 'arg' attribute - Add test case covering Sequence defaults to prevent regression --- sqlalchemy_utils/listeners.py | 4 +++- tests/test_instant_defaults_listener.py | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/sqlalchemy_utils/listeners.py b/sqlalchemy_utils/listeners.py index 03acb2f1..c2ed982f 100644 --- a/sqlalchemy_utils/listeners.py +++ b/sqlalchemy_utils/listeners.py @@ -24,7 +24,9 @@ def instant_defaults_listener(target, args, kwargs): for key, column in sa.inspect(target.__class__).columns.items(): if hasattr(column, 'default') and column.default is not None: - if callable(column.default.arg): + if not hasattr(column.default, 'arg'): + continue + elif callable(column.default.arg): kwargs[key] = column.default.arg(target) else: kwargs[key] = column.default.arg diff --git a/tests/test_instant_defaults_listener.py b/tests/test_instant_defaults_listener.py index 7db05f73..d3c9d7e8 100644 --- a/tests/test_instant_defaults_listener.py +++ b/tests/test_instant_defaults_listener.py @@ -28,6 +28,20 @@ def byline(self, value): return Article +@pytest.fixture +def Document(Base): + class Document(Base): + __tablename__ = 'document' + id = sa.Column( + sa.Integer, + sa.Sequence('document_id_seq'), + primary_key=True + ) + title = sa.Column(sa.Unicode(255), default='Untitled') + + return Document + + class TestInstantDefaultListener: def test_assigns_defaults_on_object_construction(self, Article): article = Article() @@ -40,3 +54,8 @@ def test_callables_as_defaults(self, Article): def test_override_default_with_setter_function(self, Article): article = Article(byline='provided byline') assert article.byline == 'provided byline' + + def test_handles_sequence_defaults(self, Document): + document = Document() + assert document.title == 'Untitled' + assert document.id is None