if you can't correct this model to apply the persistence details to the concrete class you wish to persist and query, then you'd do the suggested "enable_typechecks=False". There is no attribute in SQLAlchemy named "meta" and no stack trace is given here so I dont know to what that refers.
Overall I'm not sure how this API_Person class is useful because you can't query for them. I would think that if you cant change the original model then you'd have this API_Person as a series of helper functions that accept a Person as their argument. On Wed, Sep 6, 2023, at 1:56 PM, 'Luna Lucadou' via sqlalchemy wrote: > The project I am working on is split up into several modules. Previously, > each module had its own ORM classes. > However, due to several bugs arising from forgetting to update each module's > ORM classes in lock step when adding new functionality, we have decided it > would be best to extract the ORM classes which interact with our DB into > their own module and make that available to the other modules via pip. > > One of these modules, which monitors for changes in an upstream DB and > applies them to ours, has some methods which are not present in the other > modules and which cannot be easily extracted out due to its dependencies on > upstream DB functionality. > > As such, in this module, we must subclass the ORM models which interact with > our DB: > > models.apimodels.db.person.py: > #... > @dataclass(init=False, eq=True, unsafe_hash=True) > class Person(Base): > __tablename__ = "person" > > id: Mapped[int] = mapped_column(primary_key=True) > first_name: Mapped[str] > last_name: Mapped[str] > email_address: Mapped[str] > office_address: Mapped[str] > office_phone_number: Mapped[str] > > # ... > > etl.models.api_db.api_person.py: > #... > from apimodels.db.person import Person as PersonBase > # ... > class API_Person(PersonBase): > __tablename__ = "person" > __table_args__ = {"keep_existing": True} > > def get_pvi(self): > # ... > > def get_historical_pvis(self) -> list[str]: > # ... > > def __eq__(self): > # ... > > def __hash__(self): > # ... > > @staticmethod > def from_upstream_hub_person( > uh_person: Optional[UH_Person], > ) -> Optional["API_Person"]: > # ... > > Of note is that this subclass does not add any new attributes or modify > existing ones, it merely adds some helper methods related to identifying > primary key changes in the upstream DB. (This is also why we override the eq > and hash methods provided by dataclasses - incoming changesets have to be > matched against existing records, even when primary keys change upstream.) > > This is effectively single-table inheritance, but it is not a good fit for > polymorphic_identity since it is not a distinct class, merely adding > module-specific helper methods, and if I am reading the documentation > correctly, using polymorphic_identity would mean any records touched by the > API_Person subclass (which is all of them) would no longer be usable by other > modules, which do not extend any of the models. > > From what I have read, it seems like the keep_existing param should be of use > here, but neither it nor extend_existing set to True help with the errors I > am seeing when attempting to interact with this subclass in any way: > > sqlalchemy.orm.exc.FlushError: Attempting to flush an item of type <class > 'model.api_db.api_person.API_Person'> as a member of collection > "Identifier.person". Expected an object of type <class > 'apimodels.db.person.Person'> or a polymorphic subclass of this type. If > <class 'model.api_db.api_person.API_Person'> is a subclass of <class > 'apimodels.db.person.Person'>, configure mapper "Mapper[Person(person)]" to > load this subtype polymorphically, or set enable_typechecks=False to allow > any subtype to be accepted for flush. > > I did try setting enable_typechecks to False, but this results in a different > error when attempting to use getattr on the subclass: > > AttributeError: 'Person' object has no attribute 'meta' > > Is there a better way of doing this? > > > -- > SQLAlchemy - > The Python SQL Toolkit and Object Relational Mapper > > http://www.sqlalchemy.org/ > > To post example code, please provide an MCVE: Minimal, Complete, and > Verifiable Example. See http://stackoverflow.com/help/mcve for a full > description. > --- > You received this message because you are subscribed to the Google Groups > "sqlalchemy" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to sqlalchemy+unsubscr...@googlegroups.com. > To view this discussion on the web visit > https://groups.google.com/d/msgid/sqlalchemy/bff6d34f-ea35-4aba-ba94-5ae1f29154fan%40googlegroups.com > > <https://groups.google.com/d/msgid/sqlalchemy/bff6d34f-ea35-4aba-ba94-5ae1f29154fan%40googlegroups.com?utm_medium=email&utm_source=footer>. -- SQLAlchemy - The Python SQL Toolkit and Object Relational Mapper http://www.sqlalchemy.org/ To post example code, please provide an MCVE: Minimal, Complete, and Verifiable Example. See http://stackoverflow.com/help/mcve for a full description. --- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/sqlalchemy/a315e4dc-01cf-4540-8ab6-e6ce8a7a4df5%40app.fastmail.com.