Source code for robot.parsing.lexer.settings

#  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 normalize, normalize_whitespace, RecommendationFinder

from .tokens import Token


[docs]class Settings: names = () aliases = {} multi_use = ( 'Metadata', 'Library', 'Resource', 'Variables' ) single_value = ( 'Resource', 'Test Timeout', 'Test Template', 'Timeout', 'Template' ) name_and_arguments = ( 'Metadata', 'Suite Setup', 'Suite Teardown', 'Test Setup', 'Test Teardown', 'Test Template', 'Setup', 'Teardown', 'Template', 'Resource', 'Variables' ) name_arguments_and_with_name = ( 'Library', ) def __init__(self, languages): self.settings = {n: None for n in self.names} self.languages = languages
[docs] def lex(self, statement): setting = statement[0] orig = self._format_name(setting.value) name = normalize_whitespace(orig).title() name = self.languages.settings.get(name, name) if name in self.aliases: name = self.aliases[name] try: self._validate(orig, name, statement) except ValueError as err: self._lex_error(setting, statement[1:], err.args[0]) else: self._lex_setting(setting, statement[1:], name)
def _format_name(self, name): return name def _validate(self, orig, name, statement): if name not in self.settings: message = self._get_non_existing_setting_message(orig, name) raise ValueError(message) if self.settings[name] is not None and name not in self.multi_use: raise ValueError(f"Setting '{orig}' is allowed only once. " f"Only the first value is used.") if name in self.single_value and len(statement) > 2: raise ValueError(f"Setting '{orig}' accepts only one value, " f"got {len(statement)-1}.") def _get_non_existing_setting_message(self, name, normalized): if self._is_valid_somewhere(normalized): return self._not_valid_here(name) return RecommendationFinder(normalize).find_and_format( name=normalized, candidates=tuple(self.settings) + tuple(self.aliases), message=f"Non-existing setting '{name}'." ) def _is_valid_somewhere(self, normalized): for cls in Settings.__subclasses__(): if normalized in cls.names or normalized in cls.aliases: return True return False def _not_valid_here(self, name): raise NotImplementedError def _lex_error(self, setting, values, error): setting.set_error(error) for token in values: token.type = Token.COMMENT def _lex_setting(self, setting, values, name): self.settings[name] = values # TODO: Change token type from 'FORCE TAGS' to 'TEST TAGS' in RF 7.0. setting.type = name.upper() if name != 'Test Tags' else 'FORCE TAGS' if name in self.name_and_arguments: self._lex_name_and_arguments(values) elif name in self.name_arguments_and_with_name: self._lex_name_arguments_and_with_name(values) else: self._lex_arguments(values) def _lex_name_and_arguments(self, tokens): if tokens: tokens[0].type = Token.NAME self._lex_arguments(tokens[1:]) def _lex_name_arguments_and_with_name(self, tokens): self._lex_name_and_arguments(tokens) if len(tokens) > 1 and \ normalize_whitespace(tokens[-2].value) in ('WITH NAME', 'AS'): tokens[-2].type = Token.WITH_NAME tokens[-1].type = Token.NAME def _lex_arguments(self, tokens): for token in tokens: token.type = Token.ARGUMENT
[docs]class TestCaseFileSettings(Settings): names = ( 'Documentation', 'Metadata', 'Suite Setup', 'Suite Teardown', 'Test Setup', 'Test Teardown', 'Test Template', 'Test Timeout', 'Test Tags', 'Default Tags', 'Keyword Tags', 'Library', 'Resource', 'Variables' ) aliases = { 'Force Tags': 'Test Tags', 'Task Tags': 'Test Tags', 'Task Setup': 'Test Setup', 'Task Teardown': 'Test Teardown', 'Task Template': 'Test Template', 'Task Timeout': 'Test Timeout', } def _not_valid_here(self, name): return f"Setting '{name}' is not allowed in suite file."
[docs]class InitFileSettings(Settings): names = ( 'Documentation', 'Metadata', 'Suite Setup', 'Suite Teardown', 'Test Setup', 'Test Teardown', 'Test Timeout', 'Test Tags', 'Keyword Tags', 'Library', 'Resource', 'Variables' ) aliases = { 'Force Tags': 'Test Tags', 'Task Tags': 'Test Tags', 'Task Setup': 'Test Setup', 'Task Teardown': 'Test Teardown', 'Task Timeout': 'Test Timeout', } def _not_valid_here(self, name): return f"Setting '{name}' is not allowed in suite initialization file."
[docs]class ResourceFileSettings(Settings): names = ( 'Documentation', 'Keyword Tags', 'Library', 'Resource', 'Variables' ) def _not_valid_here(self, name): return f"Setting '{name}' is not allowed in resource file."
[docs]class TestCaseSettings(Settings): names = ( 'Documentation', 'Tags', 'Setup', 'Teardown', 'Template', 'Timeout' ) def __init__(self, parent, languages): super().__init__(languages) self.parent = parent def _format_name(self, name): return name[1:-1].strip() @property def template_set(self): template = self.settings['Template'] if self._has_disabling_value(template): return False parent_template = self.parent.settings['Test Template'] return self._has_value(template) or self._has_value(parent_template) def _has_disabling_value(self, setting): if setting is None: return False return setting == [] or setting[0].value.upper() == 'NONE' def _has_value(self, setting): return setting and setting[0].value def _not_valid_here(self, name): return f"Setting '{name}' is not allowed with tests or tasks."
[docs]class KeywordSettings(Settings): names = ( 'Documentation', 'Arguments', 'Teardown', 'Timeout', 'Tags', 'Return' ) def _format_name(self, name): return name[1:-1].strip() def _not_valid_here(self, name): return f"Setting '{name}' is not allowed with user keywords."