SQLAlchemy 2.0.47__cp313-cp313t-win32.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (274) hide show
  1. sqlalchemy/__init__.py +283 -0
  2. sqlalchemy/connectors/__init__.py +18 -0
  3. sqlalchemy/connectors/aioodbc.py +184 -0
  4. sqlalchemy/connectors/asyncio.py +429 -0
  5. sqlalchemy/connectors/pyodbc.py +250 -0
  6. sqlalchemy/cyextension/__init__.py +6 -0
  7. sqlalchemy/cyextension/collections.cp313t-win32.pyd +0 -0
  8. sqlalchemy/cyextension/collections.pyx +409 -0
  9. sqlalchemy/cyextension/immutabledict.cp313t-win32.pyd +0 -0
  10. sqlalchemy/cyextension/immutabledict.pxd +8 -0
  11. sqlalchemy/cyextension/immutabledict.pyx +133 -0
  12. sqlalchemy/cyextension/processors.cp313t-win32.pyd +0 -0
  13. sqlalchemy/cyextension/processors.pyx +68 -0
  14. sqlalchemy/cyextension/resultproxy.cp313t-win32.pyd +0 -0
  15. sqlalchemy/cyextension/resultproxy.pyx +102 -0
  16. sqlalchemy/cyextension/util.cp313t-win32.pyd +0 -0
  17. sqlalchemy/cyextension/util.pyx +90 -0
  18. sqlalchemy/dialects/__init__.py +62 -0
  19. sqlalchemy/dialects/_typing.py +30 -0
  20. sqlalchemy/dialects/mssql/__init__.py +88 -0
  21. sqlalchemy/dialects/mssql/aioodbc.py +63 -0
  22. sqlalchemy/dialects/mssql/base.py +4093 -0
  23. sqlalchemy/dialects/mssql/information_schema.py +285 -0
  24. sqlalchemy/dialects/mssql/json.py +129 -0
  25. sqlalchemy/dialects/mssql/provision.py +185 -0
  26. sqlalchemy/dialects/mssql/pymssql.py +126 -0
  27. sqlalchemy/dialects/mssql/pyodbc.py +760 -0
  28. sqlalchemy/dialects/mysql/__init__.py +104 -0
  29. sqlalchemy/dialects/mysql/aiomysql.py +250 -0
  30. sqlalchemy/dialects/mysql/asyncmy.py +231 -0
  31. sqlalchemy/dialects/mysql/base.py +3949 -0
  32. sqlalchemy/dialects/mysql/cymysql.py +106 -0
  33. sqlalchemy/dialects/mysql/dml.py +225 -0
  34. sqlalchemy/dialects/mysql/enumerated.py +282 -0
  35. sqlalchemy/dialects/mysql/expression.py +146 -0
  36. sqlalchemy/dialects/mysql/json.py +91 -0
  37. sqlalchemy/dialects/mysql/mariadb.py +72 -0
  38. sqlalchemy/dialects/mysql/mariadbconnector.py +322 -0
  39. sqlalchemy/dialects/mysql/mysqlconnector.py +302 -0
  40. sqlalchemy/dialects/mysql/mysqldb.py +314 -0
  41. sqlalchemy/dialects/mysql/provision.py +153 -0
  42. sqlalchemy/dialects/mysql/pymysql.py +158 -0
  43. sqlalchemy/dialects/mysql/pyodbc.py +157 -0
  44. sqlalchemy/dialects/mysql/reflection.py +727 -0
  45. sqlalchemy/dialects/mysql/reserved_words.py +570 -0
  46. sqlalchemy/dialects/mysql/types.py +835 -0
  47. sqlalchemy/dialects/oracle/__init__.py +81 -0
  48. sqlalchemy/dialects/oracle/base.py +3802 -0
  49. sqlalchemy/dialects/oracle/cx_oracle.py +1555 -0
  50. sqlalchemy/dialects/oracle/dictionary.py +507 -0
  51. sqlalchemy/dialects/oracle/oracledb.py +941 -0
  52. sqlalchemy/dialects/oracle/provision.py +297 -0
  53. sqlalchemy/dialects/oracle/types.py +316 -0
  54. sqlalchemy/dialects/oracle/vector.py +365 -0
  55. sqlalchemy/dialects/postgresql/__init__.py +167 -0
  56. sqlalchemy/dialects/postgresql/_psycopg_common.py +189 -0
  57. sqlalchemy/dialects/postgresql/array.py +519 -0
  58. sqlalchemy/dialects/postgresql/asyncpg.py +1284 -0
  59. sqlalchemy/dialects/postgresql/base.py +5378 -0
  60. sqlalchemy/dialects/postgresql/dml.py +339 -0
  61. sqlalchemy/dialects/postgresql/ext.py +540 -0
  62. sqlalchemy/dialects/postgresql/hstore.py +406 -0
  63. sqlalchemy/dialects/postgresql/json.py +404 -0
  64. sqlalchemy/dialects/postgresql/named_types.py +524 -0
  65. sqlalchemy/dialects/postgresql/operators.py +129 -0
  66. sqlalchemy/dialects/postgresql/pg8000.py +669 -0
  67. sqlalchemy/dialects/postgresql/pg_catalog.py +326 -0
  68. sqlalchemy/dialects/postgresql/provision.py +183 -0
  69. sqlalchemy/dialects/postgresql/psycopg.py +862 -0
  70. sqlalchemy/dialects/postgresql/psycopg2.py +892 -0
  71. sqlalchemy/dialects/postgresql/psycopg2cffi.py +61 -0
  72. sqlalchemy/dialects/postgresql/ranges.py +1031 -0
  73. sqlalchemy/dialects/postgresql/types.py +313 -0
  74. sqlalchemy/dialects/sqlite/__init__.py +57 -0
  75. sqlalchemy/dialects/sqlite/aiosqlite.py +482 -0
  76. sqlalchemy/dialects/sqlite/base.py +3056 -0
  77. sqlalchemy/dialects/sqlite/dml.py +263 -0
  78. sqlalchemy/dialects/sqlite/json.py +92 -0
  79. sqlalchemy/dialects/sqlite/provision.py +229 -0
  80. sqlalchemy/dialects/sqlite/pysqlcipher.py +157 -0
  81. sqlalchemy/dialects/sqlite/pysqlite.py +756 -0
  82. sqlalchemy/dialects/type_migration_guidelines.txt +145 -0
  83. sqlalchemy/engine/__init__.py +62 -0
  84. sqlalchemy/engine/_py_processors.py +136 -0
  85. sqlalchemy/engine/_py_row.py +128 -0
  86. sqlalchemy/engine/_py_util.py +74 -0
  87. sqlalchemy/engine/base.py +3390 -0
  88. sqlalchemy/engine/characteristics.py +155 -0
  89. sqlalchemy/engine/create.py +893 -0
  90. sqlalchemy/engine/cursor.py +2298 -0
  91. sqlalchemy/engine/default.py +2394 -0
  92. sqlalchemy/engine/events.py +965 -0
  93. sqlalchemy/engine/interfaces.py +3471 -0
  94. sqlalchemy/engine/mock.py +134 -0
  95. sqlalchemy/engine/processors.py +61 -0
  96. sqlalchemy/engine/reflection.py +2102 -0
  97. sqlalchemy/engine/result.py +2399 -0
  98. sqlalchemy/engine/row.py +400 -0
  99. sqlalchemy/engine/strategies.py +16 -0
  100. sqlalchemy/engine/url.py +924 -0
  101. sqlalchemy/engine/util.py +167 -0
  102. sqlalchemy/event/__init__.py +26 -0
  103. sqlalchemy/event/api.py +220 -0
  104. sqlalchemy/event/attr.py +676 -0
  105. sqlalchemy/event/base.py +472 -0
  106. sqlalchemy/event/legacy.py +258 -0
  107. sqlalchemy/event/registry.py +390 -0
  108. sqlalchemy/events.py +17 -0
  109. sqlalchemy/exc.py +832 -0
  110. sqlalchemy/ext/__init__.py +11 -0
  111. sqlalchemy/ext/associationproxy.py +2027 -0
  112. sqlalchemy/ext/asyncio/__init__.py +25 -0
  113. sqlalchemy/ext/asyncio/base.py +281 -0
  114. sqlalchemy/ext/asyncio/engine.py +1471 -0
  115. sqlalchemy/ext/asyncio/exc.py +21 -0
  116. sqlalchemy/ext/asyncio/result.py +965 -0
  117. sqlalchemy/ext/asyncio/scoping.py +1599 -0
  118. sqlalchemy/ext/asyncio/session.py +1947 -0
  119. sqlalchemy/ext/automap.py +1701 -0
  120. sqlalchemy/ext/baked.py +570 -0
  121. sqlalchemy/ext/compiler.py +600 -0
  122. sqlalchemy/ext/declarative/__init__.py +65 -0
  123. sqlalchemy/ext/declarative/extensions.py +564 -0
  124. sqlalchemy/ext/horizontal_shard.py +478 -0
  125. sqlalchemy/ext/hybrid.py +1535 -0
  126. sqlalchemy/ext/indexable.py +364 -0
  127. sqlalchemy/ext/instrumentation.py +450 -0
  128. sqlalchemy/ext/mutable.py +1085 -0
  129. sqlalchemy/ext/mypy/__init__.py +6 -0
  130. sqlalchemy/ext/mypy/apply.py +324 -0
  131. sqlalchemy/ext/mypy/decl_class.py +515 -0
  132. sqlalchemy/ext/mypy/infer.py +590 -0
  133. sqlalchemy/ext/mypy/names.py +335 -0
  134. sqlalchemy/ext/mypy/plugin.py +303 -0
  135. sqlalchemy/ext/mypy/util.py +357 -0
  136. sqlalchemy/ext/orderinglist.py +439 -0
  137. sqlalchemy/ext/serializer.py +185 -0
  138. sqlalchemy/future/__init__.py +16 -0
  139. sqlalchemy/future/engine.py +15 -0
  140. sqlalchemy/inspection.py +174 -0
  141. sqlalchemy/log.py +288 -0
  142. sqlalchemy/orm/__init__.py +171 -0
  143. sqlalchemy/orm/_orm_constructors.py +2661 -0
  144. sqlalchemy/orm/_typing.py +179 -0
  145. sqlalchemy/orm/attributes.py +2845 -0
  146. sqlalchemy/orm/base.py +971 -0
  147. sqlalchemy/orm/bulk_persistence.py +2135 -0
  148. sqlalchemy/orm/clsregistry.py +571 -0
  149. sqlalchemy/orm/collections.py +1627 -0
  150. sqlalchemy/orm/context.py +3334 -0
  151. sqlalchemy/orm/decl_api.py +2004 -0
  152. sqlalchemy/orm/decl_base.py +2192 -0
  153. sqlalchemy/orm/dependency.py +1302 -0
  154. sqlalchemy/orm/descriptor_props.py +1092 -0
  155. sqlalchemy/orm/dynamic.py +300 -0
  156. sqlalchemy/orm/evaluator.py +379 -0
  157. sqlalchemy/orm/events.py +3252 -0
  158. sqlalchemy/orm/exc.py +237 -0
  159. sqlalchemy/orm/identity.py +302 -0
  160. sqlalchemy/orm/instrumentation.py +754 -0
  161. sqlalchemy/orm/interfaces.py +1496 -0
  162. sqlalchemy/orm/loading.py +1686 -0
  163. sqlalchemy/orm/mapped_collection.py +557 -0
  164. sqlalchemy/orm/mapper.py +4444 -0
  165. sqlalchemy/orm/path_registry.py +809 -0
  166. sqlalchemy/orm/persistence.py +1788 -0
  167. sqlalchemy/orm/properties.py +935 -0
  168. sqlalchemy/orm/query.py +3459 -0
  169. sqlalchemy/orm/relationships.py +3508 -0
  170. sqlalchemy/orm/scoping.py +2148 -0
  171. sqlalchemy/orm/session.py +5280 -0
  172. sqlalchemy/orm/state.py +1168 -0
  173. sqlalchemy/orm/state_changes.py +196 -0
  174. sqlalchemy/orm/strategies.py +3470 -0
  175. sqlalchemy/orm/strategy_options.py +2568 -0
  176. sqlalchemy/orm/sync.py +164 -0
  177. sqlalchemy/orm/unitofwork.py +796 -0
  178. sqlalchemy/orm/util.py +2403 -0
  179. sqlalchemy/orm/writeonly.py +674 -0
  180. sqlalchemy/pool/__init__.py +44 -0
  181. sqlalchemy/pool/base.py +1524 -0
  182. sqlalchemy/pool/events.py +375 -0
  183. sqlalchemy/pool/impl.py +588 -0
  184. sqlalchemy/py.typed +0 -0
  185. sqlalchemy/schema.py +69 -0
  186. sqlalchemy/sql/__init__.py +145 -0
  187. sqlalchemy/sql/_dml_constructors.py +132 -0
  188. sqlalchemy/sql/_elements_constructors.py +1872 -0
  189. sqlalchemy/sql/_orm_types.py +20 -0
  190. sqlalchemy/sql/_py_util.py +75 -0
  191. sqlalchemy/sql/_selectable_constructors.py +763 -0
  192. sqlalchemy/sql/_typing.py +482 -0
  193. sqlalchemy/sql/annotation.py +587 -0
  194. sqlalchemy/sql/base.py +2293 -0
  195. sqlalchemy/sql/cache_key.py +1057 -0
  196. sqlalchemy/sql/coercions.py +1404 -0
  197. sqlalchemy/sql/compiler.py +8081 -0
  198. sqlalchemy/sql/crud.py +1752 -0
  199. sqlalchemy/sql/ddl.py +1444 -0
  200. sqlalchemy/sql/default_comparator.py +551 -0
  201. sqlalchemy/sql/dml.py +1850 -0
  202. sqlalchemy/sql/elements.py +5589 -0
  203. sqlalchemy/sql/events.py +458 -0
  204. sqlalchemy/sql/expression.py +159 -0
  205. sqlalchemy/sql/functions.py +2158 -0
  206. sqlalchemy/sql/lambdas.py +1442 -0
  207. sqlalchemy/sql/naming.py +209 -0
  208. sqlalchemy/sql/operators.py +2623 -0
  209. sqlalchemy/sql/roles.py +323 -0
  210. sqlalchemy/sql/schema.py +6222 -0
  211. sqlalchemy/sql/selectable.py +7265 -0
  212. sqlalchemy/sql/sqltypes.py +3930 -0
  213. sqlalchemy/sql/traversals.py +1024 -0
  214. sqlalchemy/sql/type_api.py +2368 -0
  215. sqlalchemy/sql/util.py +1485 -0
  216. sqlalchemy/sql/visitors.py +1164 -0
  217. sqlalchemy/testing/__init__.py +96 -0
  218. sqlalchemy/testing/assertions.py +994 -0
  219. sqlalchemy/testing/assertsql.py +520 -0
  220. sqlalchemy/testing/asyncio.py +135 -0
  221. sqlalchemy/testing/config.py +434 -0
  222. sqlalchemy/testing/engines.py +483 -0
  223. sqlalchemy/testing/entities.py +117 -0
  224. sqlalchemy/testing/exclusions.py +476 -0
  225. sqlalchemy/testing/fixtures/__init__.py +28 -0
  226. sqlalchemy/testing/fixtures/base.py +384 -0
  227. sqlalchemy/testing/fixtures/mypy.py +332 -0
  228. sqlalchemy/testing/fixtures/orm.py +227 -0
  229. sqlalchemy/testing/fixtures/sql.py +482 -0
  230. sqlalchemy/testing/pickleable.py +155 -0
  231. sqlalchemy/testing/plugin/__init__.py +6 -0
  232. sqlalchemy/testing/plugin/bootstrap.py +51 -0
  233. sqlalchemy/testing/plugin/plugin_base.py +828 -0
  234. sqlalchemy/testing/plugin/pytestplugin.py +892 -0
  235. sqlalchemy/testing/profiling.py +329 -0
  236. sqlalchemy/testing/provision.py +603 -0
  237. sqlalchemy/testing/requirements.py +1945 -0
  238. sqlalchemy/testing/schema.py +198 -0
  239. sqlalchemy/testing/suite/__init__.py +19 -0
  240. sqlalchemy/testing/suite/test_cte.py +237 -0
  241. sqlalchemy/testing/suite/test_ddl.py +389 -0
  242. sqlalchemy/testing/suite/test_deprecations.py +153 -0
  243. sqlalchemy/testing/suite/test_dialect.py +776 -0
  244. sqlalchemy/testing/suite/test_insert.py +630 -0
  245. sqlalchemy/testing/suite/test_reflection.py +3557 -0
  246. sqlalchemy/testing/suite/test_results.py +504 -0
  247. sqlalchemy/testing/suite/test_rowcount.py +258 -0
  248. sqlalchemy/testing/suite/test_select.py +2010 -0
  249. sqlalchemy/testing/suite/test_sequence.py +317 -0
  250. sqlalchemy/testing/suite/test_types.py +2147 -0
  251. sqlalchemy/testing/suite/test_unicode_ddl.py +189 -0
  252. sqlalchemy/testing/suite/test_update_delete.py +139 -0
  253. sqlalchemy/testing/util.py +535 -0
  254. sqlalchemy/testing/warnings.py +52 -0
  255. sqlalchemy/types.py +74 -0
  256. sqlalchemy/util/__init__.py +162 -0
  257. sqlalchemy/util/_collections.py +712 -0
  258. sqlalchemy/util/_concurrency_py3k.py +288 -0
  259. sqlalchemy/util/_has_cy.py +40 -0
  260. sqlalchemy/util/_py_collections.py +541 -0
  261. sqlalchemy/util/compat.py +421 -0
  262. sqlalchemy/util/concurrency.py +110 -0
  263. sqlalchemy/util/deprecations.py +401 -0
  264. sqlalchemy/util/langhelpers.py +2203 -0
  265. sqlalchemy/util/preloaded.py +150 -0
  266. sqlalchemy/util/queue.py +322 -0
  267. sqlalchemy/util/tool_support.py +201 -0
  268. sqlalchemy/util/topological.py +120 -0
  269. sqlalchemy/util/typing.py +734 -0
  270. sqlalchemy-2.0.47.dist-info/METADATA +243 -0
  271. sqlalchemy-2.0.47.dist-info/RECORD +274 -0
  272. sqlalchemy-2.0.47.dist-info/WHEEL +5 -0
  273. sqlalchemy-2.0.47.dist-info/licenses/LICENSE +19 -0
  274. sqlalchemy-2.0.47.dist-info/top_level.txt +1 -0
