From 96268f1d30c8d36f55de595d49314d7a28a828e3 Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Thu, 5 Jan 2017 15:30:24 +0100 Subject: [PATCH 1/4] factorize WorklowStatusItem.compute() --- tests/test_workflows.py | 19 +++++++++---------- wcs/qommon/misc.py | 30 ++++++++++++++++++++++++++++++ wcs/wf/backoffice_fields.py | 3 ++- wcs/wf/geolocate.py | 8 ++++---- wcs/wf/jump.py | 3 ++- wcs/wf/profile.py | 4 ++-- wcs/workflows.py | 42 +++++++----------------------------------- wcs/wscalls.py | 8 ++++---- 8 files changed, 60 insertions(+), 57 deletions(-) diff --git a/tests/test_workflows.py b/tests/test_workflows.py index 5f58135..bb68661 100644 --- a/tests/test_workflows.py +++ b/tests/test_workflows.py @@ -11,6 +11,7 @@ import mock from quixote import cleanup, get_response from wcs.qommon.http_request import HTTPRequest from qommon.form import * +from qommon.misc import compute from wcs.formdef import FormDef from wcs import sessions @@ -119,26 +120,24 @@ def test_variable_compute(pub): formdata.store() pub.substitutions.feed(formdata) - item = JumpWorkflowStatusItem() - # straight string - assert item.compute('blah') == 'blah' + assert compute('blah') == 'blah' # ezt string - assert item.compute('[form_var_foo]') == 'hello' + assert compute('[form_var_foo]') == 'hello' # ezt string, but not ezt asked - assert item.compute('[form_var_foo]', do_ezt=False) == '[form_var_foo]' + assert compute('[form_var_foo]', do_ezt=False) == '[form_var_foo]' # ezt string, with an error - assert item.compute('[end]', raises=False) == '[end]' + assert compute('[end]', raises=False) == '[end]' with pytest.raises(Exception): - item.compute('[end]', raises=True) + compute('[end]', raises=True) # python expression - assert item.compute('=form_var_foo') == 'hello' + assert compute('=form_var_foo') == 'hello' # python expression, with an error - assert item.compute('=1/0', raises=False) == '=1/0' + assert compute('=1/0', raises=False) == '=1/0' with pytest.raises(Exception): - item.compute('=1/0', raises=True) + compute('=1/0', raises=True) def test_jump_nothing(pub): FormDef.wipe() diff --git a/wcs/qommon/misc.py b/wcs/qommon/misc.py index 3024606..f544d55 100644 --- a/wcs/qommon/misc.py +++ b/wcs/qommon/misc.py @@ -503,3 +503,33 @@ def json_response(data): def parse_isotime(s): t = time.strptime(s, '%Y-%m-%dT%H:%M:%SZ') return calendar.timegm(t) + + +def compute(expr, do_ezt=True, raises=False, context=None): + if not isinstance(expr, basestring): + return expr + + if not expr.startswith('=') and not do_ezt: + return expr + + vars = get_publisher().substitutions.get_context_variables() + vars.update(context or {}) + + if not expr.startswith('='): + try: + processor = ezt.Template(compress_whitespace=False) + processor.parse(expr) + fd = StringIO() + processor.generate(fd, vars) + return fd.getvalue() + except ezt.EZTException: + if raises: + raise + return expr + + try: + return eval(expr[1:], get_publisher().get_global_eval_dict(), vars) + except: + if raises: + raise + return expr diff --git a/wcs/wf/backoffice_fields.py b/wcs/wf/backoffice_fields.py index 9585057..b77b6fa 100644 --- a/wcs/wf/backoffice_fields.py +++ b/wcs/wf/backoffice_fields.py @@ -21,6 +21,7 @@ import xml.etree.ElementTree as ET from quixote import get_publisher from qommon import get_logger +from qommon.misc import compute from qommon.form import (WidgetListAsTable, CompositeWidget, SingleSelectWidget, ComputedExpressionWidget, PicklableUpload) from wcs.fields import WidgetField @@ -121,7 +122,7 @@ class SetBackofficeFieldsWorkflowStatusItem(WorkflowStatusItem): continue try: - new_value = self.compute(field['value'], raises=True) + new_value = compute(field['value'], raises=True) except: get_publisher().notify_of_exception(sys.exc_info()) continue diff --git a/wcs/wf/geolocate.py b/wcs/wf/geolocate.py index 346da73..62e7261 100644 --- a/wcs/wf/geolocate.py +++ b/wcs/wf/geolocate.py @@ -28,7 +28,7 @@ from quixote import get_publisher from qommon import get_logger from qommon.form import RadiobuttonsWidget, ComputedExpressionWidget, CheckboxWidget -from qommon.misc import http_get_page +from qommon.misc import http_get_page, compute from wcs.workflows import WorkflowStatusItem, register_item_class class GeolocateWorkflowStatusItem(WorkflowStatusItem): @@ -106,7 +106,7 @@ class GeolocateWorkflowStatusItem(WorkflowStatusItem): nominatim_url = 'http://nominatim.openstreetmap.org' try: - address = self.compute(self.address_string, raises=True) + address = compute(self.address_string, raises=True) except Exception, e: get_logger().error('error in template for address string [%r]', e) return @@ -128,7 +128,7 @@ class GeolocateWorkflowStatusItem(WorkflowStatusItem): return {'lon': float(coords['lon']), 'lat': float(coords['lat'])} def geolocate_map_variable(self, formdata): - value = self.compute(self.map_variable) + value = compute(self.map_variable) if not value: return @@ -145,7 +145,7 @@ class GeolocateWorkflowStatusItem(WorkflowStatusItem): get_logger().error('error geolocating from file (missing PIL)') return - value = self.compute(self.photo_variable) + value = compute(self.photo_variable) if not hasattr(value, 'get_file_pointer'): get_logger().error('error geolocating from photo, invalid variable') return diff --git a/wcs/wf/jump.py b/wcs/wf/jump.py index c3c6518..72a7548 100644 --- a/wcs/wf/jump.py +++ b/wcs/wf/jump.py @@ -26,6 +26,7 @@ from qommon.form import * from qommon import errors from qommon.publisher import get_publisher_class from qommon.cron import CronJob +from qommon.misc import compute from wcs.workflows import Workflow, WorkflowStatusJumpItem, register_item_class from wcs.api import get_user_from_api_query_string, is_url_signed @@ -214,7 +215,7 @@ class JumpWorkflowStatusItem(WorkflowStatusJumpItem): must_jump = must_jump and triggered if self.timeout: - timeout = int(self.compute(self.timeout)) + timeout = int(compute(self.timeout)) if formdata.evolution: last = formdata.evolution[-1].time else: diff --git a/wcs/wf/profile.py b/wcs/wf/profile.py index 5468f1f..063c4ce 100644 --- a/wcs/wf/profile.py +++ b/wcs/wf/profile.py @@ -23,7 +23,7 @@ from quixote import get_publisher, get_response from qommon.form import (CompositeWidget, SingleSelectWidget, WidgetListAsTable, ComputedExpressionWidget) from qommon.ident.idp import is_idp_managing_user_attributes -from qommon.misc import http_patch_request +from qommon.misc import http_patch_request, compute from qommon.publisher import get_cfg, get_logger from wcs.api_utils import sign_url, get_secret_and_orig, MissingSecret @@ -144,7 +144,7 @@ class UpdateUserProfileStatusItem(WorkflowStatusItem): get_publisher().substitutions.feed(formdata) new_data = {} for field in self.fields: - new_data[field.get('field_id')] = self.compute(field.get('value')) + new_data[field.get('field_id')] = compute(field.get('value')) user_formdef = get_publisher().user_class.get_formdef() new_user_data = {} diff --git a/wcs/workflows.py b/wcs/workflows.py index b2d8a19..4fd62dc 100644 --- a/wcs/workflows.py +++ b/wcs/workflows.py @@ -29,7 +29,7 @@ import uuid from quixote import get_request, redirect -from qommon.misc import C_, get_as_datetime +from qommon.misc import C_, get_as_datetime, compute from qommon.storage import StorableObject from qommon.form import * from qommon.humantime import seconds2humanduration @@ -1606,34 +1606,6 @@ class WorkflowStatusItem(XmlSerialisable): value = getattr(self, '%s_parse' % f)(value) setattr(self, f, value) - @classmethod - def compute(cls, var, do_ezt=True, raises=False): - if not isinstance(var, basestring): - return var - - if not var.startswith('=') and not do_ezt: - return var - - vars = get_publisher().substitutions.get_context_variables() - if not var.startswith('='): - try: - processor = ezt.Template(compress_whitespace=False) - processor.parse(var) - fd = StringIO() - processor.generate(fd, vars) - return fd.getvalue() - except ezt.EZTException: - if raises: - raise - return var - - try: - return eval(var[1:], get_publisher().get_global_eval_dict(), vars) - except: - if raises: - raise - return var - def get_substitution_variables(self, formdata): return {} @@ -1883,7 +1855,7 @@ class ChoiceWorkflowStatusItem(WorkflowStatusJumpItem): return _('Change Status (not completed)') def fill_form(self, form, formdata, user): - form.add_submit('button%s' % self.id, self.compute(self.label)) + form.add_submit('button%s' % self.id, compute(self.label)) if self.require_confirmation: get_response().add_javascript(['jquery.js', '../../i18n.js', 'qommon.js']) widget = form.get_widget('button%s' % self.id) @@ -2032,13 +2004,13 @@ class SendmailWorkflowStatusItem(WorkflowStatusItem): url = formdata.get_url() try: - mail_body = template_on_formdata(formdata, self.compute(self.body, do_ezt=False)) + mail_body = template_on_formdata(formdata, compute(self.body, do_ezt=False)) except ezt.EZTException: get_logger().error('error in template for email body [%s], mail could not be generated' % url) return try: - mail_subject = template_on_formdata(formdata, self.compute(self.subject, do_ezt=False)) + mail_subject = template_on_formdata(formdata, compute(self.subject, do_ezt=False)) except ezt.EZTException: get_logger().error('error in template for email subject [%s], mail could not be generated' % url) return @@ -2054,7 +2026,7 @@ class SendmailWorkflowStatusItem(WorkflowStatusItem): addresses = [] for dest in self.to: try: - dest = self.compute(dest, raises=True) + dest = compute(dest, raises=True) except: continue @@ -2189,13 +2161,13 @@ class SendSMSWorkflowStatusItem(WorkflowStatusItem): if not self.body: return - destinations = [self.compute(x) for x in self.to] + destinations = [compute(x) for x in self.to] destinations = [x for x in destinations if x] # ignore empty elements if not destinations: return try: - sms_body = template_on_formdata(formdata, self.compute(self.body, do_ezt=False)) + sms_body = template_on_formdata(formdata, compute(self.body, do_ezt=False)) except ezt.EZTException: url = formdata.get_url() get_logger().error('error in template for sms [%s], sms could not be generated' % url) diff --git a/wcs/wscalls.py b/wcs/wscalls.py index f12aa71..01479f4 100644 --- a/wcs/wscalls.py +++ b/wcs/wscalls.py @@ -24,7 +24,7 @@ import xml.etree.ElementTree as ET from quixote import get_publisher from qommon.misc import (simplify, http_get_page, http_post_request, - get_variadic_url, JSONEncoder, json_loads) + get_variadic_url, JSONEncoder, json_loads, compute) from qommon.xml_storage import XmlStorableObject from qommon.form import (CompositeWidget, StringWidget, WidgetDict, ComputedExpressionWidget, RadiobuttonsWidget, CheckboxWidget) @@ -58,7 +58,7 @@ def call_webservice(url, qs_data=None, request_signature_key=None, qs = list(urlparse.parse_qsl(parsed.query)) for key, value in qs_data.iteritems(): try: - value = WorkflowStatusItem.compute(value, raises=True) + value = compute(value, raises=True) value = str(value) except: get_publisher().notify_of_exception(sys.exc_info()) @@ -70,7 +70,7 @@ def call_webservice(url, qs_data=None, request_signature_key=None, url = urlparse.urlunparse(parsed[:4] + (qs,) + parsed[5:6]) if request_signature_key: - signature_key = WorkflowStatusItem.compute(request_signature_key) + signature_key = compute(request_signature_key) if signature_key: url = sign_url(url, signature_key) @@ -82,7 +82,7 @@ def call_webservice(url, qs_data=None, request_signature_key=None, payload = {} for (key, value) in post_data.items(): try: - payload[key] = WorkflowStatusItem.compute(value, raises=True) + payload[key] = compute(value, raises=True) except: get_publisher().notify_of_exception(sys.exc_info()) -- 2.1.4