Revision: 3338
Author: pekka.klarck
Date: Wed May 19 23:35:23 2010
Log: started re-enabling support for setting variables after the parsing
refactoring - this may already work but cannot test easily
http://code.google.com/p/robotframework/source/detail?r=3338
Modified:
/trunk/src/robot/running/keywords.py
=======================================
--- /trunk/src/robot/running/keywords.py Wed May 19 02:58:25 2010
+++ /trunk/src/robot/running/keywords.py Wed May 19 23:35:23 2010
@@ -13,17 +13,16 @@
# limitations under the License.
from robot import utils
-from robot.errors import FrameworkError, ExecutionFailed,
ExecutionFailures, \
- DataError, HandlerExecutionFailed
+from robot.errors import (DataError, ExecutionFailed, ExecutionFailures,
+ HandlerExecutionFailed)
from robot.common import BaseKeyword
-from robot.variables import is_list_var
+from robot.variables import is_var, is_list_var
class Keywords(object):
def __init__(self, steps):
- #FIXME: Initial hack to support new parsing model
- self._keywords = [ Keyword(step.keyword, step.args) for step in
steps ]
+ self._keywords = [_KeywordFactory(step) for step in steps]
def run(self, context):
errors = []
@@ -44,27 +43,39 @@
return iter(self._keywords)
-def _KeywordFactory(kwdata):
- if kwdata.type == 'kw':
- return Keyword(kwdata.name, kwdata.args)
+def _KeywordFactory(step):
+ # TODO: Support for FOR
try:
- clazz = {'set': SetKeyword, 'for': ForKeyword,
- 'error': SyntaxErrorKeyword}[kwdata.type]
- return clazz(kwdata)
- except KeyError:
- raise FrameworkError("Invalid kw type '%s'" % kwdata.type)
+ return Keyword(step.assign, step.keyword, step.args)
+ except DataError, err:
+ return SyntaxErrorKeyword(step.keyword, unicode(err))
class Keyword(BaseKeyword):
- def __init__(self, name, args, type='kw'):
- BaseKeyword.__init__(self, name, args, type=type)
+ def __init__(self, name, args, assign):
+ BaseKeyword.__init__(self, name, args)
+ self.assign = _Assignment(name, assign)
self.handler_name = name
def run(self, context):
+ handler = self._start(context)
+ try:
+ return_value = self._run(handler, context)
+ except ExecutionFailed, err:
+ self.status = 'FAIL'
+ self._end(context, error=err)
+ raise
+ else:
+ if not (context.dry_run and handler.type == 'library'):
+ self.status = 'PASS'
+ self._end(context, return_value)
+ return return_value
+
+ def _start(self, context):
handler = context.get_handler(self.handler_name)
handler.init_keyword(context.get_current_vars())
- self.name = self._get_name(handler.longname,
context.get_current_vars())
+ self.name = self._get_name(handler.longname)
self.doc = handler.shortdoc
self.starttime = utils.get_timestamp()
context.start_keyword(self)
@@ -72,27 +83,21 @@
msg = self.doc.replace('*DEPRECATED*', '', 1).strip()
name = self.name.split('} = ', 1)[-1] # Remove possible
variable
context.warn("Keyword '%s' is deprecated. %s" % (name, msg))
- try:
- ret = self._run(handler, context)
- context.trace('Return: %s' % utils.safe_repr(ret))
- except ExecutionFailed:
- self.status = 'FAIL'
- self._end(context)
- raise
- else:
- if not (context.dry_run and handler.type == 'library'):
- self.status = 'PASS'
- self._end(context)
- return ret
-
- def _end(self, context):
+ return handler
+
+ def _get_name(self, handler_name):
+ if not self.assign:
+ return handler_name
+ return '%s = %s' % (', '.join(self.assign), handler_name)
+
+ def _end(self, context, return_value=None, error=None):
self.endtime = utils.get_timestamp()
self.elapsedtime = utils.get_elapsed_time(self.starttime,
self.endtime)
+ if not error or error.cont:
+ self._set_variables(context, return_value)
+ context.trace('Return: %s' % utils.safe_repr(return_value))
context.end_keyword(self)
- def _get_name(self, handler_name, variables):
- return handler_name
-
def _run(self, handler, context):
try:
return handler.run(context, self.args[:])
@@ -101,6 +106,14 @@
except:
self._report_failure(context)
+ def _set_variables(self, context, return_value):
+ try:
+ self.assign.set_variables(context, return_value)
+ except DataError, err:
+ msg = unicode(err)
+ context.output.fail(msg)
+ raise ExecutionFailed(msg, syntax=True)
+
def _report_failure(self, context):
error_details = utils.ErrorDetails()
context.output.fail(error_details.message)
@@ -114,38 +127,37 @@
return test_or_suite.status != 'RUNNING'
-class SetKeyword(Keyword):
-
- def __init__(self, kwdata):
- self.scalar_vars = kwdata.scalar_vars
- self.list_var = kwdata.list_var
- Keyword.__init__(self, kwdata.name, kwdata.args, 'set')
-
- def _get_name(self, handler_name, variables):
- varz = self.scalar_vars[:]
- if self.list_var is not None:
- varz.append(self.list_var)
- return '%s = %s' % (', '.join(varz), handler_name)
-
- def _run(self, handler, context):
- try:
- return self._run_and_set_variables(handler, context)
- except DataError, err:
- msg = unicode(err)
- context.output.fail(msg)
- raise ExecutionFailed(msg, syntax=True)
-
- def _run_and_set_variables(self, handler, context):
- try:
- return_value = Keyword._run(self, handler, context)
- except ExecutionFailed, err:
- if err.cont:
- self._set_variables(context, None)
- raise
- self._set_variables(context, return_value)
- return return_value
-
- def _set_variables(self, context, return_value):
+class _Assignment(object):
+
+ def __init__(self, keyword, assign):
+ self.keyword = keyword
+ self.scalar_vars, self.list_var = self._split_assing(assign)
+
+ def _split_assing(self, assign):
+ scalar_vars = []
+ list_var = None
+ for var in assign:
+ if not is_var(var):
+ raise DataError('Invalid variable to assign: %s' % var)
+ if list_var:
+ raise DataError('Only the last variable to assign can be '
+ 'a list variable.')
+ if is_list_var(var):
+ list_var = var
+ else:
+ scalar_vars.append(var)
+ return scalar_vars, list_var
+
+ def __nonzero__(self):
+ return bool(self.scalar_vars or self.list_var)
+
+ def __iter__(self):
+ for var in self.scalar_vars:
+ yield var
+ if self.list_var:
+ yield self.list_var
+
+ def set_variables(self, context, return_value):
for name, value in self._get_vars_to_set(return_value):
context.get_current_vars()[name] = value
if is_list_var(name) or utils.is_list(value):
@@ -157,7 +169,7 @@
def _get_vars_to_set(self, ret):
if ret is None:
return self._get_vars_to_set_when_ret_is_none()
- if self.list_var is None:
+ if self.list_var:
return self._get_vars_to_set_with_only_scalars(ret)
if self._is_non_string_iterable(ret):
return self._get_vars_to_set_with_scalars_and_list(list(ret))
@@ -175,7 +187,7 @@
def _get_vars_to_set_when_ret_is_none(self):
ret = [ (var, None) for var in self.scalar_vars ]
- if self.list_var is not None:
+ if self.list_var:
ret.append((self.list_var, []))
return ret
@@ -195,7 +207,7 @@
def _get_vars_to_set_with_scalars_and_list(self, ret):
needed_scalars = len(self.scalar_vars)
- if not needed_scalars:
+ if needed_scalars == 0:
return [(self.list_var, ret)]
if len(ret) < needed_scalars:
self._raise_invalid_return_value(ret)
@@ -205,17 +217,10 @@
def _raise_invalid_return_value(self, ret, wrong_type=False):
if wrong_type:
err = 'Expected list, got %s instead' % utils.type_as_str(ret,
True)
- elif ret is None:
- err = 'Keyword returned nothing'
else:
err = 'Need more values than %d' % len(ret)
- varz = self.scalar_vars[:]
- if self.list_var:
- varz.append(self.list_var)
- name = self.name.split(' = ', 1)[1]
raise DataError("Cannot assign return value of keyword '%s' to "
- "variable%s %s: %s" % (name,
utils.plural_or_not(varz),
- utils.seq2str(varz), err))
+ "variables %s: %s" % (self.keyword, list(self),
err))
class ForKeyword(BaseKeyword):
@@ -320,9 +325,9 @@
class SyntaxErrorKeyword(BaseKeyword):
- def __init__(self, kwdata):
- BaseKeyword.__init__(self, kwdata.name, type='error')
- self._error = kwdata.error
+ def __init__(self, name, error):
+ BaseKeyword.__init__(self, name, type='error')
+ self._error = error
def run(self, context):
self.starttime = utils.get_timestamp()