Open
Description
Description
I am having a problem where when I want to write a Json Decoder for SQLAlchemy but then I bump into an issue where msgspec doesn't know how to handle these types.
from sqlalchemy.orm import Mapped, MappedAsDataclass, DeclarativeBaseNoMeta, mapped_column, declared_attr
from msgspec.json import Decoder, Encoder
class SQLTable(MappedAsDataclass, DeclarativeBaseNoMeta):
pass
class User(SQLTable):
__tablename__ = "user"
# Mapped is used to register columns in the sql table without
# Having to write mapped_column out many times.
name:Mapped[str]
id:Mapped[int] = mapped_column(primary_key=True, default=None)
encoder = Encoder()
# Encoder works just fine...
print(encoder.encode(User("Vizonex", 10)))
# But the decoder on the other-hand is broken and I expect to decode the User json
# To a User Object...
# msgspec.ValidationError: Expected `Mapped`, got `str` - at `$.name`
user = Decoder(User).decode(b'{"name":"Vizonex", "id": 10}')
I am completely stumped on how to fix this problem and I have gone through all hoops and hurtles to try and make the decoder for my upcoming python library SQLTable
to decode json correctly.
Other Things I've Tried
I have tried hacking the Mapped[]
Object itself into an annotated object but then SQLAlchemy fails to find it...
from sqlalchemy.orm import Mapped, MappedAsDataclass, DeclarativeBaseNoMeta, mapped_column, declared_attr
from typing import Annotated, TypeVar
from msgspec.json import Decoder, Encoder
T = TypeVar("T")
# this was an idea I came up with to allow msgspec to act friendly with
# Sqlalchemy Mapped variables but sqlalchmey doesn't act friendly with
# finding Mapped attributes...
HackedMap = Annotated[T, Mapped[T]]
class SQLTable(MappedAsDataclass, DeclarativeBaseNoMeta):
pass
class User(SQLTable):
__tablename__ = "user"
# We can try to hack it to how we please so that msgspec's decoder works correctly
# but then a new problem arises
name:HackedMap[str]
id:HackedMap[int] = mapped_column(primary_key=True, default=None)
# It only shows {'id': <ColumnProperty at 0x20d09b14e40; id>} Because we set it with mapped_column
print(User.__mapper__.attrs._data)
I am almost completely stumped on how this will get solved. But there are 2 fixes that I could think of that could be approched to solve this once and for all.
- SQLAlchemy adds some new logic for finding mapped variables hidden inside
Annotated
types. - The way we could fix _core.c involves fixing the function
typenode_collect_type
function where we could check if the class has a__table__
or another obscure type belonging to sqlalchemy and then try to filter outMapped[T]
types through that kind of Boolean/logic.
Metadata
Metadata
Assignees
Labels
No labels