From a950cb857594f1fb3ec814020940abf36046583a Mon Sep 17 00:00:00 2001 From: tamarzanzouri Date: Wed, 6 Nov 2024 11:49:33 -0500 Subject: [PATCH] migration and initialization fixes --- .../protocol_engine/state/command_history.py | 1 + .../state/test_command_view_old.py | 5 +- .../persistence/_migrations/v7_to_v8.py | 86 +++++++++++++++++++ .../persistence/file_and_directory_names.py | 2 +- .../persistence/persistence_directory.py | 5 +- .../robot_server/runs/run_data_manager.py | 2 + robot-server/robot_server/runs/run_store.py | 1 + 7 files changed, 97 insertions(+), 5 deletions(-) create mode 100644 robot-server/robot_server/persistence/_migrations/v7_to_v8.py diff --git a/api/src/opentrons/protocol_engine/state/command_history.py b/api/src/opentrons/protocol_engine/state/command_history.py index cac7f04089a..34dd2c88f2a 100644 --- a/api/src/opentrons/protocol_engine/state/command_history.py +++ b/api/src/opentrons/protocol_engine/state/command_history.py @@ -50,6 +50,7 @@ class CommandHistory: def __init__(self) -> None: self._all_command_ids = [] + self._all_failed_command_ids = [] self._all_command_ids_but_fixit_command_ids = [] self._queued_command_ids = OrderedSet() self._queued_setup_command_ids = OrderedSet() diff --git a/api/tests/opentrons/protocol_engine/state/test_command_view_old.py b/api/tests/opentrons/protocol_engine/state/test_command_view_old.py index a5759f8ba62..27aecc545d0 100644 --- a/api/tests/opentrons/protocol_engine/state/test_command_view_old.py +++ b/api/tests/opentrons/protocol_engine/state/test_command_view_old.py @@ -34,13 +34,12 @@ QueueStatus, ) -from opentrons.protocol_engine.state.command_history import CommandEntry +from opentrons.protocol_engine.state.command_history import CommandEntry, CommandHistory from opentrons.protocol_engine.errors import ProtocolCommandFailedError, ErrorOccurrence from opentrons_shared_data.errors.codes import ErrorCodes -from opentrons.protocol_engine.state.command_history import CommandHistory from opentrons.protocol_engine.state.update_types import StateUpdate from .command_fixtures import ( @@ -100,6 +99,8 @@ def get_command_view( # noqa: C901 command_id=command.id, command_entry=CommandEntry(index=index, command=command), ) + if command.error: + command_history.append_failed_command_id(command.id) state = CommandState( command_history=command_history, diff --git a/robot-server/robot_server/persistence/_migrations/v7_to_v8.py b/robot-server/robot_server/persistence/_migrations/v7_to_v8.py new file mode 100644 index 00000000000..fd791c10f92 --- /dev/null +++ b/robot-server/robot_server/persistence/_migrations/v7_to_v8.py @@ -0,0 +1,86 @@ +"""Migrate the persistence directory from schema 7 to 8. + +Summary of changes from schema 7: + +- Adds a new command_intent to store the commands intent in the commands table +- Adds a new source to store the data files origin in the data_files table +- Adds the `boolean_setting` table. +""" + +import json +from pathlib import Path +from contextlib import ExitStack +import shutil +from typing import Any + +import sqlalchemy + +from ..database import sql_engine_ctx, sqlite_rowid +from ..tables import schema_8 +from .._folder_migrator import Migration + +from ..file_and_directory_names import ( + DB_FILE, +) + + +class Migration7to8(Migration): # noqa: D101 + def migrate(self, source_dir: Path, dest_dir: Path) -> None: + """Migrate the persistence directory from schema 6 to 7.""" + # Copy over all existing directories and files to new version + for item in source_dir.iterdir(): + if item.is_dir(): + shutil.copytree(src=item, dst=dest_dir / item.name) + else: + shutil.copy(src=item, dst=dest_dir / item.name) + + dest_db_file = dest_dir / DB_FILE + + # Append the new column to existing protocols and data_files in v6 database + with ExitStack() as exit_stack: + dest_engine = exit_stack.enter_context(sql_engine_ctx(dest_db_file)) + + schema_8.metadata.create_all(dest_engine) + + dest_transaction = exit_stack.enter_context(dest_engine.begin()) + + def add_column( + engine: sqlalchemy.engine.Engine, + table_name: str, + column: Any, + ) -> None: + column_type = column.type.compile(engine.dialect) + engine.execute( + f"ALTER TABLE {table_name} ADD COLUMN {column.key} {column_type}" + ) + + add_column( + dest_engine, + schema_8.run_command_table.name, + schema_8.run_command_table.c.command_error, + ) + + _migrate_command_table_with_new_command_error_col( + dest_transaction=dest_transaction + ) + + +def _migrate_command_table_with_new_command_error_col( + dest_transaction: sqlalchemy.engine.Connection, +) -> None: + """Add a new 'command_intent' column to run_command_table table.""" + select_commands = sqlalchemy.select(schema_8.run_command_table).order_by( + sqlite_rowid + ) + for row in dest_transaction.execute(select_commands).all(): + data = json.loads(row.command) + new_command_error = ( + # Account for old_row.command["error"] being NULL. + None + if "error" not in row.command or data["error"] == None # noqa: E711 + else data["error"] + ) + + dest_transaction.execute( + f"UPDATE run_command SET command_error='{new_command_error}' WHERE row_id={row.row_id}" + ) diff --git a/robot-server/robot_server/persistence/file_and_directory_names.py b/robot-server/robot_server/persistence/file_and_directory_names.py index 7074dd6db2f..2064b3f59fd 100644 --- a/robot-server/robot_server/persistence/file_and_directory_names.py +++ b/robot-server/robot_server/persistence/file_and_directory_names.py @@ -8,7 +8,7 @@ from typing import Final -LATEST_VERSION_DIRECTORY: Final = "7.1" +LATEST_VERSION_DIRECTORY: Final = "8.1" DECK_CONFIGURATION_FILE: Final = "deck_configuration.json" PROTOCOLS_DIRECTORY: Final = "protocols" diff --git a/robot-server/robot_server/persistence/persistence_directory.py b/robot-server/robot_server/persistence/persistence_directory.py index 2dd46711697..19e67fe8333 100644 --- a/robot-server/robot_server/persistence/persistence_directory.py +++ b/robot-server/robot_server/persistence/persistence_directory.py @@ -11,7 +11,7 @@ from anyio import Path as AsyncPath, to_thread from ._folder_migrator import MigrationOrchestrator -from ._migrations import up_to_3, v3_to_v4, v4_to_v5, v5_to_v6, v6_to_v7 +from ._migrations import up_to_3, v3_to_v4, v4_to_v5, v5_to_v6, v6_to_v7, v7_to_v8 from .file_and_directory_names import LATEST_VERSION_DIRECTORY _TEMP_PERSISTENCE_DIR_PREFIX: Final = "opentrons-robot-server-" @@ -55,7 +55,8 @@ async def prepare_active_subdirectory(prepared_root: Path) -> Path: # Subdirectory "7" was previously used on our edge branch for an in-dev # schema that was never released to the public. It may be present on # internal robots. - v6_to_v7.Migration6to7(subdirectory=LATEST_VERSION_DIRECTORY), + v6_to_v7.Migration6to7(subdirectory="7"), + v7_to_v8.Migration7to8(subdirectory=LATEST_VERSION_DIRECTORY), ], temp_file_prefix="temp-", ) diff --git a/robot-server/robot_server/runs/run_data_manager.py b/robot-server/robot_server/runs/run_data_manager.py index 94e441f9d95..fd33f72734e 100644 --- a/robot-server/robot_server/runs/run_data_manager.py +++ b/robot-server/robot_server/runs/run_data_manager.py @@ -366,6 +366,8 @@ async def update(self, run_id: str, current: Optional[bool]) -> Union[Run, BadRu if next_current is False: run_result = await self._run_orchestrator_store.clear() + state_summary = run_result.state_summary + parameters = run_result.parameters run_resource: Union[ RunResource, BadRunResource ] = self._run_store.update_run_state( diff --git a/robot-server/robot_server/runs/run_store.py b/robot-server/robot_server/runs/run_store.py index fad6a31d8b1..1ae9a911267 100644 --- a/robot-server/robot_server/runs/run_store.py +++ b/robot-server/robot_server/runs/run_store.py @@ -176,6 +176,7 @@ def update_run_state( transaction.execute(update_run) transaction.execute(delete_existing_commands) for command_index, command in enumerate(commands): + print(command.error) transaction.execute( insert_command, {