diff options
Diffstat (limited to 'lib/sqlalchemy/orm/attributes.py')
-rw-r--r-- | lib/sqlalchemy/orm/attributes.py | 81 |
1 files changed, 80 insertions, 1 deletions
diff --git a/lib/sqlalchemy/orm/attributes.py b/lib/sqlalchemy/orm/attributes.py index b96b3b61e..2e48695f5 100644 --- a/lib/sqlalchemy/orm/attributes.py +++ b/lib/sqlalchemy/orm/attributes.py @@ -334,7 +334,85 @@ def _queryable_attribute_unreduce(key, mapped_class, parententity, entity): return getattr(entity, key) -class InstrumentedAttribute(QueryableAttribute): +if util.py3k: + from typing import TypeVar, Generic + + _T = TypeVar("_T") + _Generic_T = Generic[_T] +else: + _Generic_T = type("_Generic_T", (), {}) + + +class Mapped(QueryableAttribute, _Generic_T): + """Represent an ORM mapped :term:`descriptor` attribute for typing purposes. + + This class represents the complete descriptor interface for any class + attribute that will have been :term:`instrumented` by the ORM + :class:`_orm.Mapper` class. When used with typing stubs, it is the final + type that would be used by a type checker such as mypy to provide the full + behavioral contract for the attribute. + + .. tip:: + + The :class:`_orm.Mapped` class represents attributes that are handled + directly by the :class:`_orm.Mapper` class. It does not include other + Python descriptor classes that are provided as extensions, including + :ref:`hybrids_toplevel` and the :ref:`associationproxy_toplevel`. + While these systems still make use of ORM-specific superclasses + and structures, they are not :term:`instrumented` by the + :class:`_orm.Mapper` and instead provide their own functionality + when they are accessed on a class. + + When using the :ref:`SQLAlchemy Mypy plugin <mypy_toplevel>`, the + :class:`_orm.Mapped` construct is used in typing annotations to indicate to + the plugin those attributes that are expected to be mapped; the plugin also + applies :class:`_orm.Mapped` as an annotation automatically when it scans + through declarative mappings in :ref:`orm_declarative_table` style. For + more indirect mapping styles such as + :ref:`imperative table <orm_imperative_table_configuration>` it is + typically applied explicitly to class level attributes that expect + to be mapped based on a given :class:`_schema.Table` configuration. + + :class:`_orm.Mapped` is defined in the + `sqlalchemy2-stubs <https://pypi.org/project/sqlalchemy2-stubs>`_ project + as a :pep:`484` generic class which may subscribe to any arbitrary Python + type, which represents the Python type handled by the attribute:: + + class MyMappedClass(Base): + __table_ = Table( + "some_table", Base.metadata, + Column("id", Integer, primary_key=True), + Column("data", String(50)), + Column("created_at", DateTime) + ) + + id : Mapped[int] + data: Mapped[str] + created_at: Mapped[datetime] + + For complete background on how to use :class:`_orm.Mapped` with + pep-484 tools like Mypy, see the link below for background on SQLAlchemy's + Mypy plugin. + + .. versionadded:: 1.4 + + .. seealso:: + + :ref:`mypy_toplevel` - complete background on Mypy integration + + """ + + def __get__(self, instance, owner): + raise NotImplementedError() + + def __set__(self, instance, value): + raise NotImplementedError() + + def __delete__(self, instance): + raise NotImplementedError() + + +class InstrumentedAttribute(Mapped): """Class bound instrumented attribute which adds basic :term:`descriptor` methods. @@ -1369,6 +1447,7 @@ class CollectionAttributeImpl(AttributeImpl): value, initiator=None, passive=PASSIVE_OFF, + check_old=None, pop=False, _adapt=True, ): |