]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/log
thirdparty/sqlalchemy/sqlalchemy.git
21 hours agoMerge branch 'dependabot/github_actions/pypa/cibuildwheel-4.1.0' main
Mike Bayer [Mon, 15 Jun 2026 20:29:26 +0000 (16:29 -0400)] 
Merge branch 'dependabot/github_actions/pypa/cibuildwheel-4.1.0'

Change-Id: I263869dff37838f9e34e4b6c6641c26aec714374

21 hours agoMerge "Fixes: 13363 Process ORM result rows as plain tuples without Row construction...
Michael Bayer [Mon, 15 Jun 2026 20:28:20 +0000 (20:28 +0000)] 
Merge "Fixes: 13363 Process ORM result rows as plain tuples without Row construction" into main

22 hours agoFixes: 13363 Process ORM result rows as plain tuples without Row construction
Oliver Parker [Mon, 15 Jun 2026 14:41:06 +0000 (10:41 -0400)] 
Fixes: 13363 Process ORM result rows as plain tuples without Row construction
ORM result row fetching now processes rows as plain tuples rather than
constructing :class:`.Row` objects, as ORM loaders use position-based
access and do not require the :class:`.Row` interface. :class:`.Row`
construction is still used when engine-level debug logging is enabled so
that individual rows can be logged. Benchmarks show a 3-16% improvement in
ORM entity load times depending on query shape.  Pull request courtesy
Oliver Parker.

Adds Result._all_interim_rows(), which returns the remaining rows as processed plain tuples, applying result processors and tuple filters but skipping Row object construction.  ORM loading uses this for its row fetch; its row getters are position-based itemgetters that accept any tuple-like row.  Results that require row logging or have scalar sources fall back to Row construction.

Adds tests covering the new behavior: rows are plain tuples with result processors applied, and Row construction still occurs when engine-level row logging is enabled, at both the Result and ORM loading level.

Benchmarked on an in-memory SQLite database with this change alone (median of 30 runs, ms); this path is used by all ORM entity loads:

    plain_small (500 rows x 5 cols)    2.43 ->  2.28    -6%
    plain_wide (2000 rows x 25 cols)   8.17 ->  7.24   -11%
    joined_o2m (500 x 10)             18.56 -> 16.95    -9%
    selectin_o2m (500 x 10)           18.45 -> 17.79    -4%
    selectin_nested (50 x 10 x 10)    18.67 -> 17.33    -7%
    selectin_m2m (500 x 10)           12.70 -> 11.53    -9%
    selectin_m2o (5000 -> 200)        15.83 -> 15.29    -3%
    selectin_o2m_few_big (20 x 500)   32.96 -> 31.29    -5%
    subquery_o2m (500 x 10)           21.51 -> 18.16   -16%

Fixes: #13363
Closes: #13365
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/13365
Pull-request-sha: 46f4125ead7e37b780160ae70e03ec204ecb9617

Change-Id: Ia91a89c8cac78d4790391bc5b171b76d4aaca71b

26 hours agocherry-pick changelog update for 2.0.52
Mike Bayer [Mon, 15 Jun 2026 15:41:38 +0000 (11:41 -0400)] 
cherry-pick changelog update for 2.0.52

26 hours agocherry-pick changelog from 2.0.51
Mike Bayer [Mon, 15 Jun 2026 15:41:37 +0000 (11:41 -0400)] 
cherry-pick changelog from 2.0.51

27 hours agoBump pypa/cibuildwheel from 4.0.0 to 4.1.0 13373/head
dependabot[bot] [Mon, 15 Jun 2026 15:21:14 +0000 (15:21 +0000)] 
Bump pypa/cibuildwheel from 4.0.0 to 4.1.0

