SQLAlchemy 2.1.0__cp315-cp315-win32.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (276) hide show
  1. sqlalchemy/__init__.py +299 -0
  2. sqlalchemy/connectors/__init__.py +18 -0
  3. sqlalchemy/connectors/aioodbc.py +171 -0
  4. sqlalchemy/connectors/asyncio.py +476 -0
  5. sqlalchemy/connectors/pyodbc.py +248 -0
  6. sqlalchemy/dialects/__init__.py +62 -0
  7. sqlalchemy/dialects/_typing.py +29 -0
  8. sqlalchemy/dialects/mssql/__init__.py +88 -0
  9. sqlalchemy/dialects/mssql/aioodbc.py +63 -0
  10. sqlalchemy/dialects/mssql/base.py +4833 -0
  11. sqlalchemy/dialects/mssql/information_schema.py +345 -0
  12. sqlalchemy/dialects/mssql/json.py +140 -0
  13. sqlalchemy/dialects/mssql/mssqlpython.py +251 -0
  14. sqlalchemy/dialects/mssql/provision.py +196 -0
  15. sqlalchemy/dialects/mssql/pymssql.py +130 -0
  16. sqlalchemy/dialects/mssql/pyodbc.py +697 -0
  17. sqlalchemy/dialects/mysql/__init__.py +106 -0
  18. sqlalchemy/dialects/mysql/_mariadb_shim.py +312 -0
  19. sqlalchemy/dialects/mysql/aiomysql.py +260 -0
  20. sqlalchemy/dialects/mysql/asyncmy.py +241 -0
  21. sqlalchemy/dialects/mysql/base.py +3896 -0
  22. sqlalchemy/dialects/mysql/cymysql.py +107 -0
  23. sqlalchemy/dialects/mysql/dml.py +279 -0
  24. sqlalchemy/dialects/mysql/enumerated.py +277 -0
  25. sqlalchemy/dialects/mysql/expression.py +146 -0
  26. sqlalchemy/dialects/mysql/json.py +92 -0
  27. sqlalchemy/dialects/mysql/mariadb.py +67 -0
  28. sqlalchemy/dialects/mysql/mariadbconnector.py +314 -0
  29. sqlalchemy/dialects/mysql/mysqlconnector.py +291 -0
  30. sqlalchemy/dialects/mysql/mysqldb.py +318 -0
  31. sqlalchemy/dialects/mysql/provision.py +153 -0
  32. sqlalchemy/dialects/mysql/pymysql.py +188 -0
  33. sqlalchemy/dialects/mysql/pyodbc.py +157 -0
  34. sqlalchemy/dialects/mysql/reflection.py +724 -0
  35. sqlalchemy/dialects/mysql/reserved_words.py +570 -0
  36. sqlalchemy/dialects/mysql/types.py +845 -0
  37. sqlalchemy/dialects/oracle/__init__.py +85 -0
  38. sqlalchemy/dialects/oracle/base.py +3847 -0
  39. sqlalchemy/dialects/oracle/cx_oracle.py +1736 -0
  40. sqlalchemy/dialects/oracle/dictionary.py +507 -0
  41. sqlalchemy/dialects/oracle/json.py +157 -0
  42. sqlalchemy/dialects/oracle/oracledb.py +921 -0
  43. sqlalchemy/dialects/oracle/provision.py +288 -0
  44. sqlalchemy/dialects/oracle/types.py +367 -0
  45. sqlalchemy/dialects/oracle/vector.py +366 -0
  46. sqlalchemy/dialects/postgresql/__init__.py +170 -0
  47. sqlalchemy/dialects/postgresql/_psycopg_common.py +232 -0
  48. sqlalchemy/dialects/postgresql/array.py +534 -0
  49. sqlalchemy/dialects/postgresql/asyncpg.py +1318 -0
  50. sqlalchemy/dialects/postgresql/base.py +5977 -0
  51. sqlalchemy/dialects/postgresql/bitstring.py +327 -0
  52. sqlalchemy/dialects/postgresql/dml.py +360 -0
  53. sqlalchemy/dialects/postgresql/ext.py +599 -0
  54. sqlalchemy/dialects/postgresql/hstore.py +422 -0
  55. sqlalchemy/dialects/postgresql/json.py +411 -0
  56. sqlalchemy/dialects/postgresql/named_types.py +535 -0
  57. sqlalchemy/dialects/postgresql/operators.py +129 -0
  58. sqlalchemy/dialects/postgresql/pg8000.py +655 -0
  59. sqlalchemy/dialects/postgresql/pg_catalog.py +345 -0
  60. sqlalchemy/dialects/postgresql/provision.py +202 -0
  61. sqlalchemy/dialects/postgresql/psycopg.py +800 -0
  62. sqlalchemy/dialects/postgresql/psycopg2.py +860 -0
  63. sqlalchemy/dialects/postgresql/psycopg2cffi.py +62 -0
  64. sqlalchemy/dialects/postgresql/ranges.py +1002 -0
  65. sqlalchemy/dialects/postgresql/types.py +388 -0
  66. sqlalchemy/dialects/sqlite/__init__.py +59 -0
  67. sqlalchemy/dialects/sqlite/aiosqlite.py +375 -0
  68. sqlalchemy/dialects/sqlite/base.py +3156 -0
  69. sqlalchemy/dialects/sqlite/dml.py +314 -0
  70. sqlalchemy/dialects/sqlite/json.py +134 -0
  71. sqlalchemy/dialects/sqlite/provision.py +237 -0
  72. sqlalchemy/dialects/sqlite/pysqlcipher.py +166 -0
  73. sqlalchemy/dialects/sqlite/pysqlite.py +959 -0
  74. sqlalchemy/dialects/type_migration_guidelines.txt +145 -0
  75. sqlalchemy/engine/__init__.py +62 -0
  76. sqlalchemy/engine/_processors_cy.cp315-win32.pyd +0 -0
  77. sqlalchemy/engine/_processors_cy.py +92 -0
  78. sqlalchemy/engine/_result_cy.cp315-win32.pyd +0 -0
  79. sqlalchemy/engine/_result_cy.py +711 -0
  80. sqlalchemy/engine/_row_cy.cp315-win32.pyd +0 -0
  81. sqlalchemy/engine/_row_cy.py +232 -0
  82. sqlalchemy/engine/_util_cy.cp315-win32.pyd +0 -0
  83. sqlalchemy/engine/_util_cy.py +136 -0
  84. sqlalchemy/engine/base.py +3357 -0
  85. sqlalchemy/engine/characteristics.py +155 -0
  86. sqlalchemy/engine/create.py +877 -0
  87. sqlalchemy/engine/cursor.py +2425 -0
  88. sqlalchemy/engine/default.py +2627 -0
  89. sqlalchemy/engine/events.py +965 -0
  90. sqlalchemy/engine/interfaces.py +3647 -0
  91. sqlalchemy/engine/mock.py +133 -0
  92. sqlalchemy/engine/processors.py +83 -0
  93. sqlalchemy/engine/reflection.py +2141 -0
  94. sqlalchemy/engine/result.py +2012 -0
  95. sqlalchemy/engine/row.py +397 -0
  96. sqlalchemy/engine/strategies.py +16 -0
  97. sqlalchemy/engine/url.py +922 -0
  98. sqlalchemy/engine/util.py +164 -0
  99. sqlalchemy/event/__init__.py +26 -0
  100. sqlalchemy/event/api.py +220 -0
  101. sqlalchemy/event/attr.py +675 -0
  102. sqlalchemy/event/base.py +473 -0
  103. sqlalchemy/event/legacy.py +259 -0
  104. sqlalchemy/event/registry.py +391 -0
  105. sqlalchemy/events.py +17 -0
  106. sqlalchemy/exc.py +939 -0
  107. sqlalchemy/ext/__init__.py +10 -0
  108. sqlalchemy/ext/associationproxy.py +2073 -0
  109. sqlalchemy/ext/asyncio/__init__.py +29 -0
  110. sqlalchemy/ext/asyncio/base.py +281 -0
  111. sqlalchemy/ext/asyncio/engine.py +1489 -0
  112. sqlalchemy/ext/asyncio/exc.py +30 -0
  113. sqlalchemy/ext/asyncio/result.py +994 -0
  114. sqlalchemy/ext/asyncio/scoping.py +1787 -0
  115. sqlalchemy/ext/asyncio/session.py +2268 -0
  116. sqlalchemy/ext/automap.py +1702 -0
  117. sqlalchemy/ext/baked.py +558 -0
  118. sqlalchemy/ext/compiler.py +601 -0
  119. sqlalchemy/ext/declarative/__init__.py +65 -0
  120. sqlalchemy/ext/declarative/extensions.py +561 -0
  121. sqlalchemy/ext/horizontal_shard.py +481 -0
  122. sqlalchemy/ext/hybrid.py +1877 -0
  123. sqlalchemy/ext/indexable.py +364 -0
  124. sqlalchemy/ext/instrumentation.py +450 -0
  125. sqlalchemy/ext/mutable.py +1081 -0
  126. sqlalchemy/ext/orderinglist.py +440 -0
  127. sqlalchemy/ext/serializer.py +184 -0
  128. sqlalchemy/future/__init__.py +17 -0
  129. sqlalchemy/future/engine.py +15 -0
  130. sqlalchemy/inspection.py +188 -0
  131. sqlalchemy/log.py +279 -0
  132. sqlalchemy/orm/__init__.py +176 -0
  133. sqlalchemy/orm/_orm_constructors.py +2711 -0
  134. sqlalchemy/orm/_typing.py +180 -0
  135. sqlalchemy/orm/attributes.py +2868 -0
  136. sqlalchemy/orm/base.py +991 -0
  137. sqlalchemy/orm/bulk_persistence.py +2168 -0
  138. sqlalchemy/orm/clsregistry.py +630 -0
  139. sqlalchemy/orm/collections.py +1569 -0
  140. sqlalchemy/orm/context.py +3475 -0
  141. sqlalchemy/orm/decl_api.py +2335 -0
  142. sqlalchemy/orm/decl_base.py +2300 -0
  143. sqlalchemy/orm/dependency.py +1306 -0
  144. sqlalchemy/orm/descriptor_props.py +1205 -0
  145. sqlalchemy/orm/dynamic.py +306 -0
  146. sqlalchemy/orm/evaluator.py +378 -0
  147. sqlalchemy/orm/events.py +3387 -0
  148. sqlalchemy/orm/exc.py +237 -0
  149. sqlalchemy/orm/identity.py +302 -0
  150. sqlalchemy/orm/instrumentation.py +749 -0
  151. sqlalchemy/orm/interfaces.py +1595 -0
  152. sqlalchemy/orm/loading.py +1712 -0
  153. sqlalchemy/orm/mapped_collection.py +557 -0
  154. sqlalchemy/orm/mapper.py +4465 -0
  155. sqlalchemy/orm/path_registry.py +907 -0
  156. sqlalchemy/orm/persistence.py +1790 -0
  157. sqlalchemy/orm/properties.py +972 -0
  158. sqlalchemy/orm/query.py +3528 -0
  159. sqlalchemy/orm/relationships.py +3615 -0
  160. sqlalchemy/orm/scoping.py +2251 -0
  161. sqlalchemy/orm/session.py +5493 -0
  162. sqlalchemy/orm/state.py +1175 -0
  163. sqlalchemy/orm/state_changes.py +196 -0
  164. sqlalchemy/orm/strategies.py +3559 -0
  165. sqlalchemy/orm/strategy_options.py +2648 -0
  166. sqlalchemy/orm/sync.py +164 -0
  167. sqlalchemy/orm/unitofwork.py +797 -0
  168. sqlalchemy/orm/util.py +2550 -0
  169. sqlalchemy/orm/writeonly.py +701 -0
  170. sqlalchemy/pool/__init__.py +41 -0
  171. sqlalchemy/pool/base.py +1544 -0
  172. sqlalchemy/pool/events.py +375 -0
  173. sqlalchemy/pool/impl.py +583 -0
  174. sqlalchemy/py.typed +0 -0
  175. sqlalchemy/schema.py +75 -0
  176. sqlalchemy/sql/__init__.py +156 -0
  177. sqlalchemy/sql/_annotated_cols.py +402 -0
  178. sqlalchemy/sql/_cache_key_cy.cp315-win32.pyd +0 -0
  179. sqlalchemy/sql/_cache_key_cy.py +363 -0
  180. sqlalchemy/sql/_dml_constructors.py +132 -0
  181. sqlalchemy/sql/_elements_constructors.py +2190 -0
  182. sqlalchemy/sql/_orm_types.py +19 -0
  183. sqlalchemy/sql/_selectable_constructors.py +840 -0
  184. sqlalchemy/sql/_typing.py +500 -0
  185. sqlalchemy/sql/_util_cy.cp315-win32.pyd +0 -0
  186. sqlalchemy/sql/_util_cy.pxd +11 -0
  187. sqlalchemy/sql/_util_cy.py +127 -0
  188. sqlalchemy/sql/annotation.py +590 -0
  189. sqlalchemy/sql/base.py +2852 -0
  190. sqlalchemy/sql/cache_key.py +915 -0
  191. sqlalchemy/sql/coercions.py +1373 -0
  192. sqlalchemy/sql/compiler.py +8469 -0
  193. sqlalchemy/sql/crud.py +1816 -0
  194. sqlalchemy/sql/ddl.py +1962 -0
  195. sqlalchemy/sql/default_comparator.py +660 -0
  196. sqlalchemy/sql/dml.py +2018 -0
  197. sqlalchemy/sql/elements.py +6062 -0
  198. sqlalchemy/sql/events.py +458 -0
  199. sqlalchemy/sql/expression.py +171 -0
  200. sqlalchemy/sql/functions.py +2380 -0
  201. sqlalchemy/sql/lambdas.py +1442 -0
  202. sqlalchemy/sql/naming.py +204 -0
  203. sqlalchemy/sql/operators.py +2909 -0
  204. sqlalchemy/sql/roles.py +332 -0
  205. sqlalchemy/sql/schema.py +7080 -0
  206. sqlalchemy/sql/selectable.py +7644 -0
  207. sqlalchemy/sql/sqltypes.py +4130 -0
  208. sqlalchemy/sql/traversals.py +1041 -0
  209. sqlalchemy/sql/type_api.py +2450 -0
  210. sqlalchemy/sql/util.py +1496 -0
  211. sqlalchemy/sql/visitors.py +1153 -0
  212. sqlalchemy/testing/__init__.py +97 -0
  213. sqlalchemy/testing/assertions.py +1007 -0
  214. sqlalchemy/testing/assertsql.py +519 -0
  215. sqlalchemy/testing/asyncio.py +128 -0
  216. sqlalchemy/testing/cancellation.py +237 -0
  217. sqlalchemy/testing/config.py +440 -0
  218. sqlalchemy/testing/engines.py +496 -0
  219. sqlalchemy/testing/entities.py +117 -0
  220. sqlalchemy/testing/exclusions.py +501 -0
  221. sqlalchemy/testing/fixtures/__init__.py +30 -0
  222. sqlalchemy/testing/fixtures/base.py +426 -0
  223. sqlalchemy/testing/fixtures/mypy.py +247 -0
  224. sqlalchemy/testing/fixtures/orm.py +227 -0
  225. sqlalchemy/testing/fixtures/sql.py +538 -0
  226. sqlalchemy/testing/pickleable.py +155 -0
  227. sqlalchemy/testing/plugin/__init__.py +6 -0
  228. sqlalchemy/testing/plugin/bootstrap.py +50 -0
  229. sqlalchemy/testing/plugin/plugin_base.py +828 -0
  230. sqlalchemy/testing/plugin/pytestplugin.py +896 -0
  231. sqlalchemy/testing/profiles_file.py +350 -0
  232. sqlalchemy/testing/profiling.py +294 -0
  233. sqlalchemy/testing/provision.py +633 -0
  234. sqlalchemy/testing/requirements.py +1990 -0
  235. sqlalchemy/testing/schema.py +198 -0
  236. sqlalchemy/testing/suite/__init__.py +19 -0
  237. sqlalchemy/testing/suite/test_cte.py +237 -0
  238. sqlalchemy/testing/suite/test_ddl.py +420 -0
  239. sqlalchemy/testing/suite/test_dialect.py +777 -0
  240. sqlalchemy/testing/suite/test_insert.py +630 -0
  241. sqlalchemy/testing/suite/test_reflection.py +3815 -0
  242. sqlalchemy/testing/suite/test_results.py +660 -0
  243. sqlalchemy/testing/suite/test_rowcount.py +258 -0
  244. sqlalchemy/testing/suite/test_select.py +2112 -0
  245. sqlalchemy/testing/suite/test_sequence.py +317 -0
  246. sqlalchemy/testing/suite/test_table_via_select.py +686 -0
  247. sqlalchemy/testing/suite/test_types.py +2271 -0
  248. sqlalchemy/testing/suite/test_unicode_ddl.py +189 -0
  249. sqlalchemy/testing/suite/test_update_delete.py +176 -0
  250. sqlalchemy/testing/util.py +575 -0
  251. sqlalchemy/testing/warnings.py +52 -0
  252. sqlalchemy/types.py +75 -0
  253. sqlalchemy/util/__init__.py +165 -0
  254. sqlalchemy/util/_collections.py +688 -0
  255. sqlalchemy/util/_collections_cy.cp315-win32.pyd +0 -0
  256. sqlalchemy/util/_collections_cy.pxd +8 -0
  257. sqlalchemy/util/_collections_cy.py +516 -0
  258. sqlalchemy/util/_has_cython.py +48 -0
  259. sqlalchemy/util/_immutabledict_cy.cp315-win32.pyd +0 -0
  260. sqlalchemy/util/_immutabledict_cy.py +240 -0
  261. sqlalchemy/util/compat.py +298 -0
  262. sqlalchemy/util/concurrency.py +272 -0
  263. sqlalchemy/util/cython.py +95 -0
  264. sqlalchemy/util/deprecations.py +401 -0
  265. sqlalchemy/util/langhelpers.py +2803 -0
  266. sqlalchemy/util/preloaded.py +153 -0
  267. sqlalchemy/util/queue.py +304 -0
  268. sqlalchemy/util/tool_support.py +202 -0
  269. sqlalchemy/util/topological.py +120 -0
  270. sqlalchemy/util/typing.py +709 -0
  271. sqlalchemy-2.1.0.dist-info/METADATA +270 -0
  272. sqlalchemy-2.1.0.dist-info/RECORD +276 -0
  273. sqlalchemy-2.1.0.dist-info/WHEEL +5 -0
  274. sqlalchemy-2.1.0.dist-info/licenses/AUTHORS +30 -0
  275. sqlalchemy-2.1.0.dist-info/licenses/LICENSE +19 -0
  276. sqlalchemy-2.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,2335 @@
