# Copyright 2008-2015 Nokia Networks
# Copyright 2016- Robot Framework Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from robot.utils import is_string, py2to3, unicode
from .comments import Comment
[docs]@py2to3
class Setting(object):
def __init__(self, setting_name, parent=None, comment=None):
self.setting_name = setting_name
self.parent = parent
self._set_initial_value()
self._set_comment(comment)
self._populated = False
def _set_initial_value(self):
self.value = []
def _set_comment(self, comment):
self.comment = Comment(comment)
[docs] def reset(self):
self.__init__(self.setting_name, self.parent)
@property
def source(self):
return self.parent.source if self.parent is not None else None
@property
def directory(self):
return self.parent.directory if self.parent is not None else None
[docs] def populate(self, value, comment=None):
"""Mainly used at parsing time, later attributes can be set directly."""
if not self._populated:
self._populate(value)
self._set_comment(comment)
self._populated = True
else:
self._set_initial_value()
self._set_comment(None)
self.report_invalid_syntax("Setting '%s' used multiple times."
% self.setting_name, 'ERROR')
def _populate(self, value):
self.value = value
[docs] def is_set(self):
return bool(self.value)
[docs] def is_for_loop(self):
return False
[docs] def report_invalid_syntax(self, message, level='ERROR'):
self.parent.report_invalid_syntax(message, level)
def _string_value(self, value):
return value if is_string(value) else ' '.join(value)
def _concat_string_with_value(self, string, value):
if string:
return string + ' ' + self._string_value(value)
return self._string_value(value)
[docs] def as_list(self):
return self._data_as_list() + self.comment.as_list()
def _data_as_list(self):
ret = [self.setting_name]
if self.value:
ret.extend(self.value)
return ret
def __nonzero__(self):
return self.is_set()
def __iter__(self):
return iter(self.value or ())
def __unicode__(self):
return unicode(self.value or '')
[docs]class StringValueJoiner(object):
def __init__(self, separator):
self._separator = separator
[docs] def join_string_with_value(self, string, value):
if string:
return string + self._separator + self.string_value(value)
return self.string_value(value)
[docs] def string_value(self, value):
if is_string(value):
return value
return self._separator.join(value)
[docs]class Documentation(Setting):
def _set_initial_value(self):
self.value = ''
def _populate(self, value):
self.value = self._concat_string_with_value(self.value, value)
def _string_value(self, value):
return value if is_string(value) else ''.join(value)
def _data_as_list(self):
return [self.setting_name, self.value]
[docs]class Template(Setting):
def _set_initial_value(self):
self.value = None
def _populate(self, value):
self.value = self._concat_string_with_value(self.value, value)
[docs] def is_set(self):
return self.value is not None
[docs] def is_active(self):
return self.value and self.value.upper() != 'NONE'
def _data_as_list(self):
ret = [self.setting_name]
if self.value:
ret.append(self.value)
return ret
[docs]class Fixture(Setting):
# `keyword`, `is_comment` and `assign` make the API compatible with Step.
@property
def keyword(self):
return self.name or ''
def _set_initial_value(self):
self.name = None
self.args = []
self.assign = ()
def _populate(self, value):
if not self.name:
self.name = value[0] if value else ''
value = value[1:]
self.args.extend(value)
[docs] def is_set(self):
return self.name is not None
[docs] def is_active(self):
return self.name and self.name.upper() != 'NONE'
def _data_as_list(self):
ret = [self.setting_name]
if self.name or self.args:
ret.append(self.name or '')
if self.args:
ret.extend(self.args)
return ret
[docs]class Timeout(Setting):
def _set_initial_value(self):
self.value = None
self.message = ''
def _populate(self, value):
if not self.value:
self.value = value[0] if value else ''
value = value[1:]
self.message = self._concat_string_with_value(self.message, value)
# TODO: Remove custom timeout message support in RF 3.2.
if value and self.parent:
self.parent.report_invalid_syntax(
'Using custom timeout messages is deprecated since Robot '
'Framework 3.0.1 and will be removed in future versions. '
"Message that was used is '%s'." % self.message, level='WARN')
[docs] def is_set(self):
return self.value is not None
def _data_as_list(self):
ret = [self.setting_name]
if self.value or self.message:
ret.append(self.value or '')
if self.message:
ret.append(self.message)
return ret
[docs]class Arguments(Setting):
pass
[docs]class Return(Setting):
pass
class _Import(Setting):
def __init__(self, parent, name, args=None, alias=None, comment=None):
self.parent = parent
self.name = name
self.args = args or []
self.alias = alias
self._set_comment(comment)
def reset(self):
pass
@property
def type(self):
return type(self).__name__
def is_set(self):
return True
def _data_as_list(self):
return [self.type, self.name] + self.args
def report_invalid_syntax(self, message, level='ERROR', parent=None):
parent = parent or getattr(self, 'parent', None)
if parent:
parent.report_invalid_syntax(message, level)
else:
from robot.api import logger
logger.write(message, level)
[docs]class Library(_Import):
def __init__(self, parent, name, args=None, alias=None, comment=None):
if args and not alias:
args, alias = self._split_possible_alias(args)
_Import.__init__(self, parent, name, args, alias, comment)
def _split_possible_alias(self, args):
if len(args) > 1 and args[-2] == 'WITH NAME':
return args[:-2], args[-1]
return args, None
def _data_as_list(self):
data = ['Library', self.name] + self.args
if self.alias:
data += ['WITH NAME', self.alias]
return data
[docs]class Resource(_Import):
def __init__(self, parent, name, invalid_args=None, comment=None):
if invalid_args:
name += ' ' + ' '.join(invalid_args)
_Import.__init__(self, parent, name, comment=comment)
[docs]class Variables(_Import):
def __init__(self, parent, name, args=None, comment=None):
_Import.__init__(self, parent, name, args, comment=comment)
class _DataList(object):
def __init__(self, parent):
self._parent = parent
self.data = []
def add(self, meta):
self._add(meta)
def _add(self, meta):
self.data.append(meta)
def _parse_name_and_value(self, value):
name = value[0] if value else ''
return name, value[1:]
def __getitem__(self, index):
return self.data[index]
def __setitem__(self, index, item):
self.data[index] = item
def __len__(self):
return len(self.data)
def __iter__(self):
return iter(self.data)
[docs]class ImportList(_DataList):
[docs] def populate_library(self, data, comment):
self._populate(Library, data, comment)
[docs] def populate_resource(self, data, comment):
self._populate(Resource, data, comment)
[docs] def populate_variables(self, data, comment):
self._populate(Variables, data, comment)
def _populate(self, item_class, data, comment):
name, value = self._parse_name_and_value(data)
self._add(item_class(self._parent, name, value, comment=comment))