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