def init_on_load(self): """Loads all necessary fields upon Action being loaded from database""" if not self.errors: errors = [] try: self._run, self._arguments_api = get_app_action_api(self.app_name, self.action_name) get_app_action(self.app_name, self._run) except UnknownApp: errors.append('Unknown app {}'.format(self.app_name)) except UnknownAppAction: errors.append('Unknown app action {}'.format(self.action_name)) self.errors = errors self._last_status = None self._execution_id = 'default' self._resolved_device_id = -1
def validate_actions(actions, dereferencer, app_name): from walkoff.appgateway import get_app_action from walkoff.appgateway import get_all_actions_for_app defined_actions = get_all_actions_for_app(app_name) seen = set() for action_name, action in actions.items(): if action['run'] not in defined_actions: raise InvalidApi('Action {0} has "run" property {1} ' 'which is not defined in App {2}'.format( action_name, action['run'], app_name)) action = dereferencer(action) action_params = dereferencer(action.get('parameters', [])) event = action.get('event', '') if action_params: validate_action_params(action_params, dereferencer, app_name, action_name, get_app_action(app_name, action['run']), event=event) if 'default_return' in action: if action['default_return'] not in action.get('returns', []): raise InvalidApi( 'Default return {} not in defined return codes {}'.format( action['default_return'], action.get('returns', []).keys())) validate_app_action_return_codes(action.get('returns', []), app_name, action_name) seen.add(action['run']) if seen != set(defined_actions): logger.warning( 'App {0} has defined the following actions which do not have a corresponding API: ' '{1}'.format(app_name, (set(defined_actions) - seen)))
def init_on_load(self): """Loads all necessary fields upon Action being loaded from database""" self._run, self._arguments_api = get_app_action_api( self.app_name, self.action_name) self._output = None self._action_executable = get_app_action(self.app_name, self._run) self._execution_id = 'default'
def validate_actions(actions, dereferencer, app_name): from walkoff.appgateway import get_app_action from walkoff.appgateway import get_all_actions_for_app defined_actions = get_all_actions_for_app(app_name) seen = set() for action_name, action in actions.items(): if action['run'] not in defined_actions: raise InvalidApi('Action {0} has "run" property {1} ' 'which is not defined in App {2}'.format(action_name, action['run'], app_name)) action = dereferencer(action) action_params = dereferencer(action.get('parameters', [])) event = action.get('event', '') if action_params: validate_action_params(action_params, dereferencer, app_name, action_name, get_app_action(app_name, action['run']), event=event) if 'default_return' in action: if action['default_return'] not in action.get('returns', []): raise InvalidApi( 'Default return {} not in defined return codes {}'.format( action['default_return'], action.get('returns', []).keys())) validate_app_action_return_codes(action.get('returns', []), app_name, action_name) seen.add(action['run']) if seen != set(defined_actions): logger.warning('App {0} has defined the following actions which do not have a corresponding API: ' '{1}'.format(app_name, (set(defined_actions) - seen)))
def init_on_load(self): """Loads all necessary fields upon Action being loaded from database""" if not self.errors: errors = [] try: self._run, self._arguments_api = get_app_action_api( self.app_name, self.action_name) get_app_action(self.app_name, self._run) except UnknownApp: errors.append('Unknown app {}'.format(self.app_name)) except UnknownAppAction: errors.append('Unknown app action {}'.format(self.action_name)) self.errors = errors self._last_status = None self._execution_id = 'default' self._resolved_device_id = -1
def validate(self): """Validates the object""" errors = [] try: self._run, self._arguments_api = get_app_action_api(self.app_name, self.action_name) get_app_action(self.app_name, self._run) if is_app_action_bound(self.app_name, self._run) and not self.device_id: message = 'App action is bound but no device ID was provided.'.format(self.name) errors.append(message) validate_app_action_parameters(self._arguments_api, self.arguments, self.app_name, self.action_name) except UnknownApp: errors.append('Unknown app {}'.format(self.app_name)) except UnknownAppAction: errors.append('Unknown app action {}'.format(self.action_name)) except InvalidArgument as e: errors.extend(e.errors) self.errors = errors
def validate(self): """Validates the object""" errors = [] try: self._run, self._arguments_api = get_app_action_api( self.app_name, self.action_name) get_app_action(self.app_name, self._run) if is_app_action_bound(self.app_name, self._run) and not self.device_id: message = 'App action is bound but no device ID was provided.'.format( self.name) errors.append(message) validate_app_action_parameters(self._arguments_api, self.arguments, self.app_name, self.action_name) except UnknownApp: errors.append('Unknown app {}'.format(self.app_name)) except UnknownAppAction: errors.append('Unknown app action {}'.format(self.action_name)) except InvalidArgument as e: errors.extend(e.errors) self.errors = errors
def test_validate_action_params_too_few_params_in_api(self): self.basicapi['actions']['Add Three'] = {'run': 'main.Main.addThree', 'parameters': [{'name': 'num1', 'type': 'number'}, {'name': 'num2', 'type': 'number'}]} self.__generate_resolver_dereferencer(self.basicapi) with self.assertRaises(InvalidApi): validate_action_params(self.basicapi['actions']['Add Three']['parameters'], self.dereferencer, 'HelloWorldBounded', 'Add Three', get_app_action('HelloWorldBounded', 'main.Main.addThree'))
def test_validate_action_params_no_duplicate_params_matches_signature(self): self.basicapi['actions']['Add Three'] = {'run': 'main.Main.addThree', 'parameters': [{'name': 'num1', 'type': 'number'}, {'name': 'num2', 'type': 'number'}, {'name': 'num3', 'type': 'number'}]} self.__generate_resolver_dereferencer(self.basicapi) validate_action_params(self.basicapi['actions']['Add Three']['parameters'], self.dereferencer, 'HelloWorldBounded', 'Add Three', get_app_action('HelloWorldBounded', 'main.Main.addThree'))
def test_validate_action_params_duplicate_param_name(self): self.basicapi['actions']['Add Three'] = {'run': 'main.Main.addThree', 'parameters': [{'name': 'num1', 'type': 'number'}, {'name': 'num1', 'type': 'string'}, {'name': 'num2', 'type': 'number'}]} self.__generate_resolver_dereferencer(self.basicapi, expected_success=False) with self.assertRaises(InvalidApi): validate_action_params(self.basicapi['actions']['Add Three']['parameters'], self.dereferencer, 'HelloWorldBounded', 'Add Three', get_app_action('HelloWorldBounded', 'main.Main.addThree'))
def __init__(self, app_name, action_name, name, device_id=None, id=None, arguments=None, trigger=None, position=None): """Initializes a new Action object. A Workflow has one or more actions that it executes. Args: app_name (str): The name of the app associated with the Action action_name (str): The name of the action associated with a Action name (str): The name of the Action object. device_id (int, optional): The id of the device associated with the app associated with the Action. Defaults to None. id (str|UUID, optional): Optional UUID to pass into the Action. Must be UUID object or valid UUID string. Defaults to None. arguments (list[Argument], optional): A list of Argument objects that are parameters to the action. Defaults to None. trigger (ConditionalExpression, optional): A ConditionalExpression which causes an Action to wait until the data is sent fulfilling the condition. Defaults to None. position (Position, optional): Position object for the Action. Defaults to None. """ ExecutionElement.__init__(self, id) self.trigger = trigger self.name = name self.device_id = device_id self.app_name = app_name self.action_name = action_name self.arguments = [] if arguments: self.arguments = arguments self.position = position self._run = None self._arguments_api = None self._output = None self._execution_id = 'default' self.validate() self._action_executable = get_app_action(self.app_name, self._run)
def test_validate_action_params_too_few_params_in_api(self): self.basicapi['actions']['Add Three'] = { 'run': 'main.Main.addThree', 'parameters': [{ 'name': 'num1', 'type': 'number' }, { 'name': 'num2', 'type': 'number' }] } self.__generate_resolver_dereferencer(self.basicapi) with self.assertRaises(InvalidApi): validate_action_params( self.basicapi['actions']['Add Three']['parameters'], self.dereferencer, 'HelloWorldBounded', 'Add Three', get_app_action('HelloWorldBounded', 'main.Main.addThree'))
def test_validate_action_params_no_duplicate_params_matches_signature( self): self.basicapi['actions']['Add Three'] = { 'run': 'main.Main.addThree', 'parameters': [{ 'name': 'num1', 'type': 'number' }, { 'name': 'num2', 'type': 'number' }, { 'name': 'num3', 'type': 'number' }] } self.__generate_resolver_dereferencer(self.basicapi) validate_action_params( self.basicapi['actions']['Add Three']['parameters'], self.dereferencer, 'HelloWorldBounded', 'Add Three', get_app_action('HelloWorldBounded', 'main.Main.addThree'))
def test_validate_action_params_duplicate_param_name(self): self.basicapi['actions']['Add Three'] = { 'run': 'main.Main.addThree', 'parameters': [{ 'name': 'num1', 'type': 'number' }, { 'name': 'num1', 'type': 'string' }, { 'name': 'num2', 'type': 'number' }] } self.__generate_resolver_dereferencer(self.basicapi, expected_success=False) with self.assertRaises(InvalidApi): validate_action_params( self.basicapi['actions']['Add Three']['parameters'], self.dereferencer, 'HelloWorldBounded', 'Add Three', get_app_action('HelloWorldBounded', 'main.Main.addThree'))
def __init__(self, app_name, action_name, name='', device_id=None, arguments=None, triggers=None, position=None, uid=None, templated=False, raw_representation=None): """Initializes a new Action object. A Workflow has many actions that it executes. Args: app_name (str): The name of the app associated with the Action action_name (str): The name of the action associated with a Action name (str, optional): The name of the Action object. Defaults to an empty string. device_id (int, optional): The id of the device associated with the app associated with the Action. Defaults to None. arguments ([Argument], optional): A list of Argument objects that are parameters to the action. Defaults to None. triggers (list[Flag], optional): A list of Flag objects for the Action. If a Action should wait for data before continuing, then include these Trigger objects in the Action init. Defaults to None. position (dict, optional): A dictionary with the x and y coordinates of the Action object. This is used for UI display purposes. Defaults to None. uid (str, optional): A universally unique identifier for this object. Created from uuid.uuid4().hex in Python templated (bool, optional): Whether or not the Action is templated. Used for Jinja templating. raw_representation (dict, optional): JSON representation of this object. Used for Jinja templating. """ ExecutionElement.__init__(self, uid) self.triggers = triggers if triggers is not None else [] self._incoming_data = None self._event = threading.Event() self.name = name self.device_id = device_id self.app_name = app_name self.action_name = action_name self._run, self._arguments_api = get_app_action_api( self.app_name, self.action_name) if is_app_action_bound(self.app_name, self._run) and not self.device_id: raise InvalidArgument( "Cannot initialize Action {}. App action is bound but no device ID was provided." .format(self.name)) self._action_executable = get_app_action(self.app_name, self._run) arguments = {argument.name: argument for argument in arguments } if arguments is not None else {} self.templated = templated if not self.templated: validate_app_action_parameters(self._arguments_api, arguments, self.app_name, self.action_name) self.arguments = arguments self.position = position if position is not None else {} self._output = None self._raw_representation = raw_representation if raw_representation is not None else {} self._execution_uid = 'default'