Source code for robot.result.keywordremover

#  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 abc import ABC

from robot.errors import DataError
from robot.model import SuiteVisitor, TagPattern
from robot.utils import html_escape, Matcher, plural_or_not


[docs] class KeywordRemover(SuiteVisitor, ABC): message = 'Content removed using the --remove-keywords option.' def __init__(self): self.removal_message = RemovalMessage(self.message)
[docs] @classmethod def from_config(cls, conf): upper = conf.upper() if upper.startswith('NAME:'): return ByNameKeywordRemover(pattern=conf[5:]) if upper.startswith('TAG:'): return ByTagKeywordRemover(pattern=conf[4:]) try: return {'ALL': AllKeywordsRemover, 'PASSED': PassedKeywordRemover, 'FOR': ForLoopItemsRemover, 'WHILE': WhileLoopItemsRemover, 'WUKS': WaitUntilKeywordSucceedsRemover}[upper]() except KeyError: raise DataError(f"Expected 'ALL', 'PASSED', 'NAME:<pattern>', " f"'TAG:<pattern>', 'FOR' or 'WUKS', got '{conf}'.")
def _clear_content(self, item): if item.body: item.body.clear() self.removal_message.set_to(item) def _failed_or_warning_or_error(self, item): return not item.passed or self._warning_or_error(item) def _warning_or_error(self, item): finder = WarningAndErrorFinder() item.visit(finder) return finder.found
[docs] class AllKeywordsRemover(KeywordRemover):
[docs] def start_body_item(self, item): self._clear_content(item)
[docs] def start_if(self, item): pass
[docs] def start_if_branch(self, item): self._clear_content(item)
[docs] def start_try(self, item): pass
[docs] def start_try_branch(self, item): self._clear_content(item)
[docs] class PassedKeywordRemover(KeywordRemover):
[docs] def start_suite(self, suite): if not suite.statistics.failed: self._remove_setup_and_teardown(suite)
[docs] def visit_test(self, test): if not self._failed_or_warning_or_error(test): for item in test.body: self._clear_content(item) self._remove_setup_and_teardown(test)
[docs] def visit_keyword(self, keyword): pass
def _remove_setup_and_teardown(self, item): if item.has_setup: if not self._warning_or_error(item.setup): self._clear_content(item.setup) if item.has_teardown: if not self._warning_or_error(item.teardown): self._clear_content(item.teardown)
[docs] class ByNameKeywordRemover(KeywordRemover): def __init__(self, pattern): super().__init__() self._matcher = Matcher(pattern, ignore='_')
[docs] def start_keyword(self, kw): if self._matcher.match(kw.full_name) and not self._warning_or_error(kw): self._clear_content(kw)
[docs] class ByTagKeywordRemover(KeywordRemover): def __init__(self, pattern): super().__init__() self._pattern = TagPattern.from_string(pattern)
[docs] def start_keyword(self, kw): if self._pattern.match(kw.tags) and not self._warning_or_error(kw): self._clear_content(kw)
[docs] class LoopItemsRemover(KeywordRemover, ABC): message = '{count} passing item{s} removed using the --remove-keywords option.' def _remove_from_loop(self, loop): before = len(loop.body) self._remove_keywords(loop.body) self.removal_message.set_to_if_removed(loop, before) def _remove_keywords(self, body): iterations = body.filter(messages=False) for it in iterations[:-1]: if not self._failed_or_warning_or_error(it): body.remove(it)
[docs] class ForLoopItemsRemover(LoopItemsRemover):
[docs] def start_for(self, for_): self._remove_from_loop(for_)
[docs] class WhileLoopItemsRemover(LoopItemsRemover):
[docs] def start_while(self, while_): self._remove_from_loop(while_)
[docs] class WaitUntilKeywordSucceedsRemover(KeywordRemover): message = '{count} failing item{s} removed using the --remove-keywords option.'
[docs] def start_keyword(self, kw): if kw.owner == 'BuiltIn' and kw.name == 'Wait Until Keyword Succeeds': before = len(kw.body) self._remove_keywords(kw.body) self.removal_message.set_to_if_removed(kw, before)
def _remove_keywords(self, body): keywords = body.filter(messages=False) if keywords: include_from_end = 2 if keywords[-1].passed else 1 for kw in keywords[:-include_from_end]: if not self._warning_or_error(kw): body.remove(kw)
[docs] class WarningAndErrorFinder(SuiteVisitor): def __init__(self): self.found = False
[docs] def start_suite(self, suite): return not self.found
[docs] def start_test(self, test): return not self.found
[docs] def start_keyword(self, keyword): return not self.found
[docs] def visit_message(self, msg): if msg.level in ('WARN', 'ERROR'): self.found = True
[docs] class RemovalMessage: def __init__(self, message): self.message = message
[docs] def set_to_if_removed(self, item, len_before): removed = len_before - len(item.body) if removed: message = self.message.format(count=removed, s=plural_or_not(removed)) self.set_to(item, message)
[docs] def set_to(self, item, message=None): if not item.message: start = '' elif item.message.startswith('*HTML*'): start = item.message[6:].strip() + '<hr>' else: start = html_escape(item.message) + '<hr>' message = message or self.message item.message = f'*HTML* {start}<span class="robot-note">{message}</span>'