Commit Graph
1118 Commits
Author SHA1 Message Date
rusackasandClaude Opus 4.8 24c282b036 fix: update integration-test mocks for session.get() migration
session.query(Model).get(id) at superset/commands/sql_lab/estimate.py
was migrated to db.session.get(Database, id) in bc56ecbf15, but the
integration-test mocks in tests/integration_tests/sql_lab/ still
patched the old session.query().get() chain shape, so
QueryEstimationCommand picked up an auto-generated MagicMock instead
of the fixture and failed test-mysql/postgres/sqlite. Same mock-shape
fix already applied to the unit-test sibling in the same commit.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-10 04:40:01 -07:00
Claude Code 8eea99c1c7 experiment: pin NullPool for SQLite test engines to restore 1.4 no-cross-thread-reuse behavior
SQLAlchemy 2.0 changed the default poolclass for file-based SQLite engines
from NullPool to QueuePool. Under 1.4, every checkout created a fresh
low-level sqlite3 connection, so a pooled connection was never handed to a
thread other than the one that opened it. QueuePool reuses connections
across checkouts, including checkouts from background threads such as the
GTF task framework's deferred-flush timer (superset/tasks/context.py).

Combined with the test suite's `?check_same_thread=true` SQLite URIs, a
connection opened on the main thread can now be handed to a background
timer thread, which pysqlite rejects with "SQLite objects created in a
thread can only be used in that same thread." This silently broke the
deferred DB write in TaskContext._deferred_flush, intermittently failing
tests/integration_tests/tasks/test_throttling.py::test_throttle_behavior
under full-suite load (reproduced deterministically across two full
sqlite runs, passed in isolation, confirmed via QueuePool + NullPool
introspection against the pinned 1.4.54 and 2.0.51 wheels).

Pin poolclass=NullPool for the sqlite test lane to restore the 1.4
behavior. Superset's non-test default config uses `check_same_thread=false`
instead, which is unaffected by pooled cross-thread connection reuse, so
this is scoped to the test config rather than superset/config.py.
2026-08-10 04:39:59 -07:00
Claude Code 1da693c7dd experiment: drop removed subtransactions= kwarg from Session.begin()
SQLAlchemy 2.0 removed the subtransactions= parameter from
Session.begin(); TestDatasource.setUp() called it unconditionally,
failing every test in the class with "TypeError: scoped_session.begin()
got an unexpected keyword argument 'subtransactions'" before the test
body ever ran.

Same fix as apache/superset#42866 (open at the time of this commit,
not yet merged to master despite this branch already having merged
master's tip) - applying it directly here since it's blocking all
further local verification of tests/integration_tests/datasource_tests.py
and is independent of the rest of this branch's SQLAlchemy 2.0 work.
Once #42866 merges to master, a future master-merge into this branch
will no-op on this file.

