SQLAlchemy 2.1.0b2__cp313-cp313t-win_arm64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (270) hide show
  1. sqlalchemy/__init__.py +298 -0
  2. sqlalchemy/connectors/__init__.py +18 -0
  3. sqlalchemy/connectors/aioodbc.py +171 -0
  4. sqlalchemy/connectors/asyncio.py +476 -0
  5. sqlalchemy/connectors/pyodbc.py +250 -0
  6. sqlalchemy/dialects/__init__.py +62 -0
  7. sqlalchemy/dialects/_typing.py +30 -0
  8. sqlalchemy/dialects/mssql/__init__.py +89 -0
  9. sqlalchemy/dialects/mssql/aioodbc.py +63 -0
  10. sqlalchemy/dialects/mssql/base.py +4166 -0
  11. sqlalchemy/dialects/mssql/information_schema.py +285 -0
  12. sqlalchemy/dialects/mssql/json.py +140 -0
  13. sqlalchemy/dialects/mssql/mssqlpython.py +220 -0
  14. sqlalchemy/dialects/mssql/provision.py +196 -0
  15. sqlalchemy/dialects/mssql/pymssql.py +126 -0
  16. sqlalchemy/dialects/mssql/pyodbc.py +698 -0
  17. sqlalchemy/dialects/mysql/__init__.py +106 -0
  18. sqlalchemy/dialects/mysql/_mariadb_shim.py +312 -0
  19. sqlalchemy/dialects/mysql/aiomysql.py +226 -0
  20. sqlalchemy/dialects/mysql/asyncmy.py +214 -0
  21. sqlalchemy/dialects/mysql/base.py +3877 -0
  22. sqlalchemy/dialects/mysql/cymysql.py +106 -0
  23. sqlalchemy/dialects/mysql/dml.py +279 -0
  24. sqlalchemy/dialects/mysql/enumerated.py +277 -0
  25. sqlalchemy/dialects/mysql/expression.py +146 -0
  26. sqlalchemy/dialects/mysql/json.py +92 -0
  27. sqlalchemy/dialects/mysql/mariadb.py +67 -0
  28. sqlalchemy/dialects/mysql/mariadbconnector.py +330 -0
  29. sqlalchemy/dialects/mysql/mysqlconnector.py +296 -0
  30. sqlalchemy/dialects/mysql/mysqldb.py +312 -0
  31. sqlalchemy/dialects/mysql/provision.py +153 -0
  32. sqlalchemy/dialects/mysql/pymysql.py +157 -0
  33. sqlalchemy/dialects/mysql/pyodbc.py +156 -0
  34. sqlalchemy/dialects/mysql/reflection.py +724 -0
  35. sqlalchemy/dialects/mysql/reserved_words.py +570 -0
  36. sqlalchemy/dialects/mysql/types.py +845 -0
  37. sqlalchemy/dialects/oracle/__init__.py +85 -0
  38. sqlalchemy/dialects/oracle/base.py +3977 -0
  39. sqlalchemy/dialects/oracle/cx_oracle.py +1601 -0
  40. sqlalchemy/dialects/oracle/dictionary.py +507 -0
  41. sqlalchemy/dialects/oracle/json.py +158 -0
  42. sqlalchemy/dialects/oracle/oracledb.py +909 -0
  43. sqlalchemy/dialects/oracle/provision.py +288 -0
  44. sqlalchemy/dialects/oracle/types.py +367 -0
  45. sqlalchemy/dialects/oracle/vector.py +368 -0
  46. sqlalchemy/dialects/postgresql/__init__.py +171 -0
  47. sqlalchemy/dialects/postgresql/_psycopg_common.py +229 -0
  48. sqlalchemy/dialects/postgresql/array.py +534 -0
  49. sqlalchemy/dialects/postgresql/asyncpg.py +1323 -0
  50. sqlalchemy/dialects/postgresql/base.py +5789 -0
  51. sqlalchemy/dialects/postgresql/bitstring.py +327 -0
  52. sqlalchemy/dialects/postgresql/dml.py +360 -0
  53. sqlalchemy/dialects/postgresql/ext.py +593 -0
  54. sqlalchemy/dialects/postgresql/hstore.py +423 -0
  55. sqlalchemy/dialects/postgresql/json.py +408 -0
  56. sqlalchemy/dialects/postgresql/named_types.py +521 -0
  57. sqlalchemy/dialects/postgresql/operators.py +130 -0
  58. sqlalchemy/dialects/postgresql/pg8000.py +670 -0
  59. sqlalchemy/dialects/postgresql/pg_catalog.py +344 -0
  60. sqlalchemy/dialects/postgresql/provision.py +184 -0
  61. sqlalchemy/dialects/postgresql/psycopg.py +799 -0
  62. sqlalchemy/dialects/postgresql/psycopg2.py +860 -0
  63. sqlalchemy/dialects/postgresql/psycopg2cffi.py +61 -0
  64. sqlalchemy/dialects/postgresql/ranges.py +1002 -0
  65. sqlalchemy/dialects/postgresql/types.py +388 -0
  66. sqlalchemy/dialects/sqlite/__init__.py +57 -0
  67. sqlalchemy/dialects/sqlite/aiosqlite.py +321 -0
  68. sqlalchemy/dialects/sqlite/base.py +3063 -0
  69. sqlalchemy/dialects/sqlite/dml.py +279 -0
  70. sqlalchemy/dialects/sqlite/json.py +100 -0
  71. sqlalchemy/dialects/sqlite/provision.py +229 -0
  72. sqlalchemy/dialects/sqlite/pysqlcipher.py +161 -0
  73. sqlalchemy/dialects/sqlite/pysqlite.py +754 -0
  74. sqlalchemy/dialects/type_migration_guidelines.txt +145 -0
  75. sqlalchemy/engine/__init__.py +62 -0
  76. sqlalchemy/engine/_processors_cy.cp313t-win_arm64.pyd +0 -0
  77. sqlalchemy/engine/_processors_cy.py +92 -0
  78. sqlalchemy/engine/_result_cy.cp313t-win_arm64.pyd +0 -0
  79. sqlalchemy/engine/_result_cy.py +633 -0
  80. sqlalchemy/engine/_row_cy.cp313t-win_arm64.pyd +0 -0
  81. sqlalchemy/engine/_row_cy.py +232 -0
  82. sqlalchemy/engine/_util_cy.cp313t-win_arm64.pyd +0 -0
  83. sqlalchemy/engine/_util_cy.py +136 -0
  84. sqlalchemy/engine/base.py +3354 -0
  85. sqlalchemy/engine/characteristics.py +155 -0
  86. sqlalchemy/engine/create.py +877 -0
  87. sqlalchemy/engine/cursor.py +2421 -0
  88. sqlalchemy/engine/default.py +2402 -0
  89. sqlalchemy/engine/events.py +965 -0
  90. sqlalchemy/engine/interfaces.py +3495 -0
  91. sqlalchemy/engine/mock.py +134 -0
  92. sqlalchemy/engine/processors.py +82 -0
  93. sqlalchemy/engine/reflection.py +2100 -0
  94. sqlalchemy/engine/result.py +1966 -0
  95. sqlalchemy/engine/row.py +397 -0
  96. sqlalchemy/engine/strategies.py +16 -0
  97. sqlalchemy/engine/url.py +922 -0
  98. sqlalchemy/engine/util.py +156 -0
  99. sqlalchemy/event/__init__.py +26 -0
  100. sqlalchemy/event/api.py +220 -0
  101. sqlalchemy/event/attr.py +674 -0
  102. sqlalchemy/event/base.py +472 -0
  103. sqlalchemy/event/legacy.py +258 -0
  104. sqlalchemy/event/registry.py +390 -0
  105. sqlalchemy/events.py +17 -0
  106. sqlalchemy/exc.py +922 -0
  107. sqlalchemy/ext/__init__.py +11 -0
  108. sqlalchemy/ext/associationproxy.py +2072 -0
  109. sqlalchemy/ext/asyncio/__init__.py +29 -0
  110. sqlalchemy/ext/asyncio/base.py +281 -0
  111. sqlalchemy/ext/asyncio/engine.py +1487 -0
  112. sqlalchemy/ext/asyncio/exc.py +21 -0
  113. sqlalchemy/ext/asyncio/result.py +994 -0
  114. sqlalchemy/ext/asyncio/scoping.py +1679 -0
  115. sqlalchemy/ext/asyncio/session.py +2007 -0
  116. sqlalchemy/ext/automap.py +1701 -0
  117. sqlalchemy/ext/baked.py +559 -0
  118. sqlalchemy/ext/compiler.py +600 -0
  119. sqlalchemy/ext/declarative/__init__.py +65 -0
  120. sqlalchemy/ext/declarative/extensions.py +560 -0
  121. sqlalchemy/ext/horizontal_shard.py +481 -0
  122. sqlalchemy/ext/hybrid.py +1877 -0
  123. sqlalchemy/ext/indexable.py +364 -0
  124. sqlalchemy/ext/instrumentation.py +450 -0
  125. sqlalchemy/ext/mutable.py +1081 -0
  126. sqlalchemy/ext/orderinglist.py +439 -0
  127. sqlalchemy/ext/serializer.py +185 -0
  128. sqlalchemy/future/__init__.py +16 -0
  129. sqlalchemy/future/engine.py +15 -0
  130. sqlalchemy/inspection.py +174 -0
  131. sqlalchemy/log.py +283 -0
  132. sqlalchemy/orm/__init__.py +176 -0
  133. sqlalchemy/orm/_orm_constructors.py +2694 -0
  134. sqlalchemy/orm/_typing.py +179 -0
  135. sqlalchemy/orm/attributes.py +2868 -0
  136. sqlalchemy/orm/base.py +976 -0
  137. sqlalchemy/orm/bulk_persistence.py +2152 -0
  138. sqlalchemy/orm/clsregistry.py +582 -0
  139. sqlalchemy/orm/collections.py +1568 -0
  140. sqlalchemy/orm/context.py +3471 -0
  141. sqlalchemy/orm/decl_api.py +2280 -0
  142. sqlalchemy/orm/decl_base.py +2309 -0
  143. sqlalchemy/orm/dependency.py +1306 -0
  144. sqlalchemy/orm/descriptor_props.py +1183 -0
  145. sqlalchemy/orm/dynamic.py +307 -0
  146. sqlalchemy/orm/evaluator.py +379 -0
  147. sqlalchemy/orm/events.py +3386 -0
  148. sqlalchemy/orm/exc.py +237 -0
  149. sqlalchemy/orm/identity.py +302 -0
  150. sqlalchemy/orm/instrumentation.py +746 -0
  151. sqlalchemy/orm/interfaces.py +1589 -0
  152. sqlalchemy/orm/loading.py +1684 -0
  153. sqlalchemy/orm/mapped_collection.py +557 -0
  154. sqlalchemy/orm/mapper.py +4411 -0
  155. sqlalchemy/orm/path_registry.py +829 -0
  156. sqlalchemy/orm/persistence.py +1789 -0
  157. sqlalchemy/orm/properties.py +973 -0
  158. sqlalchemy/orm/query.py +3528 -0
  159. sqlalchemy/orm/relationships.py +3570 -0
  160. sqlalchemy/orm/scoping.py +2232 -0
  161. sqlalchemy/orm/session.py +5403 -0
  162. sqlalchemy/orm/state.py +1175 -0
  163. sqlalchemy/orm/state_changes.py +196 -0
  164. sqlalchemy/orm/strategies.py +3492 -0
  165. sqlalchemy/orm/strategy_options.py +2562 -0
  166. sqlalchemy/orm/sync.py +164 -0
  167. sqlalchemy/orm/unitofwork.py +798 -0
  168. sqlalchemy/orm/util.py +2438 -0
  169. sqlalchemy/orm/writeonly.py +694 -0
  170. sqlalchemy/pool/__init__.py +41 -0
  171. sqlalchemy/pool/base.py +1522 -0
  172. sqlalchemy/pool/events.py +375 -0
  173. sqlalchemy/pool/impl.py +582 -0
  174. sqlalchemy/py.typed +0 -0
  175. sqlalchemy/schema.py +74 -0
  176. sqlalchemy/sql/__init__.py +156 -0
  177. sqlalchemy/sql/_annotated_cols.py +397 -0
  178. sqlalchemy/sql/_dml_constructors.py +132 -0
  179. sqlalchemy/sql/_elements_constructors.py +2164 -0
  180. sqlalchemy/sql/_orm_types.py +20 -0
  181. sqlalchemy/sql/_selectable_constructors.py +840 -0
  182. sqlalchemy/sql/_typing.py +487 -0
  183. sqlalchemy/sql/_util_cy.cp313t-win_arm64.pyd +0 -0
  184. sqlalchemy/sql/_util_cy.py +127 -0
  185. sqlalchemy/sql/annotation.py +590 -0
  186. sqlalchemy/sql/base.py +2699 -0
  187. sqlalchemy/sql/cache_key.py +1066 -0
  188. sqlalchemy/sql/coercions.py +1373 -0
  189. sqlalchemy/sql/compiler.py +8327 -0
  190. sqlalchemy/sql/crud.py +1815 -0
  191. sqlalchemy/sql/ddl.py +1928 -0
  192. sqlalchemy/sql/default_comparator.py +654 -0
  193. sqlalchemy/sql/dml.py +1977 -0
  194. sqlalchemy/sql/elements.py +6033 -0
  195. sqlalchemy/sql/events.py +458 -0
  196. sqlalchemy/sql/expression.py +172 -0
  197. sqlalchemy/sql/functions.py +2305 -0
  198. sqlalchemy/sql/lambdas.py +1443 -0
  199. sqlalchemy/sql/naming.py +209 -0
  200. sqlalchemy/sql/operators.py +2897 -0
  201. sqlalchemy/sql/roles.py +332 -0
  202. sqlalchemy/sql/schema.py +6703 -0
  203. sqlalchemy/sql/selectable.py +7553 -0
  204. sqlalchemy/sql/sqltypes.py +4093 -0
  205. sqlalchemy/sql/traversals.py +1042 -0
  206. sqlalchemy/sql/type_api.py +2446 -0
  207. sqlalchemy/sql/util.py +1495 -0
  208. sqlalchemy/sql/visitors.py +1157 -0
  209. sqlalchemy/testing/__init__.py +96 -0
  210. sqlalchemy/testing/assertions.py +1007 -0
  211. sqlalchemy/testing/assertsql.py +519 -0
  212. sqlalchemy/testing/asyncio.py +128 -0
  213. sqlalchemy/testing/config.py +440 -0
  214. sqlalchemy/testing/engines.py +483 -0
  215. sqlalchemy/testing/entities.py +117 -0
  216. sqlalchemy/testing/exclusions.py +476 -0
  217. sqlalchemy/testing/fixtures/__init__.py +30 -0
  218. sqlalchemy/testing/fixtures/base.py +384 -0
  219. sqlalchemy/testing/fixtures/mypy.py +247 -0
  220. sqlalchemy/testing/fixtures/orm.py +227 -0
  221. sqlalchemy/testing/fixtures/sql.py +538 -0
  222. sqlalchemy/testing/pickleable.py +155 -0
  223. sqlalchemy/testing/plugin/__init__.py +6 -0
  224. sqlalchemy/testing/plugin/bootstrap.py +51 -0
  225. sqlalchemy/testing/plugin/plugin_base.py +828 -0
  226. sqlalchemy/testing/plugin/pytestplugin.py +892 -0
  227. sqlalchemy/testing/profiling.py +329 -0
  228. sqlalchemy/testing/provision.py +613 -0
  229. sqlalchemy/testing/requirements.py +1978 -0
  230. sqlalchemy/testing/schema.py +198 -0
  231. sqlalchemy/testing/suite/__init__.py +19 -0
  232. sqlalchemy/testing/suite/test_cte.py +237 -0
  233. sqlalchemy/testing/suite/test_ddl.py +420 -0
  234. sqlalchemy/testing/suite/test_dialect.py +776 -0
  235. sqlalchemy/testing/suite/test_insert.py +630 -0
  236. sqlalchemy/testing/suite/test_reflection.py +3557 -0
  237. sqlalchemy/testing/suite/test_results.py +660 -0
  238. sqlalchemy/testing/suite/test_rowcount.py +258 -0
  239. sqlalchemy/testing/suite/test_select.py +2112 -0
  240. sqlalchemy/testing/suite/test_sequence.py +317 -0
  241. sqlalchemy/testing/suite/test_table_via_select.py +686 -0
  242. sqlalchemy/testing/suite/test_types.py +2271 -0
  243. sqlalchemy/testing/suite/test_unicode_ddl.py +189 -0
  244. sqlalchemy/testing/suite/test_update_delete.py +139 -0
  245. sqlalchemy/testing/util.py +535 -0
  246. sqlalchemy/testing/warnings.py +52 -0
  247. sqlalchemy/types.py +76 -0
  248. sqlalchemy/util/__init__.py +158 -0
  249. sqlalchemy/util/_collections.py +688 -0
  250. sqlalchemy/util/_collections_cy.cp313t-win_arm64.pyd +0 -0
  251. sqlalchemy/util/_collections_cy.pxd +8 -0
  252. sqlalchemy/util/_collections_cy.py +516 -0
  253. sqlalchemy/util/_has_cython.py +46 -0
  254. sqlalchemy/util/_immutabledict_cy.cp313t-win_arm64.pyd +0 -0
  255. sqlalchemy/util/_immutabledict_cy.py +240 -0
  256. sqlalchemy/util/compat.py +299 -0
  257. sqlalchemy/util/concurrency.py +322 -0
  258. sqlalchemy/util/cython.py +79 -0
  259. sqlalchemy/util/deprecations.py +401 -0
  260. sqlalchemy/util/langhelpers.py +2320 -0
  261. sqlalchemy/util/preloaded.py +152 -0
  262. sqlalchemy/util/queue.py +304 -0
  263. sqlalchemy/util/tool_support.py +201 -0
  264. sqlalchemy/util/topological.py +120 -0
  265. sqlalchemy/util/typing.py +711 -0
  266. sqlalchemy-2.1.0b2.dist-info/METADATA +269 -0
  267. sqlalchemy-2.1.0b2.dist-info/RECORD +270 -0
  268. sqlalchemy-2.1.0b2.dist-info/WHEEL +5 -0
  269. sqlalchemy-2.1.0b2.dist-info/licenses/LICENSE +19 -0
  270. sqlalchemy-2.1.0b2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,2100 @@
