Skip to content

Commit b8ecbde

Browse files
committed
fix @db.declared_attr(with_table=True) override
* so that overwritten methods are not called * refs #659
1 parent 849616e commit b8ecbde

File tree

2 files changed

+30
-1
lines changed

2 files changed

+30
-1
lines changed

src/gino/declarative.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,12 @@ def __new__(mcs, name, bases, namespace, **kwargs):
116116
if rv.__table__ is None:
117117
rv.__table__ = getattr(rv, "_init_table")(rv)
118118

119-
for each_cls in rv.__mro__[::-1]:
119+
visited = set()
120+
for each_cls in rv.__mro__:
120121
for k, v in getattr(each_cls, "__namespace__", each_cls.__dict__).items():
122+
if k in visited:
123+
continue
124+
visited.add(k)
121125
if callable(v) and getattr(v, "__declared_attr_with_table__", False):
122126
setattr(rv, k, v(rv))
123127
return rv

tests/test_declarative.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,3 +373,28 @@ def field(self):
373373

374374
assert len(Model.__table__.columns) == 1
375375
assert Model().field == "field is a const value"
376+
377+
378+
async def test_declared_attr_with_table_override():
379+
mixin_called = False
380+
override_called = False
381+
382+
class ModelMixin:
383+
@db.declared_attr(with_table=True)
384+
def some(self):
385+
nonlocal mixin_called
386+
mixin_called = True
387+
return "mixin"
388+
389+
class Model(db.Model, ModelMixin):
390+
__tablename__ = "model8"
391+
392+
@db.declared_attr(with_table=True)
393+
def some(self):
394+
nonlocal override_called
395+
override_called = True
396+
return "override"
397+
398+
assert Model.some == "override"
399+
assert not mixin_called
400+
assert override_called

0 commit comments

Comments
 (0)