diff --git a/platypush/procedure/__init__.py b/platypush/procedure/__init__.py index d78e19d7..58e9ec77 100644 --- a/platypush/procedure/__init__.py +++ b/platypush/procedure/__init__.py @@ -19,14 +19,14 @@ class Statement(enum.Enum): RETURN = 'return' -class Procedure(object): - """ Procedure class. A procedure is a pre-configured list of requests """ +class Procedure: + """Procedure class. A procedure is a pre-configured list of requests""" def __init__(self, name, _async, requests, args=None, backend=None): """ Params: name -- Procedure name - _async -- Whether the actions in the procedure are supposed to + _async -- Whether the actions in the procedure are supposed to be executed sequentially or in parallel (True or False) requests -- List of platypush.message.request.Request objects """ @@ -42,7 +42,17 @@ class Procedure(object): req.backend = self.backend @classmethod - def build(cls, name, _async, requests, args=None, backend=None, id=None, procedure_class=None, **kwargs): + def build( + cls, + name, + _async, + requests, + args=None, + backend=None, + id=None, + procedure_class=None, + **kwargs, + ): reqs = [] for_count = 0 while_count = 0 @@ -64,25 +74,28 @@ class Procedure(object): if m: if_count += 1 - if_name = '{}__if_{}'.format(name, if_count) + if_name = f'{name}__if_{if_count}' condition = m.group(2) - if_config.put({ - 'name': if_name, - '_async': False, - 'requests': request_config[key], - 'condition': condition, - 'else_branch': [], - 'backend': backend, - 'id': id, - }) + if_config.put( + { + 'name': if_name, + '_async': False, + 'requests': request_config[key], + 'condition': condition, + 'else_branch': [], + 'backend': backend, + 'id': id, + } + ) continue if key == 'else': if if_config.empty(): - raise RuntimeError('else statement with no ' + - 'associated if in {}'.format(name)) + raise RuntimeError( + f'else statement with no associated if in {name}' + ) conf = if_config.get() conf['else_branch'] = request_config[key] @@ -100,19 +113,23 @@ class Procedure(object): if m: for_count += 1 - loop_name = '{}__for_{}'.format(name, for_count) + loop_name = f'{name}__for_{for_count}' # A 'for' loop is synchronous. Declare a 'fork' loop if you # want to process the elements in the iterable in parallel - _async = True if m.group(1) == 'fork' else False + _async = m.group(1) == 'fork' iterator_name = m.group(2) iterable = m.group(3) - loop = ForProcedure.build(name=loop_name, _async=_async, - requests=request_config[key], - backend=backend, id=id, - iterator_name=iterator_name, - iterable=iterable) + loop = ForProcedure.build( + name=loop_name, + _async=_async, + requests=request_config[key], + backend=backend, + id=id, + iterator_name=iterator_name, + iterable=iterable, + ) reqs.append(loop) continue @@ -124,13 +141,17 @@ class Procedure(object): if m: while_count += 1 - loop_name = '{}__while_{}'.format(name, while_count) + loop_name = f'{name}__while_{while_count}' condition = m.group(1).strip() - loop = WhileProcedure.build(name=loop_name, _async=False, - requests=request_config[key], - condition=condition, - backend=backend, id=id) + loop = WhileProcedure.build( + name=loop_name, + _async=False, + requests=request_config[key], + condition=condition, + backend=backend, + id=id, + ) reqs.append(loop) continue @@ -147,8 +168,14 @@ class Procedure(object): pending_if = if_config.get() reqs.append(IfProcedure.build(**pending_if)) - # noinspection PyArgumentList - return procedure_class(name=name, _async=_async, requests=reqs, args=args, backend=backend, **kwargs) + return procedure_class( + name=name, + _async=_async, + requests=reqs, + args=args, + backend=backend, + **kwargs, + ) @staticmethod def _find_nearest_loop(stack): @@ -175,9 +202,9 @@ class Procedure(object): v = Request.expand_value_from_context(v, **context) args[k] = v context[k] = v - logger.info('Executing procedure {} with arguments {}'.format(self.name, args)) + logger.info('Executing procedure %s with arguments %s', self.name, args) else: - logger.info('Executing procedure {}'.format(self.name)) + logger.info('Executing procedure %s', self.name) response = Response() token = Config.get('token') @@ -202,13 +229,13 @@ class Procedure(object): loop._should_continue = True break - if isinstance(self, LoopProcedure): - if self._should_continue or self._should_break: - if self._should_continue: - # noinspection PyAttributeOutsideInit - self._should_continue = False + if isinstance(self, LoopProcedure) and ( + self._should_continue or self._should_break + ): + if self._should_continue: + self._should_continue = False - break + break if token: request.token = token @@ -230,6 +257,14 @@ class Procedure(object): return response or Response() + def to_dict(self): + return { + 'name': self.name, + 'requests': self.requests, + 'args': self.args, + '_async': self._async, + } + class LoopProcedure(Procedure): """ @@ -237,7 +272,9 @@ class LoopProcedure(Procedure): """ def __init__(self, name, requests, _async=False, args=None, backend=None): - super(). __init__(name=name, _async=_async, requests=requests, args=args, backend=backend) + super().__init__( + name=name, _async=_async, requests=requests, args=args, backend=backend + ) self._should_break = False self._should_continue = False @@ -264,36 +301,47 @@ class ForProcedure(LoopProcedure): """ - def __init__(self, name, iterator_name, iterable, requests, _async=False, args=None, backend=None): - super(). __init__(name=name, _async=_async, requests=requests, args=args, backend=backend) + def __init__( + self, + name, + iterator_name, + iterable, + requests, + _async=False, + args=None, + backend=None, + ): + super().__init__( + name=name, _async=_async, requests=requests, args=args, backend=backend + ) self.iterator_name = iterator_name self.iterable = iterable def execute(self, _async=None, **context): try: iterable = eval(self.iterable) - assert hasattr(iterable, '__iter__'), 'Object of type {} is not iterable: {}'.\ - format(type(iterable), iterable) + assert hasattr( + iterable, '__iter__' + ), f'Object of type {type(iterable)} is not iterable: {iterable}' except Exception as e: logger.debug(f'Iterable {self.iterable} expansion error: {e}') iterable = Request.expand_value_from_context(self.iterable, **context) response = Response() - # noinspection DuplicatedCode for item in iterable: if self._should_return: - logger.info('Returning from {}'.format(self.name)) + logger.info('Returning from %s', self.name) break if self._should_continue: self._should_continue = False - logger.info('Continuing loop {}'.format(self.name)) + logger.info('Continuing loop %s', self.name) continue if self._should_break: self._should_break = False - logger.info('Breaking loop {}'.format(self.name)) + logger.info('Breaking loop %s', self.name) break context[self.iterator_name] = item @@ -327,37 +375,41 @@ class WhileProcedure(LoopProcedure): """ - def __init__(self, name, condition, requests, _async=False, args=None, backend=None): - super(). __init__(name=name, _async=_async, requests=requests, args=args, backend=backend) + def __init__( + self, name, condition, requests, _async=False, args=None, backend=None + ): + super().__init__( + name=name, _async=_async, requests=requests, args=args, backend=backend + ) self.condition = condition @staticmethod def _get_context(**context): - for (k, v) in context.items(): + for k, v in context.items(): try: context[k] = eval(v) except Exception as e: logger.debug(f'Evaluation error for {v}: {e}') if isinstance(v, str): - # noinspection PyBroadException try: - context[k] = eval('"{}"'.format(re.sub(r'(^|[^\\])"', '\1\\"', v))) + context[k] = eval('"' + re.sub(r'(^|[^\\])"', '\1\\"', v) + '"') except Exception as e: - logger.warning('Could not parse value for context variable {}={}'.format(k, v)) - logger.warning('Context: {}'.format(context)) + logger.warning( + 'Could not parse value for context variable %s=%s', k, v + ) + logger.warning('Context: %s', context) logger.exception(e) return context - # noinspection DuplicatedCode,PyBroadException def execute(self, _async=None, **context): response = Response() context = self._get_context(**context) for k, v in context.items(): try: - exec('{}={}'.format(k, v)) + exec(f'{k}={v}') except Exception as e: - logger.debug(f'Evaluation error: {k}={v}: {e}') + logger.debug('Evaluation error: %s=%s: %s', k, v, e) while True: condition_true = eval(self.condition) @@ -365,34 +417,32 @@ class WhileProcedure(LoopProcedure): break if self._should_return: - logger.info('Returning from {}'.format(self.name)) + logger.info('Returning from %s', self.name) break if self._should_continue: self._should_continue = False - logger.info('Continuing loop {}'.format(self.name)) + logger.info('Continuing loop %s', self.name) continue if self._should_break: self._should_break = False - logger.info('Breaking loop {}'.format(self.name)) + logger.info('Breaking loop %s', self.name) break response = super().execute(**context) - if response.output: - if isinstance(response.output, dict): - new_context = self._get_context(**response.output) - for k, v in new_context.items(): - try: - exec('{}={}'.format(k, v)) - except Exception as e: - logger.debug(f'Evaluation error: {k}={v}: {e}') + if response.output and isinstance(response.output, dict): + new_context = self._get_context(**response.output) + for k, v in new_context.items(): + try: + exec(f'{k}={v}') + except Exception as e: + logger.debug(f'Evaluation error: {k}={v}: {e}') return response -# noinspection PyBroadException class IfProcedure(Procedure): """ Models an if-else construct. @@ -418,7 +468,17 @@ class IfProcedure(Procedure): cmd: '/path/turn_off_heating.sh' """ - def __init__(self, name, condition, requests, else_branch=None, args=None, backend=None, id=None, **kwargs): + def __init__( + self, + name, + condition, + requests, + else_branch=None, + args=None, + backend=None, + id=None, + **kwargs, + ): kwargs['_async'] = False self.condition = condition self.else_branch = else_branch @@ -435,32 +495,57 @@ class IfProcedure(Procedure): reqs.append(req) - super(). __init__(name=name, requests=reqs, args=args, backend=backend, **kwargs) + super().__init__(name=name, requests=reqs, args=args, backend=backend, **kwargs) @classmethod - def build(cls, name, condition, requests, else_branch=None, args=None, backend=None, id=None, **kwargs): + def build( + cls, + name, + condition, + requests, + else_branch=None, + args=None, + backend=None, + id=None, + **kwargs, + ): kwargs['_async'] = False if else_branch: - else_branch = super().build(name=name+'__else', requests=else_branch, - args=args, backend=backend, id=id, - procedure_class=Procedure, **kwargs) + else_branch = super().build( + name=name + '__else', + requests=else_branch, + args=args, + backend=backend, + id=id, + procedure_class=Procedure, + **kwargs, + ) - return super().build(name=name, condition=condition, requests=requests, - else_branch=else_branch, args=args, backend=backend, id=id, - **kwargs) + return super().build( + name=name, + condition=condition, + requests=requests, + else_branch=else_branch, + args=args, + backend=backend, + id=id, + **kwargs, + ) def execute(self, **context): - for (k, v) in context.items(): + for k, v in context.items(): try: - exec('{}={}'.format(k, v)) + exec(f'{k}={v}') except Exception as e: logger.debug(f'Evaluation error: {k}={v}: {e}') if isinstance(v, str): try: - exec('{}="{}"'.format(k, re.sub(r'(^|[^\\])"', '\1\\"', v))) + exec('{k}="' + re.sub(r'(^|[^\\])"', '\1\\"', v) + '"') except Exception as e: - logger.debug('Could not set context variable {}={}: {}'.format(k, v, str(e))) - logger.debug('Context: {}'.format(context)) + logger.debug( + 'Could not set context variable %s=%s: %s', k, v, e + ) + logger.debug('Context: %s', context) condition_true = eval(self.condition) response = Response()