1
+ # engine/reflection.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
+ """Provides an abstraction for obtaining database schema information.
9
+
10
+ Usage Notes:
11
+
12
+ Here are some general conventions when accessing the low level inspector
13
+ methods such as get_table_names, get_columns, etc.
14
+
15
+ 1. Inspector methods return lists of dicts in most cases for the following
16
+ reasons:
17
+
18
+ * They're both standard types that can be serialized.
19
+ * Using a dict instead of a tuple allows easy expansion of attributes.
20
+ * Using a list for the outer structure maintains order and is easy to work
21
+ with (e.g. list comprehension [d['name'] for d in cols]).
22
+
23
+ 2. Records that contain a name, such as the column name in a column record
24
+ use the key 'name'. So for most return values, each record will have a
25
+ 'name' attribute..
26
+ """
27
+ from __future__ import annotations
28
+
29
+ import contextlib
30
+ from dataclasses import dataclass
31
+ from enum import auto
32
+ from enum import Flag
33
+ from enum import unique
34
+ from typing import Any
35
+ from typing import Callable
36
+ from typing import Collection
37
+ from typing import Dict
38
+ from typing import final
39
+ from typing import Generator
40
+ from typing import Iterable
41
+ from typing import List
42
+ from typing import Optional
43
+ from typing import Sequence
44
+ from typing import Set
45
+ from typing import Tuple
46
+ from typing import TYPE_CHECKING
47
+ from typing import TypeVar
48
+ from typing import Union
49
+
50
+ from .base import Connection
51
+ from .base import Engine
52
+ from .. import exc
53
+ from .. import inspection
54
+ from .. import sql
55
+ from .. import util
56
+ from ..sql import operators
57
+ from ..sql import schema as sa_schema
58
+ from ..sql.cache_key import _ad_hoc_cache_key_from_args
59
+ from ..sql.elements import quoted_name
60
+ from ..sql.elements import TextClause
61
+ from ..sql.type_api import TypeEngine
62
+ from ..sql.visitors import InternalTraversal
63
+ from ..util import topological
64
+
65
+ if TYPE_CHECKING:
66
+ from .interfaces import Dialect
67
+ from .interfaces import ReflectedCheckConstraint
68
+ from .interfaces import ReflectedColumn
69
+ from .interfaces import ReflectedForeignKeyConstraint
70
+ from .interfaces import ReflectedIndex
71
+ from .interfaces import ReflectedPrimaryKeyConstraint
72
+ from .interfaces import ReflectedTableComment
73
+ from .interfaces import ReflectedUniqueConstraint
74
+ from .interfaces import TableKey
75
+
76
+ _R = TypeVar("_R")
77
+
78
+
79
+ @util.decorator
80
+ def cache(
81
+ fn: Callable[..., _R],
82
+ self: Dialect,
83
+ con: Connection,
84
+ *args: Any,
85
+ **kw: Any,
86
+ ) -> _R:
87
+ info_cache = kw.get("info_cache", None)
88
+ if info_cache is None:
89
+ return fn(self, con, *args, **kw)
90
+ exclude = {"info_cache", "unreflectable"}
91
+ key = (
92
+ fn.__name__,
93
+ tuple(
94
+ (str(a), a.quote) if isinstance(a, quoted_name) else a
95
+ for a in args
96
+ if isinstance(a, str)
97
+ ),
98
+ tuple(
99
+ (k, (str(v), v.quote) if isinstance(v, quoted_name) else v)
100
+ for k, v in kw.items()
101
+ if k not in exclude
102
+ ),
103
+ )
104
+ ret: _R = info_cache.get(key)
105
+ if ret is None:
106
+ ret = fn(self, con, *args, **kw)
107
+ info_cache[key] = ret
108
+ return ret
109
+
110
+
111
+ def flexi_cache(
112
+ *traverse_args: Tuple[str, InternalTraversal]
113
+ ) -> Callable[[Callable[..., _R]], Callable[..., _R]]:
114
+ @util.decorator
115
+ def go(
116
+ fn: Callable[..., _R],
117
+ self: Dialect,
118
+ con: Connection,
119
+ *args: Any,
120
+ **kw: Any,
121
+ ) -> _R:
122
+ info_cache = kw.get("info_cache", None)
123
+ if info_cache is None:
124
+ return fn(self, con, *args, **kw)
125
+ key = _ad_hoc_cache_key_from_args((fn.__name__,), traverse_args, args)
126
+ ret: _R = info_cache.get(key)
127
+ if ret is None:
128
+ ret = fn(self, con, *args, **kw)
129
+ info_cache[key] = ret
130
+ return ret
131
+
132
+ return go
133
+
134
+
135
+ @unique
136
+ class ObjectKind(Flag):
137
+ """Enumerator that indicates which kind of object to return when calling
138
+ the ``get_multi`` methods.
139
+
140
+ This is a Flag enum, so custom combinations can be passed. For example,
141
+ to reflect tables and plain views ``ObjectKind.TABLE | ObjectKind.VIEW``
142
+ may be used.
143
+
144
+ .. note::
145
+ Not all dialect may support all kind of object. If a dialect does
146
+ not support a particular object an empty dict is returned.
147
+ In case a dialect supports an object, but the requested method
148
+ is not applicable for the specified kind the default value
149
+ will be returned for each reflected object. For example reflecting
150
+ check constraints of view return a dict with all the views with
151
+ empty lists as values.
152
+ """
153
+
154
+ TABLE = auto()
155
+ "Reflect table objects"
156
+ VIEW = auto()
157
+ "Reflect plain view objects"
158
+ MATERIALIZED_VIEW = auto()
159
+ "Reflect materialized view object"
160
+
161
+ ANY_VIEW = VIEW | MATERIALIZED_VIEW
162
+ "Reflect any kind of view objects"
163
+ ANY = TABLE | VIEW | MATERIALIZED_VIEW
164
+ "Reflect all type of objects"
165
+
166
+
167
+ @unique
168
+ class ObjectScope(Flag):
169
+ """Enumerator that indicates which scope to use when calling
170
+ the ``get_multi`` methods.
171
+ """
172
+
173
+ DEFAULT = auto()
174
+ "Include default scope"
175
+ TEMPORARY = auto()
176
+ "Include only temp scope"
177
+ ANY = DEFAULT | TEMPORARY
178
+ "Include both default and temp scope"
179
+
180
+
181
+ @inspection._self_inspects
182
+ class Inspector(inspection.Inspectable["Inspector"]):
183
+ """Performs database schema inspection.
184
+
185
+ The Inspector acts as a proxy to the reflection methods of the
186
+ :class:`~sqlalchemy.engine.interfaces.Dialect`, providing a
187
+ consistent interface as well as caching support for previously
188
+ fetched metadata.
189
+
190
+ A :class:`_reflection.Inspector` object is usually created via the
191
+ :func:`_sa.inspect` function, which may be passed an
192
+ :class:`_engine.Engine`
193
+ or a :class:`_engine.Connection`::
194
+
195
+ from sqlalchemy import inspect, create_engine
196
+
197
+ engine = create_engine("...")
198
+ insp = inspect(engine)
199
+
200
+ Where above, the :class:`~sqlalchemy.engine.interfaces.Dialect` associated
201
+ with the engine may opt to return an :class:`_reflection.Inspector`
202
+ subclass that
203
+ provides additional methods specific to the dialect's target database.
204
+
205
+ """
206
+
207
+ bind: Union[Engine, Connection]
208
+ engine: Engine
209
+ _op_context_requires_connect: bool
210
+ dialect: Dialect
211
+ info_cache: Dict[Any, Any]
212
+
213
+ @util.deprecated(
214
+ "1.4",
215
+ "The __init__() method on :class:`_reflection.Inspector` "
216
+ "is deprecated and "
217
+ "will be removed in a future release. Please use the "
218
+ ":func:`.sqlalchemy.inspect` "
219
+ "function on an :class:`_engine.Engine` or "
220
+ ":class:`_engine.Connection` "
221
+ "in order to "
222
+ "acquire an :class:`_reflection.Inspector`.",
223
+ )
224
+ def __init__(self, bind: Union[Engine, Connection]):
225
+ """Initialize a new :class:`_reflection.Inspector`.
226
+
227
+ :param bind: a :class:`~sqlalchemy.engine.Connection`,
228
+ which is typically an instance of
229
+ :class:`~sqlalchemy.engine.Engine` or
230
+ :class:`~sqlalchemy.engine.Connection`.
231
+
232
+ For a dialect-specific instance of :class:`_reflection.Inspector`, see
233
+ :meth:`_reflection.Inspector.from_engine`
234
+
235
+ """
236
+ self._init_legacy(bind)
237
+
238
+ @classmethod
239
+ def _construct(
240
+ cls, init: Callable[..., Any], bind: Union[Engine, Connection]
241
+ ) -> Inspector:
242
+ if hasattr(bind.dialect, "inspector"):
243
+ cls = bind.dialect.inspector
244
+
245
+ self = cls.__new__(cls)
246
+ init(self, bind)
247
+ return self
248
+
249
+ def _init_legacy(self, bind: Union[Engine, Connection]) -> None:
250
+ if hasattr(bind, "exec_driver_sql"):
251
+ self._init_connection(bind) # type: ignore[arg-type]
252
+ else:
253
+ self._init_engine(bind)
254
+
255
+ def _init_engine(self, engine: Engine) -> None:
256
+ self.bind = self.engine = engine
257
+ engine.connect().close()
258
+ self._op_context_requires_connect = True
259
+ self.dialect = self.engine.dialect
260
+ self.info_cache = {}
261
+
262
+ def _init_connection(self, connection: Connection) -> None:
263
+ self.bind = connection
264
+ self.engine = connection.engine
265
+ self._op_context_requires_connect = False
266
+ self.dialect = self.engine.dialect
267
+ self.info_cache = {}
268
+
269
+ def clear_cache(self) -> None:
270
+ """reset the cache for this :class:`.Inspector`.
271
+
272
+ Inspection methods that have data cached will emit SQL queries
273
+ when next called to get new data.
274
+
275
+ .. versionadded:: 2.0
276
+
277
+ """
278
+ self.info_cache.clear()
279
+
280
+ @classmethod
281
+ @util.deprecated(
282
+ "1.4",
283
+ "The from_engine() method on :class:`_reflection.Inspector` "
284
+ "is deprecated and "
285
+ "will be removed in a future release. Please use the "
286
+ ":func:`.sqlalchemy.inspect` "
287
+ "function on an :class:`_engine.Engine` or "
288
+ ":class:`_engine.Connection` "
289
+ "in order to "
290
+ "acquire an :class:`_reflection.Inspector`.",
291
+ )
292
+ def from_engine(cls, bind: Engine) -> Inspector:
293
+ """Construct a new dialect-specific Inspector object from the given
294
+ engine or connection.
295
+
296
+ :param bind: a :class:`~sqlalchemy.engine.Connection`
297
+ or :class:`~sqlalchemy.engine.Engine`.
298
+
299
+ This method differs from direct a direct constructor call of
300
+ :class:`_reflection.Inspector` in that the
301
+ :class:`~sqlalchemy.engine.interfaces.Dialect` is given a chance to
302
+ provide a dialect-specific :class:`_reflection.Inspector` instance,
303
+ which may
304
+ provide additional methods.
305
+
306
+ See the example at :class:`_reflection.Inspector`.
307
+
308
+ """
309
+ return cls._construct(cls._init_legacy, bind)
310
+
311
+ @inspection._inspects(Engine)
312
+ def _engine_insp(bind: Engine) -> Inspector: # type: ignore[misc]
313
+ return Inspector._construct(Inspector._init_engine, bind)
314
+
315
+ @inspection._inspects(Connection)
316
+ def _connection_insp(bind: Connection) -> Inspector: # type: ignore[misc]
317
+ return Inspector._construct(Inspector._init_connection, bind)
318
+
319
+ @contextlib.contextmanager
320
+ def _operation_context(self) -> Generator[Connection, None, None]:
321
+ """Return a context that optimizes for multiple operations on a single
322
+ transaction.
323
+
324
+ This essentially allows connect()/close() to be called if we detected
325
+ that we're against an :class:`_engine.Engine` and not a
326
+ :class:`_engine.Connection`.
327
+
328
+ """
329
+ conn: Connection
330
+ if self._op_context_requires_connect:
331
+ conn = self.bind.connect() # type: ignore[union-attr]
332
+ else:
333
+ conn = self.bind # type: ignore[assignment]
334
+ try:
335
+ yield conn
336
+ finally:
337
+ if self._op_context_requires_connect:
338
+ conn.close()
339
+
340
+ @contextlib.contextmanager
341
+ def _inspection_context(self) -> Generator[Inspector, None, None]:
342
+ """Return an :class:`_reflection.Inspector`
343
+ from this one that will run all
344
+ operations on a single connection.
345
+
346
+ """
347
+
348
+ with self._operation_context() as conn:
349
+ sub_insp = self._construct(self.__class__._init_connection, conn)
350
+ sub_insp.info_cache = self.info_cache
351
+ yield sub_insp
352
+
353
+ @property
354
+ def default_schema_name(self) -> Optional[str]:
355
+ """Return the default schema name presented by the dialect
356
+ for the current engine's database user.
357
+
358
+ E.g. this is typically ``public`` for PostgreSQL and ``dbo``
359
+ for SQL Server.
360
+
361
+ """
362
+ return self.dialect.default_schema_name
363
+
364
+ def get_schema_names(self, **kw: Any) -> List[str]:
365
+ r"""Return all schema names.
366
+
367
+ :param \**kw: Additional keyword argument to pass to the dialect
368
+ specific implementation. See the documentation of the dialect
369
+ in use for more information.
370
+ """
371
+
372
+ with self._operation_context() as conn:
373
+ return self.dialect.get_schema_names(
374
+ conn, info_cache=self.info_cache, **kw
375
+ )
376
+
377
+ def get_table_names(
378
+ self, schema: Optional[str] = None, **kw: Any
379
+ ) -> List[str]:
380
+ r"""Return all table names within a particular schema.
381
+
382
+ The names are expected to be real tables only, not views.
383
+ Views are instead returned using the
384
+ :meth:`_reflection.Inspector.get_view_names` and/or
385
+ :meth:`_reflection.Inspector.get_materialized_view_names`
386
+ methods.
387
+
388
+ :param schema: Schema name. If ``schema`` is left at ``None``, the
389
+ database's default schema is
390
+ used, else the named schema is searched. If the database does not
391
+ support named schemas, behavior is undefined if ``schema`` is not
392
+ passed as ``None``. For special quoting, use :class:`.quoted_name`.
393
+ :param \**kw: Additional keyword argument to pass to the dialect
394
+ specific implementation. See the documentation of the dialect
395
+ in use for more information.
396
+
397
+ .. seealso::
398
+
399
+ :meth:`_reflection.Inspector.get_sorted_table_and_fkc_names`
400
+
401
+ :attr:`_schema.MetaData.sorted_tables`
402
+
403
+ """
404
+
405
+ with self._operation_context() as conn:
406
+ return self.dialect.get_table_names(
407
+ conn, schema, info_cache=self.info_cache, **kw
408
+ )
409
+
410
+ def has_table(
411
+ self, table_name: str, schema: Optional[str] = None, **kw: Any
412
+ ) -> bool:
413
+ r"""Return True if the backend has a table, view, or temporary
414
+ table of the given name.
415
+
416
+ :param table_name: name of the table to check
417
+ :param schema: schema name to query, if not the default schema.
418
+ :param \**kw: Additional keyword argument to pass to the dialect
419
+ specific implementation. See the documentation of the dialect
420
+ in use for more information.
421
+
422
+ .. versionadded:: 1.4 - the :meth:`.Inspector.has_table` method
423
+ replaces the :meth:`_engine.Engine.has_table` method.
424
+
425
+ .. versionchanged:: 2.0:: :meth:`.Inspector.has_table` now formally
426
+ supports checking for additional table-like objects:
427
+
428
+ * any type of views (plain or materialized)
429
+ * temporary tables of any kind
430
+
431
+ Previously, these two checks were not formally specified and
432
+ different dialects would vary in their behavior. The dialect
433
+ testing suite now includes tests for all of these object types
434
+ and should be supported by all SQLAlchemy-included dialects.
435
+ Support among third party dialects may be lagging, however.
436
+
437
+ """
438
+ with self._operation_context() as conn:
439
+ return self.dialect.has_table(
440
+ conn, table_name, schema, info_cache=self.info_cache, **kw
441
+ )
442
+
443
+ def has_sequence(
444
+ self, sequence_name: str, schema: Optional[str] = None, **kw: Any
445
+ ) -> bool:
446
+ r"""Return True if the backend has a sequence with the given name.
447
+
448
+ :param sequence_name: name of the sequence to check
449
+ :param schema: schema name to query, if not the default schema.
450
+ :param \**kw: Additional keyword argument to pass to the dialect
451
+ specific implementation. See the documentation of the dialect
452
+ in use for more information.
453
+
454
+ .. versionadded:: 1.4
455
+
456
+ """
457
+ with self._operation_context() as conn:
458
+ return self.dialect.has_sequence(
459
+ conn, sequence_name, schema, info_cache=self.info_cache, **kw
460
+ )
461
+
462
+ def has_index(
463
+ self,
464
+ table_name: str,
465
+ index_name: str,
466
+ schema: Optional[str] = None,
467
+ **kw: Any,
468
+ ) -> bool:
469
+ r"""Check the existence of a particular index name in the database.
470
+
471
+ :param table_name: the name of the table the index belongs to
472
+ :param index_name: the name of the index to check
473
+ :param schema: schema name to query, if not the default schema.
474
+ :param \**kw: Additional keyword argument to pass to the dialect
475
+ specific implementation. See the documentation of the dialect
476
+ in use for more information.
477
+
478
+ .. versionadded:: 2.0
479
+
480
+ """
481
+ with self._operation_context() as conn:
482
+ return self.dialect.has_index(
483
+ conn,
484
+ table_name,
485
+ index_name,
486
+ schema,
487
+ info_cache=self.info_cache,
488
+ **kw,
489
+ )
490
+
491
+ def has_schema(self, schema_name: str, **kw: Any) -> bool:
492
+ r"""Return True if the backend has a schema with the given name.
493
+
494
+ :param schema_name: name of the schema to check
495
+ :param \**kw: Additional keyword argument to pass to the dialect
496
+ specific implementation. See the documentation of the dialect
497
+ in use for more information.
498
+
499
+ .. versionadded:: 2.0
500
+
501
+ """
502
+ with self._operation_context() as conn:
503
+ return self.dialect.has_schema(
504
+ conn, schema_name, info_cache=self.info_cache, **kw
505
+ )
506
+
507
+ def get_sorted_table_and_fkc_names(
508
+ self,
509
+ schema: Optional[str] = None,
510
+ **kw: Any,
511
+ ) -> List[Tuple[Optional[str], List[Tuple[str, Optional[str]]]]]:
512
+ r"""Return dependency-sorted table and foreign key constraint names in
513
+ referred to within a particular schema.
514
+
515
+ This will yield 2-tuples of
516
+ ``(tablename, [(tname, fkname), (tname, fkname), ...])``
517
+ consisting of table names in CREATE order grouped with the foreign key
518
+ constraint names that are not detected as belonging to a cycle.
519
+ The final element
520
+ will be ``(None, [(tname, fkname), (tname, fkname), ..])``
521
+ which will consist of remaining
522
+ foreign key constraint names that would require a separate CREATE
523
+ step after-the-fact, based on dependencies between tables.
524
+
525
+ :param schema: schema name to query, if not the default schema.
526
+ :param \**kw: Additional keyword argument to pass to the dialect
527
+ specific implementation. See the documentation of the dialect
528
+ in use for more information.
529
+
530
+ .. seealso::
531
+
532
+ :meth:`_reflection.Inspector.get_table_names`
533
+
534
+ :func:`.sort_tables_and_constraints` - similar method which works
535
+ with an already-given :class:`_schema.MetaData`.
536
+
537
+ """
538
+
539
+ return [
540
+ (
541
+ table_key[1] if table_key else None,
542
+ [(tname, fks) for (_, tname), fks in fk_collection],
543
+ )
544
+ for (
545
+ table_key,
546
+ fk_collection,
547
+ ) in self.sort_tables_on_foreign_key_dependency(
548
+ consider_schemas=(schema,)
549
+ )
550
+ ]
551
+
552
+ def sort_tables_on_foreign_key_dependency(
553
+ self,
554
+ consider_schemas: Collection[Optional[str]] = (None,),
555
+ **kw: Any,
556
+ ) -> List[
557
+ Tuple[
558
+ Optional[Tuple[Optional[str], str]],
559
+ List[Tuple[Tuple[Optional[str], str], Optional[str]]],
560
+ ]
561
+ ]:
562
+ r"""Return dependency-sorted table and foreign key constraint names
563
+ referred to within multiple schemas.
564
+
565
+ This method may be compared to
566
+ :meth:`.Inspector.get_sorted_table_and_fkc_names`, which
567
+ works on one schema at a time; here, the method is a generalization
568
+ that will consider multiple schemas at once including that it will
569
+ resolve for cross-schema foreign keys.
570
+
571
+ .. versionadded:: 2.0
572
+
573
+ """
574
+ SchemaTab = Tuple[Optional[str], str]
575
+
576
+ tuples: Set[Tuple[SchemaTab, SchemaTab]] = set()
577
+ remaining_fkcs: Set[Tuple[SchemaTab, Optional[str]]] = set()
578
+ fknames_for_table: Dict[SchemaTab, Set[Optional[str]]] = {}
579
+ tnames: List[SchemaTab] = []
580
+
581
+ for schname in consider_schemas:
582
+ schema_fkeys = self.get_multi_foreign_keys(schname, **kw)
583
+ tnames.extend(schema_fkeys)
584
+ for (_, tname), fkeys in schema_fkeys.items():
585
+ fknames_for_table[(schname, tname)] = {
586
+ fk["name"] for fk in fkeys
587
+ }
588
+ for fkey in fkeys:
589
+ if (
590
+ tname != fkey["referred_table"]
591
+ or schname != fkey["referred_schema"]
592
+ ):
593
+ tuples.add(
594
+ (
595
+ (
596
+ fkey["referred_schema"],
597
+ fkey["referred_table"],
598
+ ),
599
+ (schname, tname),
600
+ )
601
+ )
602
+ try:
603
+ candidate_sort = list(topological.sort(tuples, tnames))
604
+ except exc.CircularDependencyError as err:
605
+ edge: Tuple[SchemaTab, SchemaTab]
606
+ for edge in err.edges:
607
+ tuples.remove(edge)
608
+ remaining_fkcs.update(
609
+ (edge[1], fkc) for fkc in fknames_for_table[edge[1]]
610
+ )
611
+
612
+ candidate_sort = list(topological.sort(tuples, tnames))
613
+ ret: List[
614
+ Tuple[Optional[SchemaTab], List[Tuple[SchemaTab, Optional[str]]]]
615
+ ]
616
+ ret = [
617
+ (
618
+ (schname, tname),
619
+ [
620
+ ((schname, tname), fk)
621
+ for fk in fknames_for_table[(schname, tname)].difference(
622
+ name for _, name in remaining_fkcs
623
+ )
624
+ ],
625
+ )
626
+ for (schname, tname) in candidate_sort
627
+ ]
628
+ return ret + [(None, list(remaining_fkcs))]
629
+
630
+ def get_temp_table_names(self, **kw: Any) -> List[str]:
631
+ r"""Return a list of temporary table names for the current bind.
632
+
633
+ This method is unsupported by most dialects; currently
634
+ only Oracle Database, PostgreSQL and SQLite implements it.
635
+
636
+ :param \**kw: Additional keyword argument to pass to the dialect
637
+ specific implementation. See the documentation of the dialect
638
+ in use for more information.
639
+
640
+ """
641
+
642
+ with self._operation_context() as conn:
643
+ return self.dialect.get_temp_table_names(
644
+ conn, info_cache=self.info_cache, **kw
645
+ )
646
+
647
+ def get_temp_view_names(self, **kw: Any) -> List[str]:
648
+ r"""Return a list of temporary view names for the current bind.
649
+
650
+ This method is unsupported by most dialects; currently
651
+ only PostgreSQL and SQLite implements it.
652
+
653
+ :param \**kw: Additional keyword argument to pass to the dialect
654
+ specific implementation. See the documentation of the dialect
655
+ in use for more information.
656
+
657
+ """
658
+ with self._operation_context() as conn:
659
+ return self.dialect.get_temp_view_names(
660
+ conn, info_cache=self.info_cache, **kw
661
+ )
662
+
663
+ def get_table_options(
664
+ self, table_name: str, schema: Optional[str] = None, **kw: Any
665
+ ) -> Dict[str, Any]:
666
+ r"""Return a dictionary of options specified when the table of the
667
+ given name was created.
668
+
669
+ This currently includes some options that apply to MySQL and Oracle
670
+ Database tables.
671
+
672
+ :param table_name: string name of the table. For special quoting,
673
+ use :class:`.quoted_name`.
674
+
675
+ :param schema: string schema name; if omitted, uses the default schema
676
+ of the database connection. For special quoting,
677
+ use :class:`.quoted_name`.
678
+
679
+ :param \**kw: Additional keyword argument to pass to the dialect
680
+ specific implementation. See the documentation of the dialect
681
+ in use for more information.
682
+
683
+ :return: a dict with the table options. The returned keys depend on the
684
+ dialect in use. Each one is prefixed with the dialect name.
685
+
686
+ .. seealso:: :meth:`Inspector.get_multi_table_options`
687
+
688
+ """
689
+ with self._operation_context() as conn:
690
+ return self.dialect.get_table_options(
691
+ conn, table_name, schema, info_cache=self.info_cache, **kw
692
+ )
693
+
694
+ def get_multi_table_options(
695
+ self,
696
+ schema: Optional[str] = None,
697
+ filter_names: Optional[Sequence[str]] = None,
698
+ kind: ObjectKind = ObjectKind.TABLE,
699
+ scope: ObjectScope = ObjectScope.DEFAULT,
700
+ **kw: Any,
701
+ ) -> Dict[TableKey, Dict[str, Any]]:
702
+ r"""Return a dictionary of options specified when the tables in the
703
+ given schema were created.
704
+
705
+ The tables can be filtered by passing the names to use to
706
+ ``filter_names``.
707
+
708
+ This currently includes some options that apply to MySQL and Oracle
709
+ tables.
710
+
711
+ :param schema: string schema name; if omitted, uses the default schema
712
+ of the database connection. For special quoting,
713
+ use :class:`.quoted_name`.
714
+
715
+ :param filter_names: optionally return information only for the
716
+ objects listed here.
717
+
718
+ :param kind: a :class:`.ObjectKind` that specifies the type of objects
719
+ to reflect. Defaults to ``ObjectKind.TABLE``.
720
+
721
+ :param scope: a :class:`.ObjectScope` that specifies if options of
722
+ default, temporary or any tables should be reflected.
723
+ Defaults to ``ObjectScope.DEFAULT``.
724
+
725
+ :param \**kw: Additional keyword argument to pass to the dialect
726
+ specific implementation. See the documentation of the dialect
727
+ in use for more information.
728
+
729
+ :return: a dictionary where the keys are two-tuple schema,table-name
730
+ and the values are dictionaries with the table options.
731
+ The returned keys in each dict depend on the
732
+ dialect in use. Each one is prefixed with the dialect name.
733
+ The schema is ``None`` if no schema is provided.
734
+
735
+ .. versionadded:: 2.0
736
+
737
+ .. seealso:: :meth:`Inspector.get_table_options`
738
+ """
739
+ with self._operation_context() as conn:
740
+ res = self.dialect.get_multi_table_options(
741
+ conn,
742
+ schema=schema,
743
+ filter_names=filter_names,
744
+ kind=kind,
745
+ scope=scope,
746
+ info_cache=self.info_cache,
747
+ **kw,
748
+ )
749
+ return dict(res)
750
+
751
+ def get_view_names(
752
+ self, schema: Optional[str] = None, **kw: Any
753
+ ) -> List[str]:
754
+ r"""Return all non-materialized view names in `schema`.
755
+
756
+ :param schema: Optional, retrieve names from a non-default schema.
757
+ For special quoting, use :class:`.quoted_name`.
758
+ :param \**kw: Additional keyword argument to pass to the dialect
759
+ specific implementation. See the documentation of the dialect
760
+ in use for more information.
761
+
762
+
763
+ .. versionchanged:: 2.0 For those dialects that previously included
764
+ the names of materialized views in this list (currently PostgreSQL),
765
+ this method no longer returns the names of materialized views.
766
+ the :meth:`.Inspector.get_materialized_view_names` method should
767
+ be used instead.
768
+
769
+ .. seealso::
770
+
771
+ :meth:`.Inspector.get_materialized_view_names`
772
+
773
+ """
774
+
775
+ with self._operation_context() as conn:
776
+ return self.dialect.get_view_names(
777
+ conn, schema, info_cache=self.info_cache, **kw
778
+ )
779
+
780
+ def get_materialized_view_names(
781
+ self, schema: Optional[str] = None, **kw: Any
782
+ ) -> List[str]:
783
+ r"""Return all materialized view names in `schema`.
784
+
785
+ :param schema: Optional, retrieve names from a non-default schema.
786
+ For special quoting, use :class:`.quoted_name`.
787
+ :param \**kw: Additional keyword argument to pass to the dialect
788
+ specific implementation. See the documentation of the dialect
789
+ in use for more information.
790
+
791
+ .. versionadded:: 2.0
792
+
793
+ .. seealso::
794
+
795
+ :meth:`.Inspector.get_view_names`
796
+
797
+ """
798
+
799
+ with self._operation_context() as conn:
800
+ return self.dialect.get_materialized_view_names(
801
+ conn, schema, info_cache=self.info_cache, **kw
802
+ )
803
+
804
+ def get_sequence_names(
805
+ self, schema: Optional[str] = None, **kw: Any
806
+ ) -> List[str]:
807
+ r"""Return all sequence names in `schema`.
808
+
809
+ :param schema: Optional, retrieve names from a non-default schema.
810
+ For special quoting, use :class:`.quoted_name`.
811
+ :param \**kw: Additional keyword argument to pass to the dialect
812
+ specific implementation. See the documentation of the dialect
813
+ in use for more information.
814
+
815
+ """
816
+
817
+ with self._operation_context() as conn:
818
+ return self.dialect.get_sequence_names(
819
+ conn, schema, info_cache=self.info_cache, **kw
820
+ )
821
+
822
+ def get_view_definition(
823
+ self, view_name: str, schema: Optional[str] = None, **kw: Any
824
+ ) -> str:
825
+ r"""Return definition for the plain or materialized view called
826
+ ``view_name``.
827
+
828
+ :param view_name: Name of the view.
829
+ :param schema: Optional, retrieve names from a non-default schema.
830
+ For special quoting, use :class:`.quoted_name`.
831
+ :param \**kw: Additional keyword argument to pass to the dialect
832
+ specific implementation. See the documentation of the dialect
833
+ in use for more information.
834
+
835
+ """
836
+
837
+ with self._operation_context() as conn:
838
+ return self.dialect.get_view_definition(
839
+ conn, view_name, schema, info_cache=self.info_cache, **kw
840
+ )
841
+
842
+ def get_columns(
843
+ self, table_name: str, schema: Optional[str] = None, **kw: Any
844
+ ) -> List[ReflectedColumn]:
845
+ r"""Return information about columns in ``table_name``.
846
+
847
+ Given a string ``table_name`` and an optional string ``schema``,
848
+ return column information as a list of :class:`.ReflectedColumn`.
849
+
850
+ :param table_name: string name of the table. For special quoting,
851
+ use :class:`.quoted_name`.
852
+
853
+ :param schema: string schema name; if omitted, uses the default schema
854
+ of the database connection. For special quoting,
855
+ use :class:`.quoted_name`.
856
+
857
+ :param \**kw: Additional keyword argument to pass to the dialect
858
+ specific implementation. See the documentation of the dialect
859
+ in use for more information.
860
+
861
+ :return: list of dictionaries, each representing the definition of
862
+ a database column.
863
+
864
+ .. seealso:: :meth:`Inspector.get_multi_columns`.
865
+
866
+ """
867
+
868
+ with self._operation_context() as conn:
869
+ col_defs = self.dialect.get_columns(
870
+ conn, table_name, schema, info_cache=self.info_cache, **kw
871
+ )
872
+ if col_defs:
873
+ self._instantiate_types([col_defs])
874
+ return col_defs
875
+
876
+ def _instantiate_types(
877
+ self, data: Iterable[List[ReflectedColumn]]
878
+ ) -> None:
879
+ # make this easy and only return instances for coltype
880
+ for col_defs in data:
881
+ for col_def in col_defs:
882
+ coltype = col_def["type"]
883
+ if not isinstance(coltype, TypeEngine):
884
+ col_def["type"] = coltype()
885
+
886
+ def get_multi_columns(
887
+ self,
888
+ schema: Optional[str] = None,
889
+ filter_names: Optional[Sequence[str]] = None,
890
+ kind: ObjectKind = ObjectKind.TABLE,
891
+ scope: ObjectScope = ObjectScope.DEFAULT,
892
+ **kw: Any,
893
+ ) -> Dict[TableKey, List[ReflectedColumn]]:
894
+ r"""Return information about columns in all objects in the given
895
+ schema.
896
+
897
+ The objects can be filtered by passing the names to use to
898
+ ``filter_names``.
899
+
900
+ For each table the value is a list of :class:`.ReflectedColumn`.
901
+
902
+ :param schema: string schema name; if omitted, uses the default schema
903
+ of the database connection. For special quoting,
904
+ use :class:`.quoted_name`.
905
+
906
+ :param filter_names: optionally return information only for the
907
+ objects listed here.
908
+
909
+ :param kind: a :class:`.ObjectKind` that specifies the type of objects
910
+ to reflect. Defaults to ``ObjectKind.TABLE``.
911
+
912
+ :param scope: a :class:`.ObjectScope` that specifies if columns of
913
+ default, temporary or any tables should be reflected.
914
+ Defaults to ``ObjectScope.DEFAULT``.
915
+
916
+ :param \**kw: Additional keyword argument to pass to the dialect
917
+ specific implementation. See the documentation of the dialect
918
+ in use for more information.
919
+
920
+ :return: a dictionary where the keys are two-tuple schema,table-name
921
+ and the values are list of dictionaries, each representing the
922
+ definition of a database column.
923
+ The schema is ``None`` if no schema is provided.
924
+
925
+ .. versionadded:: 2.0
926
+
927
+ .. seealso:: :meth:`Inspector.get_columns`
928
+ """
929
+
930
+ with self._operation_context() as conn:
931
+ table_col_defs = dict(
932
+ self.dialect.get_multi_columns(
933
+ conn,
934
+ schema=schema,
935
+ filter_names=filter_names,
936
+ kind=kind,
937
+ scope=scope,
938
+ info_cache=self.info_cache,
939
+ **kw,
940
+ )
941
+ )
942
+ self._instantiate_types(table_col_defs.values())
943
+ return table_col_defs
944
+
945
+ def get_pk_constraint(
946
+ self, table_name: str, schema: Optional[str] = None, **kw: Any
947
+ ) -> ReflectedPrimaryKeyConstraint:
948
+ r"""Return information about primary key constraint in ``table_name``.
949
+
950
+ Given a string ``table_name``, and an optional string `schema`, return
951
+ primary key information as a :class:`.ReflectedPrimaryKeyConstraint`.
952
+
953
+ :param table_name: string name of the table. For special quoting,
954
+ use :class:`.quoted_name`.
955
+
956
+ :param schema: string schema name; if omitted, uses the default schema
957
+ of the database connection. For special quoting,
958
+ use :class:`.quoted_name`.
959
+
960
+ :param \**kw: Additional keyword argument to pass to the dialect
961
+ specific implementation. See the documentation of the dialect
962
+ in use for more information.
963
+
964
+ :return: a dictionary representing the definition of
965
+ a primary key constraint.
966
+
967
+ .. seealso:: :meth:`Inspector.get_multi_pk_constraint`
968
+ """
969
+ with self._operation_context() as conn:
970
+ return self.dialect.get_pk_constraint(
971
+ conn, table_name, schema, info_cache=self.info_cache, **kw
972
+ )
973
+
974
+ def get_multi_pk_constraint(
975
+ self,
976
+ schema: Optional[str] = None,
977
+ filter_names: Optional[Sequence[str]] = None,
978
+ kind: ObjectKind = ObjectKind.TABLE,
979
+ scope: ObjectScope = ObjectScope.DEFAULT,
980
+ **kw: Any,
981
+ ) -> Dict[TableKey, ReflectedPrimaryKeyConstraint]:
982
+ r"""Return information about primary key constraints in
983
+ all tables in the given schema.
984
+
985
+ The tables can be filtered by passing the names to use to
986
+ ``filter_names``.
987
+
988
+ For each table the value is a :class:`.ReflectedPrimaryKeyConstraint`.
989
+
990
+ :param schema: string schema name; if omitted, uses the default schema
991
+ of the database connection. For special quoting,
992
+ use :class:`.quoted_name`.
993
+
994
+ :param filter_names: optionally return information only for the
995
+ objects listed here.
996
+
997
+ :param kind: a :class:`.ObjectKind` that specifies the type of objects
998
+ to reflect. Defaults to ``ObjectKind.TABLE``.
999
+
1000
+ :param scope: a :class:`.ObjectScope` that specifies if primary keys of
1001
+ default, temporary or any tables should be reflected.
1002
+ Defaults to ``ObjectScope.DEFAULT``.
1003
+
1004
+ :param \**kw: Additional keyword argument to pass to the dialect
1005
+ specific implementation. See the documentation of the dialect
1006
+ in use for more information.
1007
+
1008
+ :return: a dictionary where the keys are two-tuple schema,table-name
1009
+ and the values are dictionaries, each representing the
1010
+ definition of a primary key constraint.
1011
+ The schema is ``None`` if no schema is provided.
1012
+
1013
+ .. versionadded:: 2.0
1014
+
1015
+ .. seealso:: :meth:`Inspector.get_pk_constraint`
1016
+ """
1017
+ with self._operation_context() as conn:
1018
+ return dict(
1019
+ self.dialect.get_multi_pk_constraint(
1020
+ conn,
1021
+ schema=schema,
1022
+ filter_names=filter_names,
1023
+ kind=kind,
1024
+ scope=scope,
1025
+ info_cache=self.info_cache,
1026
+ **kw,
1027
+ )
1028
+ )
1029
+
1030
+ def get_foreign_keys(
1031
+ self, table_name: str, schema: Optional[str] = None, **kw: Any
1032
+ ) -> List[ReflectedForeignKeyConstraint]:
1033
+ r"""Return information about foreign_keys in ``table_name``.
1034
+
1035
+ Given a string ``table_name``, and an optional string `schema`, return
1036
+ foreign key information as a list of
1037
+ :class:`.ReflectedForeignKeyConstraint`.
1038
+
1039
+ :param table_name: string name of the table. For special quoting,
1040
+ use :class:`.quoted_name`.
1041
+
1042
+ :param schema: string schema name; if omitted, uses the default schema
1043
+ of the database connection. For special quoting,
1044
+ use :class:`.quoted_name`.
1045
+
1046
+ :param \**kw: Additional keyword argument to pass to the dialect
1047
+ specific implementation. See the documentation of the dialect
1048
+ in use for more information.
1049
+
1050
+ :return: a list of dictionaries, each representing the
1051
+ a foreign key definition.
1052
+
1053
+ .. seealso:: :meth:`Inspector.get_multi_foreign_keys`
1054
+ """
1055
+
1056
+ with self._operation_context() as conn:
1057
+ return self.dialect.get_foreign_keys(
1058
+ conn, table_name, schema, info_cache=self.info_cache, **kw
1059
+ )
1060
+
1061
+ def get_multi_foreign_keys(
1062
+ self,
1063
+ schema: Optional[str] = None,
1064
+ filter_names: Optional[Sequence[str]] = None,
1065
+ kind: ObjectKind = ObjectKind.TABLE,
1066
+ scope: ObjectScope = ObjectScope.DEFAULT,
1067
+ **kw: Any,
1068
+ ) -> Dict[TableKey, List[ReflectedForeignKeyConstraint]]:
1069
+ r"""Return information about foreign_keys in all tables
1070
+ in the given schema.
1071
+
1072
+ The tables can be filtered by passing the names to use to
1073
+ ``filter_names``.
1074
+
1075
+ For each table the value is a list of
1076
+ :class:`.ReflectedForeignKeyConstraint`.
1077
+
1078
+ :param schema: string schema name; if omitted, uses the default schema
1079
+ of the database connection. For special quoting,
1080
+ use :class:`.quoted_name`.
1081
+
1082
+ :param filter_names: optionally return information only for the
1083
+ objects listed here.
1084
+
1085
+ :param kind: a :class:`.ObjectKind` that specifies the type of objects
1086
+ to reflect. Defaults to ``ObjectKind.TABLE``.
1087
+
1088
+ :param scope: a :class:`.ObjectScope` that specifies if foreign keys of
1089
+ default, temporary or any tables should be reflected.
1090
+ Defaults to ``ObjectScope.DEFAULT``.
1091
+
1092
+ :param \**kw: Additional keyword argument to pass to the dialect
1093
+ specific implementation. See the documentation of the dialect
1094
+ in use for more information.
1095
+
1096
+ :return: a dictionary where the keys are two-tuple schema,table-name
1097
+ and the values are list of dictionaries, each representing
1098
+ a foreign key definition.
1099
+ The schema is ``None`` if no schema is provided.
1100
+
1101
+ .. versionadded:: 2.0
1102
+
1103
+ .. seealso:: :meth:`Inspector.get_foreign_keys`
1104
+ """
1105
+
1106
+ with self._operation_context() as conn:
1107
+ return dict(
1108
+ self.dialect.get_multi_foreign_keys(
1109
+ conn,
1110
+ schema=schema,
1111
+ filter_names=filter_names,
1112
+ kind=kind,
1113
+ scope=scope,
1114
+ info_cache=self.info_cache,
1115
+ **kw,
1116
+ )
1117
+ )
1118
+
1119
+ def get_indexes(
1120
+ self, table_name: str, schema: Optional[str] = None, **kw: Any
1121
+ ) -> List[ReflectedIndex]:
1122
+ r"""Return information about indexes in ``table_name``.
1123
+
1124
+ Given a string ``table_name`` and an optional string `schema`, return
1125
+ index information as a list of :class:`.ReflectedIndex`.
1126
+
1127
+ :param table_name: string name of the table. For special quoting,
1128
+ use :class:`.quoted_name`.
1129
+
1130
+ :param schema: string schema name; if omitted, uses the default schema
1131
+ of the database connection. For special quoting,
1132
+ use :class:`.quoted_name`.
1133
+
1134
+ :param \**kw: Additional keyword argument to pass to the dialect
1135
+ specific implementation. See the documentation of the dialect
1136
+ in use for more information.
1137
+
1138
+ :return: a list of dictionaries, each representing the
1139
+ definition of an index.
1140
+
1141
+ .. seealso:: :meth:`Inspector.get_multi_indexes`
1142
+ """
1143
+
1144
+ with self._operation_context() as conn:
1145
+ return self.dialect.get_indexes(
1146
+ conn, table_name, schema, info_cache=self.info_cache, **kw
1147
+ )
1148
+
1149
+ def get_multi_indexes(
1150
+ self,
1151
+ schema: Optional[str] = None,
1152
+ filter_names: Optional[Sequence[str]] = None,
1153
+ kind: ObjectKind = ObjectKind.TABLE,
1154
+ scope: ObjectScope = ObjectScope.DEFAULT,
1155
+ **kw: Any,
1156
+ ) -> Dict[TableKey, List[ReflectedIndex]]:
1157
+ r"""Return information about indexes in in all objects
1158
+ in the given schema.
1159
+
1160
+ The objects can be filtered by passing the names to use to
1161
+ ``filter_names``.
1162
+
1163
+ For each table the value is a list of :class:`.ReflectedIndex`.
1164
+
1165
+ :param schema: string schema name; if omitted, uses the default schema
1166
+ of the database connection. For special quoting,
1167
+ use :class:`.quoted_name`.
1168
+
1169
+ :param filter_names: optionally return information only for the
1170
+ objects listed here.
1171
+
1172
+ :param kind: a :class:`.ObjectKind` that specifies the type of objects
1173
+ to reflect. Defaults to ``ObjectKind.TABLE``.
1174
+
1175
+ :param scope: a :class:`.ObjectScope` that specifies if indexes of
1176
+ default, temporary or any tables should be reflected.
1177
+ Defaults to ``ObjectScope.DEFAULT``.
1178
+
1179
+ :param \**kw: Additional keyword argument to pass to the dialect
1180
+ specific implementation. See the documentation of the dialect
1181
+ in use for more information.
1182
+
1183
+ :return: a dictionary where the keys are two-tuple schema,table-name
1184
+ and the values are list of dictionaries, each representing the
1185
+ definition of an index.
1186
+ The schema is ``None`` if no schema is provided.
1187
+
1188
+ .. versionadded:: 2.0
1189
+
1190
+ .. seealso:: :meth:`Inspector.get_indexes`
1191
+ """
1192
+
1193
+ with self._operation_context() as conn:
1194
+ return dict(
1195
+ self.dialect.get_multi_indexes(
1196
+ conn,
1197
+ schema=schema,
1198
+ filter_names=filter_names,
1199
+ kind=kind,
1200
+ scope=scope,
1201
+ info_cache=self.info_cache,
1202
+ **kw,
1203
+ )
1204
+ )
1205
+
1206
+ def get_unique_constraints(
1207
+ self, table_name: str, schema: Optional[str] = None, **kw: Any
1208
+ ) -> List[ReflectedUniqueConstraint]:
1209
+ r"""Return information about unique constraints in ``table_name``.
1210
+
1211
+ Given a string ``table_name`` and an optional string `schema`, return
1212
+ unique constraint information as a list of
1213
+ :class:`.ReflectedUniqueConstraint`.
1214
+
1215
+ :param table_name: string name of the table. For special quoting,
1216
+ use :class:`.quoted_name`.
1217
+
1218
+ :param schema: string schema name; if omitted, uses the default schema
1219
+ of the database connection. For special quoting,
1220
+ use :class:`.quoted_name`.
1221
+
1222
+ :param \**kw: Additional keyword argument to pass to the dialect
1223
+ specific implementation. See the documentation of the dialect
1224
+ in use for more information.
1225
+
1226
+ :return: a list of dictionaries, each representing the
1227
+ definition of an unique constraint.
1228
+
1229
+ .. seealso:: :meth:`Inspector.get_multi_unique_constraints`
1230
+ """
1231
+
1232
+ with self._operation_context() as conn:
1233
+ return self.dialect.get_unique_constraints(
1234
+ conn, table_name, schema, info_cache=self.info_cache, **kw
1235
+ )
1236
+
1237
+ def get_multi_unique_constraints(
1238
+ self,
1239
+ schema: Optional[str] = None,
1240
+ filter_names: Optional[Sequence[str]] = None,
1241
+ kind: ObjectKind = ObjectKind.TABLE,
1242
+ scope: ObjectScope = ObjectScope.DEFAULT,
1243
+ **kw: Any,
1244
+ ) -> Dict[TableKey, List[ReflectedUniqueConstraint]]:
1245
+ r"""Return information about unique constraints in all tables
1246
+ in the given schema.
1247
+
1248
+ The tables can be filtered by passing the names to use to
1249
+ ``filter_names``.
1250
+
1251
+ For each table the value is a list of
1252
+ :class:`.ReflectedUniqueConstraint`.
1253
+
1254
+ :param schema: string schema name; if omitted, uses the default schema
1255
+ of the database connection. For special quoting,
1256
+ use :class:`.quoted_name`.
1257
+
1258
+ :param filter_names: optionally return information only for the
1259
+ objects listed here.
1260
+
1261
+ :param kind: a :class:`.ObjectKind` that specifies the type of objects
1262
+ to reflect. Defaults to ``ObjectKind.TABLE``.
1263
+
1264
+ :param scope: a :class:`.ObjectScope` that specifies if constraints of
1265
+ default, temporary or any tables should be reflected.
1266
+ Defaults to ``ObjectScope.DEFAULT``.
1267
+
1268
+ :param \**kw: Additional keyword argument to pass to the dialect
1269
+ specific implementation. See the documentation of the dialect
1270
+ in use for more information.
1271
+
1272
+ :return: a dictionary where the keys are two-tuple schema,table-name
1273
+ and the values are list of dictionaries, each representing the
1274
+ definition of an unique constraint.
1275
+ The schema is ``None`` if no schema is provided.
1276
+
1277
+ .. versionadded:: 2.0
1278
+
1279
+ .. seealso:: :meth:`Inspector.get_unique_constraints`
1280
+ """
1281
+
1282
+ with self._operation_context() as conn:
1283
+ return dict(
1284
+ self.dialect.get_multi_unique_constraints(
1285
+ conn,
1286
+ schema=schema,
1287
+ filter_names=filter_names,
1288
+ kind=kind,
1289
+ scope=scope,
1290
+ info_cache=self.info_cache,
1291
+ **kw,
1292
+ )
1293
+ )
1294
+
1295
+ def get_table_comment(
1296
+ self, table_name: str, schema: Optional[str] = None, **kw: Any
1297
+ ) -> ReflectedTableComment:
1298
+ r"""Return information about the table comment for ``table_name``.
1299
+
1300
+ Given a string ``table_name`` and an optional string ``schema``,
1301
+ return table comment information as a :class:`.ReflectedTableComment`.
1302
+
1303
+ Raises ``NotImplementedError`` for a dialect that does not support
1304
+ comments.
1305
+
1306
+ :param table_name: string name of the table. For special quoting,
1307
+ use :class:`.quoted_name`.
1308
+
1309
+ :param schema: string schema name; if omitted, uses the default schema
1310
+ of the database connection. For special quoting,
1311
+ use :class:`.quoted_name`.
1312
+
1313
+ :param \**kw: Additional keyword argument to pass to the dialect
1314
+ specific implementation. See the documentation of the dialect
1315
+ in use for more information.
1316
+
1317
+ :return: a dictionary, with the table comment.
1318
+
1319
+ .. seealso:: :meth:`Inspector.get_multi_table_comment`
1320
+ """
1321
+
1322
+ with self._operation_context() as conn:
1323
+ return self.dialect.get_table_comment(
1324
+ conn, table_name, schema, info_cache=self.info_cache, **kw
1325
+ )
1326
+
1327
+ def get_multi_table_comment(
1328
+ self,
1329
+ schema: Optional[str] = None,
1330
+ filter_names: Optional[Sequence[str]] = None,
1331
+ kind: ObjectKind = ObjectKind.TABLE,
1332
+ scope: ObjectScope = ObjectScope.DEFAULT,
1333
+ **kw: Any,
1334
+ ) -> Dict[TableKey, ReflectedTableComment]:
1335
+ r"""Return information about the table comment in all objects
1336
+ in the given schema.
1337
+
1338
+ The objects can be filtered by passing the names to use to
1339
+ ``filter_names``.
1340
+
1341
+ For each table the value is a :class:`.ReflectedTableComment`.
1342
+
1343
+ Raises ``NotImplementedError`` for a dialect that does not support
1344
+ comments.
1345
+
1346
+ :param schema: string schema name; if omitted, uses the default schema
1347
+ of the database connection. For special quoting,
1348
+ use :class:`.quoted_name`.
1349
+
1350
+ :param filter_names: optionally return information only for the
1351
+ objects listed here.
1352
+
1353
+ :param kind: a :class:`.ObjectKind` that specifies the type of objects
1354
+ to reflect. Defaults to ``ObjectKind.TABLE``.
1355
+
1356
+ :param scope: a :class:`.ObjectScope` that specifies if comments of
1357
+ default, temporary or any tables should be reflected.
1358
+ Defaults to ``ObjectScope.DEFAULT``.
1359
+
1360
+ :param \**kw: Additional keyword argument to pass to the dialect
1361
+ specific implementation. See the documentation of the dialect
1362
+ in use for more information.
1363
+
1364
+ :return: a dictionary where the keys are two-tuple schema,table-name
1365
+ and the values are dictionaries, representing the
1366
+ table comments.
1367
+ The schema is ``None`` if no schema is provided.
1368
+
1369
+ .. versionadded:: 2.0
1370
+
1371
+ .. seealso:: :meth:`Inspector.get_table_comment`
1372
+ """
1373
+
1374
+ with self._operation_context() as conn:
1375
+ return dict(
1376
+ self.dialect.get_multi_table_comment(
1377
+ conn,
1378
+ schema=schema,
1379
+ filter_names=filter_names,
1380
+ kind=kind,
1381
+ scope=scope,
1382
+ info_cache=self.info_cache,
1383
+ **kw,
1384
+ )
1385
+ )
1386
+
1387
+ def get_check_constraints(
1388
+ self, table_name: str, schema: Optional[str] = None, **kw: Any
1389
+ ) -> List[ReflectedCheckConstraint]:
1390
+ r"""Return information about check constraints in ``table_name``.
1391
+
1392
+ Given a string ``table_name`` and an optional string `schema`, return
1393
+ check constraint information as a list of
1394
+ :class:`.ReflectedCheckConstraint`.
1395
+
1396
+ :param table_name: string name of the table. For special quoting,
1397
+ use :class:`.quoted_name`.
1398
+
1399
+ :param schema: string schema name; if omitted, uses the default schema
1400
+ of the database connection. For special quoting,
1401
+ use :class:`.quoted_name`.
1402
+
1403
+ :param \**kw: Additional keyword argument to pass to the dialect
1404
+ specific implementation. See the documentation of the dialect
1405
+ in use for more information.
1406
+
1407
+ :return: a list of dictionaries, each representing the
1408
+ definition of a check constraints.
1409
+
1410
+ .. seealso:: :meth:`Inspector.get_multi_check_constraints`
1411
+ """
1412
+
1413
+ with self._operation_context() as conn:
1414
+ return self.dialect.get_check_constraints(
1415
+ conn, table_name, schema, info_cache=self.info_cache, **kw
1416
+ )
1417
+
1418
+ def get_multi_check_constraints(
1419
+ self,
1420
+ schema: Optional[str] = None,
1421
+ filter_names: Optional[Sequence[str]] = None,
1422
+ kind: ObjectKind = ObjectKind.TABLE,
1423
+ scope: ObjectScope = ObjectScope.DEFAULT,
1424
+ **kw: Any,
1425
+ ) -> Dict[TableKey, List[ReflectedCheckConstraint]]:
1426
+ r"""Return information about check constraints in all tables
1427
+ in the given schema.
1428
+
1429
+ The tables can be filtered by passing the names to use to
1430
+ ``filter_names``.
1431
+
1432
+ For each table the value is a list of
1433
+ :class:`.ReflectedCheckConstraint`.
1434
+
1435
+ :param schema: string schema name; if omitted, uses the default schema
1436
+ of the database connection. For special quoting,
1437
+ use :class:`.quoted_name`.
1438
+
1439
+ :param filter_names: optionally return information only for the
1440
+ objects listed here.
1441
+
1442
+ :param kind: a :class:`.ObjectKind` that specifies the type of objects
1443
+ to reflect. Defaults to ``ObjectKind.TABLE``.
1444
+
1445
+ :param scope: a :class:`.ObjectScope` that specifies if constraints of
1446
+ default, temporary or any tables should be reflected.
1447
+ Defaults to ``ObjectScope.DEFAULT``.
1448
+
1449
+ :param \**kw: Additional keyword argument to pass to the dialect
1450
+ specific implementation. See the documentation of the dialect
1451
+ in use for more information.
1452
+
1453
+ :return: a dictionary where the keys are two-tuple schema,table-name
1454
+ and the values are list of dictionaries, each representing the
1455
+ definition of a check constraints.
1456
+ The schema is ``None`` if no schema is provided.
1457
+
1458
+ .. versionadded:: 2.0
1459
+
1460
+ .. seealso:: :meth:`Inspector.get_check_constraints`
1461
+ """
1462
+
1463
+ with self._operation_context() as conn:
1464
+ return dict(
1465
+ self.dialect.get_multi_check_constraints(
1466
+ conn,
1467
+ schema=schema,
1468
+ filter_names=filter_names,
1469
+ kind=kind,
1470
+ scope=scope,
1471
+ info_cache=self.info_cache,
1472
+ **kw,
1473
+ )
1474
+ )
1475
+
1476
+ def reflect_table(
1477
+ self,
1478
+ table: sa_schema.Table,
1479
+ include_columns: Optional[Collection[str]],
1480
+ exclude_columns: Collection[str] = (),
1481
+ resolve_fks: bool = True,
1482
+ _extend_on: Optional[Set[sa_schema.Table]] = None,
1483
+ _reflect_info: Optional[_ReflectionInfo] = None,
1484
+ ) -> None:
1485
+ """Given a :class:`_schema.Table` object, load its internal
1486
+ constructs based on introspection.
1487
+
1488
+ This is the underlying method used by most dialects to produce
1489
+ table reflection. Direct usage is like::
1490
+
1491
+ from sqlalchemy import create_engine, MetaData, Table
1492
+ from sqlalchemy import inspect
1493
+
1494
+ engine = create_engine("...")
1495
+ meta = MetaData()
1496
+ user_table = Table("user", meta)
1497
+ insp = inspect(engine)
1498
+ insp.reflect_table(user_table, None)
1499
+
1500
+ .. versionchanged:: 1.4 Renamed from ``reflecttable`` to
1501
+ ``reflect_table``
1502
+
1503
+ :param table: a :class:`~sqlalchemy.schema.Table` instance.
1504
+ :param include_columns: a list of string column names to include
1505
+ in the reflection process. If ``None``, all columns are reflected.
1506
+
1507
+ """
1508
+
1509
+ if _extend_on is not None:
1510
+ if table in _extend_on:
1511
+ return
1512
+ else:
1513
+ _extend_on.add(table)
1514
+
1515
+ dialect = self.bind.dialect
1516
+
1517
+ with self._operation_context() as conn:
1518
+ schema = conn.schema_for_object(table)
1519
+
1520
+ table_name = table.name
1521
+
1522
+ # get table-level arguments that are specifically
1523
+ # intended for reflection, e.g. oracle_resolve_synonyms.
1524
+ # these are unconditionally passed to related Table
1525
+ # objects
1526
+ reflection_options = {
1527
+ k: table.dialect_kwargs.get(k)
1528
+ for k in dialect.reflection_options
1529
+ if k in table.dialect_kwargs
1530
+ }
1531
+
1532
+ table_key = (schema, table_name)
1533
+ if _reflect_info is None or table_key not in _reflect_info.columns:
1534
+ _reflect_info = self._get_reflection_info(
1535
+ schema,
1536
+ filter_names=[table_name],
1537
+ kind=ObjectKind.ANY,
1538
+ scope=ObjectScope.ANY,
1539
+ _reflect_info=_reflect_info,
1540
+ **table.dialect_kwargs,
1541
+ )
1542
+ if table_key in _reflect_info.unreflectable:
1543
+ raise _reflect_info.unreflectable[table_key]
1544
+
1545
+ if table_key not in _reflect_info.columns:
1546
+ raise exc.NoSuchTableError(table_name)
1547
+
1548
+ # reflect table options, like mysql_engine
1549
+ if _reflect_info.table_options:
1550
+ tbl_opts = _reflect_info.table_options.get(table_key)
1551
+ if tbl_opts:
1552
+ # add additional kwargs to the Table if the dialect
1553
+ # returned them
1554
+ table._validate_dialect_kwargs(tbl_opts)
1555
+
1556
+ found_table = False
1557
+ cols_by_orig_name: Dict[str, sa_schema.Column[Any]] = {}
1558
+
1559
+ for col_d in _reflect_info.columns[table_key]:
1560
+ found_table = True
1561
+
1562
+ self._reflect_column(
1563
+ table,
1564
+ col_d,
1565
+ include_columns,
1566
+ exclude_columns,
1567
+ cols_by_orig_name,
1568
+ )
1569
+
1570
+ # NOTE: support tables/views with no columns
1571
+ if not found_table and not self.has_table(table_name, schema):
1572
+ raise exc.NoSuchTableError(table_name)
1573
+
1574
+ self._reflect_pk(
1575
+ _reflect_info, table_key, table, cols_by_orig_name, exclude_columns
1576
+ )
1577
+
1578
+ self._reflect_fk(
1579
+ _reflect_info,
1580
+ table_key,
1581
+ table,
1582
+ cols_by_orig_name,
1583
+ include_columns,
1584
+ exclude_columns,
1585
+ resolve_fks,
1586
+ _extend_on,
1587
+ reflection_options,
1588
+ )
1589
+
1590
+ self._reflect_indexes(
1591
+ _reflect_info,
1592
+ table_key,
1593
+ table,
1594
+ cols_by_orig_name,
1595
+ include_columns,
1596
+ exclude_columns,
1597
+ reflection_options,
1598
+ )
1599
+
1600
+ self._reflect_unique_constraints(
1601
+ _reflect_info,
1602
+ table_key,
1603
+ table,
1604
+ cols_by_orig_name,
1605
+ include_columns,
1606
+ exclude_columns,
1607
+ reflection_options,
1608
+ )
1609
+
1610
+ self._reflect_check_constraints(
1611
+ _reflect_info,
1612
+ table_key,
1613
+ table,
1614
+ cols_by_orig_name,
1615
+ include_columns,
1616
+ exclude_columns,
1617
+ reflection_options,
1618
+ )
1619
+
1620
+ self._reflect_table_comment(
1621
+ _reflect_info,
1622
+ table_key,
1623
+ table,
1624
+ reflection_options,
1625
+ )
1626
+
1627
+ def _reflect_column(
1628
+ self,
1629
+ table: sa_schema.Table,
1630
+ col_d: ReflectedColumn,
1631
+ include_columns: Optional[Collection[str]],
1632
+ exclude_columns: Collection[str],
1633
+ cols_by_orig_name: Dict[str, sa_schema.Column[Any]],
1634
+ ) -> None:
1635
+ orig_name = col_d["name"]
1636
+
1637
+ table.metadata.dispatch.column_reflect(self, table, col_d)
1638
+ table.dispatch.column_reflect(self, table, col_d)
1639
+
1640
+ # fetch name again as column_reflect is allowed to
1641
+ # change it
1642
+ name = col_d["name"]
1643
+ if (include_columns and name not in include_columns) or (
1644
+ exclude_columns and name in exclude_columns
1645
+ ):
1646
+ return
1647
+
1648
+ coltype = col_d["type"]
1649
+
1650
+ col_kw = {
1651
+ k: col_d[k] # type: ignore[literal-required]
1652
+ for k in [
1653
+ "nullable",
1654
+ "autoincrement",
1655
+ "quote",
1656
+ "info",
1657
+ "key",
1658
+ "comment",
1659
+ ]
1660
+ if k in col_d
1661
+ }
1662
+
1663
+ if "dialect_options" in col_d:
1664
+ col_kw.update(col_d["dialect_options"])
1665
+
1666
+ colargs = []
1667
+ default: Any
1668
+ if col_d.get("default") is not None:
1669
+ default_text = col_d["default"]
1670
+ assert default_text is not None
1671
+ if isinstance(default_text, TextClause):
1672
+ default = sa_schema.DefaultClause(
1673
+ default_text, _reflected=True
1674
+ )
1675
+ elif not isinstance(default_text, sa_schema.FetchedValue):
1676
+ default = sa_schema.DefaultClause(
1677
+ sql.text(default_text), _reflected=True
1678
+ )
1679
+ else:
1680
+ default = default_text
1681
+ colargs.append(default)
1682
+
1683
+ if "computed" in col_d:
1684
+ computed = sa_schema.Computed(**col_d["computed"])
1685
+ colargs.append(computed)
1686
+
1687
+ if "identity" in col_d:
1688
+ identity = sa_schema.Identity(**col_d["identity"])
1689
+ colargs.append(identity)
1690
+
1691
+ cols_by_orig_name[orig_name] = col = sa_schema.Column(
1692
+ name, coltype, *colargs, **col_kw
1693
+ )
1694
+
1695
+ if col.key in table.primary_key:
1696
+ col.primary_key = True
1697
+ table.append_column(col, replace_existing=True)
1698
+
1699
+ def _reflect_pk(
1700
+ self,
1701
+ _reflect_info: _ReflectionInfo,
1702
+ table_key: TableKey,
1703
+ table: sa_schema.Table,
1704
+ cols_by_orig_name: Dict[str, sa_schema.Column[Any]],
1705
+ exclude_columns: Collection[str],
1706
+ ) -> None:
1707
+ pk_cons = _reflect_info.pk_constraint.get(table_key)
1708
+ if pk_cons:
1709
+ pk_cols = [
1710
+ cols_by_orig_name[pk]
1711
+ for pk in pk_cons["constrained_columns"]
1712
+ if pk in cols_by_orig_name and pk not in exclude_columns
1713
+ ]
1714
+
1715
+ # update pk constraint name, comment and dialect_kwargs
1716
+ table.primary_key.name = pk_cons.get("name")
1717
+ table.primary_key.comment = pk_cons.get("comment", None)
1718
+ dialect_options = pk_cons.get("dialect_options")
1719
+ if dialect_options:
1720
+ table.primary_key.dialect_kwargs.update(dialect_options)
1721
+
1722
+ # tell the PKConstraint to re-initialize
1723
+ # its column collection
1724
+ table.primary_key._reload(pk_cols)
1725
+
1726
+ def _reflect_fk(
1727
+ self,
1728
+ _reflect_info: _ReflectionInfo,
1729
+ table_key: TableKey,
1730
+ table: sa_schema.Table,
1731
+ cols_by_orig_name: Dict[str, sa_schema.Column[Any]],
1732
+ include_columns: Optional[Collection[str]],
1733
+ exclude_columns: Collection[str],
1734
+ resolve_fks: bool,
1735
+ _extend_on: Optional[Set[sa_schema.Table]],
1736
+ reflection_options: Dict[str, Any],
1737
+ ) -> None:
1738
+ fkeys = _reflect_info.foreign_keys.get(table_key, [])
1739
+ for fkey_d in fkeys:
1740
+ conname = fkey_d["name"]
1741
+ # look for columns by orig name in cols_by_orig_name,
1742
+ # but support columns that are in-Python only as fallback
1743
+ constrained_columns = [
1744
+ cols_by_orig_name[c].key if c in cols_by_orig_name else c
1745
+ for c in fkey_d["constrained_columns"]
1746
+ ]
1747
+
1748
+ if (
1749
+ exclude_columns
1750
+ and set(constrained_columns).intersection(exclude_columns)
1751
+ or (
1752
+ include_columns
1753
+ and set(constrained_columns).difference(include_columns)
1754
+ )
1755
+ ):
1756
+ continue
1757
+
1758
+ referred_schema = fkey_d["referred_schema"]
1759
+ referred_table = fkey_d["referred_table"]
1760
+ referred_columns = fkey_d["referred_columns"]
1761
+ refspec = []
1762
+ if referred_schema is not None:
1763
+ if resolve_fks:
1764
+ sa_schema.Table(
1765
+ referred_table,
1766
+ table.metadata,
1767
+ schema=referred_schema,
1768
+ autoload_with=self.bind,
1769
+ _extend_on=_extend_on,
1770
+ _reflect_info=_reflect_info,
1771
+ **reflection_options,
1772
+ )
1773
+ for column in referred_columns:
1774
+ refspec.append(
1775
+ ".".join([referred_schema, referred_table, column])
1776
+ )
1777
+ else:
1778
+ if resolve_fks:
1779
+ sa_schema.Table(
1780
+ referred_table,
1781
+ table.metadata,
1782
+ autoload_with=self.bind,
1783
+ schema=sa_schema.BLANK_SCHEMA,
1784
+ _extend_on=_extend_on,
1785
+ _reflect_info=_reflect_info,
1786
+ **reflection_options,
1787
+ )
1788
+ for column in referred_columns:
1789
+ refspec.append(".".join([referred_table, column]))
1790
+ if "options" in fkey_d:
1791
+ options = fkey_d["options"]
1792
+ else:
1793
+ options = {}
1794
+
1795
+ try:
1796
+ table.append_constraint(
1797
+ sa_schema.ForeignKeyConstraint(
1798
+ constrained_columns,
1799
+ refspec,
1800
+ conname,
1801
+ link_to_name=True,
1802
+ comment=fkey_d.get("comment"),
1803
+ **options,
1804
+ )
1805
+ )
1806
+ except exc.ConstraintColumnNotFoundError:
1807
+ util.warn(
1808
+ f"On reflected table {table.name}, skipping reflection of "
1809
+ "foreign key constraint "
1810
+ f"{conname}; one or more subject columns within "
1811
+ f"name(s) {', '.join(constrained_columns)} are not "
1812
+ "present in the table"
1813
+ )
1814
+
1815
+ _index_sort_exprs = {
1816
+ "asc": operators.asc_op,
1817
+ "desc": operators.desc_op,
1818
+ "nulls_first": operators.nulls_first_op,
1819
+ "nulls_last": operators.nulls_last_op,
1820
+ }
1821
+
1822
+ def _reflect_indexes(
1823
+ self,
1824
+ _reflect_info: _ReflectionInfo,
1825
+ table_key: TableKey,
1826
+ table: sa_schema.Table,
1827
+ cols_by_orig_name: Dict[str, sa_schema.Column[Any]],
1828
+ include_columns: Optional[Collection[str]],
1829
+ exclude_columns: Collection[str],
1830
+ reflection_options: Dict[str, Any],
1831
+ ) -> None:
1832
+ # Indexes
1833
+ indexes = _reflect_info.indexes.get(table_key, [])
1834
+ for index_d in indexes:
1835
+ name = index_d["name"]
1836
+ columns = index_d["column_names"]
1837
+ expressions = index_d.get("expressions")
1838
+ column_sorting = index_d.get("column_sorting", {})
1839
+ unique = index_d["unique"]
1840
+ flavor = index_d.get("type", "index")
1841
+ dialect_options = index_d.get("dialect_options", {})
1842
+
1843
+ duplicates = index_d.get("duplicates_constraint")
1844
+ if include_columns and not set(columns).issubset(include_columns):
1845
+ continue
1846
+ if duplicates:
1847
+ continue
1848
+ # look for columns by orig name in cols_by_orig_name,
1849
+ # but support columns that are in-Python only as fallback
1850
+ idx_element: Any
1851
+ idx_elements = []
1852
+ for index, c in enumerate(columns):
1853
+ if c is None:
1854
+ if not expressions:
1855
+ util.warn(
1856
+ f"Skipping {flavor} {name!r} because key "
1857
+ f"{index + 1} reflected as None but no "
1858
+ "'expressions' were returned"
1859
+ )
1860
+ break
1861
+ idx_element = sql.text(expressions[index])
1862
+ else:
1863
+ try:
1864
+ if c in cols_by_orig_name:
1865
+ idx_element = cols_by_orig_name[c]
1866
+ else:
1867
+ idx_element = table.c[c]
1868
+ except KeyError:
1869
+ util.warn(
1870
+ f"{flavor} key {c!r} was not located in "
1871
+ f"columns for table {table.name!r}"
1872
+ )
1873
+ continue
1874
+ for option in column_sorting.get(c, ()):
1875
+ if option in self._index_sort_exprs:
1876
+ op = self._index_sort_exprs[option]
1877
+ idx_element = op(idx_element)
1878
+ idx_elements.append(idx_element)
1879
+ else:
1880
+ sa_schema.Index(
1881
+ name,
1882
+ *idx_elements,
1883
+ _table=table,
1884
+ unique=unique,
1885
+ **dialect_options,
1886
+ )
1887
+
1888
+ def _reflect_unique_constraints(
1889
+ self,
1890
+ _reflect_info: _ReflectionInfo,
1891
+ table_key: TableKey,
1892
+ table: sa_schema.Table,
1893
+ cols_by_orig_name: Dict[str, sa_schema.Column[Any]],
1894
+ include_columns: Optional[Collection[str]],
1895
+ exclude_columns: Collection[str],
1896
+ reflection_options: Dict[str, Any],
1897
+ ) -> None:
1898
+ constraints = _reflect_info.unique_constraints.get(table_key, [])
1899
+ # Unique Constraints
1900
+ for const_d in constraints:
1901
+ conname = const_d["name"]
1902
+ columns = const_d["column_names"]
1903
+ comment = const_d.get("comment")
1904
+ duplicates = const_d.get("duplicates_index")
1905
+ dialect_options = const_d.get("dialect_options", {})
1906
+ if include_columns and not set(columns).issubset(include_columns):
1907
+ continue
1908
+ if duplicates:
1909
+ continue
1910
+ # look for columns by orig name in cols_by_orig_name,
1911
+ # but support columns that are in-Python only as fallback
1912
+ constrained_cols = []
1913
+ for c in columns:
1914
+ try:
1915
+ constrained_col = (
1916
+ cols_by_orig_name[c]
1917
+ if c in cols_by_orig_name
1918
+ else table.c[c]
1919
+ )
1920
+ except KeyError:
1921
+ util.warn(
1922
+ "unique constraint key '%s' was not located in "
1923
+ "columns for table '%s'" % (c, table.name)
1924
+ )
1925
+ else:
1926
+ constrained_cols.append(constrained_col)
1927
+ table.append_constraint(
1928
+ sa_schema.UniqueConstraint(
1929
+ *constrained_cols,
1930
+ name=conname,
1931
+ comment=comment,
1932
+ **dialect_options,
1933
+ )
1934
+ )
1935
+
1936
+ def _reflect_check_constraints(
1937
+ self,
1938
+ _reflect_info: _ReflectionInfo,
1939
+ table_key: TableKey,
1940
+ table: sa_schema.Table,
1941
+ cols_by_orig_name: Dict[str, sa_schema.Column[Any]],
1942
+ include_columns: Optional[Collection[str]],
1943
+ exclude_columns: Collection[str],
1944
+ reflection_options: Dict[str, Any],
1945
+ ) -> None:
1946
+ constraints = _reflect_info.check_constraints.get(table_key, [])
1947
+ for const_d in constraints:
1948
+ table.append_constraint(sa_schema.CheckConstraint(**const_d))
1949
+
1950
+ def _reflect_table_comment(
1951
+ self,
1952
+ _reflect_info: _ReflectionInfo,
1953
+ table_key: TableKey,
1954
+ table: sa_schema.Table,
1955
+ reflection_options: Dict[str, Any],
1956
+ ) -> None:
1957
+ comment_dict = _reflect_info.table_comment.get(table_key)
1958
+ if comment_dict:
1959
+ table.comment = comment_dict["text"]
1960
+
1961
+ def _get_reflection_info(
1962
+ self,
1963
+ schema: Optional[str] = None,
1964
+ filter_names: Optional[Collection[str]] = None,
1965
+ available: Optional[Collection[str]] = None,
1966
+ _reflect_info: Optional[_ReflectionInfo] = None,
1967
+ **kw: Any,
1968
+ ) -> _ReflectionInfo:
1969
+ kw["schema"] = schema
1970
+
1971
+ if filter_names and available and len(filter_names) > 100:
1972
+ fraction = len(filter_names) / len(available)
1973
+ else:
1974
+ fraction = None
1975
+
1976
+ unreflectable: Dict[TableKey, exc.UnreflectableTableError]
1977
+ kw["unreflectable"] = unreflectable = {}
1978
+
1979
+ has_result: bool = True
1980
+
1981
+ def run(
1982
+ meth: Any,
1983
+ *,
1984
+ optional: bool = False,
1985
+ check_filter_names_from_meth: bool = False,
1986
+ ) -> Any:
1987
+ nonlocal has_result
1988
+ # simple heuristic to improve reflection performance if a
1989
+ # dialect implements multi_reflection:
1990
+ # if more than 50% of the tables in the db are in filter_names
1991
+ # load all the tables, since it's most likely faster to avoid
1992
+ # a filter on that many tables.
1993
+ if (
1994
+ fraction is None
1995
+ or fraction <= 0.5
1996
+ or not self.dialect._overrides_default(meth.__name__)
1997
+ ):
1998
+ _fn = filter_names
1999
+ else:
2000
+ _fn = None
2001
+ try:
2002
+ if has_result:
2003
+ res = meth(filter_names=_fn, **kw)
2004
+ if check_filter_names_from_meth and not res:
2005
+ # method returned no result data.
2006
+ # skip any future call methods
2007
+ has_result = False
2008
+ else:
2009
+ res = {}
2010
+ except NotImplementedError:
2011
+ if not optional:
2012
+ raise
2013
+ res = {}
2014
+ return res
2015
+
2016
+ info = _ReflectionInfo(
2017
+ columns=run(
2018
+ self.get_multi_columns, check_filter_names_from_meth=True
2019
+ ),
2020
+ pk_constraint=run(self.get_multi_pk_constraint),
2021
+ foreign_keys=run(self.get_multi_foreign_keys),
2022
+ indexes=run(self.get_multi_indexes),
2023
+ unique_constraints=run(
2024
+ self.get_multi_unique_constraints, optional=True
2025
+ ),
2026
+ table_comment=run(self.get_multi_table_comment, optional=True),
2027
+ check_constraints=run(
2028
+ self.get_multi_check_constraints, optional=True
2029
+ ),
2030
+ table_options=run(self.get_multi_table_options, optional=True),
2031
+ unreflectable=unreflectable,
2032
+ )
2033
+ if _reflect_info:
2034
+ _reflect_info.update(info)
2035
+ return _reflect_info
2036
+ else:
2037
+ return info
2038
+
2039
+
2040
+ @final
2041
+ class ReflectionDefaults:
2042
+ """provides blank default values for reflection methods."""
2043
+
2044
+ @classmethod
2045
+ def columns(cls) -> List[ReflectedColumn]:
2046
+ return []
2047
+
2048
+ @classmethod
2049
+ def pk_constraint(cls) -> ReflectedPrimaryKeyConstraint:
2050
+ return {
2051
+ "name": None,
2052
+ "constrained_columns": [],
2053
+ }
2054
+
2055
+ @classmethod
2056
+ def foreign_keys(cls) -> List[ReflectedForeignKeyConstraint]:
2057
+ return []
2058
+
2059
+ @classmethod
2060
+ def indexes(cls) -> List[ReflectedIndex]:
2061
+ return []
2062
+
2063
+ @classmethod
2064
+ def unique_constraints(cls) -> List[ReflectedUniqueConstraint]:
2065
+ return []
2066
+
2067
+ @classmethod
2068
+ def check_constraints(cls) -> List[ReflectedCheckConstraint]:
2069
+ return []
2070
+
2071
+ @classmethod
2072
+ def table_options(cls) -> Dict[str, Any]:
2073
+ return {}
2074
+
2075
+ @classmethod
2076
+ def table_comment(cls) -> ReflectedTableComment:
2077
+ return {"text": None}
2078
+
2079
+
2080
+ @dataclass
2081
+ class _ReflectionInfo:
2082
+ columns: Dict[TableKey, List[ReflectedColumn]]
2083
+ pk_constraint: Dict[TableKey, Optional[ReflectedPrimaryKeyConstraint]]
2084
+ foreign_keys: Dict[TableKey, List[ReflectedForeignKeyConstraint]]
2085
+ indexes: Dict[TableKey, List[ReflectedIndex]]
2086
+ # optionals
2087
+ unique_constraints: Dict[TableKey, List[ReflectedUniqueConstraint]]
2088
+ table_comment: Dict[TableKey, Optional[ReflectedTableComment]]
2089
+ check_constraints: Dict[TableKey, List[ReflectedCheckConstraint]]
2090
+ table_options: Dict[TableKey, Dict[str, Any]]
2091
+ unreflectable: Dict[TableKey, exc.UnreflectableTableError]
2092
+
2093
+ def update(self, other: _ReflectionInfo) -> None:
2094
+ for k, v in self.__dict__.items():
2095
+ ov = getattr(other, k)
2096
+ if ov is not None:
2097
+ if v is None:
2098
+ setattr(self, k, ov)
2099
+ else:
2100
+ v.update(ov)