Source code for s4.clarity.scripts.triggered_step_epp

# Copyright 2016 Semaphore Solutions, Inc.
# ---------------------------------------------------------------------------
from .stepepp import StepEPP
import logging
import re

log = logging.getLogger(__name__)


class TriggeredStepEPP(StepEPP):
    """ TriggeredStepEPP acts as an EPP with multiple entry points, to allow the developer to group all scripts
    associated with a step together in a single file. A script implementing this class is intended to be called
    multiple times in the same step at different stages, with the Action parameter determining which method is called.

    Choices for the Action parameter are automatically generated from all class methods starting with ``on_``. The
    Action value is generated by taking the method name, trimming the ``on_``, and transforming the rest of the name to
    Pascal-case. For example, an EPP String containing ``-a TestThing`` would attempt to execute a method named
    ``on_test_thing``.

    Usage:
        ``python <script.py> -u {username} -p {password} --step-uri {stepURI:v2} -l {compoundOutputFileLuid#} -a <Action>``


    Our suggested implementation when creating method names is to mirror Clarity's language for scripts triggered
    on step transitions, and having button-triggered scripts follow the button label, as shown here:

    ====================      ===============
    Action Parameter          EPP Method Name
    ====================      ===============
    BeginningOfStep           on_beginning_of_step
    EndOfStep                 on_end_of_step
    PlacementEnter            on_placement_enter
    PlacementExit             on_placement_exit
    PoolingEnter              on_pooling_enter
    PoolingExit               on_pooling_exit
    AddReagentsEnter          on_add_reagents_enter
    AddReagentsExit           on_add_reagents_exit
    RecordDetailsEnter        on_record_details_enter
    RecordDetailsExit         on_record_details_exit
    CalculateQc               on_calculate_qc  (Record Details buttons example)
    ====================      ===============

    Ultimately, though, as long as the ``on_`` rules for method naming is followed, the pattern used in your
    implementation is up to you.

    """

    triggered_step_actions = {}

[docs] @classmethod def add_triggered_step_actions(cls): action_handler_names = [method for method in dir(cls) if method.startswith('on_')] for action_handler_name in action_handler_names: cls.triggered_step_actions[cls._generate_action(action_handler_name)] = getattr(cls, action_handler_name)
@classmethod def _generate_action(cls, action_handler_name): # Converts snake-case to camel-case, and remove the ``on`` from the front # eg. ``on_record_details_enter`` would be transformed to ``RecordDetailsEnter`` return re.sub('_.', lambda x: x.group()[1].upper(), action_handler_name).lstrip('on')
[docs] @classmethod def add_arguments(cls, argparser): super(TriggeredStepEPP, cls).add_arguments(argparser) cls.add_triggered_step_actions() argparser.add_argument("-a", "--action", choices=list(cls.triggered_step_actions), required=True)
[docs] def run(self): log.info("Handling Action '%s'" % self.options.action) action_arg = self.triggered_step_actions.get(self.options.action) if action_arg: action_arg(self)