sqlmodel icon indicating copy to clipboard operation
sqlmodel copied to clipboard

SQLAlchemy-Continuum compatibility

Open petyunchik opened this issue 2 years ago • 7 comments

First Check

  • [X] I added a very descriptive title to this issue.
  • [X] I used the GitHub search to find a similar issue and didn't find it.
  • [X] I searched the SQLModel documentation, with the integrated search.
  • [X] I already searched in Google "How to X in SQLModel" and didn't find any information.
  • [X] I already read and followed all the tutorial in the docs and didn't find an answer.
  • [X] I already checked if it is not related to SQLModel but to Pydantic.
  • [X] I already checked if it is not related to SQLModel but to SQLAlchemy.

Commit to Help

  • [X] I commit to help with one of those options 👆

Example Code

from typing import Optional

from sqlalchemy_continuum import make_versioned
from sqlmodel import Field, Session, SQLModel, create_engine
from sqlmodel.main import default_registry


# setattr(SQLModel, 'registry', default_registry)
make_versioned(user_cls=None)


class Hero(SQLModel, table=True):
    __versioned__ = {}

    id: Optional[int] = Field(default=None, primary_key=True)
    name: str
    secret_name: str
    age: Optional[int] = None


hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson")

engine = create_engine("sqlite:///database.db")


SQLModel.metadata.create_all(engine)

with Session(engine) as session:
    session.add(hero_1)
    session.commit()
    session.refresh(hero_1)
    print(hero_1)

Description

Very basic setup of SQLAlchemy-Continuum doesn't work with SQLModel. Following error raised (see here):

AttributeError: type object 'SQLModel' has no attribute '_decl_class_registry'

SQLModel class misses some expected attribute (registry for SQLAlchemy >= 1.4) from SQLAlchemy's Base. For debugging purposes the attribute can be manually populated (uncomment # setattr(SQLModel, 'registry', default_registry) in the example code) and it helps to proceed to the next error:

  <skipped>
  File ".../.venv/lib/python3.10/site-packages/sqlmodel/main.py", line 277, in __new__
    new_cls = super().__new__(cls, name, bases, dict_used, **config_kwargs)
  File "pydantic/main.py", line 228, in pydantic.main.ModelMetaclass.__new__
  File "pydantic/fields.py", line 488, in pydantic.fields.ModelField.infer
  File "pydantic/fields.py", line 419, in pydantic.fields.ModelField.__init__
  File "pydantic/fields.py", line 528, in pydantic.fields.ModelField.prepare
  File "pydantic/fields.py", line 552, in pydantic.fields.ModelField._set_default_and_type
  File "pydantic/fields.py", line 422, in pydantic.fields.ModelField.get_default
  File "pydantic/utils.py", line 652, in pydantic.utils.smart_deepcopy
  File ".../.venv/lib/python3.10/site-packages/sqlalchemy/sql/elements.py", line 582, in __bool__
    raise TypeError("Boolean value of this clause is not defined")
TypeError: Boolean value of this clause is not defined

Looks like there is some incompatibility with SQLAlchemy's expected behaviour, because this error was thrown just after SQLModel's __new__ method call.

Operating System

macOS

Operating System Details

No response

SQLModel Version

0.0.6

Python Version

3.10.2

Additional Context

No response

petyunchik avatar May 19 '22 13:05 petyunchik

For what it's worth, I am seeing this error even without sqlmodel or sqlalchemy_continuum. Did you ever find the root cause?

coneybeare avatar Jun 25 '22 10:06 coneybeare

@petyunchik were you able to get this working? upgrading pydantic fixes that issue, however, there are a couple other issues that then you have to work through, both with continuum and sqlmodel

igkins avatar Sep 01 '22 01:09 igkins

As of today (i.e. sqlmodel 0.0.14 and sqlalchemy-continuum 1.4.0), the error is

pydantic.errors.PydanticUserError: A non-annotated attribute was detected: `id = Column(None, BigInteger(), table=None, primary_key=True, nullable=False, default=Sequence('transaction_id_seq'))`. All model fields require a type annotation; if `id` is not meant to be a field, you may be able to resolve this error by annotating it as a `ClassVar` or updating `model_config['ignored_types']`.

Couldn't debug it properly, but I assume this is due to the fact that continuum create sqlalchemy models for versioning, but do not annotate these models. I think I'll have to deal with this problem, because versioning is of the essence for some of my applications. My intuition tells that it is best to create a new module by patching sqlalchemy-continuum to use sqlmodel's Base and registry, rather than adapting any of these to use the other

ftapajos avatar Jan 15 '24 13:01 ftapajos

@ftapajos thank you for the suggestion. Any update on this? I am interested in contributing 🙏

abrichr avatar Mar 10 '24 16:03 abrichr

Related: https://github.com/kvesteri/sqlalchemy-continuum/issues/271

@tiangolo any thoughts on this would be greatly appreciated! 🙏

abrichr avatar Mar 10 '24 16:03 abrichr

@abrichr I haven't even started yet, but I could follow your lead

ftapajos avatar Mar 10 '24 17:03 ftapajos