From dc11876fdb1350d09f40edd61d048927aa54a52f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20H=C3=B6ning?= Date: Wed, 2 Sep 2026 17:04:18 +0200 Subject: [PATCH 1/2] fix: handle unknown alembic revisions during startup --- documentation/changelog.rst | 1 + flexmeasures/data/tests/test_utils.py | 30 +++++++++++++++++++++++++++ flexmeasures/data/utils.py | 4 ++-- 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/documentation/changelog.rst b/documentation/changelog.rst index 02c1e5eb58..60c3827ad7 100644 --- a/documentation/changelog.rst +++ b/documentation/changelog.rst @@ -33,6 +33,7 @@ Bugfixes * KPIs on the asset page counted one day more than the selected time range [see `PR #2434 `_] * KPIs on the asset page now total the values the chart beside them draws, counting each event under the day it starts in: a sensor reported by several sources counted only one of them, and a revised value was counted on top of the value it revised [see `PR #2434 `_] * The time range sent when loading an asset's KPIs was off by the viewer's UTC offset, so KPIs could cover the wrong days [see `PR #2435 `_] +* Avoid crashing on startup when the database is stamped with an Alembic revision unknown to this FlexMeasures checkout [see `PR #XXXX `_] diff --git a/flexmeasures/data/tests/test_utils.py b/flexmeasures/data/tests/test_utils.py index 751d6f6a10..8825c16221 100644 --- a/flexmeasures/data/tests/test_utils.py +++ b/flexmeasures/data/tests/test_utils.py @@ -2,6 +2,7 @@ import logging +from alembic.script.revision import ResolutionError from sqlalchemy.exc import OperationalError, ProgrammingError from flexmeasures.data import db, register_at @@ -54,12 +55,25 @@ def iterate_revisions(self, *args, **kwargs): return (_DummyRevision(revision) for revision in self._revisions) +class _DummyRevisionMapWithUnknownRevision: + def iterate_revisions(self, *args, **kwargs): + def revisions(): + raise ResolutionError("No such revision or branch 'unknown-a'", "unknown-a") + yield + + return revisions() + + class _DummyScriptDirectoryWithRevisionMap(_DummyScriptDirectory): def __init__(self, heads: tuple[str, ...], revisions: tuple[str, ...]): super().__init__(heads) self.revision_map = _DummyRevisionMap(revisions) +class _DummyScriptDirectoryWithUnknownRevisionMap(_DummyScriptDirectory): + revision_map = _DummyRevisionMapWithUnknownRevision() + + def test_schema_mismatch_log_record_is_deduplicated( app, clean_redis, monkeypatch, caplog ): @@ -237,3 +251,19 @@ def test_database_schema_has_revision_false_when_revision_is_not_in_current_hist ) assert database_schema_has_revision(app, "required-a") is False + + +def test_database_schema_has_revision_false_when_current_revision_is_unknown( + app, monkeypatch +): + monkeypatch.setattr(db.engine, "connect", lambda: _DummyConnection()) + monkeypatch.setattr( + "flexmeasures.data.utils.MigrationContext.configure", + lambda connection: _DummyMigrationContext(("unknown-a",)), + ) + monkeypatch.setattr( + "flexmeasures.data.utils.ScriptDirectory.from_config", + lambda config: _DummyScriptDirectoryWithUnknownRevisionMap(("head-a",)), + ) + + assert database_schema_has_revision(app, "required-a") is False diff --git a/flexmeasures/data/utils.py b/flexmeasures/data/utils.py index b684c5d560..f4a84ff2e9 100644 --- a/flexmeasures/data/utils.py +++ b/flexmeasures/data/utils.py @@ -112,10 +112,10 @@ def database_schema_has_revision(app, required_revision: str) -> bool: inclusive=True, assert_relative_length=False, ) + if any(revision.revision == required_revision for revision in revisions): + return True except RevisionError: continue - if any(revision.revision == required_revision for revision in revisions): - return True return False From 0958dea479effc93508293b07afb19c684c3b92a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20H=C3=B6ning?= Date: Wed, 2 Sep 2026 20:18:35 +0200 Subject: [PATCH 2/2] add PR number MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nicolas Höning --- documentation/changelog.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/changelog.rst b/documentation/changelog.rst index 60c3827ad7..7b1e1e272c 100644 --- a/documentation/changelog.rst +++ b/documentation/changelog.rst @@ -33,7 +33,7 @@ Bugfixes * KPIs on the asset page counted one day more than the selected time range [see `PR #2434 `_] * KPIs on the asset page now total the values the chart beside them draws, counting each event under the day it starts in: a sensor reported by several sources counted only one of them, and a revised value was counted on top of the value it revised [see `PR #2434 `_] * The time range sent when loading an asset's KPIs was off by the viewer's UTC offset, so KPIs could cover the wrong days [see `PR #2435 `_] -* Avoid crashing on startup when the database is stamped with an Alembic revision unknown to this FlexMeasures checkout [see `PR #XXXX `_] +* Avoid crashing on startup when the database is stamped with an Alembic revision unknown to this FlexMeasures checkout [see `PR #2465 `_]