SQLAlchemy 2.1.5__py3-none-any.whl → 2.1.6__py3-none-any.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.
sqlalchemy/__init__.py CHANGED
@@ -285,7 +285,7 @@ from .types import Uuid as Uuid
285
285
  from .types import VARBINARY as VARBINARY
286
286
  from .types import VARCHAR as VARCHAR
287
287
 
288
- __version__ = "2.1.5"
288
+ __version__ = "2.1.6"
289
289
 
290
290
 
291
291
  def __go(lcls: Any) -> None:
@@ -2386,6 +2386,8 @@ class MySQLDDLCompiler(
2386
2386
  class MySQLTypeCompiler(
2387
2387
  _mariadb_shim.MariaDBTypeCompilerShim, compiler.GenericTypeCompiler
2388
2388
  ):
2389
+ dialect: MySQLDialect
2390
+
2389
2391
  def _extend_numeric(self, type_: _NumericCommonType, spec: str) -> str:
2390
2392
  "Extend a numeric-type declaration with MySQL specific extensions."
2391
2393
 
@@ -2680,9 +2682,12 @@ class MySQLTypeCompiler(
2680
2682
  ) -> str:
2681
2683
  quoted_enums = []
2682
2684
  for e in enumerated_values:
2685
+ e = e.replace("'", "''")
2686
+ if self.dialect._backslash_escapes:
2687
+ e = e.replace("\\", "\\\\")
2683
2688
  if self.dialect.identifier_preparer._double_percents:
2684
2689
  e = e.replace("%", "%%")
2685
- quoted_enums.append("'%s'" % e.replace("'", "''"))
2690
+ quoted_enums.append("'%s'" % e)
2686
2691
  return self._extend_string(
2687
2692
  type_, {}, "%s(%s)" % (name, ",".join(quoted_enums))
2688
2693
  )
sqlalchemy/engine/base.py CHANGED
@@ -1273,24 +1273,29 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]):
1273
1273
  self._transaction.close()
1274
1274
  skip_reset = True
1275
1275
  finally:
1276
- if self._dbapi_connection is not None:
1277
- conn = self._dbapi_connection
1278
-
1279
- # as we just closed the transaction, close the connection
1280
- # pool connection without doing an additional reset
1281
- if skip_reset:
1282
- cast("_ConnectionFairy", conn)._close_special(
1283
- transaction_reset=True
1284
- )
1285
- else:
1286
- conn.close()
1287
-
1276
+ try:
1277
+ if self._dbapi_connection is not None:
1278
+ conn = self._dbapi_connection
1279
+
1280
+ # as we just closed the transaction, close the connection
1281
+ # pool connection without doing an additional reset
1282
+ if skip_reset:
1283
+ cast("_ConnectionFairy", conn)._close_special(
1284
+ transaction_reset=True
1285
+ )
1286
+ else:
1287
+ conn.close()
1288
+ finally:
1288
1289
  # There is a slight chance that conn.close() may have
1289
1290
  # triggered an invalidation here in which case
1290
1291
  # _dbapi_connection would already be None, however usually
1291
1292
  # it will be non-None here and in a "closed" state.
1293
+ #
1294
+ # there is also a chance that the conn.close() here could
1295
+ # itself be interrupted, such as by a cancellation; hence a
1296
+ # second try/finally is needed as well (see #13699)
1292
1297
  self._dbapi_connection = None
1293
- self.__can_reconnect = False
1298
+ self.__can_reconnect = False
1294
1299
 
1295
1300
  # special case to handle mypy issue:
1296
1301
  # https://github.com/python/mypy/issues/20651
@@ -1774,10 +1774,12 @@ class FrozenResult(Generic[Unpack[_Ts]]):
1774
1774
  self._source_supports_scalars = result._source_supports_scalars
1775
1775
  self._attributes = result._attributes
1776
1776
 
1777
+ # use _allrows() rather than fetchall() so that AsyncResult, whose
1778
+ # fetchall() is a coroutine, may be frozen within greenlet_spawn()
1777
1779
  if self._source_supports_scalars:
1778
1780
  self.data = list(result._raw_row_iterator())
1779
1781
  else:
1780
- self.data = result.fetchall()
1782
+ self.data = result._allrows()
1781
1783
 
1782
1784
  def _rewrite_rows(self) -> Sequence[Sequence[Any]]:
1783
1785
  # used only by the orm fn merge_frozen_result
sqlalchemy/engine/url.py CHANGED
@@ -364,7 +364,11 @@ class URL(NamedTuple):
364
364
  return self._replace(**kw)
365
365
 
366
366
  def update_query_string(
367
- self, query_string: str, append: bool = False
367
+ self,
368
+ query_string: str,
369
+ append: bool = False,
370
+ *,
371
+ keep_blank_values: bool = False,
368
372
  ) -> URL:
369
373
  """Return a new :class:`_engine.URL` object with the :attr:`_engine.URL.query`
370
374
  parameter dictionary updated by the given query string.
@@ -387,6 +391,13 @@ class URL(NamedTuple):
387
391
  If left at its default of False, keys present in the given query
388
392
  parameters will replace those of the existing query string.
389
393
 
394
+ :param keep_blank_values: if True, parameters with blank values
395
+ such as ``key=`` are retained in the query dictionary as empty
396
+ strings. If left at its default of False, parameters with blank
397
+ values are omitted.
398
+
399
+ .. versionadded:: 2.1.6
400
+
390
401
  .. versionadded:: 1.4
391
402
 
392
403
  .. seealso::
@@ -396,7 +407,10 @@ class URL(NamedTuple):
396
407
  :meth:`_engine.URL.update_query_dict`
397
408
 
398
409
  """ # noqa: E501
399
- return self.update_query_pairs(parse_qsl(query_string), append=append)
410
+ return self.update_query_pairs(
411
+ parse_qsl(query_string, keep_blank_values=keep_blank_values),
412
+ append=append,
413
+ )
400
414
 
