def test_legacy_execute_json_v3(get_json_protocol_fixture): robot.reset() protocol_data = get_json_protocol_fixture('3', 'testAllAtomicSingleV3') protocol = JsonProtocol(text=json.dumps(protocol_data), filename=None, contents=protocol_data, schema_version=3) execute_protocol(protocol)
def _run(self): def on_command(message): if message['$'] == 'before': self.log_append() if message['name'] == command_types.PAUSE: self.set_state('paused') if message['name'] == command_types.RESUME: self.set_state('running') self._reset() _unsubscribe = self._broker.subscribe(command_types.COMMAND, on_command) self.startTime = now() self.set_state('running') try: self.resume() self._pre_run_hooks() if ff.use_protocol_api_v2(): bundled_data = None bundled_labware = None if isinstance(self._protocol, PythonProtocol): bundled_data = self._protocol.bundled_data bundled_labware = self._protocol.bundled_labware self._hardware.cache_instruments() ctx = ProtocolContext(loop=self._loop, broker=self._broker, bundled_labware=bundled_labware, bundled_data=bundled_data) ctx.connect(self._hardware) ctx.home() run_protocol(self._protocol, context=ctx) else: self._hardware.broker = self._broker if isinstance(self._protocol, JsonProtocol): execute_protocol(self._protocol) else: exec(self._protocol.contents, {}) self.set_state('finished') self._hardware.home() except Exception as e: log.exception("Exception during run:") self.error_append(e) self.set_state('error') raise e finally: _unsubscribe()
def _simulate(self): self._reset() stack = [] res = [] commands = [] self._containers.clear() self._instruments.clear() self._modules.clear() self._interactions.clear() def on_command(message): payload = message['payload'] description = payload.get('text', '').format(**payload) if message['$'] == 'before': level = len(stack) stack.append(message) commands.append(payload) res.append({ 'level': level, 'description': description, 'id': len(res) }) else: stack.pop() unsubscribe = self._broker.subscribe(command_types.COMMAND, on_command) try: # ensure actual pipettes are cached before driver is disconnected if ff.use_protocol_api_v2(): self._hardware.cache_instruments() instrs = {} for mount, pip in self._hardware.attached_instruments.items(): if pip: instrs[mount] = { 'model': pip['model'], 'id': pip.get('pipette_id', '') } sim = adapters.SynchronousAdapter.build( API.build_hardware_simulator, instrs, [ mod.name() for mod in self._hardware.attached_modules.values() ], strict_attached_instruments=False) sim.home() bundled_data = None bundled_labware = None if isinstance(self._protocol, PythonProtocol): bundled_data = self._protocol.bundled_data bundled_labware = self._protocol.bundled_labware self._simulating_ctx = ProtocolContext( loop=self._loop, hardware=sim, broker=self._broker, bundled_labware=bundled_labware, bundled_data=bundled_data) run_protocol(self._protocol, simulate=True, context=self._simulating_ctx) else: self._hardware.broker = self._broker self._hardware.cache_instrument_models() self._hardware.disconnect() if isinstance(self._protocol, JsonProtocol): execute_protocol(self._protocol) else: exec(self._protocol.contents, {}) finally: # physically attached pipettes are re-cached during robot.connect() # which is important, because during a simulation, the robot could # think that it holds a pipette model that it actually does not if not ff.use_protocol_api_v2(): self._hardware.connect() unsubscribe() instruments, containers, modules, interactions = _accumulate( [_get_labware(command) for command in commands]) self._containers.extend(_dedupe(containers)) self._instruments.extend(_dedupe(instruments)) self._modules.extend(_dedupe(modules)) self._interactions.extend(_dedupe(interactions)) # Labware calibration happens after simulation and before run, so # we have to clear the tips if they are left on after simulation # to ensure that the instruments are in the expected state at the # beginning of the labware calibration flow if not ff.use_protocol_api_v2(): self._hardware.clear_tips() return res
def test_legacy_jsonprotocol_v1(get_json_protocol_fixture): robot.reset() protocol_data = get_json_protocol_fixture('1', 'simple', False) protocol = parse(protocol_data, None) execute_protocol(protocol)
def execute(protocol_file: TextIO, propagate_logs: bool = False, log_level: str = 'warning', emit_runlog: Callable[[Dict[str, Any]], None] = None): """ Run the protocol itself. This is a one-stop function to run a protocol, whether python or json, no matter the api verson, from external (i.e. not bound up in other internal server infrastructure) sources. To run an opentrons protocol from other places, pass in a file like object as protocol_file; this function either returns (if the run has no problems) or raises an exception. To call from the command line use either the autogenerated entrypoint ``opentrons_execute`` or ``python -m opentrons.execute``. If the protocol is using Opentrons Protocol API V1, it does not need to explicitly call :py:meth:`.Robot.connect` or :py:meth:`.Robot.discover_modules`, or :py:meth:`.Robot.cache_instrument_models`. :param file-like protocol_file: The protocol file to execute :param propagate_logs: Whether this function should allow logs from the Opentrons stack to propagate up to the root handler. This can be useful if you're integrating this function in a larger application, but most logs that occur during protocol simulation are best associated with the actions in the protocol that cause them. Default: ``False`` :type propagate_logs: bool :param log_level: The level of logs to emit on the command line.. Default: 'warning' :type log_level: 'debug', 'info', 'warning', or 'error' :param emit_runlog: A callback for printing the runlog. If specified, this will be called whenever a command adds an entry to the runlog, which can be used for display and progress estimation. If specified, the callback should take a single argument (the name doesn't matter) which will be a dictionary (see below). Default: ``None`` The format of the runlog entries is as follows: .. code-block:: python { 'name': command_name, 'payload': { 'text': string_command_text, # The rest of this struct is command-dependent; see # opentrons.commands.commands. Its keys match format # keys in 'text', so that # entry['payload']['text'].format(**entry['payload']) # will produce a string with information filled in } } """ stack_logger = logging.getLogger('opentrons') stack_logger.propagate = propagate_logs stack_logger.setLevel(getattr(logging, log_level.upper(), logging.WARNING)) contents = protocol_file.read() protocol = parse(contents, protocol_file.name) if isinstance(protocol, JsonProtocol)\ or protocol.api_level == '2'\ or (ff.enable_back_compat() and ff.use_protocol_api_v2()): context = get_protocol_api( bundled_labware=getattr(protocol, 'bundled_labware', None), bundled_data=getattr(protocol, 'bundled_data', None)) if emit_runlog: context.broker.subscribe(commands.command_types.COMMAND, emit_runlog) context.home() execute_apiv2.run_protocol(protocol, simulate=False, context=context) else: from opentrons import robot from opentrons.legacy_api import protocols robot.connect() robot.cache_instrument_models() robot.discover_modules() robot.home() if emit_runlog: robot.broker.subscribe(commands.command_types.COMMAND, emit_runlog) if isinstance(protocol, JsonProtocol): protocols.execute_protocol(protocol) else: exec(protocol.contents, {})