Commit Graph

18083 Commits

Author SHA1 Message Date
Federico Caselli fc913aac9a Merge "Perf/conditional unique selectinload" into main 2026-06-04 19:50:15 +00:00
Federico Caselli 35e0d85b33 improve typed column migration docs
Change-Id: I402580004d1c0d8583ebc9e2852f38d687ba6ae8
2026-06-04 21:39:13 +02:00
Oliver Parker efa87e2500 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: 980af0383b

Change-Id: I12e993f104d354ae894f81f9b09fbcf9a95b0027
2026-06-03 13:49:17 -04:00
sebastianbreguel abfe6cc47c 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: beba43e77a

Change-Id: I95b02ffa66ef709c16bf5275924ec03244c19ecb
2026-05-31 16:12:19 -04:00
me-saurabhkohli 4fb459aaf0 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: c03904ece2

Change-Id: Ia184f77b442b069e6f9a4f94a967ead41a1704b6
2026-05-29 18:20:14 -04:00
Michael Bayer 685817d83a Merge "allow backref named 'metadata' to not break _metadata_for_cls" into main 2026-05-28 16:37:00 +00:00
Mike Bayer 96f98a9119 allow backref named 'metadata' to not break _metadata_for_cls
Fixed regression caused by 🎫`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
2026-05-28 11:03:34 -04:00
Michael Bayer 18f41b29d7 Merge "Fix subqueryload losing .and_() criteria when combined with of_type()" into main 2026-05-28 14:16:47 +00:00
Michael Bayer 7babdfbd51 Merge "Fix lambda statements with non-lambda criteria" into main 2026-05-28 14:16:16 +00:00
cjc0013 c41f25b170 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: ec3e6735bf

Change-Id: I8a32c11f3da63109cf37c39541df8ebfee52b8c5
2026-05-27 18:39:11 -04:00
Arya Rizky cf3cfa307f 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: b7a8617cde

Change-Id: I2c24652ec112511deaf39dbb9d6197e2097904ed
2026-05-27 18:06:55 -04:00
bekapono 808fd28297 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: fdd9847e7d

Change-Id: Ib68f8e2be1399222383cdd7b55793fe88402212c
2026-05-27 13:23:10 -04:00
proto-atlas e00937ec54 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: bb730f3427

Change-Id: I4c5d516b3933b4e7fae9c844881a61f557a8bb5e
2026-05-25 21:18:00 +02:00
Mike Bayer 092391036c cherry-pick changelog update for 2.0.51 2026-05-24 15:20:50 -04:00
Mike Bayer d44dfeeb24 cherry-pick changelog from 2.0.50 2026-05-24 15:20:49 -04:00
Mike Bayer 9030af40ba 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
2026-05-24 11:22:40 -04:00
Michael Bayer 9c31086f96 Merge "user_defined_options returns memoized options" into main 2026-05-23 01:32:16 +00:00
Federico Caselli 68e982ad9d 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
2026-05-21 23:14:17 +02:00
Michael Bayer 873f8773a6 Merge "Fix ExcludeConstraint not forwarding info to parent constructor" into main 2026-05-20 21:02:33 +00:00
Michael Bayer 859d370c24 Merge "implement _post_inspect for AliasedInsp" into main 2026-05-20 21:02:02 +00:00
Mike Bayer afa94c32a9 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
2026-05-20 16:30:28 -04:00
WiktorB2004 cf2984c31d 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: be7f4fee2c
Change-Id: Idc4846f02127d1d39a8c638cb03b0379932e9fd6
2026-05-20 16:17:12 -04:00
Michael Bayer f4043a6197 Merge "Fix joinedload + of_type() + and_() invalid SQL for subclass columns" into main 2026-05-20 20:02:35 +00:00
Michael Bayer 6c3c6e46a5 Merge "Fix floordiv (//) for float/numeric by int with div_is_floordiv dialects" into main 2026-05-20 19:53:18 +00:00
Joaquin Hui Gomez 4ce719fbb3 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: ba55b0c3e2

Change-Id: I78fe4672649d1d5498e3bc653e5d943ccb55dafd
2026-05-20 19:26:16 +00:00
OSS Contributor f862a4534a 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: c9cbc47c87

Change-Id: I5f9f02d966aa6ccee214a2c5cc27a73a4292da03
2026-05-20 15:25:53 -04:00
mattip 56edb237cb 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: 00472f32f6

Change-Id: Id5d4ba37cf8db2345a948f973d7b1710910359a1
2026-05-20 13:47:17 -04:00
Michael Bayer 5594b60d4a Merge "document postgresql_nulls_not_distinct" into main 2026-05-20 14:05:36 +00:00
Karolina Surma f07ad99839 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: 90bc13fc41

Change-Id: I461d71b0fad18fa4f108102bb1c22c0e980fc70e
2026-05-19 20:19:16 +00:00
Mike Bayer ee9c8625ba 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 🎫`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
2026-05-19 13:55:11 -04:00
Michael Bayer cb3e0ccbe3 Merge "Postgresql default to no backslash escaping" into main 2026-05-18 16:31:37 +00:00
Michael Bayer 2cee0b6628 Merge "resolve table names using MetaData.schema default in declarative registry" into main 2026-05-18 16:11:48 +00:00
Mike Bayer 7e0ee8b254 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
2026-05-18 10:53:07 -04:00
Michael Bayer 7f46c2bace Merge "Block Result.unique() with Result.yield_per() for ORM results" into main 2026-05-18 12:24:26 +00:00
David Lord 57dcfdacaa 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: cdc858cd88

