From 252f503e4da00743bc001ba85f47ee740ca14edd Mon Sep 17 00:00:00 2001 From: Fabio Manganiello Date: Sun, 7 Jan 2018 23:31:19 +0100 Subject: [PATCH] Better management of the context and support for proper expression expansion from the context in the action execution through eval --- platypush/message/event/__init__.py | 17 ++++++------ platypush/message/request/__init__.py | 39 ++++++++++++++++----------- platypush/procedure/__init__.py | 6 +++-- tests/test_event_parse.py | 2 +- 4 files changed, 37 insertions(+), 27 deletions(-) diff --git a/platypush/message/event/__init__.py b/platypush/message/event/__init__.py index 29d7606c3..d7a1f039c 100644 --- a/platypush/message/event/__init__.py +++ b/platypush/message/event/__init__.py @@ -97,10 +97,10 @@ class Event(Message): 'phrase': 'Hey dude turn on the living room lights' } - - self._matches_argument(argname='phrase', condition_value='Turn on the $lights lights') + - self._matches_argument(argname='phrase', condition_value='Turn on the ${lights} lights') will return EventMatchResult(is_match=True, parsed_args={ 'lights': 'living room' }) - - self._matches_argument(argname='phrase', condition_value='Turn off the $lights lights') + - self._matches_argument(argname='phrase', condition_value='Turn off the ${lights} lights') will return EventMatchResult(is_match=False, parsed_args={}) """ @@ -117,15 +117,14 @@ class Event(Message): condition_tokens.pop(0) result.score += 1 elif re.search(condition_token, event_token): - # The only supported regex-match as of now is the equivalent of - # the maybe operator. - # e.g. "turn on (the)? lights" would match both "turn on the lights" - # and "turn on lights". In such a case, we just consume the - # condition token and proceed forward. TODO add a more - # sophisticated regex-match handling + m = re.search('({})'.format(condition_token), event_token) + if m.group(1): + event_tokens.pop(0) + result.score += 1 + condition_tokens.pop(0) else: - m = re.match('[^\\\]*\$([\w\d_-]+)', condition_token) + m = re.match('[^\\\]*\${(.+?)}', condition_token) if m: argname = m.group(1) if argname not in result.parsed_args: diff --git a/platypush/message/request/__init__.py b/platypush/message/request/__init__.py index d3854b781..c28eb9c51 100644 --- a/platypush/message/request/__init__.py +++ b/platypush/message/request/__init__.py @@ -88,22 +88,33 @@ class Request(Message): return event_args - def _expand_value_from_context(self, value, **context): + @classmethod + def _expand_value_from_context(cls, value, **context): parsed_value = '' while value: - m = re.match('([^\\\]*)\$([\w\d_-]+)(.*)', value) - if m: - context_argname = m.group(2) - value = m.group(3) + m = re.match('([^\$]*)(\${\s*(.+?)\s*})(.*)', value) + if m and not m.group(1).endswith('\\'): + prefix = m.group(1); expr = m.group(2); + inner_expr = m.group(3); value = m.group(4) + + m = re.match('([^.\[\]()]+)(.*)', inner_expr) + context_argname = m.group(1) + path = m.group(2) + if context_argname in context: - parsed_value += m.group(1) + context[context_argname] - else: - parsed_value += m.group(1) + '$' + m.group(2) + try: + context_value = eval("context['{}']{}".format( + context_argname, path if path else '')) + except: context_value = expr + + parsed_value += prefix + str(context_value) + else: parsed_value += prefix + expr else: parsed_value += value value = '' - return parsed_value + try: return json.loads(parsed_value) + except ValueError as e: return parsed_value def _send_response(self, response): @@ -126,16 +137,14 @@ class Request(Message): context -- Key-valued context. Example: context = (group_name='Kitchen lights') request.args: - - group: $group_name # will be expanded as "Kitchen lights") + - group: ${group_name} # will be expanded as "Kitchen lights") """ def _thread_func(n_tries): if self.action.startswith('procedure.'): - try: - response = self._execute_procedure(n_tries=n_tries) - finally: - self._send_response(response) - return response + response = self._execute_procedure(n_tries=n_tries) + self._send_response(response) + return response else: (module_name, method_name) = get_module_and_method_from_action(self.action) plugin = get_plugin(module_name) diff --git a/platypush/procedure/__init__.py b/platypush/procedure/__init__.py index 5e9cf950e..ef2322ca7 100644 --- a/platypush/procedure/__init__.py +++ b/platypush/procedure/__init__.py @@ -54,8 +54,10 @@ class Procedure(object): request.execute(n_tries, async=True, **context) else: response = request.execute(n_tries, async=False, **context) - context = { k:v for (k,v) in response.output.items() } \ - if isinstance(response.output, dict) else {} + + if isinstance(response.output, dict): + for (k,v) in response.output.items(): + context[k] = v context['output'] = response.output context['errors'] = response.errors diff --git a/tests/test_event_parse.py b/tests/test_event_parse.py index 8f0a7ba46..42c67f3e2 100644 --- a/tests/test_event_parse.py +++ b/tests/test_event_parse.py @@ -9,7 +9,7 @@ class TestEventParse(unittest.TestCase): def setUp(self): self.condition = EventCondition.build({ 'type': 'platypush.message.event.ping.PingEvent', - 'message': 'This is (the)? answer: $answer' + 'message': 'This is (the)? answer: ${answer}' }) def test_event_parse(self):