SqlAlchemy dataclass behavior and declarative mixins: AttributeError: can't set attribute

56
November 30, 2021, at 12:10 PM

I have a set of classes that I drafted as pure python dataclasses. Here's a stripped down example that behaves as I would expect:

from dataclasses import dataclass
from abc import ABC
@dataclass
class Owner:
    name: str = ""
@dataclass
class OwnedThing(ABC):
    owner: Owner = None
@dataclass
class Thing1(OwnedThing):
    name: str = ""

owner = Owner(name="foo")
thing = Thing1( name="bar", owner=owner)
print(thing.owner.name)

Here we have a base class that establishes that a number of derived classes will all have an "owner" object. Assigning the owner is straightforward.

When I tried to add SqlAlchemy for persistence, I would like to keep the general inheritance structure so I don't have to repeat this owner-thing relationship for all of the varieties of owned things. However, when I do, I can no longer assign an owner class instance to the .owner attribute:

from dataclasses import dataclass,field
from abc import ABC
from sqlalchemy.orm import declarative_mixin, declared_attr, relationship
from sqlalchemy import Column, ForeignKey
@dataclass
class Owner:
    name: str = ""
@declarative_mixin
@dataclass
class OwnedThing(ABC):
    owner_id: int = field(init=False, default=None)
    owner: Owner = None
    @declared_attr
    def owner_id(cls):
        return Column('owner_id', ForeignKey('owner.id'))
    @declared_attr
    def owner(cls):
        return relationship(Owner)
@dataclass
class Thing1(OwnedThing):
    name: str = ""

owner = Owner(name="foo")
thing = Thing1( name="bar", owner=owner)
print(thing.owner.name)

This results in this stack trace:

/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/dataclasses.py:658: SAWarning: Unmanaged access of declarative attribute owner_id from non-mapped class OwnedThing
  default = getattr(cls, a_name, MISSING)
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/dataclasses.py:658: SAWarning: Unmanaged access of declarative attribute owner from non-mapped class OwnedThing
  default = getattr(cls, a_name, MISSING)
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/dataclasses.py:842: SAWarning: Unmanaged access of declarative attribute owner_id from non-mapped class OwnedThing
  if isinstance(getattr(cls, f.name, None), Field):
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/dataclasses.py:842: SAWarning: Unmanaged access of declarative attribute owner from non-mapped class OwnedThing
  if isinstance(getattr(cls, f.name, None), Field):
Traceback (most recent call last):
  File "test_case_sql.py", line 30, in <module>
    thing = Thing1( name="bar", owner=owner)
  File "<string>", line 2, in __init__
AttributeError: can't set attribute

Note that when I skip having a base class, things work as I'd expect, without error:

from dataclasses import dataclass,field
from abc import ABC
from sqlalchemy.orm import declarative_mixin, declared_attr, relationship
from sqlalchemy import Column, ForeignKey,Integer
@dataclass
class Owner:
    name: str = ""

@dataclass
class Thing1:
    owner_id: int = Column(Integer)
    owner: Owner = relationship("Owner")
    name: str = ""

owner = Owner(name="foo")
thing = Thing1( name="bar", owner=owner)
print(thing.owner.name)

I don't know enough about the internals of SqlAlchemy to understand what I'm doing wrong, and I haven't seen anyone else run into this problem before. Can someone help me keep using data-classes and mixins?

READ ALSO
can you combine text() equals

can you combine text() equals

Can you combine all these into 1 statement using text() === ?

62
Running the command node dist/index.js gives an error related to Typescript files in src folder

Running the command node dist/index.js gives an error related to Typescript files in src folder

I have a GraphQL and Apollo server https://githubcom/AdhamAH/Film-and-actors-list/tree/main/server

70