sqlalchemy/orm/exc.py ADDED
@@ -0,0 +1,237 @@
1
+ # orm/exc.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
+ """SQLAlchemy ORM exceptions."""
9
+
10
+ from __future__ import annotations
11
+
12
+ from typing import Any
13
+ from typing import Optional
14
+ from typing import Tuple
15
+ from typing import Type
16
+ from typing import TYPE_CHECKING
17
+ from typing import TypeVar
18
+
19
+ from .util import _mapper_property_as_plain_name
20
+ from .. import exc as sa_exc
21
+ from .. import util
22
+ from ..exc import MultipleResultsFound # noqa
23
+ from ..exc import NoResultFound # noqa
24
+
25
+ if TYPE_CHECKING:
26
+ from .interfaces import LoaderStrategy
27
+ from .interfaces import MapperProperty
28
+ from .state import InstanceState
29
+
30
+ _T = TypeVar("_T", bound=Any)
31
+
32
+ NO_STATE = (AttributeError, KeyError)
33
+ """Exception types that may be raised by instrumentation implementations."""
34
+
35
+
36
+ class StaleDataError(sa_exc.SQLAlchemyError):
37
+ """An operation encountered database state that is unaccounted for.
38
+
39
+ Conditions which cause this to happen include:
40
+
41
+ * A flush may have attempted to update or delete rows
42
+ and an unexpected number of rows were matched during
43
+ the UPDATE or DELETE statement. Note that when
44
+ version_id_col is used, rows in UPDATE or DELETE statements
45
+ are also matched against the current known version
46
+ identifier.
47
+
48
+ * A mapped object with version_id_col was refreshed,
49
+ and the version number coming back from the database does
50
+ not match that of the object itself.
51
+
52
+ * A object is detached from its parent object, however
53
+ the object was previously attached to a different parent
54
+ identity which was garbage collected, and a decision
55
+ cannot be made if the new parent was really the most
56
+ recent "parent".
57
+
58
+ """
59
+
60
+
61
+ ConcurrentModificationError = StaleDataError
62
+
63
+
64
+ class FlushError(sa_exc.SQLAlchemyError):
65
+ """A invalid condition was detected during flush()."""
66
+
67
+
68
+ class MappedAnnotationError(sa_exc.ArgumentError):
69
+ """Raised when ORM annotated declarative cannot interpret the
70
+ expression present inside of the :class:`.Mapped` construct.
71
+
72
+ .. versionadded:: 2.0.40
73
+
74
+ """
75
+
76
+
77
+ class UnmappedError(sa_exc.InvalidRequestError):
78
+ """Base for exceptions that involve expected mappings not present."""
79
+
80
+
81
+ class ObjectDereferencedError(sa_exc.SQLAlchemyError):
82
+ """An operation cannot complete due to an object being garbage
83
+ collected.
84
+
85
+ """
86
+
87
+
88
+ class DetachedInstanceError(sa_exc.SQLAlchemyError):
89
+ """An attempt to access unloaded attributes on a
90
+ mapped instance that is detached."""
91
+
92
+ code = "bhk3"
93
+
94
+
95
+ class UnmappedInstanceError(UnmappedError):
96
+ """An mapping operation was requested for an unknown instance."""
97
+
98
+ @util.preload_module("sqlalchemy.orm.base")
99
+ def __init__(self, obj: object, msg: Optional[str] = None):
100
+ base = util.preloaded.orm_base
101
+
102
+ if not msg:
103
+ try:
104
+ base.class_mapper(type(obj))
105
+ name = _safe_cls_name(type(obj))
106
+ msg = (
107
+ "Class %r is mapped, but this instance lacks "
108
+ "instrumentation. This occurs when the instance "
109
+ "is created before sqlalchemy.orm.mapper(%s) "
110
+ "was called." % (name, name)
111
+ )
112
+ except UnmappedClassError:
113
+ msg = f"Class '{_safe_cls_name(type(obj))}' is not mapped"
114
+ if isinstance(obj, type):
115
+ msg += (
116
+ "; was a class (%s) supplied where an instance was "
117
+ "required?" % _safe_cls_name(obj)
118
+ )
119
+ UnmappedError.__init__(self, msg)
120
+
121
+ def __reduce__(self) -> Any:
122
+ return self.__class__, (None, self.args[0])
123
+
124
+
125
+ class UnmappedClassError(UnmappedError):
126
+ """An mapping operation was requested for an unknown class."""
127
+
128
+ def __init__(self, cls: Type[_T], msg: Optional[str] = None):
129
+ if not msg:
130
+ msg = _default_unmapped(cls)
131
+ UnmappedError.__init__(self, msg)
132
+
133
+ def __reduce__(self) -> Any:
134
+ return self.__class__, (None, self.args[0])
135
+
136
+
137
+ class ObjectDeletedError(sa_exc.InvalidRequestError):
138
+ """A refresh operation failed to retrieve the database
139
+ row corresponding to an object's known primary key identity.
140
+
141
+ A refresh operation proceeds when an expired attribute is
142
+ accessed on an object, or when :meth:`_query.Query.get` is
143
+ used to retrieve an object which is, upon retrieval, detected
144
+ as expired. A SELECT is emitted for the target row
145
+ based on primary key; if no row is returned, this
146
+ exception is raised.
147
+
148
+ The true meaning of this exception is simply that
149
+ no row exists for the primary key identifier associated
150
+ with a persistent object. The row may have been
151
+ deleted, or in some cases the primary key updated
152
+ to a new value, outside of the ORM's management of the target
153
+ object.
154
+
155
+ """
156
+
157
+ @util.preload_module("sqlalchemy.orm.base")
158
+ def __init__(self, state: InstanceState[Any], msg: Optional[str] = None):
159
+ base = util.preloaded.orm_base
160
+
161
+ if not msg:
162
+ msg = (
163
+ "Instance '%s' has been deleted, or its "
164
+ "row is otherwise not present." % base.state_str(state)
165
+ )
166
+
167
+ sa_exc.InvalidRequestError.__init__(self, msg)
168
+
169
+ def __reduce__(self) -> Any:
170
+ return self.__class__, (None, self.args[0])
171
+
172
+
173
+ class UnmappedColumnError(sa_exc.InvalidRequestError):
174
+ """Mapping operation was requested on an unknown column."""
175
+
176
+
177
+ class LoaderStrategyException(sa_exc.InvalidRequestError):
178
+ """A loader strategy for an attribute does not exist."""
179
+
180
+ def __init__(
181
+ self,
182
+ applied_to_property_type: Type[Any],
183
+ requesting_property: MapperProperty[Any],
184
+ applies_to: Optional[Type[MapperProperty[Any]]],
185
+ actual_strategy_type: Optional[Type[LoaderStrategy]],
186
+ strategy_key: Tuple[Any, ...],
187
+ ):
188
+ if actual_strategy_type is None:
189
+ sa_exc.InvalidRequestError.__init__(
190
+ self,
191
+ "Can't find strategy %s for %s"
192
+ % (strategy_key, requesting_property),
193
+ )
194
+ else:
195
+ assert applies_to is not None
196
+ sa_exc.InvalidRequestError.__init__(
197
+ self,
198
+ 'Can\'t apply "%s" strategy to property "%s", '
199
+ 'which is a "%s"; this loader strategy is intended '
200
+ 'to be used with a "%s".'
201
+ % (
202
+ util.clsname_as_plain_name(actual_strategy_type),
203
+ requesting_property,
204
+ _mapper_property_as_plain_name(applied_to_property_type),
205
+ _mapper_property_as_plain_name(applies_to),
206
+ ),
207
+ )
208
+
209
+
210
+ def _safe_cls_name(cls: Type[Any]) -> str:
211
+ cls_name: Optional[str]
212
+ try:
213
+ cls_name = ".".join((cls.__module__, cls.__name__))
214
+ except AttributeError:
215
+ cls_name = getattr(cls, "__name__", None)
216
+ if cls_name is None:
217
+ cls_name = repr(cls)
218
+ return cls_name
219
+
220
+
221
+ @util.preload_module("sqlalchemy.orm.base")
222
+ def _default_unmapped(cls: Type[Any]) -> Optional[str]:
223
+ base = util.preloaded.orm_base
224
+
225
+ try:
226
+ mappers = base.manager_of_class(cls).mappers # type: ignore
227
+ except (
228
+ UnmappedClassError,
229
+ TypeError,
230
+ ) + NO_STATE:
231
+ mappers = {}
232
+ name = _safe_cls_name(cls)
233
+
234
+ if not mappers:
235
+ return f"Class '{name}' is not mapped"
236
+ else:
237
+ return None
@@ -0,0 +1,302 @@
1
+ # orm/identity.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
+ from __future__ import annotations
9
+
10
+ from typing import Any
11
+ from typing import cast
12
+ from typing import Dict
13
+ from typing import Iterable
14
+ from typing import Iterator
15
+ from typing import List
16
+ from typing import NoReturn
17
+ from typing import Optional
18
+ from typing import Set
19
+ from typing import Tuple
20
+ from typing import TYPE_CHECKING
21
+ from typing import TypeVar
22
+ import weakref
23
+
24
+ from . import util as orm_util
25
+ from .. import exc as sa_exc
26
+
27
+ if TYPE_CHECKING:
28
+ from ._typing import _IdentityKeyType
29
+ from .state import InstanceState
30
+
31
+
32
+ _T = TypeVar("_T", bound=Any)
33
+
34
+ _O = TypeVar("_O", bound=object)
35
+
36
+
37
+ class IdentityMap:
38
+ _wr: weakref.ref[IdentityMap]
39
+
40
+ _dict: Dict[_IdentityKeyType[Any], Any]
41
+ _modified: Set[InstanceState[Any]]
42
+
43
+ def __init__(self) -> None:
44
+ self._dict = {}
45
+ self._modified = set()
46
+ self._wr = weakref.ref(self)
47
+
48
+ def _kill(self) -> None:
49
+ self._add_unpresent = _killed # type: ignore
50
+
51
+ def all_states(self) -> List[InstanceState[Any]]:
52
+ raise NotImplementedError()
53
+
54
+ def contains_state(self, state: InstanceState[Any]) -> bool:
55
+ raise NotImplementedError()
56
+
57
+ def __contains__(self, key: _IdentityKeyType[Any]) -> bool:
58
+ raise NotImplementedError()
59
+
60
+ def safe_discard(self, state: InstanceState[Any]) -> None:
61
+ raise NotImplementedError()
62
+
63
+ def __getitem__(self, key: _IdentityKeyType[_O]) -> _O:
64
+ raise NotImplementedError()
65
+
66
+ def get(
67
+ self, key: _IdentityKeyType[_O], default: Optional[_O] = None
68
+ ) -> Optional[_O]:
69
+ raise NotImplementedError()
70
+
71
+ def fast_get_state(
72
+ self, key: _IdentityKeyType[_O]
73
+ ) -> Optional[InstanceState[_O]]:
74
+ raise NotImplementedError()
75
+
76
+ def keys(self) -> Iterable[_IdentityKeyType[Any]]:
77
+ return self._dict.keys()
78
+
79
+ def values(self) -> Iterable[object]:
80
+ raise NotImplementedError()
81
+
82
+ def replace(self, state: InstanceState[_O]) -> Optional[InstanceState[_O]]:
83
+ raise NotImplementedError()
84
+
85
+ def add(self, state: InstanceState[Any]) -> bool:
86
+ raise NotImplementedError()
87
+
88
+ def _fast_discard(self, state: InstanceState[Any]) -> None:
89
+ raise NotImplementedError()
90
+
91
+ def _add_unpresent(
92
+ self, state: InstanceState[Any], key: _IdentityKeyType[Any]
93
+ ) -> None:
94
+ """optional inlined form of add() which can assume item isn't present
95
+ in the map"""
96
+ self.add(state)
97
+
98
+ def _manage_incoming_state(self, state: InstanceState[Any]) -> None:
99
+ state._instance_dict = self._wr
100
+
101
+ if state.modified:
102
+ self._modified.add(state)
103
+
104
+ def _manage_removed_state(self, state: InstanceState[Any]) -> None:
105
+ del state._instance_dict
106
+ if state.modified:
107
+ self._modified.discard(state)
108
+
109
+ def _dirty_states(self) -> Set[InstanceState[Any]]:
110
+ return self._modified
111
+
112
+ def check_modified(self) -> bool:
113
+ """return True if any InstanceStates present have been marked
114
+ as 'modified'.
115
+
116
+ """
117
+ return bool(self._modified)
118
+
119
+ def has_key(self, key: _IdentityKeyType[Any]) -> bool:
120
+ return key in self
121
+
122
+ def __len__(self) -> int:
123
+ return len(self._dict)
124
+
125
+
126
+ class WeakInstanceDict(IdentityMap):
127
+ _dict: Dict[_IdentityKeyType[Any], InstanceState[Any]]
128
+
129
+ def __getitem__(self, key: _IdentityKeyType[_O]) -> _O:
130
+ state = cast("InstanceState[_O]", self._dict[key])
131
+ o = state.obj()
132
+ if o is None:
133
+ raise KeyError(key)
134
+ return o
135
+
136
+ def __contains__(self, key: _IdentityKeyType[Any]) -> bool:
137
+ try:
138
+ if key in self._dict:
139
+ state = self._dict[key]
140
+ o = state.obj()
141
+ else:
142
+ return False
143
+ except KeyError:
144
+ return False
145
+ else:
146
+ return o is not None
147
+
148
+ def contains_state(self, state: InstanceState[Any]) -> bool:
149
+ if state.key in self._dict:
150
+ if TYPE_CHECKING:
151
+ assert state.key is not None
152
+ try:
153
+ return self._dict[state.key] is state
154
+ except KeyError:
155
+ return False
156
+ else:
157
+ return False
158
+
159
+ def replace(
160
+ self, state: InstanceState[Any]
161
+ ) -> Optional[InstanceState[Any]]:
162
+ assert state.key is not None
163
+ if state.key in self._dict:
164
+ try:
165
+ existing = existing_non_none = self._dict[state.key]
166
+ except KeyError:
167
+ # catch gc removed the key after we just checked for it
168
+ existing = None
169
+ else:
170
+ if existing_non_none is not state:
171
+ self._manage_removed_state(existing_non_none)
172
+ else:
173
+ return None
174
+ else:
175
+ existing = None
176
+
177
+ self._dict[state.key] = state
178
+ self._manage_incoming_state(state)
179
+ return existing
180
+
181
+ def add(self, state: InstanceState[Any]) -> bool:
182
+ key = state.key
183
+ assert key is not None
184
+ # inline of self.__contains__
185
+ if key in self._dict:
186
+ try:
187
+ existing_state = self._dict[key]
188
+ except KeyError:
189
+ # catch gc removed the key after we just checked for it
190
+ pass
191
+ else:
192
+ if existing_state is not state:
193
+ o = existing_state.obj()
194
+ if o is not None:
195
+ raise sa_exc.InvalidRequestError(
196
+ "Can't attach instance "
197
+ "%s; another instance with key %s is already "
198
+ "present in this session."
199
+ % (orm_util.state_str(state), state.key)
200
+ )
201
+ else:
202
+ return False
203
+ self._dict[key] = state
204
+ self._manage_incoming_state(state)
205
+ return True
206
+
207
+ def _add_unpresent(
208
+ self, state: InstanceState[Any], key: _IdentityKeyType[Any]
209
+ ) -> None:
210
+ # inlined form of add() called by loading.py
211
+ self._dict[key] = state
212
+ state._instance_dict = self._wr
213
+
214
+ def fast_get_state(
215
+ self, key: _IdentityKeyType[_O]
216
+ ) -> Optional[InstanceState[_O]]:
217
+ return self._dict.get(key)
218
+
219
+ def get(
220
+ self, key: _IdentityKeyType[_O], default: Optional[_O] = None
221
+ ) -> Optional[_O]:
222
+ if key not in self._dict:
223
+ return default
224
+ try:
225
+ state = cast("InstanceState[_O]", self._dict[key])
226
+ except KeyError:
227
+ # catch gc removed the key after we just checked for it
228
+ return default
229
+ else:
230
+ o = state.obj()
231
+ if o is None:
232
+ return default
233
+ return o
234
+
235
+ def items(self) -> List[Tuple[_IdentityKeyType[Any], InstanceState[Any]]]:
236
+ values = self.all_states()
237
+ result = []
238
+ for state in values:
239
+ value = state.obj()
240
+ key = state.key
241
+ assert key is not None
242
+ if value is not None:
243
+ result.append((key, value))
244
+ return result
245
+
246
+ def values(self) -> List[object]:
247
+ values = self.all_states()
248
+ result = []
249
+ for state in values:
250
+ value = state.obj()
251
+ if value is not None:
252
+ result.append(value)
253
+
254
+ return result
255
+
256
+ def __iter__(self) -> Iterator[_IdentityKeyType[Any]]:
257
+ return iter(self.keys())
258
+
259
+ def all_states(self) -> List[InstanceState[Any]]:
260
+ return list(self._dict.values())
261
+
262
+ def _fast_discard(self, state: InstanceState[Any]) -> None:
263
+ # used by InstanceState for state being
264
+ # GC'ed, inlines _managed_removed_state
265
+ key = state.key
266
+ assert key is not None
267
+ try:
268
+ st = self._dict[key]
269
+ except KeyError:
270
+ # catch gc removed the key after we just checked for it
271
+ pass
272
+ else:
273
+ if st is state:
274
+ self._dict.pop(key, None)
275
+
276
+ def discard(self, state: InstanceState[Any]) -> None:
277
+ self.safe_discard(state)
278
+
279
+ def safe_discard(self, state: InstanceState[Any]) -> None:
280
+ key = state.key
281
+ if key in self._dict:
282
+ assert key is not None
283
+ try:
284
+ st = self._dict[key]
285
+ except KeyError:
286
+ # catch gc removed the key after we just checked for it
287
+ pass
288
+ else:
289
+ if st is state:
290
+ self._dict.pop(key, None)
291
+ self._manage_removed_state(state)
292
+
293
+
294
+ def _killed(state: InstanceState[Any], key: _IdentityKeyType[Any]) -> NoReturn:
295
+ # external function to avoid creating cycles when assigned to
296
+ # the IdentityMap
297
+ raise sa_exc.InvalidRequestError(
298
+ "Object %s cannot be converted to 'persistent' state, as this "
299
+ "identity map is no longer valid. Has the owning Session "
300
+ "been closed?" % orm_util.state_str(state),
301
+ code="lkrp",
302
+ )