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

TypeAlias cannot be found in type_annotation_map #11370

Open
RazerM opened this issue May 8, 2024 · 2 comments
Open

TypeAlias cannot be found in type_annotation_map #11370

RazerM opened this issue May 8, 2024 · 2 comments
Labels
bug Something isn't working near-term release addition to the milestone which indicates this should be in a near-term release orm - annotated declarative issues with the new annotations-based declarative ORM approach
Milestone

Comments

@RazerM
Copy link
Contributor

RazerM commented May 8, 2024

Describe the bug

I have a TypeAlias that I'm trying to put in type_annotation_map but SQLAlchemy can't seem to find it.

(my naive understanding was that Json in the example would be looked up directly by hash in the annotation map)

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

No response

SQLAlchemy Version in Use

2.0.30

DBAPI (i.e. the database driver)

psycopg2

Database Vendor and Major Version

PostgreSQL 12

Python Version

3.10

Operating system

macOS

To Reproduce

from typing import Annotated, Dict, List, Optional, TypeAlias, Union

from sqlalchemy.dialects.postgresql import JSONB
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column

JsonPrimitive: TypeAlias = Union[str, int, float, bool, None]
JsonObject: TypeAlias = Dict[str, "Json"]
JsonArray: TypeAlias = List["Json"]
Json: TypeAlias = Union[JsonObject, JsonArray, JsonPrimitive]


class Base(DeclarativeBase):
    type_annotation_map = {
        Json: JSONB(none_as_null=True),
    }


class Model(Base):
    __tablename__ = "model"

    id: Mapped[int] = mapped_column(primary_key=True)
    data: Mapped[Optional[Json]]

Error

Traceback (most recent call last):
  File "/scratch_184.py", line 25, in <module>
    class Model(Base):
  File "/venv/lib/python3.10/site-packages/sqlalchemy/orm/decl_api.py", line 836, in __init_subclass__
    _as_declarative(cls._sa_registry, cls, cls.__dict__)
  File "/venv/lib/python3.10/site-packages/sqlalchemy/orm/decl_base.py", line 244, in _as_declarative
    return _MapperConfig.setup_mapping(registry, cls, dict_, None, {})
  File "/venv/lib/python3.10/site-packages/sqlalchemy/orm/decl_base.py", line 325, in setup_mapping
    return _ClassScanMapperConfig(
  File "/venv/lib/python3.10/site-packages/sqlalchemy/orm/decl_base.py", line 571, in __init__
    self._extract_mappable_attributes()
  File "/venv/lib/python3.10/site-packages/sqlalchemy/orm/decl_base.py", line 1541, in _extract_mappable_attributes
    value.declarative_scan(
  File "/venv/lib/python3.10/site-packages/sqlalchemy/orm/properties.py", line 709, in declarative_scan
    self._init_column_for_annotation(
  File "/venv/lib/python3.10/site-packages/sqlalchemy/orm/properties.py", line 880, in _init_column_for_annotation
    raise sa_exc.ArgumentError(
sqlalchemy.exc.ArgumentError: Could not locate SQLAlchemy Core type for Python type typing.Union[str, int, bool, float, typing.Dict[str, ForwardRef('Json')], typing.List[ForwardRef('Json')]] inside the 'data' attribute Mapped annotation

Additional context

There's still an error even if the TypeAlias is not self-referential:

JsonPrimitive: TypeAlias = Union[str, int, float, bool, None]
JsonObject: TypeAlias = Dict[str, object]
JsonArray: TypeAlias = List[object]
Json: TypeAlias = Union[JsonObject, JsonArray, JsonPrimitive]

but weirdly it works if JsonPrimitive doesn't have None:

JsonPrimitive: TypeAlias = Union[str, int, float, bool]
JsonObject: TypeAlias = Dict[str, object]
JsonArray: TypeAlias = List[object]
Json: TypeAlias = Union[JsonArray, str, int, float]

(both of these types aren't very useful, so I would specify the JSONB explicitly in mapped_column, but I thought it's worth mentioning what I'd tried).

@RazerM RazerM added the requires triage New issue that requires categorization label May 8, 2024
@zzzeek zzzeek added bug Something isn't working near-term release addition to the milestone which indicates this should be in a near-term release orm - annotated declarative issues with the new annotations-based declarative ORM approach and removed requires triage New issue that requires categorization labels May 8, 2024
@zzzeek
Copy link
Member

zzzeek commented May 8, 2024

we probably cant use Unions as keys, kind of an edge case

@zzzeek zzzeek added this to the 2.0.x milestone May 8, 2024
@CaselIT
Copy link
Member

CaselIT commented May 8, 2024

I think the issue here is this:

JsonPrimitive: TypeAlias = Union[str, int, float, bool, None]
JsonObject: TypeAlias = Dict[str, object]
JsonArray: TypeAlias = List[object]
Json: TypeAlias = Union[JsonObject, JsonArray, JsonPrimitive]

print(Optional[Json] == Json)

This prints True. The repr is also the same

@zzzeek I think the current implementation removes the None from the union when searching for type.
It usually makes sense, but not in this case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working near-term release addition to the milestone which indicates this should be in a near-term release orm - annotated declarative issues with the new annotations-based declarative ORM approach
Projects
None yet
Development

No branches or pull requests

3 participants