Verified locally (sqlite): all 31 tests in datasource_tests.py pass.
2026-08-10 04:39:58 -07:00
Claude Code 9ae1de960c experiment: fix Presto/Trino TIMESTAMP/DATE literal rendering under SQLAlchemy 2.0
Root cause of the where_latest_partition CompileError across hive/
presto/trino tests ("Could not render literal value '2023-05-01' with
datatype TIMESTAMP"): superset/models/sql_types/presto_sql_types.py's
TimeStamp/Date TypeDecorator subclasses only override process_bind_param,
which returns the *final* literal SQL text ("TIMESTAMP '2023-05-01'") -
Presto/Trino don't support parameter binding for these types, so
process_bind_param has always done double duty as the literal-rendering
hook too.

TypeDecorator.literal_processor()'s standard composition, when only
process_bind_param is overridden (no process_literal_param), pipes its
output through the *impl* type's own literal_processor - i.e. it takes
the string "TIMESTAMP '2023-05-01'" and still runs it through the real
TIMESTAMP type's literal processor, which expects an actual datetime
and calls .isoformat() on it. That blows up with a CompileError. This
composition happens for the process_bind_param fallback path
regardless of whether SQLAlchemy 1.4 or 2.0 - confirmed empirically
that overriding process_literal_param instead doesn't help either,
since TypeDecorator's own literal_processor() chains *both* paths
through the impl processor when the impl has one.

Fixed by overriding literal_processor() directly on both classes -
against TypeDecorator's own docstring advice ("should not implement
this method"), but correct here since process_bind_param already
returns final SQL text rather than a value for further impl
processing to convert.

Separately, hive_tests.py/presto_tests.py hardcoded the expected
compiled SQL for an empty-column select() with two spaces before the
newline ("SELECT  \n"); SQLAlchemy 2.0 renders it with one ("SELECT
\n") - a cosmetic Core-compiler change, fixed the expected strings to
match.

Verified locally (sqlite): tests/integration_tests/db_engine_specs/
and tests/unit_tests/db_engine_specs/ where_latest_partition tests
(hive, presto, trino, both integration and unit) all pass.
2026-08-10 04:39:58 -07:00
Claude Code 9909f1b0ff experiment: stop double-encoding passwords now that URL.render_as_string() encodes them
Root cause of the "mypass%25123" != "mypass%123" and "p%40ss%21word"
!= "p@ss!word" round-trip failures in test_database_password_encoding.py:
Database.sqlalchemy_uri_decrypted manually percent-encoded the password
with urllib.parse.quote() before handing it to
URL.render_as_string(hide_password=False). Under SQLAlchemy 1.4,
render_as_string() rendered URL.password as a literal value, so the
manual pre-encoding was necessary. Under SQLAlchemy 2.0,
render_as_string() always percent-encodes the password itself - the
pre-encoded value gets encoded a second time (a literal "%" becomes
"%25", which decodes back to "%25" instead of "%" on the next parse).
Passing the raw password straight through and letting
render_as_string() do the (now single) encoding fixes the round-trip.

Confirmed the double-encoding mechanism directly against this branch's
sqlalchemy==2.0.51: URL.set(password=<pre-encoded>).render_as_string()
produces "mypass%2525123"; URL.set(password=<raw>).render_as_string()
correctly produces "mypass%25123".

Separately, model_tests.py::test_impersonate_user_trino (and the
mysqlclient-only test_adjust_engine_params_mysql, exercised on real CI
runners but skipped here where mysqlclient isn't importable) asserted
on str(url) for URLs containing a password. SQLAlchemy 2.0 also changed
URL.__str__() to hide the password by default (a deliberate hardening
change - 1.4 rendered it in full); switched those assertions to
render_as_string(hide_password=False) to compare against the real,
unmasked URL the engine was actually constructed with, rather than
relaxing what's being verified.

Verified locally (sqlite): test_database_password_encoding.py (5/5)
and model_tests.py (21 passed, 5 skipped - the mysqlclient-gated ones)
both pass clean.
2026-08-10 04:39:13 -07:00
Claude Code c89b71986b experiment: use db.session.get_bind() instead of the now-None db.session.bind
Root cause: Flask-SQLAlchemy 2.x's SignallingSession.__init__ explicitly
passed `bind=<default engine>` into the SQLAlchemy Session constructor.
Flask-SQLAlchemy 3.x dropped that - it resolves the engine per-call via
Session.get_bind() (consulting the app's registered engines) instead of
fixing one at session-construction time, to support its reworked
multi-engine/multi-bind model. db.session.bind is therefore always None
under FSA 3.x; it was never a documented API, just an implementation
detail of FSA 2.x's Session subclass.

Confirmed locally: `db.session.bind` prints None while
`db.session.get_bind()` correctly resolves the live Engine, against
this branch's real flask-sqlalchemy==3.1.1/sqlalchemy==2.0.51 install.

Fixes the "AttributeError: 'NoneType' object has no attribute 'dialect'"
failures in dashboards/soft_delete_tests.py's partial-index dialect
detection, and pre-emptively fixes the same pattern in
versioning/id_reuse_tests.py (skipped under postgres/current in the CI
run that surfaced this, so not in the failure log there, but broken by
the same mechanism whenever it does run).

Verified locally against both sqlite and a real postgres:17-alpine
container: dashboards/soft_delete_tests.py and
versioning/id_reuse_tests.py pass clean on both backends after this fix.
2026-08-10 04:39:13 -07:00
Claude Code 9d7dde17a9 experiment: add missing db.session.add() in report-schedule test fixtures
Root cause of the ReportSchedule "is not persisted" InvalidRequestError
and the cascaded StaleDataError/PendingRollbackError fan-out seen across
charts/api_tests.py and dashboards/api_tests.py in CI: SQLAlchemy 2.0
removes the legacy cascade_backrefs behavior entirely. Under 1.4,
constructing `ReportSchedule(chart=chart)` where `chart` was already a
persistent, session-tracked object implicitly added the new
ReportSchedule to the session too, via the Slice.report_schedules
backref collection. That auto-cascade is gone in 2.0 (this is a
documented, intentional SQLAlchemy 1.4->2.0 removal, not a bug) - an
explicit db.session.add() is now required.

Without it, `create_chart_with_report`/`create_dashboard_with_report`
committed a ReportSchedule that was silently never persisted. The
actual test bodies then found no report attached (delete succeeded
with 200 instead of the expected 422 block), and fixture teardown's
`db.session.delete(report_schedule)` blew up with "Instance ... is not
persisted" since the object was transient all along. The dashboard
variant's cascading StaleDataError on dashboard_slices was a downstream
symptom of the same root cause (the "blocked" dashboard delete actually
went through).

Other ReportSchedule(...) construction sites in the test suite already
call db.session.add() explicitly (deletion_retention/*, charts/
soft_delete_tests.py, databases/api_tests.py, reports/utils.py) or
never persist the object at all (reports/alert_tests.py,
reports/commands_tests.py) - these two fixtures were the only ones
missing it. Production code is unaffected: BaseDAO.create() already
calls db.session.add() explicitly, so the real create-report code path
never relied on the removed cascade.

Verified locally (real flask-sqlalchemy==3.1.1 + sqlalchemy==2.0.51,
sqlite backend): tests/integration_tests/charts/api_tests.py (96/96)
and tests/integration_tests/dashboards/api_tests.py (156/156) both
pass clean after this fix, including the two previously-failing
report-block tests and the dashboard_slices StaleDataError case.
2026-08-10 04:39:12 -07:00
42e4030104 feat(security): add guest user attributes and get_guest_user_attribute() macro (#33924)
Co-authored-by: Yash Janoria <yash.janoria@314ecorp.com>
Co-authored-by: Evan <evan@preset.io>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Evan Rusackas <evan@rusackas.com>
2026-08-08 16:56:07 -07:00
Bart SkowronandClaude Fable 5 bd03440ac8 feat(alerts-reports): add per-schedule toggle to include/exclude the Explore in Superset link (#42494)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-07 21:05:16 -07:00
Joe LiandClaude Opus 4.8 c901f01693 fix(datasets): preserve metric/column uuids on dataset export (#42393)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-07 11:15:24 -07:00
Mike BridgeandMike Bridge 280253b1fb fix(deletion-retention): dedupe repeated blocked audits (#42863)
Co-authored-by: Mike Bridge <michael.bridge@ext.preset.io>
2026-08-07 10:11:36 -07:00
4f2147009f feat(dashboard): expand all chart descriptions (#32958)
Co-authored-by: Urban Pettersson <urban.pettersson@alteryx.com>
Co-authored-by: rusackas <evan@rusackas.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-06 14:47:30 -07:00
Evan RusackasandClaude Code 2ecce20e48 chore(viz): remove legacy explore_json + viz.py pipeline (#41714)
Co-authored-by: Claude Code <noreply@anthropic.com>
2026-08-06 13:22:15 -07:00
Alexandru Soare 57d6e5c637 feat(hooks): add configurable post-creation hook for dashboards (#42837) 2026-08-06 16:11:55 +03:00
32e4e3c6a8 fix(reports): enforce dashboard readiness and execution budget (#42624)
Co-authored-by: Matt Fitzgerald <matt.fitzgerald@preset.io>
Co-authored-by: Elizabeth Thompson <eschutho@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-08-05 14:30:35 -07:00
126c93b495 fix(versioning): pin shadow-row reads and restore to (id, uuid) (#42797)
Co-authored-by: Mike Bridge <michael.bridge@ext.preset.io>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 11:12:20 -07:00
e103d92b48 feat(versioning): version-history UI (#41551)
Co-authored-by: Kamil Gabryjelski <kamil.gabryjelski@gmail.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Mike Bridge <michael.bridge@ext.preset.io>
2026-08-04 12:37:46 -07:00
Alexandru Soare 3dde95d809 feat(reports): add retry on failure support for reports (#42481) 2026-08-04 18:04:32 +03:00
Yuriy Krasilnikov 457cd3487d fix(api): include query lifecycle timing in /api/v1/chart/data response (#37516) 2026-08-03 17:27:57 -07:00
8f10bda68e feat(soft-delete): Recently Archived view with restore and permanent delete (#41550)
Co-authored-by: Mike Bridge <michael.bridge@ext.preset.io>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-03 12:21:48 -07:00
Mike BridgeandClaude Opus 5 db0b8b1513 test(versioning): un-skip the two obsolete activity-view skips (#42710)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-03 12:07:49 -07:00
Evan RusackasandClaude Opus 4.8 d0503c1b98 fix(dashboard): keep refresh_frequency set via the Advanced JSON editor (#42116) (#42142)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-03 12:00:39 -07:00
Evan RusackasandClaude Fable 5 06628bbd68 feat(i18n): serve language packs as versioned, immutable-cacheable scripts (#41780)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-02 21:59:44 -07:00
Joe Li 120b4420b9 fix(versioning): narrow UUIDs in restore tests (#42654) 2026-08-02 23:54:30 +07:00
Mike Bridge 59a5ae0df3 feat(soft-delete): deletion-retention purge of soft-deleted entities (#41549) 2026-07-30 09:01:12 -07:00
940b670636 feat(versioning): version-restore engine and endpoints for charts, dashboards, and datasets (#42469)
Co-authored-by: Mike Bridge <michael.bridge@ext.preset.io>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-29 09:54:37 -07:00
Enzo MartellucciandClaude Opus 4.8 069605828d feat(subjects): scope principal listings and default new assets to creator groups (#42472)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-29 14:36:45 +02:00
Mehmet Salih Yavuz b983161eef feat(async): cancel running chart queries under GLOBAL_ASYNC_QUERIES (#42305) 2026-07-28 18:02:16 +03:00
a73e2485de feat(versioning): version-history retention cleanup job (#41075)
Co-authored-by: Mike Bridge <michael.bridge@ext.preset.io>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-27 19:59:11 -07:00
8f8331f656 chore: session enforce sqlalchemy 2.0 (#42365)
Co-authored-by: Evan Rusackas <evan@rusackas.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-26 19:28:42 -07:00
Evan RusackasandClaude Code f3fa1c7d4f fix(reports): write a single execution log row per report run (#29857) (#41966)
Co-authored-by: Claude Code <noreply@anthropic.com>
2026-07-24 13:30:31 -07:00
Amin GhadersohiandClaude 3bdf134aaa fix(logging): stop noisy LocalProxy-not-mapped warning for guest users (#42306)
Co-authored-by: Claude <noreply@anthropic.com>
2026-07-24 13:06:20 -04:00
Ujjwal Jain 3ff5dbfe81 fix(native-filters): use FILTER_STATE_CACHE_CONFIG timeout for dynamic filter option queries (#38910) 2026-07-23 21:01:54 -07:00
Hans Yu 19159d58c8 refactor: engine enforce SQLAlchemy 2.0 (#42277) 2026-07-22 11:11:48 -07:00
SkinnyPigeonandEvan 8c5d465a65 feat(datasets): add RLS filter indicator badge to dataset list and explore view (#38807)
Co-authored-by: Evan <evan@preset.io>
2026-07-22 10:07:52 -07:00
c5935b6904 feat(table/pivot-table): correct non-additive totals/subtotals via DB rollup [SIP-216] (#41184)
Co-authored-by: Superset Dev <dev@superset.apache.org>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Amin Ghadersohi <amin.ghadersohi@gmail.com>
2026-07-22 10:06:05 -07:00
40a13883ea refactor: do not cascade to SqlMetric (#42221)
Co-authored-by: Evan Rusackas <evan@rusackas.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 10:26:01 -07:00
Evan RusackasandClaude Code f9378baba8 test(sqla): add the jinja orderby calculated column to the session (#42274)
Co-authored-by: Claude Code <noreply@anthropic.com>
2026-07-21 10:16:29 -07:00
Taras Pashkevych df34b5d277 fix(drill-detail): paginate Elasticsearch samples via engine cursor (#39509) 2026-07-21 10:09:28 -07:00
Evan RusackasandClaude Sonnet 5 b362d36019 chore: remove deck.gl JavaScript tooltip controls and ENABLE_JAVASCRIPT_CONTROLS (#42126)
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-21 10:01:25 -07:00
Hugh A. Miles II 00cb3037e7 feat(dashboard): export dashboard chart data to Excel (async, S3 + email) (#41133) 2026-07-21 12:17:00 -04:00
Hans Yu 6c58afe6ac refactor: do not cascade to TableColumn (#42222) 2026-07-21 09:00:47 -07:00
Evan RusackasandClaude Opus 4.8 e4005f02c6 fix(sqla): render Jinja templates in calculated columns used via orderby adhoc metrics (#41870)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 00:11:26 -07:00
4b659da5c4 fix(reports): positive per-tile chart readiness check for tiled screenshots (#42119)
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: yousoph <sophieyou12@gmail.com>
2026-07-20 17:31:45 -07:00
b3757870cc fix(sqllab): apply SQL_QUERY_MUTATOR in SQL Lab when MUTATE_AFTER_SPLIT is set (#41127)
Co-authored-by: Lucas Wolkersdorfer <lucas.wolkersdorfer@rise-world.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 15:36:45 -07:00
Evan RusackasandClaude Fable 5 48faca5b8d refactor: set cascade_backrefs=False for SqlaTable (#42213)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-20 10:22:00 -07:00
caf017bd0b feat(versioning): cross-entity version activity view (#41076)
Co-authored-by: Mike Bridge <michael.bridge@ext.preset.io>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-18 11:06:54 -07:00
9f230bcfc0 fix(cli): add --username option to import-directory command (#40994)
Co-authored-by: Evan Rusackas <evan@preset.io>
Co-authored-by: Claude <noreply@anthropic.com>
2026-07-17 12:34:38 -07:00
Joe LiandClaude Fable 5 157ef61fd8 fix(charts): render time comparison without a time grain (#42054)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 21:50:46 -07:00
Joe LiandClaude Opus 4.8 de300c70b9 test(app-root): close two blind spots in the subdirectory redirect tests (#42016)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 23:36:47 -07:00