You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by jl...@apache.org on 2026/09/29 07:55:03 UTC
(superset) 01/01: fix(mypy): narrow nullable uuid before RestoreVersionCommand calls
This is an automated email from the ASF dual-hosted git repository.
sadpandajoe pushed a commit to branch ultraset-mh-uuid-unit-versioning-2
in repository https://gitbox.apache.org/repos/asf/superset.git
commit c4bc71afa833f311126bce85eaa34c6b230f757f
Author: Joe Li <47...@users.noreply.github.com>
AuthorDate: Tue Sep 29 07:54:43 2026 +0000
fix(mypy): narrow nullable uuid before RestoreVersionCommand calls
tests/unit_tests/versioning/test_runtime_capture.py and
test_capture_gap_restore.py (added by #44514) pass Dashboard/SqlaTable
.uuid, typed UUID | None via UUIDMixin's nullable column, straight into
RestoreDashboardVersionCommand/RestoreDatasetVersionCommand's
entity_uuid: UUID parameter without narrowing, matching the same defect
class fixed previously in #44394, #44424 and #44648. Extract each .uuid
read into a local and assert it is not None before use, without an
explicit type annotation on the intermediate (the annotation itself
caused the #44648 regression).
Co-Authored-By: Claude Sonnet 5 <no...@anthropic.com>
---
.../versioning/test_capture_gap_restore.py | 52 ++++++++++++++--------
.../unit_tests/versioning/test_runtime_capture.py | 7 ++-
2 files changed, 39 insertions(+), 20 deletions(-)
diff --git a/tests/unit_tests/versioning/test_capture_gap_restore.py b/tests/unit_tests/versioning/test_capture_gap_restore.py
index 9fad0629a12..b1e9bea1e99 100644
--- a/tests/unit_tests/versioning/test_capture_gap_restore.py
+++ b/tests/unit_tests/versioning/test_capture_gap_restore.py
@@ -182,8 +182,10 @@ def test_dataset_restores_complete_post_gap_snapshot(
dataset.metrics.append(SqlMetric(metric_name="later", expression="SUM(3)"))
dataset.table_name = "later"
capture_session.commit()
+ dataset_uuid = dataset.uuid
+ assert dataset_uuid is not None
with patch.object(security_manager, "raise_for_editorship"):
- RestoreDatasetVersionCommand(dataset.uuid, target).run()
+ RestoreDatasetVersionCommand(dataset_uuid, target).run()
capture_session.expire_all()
assert dataset.table_name == "resumed snapshot"
assert (
@@ -232,8 +234,10 @@ def test_dashboard_restores_complete_post_gap_membership(
chart.slice_name = "later chart content"
dashboard.dashboard_title = "later"
capture_session.commit()
+ dashboard_uuid = dashboard.uuid
+ assert dashboard_uuid is not None
with patch.object(security_manager, "raise_for_editorship"):
- RestoreDashboardVersionCommand(dashboard.uuid, target).run()
+ RestoreDashboardVersionCommand(dashboard_uuid, target).run()
capture_session.expire_all()
assert [c.id for c in dashboard.slices] == expected_ids
assert chart.slice_name == "later chart content"
@@ -253,8 +257,10 @@ def test_restore_legitimately_removes_later_children(
dataset.columns.append(TableColumn(column_name="later", type="INT"))
dataset.metrics.append(SqlMetric(metric_name="later", expression="COUNT(*)"))
capture_session.commit()
+ dataset_uuid = dataset.uuid
+ assert dataset_uuid is not None
with patch.object(security_manager, "raise_for_editorship"):
- RestoreDatasetVersionCommand(dataset.uuid, target).run()
+ RestoreDatasetVersionCommand(dataset_uuid, target).run()
capture_session.expire_all()
assert dataset.columns == []
assert dataset.metrics == []
@@ -302,13 +308,15 @@ def test_resume_multiple_flushes_and_rollback(
assert history_counts(capture_session) == before
dataset.table_name = "later"
capture_session.commit()
+ dataset_uuid = dataset.uuid
+ assert dataset_uuid is not None
with patch.object(security_manager, "raise_for_editorship"):
- RestoreDatasetVersionCommand(dataset.uuid, target).run()
+ RestoreDatasetVersionCommand(dataset_uuid, target).run()
assert [(c.column_name, c.verbose_name) for c in dataset.columns] == [
("gap", "final label")
]
with patch.object(security_manager, "raise_for_editorship"):
- RestoreDatasetVersionCommand(dataset.uuid, target_before_gap).run()
+ RestoreDatasetVersionCommand(dataset_uuid, target_before_gap).run()
assert dataset.columns == []
@@ -412,8 +420,10 @@ def test_post_gap_reattach_across_flushes(
capture_session.commit()
capture_session.expire(dashboard, ["slices"])
assert dashboard.slices == []
+ dashboard_uuid = dashboard.uuid
+ assert dashboard_uuid is not None
with patch.object(security_manager, "raise_for_editorship"):
- RestoreDashboardVersionCommand(dashboard.uuid, target).run()
+ RestoreDashboardVersionCommand(dashboard_uuid, target).run()
capture_session.expire(dashboard, ["slices"])
assert dashboard.slices == [chart]
@@ -484,8 +494,10 @@ def test_commit_reconciles_native_detach_with_same_transaction_reattach(
capture_session.commit()
capture_session.expire(dashboard, ["slices"])
assert dashboard.slices == []
+ dashboard_uuid = dashboard.uuid
+ assert dashboard_uuid is not None
with patch.object(security_manager, "raise_for_editorship"):
- RestoreDashboardVersionCommand(dashboard.uuid, target).run()
+ RestoreDashboardVersionCommand(dashboard_uuid, target).run()
capture_session.expire(dashboard, ["slices"])
assert dashboard.slices == [chart]
@@ -604,9 +616,13 @@ def test_recycled_child_id_reconciles_across_parents_in_any_order(
old_parent.table_name = "old parent later"
new_parent.table_name = "new parent later"
capture_session.commit()
+ old_parent_uuid = old_parent.uuid
+ new_parent_uuid = new_parent.uuid
+ assert old_parent_uuid is not None
+ assert new_parent_uuid is not None
with patch.object(security_manager, "raise_for_editorship"):
- RestoreDatasetVersionCommand(old_parent.uuid, old_target).run()
- RestoreDatasetVersionCommand(new_parent.uuid, new_target).run()
+ RestoreDatasetVersionCommand(old_parent_uuid, old_target).run()
+ RestoreDatasetVersionCommand(new_parent_uuid, new_target).run()
capture_session.expire_all()
assert old_parent.table_name == "old parent resumed"
assert names(old_parent) == []
@@ -712,13 +728,13 @@ def test_pre_recycle_restore_refuses_when_child_id_now_names_another_child(
last_tx: int = capture_session.scalar(sa.select(sa.func.max(transaction.id)))
excinfo: pytest.ExceptionInfo[RecycledChildIdentityError]
+ old_parent_uuid = scenario.old_parent.uuid
+ assert old_parent_uuid is not None
with (
patch.object(security_manager, "raise_for_editorship"),
pytest.raises(RecycledChildIdentityError) as excinfo,
):
- RestoreDatasetVersionCommand(
- scenario.old_parent.uuid, scenario.pre_recycle_target
- ).run()
+ RestoreDatasetVersionCommand(old_parent_uuid, scenario.pre_recycle_target).run()
assert "left unchanged" in str(excinfo.value)
capture_session.expire_all()
assert scenario.old_parent.table_name == "old parent resumed"
@@ -748,10 +764,10 @@ def test_pre_recycle_restore_recreates_a_child_whose_id_is_no_longer_live(
scenario.children(scenario.new_parent).clear() # captured native delete
capture_session.commit()
+ old_parent_uuid = scenario.old_parent.uuid
+ assert old_parent_uuid is not None
with patch.object(security_manager, "raise_for_editorship"):
- RestoreDatasetVersionCommand(
- scenario.old_parent.uuid, scenario.pre_recycle_target
- ).run()
+ RestoreDatasetVersionCommand(old_parent_uuid, scenario.pre_recycle_target).run()
capture_session.expire_all()
assert scenario.old_parent.table_name == "old parent"
assert scenario.names(scenario.old_parent) == ["captured under old parent"]
@@ -781,10 +797,10 @@ def test_pre_recycle_restore_rewrites_a_same_parent_reborn_child(
)
assert scenario.names(scenario.old_parent) == ["reborn under old parent"]
+ old_parent_uuid = scenario.old_parent.uuid
+ assert old_parent_uuid is not None
with patch.object(security_manager, "raise_for_editorship"):
- RestoreDatasetVersionCommand(
- scenario.old_parent.uuid, scenario.pre_recycle_target
- ).run()
+ RestoreDatasetVersionCommand(old_parent_uuid, scenario.pre_recycle_target).run()
capture_session.expire_all()
assert scenario.old_parent.table_name == "old parent"
assert scenario.names(scenario.old_parent) == ["captured under old parent"]
diff --git a/tests/unit_tests/versioning/test_runtime_capture.py b/tests/unit_tests/versioning/test_runtime_capture.py
index a74490b77d8..043c6fbd82d 100644
--- a/tests/unit_tests/versioning/test_runtime_capture.py
+++ b/tests/unit_tests/versioning/test_runtime_capture.py
@@ -221,12 +221,14 @@ def test_runtime_denial_refuses_restore_before_mutation(
dashboard: Dashboard = Dashboard(dashboard_title="preserved")
capture_session.add(dashboard)
capture_session.commit()
+ dashboard_uuid = dashboard.uuid
+ assert dashboard_uuid is not None
before: dict[str, int] = history_counts(capture_session)
monkeypatch.setitem(
app.config, "VERSIONING_CAPTURE_PREDICATE", lambda session: False
)
with pytest.raises(DashboardNotFoundError):
- RestoreDashboardVersionCommand(dashboard.uuid, uuid4()).run()
+ RestoreDashboardVersionCommand(dashboard_uuid, uuid4()).run()
assert dashboard.dashboard_title == "preserved"
assert history_counts(capture_session) == before
@@ -250,7 +252,8 @@ def test_restore_capture_decision_covers_persisted_mutation(
dashboard: Dashboard = Dashboard(dashboard_title="original")
capture_session.add(dashboard)
capture_session.commit()
- entity_uuid: UUID = dashboard.uuid
+ entity_uuid = dashboard.uuid
+ assert entity_uuid is not None
shadow: Any = version_class(Dashboard)
transaction_id: int = capture_session.scalar(
sa.select(shadow.transaction_id).where(shadow.id == dashboard.id)