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,590 @@
1
+ # ext/mypy/infer.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 Optional
11
+ from typing import Sequence
12
+
13
+ from mypy.maptype import map_instance_to_supertype
14
+ from mypy.nodes import AssignmentStmt
15
+ from mypy.nodes import CallExpr
16
+ from mypy.nodes import Expression
17
+ from mypy.nodes import FuncDef
18
+ from mypy.nodes import LambdaExpr
19
+ from mypy.nodes import MemberExpr
20
+ from mypy.nodes import NameExpr
21
+ from mypy.nodes import RefExpr
22
+ from mypy.nodes import StrExpr
23
+ from mypy.nodes import TypeInfo
24
+ from mypy.nodes import Var
25
+ from mypy.plugin import SemanticAnalyzerPluginInterface
26
+ from mypy.subtypes import is_subtype
27
+ from mypy.types import AnyType
28
+ from mypy.types import CallableType
29
+ from mypy.types import get_proper_type
30
+ from mypy.types import Instance
31
+ from mypy.types import NoneType
32
+ from mypy.types import ProperType
33
+ from mypy.types import TypeOfAny
34
+ from mypy.types import UnionType
35
+
36
+ from . import names
37
+ from . import util
38
+
39
+
40
+ def infer_type_from_right_hand_nameexpr(
41
+ api: SemanticAnalyzerPluginInterface,
42
+ stmt: AssignmentStmt,
43
+ node: Var,
44
+ left_hand_explicit_type: Optional[ProperType],
45
+ infer_from_right_side: RefExpr,
46
+ ) -> Optional[ProperType]:
47
+ type_id = names.type_id_for_callee(infer_from_right_side)
48
+ if type_id is None:
49
+ return None
50
+ elif type_id is names.MAPPED:
51
+ python_type_for_type = _infer_type_from_mapped(
52
+ api, stmt, node, left_hand_explicit_type, infer_from_right_side
53
+ )
54
+ elif type_id is names.COLUMN:
55
+ python_type_for_type = _infer_type_from_decl_column(
56
+ api, stmt, node, left_hand_explicit_type
57
+ )
58
+ elif type_id is names.RELATIONSHIP:
59
+ python_type_for_type = _infer_type_from_relationship(
60
+ api, stmt, node, left_hand_explicit_type
61
+ )
62
+ elif type_id is names.COLUMN_PROPERTY:
63
+ python_type_for_type = _infer_type_from_decl_column_property(
64
+ api, stmt, node, left_hand_explicit_type
65
+ )
66
+ elif type_id is names.SYNONYM_PROPERTY:
67
+ python_type_for_type = infer_type_from_left_hand_type_only(
68
+ api, node, left_hand_explicit_type
69
+ )
70
+ elif type_id is names.COMPOSITE_PROPERTY:
71
+ python_type_for_type = _infer_type_from_decl_composite_property(
72
+ api, stmt, node, left_hand_explicit_type
73
+ )
74
+ else:
75
+ return None
76
+
77
+ return python_type_for_type
78
+
79
+
80
+ def _infer_type_from_relationship(
81
+ api: SemanticAnalyzerPluginInterface,
82
+ stmt: AssignmentStmt,
83
+ node: Var,
84
+ left_hand_explicit_type: Optional[ProperType],
85
+ ) -> Optional[ProperType]:
86
+ """Infer the type of mapping from a relationship.
87
+
88
+ E.g.::
89
+
90
+ @reg.mapped
91
+ class MyClass:
92
+ # ...
93
+
94
+ addresses = relationship(Address, uselist=True)
95
+
96
+ order: Mapped["Order"] = relationship("Order")
97
+
98
+ Will resolve in mypy as::
99
+
100
+ @reg.mapped
101
+ class MyClass:
102
+ # ...
103
+
104
+ addresses: Mapped[List[Address]]
105
+
106
+ order: Mapped["Order"]
107
+
108
+ """
109
+
110
+ assert isinstance(stmt.rvalue, CallExpr)
111
+ target_cls_arg = stmt.rvalue.args[0]
112
+ python_type_for_type: Optional[ProperType] = None
113
+
114
+ if isinstance(target_cls_arg, NameExpr) and isinstance(
115
+ target_cls_arg.node, TypeInfo
116
+ ):
117
+ # type
118
+ related_object_type = target_cls_arg.node
119
+ python_type_for_type = Instance(related_object_type, [])
120
+
121
+ # other cases not covered - an error message directs the user
122
+ # to set an explicit type annotation
123
+ #
124
+ # node.type == str, it's a string
125
+ # if isinstance(target_cls_arg, NameExpr) and isinstance(
126
+ # target_cls_arg.node, Var
127
+ # )
128
+ # points to a type
129
+ # isinstance(target_cls_arg, NameExpr) and isinstance(
130
+ # target_cls_arg.node, TypeAlias
131
+ # )
132
+ # string expression
133
+ # isinstance(target_cls_arg, StrExpr)
134
+
135
+ uselist_arg = util.get_callexpr_kwarg(stmt.rvalue, "uselist")
136
+ collection_cls_arg: Optional[Expression] = util.get_callexpr_kwarg(
137
+ stmt.rvalue, "collection_class"
138
+ )
139
+ type_is_a_collection = False
140
+
141
+ # this can be used to determine Optional for a many-to-one
142
+ # in the same way nullable=False could be used, if we start supporting
143
+ # that.
144
+ # innerjoin_arg = util.get_callexpr_kwarg(stmt.rvalue, "innerjoin")
145
+
146
+ if (
147
+ uselist_arg is not None
148
+ and api.parse_bool(uselist_arg) is True
149
+ and collection_cls_arg is None
150
+ ):
151
+ type_is_a_collection = True
152
+ if python_type_for_type is not None:
153
+ python_type_for_type = api.named_type(
154
+ names.NAMED_TYPE_BUILTINS_LIST, [python_type_for_type]
155
+ )
156
+ elif (
157
+ uselist_arg is None or api.parse_bool(uselist_arg) is True
158
+ ) and collection_cls_arg is not None:
159
+ type_is_a_collection = True
160
+ if isinstance(collection_cls_arg, CallExpr):
161
+ collection_cls_arg = collection_cls_arg.callee
162
+
163
+ if isinstance(collection_cls_arg, NameExpr) and isinstance(
164
+ collection_cls_arg.node, TypeInfo
165
+ ):
166
+ if python_type_for_type is not None:
167
+ # this can still be overridden by the left hand side
168
+ # within _infer_Type_from_left_and_inferred_right
169
+ python_type_for_type = Instance(
170
+ collection_cls_arg.node, [python_type_for_type]
171
+ )
172
+ elif (
173
+ isinstance(collection_cls_arg, NameExpr)
174
+ and isinstance(collection_cls_arg.node, FuncDef)
175
+ and collection_cls_arg.node.type is not None
176
+ ):
177
+ if python_type_for_type is not None:
178
+ # this can still be overridden by the left hand side
179
+ # within _infer_Type_from_left_and_inferred_right
180
+
181
+ # TODO: handle mypy.types.Overloaded
182
+ if isinstance(collection_cls_arg.node.type, CallableType):
183
+ rt = get_proper_type(collection_cls_arg.node.type.ret_type)
184
+
185
+ if isinstance(rt, CallableType):
186
+ callable_ret_type = get_proper_type(rt.ret_type)
187
+ if isinstance(callable_ret_type, Instance):
188
+ python_type_for_type = Instance(
189
+ callable_ret_type.type,
190
+ [python_type_for_type],
191
+ )
192
+ else:
193
+ util.fail(
194
+ api,
195
+ "Expected Python collection type for "
196
+ "collection_class parameter",
197
+ stmt.rvalue,
198
+ )
199
+ python_type_for_type = None
200
+ elif uselist_arg is not None and api.parse_bool(uselist_arg) is False:
201
+ if collection_cls_arg is not None:
202
+ util.fail(
203
+ api,
204
+ "Sending uselist=False and collection_class at the same time "
205
+ "does not make sense",
206
+ stmt.rvalue,
207
+ )
208
+ if python_type_for_type is not None:
209
+ python_type_for_type = UnionType(
210
+ [python_type_for_type, NoneType()]
211
+ )
212
+
213
+ else:
214
+ if left_hand_explicit_type is None:
215
+ msg = (
216
+ "Can't infer scalar or collection for ORM mapped expression "
217
+ "assigned to attribute '{}' if both 'uselist' and "
218
+ "'collection_class' arguments are absent from the "
219
+ "relationship(); please specify a "
220
+ "type annotation on the left hand side."
221
+ )
222
+ util.fail(api, msg.format(node.name), node)
223
+
224
+ if python_type_for_type is None:
225
+ return infer_type_from_left_hand_type_only(
226
+ api, node, left_hand_explicit_type
227
+ )
228
+ elif left_hand_explicit_type is not None:
229
+ if type_is_a_collection:
230
+ assert isinstance(left_hand_explicit_type, Instance)
231
+ assert isinstance(python_type_for_type, Instance)
232
+ return _infer_collection_type_from_left_and_inferred_right(
233
+ api, node, left_hand_explicit_type, python_type_for_type
234
+ )
235
+ else:
236
+ return _infer_type_from_left_and_inferred_right(
237
+ api,
238
+ node,
239
+ left_hand_explicit_type,
240
+ python_type_for_type,
241
+ )
242
+ else:
243
+ return python_type_for_type
244
+
245
+
246
+ def _infer_type_from_decl_composite_property(
247
+ api: SemanticAnalyzerPluginInterface,
248
+ stmt: AssignmentStmt,
249
+ node: Var,
250
+ left_hand_explicit_type: Optional[ProperType],
251
+ ) -> Optional[ProperType]:
252
+ """Infer the type of mapping from a Composite."""
253
+
254
+ assert isinstance(stmt.rvalue, CallExpr)
255
+ target_cls_arg = stmt.rvalue.args[0]
256
+ python_type_for_type = None
257
+
258
+ if isinstance(target_cls_arg, NameExpr) and isinstance(
259
+ target_cls_arg.node, TypeInfo
260
+ ):
261
+ related_object_type = target_cls_arg.node
262
+ python_type_for_type = Instance(related_object_type, [])
263
+ else:
264
+ python_type_for_type = None
265
+
266
+ if python_type_for_type is None:
267
+ return infer_type_from_left_hand_type_only(
268
+ api, node, left_hand_explicit_type
269
+ )
270
+ elif left_hand_explicit_type is not None:
271
+ return _infer_type_from_left_and_inferred_right(
272
+ api, node, left_hand_explicit_type, python_type_for_type
273
+ )
274
+ else:
275
+ return python_type_for_type
276
+
277
+
278
+ def _infer_type_from_mapped(
279
+ api: SemanticAnalyzerPluginInterface,
280
+ stmt: AssignmentStmt,
281
+ node: Var,
282
+ left_hand_explicit_type: Optional[ProperType],
283
+ infer_from_right_side: RefExpr,
284
+ ) -> Optional[ProperType]:
285
+ """Infer the type of mapping from a right side expression
286
+ that returns Mapped.
287
+
288
+
289
+ """
290
+ assert isinstance(stmt.rvalue, CallExpr)
291
+
292
+ # (Pdb) print(stmt.rvalue.callee)
293
+ # NameExpr(query_expression [sqlalchemy.orm._orm_constructors.query_expression]) # noqa: E501
294
+ # (Pdb) stmt.rvalue.callee.node
295
+ # <mypy.nodes.FuncDef object at 0x7f8d92fb5940>
296
+ # (Pdb) stmt.rvalue.callee.node.type
297
+ # def [_T] (default_expr: sqlalchemy.sql.elements.ColumnElement[_T`-1] =) -> sqlalchemy.orm.base.Mapped[_T`-1] # noqa: E501
298
+ # sqlalchemy.orm.base.Mapped[_T`-1]
299
+ # the_mapped_type = stmt.rvalue.callee.node.type.ret_type
300
+
301
+ # TODO: look at generic ref and either use that,
302
+ # or reconcile w/ what's present, etc.
303
+ the_mapped_type = util.type_for_callee(infer_from_right_side) # noqa
304
+
305
+ return infer_type_from_left_hand_type_only(
306
+ api, node, left_hand_explicit_type
307
+ )
308
+
309
+
310
+ def _infer_type_from_decl_column_property(
311
+ api: SemanticAnalyzerPluginInterface,
312
+ stmt: AssignmentStmt,
313
+ node: Var,
314
+ left_hand_explicit_type: Optional[ProperType],
315
+ ) -> Optional[ProperType]:
316
+ """Infer the type of mapping from a ColumnProperty.
317
+
318
+ This includes mappings against ``column_property()`` as well as the
319
+ ``deferred()`` function.
320
+
321
+ """
322
+ assert isinstance(stmt.rvalue, CallExpr)
323
+
324
+ if stmt.rvalue.args:
325
+ first_prop_arg = stmt.rvalue.args[0]
326
+
327
+ if isinstance(first_prop_arg, CallExpr):
328
+ type_id = names.type_id_for_callee(first_prop_arg.callee)
329
+
330
+ # look for column_property() / deferred() etc with Column as first
331
+ # argument
332
+ if type_id is names.COLUMN:
333
+ return _infer_type_from_decl_column(
334
+ api,
335
+ stmt,
336
+ node,
337
+ left_hand_explicit_type,
338
+ right_hand_expression=first_prop_arg,
339
+ )
340
+
341
+ if isinstance(stmt.rvalue, CallExpr):
342
+ type_id = names.type_id_for_callee(stmt.rvalue.callee)
343
+ # this is probably not strictly necessary as we have to use the left
344
+ # hand type for query expression in any case. any other no-arg
345
+ # column prop objects would go here also
346
+ if type_id is names.QUERY_EXPRESSION:
347
+ return _infer_type_from_decl_column(
348
+ api,
349
+ stmt,
350
+ node,
351
+ left_hand_explicit_type,
352
+ )
353
+
354
+ return infer_type_from_left_hand_type_only(
355
+ api, node, left_hand_explicit_type
356
+ )
357
+
358
+
359
+ def _infer_type_from_decl_column(
360
+ api: SemanticAnalyzerPluginInterface,
361
+ stmt: AssignmentStmt,
362
+ node: Var,
363
+ left_hand_explicit_type: Optional[ProperType],
364
+ right_hand_expression: Optional[CallExpr] = None,
365
+ ) -> Optional[ProperType]:
366
+ """Infer the type of mapping from a Column.
367
+
368
+ E.g.::
369
+
370
+ @reg.mapped
371
+ class MyClass:
372
+ # ...
373
+
374
+ a = Column(Integer)
375
+
376
+ b = Column("b", String)
377
+
378
+ c: Mapped[int] = Column(Integer)
379
+
380
+ d: bool = Column(Boolean)
381
+
382
+ Will resolve in MyPy as::
383
+
384
+ @reg.mapped
385
+ class MyClass:
386
+ # ...
387
+
388
+ a: Mapped[int]
389
+
390
+ b: Mapped[str]
391
+
392
+ c: Mapped[int]
393
+
394
+ d: Mapped[bool]
395
+
396
+ """
397
+ assert isinstance(node, Var)
398
+
399
+ callee = None
400
+
401
+ if right_hand_expression is None:
402
+ if not isinstance(stmt.rvalue, CallExpr):
403
+ return None
404
+
405
+ right_hand_expression = stmt.rvalue
406
+
407
+ for column_arg in right_hand_expression.args[0:2]:
408
+ if isinstance(column_arg, CallExpr):
409
+ if isinstance(column_arg.callee, RefExpr):
410
+ # x = Column(String(50))
411
+ callee = column_arg.callee
412
+ type_args: Sequence[Expression] = column_arg.args
413
+ break
414
+ elif isinstance(column_arg, (NameExpr, MemberExpr)):
415
+ if isinstance(column_arg.node, TypeInfo):
416
+ # x = Column(String)
417
+ callee = column_arg
418
+ type_args = ()
419
+ break
420
+ else:
421
+ # x = Column(some_name, String), go to next argument
422
+ continue
423
+ elif isinstance(column_arg, (StrExpr,)):
424
+ # x = Column("name", String), go to next argument
425
+ continue
426
+ elif isinstance(column_arg, (LambdaExpr,)):
427
+ # x = Column("name", String, default=lambda: uuid.uuid4())
428
+ # go to next argument
429
+ continue
430
+ else:
431
+ assert False
432
+
433
+ if callee is None:
434
+ return None
435
+
436
+ if isinstance(callee.node, TypeInfo) and names.mro_has_id(
437
+ callee.node.mro, names.TYPEENGINE
438
+ ):
439
+ python_type_for_type = extract_python_type_from_typeengine(
440
+ api, callee.node, type_args
441
+ )
442
+
443
+ if left_hand_explicit_type is not None:
444
+ return _infer_type_from_left_and_inferred_right(
445
+ api, node, left_hand_explicit_type, python_type_for_type
446
+ )
447
+
448
+ else:
449
+ return UnionType([python_type_for_type, NoneType()])
450
+ else:
451
+ # it's not TypeEngine, it's typically implicitly typed
452
+ # like ForeignKey. we can't infer from the right side.
453
+ return infer_type_from_left_hand_type_only(
454
+ api, node, left_hand_explicit_type
455
+ )
456
+
457
+
458
+ def _infer_type_from_left_and_inferred_right(
459
+ api: SemanticAnalyzerPluginInterface,
460
+ node: Var,
461
+ left_hand_explicit_type: ProperType,
462
+ python_type_for_type: ProperType,
463
+ orig_left_hand_type: Optional[ProperType] = None,
464
+ orig_python_type_for_type: Optional[ProperType] = None,
465
+ ) -> Optional[ProperType]:
466
+ """Validate type when a left hand annotation is present and we also
467
+ could infer the right hand side::
468
+
469
+ attrname: SomeType = Column(SomeDBType)
470
+
471
+ """
472
+
473
+ if orig_left_hand_type is None:
474
+ orig_left_hand_type = left_hand_explicit_type
475
+ if orig_python_type_for_type is None:
476
+ orig_python_type_for_type = python_type_for_type
477
+
478
+ if not is_subtype(left_hand_explicit_type, python_type_for_type):
479
+ effective_type = api.named_type(
480
+ names.NAMED_TYPE_SQLA_MAPPED, [orig_python_type_for_type]
481
+ )
482
+
483
+ msg = (
484
+ "Left hand assignment '{}: {}' not compatible "
485
+ "with ORM mapped expression of type {}"
486
+ )
487
+ util.fail(
488
+ api,
489
+ msg.format(
490
+ node.name,
491
+ util.format_type(orig_left_hand_type, api.options),
492
+ util.format_type(effective_type, api.options),
493
+ ),
494
+ node,
495
+ )
496
+
497
+ return orig_left_hand_type
498
+
499
+
500
+ def _infer_collection_type_from_left_and_inferred_right(
501
+ api: SemanticAnalyzerPluginInterface,
502
+ node: Var,
503
+ left_hand_explicit_type: Instance,
504
+ python_type_for_type: Instance,
505
+ ) -> Optional[ProperType]:
506
+ orig_left_hand_type = left_hand_explicit_type
507
+ orig_python_type_for_type = python_type_for_type
508
+
509
+ if left_hand_explicit_type.args:
510
+ left_hand_arg = get_proper_type(left_hand_explicit_type.args[0])
511
+ python_type_arg = get_proper_type(python_type_for_type.args[0])
512
+ else:
513
+ left_hand_arg = left_hand_explicit_type
514
+ python_type_arg = python_type_for_type
515
+
516
+ assert isinstance(left_hand_arg, (Instance, UnionType))
517
+ assert isinstance(python_type_arg, (Instance, UnionType))
518
+
519
+ return _infer_type_from_left_and_inferred_right(
520
+ api,
521
+ node,
522
+ left_hand_arg,
523
+ python_type_arg,
524
+ orig_left_hand_type=orig_left_hand_type,
525
+ orig_python_type_for_type=orig_python_type_for_type,
526
+ )
527
+
528
+
529
+ def infer_type_from_left_hand_type_only(
530
+ api: SemanticAnalyzerPluginInterface,
531
+ node: Var,
532
+ left_hand_explicit_type: Optional[ProperType],
533
+ ) -> Optional[ProperType]:
534
+ """Determine the type based on explicit annotation only.
535
+
536
+ if no annotation were present, note that we need one there to know
537
+ the type.
538
+
539
+ """
540
+ if left_hand_explicit_type is None:
541
+ msg = (
542
+ "Can't infer type from ORM mapped expression "
543
+ "assigned to attribute '{}'; please specify a "
544
+ "Python type or "
545
+ "Mapped[<python type>] on the left hand side."
546
+ )
547
+ util.fail(api, msg.format(node.name), node)
548
+
549
+ return api.named_type(
550
+ names.NAMED_TYPE_SQLA_MAPPED, [AnyType(TypeOfAny.special_form)]
551
+ )
552
+
553
+ else:
554
+ # use type from the left hand side
555
+ return left_hand_explicit_type
556
+
557
+
558
+ def extract_python_type_from_typeengine(
559
+ api: SemanticAnalyzerPluginInterface,
560
+ node: TypeInfo,
561
+ type_args: Sequence[Expression],
562
+ ) -> ProperType:
563
+ if node.fullname == "sqlalchemy.sql.sqltypes.Enum" and type_args:
564
+ first_arg = type_args[0]
565
+ if isinstance(first_arg, RefExpr) and isinstance(
566
+ first_arg.node, TypeInfo
567
+ ):
568
+ for base_ in first_arg.node.mro:
569
+ if base_.fullname == "enum.Enum":
570
+ return Instance(first_arg.node, [])
571
+ # TODO: support other pep-435 types here
572
+ else:
573
+ return api.named_type(names.NAMED_TYPE_BUILTINS_STR, [])
574
+
575
+ assert node.has_base("sqlalchemy.sql.type_api.TypeEngine"), (
576
+ "could not extract Python type from node: %s" % node
577
+ )
578
+
579
+ type_engine_sym = api.lookup_fully_qualified_or_none(
580
+ "sqlalchemy.sql.type_api.TypeEngine"
581
+ )
582
+
583
+ assert type_engine_sym is not None and isinstance(
584
+ type_engine_sym.node, TypeInfo
585
+ )
586
+ type_engine = map_instance_to_supertype(
587
+ Instance(node, []),
588
+ type_engine_sym.node,
589
+ )
590
+ return get_proper_type(type_engine.args[-1])