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 +1 -1
- sqlalchemy/dialects/mysql/base.py +6 -1
- sqlalchemy/engine/base.py +18 -13
- sqlalchemy/engine/result.py +3 -1
- sqlalchemy/engine/url.py +39 -6
- sqlalchemy/ext/asyncio/result.py +23 -11
- sqlalchemy/orm/context.py +89 -3
- sqlalchemy/orm/session.py +8 -1
- sqlalchemy/pool/base.py +8 -1
- sqlalchemy/sql/compiler.py +117 -44
- sqlalchemy/sql/ddl.py +4 -4
- sqlalchemy/sql/dml.py +19 -17
- sqlalchemy/sql/selectable.py +42 -19
- sqlalchemy/util/langhelpers.py +7 -1
- {sqlalchemy-2.1.5.dist-info → sqlalchemy-2.1.6.dist-info}/METADATA +2 -3
- {sqlalchemy-2.1.5.dist-info → sqlalchemy-2.1.6.dist-info}/RECORD +20 -20
- {sqlalchemy-2.1.5.dist-info → sqlalchemy-2.1.6.dist-info}/WHEEL +1 -1
- {sqlalchemy-2.1.5.dist-info → sqlalchemy-2.1.6.dist-info}/licenses/AUTHORS +0 -0
- {sqlalchemy-2.1.5.dist-info → sqlalchemy-2.1.6.dist-info}/licenses/LICENSE +0 -0
- {sqlalchemy-2.1.5.dist-info → sqlalchemy-2.1.6.dist-info}/top_level.txt +0 -0
sqlalchemy/__init__.py
CHANGED
|
@@ -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
|
|
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
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
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
|
-
|
|
1298
|
+
self.__can_reconnect = False
|
|
1294
1299
|
|
|
1295
1300
|
# special case to handle mypy issue:
|
|
1296
1301
|
# https://github.com/python/mypy/issues/20651
|
sqlalchemy/engine/result.py
CHANGED
|
@@ -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.
|
|
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,
|
|
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(
|
|
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(
|
|
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(
|
|
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)
|
sqlalchemy/ext/asyncio/result.py
CHANGED
|
@@ -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
|
|
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
|
|
515
|
+
referring to this :class:`_asyncio.AsyncResult` object.
|
|
509
516
|
|
|
510
517
|
"""
|
|
511
518
|
|
|
512
|
-
return AsyncMappingResult(self
|
|
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
|
-
|
|
542
|
+
result: AsyncResult[Unpack[TupleAny]],
|
|
536
543
|
index: _KeyIndexType,
|
|
537
544
|
):
|
|
538
|
-
|
|
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
|
|
541
|
-
self._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 =
|
|
553
|
+
self._metadata = result._metadata._reduce([index])
|
|
545
554
|
self._post_creational_filter = operator.itemgetter(0)
|
|
546
555
|
|
|
547
|
-
self._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:
|
|
669
|
-
|
|
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
|
-
|
|
2540
|
-
for
|
|
2541
|
-
|
|
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
|
sqlalchemy/sql/compiler.py
CHANGED
|
@@ -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,
|
|
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
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
5362
|
-
|
|
5363
|
-
|
|
5364
|
-
|
|
5365
|
-
|
|
5366
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
("
|
|
1262
|
-
(
|
|
1263
|
-
"_return_defaults_columns",
|
|
1264
|
-
InternalTraversal.dp_clauseelement_tuple,
|
|
1265
|
-
),
|
|
1274
|
+
("_sort_by_parameter_order", InternalTraversal.dp_boolean),
|
|
1266
1275
|
(
|
|
1267
|
-
"
|
|
1268
|
-
InternalTraversal.
|
|
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
|
sqlalchemy/sql/selectable.py
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
5095
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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." %
|
|
5150
|
+
"manually." % statement
|
|
5128
5151
|
)
|
|
5129
5152
|
|
|
5130
5153
|
return froms
|
sqlalchemy/util/langhelpers.py
CHANGED
|
@@ -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
|
|
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.
|
|
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
|
-
*
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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
|
|
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=
|
|
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=
|
|
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.
|
|
264
|
-
sqlalchemy-2.1.
|
|
265
|
-
sqlalchemy-2.1.
|
|
266
|
-
sqlalchemy-2.1.
|
|
267
|
-
sqlalchemy-2.1.
|
|
268
|
-
sqlalchemy-2.1.
|
|
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,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|