Skip to content

Log Warning if connecting to DB with older lightly-studio version#977

Open
MalteEbner wants to merge 19 commits into
mainfrom
malte-lig-9225-raise-an-error-when-connecting-to-a-db-with-a-wrong-version
Open

Log Warning if connecting to DB with older lightly-studio version#977
MalteEbner wants to merge 19 commits into
mainfrom
malte-lig-9225-raise-an-error-when-connecting-to-a-db-with-a-wrong-version

Conversation

@MalteEbner

@MalteEbner MalteEbner commented Apr 21, 2026

Copy link
Copy Markdown
Contributor

What has changed and why?

This PR adds database version tracking so LightlyStudio can detect when it connects to a database created by a different app version.

  • A new database_version table is registered in the SQLModel metadata.
  • Fresh databases get their current lightly-studio package version written automatically.
  • Existing databases with missing or mismatched version metadata now emit a warning instead of being silently accepted.
  • Existing databases with multiple database_version rows now raise an error because that state is ambiguous and should be fixed explicitly.
  • The backend tests now cover fresh databases, missing version metadata, matching versions, mismatched versions, and duplicate version rows.

How has it been tested?

New unittests, manually

  • cd lightly_studio && uv run ruff check src/lightly_studio/db_manager.py tests/test_db_manager.py
  • cd lightly_studio && uv run pytest tests/test_db_manager.py

Did you update CHANGELOG.md?

  • Yes
  • Not needed (internal change)

Summary by CodeRabbit

  • New Features

    • Warns when connecting to a database with a different LightlyStudio version.
  • Improvements

    • Safer database initialization: detects existing schema, initializes version metadata only when appropriate, and surfaces version mismatches without overwriting stored values.
  • API

    • Tag-deletion endpoint path now requires a collection identifier in addition to the tag ID.
  • Tests

    • Added tests covering database version handling and related warnings.
  • Documentation

    • Changelog updated to reflect the new database-version warning.

@coderabbitai

coderabbitai Bot commented Apr 21, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds schema-version management: new DatabaseVersionTable, DB initialization now validates/inits version metadata and logs warnings on mismatches, tests covering version scenarios, an API path-parameter change, and a changelog update.

Changes

Cohort / File(s) Summary
Database version model
lightly_studio/src/lightly_studio/models/database_version.py
New DatabaseVersionTable SQLModel mapped to database_version with version: str primary key.
DB table registration
lightly_studio/src/lightly_studio/api/db_tables.py
Imported DatabaseVersionTable so the model is included in SQLModel metadata.
Database init & validation logic
lightly_studio/src/lightly_studio/db_manager.py
Replaced unconditional SQLModel.metadata.create_all with _validate_or_initialize_database_version(engine) that creates missing tables, detects preexisting managed tables, reads package version via importlib.metadata.version, inspects database_version rows, inserts initial row only for fresh DBs, logs warnings on mismatch, and raises on duplicates.
Tests for version behavior
lightly_studio/tests/test_db_manager.py
Added runtime PACKAGE_VERSION, helper to seed database_version, and tests covering init on new DB, missing-version warning, matching-version suppression, mismatch warning, and error on multiple rows.
API type change
lightly_studio_view/src/lib/schema.d.ts
Extended operations.delete_tag.parameters.path from { tag_id: string } to { collection_id: string; tag_id: string }.
Table coverage constant
lightly_studio/src/lightly_studio/resolvers/dataset_resolver/table_coverage_utils.py
Updated _EXCLUDED_TABLES_COUNT from 2 to 3, affecting expected SQLModel table count.
Changelog
CHANGELOG.md
Updated Unreleased entry: removed Pascal VOC export note, added warning about connecting to a DB with a different LightlyStudio version.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant DBManager
  participant Package as "Package\n(importlib.metadata)"
  participant Database
  Client->>DBManager: connect(database_url, must_exist?)
  DBManager->>Database: create missing SQLModel tables
  DBManager->>Database: SELECT * FROM database_version
  DBManager->>Package: importlib.metadata.version("lightly-studio")
  alt no rows
    DBManager->>Database: INSERT database_version(version=package_version) [only if DB had no managed tables]
    DBManager->>Client: return connection
  else one row
    DBManager->>Database: read stored version
    alt stored == package_version
      DBManager->>Client: return connection
    else stored != package_version
      DBManager-->>Client: log WARNING about version mismatch
      DBManager->>Client: return connection
    end
  else multiple rows
    DBManager-->>Client: raise RuntimeError("Expected at most one row in 'database_version'")
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • JonasWurst
  • lukas-lightly
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 36.36% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title directly describes the main change: adding a warning when connecting to a database with a different (older) LightlyStudio version, which is the core feature added in this PR.
Description check ✅ Passed The description covers all required sections: what changed and why (database version tracking), how it was tested (unit tests and manual validation), and confirms CHANGELOG.md was updated.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch malte-lig-9225-raise-an-error-when-connecting-to-a-db-with-a-wrong-version

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Comment thread lightly_studio_view/src/lib/schema.d.ts Outdated
Comment on lines +4123 to +4124
/** @description The ID of the collection */
collection_id: string;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unrelated

