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
@@ -0,0 +1,6 @@
1
+ # ext/mypy/__init__.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
@@ -0,0 +1,324 @@
1
+ # ext/mypy/apply.py
2
+ # Copyright (C) 2021-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 List
11
+ from typing import Optional
12
+ from typing import Union
13
+
14
+ from mypy.nodes import ARG_NAMED_OPT
15
+ from mypy.nodes import Argument
16
+ from mypy.nodes import AssignmentStmt
17
+ from mypy.nodes import CallExpr
18
+ from mypy.nodes import ClassDef
19
+ from mypy.nodes import MDEF
20
+ from mypy.nodes import MemberExpr
21
+ from mypy.nodes import NameExpr
22
+ from mypy.nodes import RefExpr
23
+ from mypy.nodes import StrExpr
24
+ from mypy.nodes import SymbolTableNode
25
+ from mypy.nodes import TempNode
26
+ from mypy.nodes import TypeInfo
27
+ from mypy.nodes import Var
28
+ from mypy.plugin import SemanticAnalyzerPluginInterface
29
+ from mypy.plugins.common import add_method_to_class
30
+ from mypy.types import AnyType
31
+ from mypy.types import get_proper_type
32
+ from mypy.types import Instance
33
+ from mypy.types import NoneTyp
34
+ from mypy.types import ProperType
35
+ from mypy.types import TypeOfAny
36
+ from mypy.types import UnboundType
37
+ from mypy.types import UnionType
38
+
39
+ from . import infer
40
+ from . import util
41
+ from .names import expr_to_mapped_constructor
42
+ from .names import NAMED_TYPE_SQLA_MAPPED
43
+
44
+
45
+ def apply_mypy_mapped_attr(
46
+ cls: ClassDef,
47
+ api: SemanticAnalyzerPluginInterface,
48
+ item: Union[NameExpr, StrExpr],
49
+ attributes: List[util.SQLAlchemyAttribute],
50
+ ) -> None:
51
+ if isinstance(item, NameExpr):
52
+ name = item.name
53
+ elif isinstance(item, StrExpr):
54
+ name = item.value
55
+ else:
56
+ return None
57
+
58
+ for stmt in cls.defs.body:
59
+ if (
60
+ isinstance(stmt, AssignmentStmt)
61
+ and isinstance(stmt.lvalues[0], NameExpr)
62
+ and stmt.lvalues[0].name == name
63
+ ):
64
+ break
65
+ else:
66
+ util.fail(api, f"Can't find mapped attribute {name}", cls)
67
+ return None
68
+
69
+ if stmt.type is None:
70
+ util.fail(
71
+ api,
72
+ "Statement linked from _mypy_mapped_attrs has no "
73
+ "typing information",
74
+ stmt,
75
+ )
76
+ return None
77
+
78
+ left_hand_explicit_type = get_proper_type(stmt.type)
79
+ assert isinstance(
80
+ left_hand_explicit_type, (Instance, UnionType, UnboundType)
81
+ )
82
+
83
+ attributes.append(
84
+ util.SQLAlchemyAttribute(
85
+ name=name,
86
+ line=item.line,
87
+ column=item.column,
88
+ typ=left_hand_explicit_type,
89
+ info=cls.info,
90
+ )
91
+ )
92
+
93
+ apply_type_to_mapped_statement(
94
+ api, stmt, stmt.lvalues[0], left_hand_explicit_type, None
95
+ )
96
+
97
+
98
+ def re_apply_declarative_assignments(
99
+ cls: ClassDef,
100
+ api: SemanticAnalyzerPluginInterface,
101
+ attributes: List[util.SQLAlchemyAttribute],
102
+ ) -> None:
103
+ """For multiple class passes, re-apply our left-hand side types as mypy
104
+ seems to reset them in place.
105
+
106
+ """
107
+ mapped_attr_lookup = {attr.name: attr for attr in attributes}
108
+ update_cls_metadata = False
109
+
110
+ for stmt in cls.defs.body:
111
+ # for a re-apply, all of our statements are AssignmentStmt;
112
+ # @declared_attr calls will have been converted and this
113
+ # currently seems to be preserved by mypy (but who knows if this
114
+ # will change).
115
+ if (
116
+ isinstance(stmt, AssignmentStmt)
117
+ and isinstance(stmt.lvalues[0], NameExpr)
118
+ and stmt.lvalues[0].name in mapped_attr_lookup
119
+ and isinstance(stmt.lvalues[0].node, Var)
120
+ ):
121
+ left_node = stmt.lvalues[0].node
122
+
123
+ python_type_for_type = mapped_attr_lookup[
124
+ stmt.lvalues[0].name
125
+ ].type
126
+
127
+ left_node_proper_type = get_proper_type(left_node.type)
128
+
129
+ # if we have scanned an UnboundType and now there's a more
130
+ # specific type than UnboundType, call the re-scan so we
131
+ # can get that set up correctly
132
+ if (
133
+ isinstance(python_type_for_type, UnboundType)
134
+ and not isinstance(left_node_proper_type, UnboundType)
135
+ and (
136
+ isinstance(stmt.rvalue, CallExpr)
137
+ and isinstance(stmt.rvalue.callee, MemberExpr)
138
+ and isinstance(stmt.rvalue.callee.expr, NameExpr)
139
+ and stmt.rvalue.callee.expr.node is not None
140
+ and stmt.rvalue.callee.expr.node.fullname
141
+ == NAMED_TYPE_SQLA_MAPPED
142
+ and stmt.rvalue.callee.name == "_empty_constructor"
143
+ and isinstance(stmt.rvalue.args[0], CallExpr)
144
+ and isinstance(stmt.rvalue.args[0].callee, RefExpr)
145
+ )
146
+ ):
147
+ new_python_type_for_type = (
148
+ infer.infer_type_from_right_hand_nameexpr(
149
+ api,
150
+ stmt,
151
+ left_node,
152
+ left_node_proper_type,
153
+ stmt.rvalue.args[0].callee,
154
+ )
155
+ )
156
+
157
+ if new_python_type_for_type is not None and not isinstance(
158
+ new_python_type_for_type, UnboundType
159
+ ):
160
+ python_type_for_type = new_python_type_for_type
161
+
162
+ # update the SQLAlchemyAttribute with the better
163
+ # information
164
+ mapped_attr_lookup[stmt.lvalues[0].name].type = (
165
+ python_type_for_type
166
+ )
167
+
168
+ update_cls_metadata = True
169
+
170
+ if (
171
+ not isinstance(left_node.type, Instance)
172
+ or left_node.type.type.fullname != NAMED_TYPE_SQLA_MAPPED
173
+ ):
174
+ assert python_type_for_type is not None
175
+ left_node.type = api.named_type(
176
+ NAMED_TYPE_SQLA_MAPPED, [python_type_for_type]
177
+ )
178
+
179
+ if update_cls_metadata:
180
+ util.set_mapped_attributes(cls.info, attributes)
181
+
182
+
183
+ def apply_type_to_mapped_statement(
184
+ api: SemanticAnalyzerPluginInterface,
185
+ stmt: AssignmentStmt,
186
+ lvalue: NameExpr,
187
+ left_hand_explicit_type: Optional[ProperType],
188
+ python_type_for_type: Optional[ProperType],
189
+ ) -> None:
190
+ """Apply the Mapped[<type>] annotation and right hand object to a
191
+ declarative assignment statement.
192
+
193
+ This converts a Python declarative class statement such as::
194
+
195
+ class User(Base):
196
+ # ...
197
+
198
+ attrname = Column(Integer)
199
+
200
+ To one that describes the final Python behavior to Mypy::
201
+
202
+ ... format: off
203
+
204
+ class User(Base):
205
+ # ...
206
+
207
+ attrname : Mapped[Optional[int]] = <meaningless temp node>
208
+
209
+ ... format: on
210
+
211
+ """
212
+ left_node = lvalue.node
213
+ assert isinstance(left_node, Var)
214
+
215
+ # to be completely honest I have no idea what the difference between
216
+ # left_node.type and stmt.type is, what it means if these are different
217
+ # vs. the same, why in order to get tests to pass I have to assign
218
+ # to stmt.type for the second case and not the first. this is complete
219
+ # trying every combination until it works stuff.
220
+
221
+ if left_hand_explicit_type is not None:
222
+ lvalue.is_inferred_def = False
223
+ left_node.type = api.named_type(
224
+ NAMED_TYPE_SQLA_MAPPED, [left_hand_explicit_type]
225
+ )
226
+ else:
227
+ lvalue.is_inferred_def = False
228
+ left_node.type = api.named_type(
229
+ NAMED_TYPE_SQLA_MAPPED,
230
+ (
231
+ [AnyType(TypeOfAny.special_form)]
232
+ if python_type_for_type is None
233
+ else [python_type_for_type]
234
+ ),
235
+ )
236
+
237
+ # so to have it skip the right side totally, we can do this:
238
+ # stmt.rvalue = TempNode(AnyType(TypeOfAny.special_form))
239
+
240
+ # however, if we instead manufacture a new node that uses the old
241
+ # one, then we can still get type checking for the call itself,
242
+ # e.g. the Column, relationship() call, etc.
243
+
244
+ # rewrite the node as:
245
+ # <attr> : Mapped[<typ>] =
246
+ # _sa_Mapped._empty_constructor(<original CallExpr from rvalue>)
247
+ # the original right-hand side is maintained so it gets type checked
248
+ # internally
249
+ stmt.rvalue = expr_to_mapped_constructor(stmt.rvalue)
250
+
251
+ if stmt.type is not None and python_type_for_type is not None:
252
+ stmt.type = python_type_for_type
253
+
254
+
255
+ def add_additional_orm_attributes(
256
+ cls: ClassDef,
257
+ api: SemanticAnalyzerPluginInterface,
258
+ attributes: List[util.SQLAlchemyAttribute],
259
+ ) -> None:
260
+ """Apply __init__, __table__ and other attributes to the mapped class."""
261
+
262
+ info = util.info_for_cls(cls, api)
263
+
264
+ if info is None:
265
+ return
266
+
267
+ is_base = util.get_is_base(info)
268
+
269
+ if "__init__" not in info.names and not is_base:
270
+ mapped_attr_names = {attr.name: attr.type for attr in attributes}
271
+
272
+ for base in info.mro[1:-1]:
273
+ if "sqlalchemy" not in info.metadata:
274
+ continue
275
+
276
+ base_cls_attributes = util.get_mapped_attributes(base, api)
277
+ if base_cls_attributes is None:
278
+ continue
279
+
280
+ for attr in base_cls_attributes:
281
+ mapped_attr_names.setdefault(attr.name, attr.type)
282
+
283
+ arguments = []
284
+ for name, typ in mapped_attr_names.items():
285
+ if typ is None:
286
+ typ = AnyType(TypeOfAny.special_form)
287
+ arguments.append(
288
+ Argument(
289
+ variable=Var(name, typ),
290
+ type_annotation=typ,
291
+ initializer=TempNode(typ),
292
+ kind=ARG_NAMED_OPT,
293
+ )
294
+ )
295
+
296
+ add_method_to_class(api, cls, "__init__", arguments, NoneTyp())
297
+
298
+ if "__table__" not in info.names and util.get_has_table(info):
299
+ _apply_placeholder_attr_to_class(
300
+ api, cls, "sqlalchemy.sql.schema.Table", "__table__"
301
+ )
302
+ if not is_base:
303
+ _apply_placeholder_attr_to_class(
304
+ api, cls, "sqlalchemy.orm.mapper.Mapper", "__mapper__"
305
+ )
306
+
307
+
308
+ def _apply_placeholder_attr_to_class(
309
+ api: SemanticAnalyzerPluginInterface,
310
+ cls: ClassDef,
311
+ qualified_name: str,
312
+ attrname: str,
313
+ ) -> None:
314
+ sym = api.lookup_fully_qualified_or_none(qualified_name)
315
+ if sym:
316
+ assert isinstance(sym.node, TypeInfo)
317
+ type_: ProperType = Instance(sym.node, [])
318
+ else:
319
+ type_ = AnyType(TypeOfAny.special_form)
320
+ var = Var(attrname)
321
+ var._fullname = cls.fullname + "." + attrname
322
+ var.info = cls.info
323
+ var.type = type_
324
+ cls.info.names[attrname] = SymbolTableNode(MDEF, var)