Skip to content

Count subqueries explicitly: SQLAlchemy 2.1 no longer coerces a Select into a FROM - #117

Closed
Moult wants to merge 1 commit into
RDFLib:developfrom
IfcOpenShell:upstream/count-subquery
Closed

Moult wants to merge 1 commit into
RDFLib:developfrom
IfcOpenShell:upstream/count-subquery

Conversation

@Moult

@Moult Moult commented Sep 24, 2026

Copy link
Copy Markdown

(AI-written, not verified by Dion.)

SQLAlchemy 2.1.0 (released 2026-09-24) removed the implicit coercion of a Select into a FROM clause that 1.4 and 2.0 had deprecated. union_select() relies on it for the count query behind __len__():

expression.select(*[functions.count().label('aCount')]).select_from(
    expression.select(*cols).where(whereClause).distinct().select_from(table))

Under 2.0 this emits SADeprecationWarning: Implicit coercion of SELECT and textual SELECT constructs into FROM clauses is deprecated; please call .subquery() ...; under 2.1 it raises ArgumentError: FROM expression, such as a Table or alias() object expected, got <Select> from sql.py:65, so len(graph) fails on every store (reached, for us, through brickschema's Graph.__len__).

The fix is the .subquery() the warning asks for. The SQL is identical under both versions:

SELECT count(*) AS "aCount" FROM (SELECT DISTINCT ... WHERE ...) AS anon_1 UNION ALL ...

Verified with the package's tests (DB=sqlite) on SQLAlchemy 2.0.54 and 2.1.0: same results, and no deprecation warning any more on 2.0. Note that on the current develop the suite needs #116 to import on Python 3.12+ (no pkg_resources), and three tests fail under rdflib 7 because the store is not graph-aware; I have a fix for that too and can open it as a follow-up PR if wanted.

…t into a FROM

union_select() built the count query for __len__() by passing the inner
select() straight to select_from(). SQLAlchemy 1.4 and 2.0 wrapped it in
a subquery with a deprecation warning ("Implicit coercion of SELECT and
textual SELECT constructs into FROM clauses is deprecated; please call
.subquery()"); 2.1 removed the coercion and raises ArgumentError, so
len(graph) fails on every store. Calling .subquery() emits the same SQL
(SELECT count(*) AS aCount FROM (SELECT DISTINCT ...) AS anon_1 UNION
ALL ...) under both versions and silences the warning on 2.0.

This commit was written by an AI coding tool and has not been verified by
a human.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013wcN7XquTfUi4vsKQ4KchL
@Andrej730

Copy link
Copy Markdown
Contributor

Can confirm this is the correct solution, we've merged it downstream - gtfierro#2

If this will be merged - please consider using the version of this from downstream, it has some additional code simplifications for readability, just so downstream wouldn't have this extra diff they'll need to resolve later.

@mwatts15

mwatts15 commented Sep 26, 2026 via email

Copy link
Copy Markdown
Collaborator

@Andrej730

Copy link
Copy Markdown
Contributor

@mwatts15 sure, submitted the PR (#119), thank you!

@mwatts15

Copy link
Copy Markdown
Collaborator

Merged an equivalent change to develop. Thanks for your contribution.

@mwatts15 mwatts15 closed this Oct 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants