Compare commits

...

5 Commits

Author SHA1 Message Date
rusackas
c9b1c94917 fix: render known_incompatibilities in docs, resolve constants in AST fallback, correct d1 SQLAlchemy 2.0 claim
- Add the TypeScript contract for `known_incompatibilities` and render it
  on the generated database docs pages (both top-level and within each
  compatible-database entry), so the field added for the Aurora Data API /
  D1 SQLAlchemy 2.0 warnings is actually visible instead of just reaching
  the JSON unused.
- Teach the AST-based docs fallback extractor to resolve module-level
  literal constants (e.g. AURORA_DATA_API_KNOWN_INCOMPATIBILITIES) so a
  metadata dict that references a shared constant by name no longer
  serializes as the bare identifier string when Flask context isn't
  available.
- Correct the d1.py known_incompatibilities reason: sqlalchemy-d1's only
  release (0.1.0) pins `sqlalchemy<2,>=1.4`, which explicitly excludes
  SQLAlchemy 2.0 rather than merely lacking confirmation either way.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-31 16:07:41 -07:00
rusackas
61a1a34d04 fix: dedupe Aurora Data API incompatibility metadata, normalize solr pin
Extract the duplicated Aurora Data API known_incompatibilities block from
mysql.py/postgres.py into a shared base.py constant, and drop the stray
space in the sqlalchemy-solr version pin for PEP 508 consistency.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-28 15:32:02 -07:00
Claude Code
fa2e6f6ae5 revert(flask-sqlalchemy): back to 2.5.1, cap explicitly below 3.0
Real CI (test-sqlite, test-mysql) surfaced a structural incompatibility
between Flask-SQLAlchemy 3.0.5's session/app-context scoping and how
Superset currently crosses context boundaries (Celery tasks,
background jobs): widespread "NoneType has no attribute X" failures
across unrelated test files (dashboards, embedded views, security,
tasks) plus MySQL "Lock wait timeout exceeded" errors.

Tried restoring NullPool for SQLite (Flask-SQLAlchemy 3.0 stopped
defaulting SQLite to NullPool when pool_size is unset) since that
matched the initial "database is locked" symptom -- it had zero
effect (identical failure count with and without it), confirming the
locking was a downstream symptom of the deeper session-scoping issue,
not a connection-pool problem. Reverting that fix along with the bump.

Without an explicit upper bound, uv's resolver naturally re-picks
3.0.5 on any lockfile regen (flask-appbuilder allows <4), so this
pins <3.0 explicitly rather than just removing the forcing pin.

This needs dedicated investigation into Superset's session/app-context
handling, not a bump slipped into driver-compat prep. Revisit
alongside the actual SQLAlchemy 2.0 core bump (discussion #40273,
step 6) -- Flask-SQLAlchemy 3.1+ requires SQLAlchemy 2.0 anyway, so
this was always going to need to happen around the same time.
2026-07-28 11:29:53 -07:00
Claude Code
28a029cae9 fix(tests): restore NullPool for SQLite under Flask-SQLAlchemy 3.0.5
Flask-SQLAlchemy 3.0 stopped defaulting SQLite engines to NullPool
when pool_size isn't set (changelog: "SQLite engines do not use
NullPool if pool_size is 0"). Superset never configures pool_size, so
under 2.5.1 this was silently applying; under 3.0.5 it falls back to
QueuePool instead, which holds connections open.

With a file-based SQLite db shared between the test process and the
Celery worker, and ENABLE_VERSIONING_CAPTURE adding a
version_transaction write to every commit, held-open pooled
connections caused a wave of "database is locked" errors in
test-sqlite CI (19 failed, 47 errors) that don't reproduce on master.
2026-07-28 11:01:36 -07:00
Claude Code
72a7e06dd8 chore(sqla2): bump SQLAlchemy-dependent drivers to dual-compat versions
Prep work for the SQLAlchemy 1.4 -> 2.0 core bump (discussion #40273,
step 6). Every SQLAlchemy-dependent package Superset ships or offers
as an optional extra gets bumped to the newest release that supports
both SQLAlchemy 1.4 and 2.0, so each bump can be merged and tested
independently under today's SQLAlchemy 1.4 pin before the core bump
lands as its own final PR.

