Skip to content

Commit

Permalink
initial thoughts
Browse files Browse the repository at this point in the history
progress

update on fail

added completed_with_error to update signature

added tests and fixed linting

fixed linting

added EnumeratedError to errors list and removed completed_with_error

create an ErrorOccurence from the internal error

monkeypatching not going so well

progress with mocking. still not complete

fixed mocking!need fo figure out datetime failing

fixed bug with datetime compare

remove unnecessary test

reverted changes and restructured

removed print

reverted changes

Update robot-server/robot_server/protocols/protocol_analyzer.py

Co-authored-by: Seth Foster <seth@opentrons.com>

pr fixes
  • Loading branch information
TamarZanzouri committed Feb 16, 2024
1 parent eca3731 commit 2c6489f
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 153 deletions.
10 changes: 10 additions & 0 deletions robot-server/robot_server/errors/error_mappers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
"""Map errors to Exceptions."""
from opentrons_shared_data.errors import EnumeratedError, PythonException


def map_unexpected_error(error: BaseException) -> EnumeratedError:
"""Map an unhandled Exception to a known exception."""
if isinstance(error, EnumeratedError):
return error
else:
return PythonException(error)
33 changes: 29 additions & 4 deletions robot-server/robot_server/protocols/protocol_analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@
import logging

from opentrons import protocol_runner
from opentrons.protocol_engine.errors import ErrorOccurrence
import opentrons.util.helpers as datetime_helper

import robot_server.errors.error_mappers as em

from .protocol_store import ProtocolResource
from .analysis_store import AnalysisStore


log = logging.getLogger(__name__)


Expand All @@ -30,9 +33,31 @@ async def analyze(
robot_type=protocol_resource.source.robot_type,
protocol_config=protocol_resource.source.config,
)
result = await runner.run(
protocol_source=protocol_resource.source, deck_configuration=[]
)
try:
result = await runner.run(
protocol_source=protocol_resource.source, deck_configuration=[]
)
except BaseException as error:
internal_error = em.map_unexpected_error(error=error)
await self._analysis_store.update(
analysis_id=analysis_id,
robot_type=protocol_resource.source.robot_type,
commands=[],
labware=[],
modules=[],
pipettes=[],
errors=[
ErrorOccurrence.from_failed(
# TODO(tz, 2-15-24): replace with a different error type
# when we are able to support different errors.
id="internal-error",
createdAt=datetime_helper.utc_now(),
error=internal_error,
)
],
liquids=[],
)
return

log.info(f'Completed analysis "{analysis_id}".')

Expand Down
99 changes: 99 additions & 0 deletions robot-server/tests/protocols/test_protocol_analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,30 @@
)
import opentrons.protocol_runner as protocol_runner
from opentrons.protocol_reader import ProtocolSource, JsonProtocolConfig
import opentrons.util.helpers as datetime_helper

from robot_server.protocols.analysis_store import AnalysisStore
from robot_server.protocols.protocol_store import ProtocolResource
from robot_server.protocols.protocol_analyzer import ProtocolAnalyzer
import robot_server.errors.error_mappers as em

from opentrons_shared_data.errors import EnumeratedError, ErrorCodes


@pytest.fixture(autouse=True)
def patch_mock_map_unexpected_error(
decoy: Decoy, monkeypatch: pytest.MonkeyPatch
) -> None:
"""Replace map_unexpected_error with a mock."""
mock_map_unexpected_error = decoy.mock(func=em.map_unexpected_error)
monkeypatch.setattr(em, "map_unexpected_error", mock_map_unexpected_error)


@pytest.fixture(autouse=True)
def patch_mock_get_utc_datetime(decoy: Decoy, monkeypatch: pytest.MonkeyPatch) -> None:
"""Replace utc_now with a mock."""
mock_get_utc_datetime = decoy.mock(func=datetime_helper.utc_now)
monkeypatch.setattr(datetime_helper, "utc_now", mock_get_utc_datetime)


@pytest.fixture(autouse=True)
Expand Down Expand Up @@ -146,3 +166,82 @@ async def test_analyze(
liquids=[],
),
)


async def test_analyze_updates_pending_on_error(
decoy: Decoy,
analysis_store: AnalysisStore,
subject: ProtocolAnalyzer,
) -> None:
"""It should update pending analysis with an internal error."""
robot_type: RobotType = "OT-3 Standard"

protocol_resource = ProtocolResource(
protocol_id="protocol-id",
created_at=datetime(year=2021, month=1, day=1),
source=ProtocolSource(
directory=Path("/dev/null"),
main_file=Path("/dev/null/abc.json"),
config=JsonProtocolConfig(schema_version=123),
files=[],
metadata={},
robot_type=robot_type,
content_hash="abc123",
),
protocol_key="dummy-data-111",
)

raised_exception = Exception("You got me!!")

error_occurrence = pe_errors.ErrorOccurrence.construct(
id="internal-error",
createdAt=datetime(year=2023, month=3, day=3),
errorType="EnumeratedError",
detail="You got me!!",
)

enumerated_error = EnumeratedError(
code=ErrorCodes.GENERAL_ERROR,
message="You got me!!",
)

json_runner = decoy.mock(cls=protocol_runner.JsonRunner)

decoy.when(
await protocol_runner.create_simulating_runner(
robot_type=robot_type,
protocol_config=JsonProtocolConfig(schema_version=123),
)
).then_return(json_runner)

decoy.when(
await json_runner.run(
deck_configuration=[], protocol_source=protocol_resource.source
)
).then_raise(raised_exception)

decoy.when(em.map_unexpected_error(error=raised_exception)).then_return(
enumerated_error
)

decoy.when(datetime_helper.utc_now()).then_return(
datetime(year=2023, month=3, day=3)
)

await subject.analyze(
protocol_resource=protocol_resource,
analysis_id="analysis-id",
)

decoy.verify(
await analysis_store.update(
analysis_id="analysis-id",
robot_type=robot_type,
commands=[],
labware=[],
modules=[],
pipettes=[],
errors=[error_occurrence],
liquids=[],
),
)
149 changes: 0 additions & 149 deletions shared-data/fixture/schemas/1.json

This file was deleted.

0 comments on commit 2c6489f

Please sign in to comment.