Comment thread CHANGELOG.md Outdated
Comment on lines 14 to 20
- Exposed Pascal VOC segmentation export from the Python interface.
- Show Embedding Plot selection as a filter item in the left panel.
- Added thumbnail quality setting in the Settings dialog. Enable "High Quality Thumbnails" to load compressed JPEG thumbnails in grid views, reducing bandwidth for large datasets.
- Added a floating selection panel to grid pages.
- Tags can be created and assigned directly from the sample and annotation detail view.
- Tags can be created and assigned directly from the side panel in the grid view.
- Tags can be renamed directly from the side panel in the grid view.
- Tags can be deleted from the side panel in the grid view.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moving the Pascal VOC parts together

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3f4518c1d7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread lightly_studio/src/lightly_studio/db_manager.py Outdated
Comment thread lightly_studio/src/lightly_studio/models/database_version.py

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@lightly_studio/src/lightly_studio/db_manager.py`:
- Around line 116-121: In __init__, ensure the SQLAlchemy engine (self._engine)
is disposed if _validate_or_initialize_database_version raises so leftover
connections/pools are closed: wrap the SQLModel.metadata.create_all(...) and
_validate_or_initialize_database_version(...) calls in a try/except (or
try/finally) that calls self._engine.dispose() (or engine.dispose()) on failure
and then re-raises the original exception; this should be applied around the
block that uses _get_existing_managed_tables, SQLModel.metadata.create_all, and
_validate_or_initialize_database_version to guarantee cleanup when
initialization aborts.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: e06bc992-c1ed-4a68-aca9-3c4c724f1b7d

📥 Commits

Reviewing files that changed from the base of the PR and between a4e49c4 and 3f4518c.

📒 Files selected for processing (6)
  • CHANGELOG.md
  • lightly_studio/src/lightly_studio/api/db_tables.py
  • lightly_studio/src/lightly_studio/db_manager.py
  • lightly_studio/src/lightly_studio/models/database_version.py
  • lightly_studio/tests/test_db_manager.py
  • lightly_studio_view/src/lib/schema.d.ts

Comment thread lightly_studio/src/lightly_studio/db_manager.py Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
lightly_studio/src/lightly_studio/db_manager.py (1)

360-363: Compute existing_managed_tables excluding database_version.

existing_managed_tables is computed before create_all, so today this works, but it's fragile: if a prior run ever wrote the database_version table and nothing else (e.g., a partially-initialized DB, or a future change that reorders create_all), the "fresh DB" branch at Line 374-383 would be skipped and the user would get a spurious "missing version metadata" warning on an otherwise empty DB. Consider explicitly excluding DatabaseVersionTable.__tablename__ from the set to make intent robust.

♻️ Proposed tightening
-    existing_managed_tables = set(inspect(engine).get_table_names()).intersection(
-        SQLModel.metadata.tables
-    )
+    managed_table_names = set(SQLModel.metadata.tables) - {
+        DatabaseVersionTable.__tablename__
+    }
+    existing_managed_tables = set(inspect(engine).get_table_names()).intersection(
+        managed_table_names
+    )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lightly_studio/src/lightly_studio/db_manager.py` around lines 360 - 363, The
computation of existing_managed_tables should explicitly exclude the database
version table so the "fresh DB" branch isn't skipped by a pre-existing
database_version row; update the set expression that builds
existing_managed_tables (the one referencing inspect(engine).get_table_names()
and SQLModel.metadata.tables) to remove DatabaseVersionTable.__tablename__
(e.g., subtract or filter out that name) before calling
SQLModel.metadata.create_all(engine), ensuring DatabaseVersionTable does not
affect the fresh-DB detection logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@lightly_studio/src/lightly_studio/db_manager.py`:
- Line 364: The call to metadata.version("lightly-studio") inside
_validate_or_initialize_database_version (invoked from DatabaseEngine.__init__)
can raise importlib.metadata.PackageNotFoundError in dev checkouts; wrap the
metadata.version(...) call in a try/except that catches PackageNotFoundError
(imported from importlib.metadata) and handle it by logging a warning and
skipping version validation (or raising a clearer error explaining that the
package must be installed with pip install -e .), ensuring normal initialization
continues without an uncaught exception.

---

Nitpick comments:
In `@lightly_studio/src/lightly_studio/db_manager.py`:
- Around line 360-363: The computation of existing_managed_tables should
explicitly exclude the database version table so the "fresh DB" branch isn't
skipped by a pre-existing database_version row; update the set expression that
builds existing_managed_tables (the one referencing
inspect(engine).get_table_names() and SQLModel.metadata.tables) to remove
DatabaseVersionTable.__tablename__ (e.g., subtract or filter out that name)
before calling SQLModel.metadata.create_all(engine), ensuring
DatabaseVersionTable does not affect the fresh-DB detection logic.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: a64ab2c7-d12a-418e-8644-29fb936a5ca6

📥 Commits

Reviewing files that changed from the base of the PR and between 3f4518c and f3a73d7.

📒 Files selected for processing (2)
  • lightly_studio/src/lightly_studio/db_manager.py
  • lightly_studio/tests/test_db_manager.py
✅ Files skipped from review due to trivial changes (1)
  • lightly_studio/tests/test_db_manager.py

Comment thread lightly_studio/src/lightly_studio/db_manager.py Outdated
Comment thread CHANGELOG.md Outdated
Comment on lines 14 to 20
- Exposed Pascal VOC segmentation export from the Python interface.
- Show Embedding Plot selection as a filter item in the left panel.
- Added thumbnail quality setting in the Settings dialog. Enable "High Quality Thumbnails" to load compressed JPEG thumbnails in grid views, reducing bandwidth for large datasets.
- Added a floating selection panel to grid pages.
- Tags can be created and assigned directly from the sample and annotation detail view.
- Tags can be created and assigned directly from the side panel in the grid view.
- Tags can be renamed directly from the side panel in the grid view.
- Tags can be deleted from the side panel in the grid view.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moving it to keep the Pascal VOC segmentation parts together

Comment thread CHANGELOG.md Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@lightly_studio/src/lightly_studio/resolvers/dataset_resolver/table_coverage_utils.py`:
- Around line 13-16: The comment above _EXCLUDED_TABLES_COUNT is out of sync
with the count; update the comment to list the third excluded table
`database_version` and note that it is application-level schema version metadata
(not collection-specific) so the enumeration matches the value of
_EXCLUDED_TABLES_COUNT.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 529e5e7b-d75f-42e5-ab5f-9afa2b86aa58