- flask-sqlalchemy: pin explicitly (was purely transitive via
  flask-appbuilder, resolving to 2.5.1, 1.4-only) at >=3.0.5,<3.1, the
  last release before 3.1.0 drops 1.4 support. flask-appbuilder and
  marshmallow-sqlalchemy are already dual-compatible as pinned, no
  change needed.
- sqlalchemy-bigquery: 1.17.0 -> 1.17.1 (patch; the project was
  archived 2026-05-16, likely its final release).
- sqlalchemy-cratedb: 0.41.0 -> 0.43.1.
- sqlalchemy-drill: drop an artificial <2 SQLAlchemy-version ceiling
  upstream never had (1.1.10 already supports 2.0 via import_dbapi).
- firebolt-sqlalchemy: 1.0.0 -> 1.1.2.
- sqlalchemy-ocient: 1.0.0 -> 3.0.0 (lower confidence: closed-source
  vendor package, no public changelog to verify against).
- snowflake-sqlalchemy floor was already bumped independently by
  dependabot (#42418) to the same target this research landed on.

Five extras (risingwave, exasol, firebird, redshift, dremio) have NO
release supporting both SQLAlchemy versions -- version numbers cut
straight from 1.4-only to 2.0-only with no overlap. Pinned each to its
last 1.4-only version with a comment noting the 2.0 target to bump to
once the core sqlalchemy bump lands, not before.

Four extras have no SQLAlchemy 2.0 support anywhere in their
ecosystem today and are flagged via a new `known_incompatibilities`
metadata field (surfaced through the generated database docs):
kusto, aurora-data-api (including our own dormant preset-io fork),
solr, and d1. sqlalchemy-vertica-python was initially suspected to be
a fifth, but turned out to already be dual-compatible (v0.6.3 already
ships `import_dbapi`/`text()` wrapping) once the actual merged PR was
checked instead of relying on PyPI metadata alone.

Verified locally: full dependency resolution succeeds, the app boots
and creates all tables cleanly under SQLAlchemy 1.4.54 +
Flask-SQLAlchemy 3.0.5, 483/487 relevant unit tests pass (the 4
failures are a pre-existing local mysqlclient linkage issue,
unrelated to this change), and the new metadata flows through
generate_yaml_docs() end-to-end for all four flagged engines.
2026-07-28 10:11:56 -07:00
12 changed files with 262 additions and 19 deletions

View File

@@ -101,21 +101,29 @@ import json
import ast
import os
def eval_node(node):
"""Safely evaluate an AST node as a Python literal."""
def eval_node(node, constants=None):
"""Safely evaluate an AST node as a Python literal.
\`constants\` is an optional dict of module-level constant names -> already
-resolved Python values. It lets us resolve references like
\`AURORA_DATA_API_KNOWN_INCOMPATIBILITIES\` that point at a list/dict
defined (and potentially imported across files) elsewhere in
db_engine_specs, instead of falling through to the bare identifier
string.
"""
if node is None:
return None
if isinstance(node, ast.Constant):
return node.value
elif isinstance(node, ast.List):
return [eval_node(e) for e in node.elts]
return [eval_node(e, constants) for e in node.elts]
elif isinstance(node, ast.Dict):
result = {}
for k, v in zip(node.keys, node.values):
if k is not None:
key = eval_node(k)
key = eval_node(k, constants)
if key is not None:
result[key] = eval_node(v)
result[key] = eval_node(v, constants)
return result
elif isinstance(node, ast.Name):
# Handle True, False, None constants
@@ -125,12 +133,14 @@ def eval_node(node):
return False
elif node.id == 'None':
return None
if constants and node.id in constants:
return constants[node.id]
return node.id
elif isinstance(node, ast.Attribute):
# Handle DatabaseCategory.SOMETHING - return just the attribute name
return node.attr
elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.Add):
left, right = eval_node(node.left), eval_node(node.right)
left, right = eval_node(node.left, constants), eval_node(node.right, constants)
if isinstance(left, str) and isinstance(right, str):
return left + right
return None
@@ -274,6 +284,37 @@ CAP_METHODS = {
# Intermediate base classes (e.g. PrestoBaseEngineSpec) do count as overrides.
TRUE_BASE_CLASS = 'BaseEngineSpec'
# Pass 0: collect module-level literal constants across every engine spec
# file (e.g. AURORA_DATA_API_KNOWN_INCOMPATIBILITIES in base.py, imported
# into mysql.py's \`compatible_databases\` metadata) so \`metadata\` dicts
# that reference a shared constant by name resolve to its actual value
# instead of the bare identifier string. Only module-scope assignments
# (tree.body, not nested in classes/functions) are considered.
MODULE_CONSTANTS = {}
for filename in sorted(os.listdir(specs_dir)):
if not filename.endswith('.py') or filename in ('__init__.py', 'lib.py', 'lint_metadata.py'):
continue
filepath = os.path.join(specs_dir, filename)
try:
with open(filepath) as f:
source = f.read()
tree = ast.parse(source)
for item in tree.body:
targets = []
if isinstance(item, ast.Assign):
targets = item.targets
elif isinstance(item, ast.AnnAssign) and item.value is not None:
# Handle annotated module-level constants, e.g.
# \`AURORA_DATA_API_KNOWN_INCOMPATIBILITIES: list[KnownIncompatibility] = [...]\`
targets = [item.target]
for target in targets:
if isinstance(target, ast.Name) and target.id.isupper():
val = eval_node(item.value, MODULE_CONSTANTS)
if val is not None:
MODULE_CONSTANTS[target.id] = val
except Exception:
continue
# First pass: collect all class info (name, bases, metadata, cap_attrs, direct_methods)
class_info = {} # class_name -> {bases: [], metadata: {}, engine_name: str, filename: str, ...}
@@ -330,7 +371,7 @@ for filename in sorted(os.listdir(specs_dir)):
if isinstance(val, str):
engine_attr = val
elif target.id == 'metadata':
metadata = eval_node(item.value)
metadata = eval_node(item.value, MODULE_CONSTANTS)
elif target.id in CAP_ATTR_DEFAULTS:
val = eval_node(item.value)
if isinstance(val, bool):

View File

@@ -41,7 +41,7 @@ import {
GithubOutlined,
BugOutlined,
} from '@ant-design/icons';
import type { DatabaseInfo } from './types';
import type { DatabaseInfo, KnownIncompatibility } from './types';
// Simple code block component for connection strings
const CodeBlock: React.FC<{ children: React.ReactNode }> = ({ children }) => (
@@ -253,6 +253,53 @@ const DatabasePage: React.FC<DatabasePageProps> = ({ database, name }) => {
);
};
// Render known incompatibilities with a Superset dependency (e.g. a driver
// that doesn't yet support SQLAlchemy 2.0). Shared between the top-level
// documentation and each compatible-database entry.
const renderKnownIncompatibilities = (
incompatibilities?: KnownIncompatibility[],
) => {
if (!incompatibilities?.length) return null;
return (
<Space direction="vertical" style={{ width: '100%' }}>
{incompatibilities.map((incompat, idx) => (
<Alert
key={idx}
type="warning"
showIcon
message={incompat.dependency}
description={
<>
{incompat.reason && (
<Paragraph style={{ marginBottom: 4 }}>
{incompat.reason}
</Paragraph>
)}
<Space size="middle">
{incompat.tracking_url && (
<a
href={incompat.tracking_url}
target="_blank"
rel="noreferrer"
>
<LinkOutlined /> Tracking issue
</a>
)}
{incompat.since && (
<Text type="secondary">
Last confirmed: {incompat.since}
</Text>
)}
</Space>
</>
}
/>
))}
</Space>
);
};
// Render compatible databases (for PostgreSQL, etc.)
const renderCompatibleDatabases = () => {
if (!docs?.compatible_databases?.length) return null;
@@ -320,6 +367,16 @@ const DatabasePage: React.FC<DatabasePageProps> = ({ database, name }) => {
/>
</div>
)}
{compat.known_incompatibilities?.length > 0 && (
<div style={{ marginTop: 16 }}>
<Text strong>Known Incompatibilities:</Text>
<div style={{ marginTop: 8 }}>
{renderKnownIncompatibilities(
compat.known_incompatibilities,
)}
</div>
</div>
)}
{compat.notes && (
<Alert
message={compat.notes}
@@ -624,6 +681,17 @@ const DatabasePage: React.FC<DatabasePageProps> = ({ database, name }) => {
</Card>
)}
{/* Known Incompatibilities */}
{docs?.known_incompatibilities?.length > 0 && (
<Card
title="Known Incompatibilities"
style={{ marginBottom: 16 }}
type="inner"
>
{renderKnownIncompatibilities(docs.known_incompatibilities)}
</Card>
)}
{/* Installation */}
{(docs?.pypi_packages?.length || docs?.install_instructions) && (
<Card title="Installation" style={{ marginBottom: 16 }}>

View File

@@ -72,6 +72,13 @@ export interface SSLConfiguration {
};
}
export interface KnownIncompatibility {
dependency: string; // e.g. "SQLAlchemy 2.0"
reason?: string;
tracking_url?: string; // upstream issue/PR tracking a fix, if one exists
since?: string; // ISO date this was last confirmed still broken
}
export interface CompatibleDatabase {
name: string;
description?: string;
@@ -84,6 +91,7 @@ export interface CompatibleDatabase {
connection_examples?: ConnectionExample[];
notes?: string;
docs_url?: string;
known_incompatibilities?: KnownIncompatibility[];
}
export interface CustomError {
@@ -123,6 +131,7 @@ export interface DatabaseDocumentation {
advanced_features?: Record<string, string>;
compatible_databases?: CompatibleDatabase[];
custom_errors?: CustomError[]; // Database-specific error messages and troubleshooting info
known_incompatibilities?: KnownIncompatibility[]; // Unresolved incompatibilities with a Superset dependency
}
export interface TimeGrains {

View File

@@ -60,6 +60,15 @@ dependencies = [
"flask-login>=0.6.0, < 1.0",
"flask-migrate>=4.1.0, <5.0",
"flask-session>=0.4.0, <1.0",
# Pinned explicitly below 3.0: 3.0.5 resolves without conflict and
# supports both SQLAlchemy 1.4 and 2.0, but real CI runs surfaced a
# structural incompatibility with Superset's current session/app-context
# handling across Celery task boundaries (see PR #42542) -- widespread
# "NoneType has no attribute X" failures and MySQL lock-wait timeouts,
# not just a connection-pool quirk. Needs dedicated investigation, not a
# driver-compat-prep bump; revisit alongside the actual SQLAlchemy 2.0
# core bump (discussion #40273, step 6).
"flask-sqlalchemy>=2.5.1, <3.0",
"flask-wtf>=1.3.0, <2.0",
"geopy",
"greenlet<=3.5.3, >=3.5.3",
@@ -123,15 +132,25 @@ dependencies = [
[project.optional-dependencies]
athena = ["pyathena[pandas]>=2, <4"]
# No SQLAlchemy 2.0 support anywhere in this dialect's ecosystem today: our
# own preset-io/sqlalchemy-aurora-data-api fork is dead since 2021, and the
# more active community fork (cloud-utils/sqlalchemy-aurora-data-api) has an
# unresolved SQLAlchemy 2.0 break (upstream issue #43). See
# superset/db_engine_specs/aurora.py's known_incompatibilities metadata.
aurora-data-api = ["preset-sqlalchemy-aurora-data-api>=0.2.8,<0.3"]
bigquery = [
"pandas-gbq>=0.35.0",
"sqlalchemy-bigquery>=1.17.0",
# 1.17.1 is likely the final release: googleapis/python-bigquery-sqlalchemy
# was archived 2026-05-16. Both 1.17.0 and 1.17.1 support SQLAlchemy 1.4/2.0.
"sqlalchemy-bigquery>=1.17.1",
"google-cloud-bigquery>=3.42.2",
]
clickhouse = ["clickhouse-connect>=1.4.2, <2.0"]
cockroachdb = ["cockroachdb>=0.3.5, <0.4"]
crate = ["sqlalchemy-cratedb>=0.41.0, <1"]
crate = ["sqlalchemy-cratedb>=0.43.1, <1"]
# sqlalchemy-d1's only release (0.1.0, Nov 2025) pins sqlalchemy<2,>=1.4,
# explicitly excluding SQLAlchemy 2.0. See superset/db_engine_specs/d1.py's
# known_incompatibilities metadata.
d1 = [
"superset-engine-d1>=0.1.0",
"sqlalchemy-d1>=0.1.0",
@@ -145,14 +164,27 @@ databricks = [
datafusion = ["flightsql-dbapi>=0.2.2, <0.3"]
db2 = ["ibm-db-sa<=0.4.4, >=0.4.4"]
denodo = ["denodo-sqlalchemy>=2.0.5,<2.1.0"]
dremio = ["sqlalchemy-dremio>=1.2.1, <4"]
drill = ["sqlalchemy-drill>=1.1.10, <2"]
# sqlalchemy-dremio 3.0.5+ hard-pins sqlalchemy~=2.0.41, dropping 1.4; 3.0.4
# is the last dual-compat release. Capped below 3.0.5 for now; widen back to
# <4 in lockstep with Superset's own SQLAlchemy 2.0 core bump (discussion
# #40273), not before.
dremio = ["sqlalchemy-dremio>=1.2.1, <3.0.5"]
# <2 was an artificial ceiling; upstream has no SQLAlchemy version cap and
# 1.1.10 already supports SQLAlchemy 2.0 (added `import_dbapi` in 1.1.7).
drill = ["sqlalchemy-drill>=1.1.10, <3"]
druid = ["pydruid>=0.6.5,<0.7"]
duckdb = ["duckdb>=1.5.4,<2", "duckdb-engine>=0.17.0"]
dynamodb = ["pydynamodb>=0.8.2"]
solr = ["sqlalchemy-solr >= 0.2.4.3"]
# Effectively unmaintained (only dependabot bumps since 2024); hard-pinned to
# SQLAlchemy ~1.4.7 upstream, no SQLAlchemy 2.0 work. See
# superset/db_engine_specs/solr.py's known_incompatibilities metadata.
solr = ["sqlalchemy-solr>=0.2.4.3"]
elasticsearch = ["elasticsearch-dbapi>=0.2.13, <0.3.0"]
exasol = ["sqlalchemy-exasol>=2.4.0, <8.0"]
# sqlalchemy-exasol cuts hard from SQLAlchemy 1.4-only (<6.0.0) to 2.0-only
# (>=6.0.0) with no dual-compat release. Capped below 6.0.0 for now; bump to
# >=6.0.0,<8.0 in lockstep with Superset's own SQLAlchemy 2.0 core bump
# (discussion #40273), not before.
exasol = ["sqlalchemy-exasol>=2.4.0, <6.0.0"]
excel = ["xlrd>=2.0.2, <2.1"]
# Async dashboard "Export Data/Images to Excel": uploads the workbook to S3 and
# emails a pre-signed link. boto3 is imported lazily by superset.utils.s3, so
@@ -165,8 +197,12 @@ fastmcp = [
# heuristic that under-counts JSON-heavy MCP responses.
"tiktoken>=0.13.0,<1.0",
]
firebird = ["sqlalchemy-firebird>=0.8.0, <2.2"]
firebolt = ["firebolt-sqlalchemy>=1.0.0, <2"]
# sqlalchemy-firebird >=2.0.0 unconditionally requires SQLAlchemy 2.0 on
# Python >=3.8 (which covers Superset's >=3.11 floor), with no dual-compat
# release. Capped below 2.0.0 for now; bump to >=2.2.0 in lockstep with
# Superset's own SQLAlchemy 2.0 core bump (discussion #40273), not before.
firebird = ["sqlalchemy-firebird>=0.8.0, <2.0.0"]
firebolt = ["firebolt-sqlalchemy>=1.1.2, <2"]
gevent = ["gevent>=26.4.0"]
gsheets = ["shillelagh[gsheetsapi]>=1.4.4, <2"]
hana = ["hdbcli==2.29.25", "sqlalchemy_hana==3.0.3"]
@@ -177,6 +213,9 @@ hive = [
"thrift_sasl>=0.4.3, < 1.0.0",
]
impala = ["impyla>=0.24.0, <0.25"]
# Actively maintained upstream, but setup.py on main hard-pins
# sqlalchemy==1.4.*, no SQLAlchemy 2.0 work yet. See
# superset/db_engine_specs/kusto.py's known_incompatibilities metadata.
kusto = ["sqlalchemy-kusto>=3.1.2, <4"]
kylin = ["kylinpy>=2.8.4, <2.9"]
mssql = ["pymssql>=2.3.13, <3"]
@@ -184,7 +223,10 @@ mssql = ["pymssql>=2.3.13, <3"]
motherduck = ["apache-superset[duckdb]"]
mysql = ["mysqlclient>=2.2.8, <3"]
ocient = [
"sqlalchemy-ocient>=1.0.0, <4",
# Closed-source vendor package with no public changelog; permissive
# unpinned sqlalchemy>=1.4 declared, but SQLAlchemy 2.0 support is
# unverified. Lower confidence than the other bumps in this PR.
"sqlalchemy-ocient>=3.0.0, <4",
"pyocient>=1.0.15, <4",
"shapely",
"geojson",
@@ -197,8 +239,16 @@ postgres = ["psycopg2-binary==2.9.12"]
presto = ["pyhive[presto]>=0.6.5"]
trino = ["trino>=0.338.0"]
prophet = ["prophet>=1.1.6, <2"]
# sqlalchemy-redshift cuts hard from SQLAlchemy 1.4-only (0.8.x) to 2.0-only
# (>=1.0.0) with no dual-compat release; the existing <0.9 ceiling already
# keeps this on the 1.4-only line. Bump to >=1.0.0 in lockstep with
# Superset's own SQLAlchemy 2.0 core bump (discussion #40273), not before.
redshift = ["sqlalchemy-redshift>=0.8.1, <0.9"]
risingwave = ["sqlalchemy-risingwave"]
# No release of sqlalchemy-risingwave has ever supported both SQLAlchemy 1.4
# and 2.0 (version numbers don't track SQLAlchemy compat monotonically); pin
# to the newest 1.4-only release for now. Bump to >=2.0.0 in lockstep with
# Superset's own SQLAlchemy 2.0 core bump (discussion #40273), not before.
risingwave = ["sqlalchemy-risingwave>=1.4.1, <2.0.0"]
shillelagh = ["shillelagh[all]>=1.4.4, <2"]
singlestore = ["sqlalchemy-singlestoredb>=1.2.1, <2"]
snowflake = ["snowflake-sqlalchemy>=1.11.0, <2"]

View File

@@ -150,6 +150,7 @@ flask-session==0.8.0
# via apache-superset (pyproject.toml)
flask-sqlalchemy==2.5.1
# via
# apache-superset (pyproject.toml)
# flask-appbuilder
# flask-migrate
flask-talisman==1.1.0

View File

@@ -312,6 +312,7 @@ flask-session==0.8.0
flask-sqlalchemy==2.5.1
# via
# -c requirements/base-constraint.txt
# apache-superset
# flask-appbuilder
# flask-migrate
flask-talisman==1.1.0
@@ -989,7 +990,7 @@ sqlalchemy==1.4.54
# sqlalchemy-bigquery
# sqlalchemy-continuum
# sqlalchemy-utils
sqlalchemy-bigquery==1.17.0
sqlalchemy-bigquery==1.17.1
# via apache-superset
sqlalchemy-continuum==1.7.0
# via

View File

@@ -275,6 +275,36 @@ class CompatibleDatabase(TypedDict, total=False):
notes: str
docs_url: str
categories: list[str] # Override parent categories (e.g., for HOSTED_OPEN_SOURCE)
known_incompatibilities: list[KnownIncompatibility]
class KnownIncompatibility(TypedDict, total=False):
"""A known, currently-unresolved incompatibility with a Superset dependency."""
dependency: str # e.g. "SQLAlchemy 2.0"
reason: str
tracking_url: str # upstream issue/PR tracking a fix, if one exists
since: str # ISO date this was last confirmed still broken
# Shared `known_incompatibilities` entry for the Aurora Data API driver
# (`sqlalchemy-aurora-data-api`), used by both the MySQL and PostgreSQL
# `compatible_databases` metadata for their respective Aurora entries.
AURORA_DATA_API_KNOWN_INCOMPATIBILITIES: list[KnownIncompatibility] = [
{
"dependency": "SQLAlchemy 2.0",
"reason": (
"Neither our fork (preset-io/sqlalchemy-aurora-data-api, "
"dormant since 2021) nor the more active community fork "
"(cloud-utils/sqlalchemy-aurora-data-api) has resolved "
"SQLAlchemy 2.0 compatibility."
),
"tracking_url": (
"https://github.com/cloud-utils/sqlalchemy-aurora-data-api/issues/43"
),
"since": "2026-07-28",
}
]
class DBEngineSpecMetadata(TypedDict, total=False):
@@ -317,6 +347,11 @@ class DBEngineSpecMetadata(TypedDict, total=False):
install_instructions: str
version_requirements: str
# Known, currently-unresolved incompatibilities with a Superset
# dependency (e.g. a driver that doesn't yet support SQLAlchemy 2.0).
# Hopefully temporary; remove the entry once resolved upstream.
known_incompatibilities: list[KnownIncompatibility]
# Related databases (e.g., PostgreSQL-compatible databases)
compatible_databases: list[CompatibleDatabase]

View File

@@ -48,4 +48,16 @@ class CloudflareD1EngineSpec(SqliteEngineSpec):
"cloudflare_d1_database_id": "D1 database ID",
},
"install_instructions": "pip install superset-engine-d1",
"known_incompatibilities": [
{
"dependency": "SQLAlchemy 2.0",
"reason": (
"sqlalchemy-d1 is very young (single release, Nov 2025) "
"and its only release pins sqlalchemy<2,>=1.4, "
"explicitly excluding SQLAlchemy 2.0."
),
"tracking_url": ("https://github.com/sqlalchemy-cf-d1/sqlalchemy-d1"),
"since": "2026-07-28",
}
],
}

View File

@@ -131,6 +131,17 @@ class KustoSqlEngineSpec(BaseEngineSpec): # pylint: disable=abstract-method
"notes": "Use native Kusto Query Language for advanced analytics.",
},
],
"known_incompatibilities": [
{
"dependency": "SQLAlchemy 2.0",
"reason": (
"setup.py on the sqlalchemy-kusto main branch hard-pins "
"sqlalchemy==1.4.*; no SQLAlchemy 2.0 work has started."
),
"tracking_url": "https://github.com/dodopizza/sqlalchemy-kusto",
"since": "2026-07-28",
}
],
}
_time_grain_expressions = {

View File

@@ -43,6 +43,7 @@ from sqlalchemy.engine.url import URL
from superset.constants import TimeGrain
from superset.db_engine_specs.base import (
AURORA_DATA_API_KNOWN_INCOMPATIBILITIES,
BaseEngineSpec,
BasicParametersMixin,
DatabaseCategory,
@@ -183,6 +184,7 @@ class MySQLEngineSpec(BasicParametersMixin, BaseEngineSpec):
DatabaseCategory.CLOUD_AWS,
DatabaseCategory.HOSTED_OPEN_SOURCE,
],
"known_incompatibilities": AURORA_DATA_API_KNOWN_INCOMPATIBILITIES,
},
],
}

View File

@@ -34,6 +34,7 @@ from sqlalchemy.types import Date, DateTime, String
from superset.constants import TimeGrain
from superset.db_engine_specs.base import (
AURORA_DATA_API_KNOWN_INCOMPATIBILITIES,
BaseEngineSpec,
BasicParametersMixin,
DatabaseCategory,
@@ -545,6 +546,7 @@ class PostgresEngineSpec(BasicParametersMixin, PostgresBaseEngineSpec):
DatabaseCategory.CLOUD_AWS,
DatabaseCategory.HOSTED_OPEN_SOURCE,
],
"known_incompatibilities": AURORA_DATA_API_KNOWN_INCOMPATIBILITIES,
},
],
}

View File

@@ -43,6 +43,17 @@ class SolrEngineSpec(BaseEngineSpec): # pylint: disable=abstract-method
"[/?use_ssl=true|false]"
),
"default_port": 8983,
"known_incompatibilities": [
{
"dependency": "SQLAlchemy 2.0",
"reason": (
"sqlalchemy-solr hard-pins sqlalchemy~=1.4.7 and has seen no "
"activity beyond dependabot bumps since 2024."
),
"tracking_url": "https://github.com/aadel/sqlalchemy-solr",
"since": "2026-07-28",
}
],
}
_time_grain_expressions = {