from __future__ import annotations import threading from bottle import Bottle from bottle import redirect from bottle import request from bottle import SimpleTemplate from optuna.storages import BaseStorage from optuna.storages import RDBStorage from optuna.version import __version__ as optuna_ver from ._bottle_util import BottleViewReturn rdb_schema_migrate_lock = threading.Lock() rdb_schema_needs_migrate = False rdb_schema_unsupported = False rdb_schema_template = SimpleTemplate( """ Incompatible RDB Schema Error - Optuna Dashboard

Error: Incompatible RDB Schema

% if rdb_schema_unsupported:

Your Optuna version {{ optuna_ver }} seems outdated against the storage version. Please try updating optuna to the latest version by `$ pip install -U optuna`.

% elif rdb_schema_needs_migrate:

The runtime optuna version {{ optuna_ver }} is no longer compatible with the table schema. Please execute `$ optuna storage upgrade --storage $STORAGE_URL` or press the following button for upgrading the storage.

% end
""" # noqa: E501 ) def update_schema_compatibility_flags(storage: RDBStorage) -> None: global rdb_schema_needs_migrate, rdb_schema_unsupported with rdb_schema_migrate_lock: current_version = storage.get_current_version() head_version = storage.get_head_version() rdb_schema_needs_migrate = current_version != head_version rdb_schema_unsupported = current_version not in storage.get_all_versions() def is_incompatible() -> bool: return rdb_schema_needs_migrate or rdb_schema_unsupported def register_rdb_migration_route(app: Bottle, storage: BaseStorage) -> None: if isinstance(storage, RDBStorage): update_schema_compatibility_flags(storage) @app.get("/incompatible-rdb-schema") def get_incompatible_rdb_schema() -> BottleViewReturn: if not is_incompatible() or not isinstance(storage, RDBStorage): return redirect("/dashboard", 302) return rdb_schema_template.render( rdb_schema_needs_migrate=rdb_schema_needs_migrate, rdb_schema_unsupported=rdb_schema_unsupported, optuna_ver=optuna_ver, ) @app.post("/incompatible-rdb-schema") def post_incompatible_rdb_schema() -> BottleViewReturn: if not isinstance(storage, RDBStorage): return redirect("/dashboard", 302) global rdb_schema_needs_migrate assert not rdb_schema_unsupported with rdb_schema_migrate_lock: storage.upgrade() rdb_schema_needs_migrate = False return redirect("/dashboard", 302) @app.hook("before_request") def check_schema_compatibility() -> None: if not isinstance(storage, RDBStorage): return if request.path != "/" and not request.path.startswith("/dashboard"): return update_schema_compatibility_flags(storage) if is_incompatible(): return redirect("/incompatible-rdb-schema", 302)