401
415
  def update_query_pairs(
402
416
  self,
@@ -836,7 +850,9 @@ class URL(NamedTuple):
836
850
  return translated
837
851
 
838
852
 
839
- def make_url(name_or_url: Union[str, URL]) -> URL:
853
+ def make_url(
854
+ name_or_url: Union[str, URL], *, keep_blank_values: bool = False
855
+ ) -> URL:
840
856
  """Given a string, produce a new URL instance.
841
857
 
842
858
  The format of the URL generally follows `RFC-1738
@@ -846,6 +862,21 @@ def make_url(name_or_url: Union[str, URL]) -> URL:
846
862
 
847
863
  If a :class:`.URL` object is passed, it is returned as is.
848
864
 
865
+ :param name_or_url: a string URL or :class:`.URL` object.
866
+
867
+ :param keep_blank_values: if True, query string parameters with blank
868
+ values such as ``key=`` are retained in the :attr:`.URL.query`
869
+ dictionary as empty strings. If left at its default of False,
870
+ parameters with blank values are omitted. Has no effect when a
871
+ :class:`.URL` object is passed.
872
+
873
+ As :func:`_sa.create_engine` parses string URLs using the default
874
+ setting, a string URL with blank values to be retained should be
875
+ parsed with :func:`.make_url` first, and the resulting :class:`.URL`
876
+ passed to :func:`_sa.create_engine`.
877
+
878
+ .. versionadded:: 2.1.6
879
+
849
880
  .. seealso::
850
881
 
851
882
  :ref:`database_urls`
@@ -853,7 +884,7 @@ def make_url(name_or_url: Union[str, URL]) -> URL:
853
884
  """
854
885
 
855
886
  if isinstance(name_or_url, str):
856
- return _parse_url(name_or_url)
887
+ return _parse_url(name_or_url, keep_blank_values=keep_blank_values)
857
888
  elif not isinstance(name_or_url, URL) and not hasattr(
858
889
  name_or_url, "_sqla_is_testing_if_this_is_a_mock_object"
859
890
  ):
@@ -864,7 +895,7 @@ def make_url(name_or_url: Union[str, URL]) -> URL:
864
895
  return name_or_url
865
896
 
866
897
 
867
- def _parse_url(name: str) -> URL:
898
+ def _parse_url(name: str, keep_blank_values: bool = False) -> URL:
868
899
  pattern = re.compile(
869
900
  r"""
870
901
  (?P<name>[\w\+]+)://
@@ -892,7 +923,9 @@ def _parse_url(name: str) -> URL:
892
923
  if components["query"] is not None:
893
924
  query = {}
894
925
 
895
- for key, value in parse_qsl(components["query"]):
926
+ for key, value in parse_qsl(
927
+ components["query"], keep_blank_values=keep_blank_values
928
+ ):
896
929
  if key in query:
897
930
  query[key] = util.to_list(query[key])
898
931
  cast("List[str]", query[key]).append(value)
@@ -9,6 +9,7 @@ from __future__ import annotations
9
9
  import operator
10
10
  from typing import Any
11
11
  from typing import AsyncIterator
12
+ from typing import Iterator
12
13
  from typing import Literal
13
14
  from typing import Optional
14
15
  from typing import overload
@@ -20,6 +21,7 @@ from typing import TypeVar
20
21
  from . import exc as async_exc
21
22
  from ... import util
22
23
  from ...engine import Result
24
+ from ...engine._result_cy import _RowData
23
25
  from ...engine.result import _NO_ROW
24
26
  from ...engine.result import _R
25
27
  from ...engine.result import _WithKeys
@@ -467,6 +469,11 @@ class AsyncResult(_WithKeys, AsyncCommon[Row[Unpack[_Ts]]]):
467
469
 
468
470
  return await greenlet_spawn(FrozenResult, self)
469
471
 
472
+ def _raw_row_iterator(self) -> Iterator[_RowData]:
473
+ # used by FrozenResult when the source result supports scalars;
474
+ # must be invoked within greenlet_spawn()
475
+ return self._real_result._raw_row_iterator()
476
+
470
477
  @overload
471
478
  def scalars(
472
479
  self: AsyncResult[_T, Unpack[TupleAny]], index: Literal[0]
@@ -494,7 +501,7 @@ class AsyncResult(_WithKeys, AsyncCommon[Row[Unpack[_Ts]]]):
494
501
  referring to this :class:`_asyncio.AsyncResult` object.
495
502
 
496
503
  """
497
- return AsyncScalarResult(self._real_result, index)
504
+ return AsyncScalarResult(self, index)
498
505
 
499
506
  def mappings(self) -> AsyncMappingResult:
500
507
  """Apply a mappings filter to returned rows, returning an instance of
@@ -505,11 +512,11 @@ class AsyncResult(_WithKeys, AsyncCommon[Row[Unpack[_Ts]]]):
505
512
  objects.
506
513
 
507
514
  :return: a new :class:`_asyncio.AsyncMappingResult` filtering object
508
- referring to the underlying :class:`_result.Result` object.
515
+ referring to this :class:`_asyncio.AsyncResult` object.
509
516
 
510
517
  """
511
518
 
512
- return AsyncMappingResult(self._real_result)
519
+ return AsyncMappingResult(self)
513
520
 
514
521
 
515
522
  class AsyncScalarResult(AsyncCommon[_R]):
@@ -532,19 +539,21 @@ class AsyncScalarResult(AsyncCommon[_R]):
532
539
 
533
540
  def __init__(
534
541
  self,
535
- real_result: Result[Unpack[TupleAny]],
542
+ result: AsyncResult[Unpack[TupleAny]],
536
543
  index: _KeyIndexType,
537
544
  ):
538
- self._real_result = real_result
545
+ # rows are fetched from the sync Result; metadata and unique state
546
+ # come from the AsyncResult, where unique() and columns() apply them
547
+ self._real_result = result._real_result
539
548
 
540
- if real_result._source_supports_scalars:
541
- self._metadata = real_result._metadata
549
+ if result._source_supports_scalars:
550
+ self._metadata = result._metadata
542
551
  self._post_creational_filter = None
543
552
  else:
544
- self._metadata = real_result._metadata._reduce([index])
553
+ self._metadata = result._metadata._reduce([index])
545
554
  self._post_creational_filter = operator.itemgetter(0)
546
555
 
547
- self._unique_filter_state = real_result._unique_filter_state
556
+ self._unique_filter_state = result._unique_filter_state
548
557
 
549
558
  def unique(
550
559
  self,
@@ -665,8 +674,11 @@ class AsyncMappingResult(_WithKeys, AsyncCommon[RowMapping]):
665
674
 
666
675
  _post_creational_filter = operator.attrgetter("_mapping")
667
676
 
668
- def __init__(self, result: Result[Unpack[TupleAny]]):
669
- self._real_result = result
677
+ def __init__(self, result: AsyncResult[Unpack[TupleAny]]):
678
+ # rows are fetched from the sync Result; metadata and unique state
679
+ # come from the AsyncResult, where unique() and columns() apply them
680
+ self._real_result = result._real_result
681
+
670
682
  self._unique_filter_state = result._unique_filter_state
671
683
  self._metadata = result._metadata
672
684
  if result._source_supports_scalars:
sqlalchemy/orm/context.py CHANGED
@@ -10,6 +10,7 @@ from __future__ import annotations
10
10
 
11
11
  import collections
12
12
  import itertools
13
+ from typing import AbstractSet
13
14
  from typing import Any
14
15
  from typing import cast
15
16
  from typing import Dict
@@ -50,6 +51,8 @@ from ..sql import visitors
50
51
  from ..sql._typing import is_dml
51
52
  from ..sql._typing import is_insert_update
52
53
  from ..sql._typing import is_select_base
54
+ from ..sql.base import _expand_cloned
55
+ from ..sql.base import _from_objects
53
56
  from ..sql.base import _select_iterables
54
57
  from ..sql.base import CacheableOptions
55
58
  from ..sql.base import CompileState
@@ -91,6 +94,7 @@ if TYPE_CHECKING:
91
94
  from ..sql.selectable import _LabelConventionCallable
92
95
  from ..sql.selectable import _SetupJoinsElement
93
96
  from ..sql.selectable import ExecutableReturnsRows
97
+ from ..sql.selectable import FromClause
94
98
  from ..sql.selectable import SelectBase
95
99
  from ..sql.type_api import TypeEngine
96
100
 
@@ -1025,6 +1029,9 @@ class FromStatement(GroupedElement, Generative, TypedReturnsRows[Unpack[_Ts]]):
1025
1029
 
1026
1030
  """
1027
1031
 
1032
+ if compiler._collect_params:
1033
+ compiler._add_to_params(self)
1034
+
1028
1035
  compile_state = self._compile_state_factory(self, compiler, **kw)
1029
1036
 
1030
1037
  toplevel = not compiler.stack
@@ -1104,6 +1111,10 @@ class _ORMSelectCompileState(_ORMCompileState, SelectState):
1104
1111
  _where_criteria = ()
1105
1112
  _having_criteria = ()
1106
1113
 
1114
+ # see SQLCompiler._enclosing_correlate_froms()
1115
+ _explicit_correlate_froms: AbstractSet[FromClause] = util.EMPTY_SET
1116
+ _implicit_correlate_froms: AbstractSet[FromClause] = util.EMPTY_SET
1117
+
1107
1118
  @classmethod
1108
1119
  def _create_orm_context(
1109
1120
  cls,
@@ -1116,6 +1127,17 @@ class _ORMSelectCompileState(_ORMCompileState, SelectState):
1116
1127
 
1117
1128
  self = cls.__new__(cls)
1118
1129
 
1130
+ if not toplevel:
1131
+ assert compiler is not None
1132
+ (
1133
+ self._explicit_correlate_froms,
1134
+ self._implicit_correlate_froms,
1135
+ ) = compiler._enclosing_correlate_froms(
1136
+ compiler.stack[-1],
1137
+ kw.get("asfrom", False),
1138
+ kw.get("lateral", False),
1139
+ )
1140
+
1119
1141
  select_statement = statement
1120
1142
 
1121
1143
  # if we are a select() that was never a legacy Query, we won't
@@ -2519,6 +2541,44 @@ class _ORMSelectCompileState(_ORMCompileState, SelectState):
2519
2541
  else:
2520
2542
  return ()
2521
2543
 
2544
+ def _get_correlated_froms(self):
2545
+ """Return the set of FROM objects that will be correlated away
2546
+ from this SELECT, given its current state.
2547
+
2548
+ This runs ahead of the final statement being generated, so the
2549
+ FROM list is derived from the ORM-level statement.
2550
+
2551
+ """
2552
+ if not self._explicit_correlate_froms and (
2553
+ not self._implicit_correlate_froms
2554
+ ):
2555
+ return util.EMPTY_SET
2556
+
2557
+ froms = self._get_froms(self.select_statement)
2558
+
2559
+ if self.correlate:
2560
+ to_correlate = [c for c in self.correlate if c is not None]
2561
+ else:
2562
+ to_correlate = None
2563
+
2564
+ display_froms = set(
2565
+ self._correlate_froms(
2566
+ froms,
2567
+ self.select_statement,
2568
+ to_correlate,
2569
+ self.correlate_except,
2570
+ self.select_statement._auto_correlate,
2571
+ self._explicit_correlate_froms,
2572
+ self._implicit_correlate_froms,
2573
+ )
2574
+ )
2575
+
2576
+ return set(
2577
+ _expand_cloned(
2578
+ _from_objects(*[f for f in froms if f not in display_froms])
2579
+ )
2580
+ )
2581
+
2522
2582
  def _adjust_for_extra_criteria(self):
2523
2583
  """Apply extra criteria filtering.
2524
2584
 
@@ -2532,13 +2592,39 @@ class _ORMSelectCompileState(_ORMCompileState, SelectState):
2532
2592
  associated with the global context.
2533
2593
 
2534
2594
  """
2595
+ # entities that are referenced only within the WHERE clause also
2596
+ # receive criteria (#13070), except when the entity is correlated
2597
+ # to an enclosing SELECT, which has the criteria applied
2598
+ # already (#13701)
2599
+ correlated_froms = (
2600
+ self._get_correlated_froms()
2601
+ if self.select_statement._where_criteria
2602
+ else util.EMPTY_SET
2603
+ )
2535
2604
  ext_infos = [
2536
2605
  fromclause._annotations.get("parententity", None)
2537
2606
  for fromclause in self.from_clauses
2538
2607
  ] + [
2539
- elem._annotations.get("parententity", None)
2540
- for where_crit in self.select_statement._where_criteria
2541
- for elem in sql_util.surface_expressions(where_crit)
2608
+ ext_info
2609
+ for elem, ext_info in [
2610
+ (elem, elem._annotations.get("parententity", None))
2611
+ for where_crit in self.select_statement._where_criteria
2612
+ for elem in sql_util.surface_expressions(where_crit)
2613
+ ]
2614
+ if ext_info
2615
+ and not (
2616
+ # if all FROMs for this expression are correlated to an
2617
+ # enclosing query, then skip adding loader criteria for the
2618
+ # entity on behalf of this element, since the actual FROM
2619
+ # clause(s) for it are not local to this subquery
2620
+ # (#13701)
2621
+ correlated_froms
2622
+ and elem._from_objects
2623
+ and all(
2624
+ correlated_froms.intersection(from_._cloned_set)
2625
+ for from_ in elem._from_objects
2626
+ )
2627
+ )
2542
2628
  ]
2543
2629
 
2544
2630
  for ext_info in ext_infos:
sqlalchemy/orm/session.py CHANGED
@@ -3523,10 +3523,17 @@ class Session(_SessionClassMethods, EventTarget):
3523
3523
  # that is replaced when the primary keys of two instances
3524
3524
  # are swapped; see test/orm/test_naturalpks.py -> test_reverse
3525
3525
  old = self.identity_map.replace(state)
3526
+
3527
+ # check the replaced state's identity without emitting
3528
+ # any SQL; an expired state such as one left over from
3529
+ # a rollback will not match and does not warn
3526
3530
  if (
3527
3531
  old is not None
3528
- and mapper._identity_key_from_state(old) == instance_key
3529
3532
  and old.obj() is not None
3533
+ and mapper._identity_key_from_state(
3534
+ old, PassiveFlag.PASSIVE_NO_FETCH
3535
+ )
3536
+ == instance_key
3530
3537
  ):
3531
3538
  util.warn(
3532
3539
  "Identity map already had an identity for %s, "
sqlalchemy/pool/base.py CHANGED
@@ -1045,7 +1045,14 @@ def _finalize_fairy(
1045
1045
  if not isinstance(e, Exception):
1046
1046
  # a cancellation or similar propagates from here, so the
1047
1047
  # checkin() below is not reached; return the record now,
1048
- # rather than leaving it to garbage collection of the fairy
1048
+ # rather than leaving it to garbage collection of the fairy.
1049
+ # the cleanup of the fairy below is not reached either, so
1050
+ # detach it from the record first, so that it can't act on
1051
+ # the record once that's checked out again. see #13699
1052
+ if fairy is not None:
1053
+ fairy._finalizer.detach()
1054
+ fairy.dbapi_connection = None # type: ignore[assignment]
1055
+ fairy._connection_record = None
1049
1056
  if connection_record:
1050
1057
  connection_record._checkin_failed(e)
1051
1058
  raise
@@ -36,6 +36,7 @@ import operator
36
36
  import re
37
37
  from time import perf_counter
38
38
  import typing
39
+ from typing import AbstractSet
39
40
  from typing import Any
40
41
  from typing import Callable
41
42
  from typing import cast
@@ -1920,6 +1921,19 @@ class SQLCompiler(Compiled):
1920
1921
  if value is not None
1921
1922
  }
1922
1923
 
1924
+ @util.memoized_property
1925
+ def _expanded_bind_names_reserved(self) -> FrozenSet[str]:
1926
+ """Names that the individual elements of an expanding parameter
1927
+ may not take when the parameter is expanded at execution time.
1928
+
1929
+ This is every bound parameter name in the statement, both in its
1930
+ compiled and in its escaped form. See :ticket:`13695`.
1931
+
1932
+ """
1933
+ return frozenset(self.bind_names.values()).union(
1934
+ self.escaped_bind_names, self.escaped_bind_names.values()
1935
+ )
1936
+
1923
1937
  def is_subquery(self):
1924
1938
  return len(self.stack) > 1
1925
1939
 
@@ -2189,6 +2203,16 @@ class SQLCompiler(Compiled):
2189
2203
  replacement_expressions: Dict[str, Any] = {}
2190
2204
  to_update_sets: Dict[str, Any] = {}
2191
2205
 
2206
+ # names that the elements of expanding parameters can't take, as
2207
+ # they are in use either by other parameters in the statement or by
2208
+ # elements of expanding parameters that were already expanded.
2209
+ # copied into a mutable set, as it is added to within this method's
2210
+ # scope to track the additional element names generated for this
2211
+ # execution
2212
+ expanded_taken_names: Set[str] = set(
2213
+ self._expanded_bind_names_reserved
2214
+ )
2215
+
2192
2216
  # notes:
2193
2217
  # *unescaped* parameter names in:
2194
2218
  # self.bind_names, self.binds, self._bind_processors, self.positiontup
@@ -2239,7 +2263,10 @@ class SQLCompiler(Compiled):
2239
2263
  values = parameters.pop(name)
2240
2264
 
2241
2265
  leep_res = self._literal_execute_expanding_parameter(
2242
- escaped_name, parameter, values
2266
+ escaped_name,
2267
+ parameter,
2268
+ values,
2269
+ taken_names=expanded_taken_names,
2243
2270
  )
2244
2271
  to_update, replacement_expr = leep_res
2245
2272
 
@@ -2249,17 +2276,16 @@ class SQLCompiler(Compiled):
2249
2276
  if not parameter.literal_execute:
2250
2277
  parameters.update(to_update)
2251
2278
  if parameter.type._is_tuple_type:
2252
- assert values is not None
2253
- new_processors.update(
2254
- (
2255
- "%s_%s_%s" % (name, i, j),
2256
- tuple_processors[name][j - 1],
2279
+ if name in tuple_processors:
2280
+ # to_update is flattened row by row, one entry
2281
+ # per element of each tuple
2282
+ element_processors = tuple_processors[name]
2283
+ num = len(element_processors)
2284
+ new_processors.update(
2285
+ (key, element_processors[idx % num])
2286
+ for idx, (key, _) in enumerate(to_update)
2287
+ if element_processors[idx % num] is not None
2257
2288
  )
2258
- for i, tuple_element in enumerate(values, 1)
2259
- for j, _ in enumerate(tuple_element, 1)
2260
- if name in tuple_processors
2261
- and tuple_processors[name][j - 1] is not None
2262
- )
2263
2289
  else:
2264
2290
  new_processors.update(
2265
2291
  (key, single_processors[name])
@@ -3554,7 +3580,22 @@ class SQLCompiler(Compiled):
3554
3580
 
3555
3581
  return (), replacement_expression
3556
3582
 
3557
- def _literal_execute_expanding_parameter(self, name, parameter, values):
3583
+ def _literal_execute_expanding_parameter(
3584
+ self, name, parameter, values, *, taken_names
3585
+ ):
3586
+ """Render the per-element bound parameters of an expanding
3587
+ parameter.
3588
+
3589
+ ``taken_names`` is a set of names the elements may not use; each
3590
+ name generated is checked against it and added to it. The element
3591
+ names are normally ``<name>_<n>``, or ``<name>_<n>_<m>`` for tuples,
3592
+ which may be the name of another parameter in the same statement,
3593
+ e.g. a parameter ``x_1`` alongside the expanding parameter ``x``, or
3594
+ the element of another expanding parameter. A colliding name is
3595
+ uniquified with a counter, rather than the element value replacing
3596
+ the value of the other parameter. See :ticket:`13695`.
3597
+
3598
+ """
3558
3599
  if parameter.literal_execute:
3559
3600
  return self._literal_execute_expanding_parameter_literal_binds(
3560
3601
  parameter, values
@@ -3585,6 +3626,20 @@ class SQLCompiler(Compiled):
3585
3626
  def _render_bindtemplate(name):
3586
3627
  return bind_template % {"name": name}
3587
3628
 
3629
+ def _unique_name(key):
3630
+ if key in taken_names:
3631
+ base = key
3632
+ counter = 0
3633
+ while key in taken_names:
3634
+ counter += 1
3635
+ # double underscore keeps the suffix out of the
3636
+ # <name>_<n> form generated for anonymous names and
3637
+ # for the elements themselves, so a renamed element
3638
+ # won't take a name another element would generate
3639
+ key = "%s__%d" % (base, counter)
3640
+ taken_names.add(key)
3641
+ return key
3642
+
3588
3643
  if not values:
3589
3644
  to_update = []
3590
3645
  if typ_dialect_impl._is_tuple_type:
@@ -3603,7 +3658,7 @@ class SQLCompiler(Compiled):
3603
3658
  ):
3604
3659
  assert not typ_dialect_impl._is_array
3605
3660
  to_update = [
3606
- ("%s_%s_%s" % (name, i, j), value)
3661
+ (_unique_name("%s_%s_%s" % (name, i, j)), value)
3607
3662
  for i, tuple_element in enumerate(values, 1)
3608
3663
  for j, value in enumerate(tuple_element, 1)
3609
3664
  ]
@@ -3624,7 +3679,7 @@ class SQLCompiler(Compiled):
3624
3679
  )
3625
3680
  else:
3626
3681
  to_update = [
3627
- ("%s_%s" % (name, i), value)
3682
+ (_unique_name("%s_%s" % (name, i)), value)
3628
3683
  for i, value in enumerate(values, 1)
3629
3684
  ]
3630
3685
  replacement_expression = ", ".join(
@@ -5071,24 +5126,44 @@ class SQLCompiler(Compiled):
5071
5126
  toplevel = not self.stack
5072
5127
  entry = self._default_stack_entry if toplevel else self.stack[-1]
5073
5128
 
5074
- compile_state = select_stmt._compile_state_factory(select_stmt, self)
5129
+ compile_state = select_stmt._compile_state_factory(
5130
+ select_stmt, self, asfrom=asfrom, lateral=lateral
5131
+ )
5132
+
5133
+ explicit, implicit = self._enclosing_correlate_froms(
5134
+ entry, asfrom, lateral
5135
+ )
5136
+ return compile_state._get_display_froms(
5137
+ explicit_correlate_froms=explicit,
5138
+ implicit_correlate_froms=implicit,
5139
+ )
5140
+
5141
+ def _enclosing_correlate_froms(
5142
+ self, entry: _CompilerStackEntry, asfrom: bool, lateral: bool
5143
+ ) -> Tuple[AbstractSet[FromClause], AbstractSet[FromClause]]:
5144
+ """Given the stack entry of an enclosing statement, return the
5145
+ explicit and implicit correlate FROMs for a SELECT that's embedded
5146
+ within it, as passed to :meth:`.SelectState._get_display_froms`.
5075
5147
 
5148
+ explicit_correlate_froms: FROMs of enclosing SELECTs that this SELECT
5149
+ may correlate to when explicit correlation is used, i.e.
5150
+ :meth:`.Select.correlate` or :meth:`.Select.correlate_except`.
5151
+ Includes the FROMs of all enclosing SELECTs.
5152
+
5153
+ implicit_correlate_froms: FROMs of enclosing SELECTs that this SELECT
5154
+ will correlate to automatically, assuming auto-correlation is in
5155
+ effect. Includes only the FROMs of the immediately enclosing SELECT,
5156
+ and is empty if this SELECT is a subquery in a FROM clause that's not
5157
+ LATERAL. Is always a subset of explicit_correlate_froms.
5158
+
5159
+ """
5076
5160
  correlate_froms = entry["correlate_froms"]
5077
5161
  asfrom_froms = entry["asfrom_froms"]
5078
5162
 
5079
5163
  if asfrom and not lateral:
5080
- froms = compile_state._get_display_froms(
5081
- explicit_correlate_froms=correlate_froms.difference(
5082
- asfrom_froms
5083
- ),
5084
- implicit_correlate_froms=(),
5085
- )
5164
+ return correlate_froms.difference(asfrom_froms), util.EMPTY_SET
5086
5165
  else:
5087
- froms = compile_state._get_display_froms(
5088
- explicit_correlate_froms=correlate_froms,
5089
- implicit_correlate_froms=asfrom_froms,
5090
- )
5091
- return froms
5166
+ return correlate_froms, asfrom_froms
5092
5167
 
5093
5168
  translate_select_structure: Any = None
5094
5169
  """if not ``None``, should be a callable which accepts ``(select_stmt,
@@ -5126,7 +5201,7 @@ class SQLCompiler(Compiled):
5126
5201
  kwargs["within_columns_clause"] = False
5127
5202
 
5128
5203
  compile_state = select_stmt._compile_state_factory(
5129
- select_stmt, self, **kwargs
5204
+ select_stmt, self, asfrom=asfrom, lateral=lateral, **kwargs
5130
5205
  )
5131
5206
  kwargs["ambiguous_table_name_map"] = (
5132
5207
  compile_state._ambiguous_table_name_map
@@ -5157,7 +5232,11 @@ class SQLCompiler(Compiled):
5157
5232
  select_stmt = new_select_stmt
5158
5233
 
5159
5234
  compile_state = select_stmt._compile_state_factory(
5160
- select_stmt, self, **kwargs
5235
+ select_stmt,
5236
+ self,
5237
+ asfrom=asfrom,
5238
+ lateral=lateral,
5239
+ **kwargs,
5161
5240
  )
5162
5241
  select_stmt = compile_state.statement
5163
5242
 
@@ -5335,9 +5414,6 @@ class SQLCompiler(Compiled):
5335
5414
  def _setup_select_stack(
5336
5415
  self, select, compile_state, entry, asfrom, lateral, compound_index
5337
5416
  ):
5338
- correlate_froms = entry["correlate_froms"]
5339
- asfrom_froms = entry["asfrom_froms"]
5340
-
5341
5417
  if compound_index == 0:
5342
5418
  entry["select_0"] = select
5343
5419
  elif compound_index:
@@ -5358,21 +5434,18 @@ class SQLCompiler(Compiled):
5358
5434
  )
5359
5435
  )
5360
5436
 
5361
- if asfrom and not lateral:
5362
- froms = compile_state._get_display_froms(
5363
- explicit_correlate_froms=correlate_froms.difference(
5364
- asfrom_froms
5365
- ),
5366
- implicit_correlate_froms=(),
5367
- )
5368
- else:
5369
- froms = compile_state._get_display_froms(
5370
- explicit_correlate_froms=correlate_froms,
5371
- implicit_correlate_froms=asfrom_froms,
5372
- )
5437
+ explicit, implicit = self._enclosing_correlate_froms(
5438
+ entry, asfrom, lateral
5439
+ )
5440
+ froms = compile_state._get_display_froms(
5441
+ explicit_correlate_froms=explicit,
5442
+ implicit_correlate_froms=implicit,
5443
+ )
5373
5444
 
5374
5445
  new_correlate_froms = set(_from_objects(*froms))
5375
- all_correlate_froms = new_correlate_froms.union(correlate_froms)
5446
+ all_correlate_froms = new_correlate_froms.union(
5447
+ entry["correlate_froms"]
5448
+ )
5376
5449
 
5377
5450
  new_entry: _CompilerStackEntry = {
5378
5451
  "asfrom_froms": new_correlate_froms,
sqlalchemy/sql/ddl.py CHANGED
@@ -682,11 +682,11 @@ class CreateTableAs(DialectKWArgs, _TableViaSelect):
682
682
  conn.execute(cas)
683
683
 
684
684
  # or alternatively, invoke metadata.create_all()
685
- some_metdata.create_all(engine)
685
+ some_metadata.create_all(engine)
686
686
 
687
687
  # drop is performed in the usual way, via drop_all
688
688
  # or table.drop()
689
- some_metdata.drop_all(engine)
689
+ some_metadata.drop_all(engine)
690
690
 
691
691
  For detailed background on :class:`.CreateTableAs` see
692
692
  :ref:`metadata_create_table_as`.
@@ -792,11 +792,11 @@ class CreateView(DialectKWArgs, _TableViaSelect):
792
792
  conn.execute(create_view)
793
793
 
794
794
  # or alternatively, invoke metadata.create_all()
795
- some_metdata.create_all(engine)
795
+ some_metadata.create_all(engine)
796
796
 
797
797
  # drop is performed in the usual way, via drop_all
798
798
  # or table.drop() (will emit DROP VIEW)
799
- some_metdata.drop_all(engine)
799
+ some_metadata.drop_all(engine)
800
800
 
801
801
  For detailed background on :class:`.CreateView` see
802
802
  :ref:`metadata_create_view`.
sqlalchemy/sql/dml.py CHANGED
@@ -69,6 +69,7 @@ from .selectable import SelectLabelStyle
69
69
  from .selectable import TableClause
70
70
  from .selectable import TypedReturnsRows
71
71
  from .sqltypes import NullType
72
+ from .visitors import _TraverseInternalsType
72
73
  from .visitors import InternalTraversal
73
74
  from .. import exc
74
75
  from .. import util
@@ -436,6 +437,18 @@ class UpdateBase(
436
437
  _supplemental_returning: Optional[Tuple[_ColumnsClauseElement, ...]] = None
437
438
  _returning: Tuple[_ColumnsClauseElement, ...] = ()
438
439
 
440
+ _return_defaults_traverse_internals: _TraverseInternalsType = [
441
+ ("_return_defaults", InternalTraversal.dp_boolean),
442
+ (
443
+ "_return_defaults_columns",
444
+ InternalTraversal.dp_clauseelement_tuple,
445
+ ),
446
+ (
447
+ "_supplemental_returning",
448
+ InternalTraversal.dp_clauseelement_tuple,
449
+ ),
450
+ ]
451
+
439
452
  is_dml = True
440
453
 
441
454
  def _generate_fromclause_column_proxies(
@@ -1258,17 +1271,13 @@ class Insert(ValuesBase, HasSyntaxExtensions[Literal["post_values"]]):
1258
1271
  ("_post_values_clause", InternalTraversal.dp_clauseelement),
1259
1272
  ("_returning", InternalTraversal.dp_clauseelement_tuple),
1260
1273
  ("_hints", InternalTraversal.dp_table_hint_list),
1261
- ("_return_defaults", InternalTraversal.dp_boolean),
1262
- (
1263
- "_return_defaults_columns",
1264
- InternalTraversal.dp_clauseelement_tuple,
1265
- ),
1274
+ ("_sort_by_parameter_order", InternalTraversal.dp_boolean),
1266
1275
  (
1267
- "_supplemental_returning",
1268
- InternalTraversal.dp_clauseelement_tuple,
1276
+ "include_insert_from_select_defaults",
1277
+ InternalTraversal.dp_boolean,
1269
1278
  ),
1270
- ("_sort_by_parameter_order", InternalTraversal.dp_boolean),
1271
1279
  ]
1280
+ + UpdateBase._return_defaults_traverse_internals
1272
1281
  + HasPrefixes._has_prefixes_traverse_internals
1273
1282
  + DialectKWArgs._dialect_kwargs_traverse_internals
1274
1283
  + ExecutableStatement._executable_traverse_internals
@@ -1661,17 +1670,9 @@ class Update(
1661
1670
  ("_values", InternalTraversal.dp_dml_values),
1662
1671
  ("_returning", InternalTraversal.dp_clauseelement_tuple),
1663
1672
  ("_hints", InternalTraversal.dp_table_hint_list),
1664
- ("_return_defaults", InternalTraversal.dp_boolean),
1665
1673
  ("_post_criteria_clause", InternalTraversal.dp_clauseelement),
1666
- (
1667
- "_return_defaults_columns",
1668
- InternalTraversal.dp_clauseelement_tuple,
1669
- ),
1670
- (
1671
- "_supplemental_returning",
1672
- InternalTraversal.dp_clauseelement_tuple,
1673
- ),
1674
1674
  ]
1675
+ + UpdateBase._return_defaults_traverse_internals
1675
1676
  + HasPrefixes._has_prefixes_traverse_internals
1676
1677
  + DialectKWArgs._dialect_kwargs_traverse_internals
1677
1678
  + ExecutableStatement._executable_traverse_internals
@@ -1874,6 +1875,7 @@ class Delete(
1874
1875
  ("_hints", InternalTraversal.dp_table_hint_list),
1875
1876
  ("_post_criteria_clause", InternalTraversal.dp_clauseelement),
1876
1877
  ]
1878
+ + UpdateBase._return_defaults_traverse_internals
1877
1879
  + HasPrefixes._has_prefixes_traverse_internals
1878
1880
  + DialectKWArgs._dialect_kwargs_traverse_internals
1879
1881
  + ExecutableStatement._executable_traverse_internals
@@ -5088,32 +5088,55 @@ class SelectState(util.MemoizedSlots, CompileState):
5088
5088
  correlating.
5089
5089
 
5090
5090
  """
5091
+ statement = self.statement
5092
+ return self._correlate_froms(
5093
+ self.froms,
5094
+ statement,
5095
+ statement._correlate,
5096
+ statement._correlate_except,
5097
+ statement._auto_correlate,
5098
+ explicit_correlate_froms,
5099
+ implicit_correlate_froms,
5100
+ )
5101
+
5102
+ @classmethod
5103
+ def _correlate_froms(
5104
+ cls,
5105
+ froms: List[FromClause],
5106
+ statement: Select[Unpack[TupleAny]],
5107
+ to_correlate: Optional[Sequence[FromClause]],
5108
+ to_correlate_except: Optional[Sequence[FromClause]],
5109
+ auto_correlate: bool,
5110
+ explicit_correlate_froms: Optional[Sequence[FromClause]],
5111
+ implicit_correlate_froms: Optional[Sequence[FromClause]],
5112
+ ) -> List[FromClause]:
5113
+ """Given a list of FROM clauses and correlation settings, return
5114
+ the list of FROM clauses that remain after correlation.
5091
5115
 
5092
- froms = self.froms
5116
+ This is the implementation for :meth:`.SelectState._get_display_froms`
5117
+ that is also used by the ORM, which needs to know which FROM clauses
5118
+ will be correlated before it has generated the final statement.
5093
5119
 
5094
- if self.statement._correlate:
5095
- to_correlate = self.statement._correlate
5096
- if to_correlate:
5097
- to_remove = _cloned_intersection(
5098
- _cloned_intersection(
5099
- froms, explicit_correlate_froms or ()
5100
- ),
5101
- to_correlate,
5102
- )
5103
- froms = [f for f in froms if f not in to_remove]
5120
+ For ``explicit_correlate_froms`` and ``implicit_correlate_froms``,
5121
+ see :meth:`.SQLCompiler._enclosing_correlate_froms`.
5104
5122
 
5105
- if self.statement._correlate_except is not None:
5123
+ """
5124
+
5125
+ if to_correlate:
5126
+ to_remove = _cloned_intersection(
5127
+ _cloned_intersection(froms, explicit_correlate_froms or ()),
5128
+ to_correlate,
5129
+ )
5130
+ froms = [f for f in froms if f not in to_remove]
5131
+
5132
+ if to_correlate_except is not None:
5106
5133
  to_remove = _cloned_difference(
5107
5134
  _cloned_intersection(froms, explicit_correlate_froms or ()),
5108
- self.statement._correlate_except,
5135
+ to_correlate_except,
5109
5136
  )
5110
5137
  froms = [f for f in froms if f not in to_remove]
5111
5138
 
5112
- if (
5113
- self.statement._auto_correlate
5114
- and implicit_correlate_froms
5115
- and len(froms) > 1
5116
- ):
5139
+ if auto_correlate and implicit_correlate_froms and len(froms) > 1:
5117
5140
  to_remove = _cloned_intersection(froms, implicit_correlate_froms)
5118
5141
  froms = [f for f in froms if f not in to_remove]
5119
5142
 
@@ -5124,7 +5147,7 @@ class SelectState(util.MemoizedSlots, CompileState):
5124
5147
  "due to auto-correlation; "
5125
5148
  "specify correlate(<tables>) "
5126
5149
  "to control correlation "
5127
- "manually." % self.statement
5150
+ "manually." % statement
5128
5151
  )
5129
5152
 
5130
5153
  return froms
@@ -1046,6 +1046,8 @@ def class_hierarchy(cls):
1046
1046
  Fibs slightly: subclasses of builtin types are not returned. Thus
1047
1047
  class_hierarchy(class A(object)) returns (A, object), not A plus every
1048
1048
  class systemwide that derives from object.
1049
+ Likewise, class_hierarchy(class A(Generic[T])) returns
1050
+ (A, Generic, object), not every class systemwide that derives from Generic.
1049
1051
 
1050
1052
  """
1051
1053
 
@@ -1059,7 +1061,11 @@ def class_hierarchy(cls):
1059
1061
  process.append(b)
1060
1062
  hier.add(b)
1061
1063
 
1062
- if c.__module__ == "builtins" or not hasattr(c, "__subclasses__"):
1064
+ if (
1065
+ c is Generic
1066
+ or c.__module__ == "builtins"
1067
+ or not hasattr(c, "__subclasses__")
1068
+ ):
1063
1069
  continue
1064
1070
 
1065
1071
  for s in [
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: SQLAlchemy
3
- Version: 2.1.5
3
+ Version: 2.1.6
4
4
  Summary: Database Abstraction Library
5
5
  Author-email: Mike Bayer <mike_mp@zzzcomputing.com>
6
6
  License-Expression: MIT
@@ -153,8 +153,7 @@ Major SQLAlchemy features include:
153
153
  an extensible Python-based SQL expression
154
154
  language, schema metadata, connection pooling,
155
155
  type coercion, and custom types.
156
- * All primary and foreign key constraints are
157
- assumed to be composite and natural. Surrogate
156
+ * Primary and foreign key constraints may be composite and natural. Surrogate
158
157
  integer primary keys are of course still the
159
158
  norm, but SQLAlchemy never assumes or hardcodes
160
159
  to this model.
@@ -1,4 +1,4 @@
1
- sqlalchemy/__init__.py,sha256=Hnbd58adinVx0ixPexLwMYDC8VEemlyvjSGs_dwWw4M,13562
1
+ sqlalchemy/__init__.py,sha256=7wWqnfydTy9a9U0rJ5_9j1FcdJFh6dg1f9SXxDYOQzo,13562
2
2
  sqlalchemy/events.py,sha256=vEDW04X_PMhMw5y0_95tbEzht3wua8_gnkMBJstYNRw,525
3
3
  sqlalchemy/exc.py,sha256=CKyzx9WSeWTYxueZLAtTFpZTNKSon0YlpGt9v-C8dl8,27503
4
4
  sqlalchemy/inspection.py,sha256=2mcgybcOVuQDB2bSIhwidrMteP9qOpEbmehyT2lrnt8,5661
@@ -26,7 +26,7 @@ sqlalchemy/dialects/mysql/__init__.py,sha256=xOiKZDkLvsuyjJxYk1Hp_jwePmTBd2Sw312
26
26
  sqlalchemy/dialects/mysql/_mariadb_shim.py,sha256=3RyOxZDknEojK0hpYp9_u3lHOOtmd6tQf0jhgwsVPM0,10819
27
27
  sqlalchemy/dialects/mysql/aiomysql.py,sha256=EY0nNh13OixGIMB6rIYqzPr5JTq5QJwkkrnlPY7LIK4,8309
28
28
  sqlalchemy/dialects/mysql/asyncmy.py,sha256=LY29o8L4t3d2IU6FD4_At9utbHU9Wsi2-Kr-sKbFceM,7680
29
- sqlalchemy/dialects/mysql/base.py,sha256=EZl0wlZoJTWHTEWmgL-J8cyJPkMntEmCeJ9p5tkCDP8,135863
29
+ sqlalchemy/dialects/mysql/base.py,sha256=SbDV5qT_rDEZvqRHW8H5FCGr_1IyhZDw-wHZLGSbl60,136000
30
30
  sqlalchemy/dialects/mysql/cymysql.py,sha256=GSoPEjug8UXoNxatfhXqC_LhL970arpzrZIItOnvpos,3216
31
31
  sqlalchemy/dialects/mysql/dml.py,sha256=gyRfFRoKgZz16YF7kgykp_EH2nvIx2LS4XK0L3JIdQc,9560
32
32
  sqlalchemy/dialects/mysql/enumerated.py,sha256=44aqHgDmso9aIcax3hrLZBQdUS3kHrPNMw57s_DDM7w,10215
@@ -84,7 +84,7 @@ sqlalchemy/engine/_processors_cy.py,sha256=Q68s_s1zINR4nFQCfUfMJqjdRWI-J2BIF01tp
84
84
  sqlalchemy/engine/_result_cy.py,sha256=Lk65cmkNwSM0tDRBFHCMB8mdMmaAPjP-LY9L6qwdRqo,24006
85
85
  sqlalchemy/engine/_row_cy.py,sha256=GUX53624m7KpLOTQhsi5aMHv-ypdB4caWMQPGkuAIC4,7413
86
86
  sqlalchemy/engine/_util_cy.py,sha256=AicwKLv6IuJ46WNVhEkT0MUPEFS5z8ltxKKTIA_HyNI,4504
87
- sqlalchemy/engine/base.py,sha256=No50TjNw8uWfPug5CAgWQjLe6IIA29sZUfgyUEMdED0,124432
87
+ sqlalchemy/engine/base.py,sha256=NwGhPNQTiO0999tIPJmNrVlJR1cWKfLALpe4Ggg-qcY,124749
88
88
  sqlalchemy/engine/characteristics.py,sha256=QctD35XaPso4brk2W8zQmdomMkRRV6X7vbeo96eUvA4,4768
89
89
  sqlalchemy/engine/create.py,sha256=6iVLjpTt3DcYKwdlwkWZu_Q0DOd2xbXYJt2Zf62oais,34245
90
90
  sqlalchemy/engine/cursor.py,sha256=B5NmeqIEsOiPU8QaE4dXh7s1cSp2_5erukysuKs7ipo,85474
@@ -94,10 +94,10 @@ sqlalchemy/engine/interfaces.py,sha256=IKYAaYa-iA44O3bsxsmhyNWwIf3FToX7Wx8N-I9xD
94
94
  sqlalchemy/engine/mock.py,sha256=i9J-z0NsL78VlqC85MRgo5SNNQU256UtEqficO3DCwY,4155
95
95
  sqlalchemy/engine/processors.py,sha256=uh6xb1ajvSzJufQDG2DmmMeP0VbgaeSHZOJPBSN3mwU,2710
96
96
  sqlalchemy/engine/reflection.py,sha256=vbRdfQ00pekzzdC3mwL6gwZ8iFnsVIbiawvDzoXTXBc,77136
97
- sqlalchemy/engine/result.py,sha256=Z1NMmi3t_ihv5kCLSU4WajyMBhRaCdGQtW3lhWeTB28,66166
97
+ sqlalchemy/engine/result.py,sha256=4a1leqUbZCGJ0eXDeB47_rdDwDIzJbDlVKkvBKeqYVU,66316
98
98
  sqlalchemy/engine/row.py,sha256=8LTxWWUKiDerzelGRRNtXe1S66nvcrED4hyJ3kUO9cI,12091
99
99
  sqlalchemy/engine/strategies.py,sha256=EUOp1y78tDlpbC2J9XJnyDMH-lVjusFBx_39zCh1khE,439
100
- sqlalchemy/engine/url.py,sha256=57sVfPuku1qweg2UY2Js7QYd-mHRgOrdLGXP82V-4UA,31025
100
+ sqlalchemy/engine/url.py,sha256=BYgnzXVa15FGaiXsW0_MKd5OkOU4fVSNHXuBd8rjs5g,32295
101
101
  sqlalchemy/engine/util.py,sha256=dyPzgmZbPmnVa1eKCTammVdjLUgevNwvBuArAlBuTd4,5702
102
102
  sqlalchemy/event/__init__.py,sha256=DfSYrhLMf1nrCnEBeKaZT4bJkksge2cY2Tg506E41mU,1066
103
103
  sqlalchemy/event/api.py,sha256=s1qCAQ0yxC3W1erIvTt79QoEvOYo4u44xostJYaBWOs,8109
@@ -121,7 +121,7 @@ sqlalchemy/ext/asyncio/__init__.py,sha256=0MnGUog_nAVA71tE0IAiyqVbOn2Dpt71QpMAf5
121
121
  sqlalchemy/ext/asyncio/base.py,sha256=xglkFz_OXJvwEirKp0_dgL45nKkgkM7ayBuQ4OhIi7Q,10137
122
122
  sqlalchemy/ext/asyncio/engine.py,sha256=YljEm1OndgZFLzTIJpYDeWu3cXD1H-zex2197AEJE2M,49151
123
123
  sqlalchemy/ext/asyncio/exc.py,sha256=XiR-wyLJGuYNwL7yNrjmNq_RvfatH7aU8iXFeF4t-28,817
124
- sqlalchemy/ext/asyncio/result.py,sha256=MkwK2VAJhJuYKpUEHSxqkUGZYyrMiemureuJwERu6Gg,31714
124
+ sqlalchemy/ext/asyncio/result.py,sha256=EPdEY0Iw50p7cSCh2POkmI-MzupWQqLbpW5ismmf3aE,32296
125
125
  sqlalchemy/ext/asyncio/scoping.py,sha256=waZ7UY7dXfyPKbhVUiPjcDGGs3H1axSSm9x4ltY2c18,58731
126
126
  sqlalchemy/ext/asyncio/session.py,sha256=-7SvcVsoaQLzAgQqCQP6Qc3h-s1RA-S_kCWzjMXqbbk,74747
127
127
  sqlalchemy/ext/declarative/__init__.py,sha256=wrIs8z6am8-rSwDYwoxZntw_3T2Dj_28NbyODnDxA8s,1818
@@ -136,7 +136,7 @@ sqlalchemy/orm/base.py,sha256=IM8QpIF_rKpslfEa3bpZzL2igw_0KJhJ6FJZPvDYq64,30272
136
136
  sqlalchemy/orm/bulk_persistence.py,sha256=RXmWN0DaLGtSbSAhgNAQW_QMOGT5l0BCPA3AhMtwQhY,74414
137
137
  sqlalchemy/orm/clsregistry.py,sha256=dmIYdM2VTyLVLYiale_x9-JGSK6GpQ0JOqsZuxfSfQE,20241
138
138
  sqlalchemy/orm/collections.py,sha256=sc-KrVjRZ1EKArBPn2lqmH9QX7HKr6d2oX0fPV5a4h8,50026
139
- sqlalchemy/orm/context.py,sha256=F1poIa-NftQTO_cNUfSnbJKjbPQs9kWy6tBEyznTD_8,120868
139
+ sqlalchemy/orm/context.py,sha256=U8NhYbD9oItGws6od3PfN5hBjXNEOKGjSq-2ti7SY00,123933
140
140
  sqlalchemy/orm/decl_api.py,sha256=CqKg0SPyvYb2zWK4rVZvScWAhGsT5LEqXWYlkR3aK_w,79344
141
141
  sqlalchemy/orm/decl_base.py,sha256=ZbYvSZfSn5l1GPwuX8wXoQiW7SVgJ9Nw4qfMBIDNo6Y,91508
142
142
  sqlalchemy/orm/dependency.py,sha256=gqUUJi7LMF2RIEvq7hw_w-WfbpW8CXzSaDW5QTW5NlQ,47739
@@ -157,7 +157,7 @@ sqlalchemy/orm/properties.py,sha256=W-6JnQ5QCGP3OiEwEoNHowFMbhtGpZWXXakUEUJec3g,
157
157
  sqlalchemy/orm/query.py,sha256=kltlyhiUqSbfh6dfSpB30n3OrdMTTjA0q4kuQMDZLX8,121505
158
158
  sqlalchemy/orm/relationships.py,sha256=huDSvUgKxKms5zcj3jWMKBqoEazs0-vjUrn1Hp2enXM,133724
159
159
  sqlalchemy/orm/scoping.py,sha256=eGXEv3sthVrBau1t7XCy-Irq9DA1uc7vpqw0IulAwjk,81158
160
- sqlalchemy/orm/session.py,sha256=6-nextPWqVjwA7hW79oozm6pXbGHXF7Js3HLfJcgyUQ,203522
160
+ sqlalchemy/orm/session.py,sha256=E-7R3YWPH1WzLAOhG0ikMmb_bvhTMO9wGt3hQAQK634,203823
161
161
  sqlalchemy/orm/state.py,sha256=IxVE17w39HuK_U3vYKEGry-TE53ptfdCVuZmHjKn2MM,38600
162
162
  sqlalchemy/orm/state_changes.py,sha256=zbtHp9OaZhU80uTQSPyiDyQuCOQZsYil4mdiRa0Lvrw,6809
163
163
  sqlalchemy/orm/strategies.py,sha256=jJxPsfhUR_PGNogmrxQ83XiU53oOb9SvqDXphOIbEes,124439
@@ -167,7 +167,7 @@ sqlalchemy/orm/unitofwork.py,sha256=ewxWWxVZw62LndJL0K_L3VFaACe_9m7ub0w-j2vyIjU,
167
167
  sqlalchemy/orm/util.py,sha256=sQDShyvhf3Lyy3vGRNcG6aROsBppFidALgFk2hgsqVw,87079
168
168
  sqlalchemy/orm/writeonly.py,sha256=LAbF6qIkV6agnH6f9piLFdsPvdewLsvhEagNebd-Kig,23096
169
169
  sqlalchemy/pool/__init__.py,sha256=h3EJgaBrR5w7aTqbf9cH8j3qf64jKj4fGe7nQ61jKNg,1714
170
- sqlalchemy/pool/base.py,sha256=PATgMCc8HI95SCtpIi18QsEAxAaAL6xnviHFSQHCmZ4,55614
170
+ sqlalchemy/pool/base.py,sha256=yP_wXm5On9in-rHXQH_LJKoBdJ-7a7u3Sy8nRrMSf6s,56051
171
171
  sqlalchemy/pool/events.py,sha256=Fma2EvUl8XfbnPEYsRYmarRtumYJmpFTExxvO4bmOmk,13455
172
172
  sqlalchemy/pool/impl.py,sha256=18axjQPyIIVr8QviQSMd05ok71j6YYj5nYgzSuCljg4,19108
173
173
  sqlalchemy/sql/__init__.py,sha256=bQP61xcHeqWHjKiHbA-X3rNakpBKQO2cDnsZ_DSHemk,6438
@@ -184,11 +184,11 @@ sqlalchemy/sql/annotation.py,sha256=gkFPOq3qGo6fahIxTwXgxCdcEyiD8W4CH0q01d1E0mo,
184
184
  sqlalchemy/sql/base.py,sha256=1xkh7mgC25GVZS8tczZbwDAxRvdumoaW3UPrJXbynbQ,98615
185
185
  sqlalchemy/sql/cache_key.py,sha256=OihJqOVsdU0F_IShr0FIptTRHtIlM1UIZ_5LR8LQd0Q,28872
186
186
  sqlalchemy/sql/coercions.py,sha256=XyV6wyiIHHD6ViGdZhLMQ8OVWNk4_LyBvv15t504UYI,39144
187
- sqlalchemy/sql/compiler.py,sha256=9vNcKzGXY-gqOl_R42tzwQR0V0MjBNn79OmJmjiVjQo,301830
187
+ sqlalchemy/sql/compiler.py,sha256=Y7xWkxvUobvd3LTPmjd4EnP5lzebKNYdCczpRdnifew,305285
188
188
  sqlalchemy/sql/crud.py,sha256=1qtcYPM-p9DsjMaqixYgKVSPuQEK43QEsAdgmXYY_ok,61581
189
- sqlalchemy/sql/ddl.py,sha256=6vfeMHtVcV6vWBQLxDZ906CHBnnadG5C8vmQNbpY5k8,65048
189
+ sqlalchemy/sql/ddl.py,sha256=lytVJHoLxOU9T0XoHL42hyMMnhqNEzRh7fCmngz8eFg,65052
190
190
  sqlalchemy/sql/default_comparator.py,sha256=MC1yWLbOArtLAsVWho_08Jk8ogP6mEgtRP-IxBYFtv4,18684
191
- sqlalchemy/sql/dml.py,sha256=-j0vtiT_JPyZoxUxtgOwtSOT3BHK_S6BlBR5vzfrzcM,71911
191
+ sqlalchemy/sql/dml.py,sha256=lc6cBkLvDiZkvFLefKo41gBZxhBr3ZcEt7D8Pe3EfjA,71971
192
192
  sqlalchemy/sql/elements.py,sha256=zPomd9yuJm5DJ9Jie87V5w2M8Zcv6mrd1nx174QKSmo,196427
193
193
  sqlalchemy/sql/events.py,sha256=xpqx3irkG8N3gysXAViLCqXXke9KCSU-6w4zZUdYXzw,18312
194
194
  sqlalchemy/sql/expression.py,sha256=SStPoDh7LSBTj6-4_KZSzyH0i5f493lqx4EnwcGPCZU,8342
@@ -198,7 +198,7 @@ sqlalchemy/sql/naming.py,sha256=qBLfM2BizVlnFrDTcZ2AzTiUMml281BiOHRD-Qw1uXg,6705
198
198
  sqlalchemy/sql/operators.py,sha256=91HJboxRkDFNHx9JlpO9hsss7wqTfeoANOxjMFszTt0,87215
199
199
  sqlalchemy/sql/roles.py,sha256=QG4iNsYMCqjnMP3wt-5lEKxQZIh3uD2yVhurcS-z7VM,7857
200
200
  sqlalchemy/sql/schema.py,sha256=v-F5LUroXFN1TjKz4q9bj29z6gf7oAe-k3ejww81-0U,262539
201
- sqlalchemy/sql/selectable.py,sha256=PcrGphf752_nMgFvA5d5LLUGhio9glG3nrCSEJtbvTs,257803
201
+ sqlalchemy/sql/selectable.py,sha256=x6Q-52QhBrVKVGRxkyZRNvHrjXvo-F6-XRv6dKmWnyc,258794
202
202
  sqlalchemy/sql/sqltypes.py,sha256=zykH4bSbQRbmrdq9_lqnOqwwtgWAq0j-XnWa4zQPtQw,138822
203
203
  sqlalchemy/sql/traversals.py,sha256=xLBzv1qpTUjBTiTGMBvPUvl1UPffYSWMxV4wHgOM4i4,34355
204
204
  sqlalchemy/sql/type_api.py,sha256=nIjquO8VkktzgurEYoxPYDMShBRi_xfCyV0wsw8yEAQ,89578
@@ -254,15 +254,15 @@ sqlalchemy/util/compat.py,sha256=9_xMEtXJsbe5IWgKbqRT9u6bdgmq47c_xXc4FtFmxcc,891
254
254
  sqlalchemy/util/concurrency.py,sha256=MpIMr-DqUnsYool27DfOeIMXndyzdWe_JnsktAYxLSc,8849
255
255
  sqlalchemy/util/cython.py,sha256=mfWXvmFqP4y3eiA2kGgcgV5GR5sTZfOob32UGY1BYA4,1968
256
256
  sqlalchemy/util/deprecations.py,sha256=9X3kYnZcVCEf1hyWU14_RNFahgUejlaLQX78B4UbhP8,12041
257
- sqlalchemy/util/langhelpers.py,sha256=CmSvEzkhj7IfW6gDrTZPo4NoUSZL60OVhKoYkGKoFBc,84552
257
+ sqlalchemy/util/langhelpers.py,sha256=_Kz4ejcbQ9kfSEyjc817pO8fS5K3O9gRWJpYEOmodS0,84755
258
258
  sqlalchemy/util/preloaded.py,sha256=DMfxtGeRyWpnUN3T9NvFdkPkTBPmruWOnUjLqrw8L0M,5975
259
259
  sqlalchemy/util/queue.py,sha256=p9FOM0eUWGC_2VK1euQLzQ0gQoUyaGvinEIuKXbKAFw,10237
260
260
  sqlalchemy/util/tool_support.py,sha256=iZSwvKdF5pA8UtXuwbtln6dEDgerKJWasELSi7q6Epw,6136
261
261
  sqlalchemy/util/topological.py,sha256=yMpaA2s0JYIekQF4XKwzJzy8lVo-8yeo8o1J2xzxq48,3451
262
262
  sqlalchemy/util/typing.py,sha256=p3vOTJ4F7i3eqeFw7W_tayq88U0e53ZgOsCu7eNQ3lA,21125
263
- sqlalchemy-2.1.5.dist-info/licenses/AUTHORS,sha256=3B2wtdF0Va3De2k_-OQJyagPYD5EFpWCVRjDb3hslj4,492
264
- sqlalchemy-2.1.5.dist-info/licenses/LICENSE,sha256=6GK7W5BPtVE8PhQojXoloS6w7MeEegqWXTEOmpVefLk,1100
265
- sqlalchemy-2.1.5.dist-info/METADATA,sha256=f1aOpxrs-yl5LM7iyLE0WCXjhdVLfnu6dV5EXlO1aW8,9680
266
- sqlalchemy-2.1.5.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
267
- sqlalchemy-2.1.5.dist-info/top_level.txt,sha256=rp-ZgB7D8G11ivXON5VGPjupT1voYmWqkciDt5Uaw_Q,11
268
- sqlalchemy-2.1.5.dist-info/RECORD,,
263
+ sqlalchemy-2.1.6.dist-info/licenses/AUTHORS,sha256=3B2wtdF0Va3De2k_-OQJyagPYD5EFpWCVRjDb3hslj4,492
264
+ sqlalchemy-2.1.6.dist-info/licenses/LICENSE,sha256=6GK7W5BPtVE8PhQojXoloS6w7MeEegqWXTEOmpVefLk,1100
265
+ sqlalchemy-2.1.6.dist-info/METADATA,sha256=8XT7KgUqw2efOZup5ztb1ai9H2mnixRgrryQ63692lA,9662
266
+ sqlalchemy-2.1.6.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
267
+ sqlalchemy-2.1.6.dist-info/top_level.txt,sha256=rp-ZgB7D8G11ivXON5VGPjupT1voYmWqkciDt5Uaw_Q,11
268
+ sqlalchemy-2.1.6.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (84.0.0)
2
+ Generator: setuptools (84.2.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5