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