📥 Commits

Reviewing files that changed from the base of the PR and between 4074852 and 80c0ac7.

📒 Files selected for processing (1)
  • lightly_studio/src/lightly_studio/resolvers/dataset_resolver/table_coverage_utils.py

@MalteEbner

Copy link
Copy Markdown
Contributor Author

/review

missing or mismatched version are warned about but never auto-updated, so
the warning persists until the user takes action.
"""
existing_managed_tables = set(inspect(engine).get_table_names()).intersection(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this really need to be handled? What happens if there is an existing database without the DatabaseVersionTable?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is needed to distinguish cases 1 and 2 here:

These cases are handled:
    1. Fresh database with no managed tables: Insert the expected version.
    2. Existing database without a `database_version` table: Warn.
    3. Existing database with a `database_version` table:
         a. With 0 rows: Raise an error, this should not happen.
         b. With >1 rows: Raise an error, this should not happen.
         c. With 1 row and a different version: Warn about incompatible version.
         d. With 1 row and the expected version: Do nothing.



@pytest.fixture
def patch_engine_singleton(mocker: MockerFixture) -> None:

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved to lightly_studio/tests/conftest.py



@pytest.fixture
def patch_engine_singleton(mocker: MockerFixture) -> None:

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved from lightly_studio/tests/test_db_manager.py

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