Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Could not de-stringify annotation #11062

Open
finswimmer opened this issue Feb 27, 2024 · 3 comments
Open

Could not de-stringify annotation #11062

finswimmer opened this issue Feb 27, 2024 · 3 comments
Labels
documentation orm - annotated declarative issues with the new annotations-based declarative ORM approach orm

Comments

@finswimmer
Copy link

finswimmer commented Feb 27, 2024

Describe the bug

Hey,

the following code raises an NameError: Could not de-stringify annotation 'long str'. But as soon as I changed Annotated[str, "long str"] to Annotated[str, "long_str"] it works. Any idea about what's going on here?

fin swimmer

Optional link from https://docs.sqlalchemy.org which documents the behavior that is expected

No response

SQLAlchemy Version in Use

2.0.27

DBAPI (i.e. the database driver)

sqlite, oracaledb

Database Vendor and Major Version

current

Python Version

3.11, 3.12

Operating system

Linux, Windows

To Reproduce

from typing import Annotated

from sqlalchemy import Integer, Text, create_engine
from sqlalchemy.orm import DeclarativeBase, Mapped, Session, mapped_column

long_str = Annotated[str, "long str"]


class Base(DeclarativeBase):
    type_annotation_map = {
        long_str: Text,
    }


class User(Base):
    __tablename__ = "users"

    user_id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
    name: Mapped[str]
    data: Mapped[long_str]


if __name__ == "__main__":
    engine = create_engine("sqlite:///test_database.db", echo="debug")
    Base.metadata.create_all(engine)

    session = Session(autocommit=False, autoflush=False, bind=engine)

    user = User(user_id=1, name="me", data="some data")
    session.add(user)
    session.commit()

Error

Traceback (most recent call last):
  File "/home/finswimmer/tmp/alchemy-annotated/.venv/lib/python3.12/site-packages/sqlalchemy/util/typing.py", line 230, in eval_expression
    annotation = eval(expression, cls_namespace, locals_)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<string>", line 1
    long str
         ^^^
SyntaxError: invalid syntax

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/finswimmer/tmp/alchemy-annotated/alchemy_annotated/base.py", line 15, in <module>
    class User(Base):
  File "/home/finswimmer/tmp/alchemy-annotated/.venv/lib/python3.12/site-packages/sqlalchemy/orm/decl_api.py", line 836, in __init_subclass__
    _as_declarative(cls._sa_registry, cls, cls.__dict__)
  File "/home/finswimmer/tmp/alchemy-annotated/.venv/lib/python3.12/site-packages/sqlalchemy/orm/decl_base.py", line 244, in _as_declarative
    return _MapperConfig.setup_mapping(registry, cls, dict_, None, {})
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/finswimmer/tmp/alchemy-annotated/.venv/lib/python3.12/site-packages/sqlalchemy/orm/decl_base.py", line 325, in setup_mapping
    return _ClassScanMapperConfig(
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/finswimmer/tmp/alchemy-annotated/.venv/lib/python3.12/site-packages/sqlalchemy/orm/decl_base.py", line 560, in __init__
    self._scan_attributes()
  File "/home/finswimmer/tmp/alchemy-annotated/.venv/lib/python3.12/site-packages/sqlalchemy/orm/decl_base.py", line 1003, in _scan_attributes
    collected_annotation = self._collect_annotation(
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/finswimmer/tmp/alchemy-annotated/.venv/lib/python3.12/site-packages/sqlalchemy/orm/decl_base.py", line 1297, in _collect_annotation
    elem = de_stringify_annotation(
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/finswimmer/tmp/alchemy-annotated/.venv/lib/python3.12/site-packages/sqlalchemy/util/typing.py", line 156, in de_stringify_annotation
    annotation = eval_expression(
                 ^^^^^^^^^^^^^^^^
  File "/home/finswimmer/tmp/alchemy-annotated/.venv/lib/python3.12/site-packages/sqlalchemy/util/typing.py", line 234, in eval_expression
    raise NameError(
NameError: Could not de-stringify annotation 'long str'

Additional context

No response

@finswimmer finswimmer added the requires triage New issue that requires categorization label Feb 27, 2024
@CaselIT
Copy link
Member

CaselIT commented Feb 27, 2024

Hi,

Sqlalchemy is looking for mapped columns in the annotations, see https://docs.sqlalchemy.org/en/20/orm/declarative_tables.html#mapping-whole-column-declarations-to-python-types, so I guess when passing a string it needs to be a valid python identifier.
@zzzeek I'm not sure if in this case it could ignore the error and keep the string literal? Seems like a bit too magic, so maybe just document that in the Annotated section?

@CaselIT CaselIT added orm orm - annotated declarative issues with the new annotations-based declarative ORM approach documentation and removed requires triage New issue that requires categorization labels Feb 27, 2024
@finswimmer
Copy link
Author

Hi @CaselIT,

thanks for your response!

Due to https://docs.sqlalchemy.org/en/20/orm/declarative_tables.html#mapping-multiple-type-configurations-to-python-types I was under the impression, that the second argument of Annotated is only taken into account for magic if it contains a mapped_column. Obviously I was wrong 😄

So in my case, the correct way would be:

long_str = Annotated[str, mapped_column(Text)]

And than omit the type_annotation_map in the Base class. Correct? (At least in seems to work as expected)

fin swimmer

@CaselIT
Copy link
Member

CaselIT commented Feb 28, 2024

the correct way would be:

I would say a way. there are various options to achieve it, so there isn't a correct one.

If you prefer that one by all means use it!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation orm - annotated declarative issues with the new annotations-based declarative ORM approach orm
Projects
None yet
Development

No branches or pull requests

2 participants