coercions.py 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404
  1. # sql/coercions.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. # mypy: allow-untyped-defs, allow-untyped-calls
  8. from __future__ import annotations
  9. import collections.abc as collections_abc
  10. import numbers
  11. import re
  12. import typing
  13. from typing import Any
  14. from typing import Callable
  15. from typing import cast
  16. from typing import Dict
  17. from typing import Iterable
  18. from typing import Iterator
  19. from typing import List
  20. from typing import NoReturn
  21. from typing import Optional
  22. from typing import overload
  23. from typing import Sequence
  24. from typing import Tuple
  25. from typing import Type
  26. from typing import TYPE_CHECKING
  27. from typing import TypeVar
  28. from typing import Union
  29. from . import roles
  30. from . import visitors
  31. from ._typing import is_from_clause
  32. from .base import ExecutableOption
  33. from .base import Options
  34. from .cache_key import HasCacheKey
  35. from .visitors import Visitable
  36. from .. import exc
  37. from .. import inspection
  38. from .. import util
  39. from ..util.typing import Literal
  40. if typing.TYPE_CHECKING:
  41. # elements lambdas schema selectable are set by __init__
  42. from . import elements
  43. from . import lambdas
  44. from . import schema
  45. from . import selectable
  46. from ._typing import _ColumnExpressionArgument
  47. from ._typing import _ColumnsClauseArgument
  48. from ._typing import _DDLColumnArgument
  49. from ._typing import _DMLTableArgument
  50. from ._typing import _FromClauseArgument
  51. from ._typing import _OnlyColumnArgument
  52. from .dml import _DMLTableElement
  53. from .elements import BindParameter
  54. from .elements import ClauseElement
  55. from .elements import ColumnClause
  56. from .elements import ColumnElement
  57. from .elements import NamedColumn
  58. from .elements import SQLCoreOperations
  59. from .elements import TextClause
  60. from .schema import Column
  61. from .selectable import _ColumnsClauseElement
  62. from .selectable import _JoinTargetProtocol
  63. from .selectable import FromClause
  64. from .selectable import HasCTE
  65. from .selectable import SelectBase
  66. from .selectable import Subquery
  67. from .visitors import _TraverseCallableType
  68. _SR = TypeVar("_SR", bound=roles.SQLRole)
  69. _F = TypeVar("_F", bound=Callable[..., Any])
  70. _StringOnlyR = TypeVar("_StringOnlyR", bound=roles.StringRole)
  71. _T = TypeVar("_T", bound=Any)
  72. def _is_literal(element: Any) -> bool:
  73. """Return whether or not the element is a "literal" in the context
  74. of a SQL expression construct.
  75. """
  76. return not isinstance(
  77. element,
  78. (Visitable, schema.SchemaEventTarget),
  79. ) and not hasattr(element, "__clause_element__")
  80. def _deep_is_literal(element):
  81. """Return whether or not the element is a "literal" in the context
  82. of a SQL expression construct.
  83. does a deeper more esoteric check than _is_literal. is used
  84. for lambda elements that have to distinguish values that would
  85. be bound vs. not without any context.
  86. """
  87. if isinstance(element, collections_abc.Sequence) and not isinstance(
  88. element, str
  89. ):
  90. for elem in element:
  91. if not _deep_is_literal(elem):
  92. return False
  93. else:
  94. return True
  95. return (
  96. not isinstance(
  97. element,
  98. (
  99. Visitable,
  100. schema.SchemaEventTarget,
  101. HasCacheKey,
  102. Options,
  103. util.langhelpers.symbol,
  104. ),
  105. )
  106. and not hasattr(element, "__clause_element__")
  107. and (
  108. not isinstance(element, type)
  109. or not issubclass(element, HasCacheKey)
  110. )
  111. )
  112. def _document_text_coercion(
  113. paramname: str, meth_rst: str, param_rst: str
  114. ) -> Callable[[_F], _F]:
  115. return util.add_parameter_text(
  116. paramname,
  117. (
  118. ".. warning:: "
  119. "The %s argument to %s can be passed as a Python string argument, "
  120. "which will be treated "
  121. "as **trusted SQL text** and rendered as given. **DO NOT PASS "
  122. "UNTRUSTED INPUT TO THIS PARAMETER**."
  123. )
  124. % (param_rst, meth_rst),
  125. )
  126. def _expression_collection_was_a_list(
  127. attrname: str,
  128. fnname: str,
  129. args: Union[Sequence[_T], Sequence[Sequence[_T]]],
  130. ) -> Sequence[_T]:
  131. if args and isinstance(args[0], (list, set, dict)) and len(args) == 1:
  132. if isinstance(args[0], list):
  133. raise exc.ArgumentError(
  134. f'The "{attrname}" argument to {fnname}(), when '
  135. "referring to a sequence "
  136. "of items, is now passed as a series of positional "
  137. "elements, rather than as a list. "
  138. )
  139. return cast("Sequence[_T]", args[0])
  140. return cast("Sequence[_T]", args)
  141. @overload
  142. def expect(
  143. role: Type[roles.TruncatedLabelRole],
  144. element: Any,
  145. **kw: Any,
  146. ) -> str: ...
  147. @overload
  148. def expect(
  149. role: Type[roles.DMLColumnRole],
  150. element: Any,
  151. *,
  152. as_key: Literal[True] = ...,
  153. **kw: Any,
  154. ) -> str: ...
  155. @overload
  156. def expect(
  157. role: Type[roles.LiteralValueRole],
  158. element: Any,
  159. **kw: Any,
  160. ) -> BindParameter[Any]: ...
  161. @overload
  162. def expect(
  163. role: Type[roles.DDLReferredColumnRole],
  164. element: Any,
  165. **kw: Any,
  166. ) -> Union[Column[Any], str]: ...
  167. @overload
  168. def expect(
  169. role: Type[roles.DDLConstraintColumnRole],
  170. element: Any,
  171. **kw: Any,
  172. ) -> Union[Column[Any], str]: ...
  173. @overload
  174. def expect(
  175. role: Type[roles.StatementOptionRole],
  176. element: Any,
  177. **kw: Any,
  178. ) -> Union[ColumnElement[Any], TextClause]: ...
  179. @overload
  180. def expect(
  181. role: Type[roles.LabeledColumnExprRole[Any]],
  182. element: Union[_ColumnExpressionArgument[_T], _OnlyColumnArgument[_T]],
  183. **kw: Any,
  184. ) -> NamedColumn[_T]: ...
  185. @overload
  186. def expect(
  187. role: Union[
  188. Type[roles.ExpressionElementRole[Any]],
  189. Type[roles.LimitOffsetRole],
  190. Type[roles.WhereHavingRole],
  191. ],
  192. element: _ColumnExpressionArgument[_T],
  193. **kw: Any,
  194. ) -> ColumnElement[_T]: ...
  195. @overload
  196. def expect(
  197. role: Union[
  198. Type[roles.ExpressionElementRole[Any]],
  199. Type[roles.LimitOffsetRole],
  200. Type[roles.WhereHavingRole],
  201. Type[roles.OnClauseRole],
  202. Type[roles.ColumnArgumentRole],
  203. ],
  204. element: Any,
  205. **kw: Any,
  206. ) -> ColumnElement[Any]: ...
  207. @overload
  208. def expect(
  209. role: Type[roles.DMLTableRole],
  210. element: _DMLTableArgument,
  211. **kw: Any,
  212. ) -> _DMLTableElement: ...
  213. @overload
  214. def expect(
  215. role: Type[roles.HasCTERole],
  216. element: HasCTE,
  217. **kw: Any,
  218. ) -> HasCTE: ...
  219. @overload
  220. def expect(
  221. role: Type[roles.SelectStatementRole],
  222. element: SelectBase,
  223. **kw: Any,
  224. ) -> SelectBase: ...
  225. @overload
  226. def expect(
  227. role: Type[roles.FromClauseRole],
  228. element: _FromClauseArgument,
  229. **kw: Any,
  230. ) -> FromClause: ...
  231. @overload
  232. def expect(
  233. role: Type[roles.FromClauseRole],
  234. element: SelectBase,
  235. *,
  236. explicit_subquery: Literal[True] = ...,
  237. **kw: Any,
  238. ) -> Subquery: ...
  239. @overload
  240. def expect(
  241. role: Type[roles.ColumnsClauseRole],
  242. element: _ColumnsClauseArgument[Any],
  243. **kw: Any,
  244. ) -> _ColumnsClauseElement: ...
  245. @overload
  246. def expect(
  247. role: Type[roles.JoinTargetRole],
  248. element: _JoinTargetProtocol,
  249. **kw: Any,
  250. ) -> _JoinTargetProtocol: ...
  251. # catchall for not-yet-implemented overloads
  252. @overload
  253. def expect(
  254. role: Type[_SR],
  255. element: Any,
  256. **kw: Any,
  257. ) -> Any: ...
  258. def expect(
  259. role: Type[_SR],
  260. element: Any,
  261. *,
  262. apply_propagate_attrs: Optional[ClauseElement] = None,
  263. argname: Optional[str] = None,
  264. post_inspect: bool = False,
  265. disable_inspection: bool = False,
  266. **kw: Any,
  267. ) -> Any:
  268. if (
  269. role.allows_lambda
  270. # note callable() will not invoke a __getattr__() method, whereas
  271. # hasattr(obj, "__call__") will. by keeping the callable() check here
  272. # we prevent most needless calls to hasattr() and therefore
  273. # __getattr__(), which is present on ColumnElement.
  274. and callable(element)
  275. and hasattr(element, "__code__")
  276. ):
  277. return lambdas.LambdaElement(
  278. element,
  279. role,
  280. lambdas.LambdaOptions(**kw),
  281. apply_propagate_attrs=apply_propagate_attrs,
  282. )
  283. # major case is that we are given a ClauseElement already, skip more
  284. # elaborate logic up front if possible
  285. impl = _impl_lookup[role]
  286. original_element = element
  287. if not isinstance(
  288. element,
  289. (
  290. elements.CompilerElement,
  291. schema.SchemaItem,
  292. schema.FetchedValue,
  293. lambdas.PyWrapper,
  294. ),
  295. ):
  296. resolved = None
  297. if impl._resolve_literal_only:
  298. resolved = impl._literal_coercion(element, **kw)
  299. else:
  300. original_element = element
  301. is_clause_element = False
  302. # this is a special performance optimization for ORM
  303. # joins used by JoinTargetImpl that we don't go through the
  304. # work of creating __clause_element__() when we only need the
  305. # original QueryableAttribute, as the former will do clause
  306. # adaption and all that which is just thrown away here.
  307. if (
  308. impl._skip_clauseelement_for_target_match
  309. and isinstance(element, role)
  310. and hasattr(element, "__clause_element__")
  311. ):
  312. is_clause_element = True
  313. else:
  314. while hasattr(element, "__clause_element__"):
  315. is_clause_element = True
  316. if not getattr(element, "is_clause_element", False):
  317. element = element.__clause_element__()
  318. else:
  319. break
  320. if not is_clause_element:
  321. if impl._use_inspection and not disable_inspection:
  322. insp = inspection.inspect(element, raiseerr=False)
  323. if insp is not None:
  324. if post_inspect:
  325. insp._post_inspect
  326. try:
  327. resolved = insp.__clause_element__()
  328. except AttributeError:
  329. impl._raise_for_expected(original_element, argname)
  330. if resolved is None:
  331. resolved = impl._literal_coercion(
  332. element, argname=argname, **kw
  333. )
  334. else:
  335. resolved = element
  336. elif isinstance(element, lambdas.PyWrapper):
  337. resolved = element._sa__py_wrapper_literal(**kw)
  338. else:
  339. resolved = element
  340. if apply_propagate_attrs is not None:
  341. if typing.TYPE_CHECKING:
  342. assert isinstance(resolved, (SQLCoreOperations, ClauseElement))
  343. if not apply_propagate_attrs._propagate_attrs and getattr(
  344. resolved, "_propagate_attrs", None
  345. ):
  346. apply_propagate_attrs._propagate_attrs = resolved._propagate_attrs
  347. if impl._role_class in resolved.__class__.__mro__:
  348. if impl._post_coercion:
  349. resolved = impl._post_coercion(
  350. resolved,
  351. argname=argname,
  352. original_element=original_element,
  353. **kw,
  354. )
  355. return resolved
  356. else:
  357. return impl._implicit_coercions(
  358. original_element, resolved, argname=argname, **kw
  359. )
  360. def expect_as_key(
  361. role: Type[roles.DMLColumnRole], element: Any, **kw: Any
  362. ) -> str:
  363. kw.pop("as_key", None)
  364. return expect(role, element, as_key=True, **kw)
  365. def expect_col_expression_collection(
  366. role: Type[roles.DDLConstraintColumnRole],
  367. expressions: Iterable[_DDLColumnArgument],
  368. ) -> Iterator[
  369. Tuple[
  370. Union[str, Column[Any]],
  371. Optional[ColumnClause[Any]],
  372. Optional[str],
  373. Optional[Union[Column[Any], str]],
  374. ]
  375. ]:
  376. for expr in expressions:
  377. strname = None
  378. column = None
  379. resolved: Union[Column[Any], str] = expect(role, expr)
  380. if isinstance(resolved, str):
  381. assert isinstance(expr, str)
  382. strname = resolved = expr
  383. else:
  384. cols: List[Column[Any]] = []
  385. col_append: _TraverseCallableType[Column[Any]] = cols.append
  386. visitors.traverse(resolved, {}, {"column": col_append})
  387. if cols:
  388. column = cols[0]
  389. add_element = column if column is not None else strname
  390. yield resolved, column, strname, add_element
  391. class RoleImpl:
  392. __slots__ = ("_role_class", "name", "_use_inspection")
  393. def _literal_coercion(self, element, **kw):
  394. raise NotImplementedError()
  395. _post_coercion: Any = None
  396. _resolve_literal_only = False
  397. _skip_clauseelement_for_target_match = False
  398. def __init__(self, role_class):
  399. self._role_class = role_class
  400. self.name = role_class._role_name
  401. self._use_inspection = issubclass(role_class, roles.UsesInspection)
  402. def _implicit_coercions(
  403. self,
  404. element: Any,
  405. resolved: Any,
  406. argname: Optional[str] = None,
  407. **kw: Any,
  408. ) -> Any:
  409. self._raise_for_expected(element, argname, resolved)
  410. def _raise_for_expected(
  411. self,
  412. element: Any,
  413. argname: Optional[str] = None,
  414. resolved: Optional[Any] = None,
  415. *,
  416. advice: Optional[str] = None,
  417. code: Optional[str] = None,
  418. err: Optional[Exception] = None,
  419. **kw: Any,
  420. ) -> NoReturn:
  421. if resolved is not None and resolved is not element:
  422. got = "%r object resolved from %r object" % (resolved, element)
  423. else:
  424. got = repr(element)
  425. if argname:
  426. msg = "%s expected for argument %r; got %s." % (
  427. self.name,
  428. argname,
  429. got,
  430. )
  431. else:
  432. msg = "%s expected, got %s." % (self.name, got)
  433. if advice:
  434. msg += " " + advice
  435. raise exc.ArgumentError(msg, code=code) from err
  436. class _Deannotate:
  437. __slots__ = ()
  438. def _post_coercion(self, resolved, **kw):
  439. from .util import _deep_deannotate
  440. return _deep_deannotate(resolved)
  441. class _StringOnly:
  442. __slots__ = ()
  443. _resolve_literal_only = True
  444. class _ReturnsStringKey(RoleImpl):
  445. __slots__ = ()
  446. def _implicit_coercions(self, element, resolved, argname=None, **kw):
  447. if isinstance(element, str):
  448. return element
  449. else:
  450. self._raise_for_expected(element, argname, resolved)
  451. def _literal_coercion(self, element, **kw):
  452. return element
  453. class _ColumnCoercions(RoleImpl):
  454. __slots__ = ()
  455. def _warn_for_scalar_subquery_coercion(self):
  456. util.warn(
  457. "implicitly coercing SELECT object to scalar subquery; "
  458. "please use the .scalar_subquery() method to produce a scalar "
  459. "subquery.",
  460. )
  461. def _implicit_coercions(self, element, resolved, argname=None, **kw):
  462. original_element = element
  463. if not getattr(resolved, "is_clause_element", False):
  464. self._raise_for_expected(original_element, argname, resolved)
  465. elif resolved._is_select_base:
  466. self._warn_for_scalar_subquery_coercion()
  467. return resolved.scalar_subquery()
  468. elif resolved._is_from_clause and isinstance(
  469. resolved, selectable.Subquery
  470. ):
  471. self._warn_for_scalar_subquery_coercion()
  472. return resolved.element.scalar_subquery()
  473. elif self._role_class.allows_lambda and resolved._is_lambda_element:
  474. return resolved
  475. else:
  476. self._raise_for_expected(original_element, argname, resolved)
  477. def _no_text_coercion(
  478. element: Any,
  479. argname: Optional[str] = None,
  480. exc_cls: Type[exc.SQLAlchemyError] = exc.ArgumentError,
  481. extra: Optional[str] = None,
  482. err: Optional[Exception] = None,
  483. ) -> NoReturn:
  484. raise exc_cls(
  485. "%(extra)sTextual SQL expression %(expr)r %(argname)sshould be "
  486. "explicitly declared as text(%(expr)r)"
  487. % {
  488. "expr": util.ellipses_string(element),
  489. "argname": "for argument %s" % (argname,) if argname else "",
  490. "extra": "%s " % extra if extra else "",
  491. }
  492. ) from err
  493. class _NoTextCoercion(RoleImpl):
  494. __slots__ = ()
  495. def _literal_coercion(self, element, *, argname=None, **kw):
  496. if isinstance(element, str) and issubclass(
  497. elements.TextClause, self._role_class
  498. ):
  499. _no_text_coercion(element, argname)
  500. else:
  501. self._raise_for_expected(element, argname)
  502. class _CoerceLiterals(RoleImpl):
  503. __slots__ = ()
  504. _coerce_consts = False
  505. _coerce_star = False
  506. _coerce_numerics = False
  507. def _text_coercion(self, element, argname=None):
  508. return _no_text_coercion(element, argname)
  509. def _literal_coercion(self, element, *, argname=None, **kw):
  510. if isinstance(element, str):
  511. if self._coerce_star and element == "*":
  512. return elements.ColumnClause("*", is_literal=True)
  513. else:
  514. return self._text_coercion(element, argname, **kw)
  515. if self._coerce_consts:
  516. if element is None:
  517. return elements.Null()
  518. elif element is False:
  519. return elements.False_()
  520. elif element is True:
  521. return elements.True_()
  522. if self._coerce_numerics and isinstance(element, (numbers.Number)):
  523. return elements.ColumnClause(str(element), is_literal=True)
  524. self._raise_for_expected(element, argname)
  525. class LiteralValueImpl(RoleImpl):
  526. _resolve_literal_only = True
  527. def _implicit_coercions(
  528. self,
  529. element,
  530. resolved,
  531. argname=None,
  532. *,
  533. type_=None,
  534. literal_execute=False,
  535. **kw,
  536. ):
  537. if not _is_literal(resolved):
  538. self._raise_for_expected(
  539. element, resolved=resolved, argname=argname, **kw
  540. )
  541. return elements.BindParameter(
  542. None,
  543. element,
  544. type_=type_,
  545. unique=True,
  546. literal_execute=literal_execute,
  547. )
  548. def _literal_coercion(self, element, **kw):
  549. return element
  550. class _SelectIsNotFrom(RoleImpl):
  551. __slots__ = ()
  552. def _raise_for_expected(
  553. self,
  554. element: Any,
  555. argname: Optional[str] = None,
  556. resolved: Optional[Any] = None,
  557. *,
  558. advice: Optional[str] = None,
  559. code: Optional[str] = None,
  560. err: Optional[Exception] = None,
  561. **kw: Any,
  562. ) -> NoReturn:
  563. if (
  564. not advice
  565. and isinstance(element, roles.SelectStatementRole)
  566. or isinstance(resolved, roles.SelectStatementRole)
  567. ):
  568. advice = (
  569. "To create a "
  570. "FROM clause from a %s object, use the .subquery() method."
  571. % (resolved.__class__ if resolved is not None else element,)
  572. )
  573. code = "89ve"
  574. else:
  575. code = None
  576. super()._raise_for_expected(
  577. element,
  578. argname=argname,
  579. resolved=resolved,
  580. advice=advice,
  581. code=code,
  582. err=err,
  583. **kw,
  584. )
  585. # never reached
  586. assert False
  587. class HasCacheKeyImpl(RoleImpl):
  588. __slots__ = ()
  589. def _implicit_coercions(
  590. self,
  591. element: Any,
  592. resolved: Any,
  593. argname: Optional[str] = None,
  594. **kw: Any,
  595. ) -> Any:
  596. if isinstance(element, HasCacheKey):
  597. return element
  598. else:
  599. self._raise_for_expected(element, argname, resolved)
  600. def _literal_coercion(self, element, **kw):
  601. return element
  602. class ExecutableOptionImpl(RoleImpl):
  603. __slots__ = ()
  604. def _implicit_coercions(
  605. self,
  606. element: Any,
  607. resolved: Any,
  608. argname: Optional[str] = None,
  609. **kw: Any,
  610. ) -> Any:
  611. if isinstance(element, ExecutableOption):
  612. return element
  613. else:
  614. self._raise_for_expected(element, argname, resolved)
  615. def _literal_coercion(self, element, **kw):
  616. return element
  617. class ExpressionElementImpl(_ColumnCoercions, RoleImpl):
  618. __slots__ = ()
  619. def _literal_coercion(
  620. self, element, *, name=None, type_=None, is_crud=False, **kw
  621. ):
  622. if (
  623. element is None
  624. and not is_crud
  625. and (type_ is None or not type_.should_evaluate_none)
  626. ):
  627. # TODO: there's no test coverage now for the
  628. # "should_evaluate_none" part of this, as outside of "crud" this
  629. # codepath is not normally used except in some special cases
  630. return elements.Null()
  631. else:
  632. try:
  633. return elements.BindParameter(
  634. name, element, type_, unique=True, _is_crud=is_crud
  635. )
  636. except exc.ArgumentError as err:
  637. self._raise_for_expected(element, err=err)
  638. def _raise_for_expected(self, element, argname=None, resolved=None, **kw):
  639. # select uses implicit coercion with warning instead of raising
  640. if isinstance(element, selectable.Values):
  641. advice = (
  642. "To create a column expression from a VALUES clause, "
  643. "use the .scalar_values() method."
  644. )
  645. elif isinstance(element, roles.AnonymizedFromClauseRole):
  646. advice = (
  647. "To create a column expression from a FROM clause row "
  648. "as a whole, use the .table_valued() method."
  649. )
  650. else:
  651. advice = None
  652. return super()._raise_for_expected(
  653. element, argname=argname, resolved=resolved, advice=advice, **kw
  654. )
  655. class BinaryElementImpl(ExpressionElementImpl, RoleImpl):
  656. __slots__ = ()
  657. def _literal_coercion( # type: ignore[override]
  658. self,
  659. element,
  660. *,
  661. expr,
  662. operator,
  663. bindparam_type=None,
  664. argname=None,
  665. **kw,
  666. ):
  667. try:
  668. return expr._bind_param(operator, element, type_=bindparam_type)
  669. except exc.ArgumentError as err:
  670. self._raise_for_expected(element, err=err)
  671. def _post_coercion(self, resolved, *, expr, bindparam_type=None, **kw):
  672. if resolved.type._isnull and not expr.type._isnull:
  673. resolved = resolved._with_binary_element_type(
  674. bindparam_type if bindparam_type is not None else expr.type
  675. )
  676. return resolved
  677. class InElementImpl(RoleImpl):
  678. __slots__ = ()
  679. def _implicit_coercions(
  680. self,
  681. element: Any,
  682. resolved: Any,
  683. argname: Optional[str] = None,
  684. **kw: Any,
  685. ) -> Any:
  686. if resolved._is_from_clause:
  687. if (
  688. isinstance(resolved, selectable.Alias)
  689. and resolved.element._is_select_base
  690. ):
  691. self._warn_for_implicit_coercion(resolved)
  692. return self._post_coercion(resolved.element, **kw)
  693. else:
  694. self._warn_for_implicit_coercion(resolved)
  695. return self._post_coercion(resolved.select(), **kw)
  696. else:
  697. self._raise_for_expected(element, argname, resolved)
  698. def _warn_for_implicit_coercion(self, elem):
  699. util.warn(
  700. "Coercing %s object into a select() for use in IN(); "
  701. "please pass a select() construct explicitly"
  702. % (elem.__class__.__name__)
  703. )
  704. @util.preload_module("sqlalchemy.sql.elements")
  705. def _literal_coercion(self, element, *, expr, operator, **kw): # type: ignore[override] # noqa: E501
  706. if util.is_non_string_iterable(element):
  707. non_literal_expressions: Dict[
  708. Optional[_ColumnExpressionArgument[Any]],
  709. _ColumnExpressionArgument[Any],
  710. ] = {}
  711. element = list(element)
  712. for o in element:
  713. if not _is_literal(o):
  714. if not isinstance(
  715. o, util.preloaded.sql_elements.ColumnElement
  716. ) and not hasattr(o, "__clause_element__"):
  717. self._raise_for_expected(element, **kw)
  718. else:
  719. non_literal_expressions[o] = o
  720. if non_literal_expressions:
  721. return elements.ClauseList(
  722. *[
  723. (
  724. non_literal_expressions[o]
  725. if o in non_literal_expressions
  726. else expr._bind_param(operator, o)
  727. )
  728. for o in element
  729. ]
  730. )
  731. else:
  732. return expr._bind_param(operator, element, expanding=True)
  733. else:
  734. self._raise_for_expected(element, **kw)
  735. def _post_coercion(self, element, *, expr, operator, **kw):
  736. if element._is_select_base:
  737. # for IN, we are doing scalar_subquery() coercion without
  738. # a warning
  739. return element.scalar_subquery()
  740. elif isinstance(element, elements.ClauseList):
  741. assert not len(element.clauses) == 0
  742. return element.self_group(against=operator)
  743. elif isinstance(element, elements.BindParameter):
  744. element = element._clone(maintain_key=True)
  745. element.expanding = True
  746. element.expand_op = operator
  747. return element
  748. elif isinstance(element, selectable.Values):
  749. return element.scalar_values()
  750. else:
  751. return element
  752. class OnClauseImpl(_ColumnCoercions, RoleImpl):
  753. __slots__ = ()
  754. _coerce_consts = True
  755. def _literal_coercion(self, element, **kw):
  756. self._raise_for_expected(element)
  757. def _post_coercion(self, resolved, *, original_element=None, **kw):
  758. # this is a hack right now as we want to use coercion on an
  759. # ORM InstrumentedAttribute, but we want to return the object
  760. # itself if it is one, not its clause element.
  761. # ORM context _join and _legacy_join() would need to be improved
  762. # to look for annotations in a clause element form.
  763. if isinstance(original_element, roles.JoinTargetRole):
  764. return original_element
  765. return resolved
  766. class WhereHavingImpl(_CoerceLiterals, _ColumnCoercions, RoleImpl):
  767. __slots__ = ()
  768. _coerce_consts = True
  769. def _text_coercion(self, element, argname=None):
  770. return _no_text_coercion(element, argname)
  771. class StatementOptionImpl(_CoerceLiterals, RoleImpl):
  772. __slots__ = ()
  773. _coerce_consts = True
  774. def _text_coercion(self, element, argname=None):
  775. return elements.TextClause(element)
  776. class ColumnArgumentImpl(_NoTextCoercion, RoleImpl):
  777. __slots__ = ()
  778. class ColumnArgumentOrKeyImpl(_ReturnsStringKey, RoleImpl):
  779. __slots__ = ()
  780. class StrAsPlainColumnImpl(_CoerceLiterals, RoleImpl):
  781. __slots__ = ()
  782. def _text_coercion(self, element, argname=None):
  783. return elements.ColumnClause(element)
  784. class ByOfImpl(_CoerceLiterals, _ColumnCoercions, RoleImpl, roles.ByOfRole):
  785. __slots__ = ()
  786. _coerce_consts = True
  787. def _text_coercion(self, element, argname=None):
  788. return elements._textual_label_reference(element)
  789. class OrderByImpl(ByOfImpl, RoleImpl):
  790. __slots__ = ()
  791. def _post_coercion(self, resolved, **kw):
  792. if (
  793. isinstance(resolved, self._role_class)
  794. and resolved._order_by_label_element is not None
  795. ):
  796. return elements._label_reference(resolved)
  797. else:
  798. return resolved
  799. class GroupByImpl(ByOfImpl, RoleImpl):
  800. __slots__ = ()
  801. def _implicit_coercions(
  802. self,
  803. element: Any,
  804. resolved: Any,
  805. argname: Optional[str] = None,
  806. **kw: Any,
  807. ) -> Any:
  808. if is_from_clause(resolved):
  809. return elements.ClauseList(*resolved.c)
  810. else:
  811. return resolved
  812. class DMLColumnImpl(_ReturnsStringKey, RoleImpl):
  813. __slots__ = ()
  814. def _post_coercion(self, element, *, as_key=False, **kw):
  815. if as_key:
  816. return element.key
  817. else:
  818. return element
  819. class ConstExprImpl(RoleImpl):
  820. __slots__ = ()
  821. def _literal_coercion(self, element, *, argname=None, **kw):
  822. if element is None:
  823. return elements.Null()
  824. elif element is False:
  825. return elements.False_()
  826. elif element is True:
  827. return elements.True_()
  828. else:
  829. self._raise_for_expected(element, argname)
  830. class TruncatedLabelImpl(_StringOnly, RoleImpl):
  831. __slots__ = ()
  832. def _implicit_coercions(
  833. self,
  834. element: Any,
  835. resolved: Any,
  836. argname: Optional[str] = None,
  837. **kw: Any,
  838. ) -> Any:
  839. if isinstance(element, str):
  840. return resolved
  841. else:
  842. self._raise_for_expected(element, argname, resolved)
  843. def _literal_coercion(self, element, **kw):
  844. """coerce the given value to :class:`._truncated_label`.
  845. Existing :class:`._truncated_label` and
  846. :class:`._anonymous_label` objects are passed
  847. unchanged.
  848. """
  849. if isinstance(element, elements._truncated_label):
  850. return element
  851. else:
  852. return elements._truncated_label(element)
  853. class DDLExpressionImpl(_Deannotate, _CoerceLiterals, RoleImpl):
  854. __slots__ = ()
  855. _coerce_consts = True
  856. def _text_coercion(self, element, argname=None):
  857. # see #5754 for why we can't easily deprecate this coercion.
  858. # essentially expressions like postgresql_where would have to be
  859. # text() as they come back from reflection and we don't want to
  860. # have text() elements wired into the inspection dictionaries.
  861. return elements.TextClause(element)
  862. class DDLConstraintColumnImpl(_Deannotate, _ReturnsStringKey, RoleImpl):
  863. __slots__ = ()
  864. class DDLReferredColumnImpl(DDLConstraintColumnImpl):
  865. __slots__ = ()
  866. class LimitOffsetImpl(RoleImpl):
  867. __slots__ = ()
  868. def _implicit_coercions(
  869. self,
  870. element: Any,
  871. resolved: Any,
  872. argname: Optional[str] = None,
  873. **kw: Any,
  874. ) -> Any:
  875. if resolved is None:
  876. return None
  877. else:
  878. self._raise_for_expected(element, argname, resolved)
  879. def _literal_coercion( # type: ignore[override]
  880. self, element, *, name, type_, **kw
  881. ):
  882. if element is None:
  883. return None
  884. else:
  885. value = util.asint(element)
  886. return selectable._OffsetLimitParam(
  887. name, value, type_=type_, unique=True
  888. )
  889. class LabeledColumnExprImpl(ExpressionElementImpl):
  890. __slots__ = ()
  891. def _implicit_coercions(
  892. self,
  893. element: Any,
  894. resolved: Any,
  895. argname: Optional[str] = None,
  896. **kw: Any,
  897. ) -> Any:
  898. if isinstance(resolved, roles.ExpressionElementRole):
  899. return resolved.label(None)
  900. else:
  901. new = super()._implicit_coercions(
  902. element, resolved, argname=argname, **kw
  903. )
  904. if isinstance(new, roles.ExpressionElementRole):
  905. return new.label(None)
  906. else:
  907. self._raise_for_expected(element, argname, resolved)
  908. class ColumnsClauseImpl(_SelectIsNotFrom, _CoerceLiterals, RoleImpl):
  909. __slots__ = ()
  910. _coerce_consts = True
  911. _coerce_numerics = True
  912. _coerce_star = True
  913. _guess_straight_column = re.compile(r"^\w\S*$", re.I)
  914. def _raise_for_expected(
  915. self, element, argname=None, resolved=None, *, advice=None, **kw
  916. ):
  917. if not advice and isinstance(element, list):
  918. advice = (
  919. f"Did you mean to say select("
  920. f"{', '.join(repr(e) for e in element)})?"
  921. )
  922. return super()._raise_for_expected(
  923. element, argname=argname, resolved=resolved, advice=advice, **kw
  924. )
  925. def _text_coercion(self, element, argname=None):
  926. element = str(element)
  927. guess_is_literal = not self._guess_straight_column.match(element)
  928. raise exc.ArgumentError(
  929. "Textual column expression %(column)r %(argname)sshould be "
  930. "explicitly declared with text(%(column)r), "
  931. "or use %(literal_column)s(%(column)r) "
  932. "for more specificity"
  933. % {
  934. "column": util.ellipses_string(element),
  935. "argname": "for argument %s" % (argname,) if argname else "",
  936. "literal_column": (
  937. "literal_column" if guess_is_literal else "column"
  938. ),
  939. }
  940. )
  941. class ReturnsRowsImpl(RoleImpl):
  942. __slots__ = ()
  943. class StatementImpl(_CoerceLiterals, RoleImpl):
  944. __slots__ = ()
  945. def _post_coercion(
  946. self, resolved, *, original_element, argname=None, **kw
  947. ):
  948. if resolved is not original_element and not isinstance(
  949. original_element, str
  950. ):
  951. # use same method as Connection uses; this will later raise
  952. # ObjectNotExecutableError
  953. try:
  954. original_element._execute_on_connection
  955. except AttributeError:
  956. util.warn_deprecated(
  957. "Object %r should not be used directly in a SQL statement "
  958. "context, such as passing to methods such as "
  959. "session.execute(). This usage will be disallowed in a "
  960. "future release. "
  961. "Please use Core select() / update() / delete() etc. "
  962. "with Session.execute() and other statement execution "
  963. "methods." % original_element,
  964. "1.4",
  965. )
  966. return resolved
  967. def _implicit_coercions(
  968. self,
  969. element: Any,
  970. resolved: Any,
  971. argname: Optional[str] = None,
  972. **kw: Any,
  973. ) -> Any:
  974. if resolved._is_lambda_element:
  975. return resolved
  976. else:
  977. return super()._implicit_coercions(
  978. element, resolved, argname=argname, **kw
  979. )
  980. class SelectStatementImpl(_NoTextCoercion, RoleImpl):
  981. __slots__ = ()
  982. def _implicit_coercions(
  983. self,
  984. element: Any,
  985. resolved: Any,
  986. argname: Optional[str] = None,
  987. **kw: Any,
  988. ) -> Any:
  989. if resolved._is_text_clause:
  990. return resolved.columns()
  991. else:
  992. self._raise_for_expected(element, argname, resolved)
  993. class HasCTEImpl(ReturnsRowsImpl):
  994. __slots__ = ()
  995. class IsCTEImpl(RoleImpl):
  996. __slots__ = ()
  997. class JoinTargetImpl(RoleImpl):
  998. __slots__ = ()
  999. _skip_clauseelement_for_target_match = True
  1000. def _literal_coercion(self, element, *, argname=None, **kw):
  1001. self._raise_for_expected(element, argname)
  1002. def _implicit_coercions(
  1003. self,
  1004. element: Any,
  1005. resolved: Any,
  1006. argname: Optional[str] = None,
  1007. *,
  1008. legacy: bool = False,
  1009. **kw: Any,
  1010. ) -> Any:
  1011. if isinstance(element, roles.JoinTargetRole):
  1012. # note that this codepath no longer occurs as of
  1013. # #6550, unless JoinTargetImpl._skip_clauseelement_for_target_match
  1014. # were set to False.
  1015. return element
  1016. elif legacy and resolved._is_select_base:
  1017. util.warn_deprecated(
  1018. "Implicit coercion of SELECT and textual SELECT "
  1019. "constructs into FROM clauses is deprecated; please call "
  1020. ".subquery() on any Core select or ORM Query object in "
  1021. "order to produce a subquery object.",
  1022. version="1.4",
  1023. )
  1024. # TODO: doing _implicit_subquery here causes tests to fail,
  1025. # how was this working before? probably that ORM
  1026. # join logic treated it as a select and subquery would happen
  1027. # in _ORMJoin->Join
  1028. return resolved
  1029. else:
  1030. self._raise_for_expected(element, argname, resolved)
  1031. class FromClauseImpl(_SelectIsNotFrom, _NoTextCoercion, RoleImpl):
  1032. __slots__ = ()
  1033. def _implicit_coercions(
  1034. self,
  1035. element: Any,
  1036. resolved: Any,
  1037. argname: Optional[str] = None,
  1038. *,
  1039. explicit_subquery: bool = False,
  1040. allow_select: bool = True,
  1041. **kw: Any,
  1042. ) -> Any:
  1043. if resolved._is_select_base:
  1044. if explicit_subquery:
  1045. return resolved.subquery()
  1046. elif allow_select:
  1047. util.warn_deprecated(
  1048. "Implicit coercion of SELECT and textual SELECT "
  1049. "constructs into FROM clauses is deprecated; please call "
  1050. ".subquery() on any Core select or ORM Query object in "
  1051. "order to produce a subquery object.",
  1052. version="1.4",
  1053. )
  1054. return resolved._implicit_subquery
  1055. elif resolved._is_text_clause:
  1056. return resolved
  1057. else:
  1058. self._raise_for_expected(element, argname, resolved)
  1059. def _post_coercion(self, element, *, deannotate=False, **kw):
  1060. if deannotate:
  1061. return element._deannotate()
  1062. else:
  1063. return element
  1064. class StrictFromClauseImpl(FromClauseImpl):
  1065. __slots__ = ()
  1066. def _implicit_coercions(
  1067. self,
  1068. element: Any,
  1069. resolved: Any,
  1070. argname: Optional[str] = None,
  1071. *,
  1072. allow_select: bool = False,
  1073. **kw: Any,
  1074. ) -> Any:
  1075. if resolved._is_select_base and allow_select:
  1076. util.warn_deprecated(
  1077. "Implicit coercion of SELECT and textual SELECT constructs "
  1078. "into FROM clauses is deprecated; please call .subquery() "
  1079. "on any Core select or ORM Query object in order to produce a "
  1080. "subquery object.",
  1081. version="1.4",
  1082. )
  1083. return resolved._implicit_subquery
  1084. else:
  1085. self._raise_for_expected(element, argname, resolved)
  1086. class AnonymizedFromClauseImpl(StrictFromClauseImpl):
  1087. __slots__ = ()
  1088. def _post_coercion(self, element, *, flat=False, name=None, **kw):
  1089. assert name is None
  1090. return element._anonymous_fromclause(flat=flat)
  1091. class DMLTableImpl(_SelectIsNotFrom, _NoTextCoercion, RoleImpl):
  1092. __slots__ = ()
  1093. def _post_coercion(self, element, **kw):
  1094. if "dml_table" in element._annotations:
  1095. return element._annotations["dml_table"]
  1096. else:
  1097. return element
  1098. class DMLSelectImpl(_NoTextCoercion, RoleImpl):
  1099. __slots__ = ()
  1100. def _implicit_coercions(
  1101. self,
  1102. element: Any,
  1103. resolved: Any,
  1104. argname: Optional[str] = None,
  1105. **kw: Any,
  1106. ) -> Any:
  1107. if resolved._is_from_clause:
  1108. if (
  1109. isinstance(resolved, selectable.Alias)
  1110. and resolved.element._is_select_base
  1111. ):
  1112. return resolved.element
  1113. else:
  1114. return resolved.select()
  1115. else:
  1116. self._raise_for_expected(element, argname, resolved)
  1117. class CompoundElementImpl(_NoTextCoercion, RoleImpl):
  1118. __slots__ = ()
  1119. def _raise_for_expected(self, element, argname=None, resolved=None, **kw):
  1120. if isinstance(element, roles.FromClauseRole):
  1121. if element._is_subquery:
  1122. advice = (
  1123. "Use the plain select() object without "
  1124. "calling .subquery() or .alias()."
  1125. )
  1126. else:
  1127. advice = (
  1128. "To SELECT from any FROM clause, use the .select() method."
  1129. )
  1130. else:
  1131. advice = None
  1132. return super()._raise_for_expected(
  1133. element, argname=argname, resolved=resolved, advice=advice, **kw
  1134. )
  1135. _impl_lookup = {}
  1136. for name in dir(roles):
  1137. cls = getattr(roles, name)
  1138. if name.endswith("Role"):
  1139. name = name.replace("Role", "Impl")
  1140. if name in globals():
  1141. impl = globals()[name](cls)
  1142. _impl_lookup[cls] = impl
  1143. if not TYPE_CHECKING:
  1144. ee_impl = _impl_lookup[roles.ExpressionElementRole]
  1145. for py_type in (int, bool, str, float):
  1146. _impl_lookup[roles.ExpressionElementRole[py_type]] = ee_impl