Better management of the context and support for proper expression expansion from the context in the action execution through eval

This commit is contained in:
Fabio Manganiello 2018-01-07 23:31:19 +01:00
parent 2871583c75
commit 252f503e4d
4 changed files with 37 additions and 27 deletions

View File

@ -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:

View File

@ -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)

View File

@ -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

View File

@ -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):