1
+ # orm/decl_api.py
2
+ # Copyright (C) 2005-2026 the SQLAlchemy authors and contributors
3
+ # <see AUTHORS file>
4
+ #
5
+ # This module is part of SQLAlchemy and is released under
6
+ # the MIT License: https://www.opensource.org/licenses/mit-license.php
7
+
8
+ """Public API functions and helpers for declarative."""
9
+
10
+ from __future__ import annotations
11
+
12
+ import re
13
+ import typing
14
+ from typing import Any
15
+ from typing import Callable
16
+ from typing import cast
17
+ from typing import ClassVar
18
+ from typing import Dict
19
+ from typing import FrozenSet
20
+ from typing import Generic
21
+ from typing import Iterable
22
+ from typing import Iterator
23
+ from typing import Literal
24
+ from typing import Mapping
25
+ from typing import Optional
26
+ from typing import overload
27
+ from typing import Protocol
28
+ from typing import Set
29
+ from typing import Tuple
30
+ from typing import Type
31
+ from typing import TYPE_CHECKING
32
+ from typing import TypeVar
33
+ from typing import Union
34
+ import weakref
35
+
36
+ from . import attributes
37
+ from . import clsregistry
38
+ from . import instrumentation
39
+ from . import interfaces
40
+ from . import mapperlib
41
+ from ._orm_constructors import composite
42
+ from ._orm_constructors import deferred
43
+ from ._orm_constructors import mapped_column
44
+ from ._orm_constructors import relationship
45
+ from ._orm_constructors import synonym
46
+ from .attributes import InstrumentedAttribute
47
+ from .base import _inspect_mapped_class
48
+ from .base import _is_mapped_class
49
+ from .base import Mapped
50
+ from .base import ORMDescriptor
51
+ from .decl_base import _add_attribute
52
+ from .decl_base import _declarative_constructor
53
+ from .decl_base import _DeclarativeMapperConfig
54
+ from .decl_base import _DeclMappedClassProtocol
55
+ from .decl_base import _DeferredDeclarativeConfig
56
+ from .decl_base import _del_attribute
57
+ from .decl_base import _get_immediate_cls_attr
58
+ from .decl_base import _ORMClassConfigurator
59
+ from .decl_base import MappedClassProtocol
60
+ from .descriptor_props import Composite
61
+ from .descriptor_props import Synonym
62
+ from .descriptor_props import Synonym as _orm_synonym
63
+ from .mapper import Mapper
64
+ from .properties import MappedColumn
65
+ from .relationships import RelationshipProperty
66
+ from .state import InstanceState
67
+ from .. import event
68
+ from .. import exc
69
+ from .. import inspection
70
+ from .. import util
71
+ from ..event import dispatcher
72
+ from ..event import EventTarget
73
+ from ..sql import sqltypes
74
+ from ..sql._annotated_cols import _TC
75
+ from ..sql.base import _NoArg
76
+ from ..sql.elements import SQLCoreOperations
77
+ from ..sql.schema import MetaData
78
+ from ..sql.selectable import FromClause
79
+ from ..util import hybridmethod
80
+ from ..util import hybridproperty
81
+ from ..util import typing as compat_typing
82
+ from ..util import TypingOnly
83
+ from ..util.typing import CallableReference
84
+ from ..util.typing import de_optionalize_union_types
85
+ from ..util.typing import GenericProtocol
86
+ from ..util.typing import is_generic
87
+ from ..util.typing import is_literal
88
+ from ..util.typing import LITERAL_TYPES
89
+ from ..util.typing import Self
90
+ from ..util.typing import TypeAliasType
91
+
92
+ if TYPE_CHECKING:
93
+ from ._typing import _O
94
+ from ._typing import _RegistryType
95
+ from .instrumentation import ClassManager
96
+ from .interfaces import _DataclassArguments
97
+ from .interfaces import MapperProperty
98
+ from .state import InstanceState # noqa
99
+ from ..sql._typing import _TypeEngineArgument
100
+ from ..util.typing import _MatchedOnType
101
+
102
+ _T = TypeVar("_T", bound=Any)
103
+ _T_co = TypeVar("_T_co", bound=Any, covariant=True)
104
+
105
+ _TT = TypeVar("_TT", bound=Any)
106
+
107
+ # it's not clear how to have Annotated, Union objects etc. as keys here
108
+ # from a typing perspective so just leave it open ended for now
109
+ _TypeAnnotationMapType = Mapping[Any, "_TypeEngineArgument[Any]"]
110
+ _MutableTypeAnnotationMapType = Dict[Any, "_TypeEngineArgument[Any]"]
111
+
112
+ _DeclaredAttrDecorated = Callable[
113
+ ..., Union[Mapped[_T_co], ORMDescriptor[_T_co], SQLCoreOperations[_T_co]]
114
+ ]
115
+
116
+
117
+ def has_inherited_table(cls: Type[_O]) -> bool:
118
+ """Given a class, return True if any of the classes it inherits from has a
119
+ mapped table, otherwise return False.
120
+
121
+ This is used in declarative mixins to build attributes that behave
122
+ differently for the base class vs. a subclass in an inheritance
123
+ hierarchy.
124
+
125
+ .. seealso::
126
+
127
+ :ref:`decl_mixin_inheritance`
128
+
129
+ """
130
+ for class_ in cls.__mro__[1:]:
131
+ if getattr(class_, "__table__", None) is not None:
132
+ return True
133
+ return False
134
+
135
+
136
+ class _DynamicAttributesType(type):
137
+ def __setattr__(cls, key: str, value: Any) -> None:
138
+ if "__mapper__" in cls.__dict__:
139
+ _add_attribute(cls, key, value)
140
+ else:
141
+ type.__setattr__(cls, key, value)
142
+
143
+ def __delattr__(cls, key: str) -> None:
144
+ if "__mapper__" in cls.__dict__:
145
+ _del_attribute(cls, key)
146
+ else:
147
+ type.__delattr__(cls, key)
148
+
149
+
150
+ class DeclarativeAttributeIntercept(
151
+ _DynamicAttributesType,
152
+ # Inspectable is used only by the mypy plugin
153
+ inspection.Inspectable[Mapper[Any]],
154
+ ):
155
+ """Metaclass that may be used in conjunction with the
156
+ :class:`_orm.DeclarativeBase` class to support addition of class
157
+ attributes dynamically.
158
+
159
+ """
160
+
161
+
162
+ @compat_typing.dataclass_transform(
163
+ field_specifiers=(
164
+ MappedColumn,
165
+ RelationshipProperty,
166
+ Composite,
167
+ Synonym,
168
+ mapped_column,
169
+ relationship,
170
+ composite,
171
+ synonym,
172
+ deferred,
173
+ ),
174
+ )
175
+ class DCTransformDeclarative(DeclarativeAttributeIntercept):
176
+ """metaclass that includes @dataclass_transforms"""
177
+
178
+
179
+ class DeclarativeMeta(DeclarativeAttributeIntercept):
180
+ metadata: MetaData
181
+ registry: RegistryType
182
+
183
+ def __init__(
184
+ cls, classname: Any, bases: Any, dict_: Any, **kw: Any
185
+ ) -> None:
186
+ # use cls.__dict__, which can be modified by an
187
+ # __init_subclass__() method (#7900)
188
+ dict_ = cls.__dict__
189
+
190
+ # early-consume registry from the initial declarative base,
191
+ # assign privately to not conflict with subclass attributes named
192
+ # "registry"
193
+ reg = getattr(cls, "_sa_registry", None)
194
+ if reg is None:
195
+ reg = dict_.get("registry", None)
196
+ if not isinstance(reg, registry):
197
+ raise exc.InvalidRequestError(
198
+ "Declarative base class has no 'registry' attribute, "
199
+ "or registry is not a sqlalchemy.orm.registry() object"
200
+ )
201
+ else:
202
+ cls._sa_registry = reg
203
+
204
+ if not cls.__dict__.get("__abstract__", False):
205
+ _ORMClassConfigurator._as_declarative(reg, cls, dict_)
206
+ type.__init__(cls, classname, bases, dict_)
207
+
208
+
209
+ def synonym_for(
210
+ name: str, map_column: bool = False
211
+ ) -> Callable[[Callable[..., Any]], Synonym[Any]]:
212
+ """Decorator that produces an :func:`_orm.synonym`
213
+ attribute in conjunction with a Python descriptor.
214
+
215
+ The function being decorated is passed to :func:`_orm.synonym` as the
216
+ :paramref:`.orm.synonym.descriptor` parameter::
217
+
218
+ class MyClass(Base):
219
+ __tablename__ = "my_table"
220
+
221
+ id = Column(Integer, primary_key=True)
222
+ _job_status = Column("job_status", String(50))
223
+
224
+ @synonym_for("job_status")
225
+ @property
226
+ def job_status(self):
227
+ return "Status: %s" % self._job_status
228
+
229
+ The :ref:`hybrid properties <mapper_hybrids>` feature of SQLAlchemy
230
+ is typically preferred instead of synonyms, which is a more legacy
231
+ feature.
232
+
233
+ .. seealso::
234
+
235
+ :ref:`synonyms` - Overview of synonyms
236
+
237
+ :func:`_orm.synonym` - the mapper-level function
238
+
239
+ :ref:`mapper_hybrids` - The Hybrid Attribute extension provides an
240
+ updated approach to augmenting attribute behavior more flexibly than
241
+ can be achieved with synonyms.
242
+
243
+ """
244
+
245
+ def decorate(fn: Callable[..., Any]) -> Synonym[Any]:
246
+ return _orm_synonym(name, map_column=map_column, descriptor=fn)
247
+
248
+ return decorate
249
+
250
+
251
+ class _declared_attr_common:
252
+ def __init__(
253
+ self,
254
+ fn: Callable[..., Any],
255
+ cascading: bool = False,
256
+ quiet: bool = False,
257
+ ):
258
+ # support
259
+ # @declared_attr
260
+ # @classmethod
261
+ # def foo(cls) -> Mapped[thing]:
262
+ # ...
263
+ # which seems to help typing tools interpret the fn as a classmethod
264
+ # for situations where needed
265
+ if isinstance(fn, classmethod):
266
+ fn = fn.__func__
267
+
268
+ self.fget = fn
269
+ self._cascading = cascading
270
+ self._quiet = quiet
271
+ self.__doc__ = fn.__doc__
272
+
273
+ def _collect_return_annotation(self) -> Optional[Type[Any]]:
274
+ return util.get_annotations(self.fget).get("return")
275
+
276
+ def __get__(self, instance: Optional[object], owner: Any) -> Any:
277
+ # the declared_attr needs to make use of a cache that exists
278
+ # for the span of the declarative scan_attributes() phase.
279
+ # to achieve this we look at the class manager that's configured.
280
+
281
+ # note this method should not be called outside of the declarative
282
+ # setup phase
283
+
284
+ cls = owner
285
+ manager = attributes.opt_manager_of_class(cls)
286
+ if manager is None:
287
+ if not re.match(r"^__.+__$", self.fget.__name__):
288
+ # if there is no manager at all, then this class hasn't been
289
+ # run through declarative or mapper() at all, emit a warning.
290
+ util.warn(
291
+ "Unmanaged access of declarative attribute %s from "
292
+ "non-mapped class %s" % (self.fget.__name__, cls.__name__)
293
+ )
294
+ return self.fget(cls)
295
+ elif manager.is_mapped:
296
+ # the class is mapped, which means we're outside of the declarative
297
+ # scan setup, just run the function.
298
+ return self.fget(cls)
299
+
300
+ # here, we are inside of the declarative scan. use the registry
301
+ # that is tracking the values of these attributes.
302
+ declarative_scan = manager.declarative_scan()
303
+
304
+ # assert that we are in fact in the declarative scan
305
+ assert declarative_scan is not None
306
+
307
+ reg = declarative_scan.declared_attr_reg
308
+
309
+ if self in reg:
310
+ return reg[self]
311
+ else:
312
+ reg[self] = obj = self.fget(cls)
313
+ return obj
314
+
315
+
316
+ class _declared_directive(_declared_attr_common, Generic[_T]):
317
+ # see mapping_api.rst for docstring
318
+
319
+ if typing.TYPE_CHECKING:
320
+
321
+ def __init__(
322
+ self,
323
+ fn: Callable[..., _T],
324
+ cascading: bool = False,
325
+ ): ...
326
+
327
+ def __get__(self, instance: Optional[object], owner: Any) -> _T: ...
328
+
329
+ def __set__(self, instance: Any, value: Any) -> None: ...
330
+
331
+ def __delete__(self, instance: Any) -> None: ...
332
+
333
+ def __call__(self, fn: Callable[..., _TT]) -> _declared_directive[_TT]:
334
+ # extensive fooling of mypy underway...
335
+ ...
336
+
337
+
338
+ class declared_attr(interfaces._MappedAttribute[_T_co], _declared_attr_common):
339
+ """Mark a class-level method as representing the definition of
340
+ a mapped property or Declarative directive.
341
+
342
+ :class:`_orm.declared_attr` is typically applied as a decorator to a class
343
+ level method, turning the attribute into a scalar-like property that can be
344
+ invoked from the uninstantiated class. The Declarative mapping process
345
+ looks for these :class:`_orm.declared_attr` callables as it scans classes,
346
+ and assumes any attribute marked with :class:`_orm.declared_attr` will be a
347
+ callable that will produce an object specific to the Declarative mapping or
348
+ table configuration.
349
+
350
+ :class:`_orm.declared_attr` is usually applicable to
351
+ :ref:`mixins <orm_mixins_toplevel>`, to define relationships that are to be
352
+ applied to different implementors of the class. It may also be used to
353
+ define dynamically generated column expressions and other Declarative
354
+ attributes.
355
+
356
+ Example::
357
+
358
+ class ProvidesUserMixin:
359
+ "A mixin that adds a 'user' relationship to classes."
360
+
361
+ user_id: Mapped[int] = mapped_column(ForeignKey("user_table.id"))
362
+
363
+ @declared_attr
364
+ def user(cls) -> Mapped["User"]:
365
+ return relationship("User")
366
+
367
+ When used with Declarative directives such as ``__tablename__``, the
368
+ :meth:`_orm.declared_attr.directive` modifier may be used which indicates
369
+ to :pep:`484` typing tools that the given method is not dealing with
370
+ :class:`_orm.Mapped` attributes::
371
+
372
+ class CreateTableName:
373
+ @declared_attr.directive
374
+ def __tablename__(cls) -> str:
375
+ return cls.__name__.lower()
376
+
377
+ :class:`_orm.declared_attr` can also be applied directly to mapped
378
+ classes, to allow for attributes that dynamically configure themselves
379
+ on subclasses when using mapped inheritance schemes. Below
380
+ illustrates :class:`_orm.declared_attr` to create a dynamic scheme
381
+ for generating the :paramref:`_orm.Mapper.polymorphic_identity` parameter
382
+ for subclasses::
383
+
384
+ class Employee(Base):
385
+ __tablename__ = "employee"
386
+
387
+ id: Mapped[int] = mapped_column(primary_key=True)
388
+ type: Mapped[str] = mapped_column(String(50))
389
+
390
+ @declared_attr.directive
391
+ def __mapper_args__(cls) -> Dict[str, Any]:
392
+ if cls.__name__ == "Employee":
393
+ return {
394
+ "polymorphic_on": cls.type,
395
+ "polymorphic_identity": "Employee",
396
+ }
397
+ else:
398
+ return {"polymorphic_identity": cls.__name__}
399
+
400
+
401
+ class Engineer(Employee):
402
+ pass
403
+
404
+ :class:`_orm.declared_attr` supports decorating functions that are
405
+ explicitly decorated with ``@classmethod``. This is never necessary from a
406
+ runtime perspective, however may be needed in order to support :pep:`484`
407
+ typing tools that don't otherwise recognize the decorated function as
408
+ having class-level behaviors for the ``cls`` parameter::
409
+
410
+ class SomethingMixin:
411
+ x: Mapped[int]
412
+ y: Mapped[int]
413
+
414
+ @declared_attr
415
+ @classmethod
416
+ def x_plus_y(cls) -> Mapped[int]:
417
+ return column_property(cls.x + cls.y)
418
+
419
+ .. versionadded:: 2.0 - :class:`_orm.declared_attr` can accommodate a
420
+ function decorated with ``@classmethod`` to help with :pep:`484`
421
+ integration where needed.
422
+
423
+
424
+ .. seealso::
425
+
426
+ :ref:`orm_mixins_toplevel` - Declarative Mixin documentation with
427
+ background on use patterns for :class:`_orm.declared_attr`.
428
+
429
+ """ # noqa: E501
430
+
431
+ if typing.TYPE_CHECKING:
432
+
433
+ def __init__(
434
+ self,
435
+ fn: _DeclaredAttrDecorated[_T_co],
436
+ cascading: bool = False,
437
+ ): ...
438
+
439
+ def __set__(self, instance: Any, value: Any) -> None: ...
440
+
441
+ def __delete__(self, instance: Any) -> None: ...
442
+
443
+ # this is the Mapped[] API where at class descriptor get time we want
444
+ # the type checker to see InstrumentedAttribute[_T]. However the
445
+ # callable function prior to mapping in fact calls the given
446
+ # declarative function that does not return InstrumentedAttribute
447
+ @overload
448
+ def __get__(
449
+ self, instance: None, owner: Any
450
+ ) -> InstrumentedAttribute[_T_co]: ...
451
+
452
+ @overload
453
+ def __get__(self, instance: object, owner: Any) -> _T_co: ...
454
+
455
+ def __get__(
456
+ self, instance: Optional[object], owner: Any
457
+ ) -> Union[InstrumentedAttribute[_T_co], _T_co]: ...
458
+
459
+ @hybridmethod
460
+ def _stateful(cls, **kw: Any) -> _stateful_declared_attr[_T_co]:
461
+ return _stateful_declared_attr(**kw)
462
+
463
+ @hybridproperty
464
+ def directive(cls) -> _declared_directive[Any]:
465
+ # see mapping_api.rst for docstring
466
+ return _declared_directive # type: ignore[return-value]
467
+
468
+ @hybridproperty
469
+ def cascading(cls) -> _stateful_declared_attr[_T_co]:
470
+ # see mapping_api.rst for docstring
471
+ return cls._stateful(cascading=True)
472
+
473
+
474
+ class _stateful_declared_attr(declared_attr[_T_co]):
475
+ kw: Dict[str, Any]
476
+
477
+ def __init__(self, **kw: Any):
478
+ self.kw = kw
479
+
480
+ @hybridmethod
481
+ def _stateful(self, **kw: Any) -> _stateful_declared_attr[_T_co]:
482
+ new_kw = self.kw.copy()
483
+ new_kw.update(kw)
484
+ return _stateful_declared_attr(**new_kw)
485
+
486
+ def __call__(
487
+ self, fn: _DeclaredAttrDecorated[_T_co]
488
+ ) -> declared_attr[_T_co]:
489
+ return declared_attr(fn, **self.kw)
490
+
491
+
492
+ @util.deprecated(
493
+ "2.1",
494
+ "The declarative_mixin decorator was used only by the now removed "
495
+ "mypy plugin so it has no longer any use and can be safely removed.",
496
+ )
497
+ def declarative_mixin(cls: Type[_T]) -> Type[_T]:
498
+ """Mark a class as providing the feature of "declarative mixin".
499
+
500
+ E.g.::
501
+
502
+ from sqlalchemy.orm import declared_attr
503
+ from sqlalchemy.orm import declarative_mixin
504
+
505
+
506
+ @declarative_mixin
507
+ class MyMixin:
508
+
509
+ @declared_attr
510
+ def __tablename__(cls):
511
+ return cls.__name__.lower()
512
+
513
+ __table_args__ = {"mysql_engine": "InnoDB"}
514
+ __mapper_args__ = {"always_refresh": True}
515
+
516
+ id = Column(Integer, primary_key=True)
517
+
518
+
519
+ class MyModel(MyMixin, Base):
520
+ name = Column(String(1000))
521
+
522
+ The :func:`_orm.declarative_mixin` decorator currently does not modify
523
+ the given class in any way; it's current purpose is strictly to assist
524
+ the Mypy plugin in being able to identify
525
+ SQLAlchemy declarative mixin classes when no other context is present.
526
+
527
+ .. versionadded:: 1.4.6
528
+
529
+ .. seealso::
530
+
531
+ :ref:`orm_mixins_toplevel`
532
+
533
+ """ # noqa: E501
534
+
535
+ return cls
536
+
537
+
538
+ def _setup_declarative_base(cls: Type[Any]) -> None:
539
+ metadata = getattr(cls, "metadata", None)
540
+ type_annotation_map = getattr(cls, "type_annotation_map", None)
541
+ reg = getattr(cls, "registry", None)
542
+
543
+ if reg is not None:
544
+ if not isinstance(reg, registry):
545
+ raise exc.InvalidRequestError(
546
+ "Declarative base class has a 'registry' attribute that is "
547
+ "not an instance of sqlalchemy.orm.registry()"
548
+ )
549
+ elif type_annotation_map is not None:
550
+ raise exc.InvalidRequestError(
551
+ "Declarative base class has both a 'registry' attribute and a "
552
+ "type_annotation_map entry. Per-base type_annotation_maps "
553
+ "are not supported. Please apply the type_annotation_map "
554
+ "to this registry directly."
555
+ )
556
+
557
+ else:
558
+ reg = registry(
559
+ metadata=metadata, type_annotation_map=type_annotation_map
560
+ )
561
+ cls.registry = reg
562
+
563
+ cls._sa_registry = reg
564
+
565
+ if "metadata" not in cls.__dict__:
566
+ cls.metadata = cls.registry.metadata
567
+
568
+ if getattr(cls, "__init__", object.__init__) is object.__init__:
569
+ cls.__init__ = cls.registry.constructor
570
+
571
+
572
+ def _generate_dc_transforms(
573
+ cls_: Type[_O],
574
+ init: Union[_NoArg, bool] = _NoArg.NO_ARG,
575
+ repr: Union[_NoArg, bool] = _NoArg.NO_ARG, # noqa: A002
576
+ eq: Union[_NoArg, bool] = _NoArg.NO_ARG,
577
+ order: Union[_NoArg, bool] = _NoArg.NO_ARG,
578
+ unsafe_hash: Union[_NoArg, bool] = _NoArg.NO_ARG,
579
+ match_args: Union[_NoArg, bool] = _NoArg.NO_ARG,
580
+ kw_only: Union[_NoArg, bool] = _NoArg.NO_ARG,
581
+ dataclass_callable: Union[
582
+ _NoArg, Callable[..., Type[Any]]
583
+ ] = _NoArg.NO_ARG,
584
+ ) -> None:
585
+ apply_dc_transforms: _DataclassArguments = {
586
+ "init": init,
587
+ "repr": repr,
588
+ "eq": eq,
589
+ "order": order,
590
+ "unsafe_hash": unsafe_hash,
591
+ "match_args": match_args,
592
+ "kw_only": kw_only,
593
+ "dataclass_callable": dataclass_callable,
594
+ }
595
+
596
+ if hasattr(cls_, "_sa_apply_dc_transforms"):
597
+ current = cls_._sa_apply_dc_transforms # type: ignore[attr-defined]
598
+
599
+ _DeclarativeMapperConfig._assert_dc_arguments(current)
600
+
601
+ cls_._sa_apply_dc_transforms = { # type: ignore[attr-defined] # noqa: E501
602
+ k: current.get(k, _NoArg.NO_ARG) if v is _NoArg.NO_ARG else v
603
+ for k, v in apply_dc_transforms.items()
604
+ }
605
+ else:
606
+ setattr(cls_, "_sa_apply_dc_transforms", apply_dc_transforms)
607
+
608
+
609
+ class MappedAsDataclass(metaclass=DCTransformDeclarative):
610
+ """Mixin class to indicate when mapping this class, also convert it to be
611
+ a dataclass.
612
+
613
+ .. seealso::
614
+
615
+ :ref:`orm_declarative_native_dataclasses` - complete background
616
+ on SQLAlchemy native dataclass mapping with
617
+ :class:`_orm.MappedAsDataclass`.
618
+
619
+ :ref:`orm_declarative_dc_mixins` - examples specific to using
620
+ :class:`_orm.MappedAsDataclass` to create mixins
621
+
622
+ :func:`_orm.mapped_as_dataclass` / :func:`_orm.unmapped_dataclass` -
623
+ decorator versions with equivalent functionality
624
+
625
+ .. versionadded:: 2.0
626
+
627
+ """
628
+
629
+ def __init_subclass__(
630
+ cls,
631
+ init: Union[_NoArg, bool] = _NoArg.NO_ARG,
632
+ repr: Union[_NoArg, bool] = _NoArg.NO_ARG, # noqa: A002
633
+ eq: Union[_NoArg, bool] = _NoArg.NO_ARG,
634
+ order: Union[_NoArg, bool] = _NoArg.NO_ARG,
635
+ unsafe_hash: Union[_NoArg, bool] = _NoArg.NO_ARG,
636
+ match_args: Union[_NoArg, bool] = _NoArg.NO_ARG,
637
+ kw_only: Union[_NoArg, bool] = _NoArg.NO_ARG,
638
+ dataclass_callable: Union[
639
+ _NoArg, Callable[..., Type[Any]]
640
+ ] = _NoArg.NO_ARG,
641
+ **kw: Any,
642
+ ) -> None:
643
+ _generate_dc_transforms(
644
+ init=init,
645
+ repr=repr,
646
+ eq=eq,
647
+ order=order,
648
+ unsafe_hash=unsafe_hash,
649
+ match_args=match_args,
650
+ kw_only=kw_only,
651
+ dataclass_callable=dataclass_callable,
652
+ cls_=cls,
653
+ )
654
+ super().__init_subclass__(**kw)
655
+
656
+ if not _is_mapped_class(cls):
657
+ # turn unmapped classes into "good enough" dataclasses to serve
658
+ # as a base or a mixin
659
+ _ORMClassConfigurator._as_unmapped_dataclass(cls, cls.__dict__)
660
+
661
+
662
+ class _DeclarativeTyping(TypingOnly):
663
+ """Common typing annotations shared by the DeclarativeBase and
664
+ DeclarativeBaseNoMeta classes.
665
+ """
666
+
667
+ __slots__ = ()
668
+
669
+ if typing.TYPE_CHECKING:
670
+ # protocols for inspection
671
+ def _sa_inspect_type(self) -> Mapper[Self]: ...
672
+
673
+ def _sa_inspect_instance(self) -> InstanceState[Self]: ...
674
+
675
+ # internal stuff
676
+ _sa_registry: ClassVar[_RegistryType]
677
+
678
+ # public interface
679
+ registry: ClassVar[_RegistryType]
680
+ """Refers to the :class:`_orm.registry` in use where new
681
+ :class:`_orm.Mapper` objects will be associated."""
682
+
683
+ metadata: ClassVar[MetaData]
684
+ """Refers to the :class:`_schema.MetaData` collection that will be used
685
+ for new :class:`_schema.Table` objects.
686
+
687
+ .. seealso::
688
+
689
+ :ref:`orm_declarative_metadata`
690
+
691
+ """
692
+
693
+ __name__: ClassVar[str]
694
+
695
+ # this ideally should be Mapper[Self], but mypy as of 1.4.1 does not
696
+ # like it, and breaks the declared_attr_one test. Pyright/pylance is
697
+ # ok with it.
698
+ __mapper__: ClassVar[Mapper[Any]]
699
+ """The :class:`_orm.Mapper` object to which a particular class is
700
+ mapped.
701
+
702
+ May also be acquired using :func:`_sa.inspect`, e.g.
703
+ ``inspect(klass)``.
704
+
705
+ """
706
+
707
+ __table__: ClassVar[FromClause]
708
+ """The :class:`_sql.FromClause` to which a particular subclass is
709
+ mapped.
710
+
711
+ This is usually an instance of :class:`_schema.Table` but may also
712
+ refer to other kinds of :class:`_sql.FromClause` such as
713
+ :class:`_sql.Subquery`, depending on how the class is mapped.
714
+
715
+ .. seealso::
716
+
717
+ :ref:`orm_declarative_metadata`
718
+
719
+ """
720
+
721
+ # pyright/pylance do not consider a classmethod a ClassVar so use Any
722
+ # https://github.com/microsoft/pylance-release/issues/3484
723
+ __tablename__: Any
724
+ """String name to assign to the generated
725
+ :class:`_schema.Table` object, if not specified directly via
726
+ :attr:`_orm.DeclarativeBase.__table__`.
727
+
728
+ .. seealso::
729
+
730
+ :ref:`orm_declarative_table`
731
+
732
+ """
733
+
734
+ __mapper_args__: Any
735
+ """Dictionary of arguments which will be passed to the
736
+ :class:`_orm.Mapper` constructor.
737
+
738
+ .. seealso::
739
+
740
+ :ref:`orm_declarative_mapper_options`
741
+
742
+ """
743
+
744
+ __table_args__: Any
745
+ """A dictionary or tuple of arguments that will be passed to the
746
+ :class:`_schema.Table` constructor. See
747
+ :ref:`orm_declarative_table_configuration`
748
+ for background on the specific structure of this collection.
749
+
750
+ .. seealso::
751
+
752
+ :ref:`orm_declarative_table_configuration`
753
+
754
+ """
755
+
756
+ def __init__(self, **kw: Any): ...
757
+
758
+
759
+ class MappedClassWithTypedColumnsProtocol(Protocol[_TC]):
760
+ """An ORM mapped class that also defines in the ``__typed_cols__``
761
+ attribute its typed columns.
762
+
763
+ .. versionadded:: 2.1.0b2
764
+ """
765
+
766
+ __typed_cols__: _TC
767
+ """The :class:`_schema.TypedColumns` of this ORM mapped class."""
768
+
769
+ __name__: ClassVar[str]
770
+ __mapper__: ClassVar[Mapper[Any]]
771
+ __table__: ClassVar[FromClause]
772
+
773
+
774
+ @overload
775
+ def as_typed_table(
776
+ cls: type[MappedClassWithTypedColumnsProtocol[_TC]], /
777
+ ) -> FromClause[_TC]: ...
778
+
779
+
780
+ @overload
781
+ def as_typed_table(
782
+ cls: MappedClassProtocol[Any], typed_columns_cls: type[_TC], /
783
+ ) -> FromClause[_TC]: ...
784
+
785
+
786
+ def as_typed_table(
787
+ cls: (
788
+ MappedClassProtocol[Any]
789
+ | type[MappedClassWithTypedColumnsProtocol[Any]]
790
+ ),
791
+ typed_columns_cls: Any = None,
792
+ /,
793
+ ) -> FromClause[Any]:
794
+ """Return a typed :class:`_sql.FromClause` from the give ORM model.
795
+
796
+ This function is just a typing help, at runtime it just returns the
797
+ ``__table__`` attribute of the provided ORM model.
798
+
799
+ It's usually called providing both the ORM model and the
800
+ :class:`_schema.TypedColumns` class. Single argument calls are supported
801
+ if the ORM model class provides an annotation pointing to its
802
+ :class:`_schema.TypedColumns` in the ``__typed_cols__`` attribute.
803
+
804
+
805
+ Example usage::
806
+
807
+ from sqlalchemy import TypedColumns
808
+ from sqlalchemy.orm import DeclarativeBase, mapped_column
809
+ from sqlalchemy.orm import MappedColumn, as_typed_table
810
+
811
+
812
+ class Base(DeclarativeBase):
813
+ pass
814
+
815
+
816
+ class A(Base):
817
+ __tablename__ = "a"
818
+
819
+ id: MappedColumn[int] = mapped_column(primary_key=True)
820
+ data: MappedColumn[str]
821
+
822
+
823
+ class a_cols(A, TypedColumns):
824
+ pass
825
+
826
+
827
+ # table_a is annotated as FromClause[a_cols]
828
+ table_a = as_typed_table(A, a_cols)
829
+
830
+
831
+ class B(Base):
832
+ __tablename__ = "b"
833
+ __typed_cols__: "b_cols"
834
+
835
+ a: Mapped[int] = mapped_column(primary_key=True)
836
+ b: Mapped[str]
837
+
838
+
839
+ class b_cols(B, TypedColumns):
840
+ pass
841
+
842
+
843
+ # table_b is a FromClause[b_cols], can call with just B since it
844
+ # provides the __typed_cols__ annotation
845
+ table_b = as_typed_table(B)
846
+
847
+ For proper typing integration :class:`_orm.MappedColumn` should be used
848
+ to annotate the single columns, since it's a more specific annotation than
849
+ the usual :class:`_orm.Mapped` used for ORM attributes.
850
+
851
+ .. versionadded:: 2.1.0b2
852
+ """
853
+ return cls.__table__
854
+
855
+
856
+ class DeclarativeBase(
857
+ # Inspectable is used only by the mypy plugin
858
+ inspection.Inspectable[InstanceState[Any]],
859
+ _DeclarativeTyping,
860
+ metaclass=DeclarativeAttributeIntercept,
861
+ ):
862
+ """Base class used for declarative class definitions.
863
+
864
+ The :class:`_orm.DeclarativeBase` allows for the creation of new
865
+ declarative bases in such a way that is compatible with type checkers::
866
+
867
+
868
+ from sqlalchemy.orm import DeclarativeBase
869
+
870
+
871
+ class Base(DeclarativeBase):
872
+ pass
873
+
874
+ The above ``Base`` class is now usable as the base for new declarative
875
+ mappings. The superclass makes use of the ``__init_subclass__()``
876
+ method to set up new classes and metaclasses aren't used.
877
+
878
+ When first used, the :class:`_orm.DeclarativeBase` class instantiates a new
879
+ :class:`_orm.registry` to be used with the base, assuming one was not
880
+ provided explicitly. The :class:`_orm.DeclarativeBase` class supports
881
+ class-level attributes which act as parameters for the construction of this
882
+ registry; such as to indicate a specific :class:`_schema.MetaData`
883
+ collection as well as a specific value for
884
+ :paramref:`_orm.registry.type_annotation_map`::
885
+
886
+ from typing import Annotated
887
+
888
+ from sqlalchemy import BigInteger
889
+ from sqlalchemy import MetaData
890
+ from sqlalchemy import String
891
+ from sqlalchemy.orm import DeclarativeBase
892
+
893
+ bigint = Annotated[int, "bigint"]
894
+ my_metadata = MetaData()
895
+
896
+
897
+ class Base(DeclarativeBase):
898
+ metadata = my_metadata
899
+ type_annotation_map = {
900
+ str: String().with_variant(String(255), "mysql", "mariadb"),
901
+ bigint: BigInteger(),
902
+ }
903
+
904
+ Class-level attributes which may be specified include:
905
+
906
+ :param metadata: optional :class:`_schema.MetaData` collection.
907
+ If a :class:`_orm.registry` is constructed automatically, this
908
+ :class:`_schema.MetaData` collection will be used to construct it.
909
+ Otherwise, the local :class:`_schema.MetaData` collection will supersede
910
+ that used by an existing :class:`_orm.registry` passed using the
911
+ :paramref:`_orm.DeclarativeBase.registry` parameter.
912
+ :param type_annotation_map: optional type annotation map that will be
913
+ passed to the :class:`_orm.registry` as
914
+ :paramref:`_orm.registry.type_annotation_map`.
915
+ :param registry: supply a pre-existing :class:`_orm.registry` directly.
916
+
917
+ .. versionadded:: 2.0 Added :class:`.DeclarativeBase`, so that declarative
918
+ base classes may be constructed in such a way that is also recognized
919
+ by :pep:`484` type checkers. As a result, :class:`.DeclarativeBase`
920
+ and other subclassing-oriented APIs should be seen as
921
+ superseding previous "class returned by a function" APIs, namely
922
+ :func:`_orm.declarative_base` and :meth:`_orm.registry.generate_base`,
923
+ where the base class returned cannot be recognized by type checkers
924
+ without using plugins.
925
+
926
+ **__init__ behavior**
927
+
928
+ In a plain Python class, the base-most ``__init__()`` method in the class
929
+ hierarchy is ``object.__init__()``, which accepts no arguments. However,
930
+ when the :class:`_orm.DeclarativeBase` subclass is first declared, the
931
+ class is given an ``__init__()`` method that links to the
932
+ :paramref:`_orm.registry.constructor` constructor function, if no
933
+ ``__init__()`` method is already present; this is the usual declarative
934
+ constructor that will assign keyword arguments as attributes on the
935
+ instance, assuming those attributes are established at the class level
936
+ (i.e. are mapped, or are linked to a descriptor). This constructor is
937
+ **never accessed by a mapped class without being called explicitly via
938
+ super()**, as mapped classes are themselves given an ``__init__()`` method
939
+ directly which calls :paramref:`_orm.registry.constructor`, so in the
940
+ default case works independently of what the base-most ``__init__()``
941
+ method does.
942
+
943
+ .. versionchanged:: 2.0.1 :class:`_orm.DeclarativeBase` has a default
944
+ constructor that links to :paramref:`_orm.registry.constructor` by
945
+ default, so that calls to ``super().__init__()`` can access this
946
+ constructor. Previously, due to an implementation mistake, this default
947
+ constructor was missing, and calling ``super().__init__()`` would invoke
948
+ ``object.__init__()``.
949
+
950
+ The :class:`_orm.DeclarativeBase` subclass may also declare an explicit
951
+ ``__init__()`` method which will replace the use of the
952
+ :paramref:`_orm.registry.constructor` function at this level::
953
+
954
+ class Base(DeclarativeBase):
955
+ def __init__(self, id=None):
956
+ self.id = id
957
+
958
+ Mapped classes still will not invoke this constructor implicitly; it
959
+ remains only accessible by calling ``super().__init__()``::
960
+
961
+ class MyClass(Base):
962
+ def __init__(self, id=None, name=None):
963
+ self.name = name
964
+ super().__init__(id=id)
965
+
966
+ Note that this is a different behavior from what functions like the legacy
967
+ :func:`_orm.declarative_base` would do; the base created by those functions
968
+ would always install :paramref:`_orm.registry.constructor` for
969
+ ``__init__()``.
970
+
971
+
972
+ """
973
+
974
+ def __init_subclass__(cls, **kw: Any) -> None:
975
+ if DeclarativeBase in cls.__bases__:
976
+ _check_not_declarative(cls, DeclarativeBase)
977
+ _setup_declarative_base(cls)
978
+ else:
979
+ _ORMClassConfigurator._as_declarative(
980
+ cls._sa_registry, cls, cls.__dict__
981
+ )
982
+ super().__init_subclass__(**kw)
983
+
984
+
985
+ def _check_not_declarative(cls: Type[Any], base: Type[Any]) -> None:
986
+ cls_dict = cls.__dict__
987
+ if (
988
+ "__table__" in cls_dict
989
+ and not (
990
+ callable(cls_dict["__table__"])
991
+ or hasattr(cls_dict["__table__"], "__get__")
992
+ )
993
+ ) or isinstance(cls_dict.get("__tablename__", None), str):
994
+ raise exc.InvalidRequestError(
995
+ f"Cannot use {base.__name__!r} directly as a declarative base "
996
+ "class. Create a Base by creating a subclass of it."
997
+ )
998
+
999
+
1000
+ class DeclarativeBaseNoMeta(
1001
+ # Inspectable is used only by the mypy plugin
1002
+ inspection.Inspectable[InstanceState[Any]],
1003
+ _DeclarativeTyping,
1004
+ ):
1005
+ """Same as :class:`_orm.DeclarativeBase`, but does not use a metaclass
1006
+ to intercept new attributes.
1007
+
1008
+ The :class:`_orm.DeclarativeBaseNoMeta` base may be used when use of
1009
+ custom metaclasses is desirable.
1010
+
1011
+ .. versionadded:: 2.0
1012
+
1013
+
1014
+ """
1015
+
1016
+ def __init_subclass__(cls, **kw: Any) -> None:
1017
+ if DeclarativeBaseNoMeta in cls.__bases__:
1018
+ _check_not_declarative(cls, DeclarativeBaseNoMeta)
1019
+ _setup_declarative_base(cls)
1020
+ else:
1021
+ _ORMClassConfigurator._as_declarative(
1022
+ cls._sa_registry, cls, cls.__dict__
1023
+ )
1024
+ super().__init_subclass__(**kw)
1025
+
1026
+
1027
+ def add_mapped_attribute(
1028
+ target: Type[_O], key: str, attr: MapperProperty[Any]
1029
+ ) -> None:
1030
+ """Add a new mapped attribute to an ORM mapped class.
1031
+
1032
+ E.g.::
1033
+
1034
+ add_mapped_attribute(User, "addresses", relationship(Address))
1035
+
1036
+ This may be used for ORM mappings that aren't using a declarative
1037
+ metaclass that intercepts attribute set operations.
1038
+
1039
+ .. versionadded:: 2.0
1040
+
1041
+
1042
+ """
1043
+ _add_attribute(target, key, attr)
1044
+
1045
+
1046
+ def declarative_base(
1047
+ *,
1048
+ metadata: Optional[MetaData] = None,
1049
+ mapper: Optional[Callable[..., Mapper[Any]]] = None,
1050
+ cls: Type[Any] = object,
1051
+ name: str = "Base",
1052
+ class_registry: Optional[clsregistry._ClsRegistryType] = None,
1053
+ type_annotation_map: Optional[_TypeAnnotationMapType] = None,
1054
+ constructor: Callable[..., None] = _declarative_constructor,
1055
+ metaclass: Type[Any] = DeclarativeMeta,
1056
+ ) -> Any:
1057
+ r"""Construct a base class for declarative class definitions.
1058
+
1059
+ The new base class will be given a metaclass that produces
1060
+ appropriate :class:`~sqlalchemy.schema.Table` objects and makes
1061
+ the appropriate :class:`_orm.Mapper` calls based on the
1062
+ information provided declaratively in the class and any subclasses
1063
+ of the class.
1064
+
1065
+ .. versionchanged:: 2.0 Note that the :func:`_orm.declarative_base`
1066
+ function is superseded by the new :class:`_orm.DeclarativeBase` class,
1067
+ which generates a new "base" class using subclassing, rather than
1068
+ return value of a function. This allows an approach that is compatible
1069
+ with :pep:`484` typing tools.
1070
+
1071
+ The :func:`_orm.declarative_base` function is a shorthand version
1072
+ of using the :meth:`_orm.registry.generate_base`
1073
+ method. That is, the following::
1074
+
1075
+ from sqlalchemy.orm import declarative_base
1076
+
1077
+ Base = declarative_base()
1078
+
1079
+ Is equivalent to::
1080
+
1081
+ from sqlalchemy.orm import registry
1082
+
1083
+ mapper_registry = registry()
1084
+ Base = mapper_registry.generate_base()
1085
+
1086
+ See the docstring for :class:`_orm.registry`
1087
+ and :meth:`_orm.registry.generate_base`
1088
+ for more details.
1089
+
1090
+ .. versionchanged:: 1.4 The :func:`_orm.declarative_base`
1091
+ function is now a specialization of the more generic
1092
+ :class:`_orm.registry` class. The function also moves to the
1093
+ ``sqlalchemy.orm`` package from the ``declarative.ext`` package.
1094
+
1095
+
1096
+ :param metadata:
1097
+ An optional :class:`~sqlalchemy.schema.MetaData` instance. All
1098
+ :class:`~sqlalchemy.schema.Table` objects implicitly declared by
1099
+ subclasses of the base will share this MetaData. A MetaData instance
1100
+ will be created if none is provided. The
1101
+ :class:`~sqlalchemy.schema.MetaData` instance will be available via the
1102
+ ``metadata`` attribute of the generated declarative base class.
1103
+
1104
+ :param mapper:
1105
+ An optional callable, defaults to :class:`_orm.Mapper`. Will
1106
+ be used to map subclasses to their Tables.
1107
+
1108
+ :param cls:
1109
+ Defaults to :class:`object`. A type to use as the base for the generated
1110
+ declarative base class. May be a class or tuple of classes.
1111
+
1112
+ :param name:
1113
+ Defaults to ``Base``. The display name for the generated
1114
+ class. Customizing this is not required, but can improve clarity in
1115
+ tracebacks and debugging.
1116
+
1117
+ :param constructor:
1118
+ Specify the implementation for the ``__init__`` function on a mapped
1119
+ class that has no ``__init__`` of its own. Defaults to an
1120
+ implementation that assigns \**kwargs for declared
1121
+ fields and relationships to an instance. If ``None`` is supplied,
1122
+ no __init__ will be provided and construction will fall back to
1123
+ cls.__init__ by way of the normal Python semantics.
1124
+
1125
+ :param class_registry: optional dictionary that will serve as the
1126
+ registry of class names-> mapped classes when string names
1127
+ are used to identify classes inside of :func:`_orm.relationship`
1128
+ and others. Allows two or more declarative base classes
1129
+ to share the same registry of class names for simplified
1130
+ inter-base relationships.
1131
+
1132
+ :param type_annotation_map: optional dictionary of Python types to
1133
+ SQLAlchemy :class:`_types.TypeEngine` classes or instances. This
1134
+ is used exclusively by the :class:`_orm.MappedColumn` construct
1135
+ to produce column types based on annotations within the
1136
+ :class:`_orm.Mapped` type.
1137
+
1138
+
1139
+ .. versionadded:: 2.0
1140
+
1141
+ .. seealso::
1142
+
1143
+ :ref:`orm_declarative_mapped_column_type_map`
1144
+
1145
+ :param metaclass:
1146
+ Defaults to :class:`.DeclarativeMeta`. A metaclass or __metaclass__
1147
+ compatible callable to use as the meta type of the generated
1148
+ declarative base class.
1149
+
1150
+ .. seealso::
1151
+
1152
+ :class:`_orm.registry`
1153
+
1154
+ """
1155
+
1156
+ return registry(
1157
+ metadata=metadata,
1158
+ class_registry=class_registry,
1159
+ constructor=constructor,
1160
+ type_annotation_map=type_annotation_map,
1161
+ ).generate_base(
1162
+ mapper=mapper,
1163
+ cls=cls,
1164
+ name=name,
1165
+ metaclass=metaclass,
1166
+ )
1167
+
1168
+
1169
+ class registry(EventTarget):
1170
+ """Generalized registry for mapping classes.
1171
+
1172
+ The :class:`_orm.registry` serves as the basis for maintaining a collection
1173
+ of mappings, and provides configurational hooks used to map classes.
1174
+
1175
+ The three general kinds of mappings supported are Declarative Base,
1176
+ Declarative Decorator, and Imperative Mapping. All of these mapping
1177
+ styles may be used interchangeably:
1178
+
1179
+ * :meth:`_orm.registry.generate_base` returns a new declarative base
1180
+ class, and is the underlying implementation of the
1181
+ :func:`_orm.declarative_base` function.
1182
+
1183
+ * :meth:`_orm.registry.mapped` provides a class decorator that will
1184
+ apply declarative mapping to a class without the use of a declarative
1185
+ base class.
1186
+
1187
+ * :meth:`_orm.registry.map_imperatively` will produce a
1188
+ :class:`_orm.Mapper` for a class without scanning the class for
1189
+ declarative class attributes. This method suits the use case historically
1190
+ provided by the ``sqlalchemy.orm.mapper()`` classical mapping function,
1191
+ which is removed as of SQLAlchemy 2.0.
1192
+
1193
+ .. versionadded:: 1.4
1194
+
1195
+ .. seealso::
1196
+
1197
+ :ref:`orm_mapping_classes_toplevel` - overview of class mapping
1198
+ styles.
1199
+
1200
+ """
1201
+
1202
+ _class_registry: clsregistry._ClsRegistryType
1203
+ _managers: weakref.WeakKeyDictionary[ClassManager[Any], Literal[True]]
1204
+ metadata: MetaData
1205
+ constructor: CallableReference[Callable[..., None]]
1206
+ type_annotation_map: _MutableTypeAnnotationMapType
1207
+ _dependents: Set[_RegistryType]
1208
+ _dependencies: Set[_RegistryType]
1209
+ _declare_first_classes: weakref.WeakKeyDictionary[
1210
+ _DeclMappedClassProtocol[Any], Literal[True]
1211
+ ]
1212
+ _declare_last_classes: weakref.WeakKeyDictionary[
1213
+ _DeclMappedClassProtocol[Any], Literal[True]
1214
+ ]
1215
+ _new_mappers: bool
1216
+ dispatch: dispatcher["registry"]
1217
+
1218
+ def __init__(
1219
+ self,
1220
+ *,
1221
+ metadata: Optional[MetaData] = None,
1222
+ class_registry: Optional[clsregistry._ClsRegistryType] = None,
1223
+ type_annotation_map: Optional[_TypeAnnotationMapType] = None,
1224
+ constructor: Callable[..., None] = _declarative_constructor,
1225
+ ):
1226
+ r"""Construct a new :class:`_orm.registry`
1227
+
1228
+ :param metadata:
1229
+ An optional :class:`_schema.MetaData` instance. All
1230
+ :class:`_schema.Table` objects generated using declarative
1231
+ table mapping will make use of this :class:`_schema.MetaData`
1232
+ collection. If this argument is left at its default of ``None``,
1233
+ a blank :class:`_schema.MetaData` collection is created.
1234
+
1235
+ :param constructor:
1236
+ Specify the implementation for the ``__init__`` function on a mapped
1237
+ class that has no ``__init__`` of its own. Defaults to an
1238
+ implementation that assigns \**kwargs for declared
1239
+ fields and relationships to an instance. If ``None`` is supplied,
1240
+ no __init__ will be provided and construction will fall back to
1241
+ cls.__init__ by way of the normal Python semantics.
1242
+
1243
+ :param class_registry: optional dictionary that will serve as the
1244
+ registry of class names-> mapped classes when string names
1245
+ are used to identify classes inside of :func:`_orm.relationship`
1246
+ and others. Allows two or more declarative base classes
1247
+ to share the same registry of class names for simplified
1248
+ inter-base relationships.
1249
+
1250
+ :param type_annotation_map: optional dictionary of Python types to
1251
+ SQLAlchemy :class:`_types.TypeEngine` classes or instances.
1252
+ The provided dict will update the default type mapping. This
1253
+ is used exclusively by the :class:`_orm.MappedColumn` construct
1254
+ to produce column types based on annotations within the
1255
+ :class:`_orm.Mapped` type.
1256
+
1257
+ .. versionadded:: 2.0
1258
+
1259
+ .. seealso::
1260
+
1261
+ :ref:`orm_declarative_mapped_column_type_map`
1262
+
1263
+
1264
+ """
1265
+ lcl_metadata = metadata or MetaData()
1266
+
1267
+ if class_registry is None:
1268
+ class_registry = weakref.WeakValueDictionary()
1269
+
1270
+ self._class_registry = class_registry
1271
+ self._managers = weakref.WeakKeyDictionary()
1272
+ self.metadata = lcl_metadata
1273
+ self.constructor = constructor
1274
+ self.type_annotation_map = {}
1275
+ if type_annotation_map is not None:
1276
+ self.update_type_annotation_map(type_annotation_map)
1277
+ self._dependents = set()
1278
+ self._dependencies = set()
1279
+ self._declare_first_classes = weakref.WeakKeyDictionary()
1280
+ self._declare_last_classes = weakref.WeakKeyDictionary()
1281
+
1282
+ # these listeners are established first, so that user-defined
1283
+ # listeners appended to the same events run after the
1284
+ # ``__declare_first__()`` / ``__declare_last__()`` hooks; a listener
1285
+ # added with ``insert=True`` will run before them
1286
+ event.listen(self, "before_configured", _declare_first_for_registry)
1287
+ event.listen(self, "after_configured", _declare_last_for_registry)
1288
+
1289
+ self._new_mappers = False
1290
+
1291
+ with mapperlib._CONFIGURE_MUTEX:
1292
+ mapperlib._mapper_registries[self] = True
1293
+
1294
+ def update_type_annotation_map(
1295
+ self,
1296
+ type_annotation_map: _TypeAnnotationMapType,
1297
+ ) -> None:
1298
+ """update the :paramref:`_orm.registry.type_annotation_map` with new
1299
+ values."""
1300
+
1301
+ self.type_annotation_map.update(
1302
+ {
1303
+ de_optionalize_union_types(typ): sqltype
1304
+ for typ, sqltype in type_annotation_map.items()
1305
+ }
1306
+ )
1307
+
1308
+ def _resolve_type_with_events(
1309
+ self,
1310
+ cls: Any,
1311
+ key: str,
1312
+ raw_annotation: _MatchedOnType,
1313
+ extracted_type: _MatchedOnType,
1314
+ *,
1315
+ raw_pep_593_type: Optional[GenericProtocol[Any]] = None,
1316
+ pep_593_resolved_argument: Optional[_MatchedOnType] = None,
1317
+ raw_pep_695_type: Optional[TypeAliasType] = None,
1318
+ pep_695_resolved_value: Optional[_MatchedOnType] = None,
1319
+ ) -> Optional[sqltypes.TypeEngine[Any]]:
1320
+ """Resolve type with event support for custom type mapping.
1321
+
1322
+ This method fires the resolve_type_annotation event first to allow
1323
+ custom resolution, then falls back to normal resolution.
1324
+
1325
+ """
1326
+
1327
+ if self.dispatch.resolve_type_annotation:
1328
+ type_resolve = TypeResolve(
1329
+ self,
1330
+ cls,
1331
+ key,
1332
+ raw_annotation,
1333
+ (
1334
+ pep_593_resolved_argument
1335
+ if pep_593_resolved_argument is not None
1336
+ else (
1337
+ pep_695_resolved_value
1338
+ if pep_695_resolved_value is not None
1339
+ else extracted_type
1340
+ )
1341
+ ),
1342
+ raw_pep_593_type,
1343
+ pep_593_resolved_argument,
1344
+ raw_pep_695_type,
1345
+ pep_695_resolved_value,
1346
+ )
1347
+
1348
+ for fn in self.dispatch.resolve_type_annotation:
1349
+ result = fn(type_resolve)
1350
+ if result is not None:
1351
+ return sqltypes.to_instance(result) # type: ignore[no-any-return] # noqa: E501
1352
+
1353
+ if raw_pep_695_type is not None:
1354
+ sqltype = self._resolve_type(raw_pep_695_type)
1355
+ if sqltype is not None:
1356
+ return sqltype
1357
+
1358
+ sqltype = self._resolve_type(extracted_type)
1359
+ if sqltype is not None:
1360
+ return sqltype
1361
+
1362
+ if pep_593_resolved_argument is not None:
1363
+ sqltype = self._resolve_type(pep_593_resolved_argument)
1364
+
1365
+ return sqltype
1366
+
1367
+ def _resolve_type(
1368
+ self, python_type: _MatchedOnType
1369
+ ) -> Optional[sqltypes.TypeEngine[Any]]:
1370
+ python_type_type: Type[Any]
1371
+ search: Iterable[Tuple[_MatchedOnType, Type[Any]]]
1372
+
1373
+ if is_generic(python_type):
1374
+ if is_literal(python_type):
1375
+ python_type_type = python_type # type: ignore[assignment]
1376
+
1377
+ search = (
1378
+ (python_type, python_type_type),
1379
+ *((lt, python_type_type) for lt in LITERAL_TYPES),
1380
+ )
1381
+ else:
1382
+ python_type_type = python_type.__origin__
1383
+ search = ((python_type, python_type_type),)
1384
+ elif isinstance(python_type, type):
1385
+ python_type_type = python_type
1386
+ search = ((pt, pt) for pt in python_type_type.__mro__)
1387
+ else:
1388
+ python_type_type = python_type # type: ignore[assignment]
1389
+ search = ((python_type, python_type_type),)
1390
+
1391
+ for pt, flattened in search:
1392
+ # we search through full __mro__ for types. however...
1393
+ sql_type = self.type_annotation_map.get(pt)
1394
+ if sql_type is None:
1395
+ sql_type = sqltypes._type_map_get(pt) # type: ignore[arg-type] # noqa: E501
1396
+
1397
+ if sql_type is not None:
1398
+ sql_type_inst = sqltypes.to_instance(sql_type)
1399
+
1400
+ # ... this additional step will reject most
1401
+ # type -> supertype matches, such as if we had
1402
+ # a MyInt(int) subclass. note also we pass NewType()
1403
+ # here directly; these always have to be in the
1404
+ # type_annotation_map to be useful
1405
+ resolved_sql_type = sql_type_inst._resolve_for_python_type(
1406
+ python_type_type,
1407
+ pt,
1408
+ flattened,
1409
+ )
1410
+ if resolved_sql_type is not None:
1411
+ return resolved_sql_type
1412
+
1413
+ return None
1414
+
1415
+ @property
1416
+ def mappers(self) -> FrozenSet[Mapper[Any]]:
1417
+ """read only collection of all :class:`_orm.Mapper` objects."""
1418
+
1419
+ return frozenset(manager.mapper for manager in self._managers)
1420
+
1421
+ def _set_depends_on(self, registry: RegistryType) -> None:
1422
+ if registry is self:
1423
+ return
1424
+ registry._dependents.add(self)
1425
+ self._dependencies.add(registry)
1426
+
1427
+ def _flag_new_mapper(self, mapper: Mapper[Any]) -> None:
1428
+ mapper._ready_for_configure = True
1429
+ if self._new_mappers:
1430
+ return
1431
+
1432
+ for reg in self._recurse_with_dependents({self}):
1433
+ reg._new_mappers = True
1434
+
1435
+ @classmethod
1436
+ def _recurse_with_dependents(
1437
+ cls, registries: Set[RegistryType]
1438
+ ) -> Iterator[RegistryType]:
1439
+ todo = registries
1440
+ done = set()
1441
+ while todo:
1442
+ reg = todo.pop()
1443
+ done.add(reg)
1444
+
1445
+ # if yielding would remove dependents, make sure we have
1446
+ # them before
1447
+ todo.update(reg._dependents.difference(done))
1448
+ yield reg
1449
+
1450
+ # if yielding would add dependents, make sure we have them
1451
+ # after
1452
+ todo.update(reg._dependents.difference(done))
1453
+
1454
+ @classmethod
1455
+ def _recurse_with_dependencies(
1456
+ cls, registries: Set[RegistryType]
1457
+ ) -> Iterator[RegistryType]:
1458
+ todo = registries
1459
+ done = set()
1460
+ while todo:
1461
+ reg = todo.pop()
1462
+ done.add(reg)
1463
+
1464
+ # if yielding would remove dependencies, make sure we have
1465
+ # them before
1466
+ todo.update(reg._dependencies.difference(done))
1467
+
1468
+ yield reg
1469
+
1470
+ # if yielding would remove dependencies, make sure we have
1471
+ # them before
1472
+ todo.update(reg._dependencies.difference(done))
1473
+
1474
+ def _mappers_to_configure(self) -> Iterator[Mapper[Any]]:
1475
+ return (
1476
+ manager.mapper
1477
+ for manager in list(self._managers)
1478
+ if manager.is_mapped
1479
+ and not manager.mapper.configured
1480
+ and manager.mapper._ready_for_configure
1481
+ )
1482
+
1483
+ def _dispose_cls(self, cls: Type[_O]) -> None:
1484
+ clsregistry._remove_class(cls.__name__, cls, self._class_registry)
1485
+
1486
+ def _add_manager(self, manager: ClassManager[Any]) -> None:
1487
+ self._managers[manager] = True
1488
+
1489
+ # collect the class if it uses the __declare_first__() /
1490
+ # __declare_last__() hooks, so that the registry-level listeners
1491
+ # established in __init__() can invoke them. the collection is
1492
+ # weak so that the class remains garbage collectable.
1493
+ #
1494
+ # these are insertion ordered dictionaries rather than sets, as a
1495
+ # class is necessarily added after its bases, and the hook of a base
1496
+ # class has to run before that of its subclasses; ConcreteBase
1497
+ # inherits __declare_first__() to the whole hierarchy, and the first
1498
+ # class to run establishes the "type" property that the remaining
1499
+ # ones then adapt as a ConcreteInheritedProperty
1500
+ cls = manager.class_
1501
+ decl_cls = cast("_DeclMappedClassProtocol[Any]", cls)
1502
+ if _get_immediate_cls_attr(cls, "__declare_first__"):
1503
+ self._declare_first_classes[decl_cls] = True
1504
+ if _get_immediate_cls_attr(cls, "__declare_last__"):
1505
+ self._declare_last_classes[decl_cls] = True
1506
+
1507
+ if manager.is_mapped:
1508
+ raise exc.ArgumentError(
1509
+ "Class '%s' already has a primary mapper defined. "
1510
+ % manager.class_
1511
+ )
1512
+ assert manager.registry is None
1513
+ manager.registry = self
1514
+
1515
+ def configure(self, cascade: bool = False) -> None:
1516
+ """Configure all as-yet unconfigured mappers in this
1517
+ :class:`_orm.registry`.
1518
+
1519
+ The configure step is used to reconcile and initialize the
1520
+ :func:`_orm.relationship` linkages between mapped classes, as well as
1521
+ to invoke configuration events such as the
1522
+ :meth:`_orm.MapperEvents.before_configured` and
1523
+ :meth:`_orm.MapperEvents.after_configured`, which may be used by ORM
1524
+ extensions or user-defined extension hooks.
1525
+
1526
+ If one or more mappers in this registry contain
1527
+ :func:`_orm.relationship` constructs that refer to mapped classes in
1528
+ other registries, this registry is said to be *dependent* on those
1529
+ registries. In order to configure those dependent registries
1530
+ automatically, the :paramref:`_orm.registry.configure.cascade` flag
1531
+ should be set to ``True``. Otherwise, if they are not configured, an
1532
+ exception will be raised. The rationale behind this behavior is to
1533
+ allow an application to programmatically invoke configuration of
1534
+ registries while controlling whether or not the process implicitly
1535
+ reaches other registries.
1536
+
1537
+ As an alternative to invoking :meth:`_orm.registry.configure`, the ORM
1538
+ function :func:`_orm.configure_mappers` function may be used to ensure
1539
+ configuration is complete for all :class:`_orm.registry` objects in
1540
+ memory. This is generally simpler to use and also predates the usage of
1541
+ :class:`_orm.registry` objects overall. However, this function will
1542
+ impact all mappings throughout the running Python process and may be
1543
+ more memory/time consuming for an application that has many registries
1544
+ in use for different purposes that may not be needed immediately.
1545
+
1546
+ .. seealso::
1547
+
1548
+ :func:`_orm.configure_mappers`
1549
+
1550
+
1551
+ .. versionadded:: 1.4.0b2
1552
+
1553
+ """
1554
+ mapperlib._configure_registries({self}, cascade=cascade)
1555
+
1556
+ def dispose(self, cascade: bool = False) -> None:
1557
+ """Dispose of all mappers in this :class:`_orm.registry`.
1558
+
1559
+ After invocation, all the classes that were mapped within this registry
1560
+ will no longer have class instrumentation associated with them. This
1561
+ method is the per-:class:`_orm.registry` analogue to the
1562
+ application-wide :func:`_orm.clear_mappers` function.
1563
+
1564
+ If this registry contains mappers that are dependencies of other
1565
+ registries, typically via :func:`_orm.relationship` links, then those
1566
+ registries must be disposed as well. When such registries exist in
1567
+ relation to this one, their :meth:`_orm.registry.dispose` method will
1568
+ also be called, if the :paramref:`_orm.registry.dispose.cascade` flag
1569
+ is set to ``True``; otherwise, an error is raised if those registries
1570
+ were not already disposed.
1571
+
1572
+ .. versionadded:: 1.4.0b2
1573
+
1574
+ .. seealso::
1575
+
1576
+ :func:`_orm.clear_mappers`
1577
+
1578
+ """
1579
+
1580
+ mapperlib._dispose_registries({self}, cascade=cascade)
1581
+
1582
+ def _dispose_manager_and_mapper(self, manager: ClassManager[Any]) -> None:
1583
+ if "mapper" in manager.__dict__:
1584
+ mapper = manager.mapper
1585
+
1586
+ mapper._set_dispose_flags()
1587
+
1588
+ class_ = manager.class_
1589
+ self._dispose_cls(class_)
1590
+ instrumentation._instrumentation_factory.unregister(class_)
1591
+
1592
+ def generate_base(
1593
+ self,
1594
+ mapper: Optional[Callable[..., Mapper[Any]]] = None,
1595
+ cls: Type[Any] = object,
1596
+ name: str = "Base",
1597
+ metaclass: Type[Any] = DeclarativeMeta,
1598
+ ) -> Any:
1599
+ """Generate a declarative base class.
1600
+
1601
+ Classes that inherit from the returned class object will be
1602
+ automatically mapped using declarative mapping.
1603
+
1604
+ E.g.::
1605
+
1606
+ from sqlalchemy.orm import registry
1607
+
1608
+ mapper_registry = registry()
1609
+
1610
+ Base = mapper_registry.generate_base()
1611
+
1612
+
1613
+ class MyClass(Base):
1614
+ __tablename__ = "my_table"
1615
+ id = Column(Integer, primary_key=True)
1616
+
1617
+ The above dynamically generated class is equivalent to the
1618
+ non-dynamic example below::
1619
+
1620
+ from sqlalchemy.orm import registry
1621
+ from sqlalchemy.orm.decl_api import DeclarativeMeta
1622
+
1623
+ mapper_registry = registry()
1624
+
1625
+
1626
+ class Base(metaclass=DeclarativeMeta):
1627
+ __abstract__ = True
1628
+ registry = mapper_registry
1629
+ metadata = mapper_registry.metadata
1630
+
1631
+ __init__ = mapper_registry.constructor
1632
+
1633
+ .. versionchanged:: 2.0 Note that the
1634
+ :meth:`_orm.registry.generate_base` method is superseded by the new
1635
+ :class:`_orm.DeclarativeBase` class, which generates a new "base"
1636
+ class using subclassing, rather than return value of a function.
1637
+ This allows an approach that is compatible with :pep:`484` typing
1638
+ tools.
1639
+
1640
+ The :meth:`_orm.registry.generate_base` method provides the
1641
+ implementation for the :func:`_orm.declarative_base` function, which
1642
+ creates the :class:`_orm.registry` and base class all at once.
1643
+
1644
+ See the section :ref:`orm_declarative_mapping` for background and
1645
+ examples.
1646
+
1647
+ :param mapper:
1648
+ An optional callable, defaults to :class:`_orm.Mapper`.
1649
+ This function is used to generate new :class:`_orm.Mapper` objects.
1650
+
1651
+ :param cls:
1652
+ Defaults to :class:`object`. A type to use as the base for the
1653
+ generated declarative base class. May be a class or tuple of classes.
1654
+
1655
+ :param name:
1656
+ Defaults to ``Base``. The display name for the generated
1657
+ class. Customizing this is not required, but can improve clarity in
1658
+ tracebacks and debugging.
1659
+
1660
+ :param metaclass:
1661
+ Defaults to :class:`.DeclarativeMeta`. A metaclass or __metaclass__
1662
+ compatible callable to use as the meta type of the generated
1663
+ declarative base class.
1664
+
1665
+ .. seealso::
1666
+
1667
+ :ref:`orm_declarative_mapping`
1668
+
1669
+ :func:`_orm.declarative_base`
1670
+
1671
+ """
1672
+ metadata = self.metadata
1673
+
1674
+ bases = not isinstance(cls, tuple) and (cls,) or cls
1675
+
1676
+ class_dict: Dict[str, Any] = dict(registry=self, metadata=metadata)
1677
+ if isinstance(cls, type):
1678
+ class_dict["__doc__"] = cls.__doc__
1679
+
1680
+ if self.constructor is not None:
1681
+ class_dict["__init__"] = self.constructor
1682
+
1683
+ class_dict["__abstract__"] = True
1684
+ if mapper:
1685
+ class_dict["__mapper_cls__"] = mapper
1686
+
1687
+ if hasattr(cls, "__class_getitem__"):
1688
+
1689
+ def __class_getitem__(cls: Type[_T], key: Any) -> Type[_T]:
1690
+ # allow generic classes in py3.9+
1691
+ return cls
1692
+
1693
+ class_dict["__class_getitem__"] = __class_getitem__
1694
+
1695
+ return metaclass(name, bases, class_dict)
1696
+
1697
+ @compat_typing.dataclass_transform(
1698
+ field_specifiers=(
1699
+ MappedColumn,
1700
+ RelationshipProperty,
1701
+ Composite,
1702
+ Synonym,
1703
+ mapped_column,
1704
+ relationship,
1705
+ composite,
1706
+ synonym,
1707
+ deferred,
1708
+ ),
1709
+ )
1710
+ @overload
1711
+ def mapped_as_dataclass(self, __cls: Type[_O], /) -> Type[_O]: ...
1712
+
1713
+ @overload
1714
+ def mapped_as_dataclass(
1715
+ self,
1716
+ __cls: Literal[None] = ...,
1717
+ /,
1718
+ *,
1719
+ init: Union[_NoArg, bool] = ...,
1720
+ repr: Union[_NoArg, bool] = ..., # noqa: A002
1721
+ eq: Union[_NoArg, bool] = ...,
1722
+ order: Union[_NoArg, bool] = ...,
1723
+ unsafe_hash: Union[_NoArg, bool] = ...,
1724
+ match_args: Union[_NoArg, bool] = ...,
1725
+ kw_only: Union[_NoArg, bool] = ...,
1726
+ dataclass_callable: Union[_NoArg, Callable[..., Type[Any]]] = ...,
1727
+ ) -> Callable[[Type[_O]], Type[_O]]: ...
1728
+
1729
+ def mapped_as_dataclass(
1730
+ self,
1731
+ __cls: Optional[Type[_O]] = None,
1732
+ /,
1733
+ *,
1734
+ init: Union[_NoArg, bool] = _NoArg.NO_ARG,
1735
+ repr: Union[_NoArg, bool] = _NoArg.NO_ARG, # noqa: A002
1736
+ eq: Union[_NoArg, bool] = _NoArg.NO_ARG,
1737
+ order: Union[_NoArg, bool] = _NoArg.NO_ARG,
1738
+ unsafe_hash: Union[_NoArg, bool] = _NoArg.NO_ARG,
1739
+ match_args: Union[_NoArg, bool] = _NoArg.NO_ARG,
1740
+ kw_only: Union[_NoArg, bool] = _NoArg.NO_ARG,
1741
+ dataclass_callable: Union[
1742
+ _NoArg, Callable[..., Type[Any]]
1743
+ ] = _NoArg.NO_ARG,
1744
+ ) -> Union[Type[_O], Callable[[Type[_O]], Type[_O]]]:
1745
+ """Class decorator that will apply the Declarative mapping process
1746
+ to a given class, and additionally convert the class to be a
1747
+ Python dataclass.
1748
+
1749
+ .. seealso::
1750
+
1751
+ :ref:`orm_declarative_native_dataclasses` - complete background
1752
+ on SQLAlchemy native dataclass mapping
1753
+
1754
+ :func:`_orm.mapped_as_dataclass` - functional version that may
1755
+ provide better compatibility with mypy
1756
+
1757
+ .. versionadded:: 2.0
1758
+
1759
+
1760
+ """
1761
+
1762
+ decorate = mapped_as_dataclass(
1763
+ self,
1764
+ init=init,
1765
+ repr=repr,
1766
+ eq=eq,
1767
+ order=order,
1768
+ unsafe_hash=unsafe_hash,
1769
+ match_args=match_args,
1770
+ kw_only=kw_only,
1771
+ dataclass_callable=dataclass_callable,
1772
+ )
1773
+
1774
+ if __cls:
1775
+ return decorate(__cls)
1776
+ else:
1777
+ return decorate
1778
+
1779
+ def mapped(self, cls: Type[_O]) -> Type[_O]:
1780
+ """Class decorator that will apply the Declarative mapping process
1781
+ to a given class.
1782
+
1783
+ E.g.::
1784
+
1785
+ from sqlalchemy.orm import registry
1786
+
1787
+ mapper_registry = registry()
1788
+
1789
+
1790
+ @mapper_registry.mapped
1791
+ class Foo:
1792
+ __tablename__ = "some_table"
1793
+
1794
+ id = Column(Integer, primary_key=True)
1795
+ name = Column(String)
1796
+
1797
+ See the section :ref:`orm_declarative_mapping` for complete
1798
+ details and examples.
1799
+
1800
+ :param cls: class to be mapped.
1801
+
1802
+ :return: the class that was passed.
1803
+
1804
+ .. seealso::
1805
+
1806
+ :ref:`orm_declarative_mapping`
1807
+
1808
+ :meth:`_orm.registry.generate_base` - generates a base class
1809
+ that will apply Declarative mapping to subclasses automatically
1810
+ using a Python metaclass.
1811
+
1812
+ .. seealso::
1813
+
1814
+ :meth:`_orm.registry.mapped_as_dataclass`
1815
+
1816
+ """
1817
+ _ORMClassConfigurator._as_declarative(self, cls, cls.__dict__)
1818
+ return cls
1819
+
1820
+ def as_declarative_base(self, **kw: Any) -> Callable[[Type[_T]], Type[_T]]:
1821
+ """
1822
+ Class decorator which will invoke
1823
+ :meth:`_orm.registry.generate_base`
1824
+ for a given base class.
1825
+
1826
+ E.g.::
1827
+
1828
+ from sqlalchemy.orm import registry
1829
+
1830
+ mapper_registry = registry()
1831
+
1832
+
1833
+ @mapper_registry.as_declarative_base()
1834
+ class Base:
1835
+ @declared_attr
1836
+ def __tablename__(cls):
1837
+ return cls.__name__.lower()
1838
+
1839
+ id = Column(Integer, primary_key=True)
1840
+
1841
+
1842
+ class MyMappedClass(Base): ...
1843
+
1844
+ All keyword arguments passed to
1845
+ :meth:`_orm.registry.as_declarative_base` are passed
1846
+ along to :meth:`_orm.registry.generate_base`.
1847
+
1848
+ """
1849
+
1850
+ def decorate(cls: Type[_T]) -> Type[_T]:
1851
+ kw["cls"] = cls
1852
+ kw["name"] = cls.__name__
1853
+ return self.generate_base(**kw) # type: ignore[no-any-return]
1854
+
1855
+ return decorate
1856
+
1857
+ def map_declaratively(self, cls: Type[_O]) -> Mapper[_O]:
1858
+ """Map a class declaratively.
1859
+
1860
+ In this form of mapping, the class is scanned for mapping information,
1861
+ including for columns to be associated with a table, and/or an
1862
+ actual table object.
1863
+
1864
+ Returns the :class:`_orm.Mapper` object.
1865
+
1866
+ E.g.::
1867
+
1868
+ from sqlalchemy.orm import registry
1869
+
1870
+ mapper_registry = registry()
1871
+
1872
+
1873
+ class Foo:
1874
+ __tablename__ = "some_table"
1875
+
1876
+ id = Column(Integer, primary_key=True)
1877
+ name = Column(String)
1878
+
1879
+
1880
+ mapper = mapper_registry.map_declaratively(Foo)
1881
+
1882
+ This function is more conveniently invoked indirectly via either the
1883
+ :meth:`_orm.registry.mapped` class decorator or by subclassing a
1884
+ declarative metaclass generated from
1885
+ :meth:`_orm.registry.generate_base`.
1886
+
1887
+ See the section :ref:`orm_declarative_mapping` for complete
1888
+ details and examples.
1889
+
1890
+ :param cls: class to be mapped.
1891
+
1892
+ :return: a :class:`_orm.Mapper` object.
1893
+
1894
+ .. seealso::
1895
+
1896
+ :ref:`orm_declarative_mapping`
1897
+
1898
+ :meth:`_orm.registry.mapped` - more common decorator interface
1899
+ to this function.
1900
+
1901
+ :meth:`_orm.registry.map_imperatively`
1902
+
1903
+ """
1904
+ _ORMClassConfigurator._as_declarative(self, cls, cls.__dict__)
1905
+ return cls.__mapper__ # type: ignore[attr-defined, no-any-return]
1906
+
1907
+ def map_imperatively(
1908
+ self,
1909
+ class_: Type[_O],
1910
+ local_table: Optional[FromClause] = None,
1911
+ **kw: Any,
1912
+ ) -> Mapper[_O]:
1913
+ r"""Map a class imperatively.
1914
+
1915
+ In this form of mapping, the class is not scanned for any mapping
1916
+ information. Instead, all mapping constructs are passed as
1917
+ arguments.
1918
+
1919
+ This method is intended to be fully equivalent to the now-removed
1920
+ SQLAlchemy ``mapper()`` function, except that it's in terms of
1921
+ a particular registry.
1922
+
1923
+ E.g.::
1924
+
1925
+ from sqlalchemy.orm import registry
1926
+
1927
+ mapper_registry = registry()
1928
+
1929
+ my_table = Table(
1930
+ "my_table",
1931
+ mapper_registry.metadata,
1932
+ Column("id", Integer, primary_key=True),
1933
+ )
1934
+
1935
+
1936
+ class MyClass:
1937
+ pass
1938
+
1939
+
1940
+ mapper_registry.map_imperatively(MyClass, my_table)
1941
+
1942
+ See the section :ref:`orm_imperative_mapping` for complete background
1943
+ and usage examples.
1944
+
1945
+ :param class\_: The class to be mapped. Corresponds to the
1946
+ :paramref:`_orm.Mapper.class_` parameter.
1947
+
1948
+ :param local_table: the :class:`_schema.Table` or other
1949
+ :class:`_sql.FromClause` object that is the subject of the mapping.
1950
+ Corresponds to the
1951
+ :paramref:`_orm.Mapper.local_table` parameter.
1952
+
1953
+ :param \**kw: all other keyword arguments are passed to the
1954
+ :class:`_orm.Mapper` constructor directly.
1955
+
1956
+ .. seealso::
1957
+
1958
+ :ref:`orm_imperative_mapping`
1959
+
1960
+ :ref:`orm_declarative_mapping`
1961
+
1962
+ """
1963
+ return _ORMClassConfigurator._mapper(self, class_, local_table, kw)
1964
+
1965
+
1966
+ RegistryType = registry
1967
+
1968
+ if not TYPE_CHECKING:
1969
+ # allow for runtime type resolution of ``ClassVar[_RegistryType]``
1970
+ _RegistryType = registry # noqa
1971
+
1972
+
1973
+ def _declare_first_for_registry(registry: registry) -> None:
1974
+ """Invoke ``__declare_first__()`` for classes within this registry."""
1975
+
1976
+ for cls in list(registry._declare_first_classes):
1977
+ cls.__declare_first__()
1978
+
1979
+
1980
+ def _declare_last_for_registry(registry: registry) -> None:
1981
+ """Invoke ``__declare_last__()`` for classes within this registry."""
1982
+
1983
+ for cls in list(registry._declare_last_classes):
1984
+ cls.__declare_last__()
1985
+
1986
+
1987
+ class TypeResolve:
1988
+ """Primary argument to the :meth:`.RegistryEvents.resolve_type_annotation`
1989
+ event.
1990
+
1991
+ This object contains all the information needed to resolve a Python
1992
+ type to a SQLAlchemy type. The :attr:`.TypeResolve.resolved_type` is
1993
+ typically the main type that's resolved. To resolve an arbitrary
1994
+ Python type against the current type map, the :meth:`.TypeResolve.resolve`
1995
+ method may be used.
1996
+
1997
+ .. versionadded:: 2.1
1998
+
1999
+ """
2000
+
2001
+ __slots__ = (
2002
+ "registry",
2003
+ "cls",
2004
+ "key",
2005
+ "raw_type",
2006
+ "resolved_type",
2007
+ "raw_pep_593_type",
2008
+ "raw_pep_695_type",
2009
+ "pep_593_resolved_argument",
2010
+ "pep_695_resolved_value",
2011
+ )
2012
+
2013
+ cls: Any
2014
+ "The class being processed during declarative mapping"
2015
+
2016
+ registry: "registry"
2017
+ "The :class:`registry` being used"
2018
+
2019
+ key: str
2020
+ "String name of the ORM mapped attribute being processed"
2021
+
2022
+ raw_type: _MatchedOnType
2023
+ """The type annotation object directly from the attribute's annotations.
2024
+
2025
+ It's recommended to look at :attr:`.TypeResolve.resolved_type` or
2026
+ one of :attr:`.TypeResolve.pep_593_resolved_argument` or
2027
+ :attr:`.TypeResolve.pep_695_resolved_value` rather than the raw type, as
2028
+ the raw type will not be de-optionalized.
2029
+
2030
+ """
2031
+
2032
+ resolved_type: _MatchedOnType
2033
+ """The de-optionalized, "resolved" type after accounting for :pep:`695`
2034
+ and :pep:`593` indirection:
2035
+
2036
+ * If the annotation were a plain Python type or simple alias e.g.
2037
+ ``Mapped[int]``, the resolved_type will be ``int``
2038
+ * If the annotation refers to a :pep:`695` type that references a
2039
+ plain Python type or simple alias, e.g. ``type MyType = int``
2040
+ then ``Mapped[MyType]``, the type will refer to the ``__value__``
2041
+ of the :pep:`695` type, e.g. ``int``, the same as
2042
+ :attr:`.TypeResolve.pep_695_resolved_value`.
2043
+ * If the annotation refers to a :pep:`593` ``Annotated`` object, or
2044
+ a :pep:`695` type alias that in turn refers to a :pep:`593` type,
2045
+ then the type will be the inner type inside of the ``Annotated``,
2046
+ e.g. ``MyType = Annotated[float, mapped_column(...)]`` with
2047
+ ``Mapped[MyType]`` becomes ``float``, the same as
2048
+ :attr:`.TypeResolve.pep_593_resolved_argument`.
2049
+
2050
+ """
2051
+
2052
+ raw_pep_593_type: Optional[GenericProtocol[Any]]
2053
+ """The de-optionalized :pep:`593` type, if the raw type referred to one.
2054
+
2055
+ This would refer to an ``Annotated`` object.
2056
+
2057
+ """
2058
+
2059
+ pep_593_resolved_argument: Optional[_MatchedOnType]
2060
+ """The type extracted from a :pep:`593` ``Annotated`` construct, if the
2061
+ type referred to one.
2062
+
2063
+ When present, this type would be the same as the
2064
+ :attr:`.TypeResolve.resolved_type`.
2065
+
2066
+ """
2067
+
2068
+ raw_pep_695_type: Optional[TypeAliasType]
2069
+ "The de-optionalized :pep:`695` type, if the raw type referred to one."
2070
+
2071
+ pep_695_resolved_value: Optional[_MatchedOnType]
2072
+ """The de-optionalized type referenced by the raw :pep:`695` type, if the
2073
+ raw type referred to one.
2074
+
2075
+ When present, and a :pep:`593` type is not present, this type would be the
2076
+ same as the :attr:`.TypeResolve.resolved_type`.
2077
+
2078
+ """
2079
+
2080
+ def __init__(
2081
+ self,
2082
+ registry: RegistryType,
2083
+ cls: Any,
2084
+ key: str,
2085
+ raw_type: _MatchedOnType,
2086
+ resolved_type: _MatchedOnType,
2087
+ raw_pep_593_type: Optional[GenericProtocol[Any]],
2088
+ pep_593_resolved_argument: Optional[_MatchedOnType],
2089
+ raw_pep_695_type: Optional[TypeAliasType],
2090
+ pep_695_resolved_value: Optional[_MatchedOnType],
2091
+ ):
2092
+ self.registry = registry
2093
+ self.cls = cls
2094
+ self.key = key
2095
+ self.raw_type = raw_type
2096
+ self.resolved_type = resolved_type
2097
+ self.raw_pep_593_type = raw_pep_593_type
2098
+ self.pep_593_resolved_argument = pep_593_resolved_argument
2099
+ self.raw_pep_695_type = raw_pep_695_type
2100
+ self.pep_695_resolved_value = pep_695_resolved_value
2101
+
2102
+ def resolve(
2103
+ self, python_type: _MatchedOnType
2104
+ ) -> Optional[sqltypes.TypeEngine[Any]]:
2105
+ """Resolve the given python type using the type_annotation_map of
2106
+ the :class:`registry`.
2107
+
2108
+ :param python_type: a Python type (e.g. ``int``, ``str``, etc.) Any
2109
+ type object that's present in
2110
+ :paramref:`_orm.registry_type_annotation_map` should produce a
2111
+ non-``None`` result.
2112
+ :return: a SQLAlchemy :class:`.TypeEngine` instance
2113
+ (e.g. :class:`.Integer`,
2114
+ :class:`.String`, etc.), or ``None`` to indicate no type could be
2115
+ matched.
2116
+
2117
+ """
2118
+ return self.registry._resolve_type(python_type)
2119
+
2120
+
2121
+ def as_declarative(**kw: Any) -> Callable[[Type[_T]], Type[_T]]:
2122
+ """
2123
+ Class decorator which will adapt a given class into a
2124
+ :func:`_orm.declarative_base`.
2125
+
2126
+ This function makes use of the :meth:`_orm.registry.as_declarative_base`
2127
+ method, by first creating a :class:`_orm.registry` automatically
2128
+ and then invoking the decorator.
2129
+
2130
+ E.g.::
2131
+
2132
+ from sqlalchemy.orm import as_declarative
2133
+
2134
+
2135
+ @as_declarative()
2136
+ class Base:
2137
+ @declared_attr
2138
+ def __tablename__(cls):
2139
+ return cls.__name__.lower()
2140
+
2141
+ id = Column(Integer, primary_key=True)
2142
+
2143
+
2144
+ class MyMappedClass(Base): ...
2145
+
2146
+ .. seealso::
2147
+
2148
+ :meth:`_orm.registry.as_declarative_base`
2149
+
2150
+ """
2151
+ metadata, class_registry = (
2152
+ kw.pop("metadata", None),
2153
+ kw.pop("class_registry", None),
2154
+ )
2155
+
2156
+ return registry(
2157
+ metadata=metadata, class_registry=class_registry
2158
+ ).as_declarative_base(**kw)
2159
+
2160
+
2161
+ @compat_typing.dataclass_transform(
2162
+ field_specifiers=(
2163
+ MappedColumn,
2164
+ RelationshipProperty,
2165
+ Composite,
2166
+ Synonym,
2167
+ mapped_column,
2168
+ relationship,
2169
+ composite,
2170
+ synonym,
2171
+ deferred,
2172
+ ),
2173
+ )
2174
+ def mapped_as_dataclass(
2175
+ registry: RegistryType,
2176
+ /,
2177
+ *,
2178
+ init: Union[_NoArg, bool] = _NoArg.NO_ARG,
2179
+ repr: Union[_NoArg, bool] = _NoArg.NO_ARG, # noqa: A002
2180
+ eq: Union[_NoArg, bool] = _NoArg.NO_ARG,
2181
+ order: Union[_NoArg, bool] = _NoArg.NO_ARG,
2182
+ unsafe_hash: Union[_NoArg, bool] = _NoArg.NO_ARG,
2183
+ match_args: Union[_NoArg, bool] = _NoArg.NO_ARG,
2184
+ kw_only: Union[_NoArg, bool] = _NoArg.NO_ARG,
2185
+ dataclass_callable: Union[
2186
+ _NoArg, Callable[..., Type[Any]]
2187
+ ] = _NoArg.NO_ARG,
2188
+ ) -> Callable[[Type[_O]], Type[_O]]:
2189
+ """Standalone function form of :meth:`_orm.registry.mapped_as_dataclass`
2190
+ which may have better compatibility with mypy.
2191
+
2192
+ The :class:`_orm.registry` is passed as the first argument to the
2193
+ decorator.
2194
+
2195
+ e.g.::
2196
+
2197
+ from sqlalchemy.orm import Mapped
2198
+ from sqlalchemy.orm import mapped_as_dataclass
2199
+ from sqlalchemy.orm import mapped_column
2200
+ from sqlalchemy.orm import registry
2201
+
2202
+ some_registry = registry()
2203
+
2204
+
2205
+ @mapped_as_dataclass(some_registry)
2206
+ class Relationships:
2207
+ __tablename__ = "relationships"
2208
+
2209
+ entity_id1: Mapped[int] = mapped_column(primary_key=True)
2210
+ entity_id2: Mapped[int] = mapped_column(primary_key=True)
2211
+ level: Mapped[int] = mapped_column(Integer)
2212
+
2213
+ .. versionadded:: 2.0.44
2214
+
2215
+ """
2216
+
2217
+ def decorate(cls: Type[_O]) -> Type[_O]:
2218
+ _generate_dc_transforms(
2219
+ init=init,
2220
+ repr=repr,
2221
+ eq=eq,
2222
+ order=order,
2223
+ unsafe_hash=unsafe_hash,
2224
+ match_args=match_args,
2225
+ kw_only=kw_only,
2226
+ dataclass_callable=dataclass_callable,
2227
+ cls_=cls,
2228
+ )
2229
+ _ORMClassConfigurator._as_declarative(registry, cls, cls.__dict__)
2230
+ return cls
2231
+
2232
+ return decorate
2233
+
2234
+
2235
+ @inspection._inspects(
2236
+ DeclarativeMeta, DeclarativeBase, DeclarativeAttributeIntercept
2237
+ )
2238
+ def _inspect_decl_meta(cls: Type[Any]) -> Optional[Mapper[Any]]:
2239
+ mp: Optional[Mapper[Any]] = _inspect_mapped_class(cls)
2240
+ if mp is None:
2241
+ if _DeferredDeclarativeConfig.has_cls(cls):
2242
+ _DeferredDeclarativeConfig.raise_unmapped_for_cls(cls)
2243
+ return mp
2244
+
2245
+
2246
+ @compat_typing.dataclass_transform(
2247
+ field_specifiers=(
2248
+ MappedColumn,
2249
+ RelationshipProperty,
2250
+ Composite,
2251
+ Synonym,
2252
+ mapped_column,
2253
+ relationship,
2254
+ composite,
2255
+ synonym,
2256
+ deferred,
2257
+ ),
2258
+ )
2259
+ @overload
2260
+ def unmapped_dataclass(__cls: Type[_O], /) -> Type[_O]: ...
2261
+
2262
+
2263
+ @overload
2264
+ def unmapped_dataclass(
2265
+ __cls: Literal[None] = ...,
2266
+ /,
2267
+ *,
2268
+ init: Union[_NoArg, bool] = ...,
2269
+ repr: Union[_NoArg, bool] = ..., # noqa: A002
2270
+ eq: Union[_NoArg, bool] = ...,
2271
+ order: Union[_NoArg, bool] = ...,
2272
+ unsafe_hash: Union[_NoArg, bool] = ...,
2273
+ match_args: Union[_NoArg, bool] = ...,
2274
+ kw_only: Union[_NoArg, bool] = ...,
2275
+ dataclass_callable: Union[_NoArg, Callable[..., Type[Any]]] = ...,
2276
+ ) -> Callable[[Type[_O]], Type[_O]]: ...
2277
+
2278
+
2279
+ def unmapped_dataclass(
2280
+ __cls: Optional[Type[_O]] = None,
2281
+ /,
2282
+ *,
2283
+ init: Union[_NoArg, bool] = _NoArg.NO_ARG,
2284
+ repr: Union[_NoArg, bool] = _NoArg.NO_ARG, # noqa: A002
2285
+ eq: Union[_NoArg, bool] = _NoArg.NO_ARG,
2286
+ order: Union[_NoArg, bool] = _NoArg.NO_ARG,
2287
+ unsafe_hash: Union[_NoArg, bool] = _NoArg.NO_ARG,
2288
+ match_args: Union[_NoArg, bool] = _NoArg.NO_ARG,
2289
+ kw_only: Union[_NoArg, bool] = _NoArg.NO_ARG,
2290
+ dataclass_callable: Union[
2291
+ _NoArg, Callable[..., Type[Any]]
2292
+ ] = _NoArg.NO_ARG,
2293
+ ) -> Union[Type[_O], Callable[[Type[_O]], Type[_O]]]:
2294
+ """Decorator which allows the creation of dataclass-compatible mixins
2295
+ within mapped class hierarchies based on the
2296
+ :func:`_orm.mapped_as_dataclass` decorator.
2297
+
2298
+ Parameters are the same as those of :func:`_orm.mapped_as_dataclass`.
2299
+ The decorator turns the given class into a SQLAlchemy-compatible dataclass
2300
+ in the same way that :func:`_orm.mapped_as_dataclass` does, taking
2301
+ into account :func:`_orm.mapped_column` and other attributes for dataclass-
2302
+ specific directives, but not actually mapping the class.
2303
+
2304
+ To create unmapped dataclass mixins when using a class hierarchy defined
2305
+ by :class:`.DeclarativeBase` and :class:`.MappedAsDataclass`, the
2306
+ :class:`.MappedAsDataclass` class may be subclassed alone for a similar
2307
+ effect.
2308
+
2309
+ .. versionadded:: 2.1
2310
+
2311
+ .. seealso::
2312
+
2313
+ :ref:`orm_declarative_dc_mixins` - background and example use.
2314
+
2315
+ """
2316
+
2317
+ def decorate(cls: Type[_O]) -> Type[_O]:
2318
+ _generate_dc_transforms(
2319
+ init=init,
2320
+ repr=repr,
2321
+ eq=eq,
2322
+ order=order,
2323
+ unsafe_hash=unsafe_hash,
2324
+ match_args=match_args,
2325
+ kw_only=kw_only,
2326
+ dataclass_callable=dataclass_callable,
2327
+ cls_=cls,
2328
+ )
2329
+ _ORMClassConfigurator._as_unmapped_dataclass(cls, cls.__dict__)
2330
+ return cls
2331
+
2332
+ if __cls:
2333
+ return decorate(__cls)
2334
+ else:
2335
+ return decorate