_typing.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. # sql/_typing.py
  2. # Copyright (C) 2022-2025 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. from __future__ import annotations
  8. import operator
  9. from typing import Any
  10. from typing import Callable
  11. from typing import Dict
  12. from typing import Generic
  13. from typing import Iterable
  14. from typing import Mapping
  15. from typing import NoReturn
  16. from typing import Optional
  17. from typing import overload
  18. from typing import Set
  19. from typing import Tuple
  20. from typing import Type
  21. from typing import TYPE_CHECKING
  22. from typing import TypeVar
  23. from typing import Union
  24. from . import roles
  25. from .. import exc
  26. from .. import util
  27. from ..inspection import Inspectable
  28. from ..util.typing import Literal
  29. from ..util.typing import Protocol
  30. from ..util.typing import TypeAlias
  31. if TYPE_CHECKING:
  32. from datetime import date
  33. from datetime import datetime
  34. from datetime import time
  35. from datetime import timedelta
  36. from decimal import Decimal
  37. from uuid import UUID
  38. from .base import Executable
  39. from .compiler import Compiled
  40. from .compiler import DDLCompiler
  41. from .compiler import SQLCompiler
  42. from .dml import UpdateBase
  43. from .dml import ValuesBase
  44. from .elements import ClauseElement
  45. from .elements import ColumnElement
  46. from .elements import KeyedColumnElement
  47. from .elements import quoted_name
  48. from .elements import SQLCoreOperations
  49. from .elements import TextClause
  50. from .lambdas import LambdaElement
  51. from .roles import FromClauseRole
  52. from .schema import Column
  53. from .selectable import Alias
  54. from .selectable import CompoundSelect
  55. from .selectable import CTE
  56. from .selectable import FromClause
  57. from .selectable import Join
  58. from .selectable import NamedFromClause
  59. from .selectable import ReturnsRows
  60. from .selectable import Select
  61. from .selectable import Selectable
  62. from .selectable import SelectBase
  63. from .selectable import Subquery
  64. from .selectable import TableClause
  65. from .sqltypes import TableValueType
  66. from .sqltypes import TupleType
  67. from .type_api import TypeEngine
  68. from ..engine import Connection
  69. from ..engine import Dialect
  70. from ..engine import Engine
  71. from ..engine.mock import MockConnection
  72. from ..util.typing import TypeGuard
  73. _T = TypeVar("_T", bound=Any)
  74. _T_co = TypeVar("_T_co", bound=Any, covariant=True)
  75. _CE = TypeVar("_CE", bound="ColumnElement[Any]")
  76. _CLE = TypeVar("_CLE", bound="ClauseElement")
  77. class _HasClauseElement(Protocol, Generic[_T_co]):
  78. """indicates a class that has a __clause_element__() method"""
  79. def __clause_element__(self) -> roles.ExpressionElementRole[_T_co]: ...
  80. class _CoreAdapterProto(Protocol):
  81. """protocol for the ClauseAdapter/ColumnAdapter.traverse() method."""
  82. def __call__(self, obj: _CE) -> _CE: ...
  83. class _HasDialect(Protocol):
  84. """protocol for Engine/Connection-like objects that have dialect
  85. attribute.
  86. """
  87. @property
  88. def dialect(self) -> Dialect: ...
  89. # match column types that are not ORM entities
  90. _NOT_ENTITY = TypeVar(
  91. "_NOT_ENTITY",
  92. int,
  93. str,
  94. bool,
  95. "datetime",
  96. "date",
  97. "time",
  98. "timedelta",
  99. "UUID",
  100. float,
  101. "Decimal",
  102. )
  103. _StarOrOne = Literal["*", 1]
  104. _MAYBE_ENTITY = TypeVar(
  105. "_MAYBE_ENTITY",
  106. roles.ColumnsClauseRole,
  107. _StarOrOne,
  108. Type[Any],
  109. Inspectable[_HasClauseElement[Any]],
  110. _HasClauseElement[Any],
  111. )
  112. # convention:
  113. # XYZArgument - something that the end user is passing to a public API method
  114. # XYZElement - the internal representation that we use for the thing.
  115. # the coercions system is responsible for converting from XYZArgument to
  116. # XYZElement.
  117. _TextCoercedExpressionArgument = Union[
  118. str,
  119. "TextClause",
  120. "ColumnElement[_T]",
  121. _HasClauseElement[_T],
  122. roles.ExpressionElementRole[_T],
  123. ]
  124. _ColumnsClauseArgument = Union[
  125. roles.TypedColumnsClauseRole[_T],
  126. roles.ColumnsClauseRole,
  127. "SQLCoreOperations[_T]",
  128. _StarOrOne,
  129. Type[_T],
  130. Inspectable[_HasClauseElement[_T]],
  131. _HasClauseElement[_T],
  132. ]
  133. """open-ended SELECT columns clause argument.
  134. Includes column expressions, tables, ORM mapped entities, a few literal values.
  135. This type is used for lists of columns / entities to be returned in result
  136. sets; select(...), insert().returning(...), etc.
  137. """
  138. _TypedColumnClauseArgument = Union[
  139. roles.TypedColumnsClauseRole[_T],
  140. "SQLCoreOperations[_T]",
  141. Type[_T],
  142. ]
  143. _TP = TypeVar("_TP", bound=Tuple[Any, ...])
  144. _T0 = TypeVar("_T0", bound=Any)
  145. _T1 = TypeVar("_T1", bound=Any)
  146. _T2 = TypeVar("_T2", bound=Any)
  147. _T3 = TypeVar("_T3", bound=Any)
  148. _T4 = TypeVar("_T4", bound=Any)
  149. _T5 = TypeVar("_T5", bound=Any)
  150. _T6 = TypeVar("_T6", bound=Any)
  151. _T7 = TypeVar("_T7", bound=Any)
  152. _T8 = TypeVar("_T8", bound=Any)
  153. _T9 = TypeVar("_T9", bound=Any)
  154. _ColumnExpressionArgument = Union[
  155. "ColumnElement[_T]",
  156. _HasClauseElement[_T],
  157. "SQLCoreOperations[_T]",
  158. roles.ExpressionElementRole[_T],
  159. roles.TypedColumnsClauseRole[_T],
  160. Callable[[], "ColumnElement[_T]"],
  161. "LambdaElement",
  162. ]
  163. "See docs in public alias ColumnExpressionArgument."
  164. ColumnExpressionArgument: TypeAlias = _ColumnExpressionArgument[_T]
  165. """Narrower "column expression" argument.
  166. This type is used for all the other "column" kinds of expressions that
  167. typically represent a single SQL column expression, not a set of columns the
  168. way a table or ORM entity does.
  169. This includes ColumnElement, or ORM-mapped attributes that will have a
  170. ``__clause_element__()`` method, it also has the ExpressionElementRole
  171. overall which brings in the TextClause object also.
  172. .. versionadded:: 2.0.13
  173. """
  174. _ColumnExpressionOrLiteralArgument = Union[Any, _ColumnExpressionArgument[_T]]
  175. _ColumnExpressionOrStrLabelArgument = Union[str, _ColumnExpressionArgument[_T]]
  176. _ByArgument = Union[
  177. Iterable[_ColumnExpressionOrStrLabelArgument[Any]],
  178. _ColumnExpressionOrStrLabelArgument[Any],
  179. ]
  180. """Used for keyword-based ``order_by`` and ``partition_by`` parameters."""
  181. _InfoType = Dict[Any, Any]
  182. """the .info dictionary accepted and used throughout Core /ORM"""
  183. _FromClauseArgument = Union[
  184. roles.FromClauseRole,
  185. Type[Any],
  186. Inspectable[_HasClauseElement[Any]],
  187. _HasClauseElement[Any],
  188. ]
  189. """A FROM clause, like we would send to select().select_from().
  190. Also accommodates ORM entities and related constructs.
  191. """
  192. _JoinTargetArgument = Union[_FromClauseArgument, roles.JoinTargetRole]
  193. """target for join() builds on _FromClauseArgument to include additional
  194. join target roles such as those which come from the ORM.
  195. """
  196. _OnClauseArgument = Union[_ColumnExpressionArgument[Any], roles.OnClauseRole]
  197. """target for an ON clause, includes additional roles such as those which
  198. come from the ORM.
  199. """
  200. _SelectStatementForCompoundArgument = Union[
  201. "Select[_TP]",
  202. "CompoundSelect[_TP]",
  203. roles.CompoundElementRole,
  204. ]
  205. """SELECT statement acceptable by ``union()`` and other SQL set operations"""
  206. _DMLColumnArgument = Union[
  207. str,
  208. _HasClauseElement[Any],
  209. roles.DMLColumnRole,
  210. "SQLCoreOperations[Any]",
  211. ]
  212. """A DML column expression. This is a "key" inside of insert().values(),
  213. update().values(), and related.
  214. These are usually strings or SQL table columns.
  215. There's also edge cases like JSON expression assignment, which we would want
  216. the DMLColumnRole to be able to accommodate.
  217. """
  218. _DMLKey = TypeVar("_DMLKey", bound=_DMLColumnArgument)
  219. _DMLColumnKeyMapping = Mapping[_DMLKey, Any]
  220. _DDLColumnArgument = Union[str, "Column[Any]", roles.DDLConstraintColumnRole]
  221. """DDL column.
  222. used for :class:`.PrimaryKeyConstraint`, :class:`.UniqueConstraint`, etc.
  223. """
  224. _DMLTableArgument = Union[
  225. "TableClause",
  226. "Join",
  227. "Alias",
  228. "CTE",
  229. Type[Any],
  230. Inspectable[_HasClauseElement[Any]],
  231. _HasClauseElement[Any],
  232. ]
  233. _PropagateAttrsType = util.immutabledict[str, Any]
  234. _TypeEngineArgument = Union[Type["TypeEngine[_T]"], "TypeEngine[_T]"]
  235. _EquivalentColumnMap = Dict["ColumnElement[Any]", Set["ColumnElement[Any]"]]
  236. _LimitOffsetType = Union[int, _ColumnExpressionArgument[int], None]
  237. _AutoIncrementType = Union[bool, Literal["auto", "ignore_fk"]]
  238. _CreateDropBind = Union["Engine", "Connection", "MockConnection"]
  239. if TYPE_CHECKING:
  240. def is_sql_compiler(c: Compiled) -> TypeGuard[SQLCompiler]: ...
  241. def is_ddl_compiler(c: Compiled) -> TypeGuard[DDLCompiler]: ...
  242. def is_named_from_clause(
  243. t: FromClauseRole,
  244. ) -> TypeGuard[NamedFromClause]: ...
  245. def is_column_element(
  246. c: ClauseElement,
  247. ) -> TypeGuard[ColumnElement[Any]]: ...
  248. def is_keyed_column_element(
  249. c: ClauseElement,
  250. ) -> TypeGuard[KeyedColumnElement[Any]]: ...
  251. def is_text_clause(c: ClauseElement) -> TypeGuard[TextClause]: ...
  252. def is_from_clause(c: ClauseElement) -> TypeGuard[FromClause]: ...
  253. def is_tuple_type(t: TypeEngine[Any]) -> TypeGuard[TupleType]: ...
  254. def is_table_value_type(
  255. t: TypeEngine[Any],
  256. ) -> TypeGuard[TableValueType]: ...
  257. def is_selectable(t: Any) -> TypeGuard[Selectable]: ...
  258. def is_select_base(
  259. t: Union[Executable, ReturnsRows],
  260. ) -> TypeGuard[SelectBase]: ...
  261. def is_select_statement(
  262. t: Union[Executable, ReturnsRows],
  263. ) -> TypeGuard[Select[Any]]: ...
  264. def is_table(t: FromClause) -> TypeGuard[TableClause]: ...
  265. def is_subquery(t: FromClause) -> TypeGuard[Subquery]: ...
  266. def is_dml(c: ClauseElement) -> TypeGuard[UpdateBase]: ...
  267. else:
  268. is_sql_compiler = operator.attrgetter("is_sql")
  269. is_ddl_compiler = operator.attrgetter("is_ddl")
  270. is_named_from_clause = operator.attrgetter("named_with_column")
  271. is_column_element = operator.attrgetter("_is_column_element")
  272. is_keyed_column_element = operator.attrgetter("_is_keyed_column_element")
  273. is_text_clause = operator.attrgetter("_is_text_clause")
  274. is_from_clause = operator.attrgetter("_is_from_clause")
  275. is_tuple_type = operator.attrgetter("_is_tuple_type")
  276. is_table_value_type = operator.attrgetter("_is_table_value")
  277. is_selectable = operator.attrgetter("is_selectable")
  278. is_select_base = operator.attrgetter("_is_select_base")
  279. is_select_statement = operator.attrgetter("_is_select_statement")
  280. is_table = operator.attrgetter("_is_table")
  281. is_subquery = operator.attrgetter("_is_subquery")
  282. is_dml = operator.attrgetter("is_dml")
  283. def has_schema_attr(t: FromClauseRole) -> TypeGuard[TableClause]:
  284. return hasattr(t, "schema")
  285. def is_quoted_name(s: str) -> TypeGuard[quoted_name]:
  286. return hasattr(s, "quote")
  287. def is_has_clause_element(s: object) -> TypeGuard[_HasClauseElement[Any]]:
  288. return hasattr(s, "__clause_element__")
  289. def is_insert_update(c: ClauseElement) -> TypeGuard[ValuesBase]:
  290. return c.is_dml and (c.is_insert or c.is_update) # type: ignore
  291. def _no_kw() -> exc.ArgumentError:
  292. return exc.ArgumentError(
  293. "Additional keyword arguments are not accepted by this "
  294. "function/method. The presence of **kw is for pep-484 typing purposes"
  295. )
  296. def _unexpected_kw(methname: str, kw: Dict[str, Any]) -> NoReturn:
  297. k = list(kw)[0]
  298. raise TypeError(f"{methname} got an unexpected keyword argument '{k}'")
  299. @overload
  300. def Nullable(
  301. val: "SQLCoreOperations[_T]",
  302. ) -> "SQLCoreOperations[Optional[_T]]": ...
  303. @overload
  304. def Nullable(
  305. val: roles.ExpressionElementRole[_T],
  306. ) -> roles.ExpressionElementRole[Optional[_T]]: ...
  307. @overload
  308. def Nullable(val: Type[_T]) -> Type[Optional[_T]]: ...
  309. def Nullable(
  310. val: _TypedColumnClauseArgument[_T],
  311. ) -> _TypedColumnClauseArgument[Optional[_T]]:
  312. """Types a column or ORM class as nullable.
  313. This can be used in select and other contexts to express that the value of
  314. a column can be null, for example due to an outer join::
  315. stmt1 = select(A, Nullable(B)).outerjoin(A.bs)
  316. stmt2 = select(A.data, Nullable(B.data)).outerjoin(A.bs)
  317. At runtime this method returns the input unchanged.
  318. .. versionadded:: 2.0.20
  319. """
  320. return val
  321. @overload
  322. def NotNullable(
  323. val: "SQLCoreOperations[Optional[_T]]",
  324. ) -> "SQLCoreOperations[_T]": ...
  325. @overload
  326. def NotNullable(
  327. val: roles.ExpressionElementRole[Optional[_T]],
  328. ) -> roles.ExpressionElementRole[_T]: ...
  329. @overload
  330. def NotNullable(val: Type[Optional[_T]]) -> Type[_T]: ...
  331. @overload
  332. def NotNullable(val: Optional[Type[_T]]) -> Type[_T]: ...
  333. def NotNullable(
  334. val: Union[_TypedColumnClauseArgument[Optional[_T]], Optional[Type[_T]]],
  335. ) -> _TypedColumnClauseArgument[_T]:
  336. """Types a column or ORM class as not nullable.
  337. This can be used in select and other contexts to express that the value of
  338. a column cannot be null, for example due to a where condition on a
  339. nullable column::
  340. stmt = select(NotNullable(A.value)).where(A.value.is_not(None))
  341. At runtime this method returns the input unchanged.
  342. .. versionadded:: 2.0.20
  343. """
  344. return val # type: ignore