Bumps [pypa/cibuildwheel](https://github.com/pypa/cibuildwheel) from 4.0.0 to 4.1.0.
- [Release notes](https://github.com/pypa/cibuildwheel/releases)
- [Changelog](https://github.com/pypa/cibuildwheel/blob/main/docs/changelog.md)
- [Commits](https://github.com/pypa/cibuildwheel/compare/v4.0.0...v4.1.0)

---
updated-dependencies:
- dependency-name: pypa/cibuildwheel
  dependency-version: 4.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
27 hours agofix backtracking hang in hstore literal parser
dxbjavid [Fri, 12 Jun 2026 11:19:04 +0000 (07:19 -0400)] 
fix backtracking hang in hstore literal parser

Fixed regular expression in the pure Python hstore result processor,
used when ``use_native_hstore=False`` is set, which could hang on
malformed hstore text containing unterminated quoted segments with
backslashes.  Pull request courtesy dxbjavid.

Fixes: #13370
Closes: #13371
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/13371
Pull-request-sha: f5eddae11c435c78f326b70a15357cbaf6d09337

Change-Id: I0d2d7565dc88f56a73b41e2ad20ca1c5a6f738bb

4 days agoadd row logging tests
Mike Bayer [Fri, 12 Jun 2026 17:33:05 +0000 (13:33 -0400)] 
add row logging tests

ensure all the main result methods as well as the ORM-used
_raw_all_rows() perform equivalent row logging.

Change-Id: Iee0dc3c75a9c71f6d1a73fa058c5edf0b16348ec

4 days agobump mssql-python to 1.9.0
Mike Bayer [Fri, 12 Jun 2026 18:13:50 +0000 (14:13 -0400)] 
bump mssql-python to 1.9.0

1.9.0 seems to fix the picklable statement exception fail,
so fix for that test and pin to lower version

Change-Id: Ic561b1a6b688f38b9f5189508d9203bca47fef79

4 days agoMerge "factor single-table reflection wrappers into common mixin" into main
Michael Bayer [Fri, 12 Jun 2026 16:12:57 +0000 (16:12 +0000)] 
Merge "factor single-table reflection wrappers into common mixin" into main

4 days agochore: improve sqlalchemy maintenance path (#13351)
lphuc2250gma [Thu, 11 Jun 2026 21:19:57 +0000 (17:19 -0400)] 
chore: improve sqlalchemy maintenance path (#13351)

Co-authored-by: Noa Levi <275430404+lphuc2250gma@users.noreply.github.com>
4 days agoDocument quoted_name use for PostgreSQL INHERITS (#13342)
CaoRongkai [Thu, 11 Jun 2026 21:19:16 +0000 (05:19 +0800)] 
Document quoted_name use for PostgreSQL INHERITS (#13342)

4 days agoBump pypa/cibuildwheel from 3.4.1 to 4.0.0 (#13358)
dependabot[bot] [Thu, 11 Jun 2026 20:57:54 +0000 (22:57 +0200)] 
Bump pypa/cibuildwheel from 3.4.1 to 4.0.0 (#13358)

Bumps [pypa/cibuildwheel](https://github.com/pypa/cibuildwheel) from 3.4.1 to 4.0.0.
- [Release notes](https://github.com/pypa/cibuildwheel/releases)
- [Changelog](https://github.com/pypa/cibuildwheel/blob/main/docs/changelog.md)
- [Commits](https://github.com/pypa/cibuildwheel/compare/v3.4.1...v4.0.0)

---
updated-dependencies:
- dependency-name: pypa/cibuildwheel
  dependency-version: 4.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
5 days agofactor single-table reflection wrappers into common mixin
Mike Bayer [Fri, 5 Jun 2026 20:02:02 +0000 (16:02 -0400)] 
factor single-table reflection wrappers into common mixin

Introduced _BackendsMultiReflection mixin in engine/default.py
that provides the get_columns(), get_pk_constraint(),
get_foreign_keys(), get_indexes(), get_unique_constraints(),
get_check_constraints(), get_table_comment(), and
get_table_options() single-table methods, each delegating to
the corresponding get_multi_* method with
filter_names=[table_name].

PostgreSQL, Oracle, and MSSQL dialects now inherit from this
mixin instead of duplicating the wrapper pattern.  Oracle
retains its _value_or_raise() override which applies
normalize_name() for case-folding.  MSSQL overrides
get_unique_constraints(), get_check_constraints(), and
get_table_options() with NotImplementedError since it has no
native get_multi_* for those yet.

Change-Id: If68bbf94b3956348fc7ae8179ff093d63dcdfbe2

6 days agoMerge "allow rollback within _prepare_impl on twophase prepare failure" into main
Michael Bayer [Wed, 10 Jun 2026 13:08:43 +0000 (13:08 +0000)] 
Merge "allow rollback within _prepare_impl on twophase prepare failure" into main

6 days agoMerge "repair xid in psycopg" into main
Michael Bayer [Wed, 10 Jun 2026 13:08:10 +0000 (13:08 +0000)] 
Merge "repair xid in psycopg" into main

6 days agoallow rollback within _prepare_impl on twophase prepare failure
Mike Bayer [Tue, 9 Jun 2026 18:47:46 +0000 (14:47 -0400)] 
allow rollback within _prepare_impl on twophase prepare failure

When tpc_prepare() raised during SessionTransaction._prepare_impl(),
the error handler's call to self.rollback() was blocked by the
@declare_states decorator, which had set _next_state to
CHANGE_IN_PROGRESS. This caused IllegalStateChangeError to be raised
instead of the original database exception, masking the real error
and preventing proper cleanup.

Used _expect_state(SessionTransactionState.CLOSED) to temporarily
allow the rollback state transition, matching the existing pattern
used in commit() for the close() call.

Fixes: #13356
Change-Id: Ie8212d5b6f8515340cf9d83c56dcbfa5a7415812

6 days agoMerge "send execution options to connection also" into main
Michael Bayer [Tue, 9 Jun 2026 18:34:29 +0000 (18:34 +0000)] 
Merge "send execution options to connection also" into main

7 days agoMerge "remove legacy include_columns in index reflection" into main
Michael Bayer [Tue, 9 Jun 2026 14:23:36 +0000 (14:23 +0000)] 
Merge "remove legacy include_columns in index reflection" into main

7 days agorepair xid in psycopg
Federico Caselli [Fri, 5 Jun 2026 19:51:13 +0000 (21:51 +0200)] 
repair xid in psycopg

Repaired bug introduced in :ticket:`13229` where a two-phase
transaction recovery would not return the correct transaction
identifier when generating the identifiers using the ``xid()``
method of the psycopg connection.

Fixes: #13355
Change-Id: Iffe68c1701afaa678fa7b598559dd396d3f8db41

11 days agouse trusted publishing for PyPI wheel uploads
Mike Bayer [Fri, 5 Jun 2026 16:35:35 +0000 (12:35 -0400)] 
use trusted publishing for PyPI wheel uploads

Replace token-based PyPI authentication with OIDC trusted publishing.
Add workflow-level id-token: write permission, generate PEP 740
attestations using pypi-attestations, and upload with
twine --attestations.  Removes the pypi_token secret dependency.

Closes: #13324
Change-Id: I75d8eab7ade7be61ed86d773ea2403cd484c81dd

11 days agoMerge "minor code improvement to the mssql multi reflection" into main
Michael Bayer [Fri, 5 Jun 2026 14:25:26 +0000 (14:25 +0000)] 
Merge "minor code improvement to the mssql multi reflection" into main

11 days agoMerge "Register func.any(), func.all(), func.some() as collection aggregates" into...
Michael Bayer [Fri, 5 Jun 2026 14:08:03 +0000 (14:08 +0000)] 
Merge "Register func.any(), func.all(), func.some() as collection aggregates" into main

11 days agominor code improvement to the mssql multi reflection
Federico Caselli [Thu, 4 Jun 2026 22:47:52 +0000 (00:47 +0200)] 
minor code improvement to the mssql multi reflection

improve caching and remove redundant flag

Change-Id: I46ee752c908227667a281bd4d436fac2b43b0d8e

11 days agoremove legacy include_columns in index reflection
Federico Caselli [Thu, 4 Jun 2026 21:23:46 +0000 (23:23 +0200)] 
remove legacy include_columns in index reflection

Removed the legacy ``include_columns`` key from the dictionary returned
by the index reflection methods of some dialects.
This information is now part of the ``dialect_options`` dictionary under the key
``{dialect_name}_include``, such as ``postgresql_include`` or ``mssql_include``.

Fixes: #13350
Change-Id: I9535690350d97e19477f7e9919dc4994b876af47

11 days agofix docs lint warning
Federico Caselli [Thu, 4 Jun 2026 21:26:13 +0000 (23:26 +0200)] 
fix docs lint warning

Change-Id: I6c8e38dc663bc0b53ab1259daab50617583ccdbb

11 days agoMerge "Implement native multi-table reflection API for the mssql dialect" into main
Federico Caselli [Thu, 4 Jun 2026 21:25:40 +0000 (21:25 +0000)] 
Merge "Implement native multi-table reflection API for the mssql dialect" into main

11 days agoImplement native multi-table reflection API for the mssql dialect
Gaurav Sharma [Wed, 3 Jun 2026 12:52:09 +0000 (08:52 -0400)] 
Implement native multi-table reflection API for the mssql dialect

### Description

Adds 5 native `get_multi_*` reflection methods (columns, pk, fk, indexes, table_comment) for the MSSQL dialect, replacing the per-table loop in `_default_multi_reflect`. Single-table methods now delegate to the multi versions (PG/Oracle pattern); legacy per-table SQL is retained as `_internal_get_*` helpers, used only for tempdb reflection.

Not implemented here: `get_multi_unique_constraints`, `get_multi_check_constraints`, `get_multi_table_options` -MSSQL has no single-table counterparts to delegate from. Happy to add as a follow-up.

### Performance

Measured with `test/perf/many_table_reflection.py` against SQL Server 2022 (Docker, localhost, pyodbc + ODBC Driver 18) on a 250-table fixture, 15-50 cols, with PKs/FKs/indexes/comments:

| | single | multi | speedup |
|---|---|---|---|
| `get_columns` | 1.33s | 0.35s | 3.8x |
| `get_pk_constraint` | 1.41s | 0.08s | 18x |
| `get_foreign_keys` | 7.07s | 0.19s | 37x |
| `get_indexes` | 0.80s | 0.09s | 8.6x |
| `get_table_comment` | 0.71s | 0.05s | 14x |
| **MetaData.reflect** | **12.62s** | **1.15s** | **11x** |

### Checklist

This pull request is:

- [x] A new feature implementation
- Fixes: #8430
- Tests added in `test/dialect/mssql/test_reflection.py`
- Changelog entry: `doc/build/changelog/unreleased_21/8430.rst`

Closes: #13297
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/13297
Pull-request-sha: 2c6c69f159225f85312e39d99222279ef8cbadd1

Change-Id: I525c60fc5ece94dd250f376b05b64b09e65ca0d7

11 days agoRemoved erroneous debug print (#13349)
Bradley Davis [Thu, 4 Jun 2026 19:51:32 +0000 (12:51 -0700)] 
Removed erroneous debug print (#13349)

11 days agoMerge "Perf/conditional unique selectinload" into main
Federico Caselli [Thu, 4 Jun 2026 19:50:15 +0000 (19:50 +0000)] 
Merge "Perf/conditional unique selectinload" into main

11 days agoimprove typed column migration docs
Federico Caselli [Thu, 4 Jun 2026 19:33:19 +0000 (21:33 +0200)] 
improve typed column migration docs

Change-Id: I402580004d1c0d8583ebc9e2852f38d687ba6ae8

12 days agosend execution options to connection also
Mike Bayer [Wed, 3 Jun 2026 13:46:19 +0000 (09:46 -0400)] 
send execution options to connection also

Session level :paramref:`_orm.Session.execution_options` now take
effect for Core level SQL emitted by unit of work operations, in
addition to their existing use within ORM statement executions.
This is to provide for Core options such as
:paramref:`_engine.Connection.execution_options.schema_translate_map`
to be applicable to a :class:`.Session` overall.

Fixes: #13346
Change-Id: Icb453b7925f1bc38f30538d7726d222842bc65bd

12 days agoRegister func.any(), func.all(), func.some() as collection aggregates
Mike Bayer [Thu, 4 Jun 2026 14:17:06 +0000 (10:17 -0400)] 
Register func.any(), func.all(), func.some() as collection aggregates

Added CollectionAggregateFunction base class that sets
_is_collection_aggregate = True, and registered any_, all_, some_
as subclasses so that func.any(), func.all(), and func.some() correctly
prevent operator flipping on negation. Previously ~(col == func.any(arr))
would incorrectly compile to col != any(arr) instead of
NOT (col = any(arr)), which has different semantics for collection
aggregate comparison modifiers.

Also extended the _construct_for_op guard to check both left and right
operands for _is_collection_aggregate, since func.any(arr) can appear
on either side of a comparison unlike the standalone any_() construct
which auto-reverses operands.

Fixes: #13343
Change-Id: Id4774938876dc7f1f38cf143dccfe3c8ddba464d

13 days agoPerf/conditional unique selectinload
Oliver Parker [Wed, 3 Jun 2026 06:51:13 +0000 (02:51 -0400)] 
Perf/conditional unique selectinload

Optimized :func:`_orm.selectinload` to skip the ``.unique()`` call on inner
result sets when no nested :func:`_orm.joinedload` on a collection is
present.  The uniquing pass is only required when a joined eager load
inflates rows due to a one-to-many or many-to-many JOIN; in the common case
of a leaf selectin load, rows are already unique by construction and the
per-row hashing overhead can be avoided. As a side effect, ``yield_per``
set in a ``do_orm_execute`` event for a :func:`_orm.selectinload`
relationship load no longer raises ``InvalidRequestError`` when no nested
collection joinedload is in effect, since ``.unique()`` is no longer called
in that path. Pull request courtesy Oliver Parker.

`_SelectInLoader._load_via_parent` and `_load_via_child` currently call
`.unique()` unconditionally on the inner `Result`. The uniqueness pass is only
required when a nested `joinedload` on a collection is in effect — in that case
the `JOIN` inflates rows (one row per `(child, grandchild)` instead of one per
child) and the outer `groupby` would produce duplicated entries without dedup.

`loading.instances()` already signals exactly this condition: it sets
`Result._unique_filter_state` to a `require_unique` guard when the inner
compile state has `multi_row_eager_loaders=True`. When that flag is unset (no
nested collection `joinedload`), `_unique_filter_state` stays `None`, meaning
the inner query produces unique rows by construction:

- `omit_join` 1:N — one row per child
- `omit_join` M2O — one row per parent
- `omit_join` M2M — one row per (parent, entity)
- `load_with_join` (non-omit) — one row per (parent, child)

This PR makes the `.unique()` call conditional, via a new `_has_unique_filter`
property on `Result` that exposes this state without reaching into the private
`_unique_filter_state` attribute directly:

```python
if result._has_unique_filter:
    result = result.unique()
```

Per-row hashing in `_iterator_getter` is avoided in the common leaf-load case.
On an in-memory SQLite bench (2000 parents × 5 children + M:N tags, Python
3.14, n=1000 iterations):

| Workload | before avg | after avg | delta | before sd | after sd |
|---|---|---|---|---|---|
| selectin children (1:N) | 56.0 ms | 41.4 ms | **−26%** | 5.2 ms | 1.9 ms |
| selectin tags M2M | 25.6 ms | 20.0 ms | **−22%** | 4.2 ms | 3.1 ms |
| joined children (1:N) | 42.9 ms | 37.6 ms | ~0% | — | — |
| plain parent load | 4.2 ms | 3.6 ms | ~0% | — | — |

**Behaviour change:** `yield_per` set in a `do_orm_execute` event for a
relationship load no longer raises
`InvalidRequestError("Can't use yield_per in conjunction with unique")` for
`selectinload` without a nested collection `joinedload` — because `.unique()`
is no longer called in that path. `immediateload` is unaffected (it still calls
`.unique()` unconditionally).

Fixes: #13339
Closes: #13341
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/13341
Pull-request-sha: 980af0383b174271bb602a890f595c26f78ddcee

Change-Id: I12e993f104d354ae894f81f9b09fbcf9a95b0027

2 weeks agoHoist loop-invariant set intersection in _get_display_froms
sebastianbreguel [Sun, 31 May 2026 20:12:19 +0000 (16:12 -0400)] 
Hoist loop-invariant set intersection in _get_display_froms

Fixes #13336.

`SelectState._get_display_froms` recomputed a loop-invariant `_cloned_intersection(...)` once per FROM element in each of the three correlation comprehensions, making each branch O(N²) in the number of FROM elements. This hoists the call so it runs once, which is O(N).

`_cloned_intersection` / `_cloned_difference` are pure and return a set, and neither argument changes during the comprehension, so the result is identical. A function-level benchmark asserts `old == new` at every N (full numbers in #13336), and `test/sql/` plus the ORM compilation/query tests pass: 7442 passed, 359 skipped. Net -14 lines.

Per the issue discussion, no changelog entry is included.

### Checklist

This pull request is:

- [x] A short code fix
  - Issue with a runnable demonstration: #13336
  - Behavior-preserving (no logic change), so it is covered by the existing `test/sql/` and ORM compilation/query suites rather than adding new tests.

Closes: #13337
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/13337
Pull-request-sha: beba43e77a773a4d9e9d55cc39c7c85ecda6293e

Change-Id: I95b02ffa66ef709c16bf5275924ec03244c19ecb

2 weeks agoAdd ambiguous column support to SimpleResultMetaData
me-saurabhkohli [Fri, 29 May 2026 20:03:40 +0000 (16:03 -0400)] 
Add ambiguous column support to SimpleResultMetaData

Fixed issue where :meth:`.Result.freeze` would lose track of ambiguous
column names present in the original :class:`.CursorResult`, causing
key-based access on the thawed result to silently return a value instead of
raising :class:`.InvalidRequestError`.  The
:class:`.SimpleResultMetaData` now accepts and propagates ambiguous key
information so that frozen, thawed, and pickled results raise consistently
for duplicate column names.  Pull request courtesy Saurabh Kohli.

Fixes: #9427
Closes: #13335
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/13335
Pull-request-sha: c03904ece298493ca69bf6e9cbdae23c7fb6a7b0

Change-Id: Ia184f77b442b069e6f9a4f94a967ead41a1704b6

2 weeks agoMerge "allow backref named 'metadata' to not break _metadata_for_cls" into main
Michael Bayer [Thu, 28 May 2026 16:37:00 +0000 (16:37 +0000)] 
Merge "allow backref named 'metadata' to not break _metadata_for_cls" into main

2 weeks agoallow backref named 'metadata' to not break _metadata_for_cls
Mike Bayer [Thu, 28 May 2026 14:25:39 +0000 (10:25 -0400)] 
allow backref named 'metadata' to not break _metadata_for_cls

Fixed regression caused by :ticket:`8068` where a ``backref``
named ``'metadata'`` on a mapped class would cause an
``AssertionError`` when the class also used string-based
relationship references (e.g. ``secondary="some_table"``).
The ``_metadata_for_cls()`` helper now checks
``isinstance(meta, MetaData)`` as a condition rather than
asserting, falling back to ``registry.metadata`` when the
class attribute has been overwritten by a backref.

A warning is now emitted when a Declarative attribute name is named
``metadata`` or ``registry``.  Previously, no warning was emitted for
``registry``, and using the name ``metadata`` would raise an
InvalidRequestError.   Since these names can be used for attributes
that are mapped as backrefs or using imperative mappings, usage
under Declarative has been relaxed for ``metadata`` but also warns
for both names as they may have unintended interactions with the
Declarative reserved names.

References: https://bugs.launchpad.net/nova/+bug/2154165
References: https://github.com/sqlalchemy/sqlalchemy/discussions/8619

Fixes: #13333
Change-Id: I0f3173bce9c8c8881bd6b8ea75102bb8ec92be8b

2 weeks agoMerge "Fix subqueryload losing .and_() criteria when combined with of_type()" into...
Michael Bayer [Thu, 28 May 2026 14:16:47 +0000 (14:16 +0000)] 
Merge "Fix subqueryload losing .and_() criteria when combined with of_type()" into main

2 weeks agoMerge "Fix lambda statements with non-lambda criteria" into main
Michael Bayer [Thu, 28 May 2026 14:16:16 +0000 (14:16 +0000)] 
Merge "Fix lambda statements with non-lambda criteria" into main

2 weeks agoFix lambda statements with non-lambda criteria
cjc0013 [Mon, 25 May 2026 16:46:50 +0000 (12:46 -0400)] 
Fix lambda statements with non-lambda criteria

Fixed issue where :class:`_sql.StatementLambdaElement` would proxy
attribute access through the cached "expected" expression rather than the
resolved expression, causing stale closure-bound parameter values to be
used when a lambda statement was extended with non-lambda criteria such as
an additional ``.where()`` clause.  Courtesy cjc0013.

Fixes: #10827
Closes: #13327
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/13327
Pull-request-sha: ec3e6735bf95d62d768f214dd5a49bbfc4fecaa5

Change-Id: I8a32c11f3da63109cf37c39541df8ebfee52b8c5

2 weeks agoFix subqueryload losing .and_() criteria when combined with of_type()
Arya Rizky [Tue, 12 May 2026 19:08:02 +0000 (15:08 -0400)] 
Fix subqueryload losing .and_() criteria when combined with of_type()

Fixed issue where :func:`_orm.subqueryload` combined with
:meth:`.PropComparator.of_type` and :meth:`.PropComparator.and_` would
silently drop the additional filter criteria, causing all related objects
to be loaded instead of only those matching the filter.  The
:class:`.LoaderCriteriaOption` was being constructed against the base
entity rather than the effective entity indicated by
:meth:`.PropComparator.of_type`.  Pull request courtesy Arya Rizky.

Fixes: #13207
Closes: #13290
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/13290
Pull-request-sha: b7a8617cdee3757f4af4abdb4ff0090d69bb1fb5

Change-Id: I2c24652ec112511deaf39dbb9d6197e2097904ed

2 weeks agoomit_join optimization for selectinload on many-to-many relationships
bekapono [Mon, 18 May 2026 16:29:50 +0000 (12:29 -0400)] 
omit_join optimization for selectinload on many-to-many relationships

The :func:`.selectinload` loader strategy now selects the ``omit_join``
optimization for many-to-many non-self-referential relationships, reducing
the number of joins in the secondary SELECT by selecting from the secondary
table directly rather than joining back to the parent entity. ``omit_join``
is enabled automatically when the join condition determines that the
secondary table's foreign keys fully cover the parent's primary key. As
always, ``omit_join`` can be disabled by setting
:paramref:`.relationship.omit_join` to ``False``. Pull request courtesy
bekapono.

Fixes: #5987
Closes: #13278
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/13278
Pull-request-sha: fdd9847e7db041be51160853c075b1427f7be051

Change-Id: Ib68f8e2be1399222383cdd7b55793fe88402212c

3 weeks agoFix Session bulk mappings typing for mapped classes
proto-atlas [Mon, 25 May 2026 19:14:40 +0000 (15:14 -0400)] 
Fix Session bulk mappings typing for mapped classes

Fixes #9256.

This updates the annotations for Session.bulk_insert_mappings() and Session.bulk_update_mappings().

The docstrings and runtime behavior already allow either a mapped class or a Mapper object, but the previous annotations only accepted Mapper[Any].

This patch switches those arguments to the existing _EntityBindKey alias, which matches the inputs accepted by _class_to_mapper(): mapped classes and Mapper objects, but not AliasedClass or AliasedInsp.

I also updated the internal _bulk_save_mappings() annotation so the public methods and the private helper stay consistent. The scoped_session proxy output has been kept in sync with tools/generate_proxy_methods.py, and the generator check passes.

I added a typing regression test covering both mapped classes and Mapper objects for the two bulk mapping methods. I confirmed that the mapped-class cases fail with the old annotation and pass with this change.

Checked locally:

python -m pytest -m mypy test/typing/test_mypy.py -k "session.py" -q
python -m mypy ./lib/sqlalchemy
python tools/generate_proxy_methods.py --check
python -m pytest test/orm/dml/test_bulk.py -q
python -m pytest -m mypy test/typing/test_mypy.py -k "not typed_queries.py" -q

I could not run the full typing suite locally because my local Python 3.12 environment does not include string.templatelib. I only skipped typed_queries.py; that file is expected to be covered by SQLAlchemy's Python 3.14 mypy CI job.

Closes: #13322
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/13322
Pull-request-sha: bb730f34275a7c40c94e668ecda1131804ba3084

Change-Id: I4c5d516b3933b4e7fae9c844881a61f557a8bb5e

3 weeks agocherry-pick changelog update for 2.0.51
Mike Bayer [Sun, 24 May 2026 19:20:50 +0000 (15:20 -0400)] 
cherry-pick changelog update for 2.0.51

3 weeks agocherry-pick changelog from 2.0.50
Mike Bayer [Sun, 24 May 2026 19:20:49 +0000 (15:20 -0400)] 
cherry-pick changelog from 2.0.50

3 weeks agodont produce side effects for do_orm_execute
Mike Bayer [Fri, 22 May 2026 20:01:10 +0000 (16:01 -0400)] 
dont produce side effects for do_orm_execute

Fixed issue where the presence of a :meth:`.SessionEvents.do_orm_execute`
event hook would cause internal execution options such as ``yield_per`` and
loader-specific state from the first ``orm_pre_session_exec`` pass to leak
into the second pass, leading to errors when using relationship loaders
such as :func:`.selectinload` and :func:`.immediateload`.  The execution
options passed to the second compilation pass are now based on the original
options plus only the explicit updates made via
:meth:`.ORMExecuteState.update_execution_options` within the event hook.

Fixes: #13301
Change-Id: Ide64d7202102930b68a2ab903054d538cd2f99dd

3 weeks agoMerge "user_defined_options returns memoized options" into main
Michael Bayer [Sat, 23 May 2026 01:32:16 +0000 (01:32 +0000)] 
Merge "user_defined_options returns memoized options" into main

3 weeks agouser_defined_options returns memoized options
Federico Caselli [Tue, 19 May 2026 21:39:49 +0000 (23:39 +0200)] 
user_defined_options returns memoized options

Updated the attribute :attr:`_orm.ORMExecuteState.user_defined_options` to
include options that were added to the statement before calling
:meth:`.Select.with_only_columns` or :meth:`_orm.Query.with_entities`.

Fixes: #13309
Change-Id: Ie6e3f46662542010f4d524820ae697638f36d459

3 weeks agoMerge "Fix ExcludeConstraint not forwarding info to parent constructor" into main
Michael Bayer [Wed, 20 May 2026 21:02:33 +0000 (21:02 +0000)] 
Merge "Fix ExcludeConstraint not forwarding info to parent constructor" into main

3 weeks agoMerge "implement _post_inspect for AliasedInsp" into main
Michael Bayer [Wed, 20 May 2026 21:02:02 +0000 (21:02 +0000)] 
Merge "implement _post_inspect for AliasedInsp" into main

3 weeks agoimplement _post_inspect for AliasedInsp
Mike Bayer [Wed, 20 May 2026 19:59:10 +0000 (15:59 -0400)] 
implement _post_inspect for AliasedInsp

Fixed issue where using :func:`_orm.with_polymorphic` on a leaf class (a
subclass with no further descendants) or a non-inherited class would fail
with an ``AttributeError`` when used in an ORM statement, due to
:func:`_orm.configure_mappers` not being triggered implicitly. The fix
ensures that :class:`.AliasedInsp` participates in the ``_post_inspect``
hook, triggering mapper configuration during ORM statement compilation.

Fixes: #13319
Change-Id: Ic5910474676be41f8c815dc72c38fca8e20cdeb9

3 weeks agoFix ExcludeConstraint not forwarding info to parent constructor
WiktorB2004 [Wed, 20 May 2026 20:05:41 +0000 (16:05 -0400)] 
Fix ExcludeConstraint not forwarding info to parent constructor

Fixed issue where the :class:`.ExcludeConstraint` construct did not
correctly forward the :paramref:`.ExcludeConstraint.info` parameter to
the superclass, causing user-defined metadata to be lost. Pull request
courtesy Wiktor Byrka.

Fixes: #13317
Closes: #13316
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/13316
Pull-request-sha: be7f4fee2c40d1986519e93145471faad61021af
Change-Id: Idc4846f02127d1d39a8c638cb03b0379932e9fd6

3 weeks agoMerge "Fix joinedload + of_type() + and_() invalid SQL for subclass columns" into...
Michael Bayer [Wed, 20 May 2026 20:02:35 +0000 (20:02 +0000)] 
Merge "Fix joinedload + of_type() + and_() invalid SQL for subclass columns" into main

3 weeks agoMerge "Fix floordiv (//) for float/numeric by int with div_is_floordiv dialects"...
Michael Bayer [Wed, 20 May 2026 19:53:18 +0000 (19:53 +0000)] 
Merge "Fix floordiv (//) for float/numeric by int with div_is_floordiv dialects" into main

3 weeks agoFix joinedload + of_type() + and_() invalid SQL for subclass columns
Joaquin Hui Gomez [Wed, 1 Apr 2026 17:29:38 +0000 (13:29 -0400)] 
Fix joinedload + of_type() + and_() invalid SQL for subclass columns

Fixed issue where using :func:`_orm.joinedload` with
:meth:`.PropComparator.of_type` targeting a joined-table subclass combined
with :meth:`.PropComparator.and_` referencing a column on that subclass
would generate invalid SQL, where the subclass column was not adapted to
the subquery alias.  Pull request courtesy Joaquin Hui Gomez.

Fixes #13203

Closes: #13206
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/13206
Pull-request-sha: ba55b0c3e2a8dae28a1c7d7ae646e3480a04425c

Change-Id: I78fe4672649d1d5498e3bc653e5d943ccb55dafd

3 weeks agoFix floordiv (//) for float/numeric by int with div_is_floordiv dialects
OSS Contributor [Mon, 23 Mar 2026 14:44:40 +0000 (10:44 -0400)] 
Fix floordiv (//) for float/numeric by int with div_is_floordiv dialects

Fixed issue where floor division (``//``) between a :class:`.Float` or
:class:`.Numeric` numerator and an :class:`.Integer` denominator would omit
the ``FLOOR()`` SQL wrapper on dialects where
:attr:`.Dialect.div_is_floordiv` is ``True`` (the default, including
PostgreSQL and SQLite).  ``FLOOR()`` is now applied if either the
denominator or the numerator is a non-integer, so that expressions such as
``float_col // int_col`` render as ``FLOOR(float_col / int_col)`` instead
of the incorrect ``float_col / int_col``.  Pull request courtesy r266-tech.

Fixes: #10528
Closes: #13191
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/13191
Pull-request-sha: c9cbc47c877e19c91f912556b4ead6cd26e3cfe6

Change-Id: I5f9f02d966aa6ccee214a2c5cc27a73a4292da03

3 weeks agoFix trivial PyPy failures
mattip [Wed, 20 May 2026 17:47:17 +0000 (13:47 -0400)] 
Fix trivial PyPy failures

<!-- Provide a general summary of your proposed changes in the Title field above -->

### Description

Fixes: #13274
References: #9154

There were two relatively causes to some of the ~21 failures on PyPy:
- weakrefs may be deleted but the objects not finalized on PyPy. This manifests as `ref.obj() is None` I added a test for the `release()` case that also failed on CPython before the fix.
- a condition added in 2022 for missing sqllite3 behaviour is no longer necessary, and is now causing a failure

In order to run the changes in CI, I added PyPy to the PR CI run. Before merging I will revert that change. There are still a number of failures with PyPy around different error messages, different inspect.signatures and one sticky problem with the pure-python datetime.py that actually comes from CPython. I will continue to work on them, but they are not specific to sqlalchemy.

Note the CI run is ~6 minutes where the CPython ones are ~3 minutes. This is expected, since PyPy's JIT does not kick in on short tests, and the base compiler is about 2x slower.

### Checklist
<!-- go over following points. check them with an `x` if they do apply, (they turn into clickable checkboxes once the PR is submitted, so no need to do everything at once)

-->

This pull request is:

- [ ] A documentation / typographical / small typing error fix
- Good to go, no issue or tests are needed
- [x] A short code fix
- please include the issue number, and create an issue if none exists, which
  must include a complete example of the issue.  one line code fixes without an
  issue and demonstration will not be accepted.
- Please include: `Fixes: #<issue number>` in the commit message
- please include tests.   one line code fixes without tests will not be accepted.
- [ ] A new feature implementation
- please include the issue number, and create an issue if none exists, which must
  include a complete example of how the feature would look.
- Please include: `Fixes: #<issue number>` in the commit message
- please include tests.

**Have a nice day!**

Closes: #13276
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/13276
Pull-request-sha: 00472f32f64827325f071150e8b6ecf1fbe9f22e

Change-Id: Id5d4ba37cf8db2345a948f973d7b1710910359a1

3 weeks agoMerge "document postgresql_nulls_not_distinct" into main
Michael Bayer [Wed, 20 May 2026 14:05:36 +0000 (14:05 +0000)] 
Merge "document postgresql_nulls_not_distinct" into main

3 weeks agoAdjust TypeError message to Python 3.15
Karolina Surma [Tue, 19 May 2026 14:20:38 +0000 (10:20 -0400)] 
Adjust TypeError message to Python 3.15

<!-- Provide a general summary of your proposed changes in the Title field above -->

### Description
The `.fromisoformat()` error message tested in `test_no_string()` changed in Python 3.15, this fixes the test.

See #13308 for the `rel_2_0` branch.

### Checklist
<!-- go over following points. check them with an `x` if they do apply, (they turn into clickable checkboxes once the PR is submitted, so no need to do everything at once)

-->

This pull request is:

- [ ] A documentation / typographical / small typing error fix
- Good to go, no issue or tests are needed
- [x] A short code fix (in a test, therefore I didn’t create an issue)
- please include the issue number, and create an issue if none exists, which
  must include a complete example of the issue.  one line code fixes without an
  issue and demonstration will not be accepted.
- Please include: `Fixes: #<issue number>` in the commit message
- please include tests.   one line code fixes without tests will not be accepted.
- [ ] A new feature implementation
- please include the issue number, and create an issue if none exists, which must
  include a complete example of how the feature would look.
- Please include: `Fixes: #<issue number>` in the commit message
- please include tests.

**Have a nice day!**

Closes: #13307
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/13307
Pull-request-sha: 90bc13fc416ea45ba5429d5f8ecffc24b108c1b1

Change-Id: I461d71b0fad18fa4f108102bb1c22c0e980fc70e

4 weeks agorobustly handle reconnect param across all pymysql variants
Mike Bayer [Tue, 19 May 2026 13:40:01 +0000 (09:40 -0400)] 
robustly handle reconnect param across all pymysql variants

Fixed issue in aiomysql and asyncmy dialects that appears as of using
pymysql 1.2.0; the dialects were not properly taking into account logic
that detects the argument signature of pymysql's ``ping()`` method which
was added as part of :ticket:`10492`.

We add a "does ping have reconnect" check for all three DBAPIs
individually.  To suit asyncmy's use of cython we also needed to
adjust vendored getargspec() routines.

Fixes: #13306
Change-Id: Iad90ec6cfe9ee3b99736dd2153264090e7f76be1

4 weeks agoMerge "Postgresql default to no backslash escaping" into main
Michael Bayer [Mon, 18 May 2026 16:31:37 +0000 (16:31 +0000)] 
Merge "Postgresql default to no backslash escaping" into main

4 weeks agoMerge "resolve table names using MetaData.schema default in declarative registry...
Michael Bayer [Mon, 18 May 2026 16:11:48 +0000 (16:11 +0000)] 
Merge "resolve table names using MetaData.schema default in declarative registry" into main

4 weeks agoresolve table names using MetaData.schema default in declarative registry
Mike Bayer [Thu, 30 Apr 2026 19:13:39 +0000 (15:13 -0400)] 
resolve table names using MetaData.schema default in declarative registry

Also resolved class-level MetaData not being consulted by the
declarative class registry when resolving string-based table
references.  The registry now uses the same metadata resolution
logic as table creation, checking for a class-specific ``metadata``
attribute before falling back to ``registry.metadata``.  The
``_metadata_for_cls`` function was factored into ``orm/util.py``
for shared use by both ``decl_base.py`` and ``clsregistry.py``.

Fixes: #8068
Fixes: #13291
Change-Id: Ib846be0267f9295a5fee945dc6cf0a72c237bd2c

4 weeks agoMerge "Block Result.unique() with Result.yield_per() for ORM results" into main
Michael Bayer [Mon, 18 May 2026 12:24:26 +0000 (12:24 +0000)] 
Merge "Block Result.unique() with Result.yield_per() for ORM results" into main

4 weeks agodocument postgresql_nulls_not_distinct
David Lord [Sun, 17 May 2026 20:09:16 +0000 (16:09 -0400)] 
document postgresql_nulls_not_distinct

<!-- Provide a general summary of your proposed changes in the Title field above -->

### Description
<!-- Describe your changes in detail -->

https://github.com/sqlalchemy/sqlalchemy/issues/8240 and https://github.com/sqlalchemy/sqlalchemy/pull/9834 added support for `NULLS NOT DISTINCT` to the PostgreSQL dialect, but didn't add it to the docs (only the change log). This adds a section to the "Constraint Options" section of the PostgreSQL dialect docs.

### Checklist
<!-- go over following points. check them with an `x` if they do apply, (they turn into clickable checkboxes once the PR is submitted, so no need to do everything at once)

-->

This pull request is:

- [x] A documentation / typographical / small typing error fix
- Good to go, no issue or tests are needed
- [ ] A short code fix
- please include the issue number, and create an issue if none exists, which
  must include a complete example of the issue.  one line code fixes without an
  issue and demonstration will not be accepted.
- Please include: `Fixes: #<issue number>` in the commit message
- please include tests.   one line code fixes without tests will not be accepted.
- [ ] A new feature implementation
- please include the issue number, and create an issue if none exists, which must
  include a complete example of how the feature would look.
- Please include: `Fixes: #<issue number>` in the commit message
- please include tests.

**Have a nice day!**

Closes: #13279
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/13279
Pull-request-sha: cdc858cd88fbf86661662147210f9587117aa593

Change-Id: I3f2c8fe346d3235fa8ba12c4d9ab712ddb840230

4 weeks agoadd update to black 26.3.1 commit to blame ignore
Federico Caselli [Sun, 17 May 2026 20:05:26 +0000 (22:05 +0200)] 
add update to black 26.3.1 commit to blame ignore

Change-Id: I98dbccf0b60d7672627736bbc20a7a6a27fba22a

4 weeks agoremove redundant deserializer assignment from asyncpg dialect (#13287)
Henry Cai [Sun, 17 May 2026 20:02:37 +0000 (13:02 -0700)] 
remove redundant deserializer assignment from asyncpg dialect (#13287)

4 weeks agoBlock Result.unique() with Result.yield_per() for ORM results
Mike Bayer [Tue, 12 May 2026 18:30:37 +0000 (14:30 -0400)] 
Block Result.unique() with Result.yield_per() for ORM results

The unique() + yield_per combination was only blocked when yield_per
was set via execution_options(yield_per=N); calling these as methods
on the result (e.g. result.unique().yield_per(N)) bypassed the check
and silently produced incorrect results.

Restructured _unique_filters on SimpleResultMetaData to be a callable
_create_unique_filters that receives the Result, allowing it to check
the yield_per state regardless of how it was activated.

Fixes: #13293
Change-Id: I7e6a5e5b2e1d4c8f9a0b3d6e7f1c2a4d5b8e9f0a

5 weeks agoMerge "populate existing can be in exec option in session.get" into main
Michael Bayer [Tue, 12 May 2026 13:03:37 +0000 (13:03 +0000)] 
Merge "populate existing can be in exec option in session.get" into main

5 weeks agoupdate to black 26.3.1
Federico Caselli [Fri, 8 May 2026 20:48:58 +0000 (22:48 +0200)] 
update to black 26.3.1

Closes: #13280
Change-Id: Ifbb77dd6d2a1c228ae97fcf8160f40e975edc57c

5 weeks agopopulate existing can be in exec option in session.get
Federico Caselli [Wed, 29 Apr 2026 21:09:57 +0000 (23:09 +0200)] 
populate existing can be in exec option in session.get

The ``populate_existing`` execution option is now honored when passed
in the :paramref:`.Session.get.execution_options` dict by the method
:meth:`.Session.get` and analogous in other session kinds. The current
:paramref:`.Session.get.populate_existing` parameter will takes precedence
if specified, overriding the value of the execution options.

Fixes: #10610
Change-Id: I4ddc9a7c6dda8f31f4dd413b49a9196efb3edaa6

5 weeks agocollect pep8 errors
Mike Bayer [Sun, 10 May 2026 15:30:00 +0000 (11:30 -0400)] 
collect pep8 errors

run each command in a try/except (they print out error messages
regardless) and report at the end on all individual runs.

Change-Id: I347c04f5c49c69daadf9f5f9e7c6c488cdf27f35

5 weeks agoAdd sqlite.JSONB type for binary JSON storage (SQLite >= 3.45.0)
Shamil Abdulaev [Tue, 28 Apr 2026 11:23:14 +0000 (07:23 -0400)] 
Add sqlite.JSONB type for binary JSON storage (SQLite >= 3.45.0)

Added :class:`_sqlite.JSONB` type for SQLite's binary JSON storage
format, available as of SQLite version 3.45.0. Values are stored via
the ``jsonb()`` SQL function and retrieved via ``json()``, while the
Python-side behavior remains identical to :class:`_sqlite.JSON`.
Pull request courtesy Shamil Abdulaev.

Fixes: #13260
Adds `sqlalchemy.dialects.sqlite.JSONB` — a new dialect-specific type
for SQLite's binary JSON storage format, introduced in SQLite 3.45.0.

The type:
- renders `JSONB` in DDL (`CREATE TABLE t (col JSONB)`)
- wraps bind values with `jsonb()` on write, storing data as a BLOB
- wraps column reads with `json()`, returning standard text JSON to Python
- reflects back from the database as `sqlite.JSONB`
- behaves identically to `sqlite.JSON` on the Python side

SQLite 3.45.0 introduced a native binary JSON format (JSONB) that is
more compact and faster to parse than text JSON. Users who want to opt
into this storage format had no way to do so via SQLAlchemy.

- `JSONB` inherits from `sqlite.JSON` and defines `__visit_name__ = "JSONB"`
  so the DDL compiler dispatches to `visit_JSONB` instead of `visit_JSON`
- Added `JSONB: JSONB` to `colspecs` so the type is not remapped to
  `_SQliteJson` via the `sqltypes.JSON` MRO entry
- `bind_expression` / `column_expression` apply `jsonb()` / `json()`
  transparently; existing `result_processor` from `sqltypes.JSON` handles
  deserialization without changes
- Added `sqlite_jsonb` requirement (checks for SQLite >= 3.45 and that
  `jsonb()` is available, since it is a loadable extension)

`test/dialect/sqlite/test_types.py::JSONBTest` (8 tests):
- DDL renders `JSONB`
- Reflection returns `sqlite.JSONB`
- Round-trip read/write including `None`
- Sub-object extraction via `[]` indexing
- Compiled SQL shows `jsonb(?)` on INSERT and `json(col)` on SELECT
- `typeof(col)` returns `blob` confirming binary storage

Closes: #13261
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/13261
Pull-request-sha: 81b93af698e0222a9262614d39dd5ade6b640273

Change-Id: Ic38704674d30aa3d1bb5ce1e8ef5e4b0562ad91a

5 weeks agosupport mypy 2.0
Mike Bayer [Thu, 7 May 2026 15:54:58 +0000 (11:54 -0400)] 
support mypy 2.0

mypy just went to 2.0.

and there seems to be...

exactly one "type: ignore" to remove and...that's it?

well OK!

Change-Id: I29f919641acc0e970b566c850063db7ecad70ed9

5 weeks agoMerge "Fixes: #10673: make declared_attr covariant" into main
Michael Bayer [Thu, 7 May 2026 15:32:20 +0000 (15:32 +0000)] 
Merge "Fixes: #10673: make declared_attr covariant" into main

5 weeks agoReplace logging.WARN by logging.WARNING (#13277)
Léo Gallot [Tue, 5 May 2026 19:01:21 +0000 (21:01 +0200)] 
Replace logging.WARN by logging.WARNING (#13277)

6 weeks agolimit pypy to one build, fix typo (#13275)
Matti Picus [Mon, 4 May 2026 12:51:32 +0000 (15:51 +0300)] 
limit pypy to one build, fix typo (#13275)

6 weeks agorestore skip of 3.14t with cext and greenlet
Federico Caselli [Sun, 3 May 2026 19:27:32 +0000 (21:27 +0200)] 
restore skip of 3.14t with cext and greenlet

Change-Id: Ia75ab15c73f5a93f5eb2b6b99870aab824d0a43d

6 weeks agoBump pypa/cibuildwheel from 3.3.0 to 3.4.1 (#13271)
dependabot[bot] [Sat, 2 May 2026 18:33:39 +0000 (20:33 +0200)] 
Bump pypa/cibuildwheel from 3.3.0 to 3.4.1 (#13271)

* Bump pypa/cibuildwheel from 3.3.0 to 3.4.1

Bumps [pypa/cibuildwheel](https://github.com/pypa/cibuildwheel) from 3.3.0 to 3.4.1.
- [Release notes](https://github.com/pypa/cibuildwheel/releases)
- [Changelog](https://github.com/pypa/cibuildwheel/blob/main/docs/changelog.md)
- [Commits](https://github.com/pypa/cibuildwheel/compare/v3.3.0...v3.4.1)

---
updated-dependencies:
- dependency-name: pypa/cibuildwheel
  dependency-version: 3.4.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
* remove wheels for 3.13t since it's deprecated

Change-Id: I51157a09e7b01d5b23adc10d9a4b386776dedf7e

* remove tests from 3.13t

Change-Id: I73bb2761d07b0c8f549a4ba8ee7299dec6907df7

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Federico Caselli <cfederico87@gmail.com>
6 weeks agoBump actions/checkout from 4 to 6 (#13273)
dependabot[bot] [Thu, 30 Apr 2026 19:57:42 +0000 (21:57 +0200)] 
Bump actions/checkout from 4 to 6 (#13273)

Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
6 weeks agoBump docker/setup-qemu-action from 3 to 4 (#13272)
dependabot[bot] [Thu, 30 Apr 2026 19:54:35 +0000 (21:54 +0200)] 
Bump docker/setup-qemu-action from 3 to 4 (#13272)

Bumps [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) from 3 to 4.
- [Release notes](https://github.com/docker/setup-qemu-action/releases)
- [Commits](https://github.com/docker/setup-qemu-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: docker/setup-qemu-action
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
6 weeks agoBump actions/setup-python from 5 to 6 (#13270)
dependabot[bot] [Thu, 30 Apr 2026 19:53:11 +0000 (21:53 +0200)] 
Bump actions/setup-python from 5 to 6 (#13270)

Bumps [actions/setup-python](https://github.com/actions/setup-python) from 5 to 6.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
6 weeks agodocs: fix typo pool_echo -> echo_pool (#13269)
Léo Gallot [Thu, 30 Apr 2026 19:51:19 +0000 (21:51 +0200)] 
docs: fix typo pool_echo -> echo_pool (#13269)

6 weeks agoFixes: #10673: make declared_attr covariant
Luiz Felipe Neves [Thu, 30 Apr 2026 17:06:25 +0000 (13:06 -0400)] 
Fixes: #10673: make declared_attr covariant
<!-- Provide a general summary of your proposed changes in the Title field above -->

### Description
<!-- Describe your changes in detail -->
I made declared_attr covariant as suggested in #10673. mypy didn't seem to complain. Added a regression test for the use case that was asked for. Unfortunately, it seems like using `Mapped[int | UUID]` directly in the Protocol won't work:

```python
class CompareProtocol(Protocol):
    id: Mapped[int | UUID]
```

Because mypy will see this as a settable variable and not as a SQLAlchemy descriptor. Using `@property` instead seems to work and it's what I used in the test (perhaps it should be documented as the way to achieve this?):

```python
class CompareProtocol(Protocol):
    @property
    def id(self) -> Mapped[int | UUID]: ...
```

### Checklist
<!-- go over following points. check them with an `x` if they do apply, (they turn into clickable checkboxes once the PR is submitted, so no need to do everything at once)

-->

This pull request is:

- [ ] A documentation / typographical / small typing error fix
- Good to go, no issue or tests are needed
- [X] A short code fix
- please include the issue number, and create an issue if none exists, which
  must include a complete example of the issue.  one line code fixes without an
  issue and demonstration will not be accepted.
- Please include: `Fixes: #<issue number>` in the commit message
- please include tests.   one line code fixes without tests will not be accepted.
- [ ] A new feature implementation
- please include the issue number, and create an issue if none exists, which must
  include a complete example of how the feature would look.
- Please include: `Fixes: #<issue number>` in the commit message
- please include tests.

Closes: #13266
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/13266
Pull-request-sha: 8edd2841f4bbe61f8bb9bc15a7a57e0560698779

Change-Id: I7d63ad43df0ab34ee7c7389a007191be91efa574

6 weeks agoPostgresql default to no backslash escaping
Federico Caselli [Wed, 29 Apr 2026 20:11:35 +0000 (22:11 +0200)] 
Postgresql default to no backslash escaping

Changed the default backslash escape value in the PostgreSQL dialect to
``False`` to align it with the default value of
``standard_conforming_strings=on``. This change should not affect most users
since the value is set at driver initialization on first connect.

Fixes: #13268
Change-Id: I9b7986f1ee466fab3cab88e3f6117e313e3376cd

6 weeks agodocs: fix incorrect execution context class reference (#13254)
Léo Gallot [Wed, 29 Apr 2026 19:56:29 +0000 (21:56 +0200)] 
docs: fix incorrect execution context class reference (#13254)

7 weeks agoMerge "Remove unused TypeVars and compat import from typing modules" into main
Michael Bayer [Fri, 24 Apr 2026 21:38:50 +0000 (21:38 +0000)] 
Merge "Remove unused TypeVars and compat import from typing modules" into main

7 weeks agoconfigurable chunksize parameter for selectinload
bekapono [Wed, 22 Apr 2026 21:15:29 +0000 (17:15 -0400)] 
configurable chunksize parameter for selectinload

Added :paramref:`.selectinload.chunksize` parameter to :func`.selectinload`
allowing users to configure the number of primary keys sent per IN clause
when loading reltaionships. Pull request courtesy bekapono.

Fixes: #11450
Closes: #13235
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/13235
Pull-request-sha: 360585a48c0fe898aa249769e9c7c1171f9e0988

Change-Id: Id09776b7ba53c630a780f128fc67dfdc085a4062

7 weeks agoRemove unused TypeVars and compat import from typing modules
Shamil Abdulaev [Thu, 23 Apr 2026 17:09:07 +0000 (13:09 -0400)] 
Remove unused TypeVars and compat import from typing modules

## Summary

Removes 4 dead symbols from SQLAlchemy's typing modules. Each symbol has **zero references** across `lib/`, `test/`, `doc/`, `tools/`, and `examples/` — verified by grep for direct references, string forward references, and `getattr`-style dynamic access.

## Changes

**`lib/sqlalchemy/util/typing.py`**
- Remove `from . import compat` — unused module import; the only occurrence of `compat` in the file is in a code comment on line 221
- Remove `_KT_co = TypeVar("_KT_co", covariant=True)` — unused TypeVar
- Remove `_KT_contra = TypeVar("_KT_contra", contravariant=True)` — unused TypeVar

**`lib/sqlalchemy/orm/_typing.py`**
- Remove `_T_co = TypeVar("_T_co", bound=Any, covariant=True)` — orphaned; `orm.base` imports `_T_co` from `sql._typing` instead, and other orm modules (`interfaces.py`, `attributes.py`) define their own local `_T_co`

Total: **-7 lines**, no additions.

## Verification

For each removed symbol:

| Symbol | Repo-wide grep result |
|---|---|
| `compat` (in `util/typing.py`) | 0 references to `compat.` or `util.typing.compat` outside the import itself |
| `_KT_co` | 1 hit total (the removed definition line) |
| `_KT_contra` | 1 hit total (the removed definition line) |
| `_T_co` (in `orm/_typing.py`) | No `from sqlalchemy.orm._typing import _T_co` or `from ..orm._typing import _T_co` anywhere; all consumers import from `sql._typing` or define locally |

Additionally checked:
- No `__all__` references
- No string forward references (e.g. `"_KT_co"`)
- No `getattr(..., "_T_co")` or similar dynamic access
- No re-exports via `util/__init__.py` or any other module
- `test/base/test_typing_utils.py` (which imports `util.typing as sa_typing`) does not touch any of these names

## Test plan

- [x] `pre-commit` hooks pass (black, zimports, flake8)
- [x] `import sqlalchemy`, `sqlalchemy.orm`, `sqlalchemy.util.typing`, `sqlalchemy.orm._typing`, `sqlalchemy.sql._typing`, `sqlalchemy.dialects._typing` — all import cleanly
- [x] Broad import smoke test: `Mapped`, `DeclarativeBase`, `relationship`, `Session`, `Mapper`, `mapped_column`, `Column`, `select`, `create_engine`, `MetaData`, `QueuePool`, `hybrid_property`, `association_proxy` — all import cleanly
- [x] Full `tox` / test suite — would appreciate CI confirmation

## Not included (intentionally)

- `LiteralString` re-export in `util/typing.py:54` — has 0 in-tree consumers but is an explicit `as X as X` public re-export; kept for API stability
- `is_origin_of` rename to `_is_origin_of` — used only internally by `is_union`, but renaming is a minor breaking change not worth the churn

Closes: #13244
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/13244
Pull-request-sha: 8242f373685c35264ffd52071345a6dfce855277

Change-Id: Iae389447ac46599df27ab9776ff5ad19dfef4e2c

7 weeks agoMerge "Accept OrderByLists in order_by" into main
Michael Bayer [Wed, 22 Apr 2026 13:01:26 +0000 (13:01 +0000)] 
Merge "Accept OrderByLists in order_by" into main

7 weeks agoUse python to invoke pip
Federico Caselli [Tue, 21 Apr 2026 20:26:06 +0000 (22:26 +0200)] 
Use python to invoke pip

Fixes #13246 (hopefully)

Change-Id: If57a59e92ec933a1611c64534669a602ff2f3a92

8 weeks agoMerge "narrow scope of _correct_for_mysql_bugs_88718_96365" into main
Michael Bayer [Tue, 21 Apr 2026 17:17:36 +0000 (17:17 +0000)] 
Merge "narrow scope of _correct_for_mysql_bugs_88718_96365" into main

8 weeks agoAccept OrderByLists in order_by
Tobias Petersen [Tue, 21 Apr 2026 16:48:17 +0000 (12:48 -0400)] 
Accept OrderByLists in order_by

Add OrderByRole to acceptable arguments for order_by

Fixes: #13248
### Description
Add OrderByRole to acceptable arguments for order_by to solve typing regression

### Checklist
<!-- go over following points. check them with an `x` if they do apply, (they turn into clickable checkboxes once the PR is submitted, so no need to do everything at once)

-->

This pull request is:

- [x] A documentation / typographical / small typing error fix
- Good to go, no issue or tests are needed
- [x] A short code fix
- please include the issue number, and create an issue if none exists, which
  must include a complete example of the issue.  one line code fixes without an
  issue and demonstration will not be accepted.
- Please include: `Fixes: #<issue number>` in the commit message
- please include tests.   one line code fixes without tests will not be accepted.
- [ ] A new feature implementation
- please include the issue number, and create an issue if none exists, which must
  include a complete example of how the feature would look.
- Please include: `Fixes: #<issue number>` in the commit message
- please include tests.

**Have a nice day!**

Closes: #13251
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/13251
Pull-request-sha: 267e33f31139d4b6c6c3309b5875e1896e10e743

Change-Id: I0778cdecfebfb12bafc5b6027763ae5f5dcf02a2

8 weeks agonarrow scope of _correct_for_mysql_bugs_88718_96365
Mike Bayer [Mon, 20 Apr 2026 13:30:35 +0000 (09:30 -0400)] 
narrow scope of _correct_for_mysql_bugs_88718_96365

Narrowed the scope of the internal workaround for MySQL bugs `#88718
<https://bugs.mysql.com/bug.php?id=88718>`_ and `#96365
<https://bugs.mysql.com/bug.php?id=96365>`_ so that it is only applied
where needed: MySQL 8.0.1 through 8.0.13 (where bug 88718 is present), and
on systems with ``lower_case_table_names=2`` (where bug 96365 applies,
typically macOS).  Previously the workaround was applied unconditionally
for all MySQL 8.0+ versions, which caused a ``KeyError`` during foreign key
reflection when the database user lacked SELECT privileges on referred
tables.

Fixes: #13243
Change-Id: I7c29f67d1653c5cd32f29e098f038fea1d56117b

8 weeks agodocs: fix typo 'nad' -> 'and' in DefaultDialect.construct_arguments docstring (#13245)
Bojun Chai [Mon, 20 Apr 2026 20:30:20 +0000 (04:30 +0800)] 
docs: fix typo 'nad' -> 'and' in DefaultDialect.construct_arguments docstring (#13245)

Co-authored-by: Bojun Chai <bojunchai@microsoft.com>
8 weeks agohandle asyncpg InternalClientError
Mike Bayer [Fri, 17 Apr 2026 20:13:53 +0000 (16:13 -0400)] 
handle asyncpg InternalClientError

Fixed issue where the asyncpg driver could throw an insufficiently-handled
exception ``InternalClientError`` under some circumstances, leading to
connections not being properly marked as invalidated.

Fixes: #13241
References: https://github.com/MagicStack/asyncpg/issues/1069
Change-Id: Iaaf551b3d7b062cce62e13b441161583a484615f

2 months agoVersion 2.1.0b3 placeholder
Mike Bayer [Thu, 16 Apr 2026 20:16:54 +0000 (16:16 -0400)] 
Version 2.1.0b3 placeholder

2 months ago- 2.1.0b2 rel_2_1_0b2
Mike Bayer [Thu, 16 Apr 2026 20:04:09 +0000 (16:04 -0400)] 
- 2.1.0b2

2 months agodoc edits
Mike Bayer [Thu, 16 Apr 2026 20:02:37 +0000 (16:02 -0400)] 
doc edits

Change-Id: I2a30ceba5d27eba858396ab98ccb25e62d3dc3dc