Description
Describe the bug
Trying to use NewType
s for a column annotation causes a crash without any reference as to what column caused the problem.
Even if using NewType
s is not supported (which I assumed it was), I would have expected sqlalchemy to not crash internally, but handle this case and throw an exception to communicate to me
- what the relevant column with the problem is (I had to bisect for a while)
- that
NewType
-mapped columns are currently not supported.
If NewType
s are nontrivial to support then a remark in the docs + „what's new“ document might be helpful (the search term NewType
had 0 occurences in the docs).
(hope using an issue was the right call. This form with MWE/Backtrace fields felt more appropriate.)
To Reproduce
from datetime import datetime
import typing as t
from sqlalchemy import *
from sqlalchemy.orm import *
DateTimeTz = t.NewType("DateTimeTz", datetime)
class Base(DeclarativeBase):
type_annotation_map = {DateTimeTz: DateTime}
class Foo(Base):
__tablename__ = "foo"
id: Mapped[int] = mapped_column(primary_key=True)
dt: Mapped[DateTimeTz]
Error
Traceback (most recent call last):
File "/opt/pycroft/app/test.py", line 8, in <module>
class Foo(Base):
File "/opt/pycroft/venv/lib/python3.10/site-packages/sqlalchemy/orm/decl_api.py", line 768, in __init_subclass__
_as_declarative(cls._sa_registry, cls, cls.__dict__)
File "/opt/pycroft/venv/lib/python3.10/site-packages/sqlalchemy/orm/decl_base.py", line 246, in _as_declarative
return _MapperConfig.setup_mapping(registry, cls, dict_, None, {})
File "/opt/pycroft/venv/lib/python3.10/site-packages/sqlalchemy/orm/decl_base.py", line 327, in setup_mapping
return _ClassScanMapperConfig(
File "/opt/pycroft/venv/lib/python3.10/site-packages/sqlalchemy/orm/decl_base.py", line 569, in __init__
self._extract_mappable_attributes()
File "/opt/pycroft/venv/lib/python3.10/site-packages/sqlalchemy/orm/decl_base.py", line 1388, in _extract_mappable_attributes
value.declarative_scan(
File "/opt/pycroft/venv/lib/python3.10/site-packages/sqlalchemy/orm/properties.py", line 681, in declarative_scan
self._init_column_for_annotation(
File "/opt/pycroft/venv/lib/python3.10/site-packages/sqlalchemy/orm/properties.py", line 763, in _init_column_for_annotation
new_sqltype = registry._resolve_type(check_type)
File "/opt/pycroft/venv/lib/python3.10/site-packages/sqlalchemy/orm/decl_api.py", line 1167, in _resolve_type
search = python_type_type.__mro__
AttributeError: 'NewType' object has no attribute '__mro__'. Did you mean: '__or__'?
Versions
- OS: Linux 6.0.10 in Docker
- Python: 3.10.x
- SQLAlchemy: 2.0.0
- Database: None
- DBAPI (eg: psycopg, cx_oracle, mysqlclient): None
Additional context
I have a type decorator wrapping DateTime
which still translates to python's datetime
, however existence of a tzinfo
is ensured. Since python does not distinguish between tz-less and tz-aware datetimes, the NewType
is necessary; a type alias won't do to ensure tz-awareness on the type checking level.
Activity
lukasjuhrich commentedon Jan 29, 2023
Explicitly setting
dt: Mapped[DateTimeTz] = mapped_column(DateTime)
seems to be a workaround.zzzeek commentedon Jan 29, 2023
I would assume we handle NewType the same way we do Annotated, so the codepaths that are checking for Annotated need to be augmented for this as well.
[-]SQLAlchemy v2 crashes when trying to map columns with `NewType`[/-][+]support NewType similarly to Annotated[/+]sqla-tester commentedon Jan 30, 2023
Mike Bayer has proposed a fix for this issue in the main branch:
support NewType in type_annotation_map https://gerrit.sqlalchemy.org/c/sqlalchemy/sqlalchemy/+/4408
support NewType in type_annotation_map