Change-Id: I3f2c8fe346d3235fa8ba12c4d9ab712ddb840230
2026-05-17 16:09:16 -04:00
Federico Caselli f55557e96a add update to black 26.3.1 commit to blame ignore
Change-Id: I98dbccf0b60d7672627736bbc20a7a6a27fba22a
2026-05-17 22:05:26 +02:00
Henry Cai 120a967505 remove redundant deserializer assignment from asyncpg dialect (#13287) 2026-05-17 22:02:37 +02:00
Mike Bayer 15a9df9b2d 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
2026-05-12 18:47:56 -04:00
Michael Bayer 649d70db39 Merge "populate existing can be in exec option in session.get" into main 2026-05-12 13:03:37 +00:00
Federico Caselli 1e1c0084b1 update to black 26.3.1
Closes: #13280
Change-Id: Ifbb77dd6d2a1c228ae97fcf8160f40e975edc57c
2026-05-10 19:00:42 +02:00
Federico Caselli 43213299b5 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
2026-05-10 11:39:45 -04:00
Mike Bayer 3c650cede4 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
2026-05-10 11:30:00 -04:00
Shamil Abdulaev 0aa47f8082 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: 81b93af698

Change-Id: Ic38704674d30aa3d1bb5ce1e8ef5e4b0562ad91a
2026-05-07 17:59:09 +00:00
Mike Bayer dcb36d73bb 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
2026-05-07 11:54:58 -04:00
Michael Bayer 5e48edad84 Merge "Fixes: #10673: make declared_attr covariant" into main 2026-05-07 15:32:20 +00:00
Léo Gallot ffc32e517d Replace logging.WARN by logging.WARNING (#13277) 2026-05-05 21:01:21 +02:00
Matti Picus f353f62327 limit pypy to one build, fix typo (#13275) 2026-05-04 14:51:32 +02:00
Federico Caselli a50a9097d3 restore skip of 3.14t with cext and greenlet
Change-Id: Ia75ab15c73f5a93f5eb2b6b99870aab824d0a43d
2026-05-03 21:27:32 +02:00
dependabot[bot] 583e2c4a0c 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>
2026-05-02 20:33:39 +02:00
dependabot[bot] db9b991551 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>
2026-04-30 21:57:42 +02:00