From a0560a643d1594bf6f575855de5a750a125ade79 Mon Sep 17 00:00:00 2001 From: Vadzim Hushchanskou Date: Wed, 20 Mar 2024 14:14:59 +0300 Subject: [PATCH] flake8 fixes --- CHANGELOG.md | 2 + robotframework_reportportal/listener.py | 22 +-- robotframework_reportportal/model.py | 197 +++++++++++++++--------- robotframework_reportportal/model.pyi | 101 ------------ robotframework_reportportal/service.py | 2 +- tests/unit/test_model.py | 2 +- 6 files changed, 142 insertions(+), 184 deletions(-) delete mode 100644 robotframework_reportportal/model.pyi diff --git a/CHANGELOG.md b/CHANGELOG.md index 220cefb..a16645b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # Changelog ## [Unreleased] +### Removed +- `model.pyi` stub file, as we don't really need it anymore, by @HardNorth ## [5.5.2] ### Added diff --git a/robotframework_reportportal/listener.py b/robotframework_reportportal/listener.py index db87617..d7842d0 100644 --- a/robotframework_reportportal/listener.py +++ b/robotframework_reportportal/listener.py @@ -207,18 +207,18 @@ def variables(self) -> Variables: return self._variables @check_rp_enabled - def start_launch(self, attributes: Dict, ts: Optional[Any] = None) -> None: + def start_launch(self, attributes: Dict[str, Any], ts: Optional[Any] = None) -> None: """Start a new launch at the ReportPortal. :param attributes: Dictionary passed by the Robot Framework :param ts: Timestamp(used by the ResultVisitor) """ - launch = Launch(self.variables.launch_name, attributes) - launch.attributes = gen_attributes(self.variables.launch_attributes) + launch = Launch(self.variables.launch_name, attributes, gen_attributes(self.variables.launch_attributes)) + launch.robot_attributes = gen_attributes(self.variables.launch_attributes) launch.doc = self.variables.launch_doc or launch.doc if self.variables.pabot_used: warn(PABOT_WIHOUT_LAUNCH_ID_MSG, stacklevel=2) - logger.debug('ReportPortal - Start Launch: {0}'.format(launch.attributes)) + logger.debug('ReportPortal - Start Launch: {0}'.format(launch.robot_attributes)) self.service.start_launch( launch=launch, mode=self.variables.mode, @@ -255,10 +255,10 @@ def end_suite(self, _: Optional[str], attributes: Dict, ts: Optional[Any] = None :param ts: Timestamp(used by the ResultVisitor) """ suite = self._remove_current_item().update(attributes) - logger.debug('ReportPortal - End Suite: {0}'.format(suite.attributes)) + logger.debug('ReportPortal - End Suite: {0}'.format(suite.robot_attributes)) self.service.finish_suite(suite=suite, ts=ts) if attributes['id'] == MAIN_SUITE_ID: - launch = Launch(self.variables.launch_name, attributes) + launch = Launch(self.variables.launch_name, attributes, None) logger.debug( msg='ReportPortal - End Launch: {0}'.format(attributes)) self.service.finish_launch(launch=launch, ts=ts) @@ -275,7 +275,7 @@ def start_test(self, name: str, attributes: Dict, ts: Optional[Any] = None) -> N # no 'source' parameter at this level for Robot versions < 4 attributes = attributes.copy() attributes['source'] = getattr(self.current_item, 'source', None) - test = Test(name=name, attributes=attributes) + test = Test(name=name, robot_attributes=attributes) logger.debug('ReportPortal - Start Test: {0}'.format(attributes)) test.attributes = gen_attributes(self.variables.test_attributes + test.tags) test.rp_parent_item_id = self.parent_id @@ -291,13 +291,13 @@ def end_test(self, _: Optional[str], attributes: Dict, ts: Optional[Any] = None) :param ts: Timestamp(used by the ResultVisitor) """ test = self.current_item.update(attributes) - test.attributes = gen_attributes( + test.robot_attributes = gen_attributes( self.variables.test_attributes + test.tags) if not test.critical and test.status == 'FAIL': test.status = 'SKIP' if test.message: self.log_message({'message': test.message, 'level': 'DEBUG'}) - logger.debug('ReportPortal - End Test: {0}'.format(test.attributes)) + logger.debug('ReportPortal - End Test: {0}'.format(test.robot_attributes)) self._remove_current_item() self.service.finish_test(test=test, ts=ts) @@ -309,7 +309,7 @@ def start_keyword(self, name: str, attributes: Dict, ts: Optional[Any] = None) - :param attributes: Dictionary passed by the Robot Framework :param ts: Timestamp(used by the ResultVisitor) """ - kwd = Keyword(name=name, parent_type=self.current_item.type, attributes=attributes) + kwd = Keyword(name=name, parent_type=self.current_item.type, robot_attributes=attributes) kwd.rp_parent_item_id = self.parent_id logger.debug('ReportPortal - Start Keyword: {0}'.format(attributes)) kwd.rp_item_id = self.service.start_keyword(keyword=kwd, ts=ts) @@ -324,7 +324,7 @@ def end_keyword(self, _: Optional[str], attributes: Dict, ts: Optional[Any] = No :param ts: Timestamp(used by the ResultVisitor) """ kwd = self._remove_current_item().update(attributes) - logger.debug('ReportPortal - End Keyword: {0}'.format(kwd.attributes)) + logger.debug('ReportPortal - End Keyword: {0}'.format(kwd.robot_attributes)) self.service.finish_keyword(keyword=kwd, ts=ts) def log_file(self, log_path: str) -> None: diff --git a/robotframework_reportportal/model.py b/robotframework_reportportal/model.py index 969b623..53f0122 100644 --- a/robotframework_reportportal/model.py +++ b/robotframework_reportportal/model.py @@ -1,55 +1,75 @@ -# Copyright (c) 2023 EPAM Systems +# Copyright 2024 EPAM Systems +# # 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 # -# https://www.apache.org/licenses/LICENSE-2.0 +# https://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 +# limitations under the License. """This module contains models representing Robot Framework test items.""" import os +from typing import Any, Dict, List, Optional, Union class Suite: """Class represents Robot Framework test suite.""" - def __init__(self, name, attributes): + robot_attributes: Union[List[str], Dict[str, Any]] + doc: str + end_time: str + longname: str + message: str + metadata: Dict[str, str] + name: str + robot_id: str + rp_item_id: Optional[str] + rp_parent_item_id: Optional[str] + start_time: Optional[str] + statistics: str + status: str + suites: List[str] + tests: List[str] + total_tests: int + type: str = 'SUITE' + + def __init__(self, name: str, robot_attributes: Dict[str, Any]): """Initialize required attributes. :param name: Suite name - :param attributes: Suite attributes passed through the listener + :param robot_attributes: Suite attributes passed through the listener """ - self.attributes = attributes - self.doc = attributes['doc'] - self.end_time = attributes.get('endtime', '') - self.longname = attributes['longname'] - self.message = attributes.get('message') - self.metadata = attributes['metadata'] + self.robot_attributes = robot_attributes + self.doc = robot_attributes['doc'] + self.end_time = robot_attributes.get('endtime', '') + self.longname = robot_attributes['longname'] + self.message = robot_attributes.get('message') + self.metadata = robot_attributes['metadata'] self.name = name - self.robot_id = attributes['id'] + self.robot_id = robot_attributes['id'] self.rp_item_id = None self.rp_parent_item_id = None - self.start_time = attributes.get('starttime') - self.statistics = attributes.get('statistics') - self.status = attributes.get('status') - self.suites = attributes['suites'] - self.tests = attributes['tests'] - self.total_tests = attributes['totaltests'] + self.start_time = robot_attributes.get('starttime') + self.statistics = robot_attributes.get('statistics') + self.status = robot_attributes.get('status') + self.suites = robot_attributes['suites'] + self.tests = robot_attributes['tests'] + self.total_tests = robot_attributes['totaltests'] self.type = 'SUITE' @property - def source(self): + def source(self) -> str: """Return the test case source file path.""" - if self.attributes.get('source') is not None: - return os.path.relpath(self.attributes['source'], os.getcwd()) + if self.robot_attributes.get('source') is not None: + return os.path.relpath(self.robot_attributes['source'], os.getcwd()) - def update(self, attributes): + def update(self, attributes: Dict[str, Any]) -> 'Suite': """Update suite attributes on suite finish. :param attributes: Suite attributes passed through the listener @@ -64,74 +84,92 @@ def update(self, attributes): class Launch(Suite): """Class represents Robot Framework test suite.""" - def __init__(self, name, attributes): + type: str = 'LAUNCH' + + def __init__(self, name: str, robot_attributes: Dict[str, Any], launch_attributes: Optional[List[Dict[str, str]]]): """Initialize required attributes. :param name: Launch name - :param attributes: Suite attributes passed through the listener + :param robot_attributes: Suite attributes passed through the listener """ - # noinspection PySuperArguments - super(Launch, self).__init__(name, attributes) + super().__init__(name, robot_attributes) self.type = 'LAUNCH' class Test: """Class represents Robot Framework test case.""" - def __init__(self, name, attributes): + _critical: str + _tags: List[str] + robot_attributes: Dict[str, Any] + attributes: List[Dict[str, str]] + doc: str + end_time: str + longname: str + message: str + name: str + robot_id: str + rp_item_id: Optional[str] + rp_parent_item_id: Optional[str] + start_time: str + status: str + template: str + type: str = 'TEST' + + def __init__(self, name: str, robot_attributes: Dict[str, Any]): """Initialize required attributes. :param name: Name of the test - :param attributes: Test attributes passed through the listener + :param robot_attributes: Test attributes passed through the listener """ # for backward compatibility with Robot < 4.0 mark every test case # as critical if not set - self._critical = attributes.get('critical', 'yes') - self._tags = attributes['tags'] - self._attributes = attributes - self.doc = attributes['doc'] - self.end_time = attributes.get('endtime', '') - self.longname = attributes['longname'] - self.message = attributes.get('message') + self._critical = robot_attributes.get('critical', 'yes') + self._tags = robot_attributes['tags'] + self.robot_attributes = robot_attributes + self.doc = robot_attributes['doc'] + self.end_time = robot_attributes.get('endtime', '') + self.longname = robot_attributes['longname'] + self.message = robot_attributes.get('message') self.name = name - self.robot_id = attributes['id'] + self.robot_id = robot_attributes['id'] self.rp_item_id = None self.rp_parent_item_id = None - self.start_time = attributes['starttime'] - self.status = attributes.get('status') - self.template = attributes['template'] + self.start_time = robot_attributes['starttime'] + self.status = robot_attributes.get('status') + self.template = robot_attributes['template'] self.type = 'TEST' @property - def critical(self): + def critical(self) -> bool: """Form unique value for RF 4.0+ and older versions.""" return self._critical in ('yes', True) @property - def tags(self): + def tags(self) -> List[str]: """Get list of test tags excluding test_case_id.""" return [ tag for tag in self._tags if not tag.startswith('test_case_id')] @property - def source(self): + def source(self) -> str: """Return the test case source file path.""" - if self._attributes['source'] is not None: - return os.path.relpath(self._attributes['source'], os.getcwd()) + if self.robot_attributes['source'] is not None: + return os.path.relpath(self.robot_attributes['source'], os.getcwd()) @property - def code_ref(self): + def code_ref(self) -> str: """Return the test case code reference. The result line should be exactly how it appears in '.robot' file. """ - line_number = self._attributes.get("lineno") + line_number = self.robot_attributes.get("lineno") if line_number is not None: return '{0}:{1}'.format(self.source, line_number) return '{0}:{1}'.format(self.source, self.name) @property - def test_case_id(self): + def test_case_id(self) -> Optional[str]: """Get test case ID through the tags.""" # use test case id from tags if specified for tag in self._tags: @@ -140,7 +178,7 @@ def test_case_id(self): # generate it if not return '{0}:{1}'.format(self.source, self.name) - def update(self, attributes): + def update(self, attributes: Dict[str, Any]) -> 'Test': """Update test attributes on test finish. :param attributes: Suite attributes passed through the listener @@ -155,31 +193,48 @@ def update(self, attributes): class Keyword: """Class represents Robot Framework keyword.""" - def __init__(self, name, attributes, parent_type=None): + robot_attributes: Dict[str, Any] + args: List[str] + assign: List[str] + doc: str + end_time: str + keyword_name: str + keyword_type: str + libname: str + name: str + rp_item_id: Optional[str] + rp_parent_item_id: Optional[str] + parent_type: str + start_time: str + status: str + tags: List[str] + type: str = 'KEYWORD' + + def __init__(self, name: str, robot_attributes: Dict[str, Any], parent_type: Optional[str] = None): """Initialize required attributes. :param name: Name of the keyword - :param attributes: Keyword attributes passed through the listener + :param robot_attributes: Keyword attributes passed through the listener :param parent_type: Type of the parent test item """ - self.attributes = attributes - self.args = attributes['args'] - self.assign = attributes['assign'] - self.doc = attributes['doc'] - self.end_time = attributes.get('endtime') - self.keyword_name = attributes['kwname'] - self.keyword_type = attributes['type'] - self.libname = attributes['libname'] + self.robot_attributes = robot_attributes + self.args = robot_attributes['args'] + self.assign = robot_attributes['assign'] + self.doc = robot_attributes['doc'] + self.end_time = robot_attributes.get('endtime') + self.keyword_name = robot_attributes['kwname'] + self.keyword_type = robot_attributes['type'] + self.libname = robot_attributes['libname'] self.name = name self.rp_item_id = None self.rp_parent_item_id = None self.parent_type = parent_type - self.start_time = attributes['starttime'] - self.status = attributes.get('status') - self.tags = attributes['tags'] + self.start_time = robot_attributes['starttime'] + self.status = robot_attributes.get('status') + self.tags = robot_attributes['tags'] self.type = 'KEYWORD' - def get_name(self): + def get_name(self) -> str: """Get name of the keyword suitable for ReportPortal.""" assign = ', '.join(self.assign) assignment = '{0} = '.format(assign) if self.assign else '' @@ -187,7 +242,7 @@ def get_name(self): full_name = f'{assignment}{self.name} ({arguments})' return full_name[:256] - def get_type(self): + def get_type(self) -> str: """Get keyword type.""" if self.keyword_type.lower() in ('setup', 'teardown'): if self.parent_type.lower() == 'keyword': @@ -199,7 +254,7 @@ def get_type(self): else: return 'STEP' - def update(self, attributes): + def update(self, attributes: Dict[str, Any]) -> 'Keyword': """Update keyword attributes on keyword finish. :param attributes: Suite attributes passed through the listener @@ -209,17 +264,19 @@ def update(self, attributes): return self -class LogMessage(str): +class LogMessage: """Class represents Robot Framework messages.""" - def __init__(self, message): + attachment: Optional[Dict[str, str]] + launch_log: bool + item_id: Optional[str] + level: str + message: str + + def __init__(self, message: str): """Initialize required attributes.""" self.attachment = None self.item_id = None self.level = 'INFO' self.launch_log = False self.message = message - - def __repr__(self): - """Return string representation of the object.""" - return self.message diff --git a/robotframework_reportportal/model.pyi b/robotframework_reportportal/model.pyi deleted file mode 100644 index 79fd73d..0000000 --- a/robotframework_reportportal/model.pyi +++ /dev/null @@ -1,101 +0,0 @@ -# Copyright (c) 2023 EPAM Systems -# 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 -# -# https://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 typing import Any, Dict, List, Optional, Tuple, Union - -class Suite: - attributes: Union[List[str], Dict[str, Any]] = ... - doc: str = ... - end_time: str = ... - longname: str = ... - message: str = ... - metadata: Dict[str, str] = ... - name: str = ... - robot_id: str = ... - rp_item_id: Optional[str] = ... - rp_parent_item_id: Optional[str] = ... - start_time: Optional[str] = ... - statistics: str = ... - status: str = ... - suites: List[str] = ... - tests: List[str] = ... - total_tests: int = ... - type: str = 'SUITE' - def __init__(self, name: str, attributes: Dict[str, Any]) -> None: ... - @property - def source(self) -> str: ... - def update(self, attributes: Dict[str, Any]) -> Union[Launch, Suite]: ... - -class Launch(Suite): - type: str = 'LAUNCH' - def __init__(self, name: str, attributes: Dict[str, Any]) -> None: ... - -class Test: - _critical: str = ... - _tags: List[str] = ... - _attributes: Dict[str, Any] = ... - attributes: List[Dict[str, str]] = ... - doc: str = ... - end_time: str = ... - longname: str = ... - message: str = ... - name: str = ... - robot_id: str = ... - rp_item_id: Optional[str] = ... - rp_parent_item_id: Optional[str] = ... - start_time: str = ... - status: str = ... - template: str = ... - type: str = 'TEST' - def __init__(self, name: str, attributes: Dict[str, Any]) -> None: ... - @property - def critical(self) -> bool: ... - @property - def tags(self) -> List[str]: ... - @property - def source(self) -> str: ... - @property - def code_ref(self) -> str: ... - @property - def test_case_id(self) -> Optional[str]: ... - def update(self, attributes: Dict[str, Any]) -> Test: ... - -class Keyword: - attributes: Dict[str, Any] = ... - args: List[str] = ... - assign: List[str] = ... - doc: str = ... - end_time: str = ... - keyword_name: str = ... - keyword_type: str = ... - libname: str = ... - name: str = ... - rp_item_id: Optional[str] = ... - rp_parent_item_id: Optional[str] = ... - parent_type: str = ... - start_time: str = ... - status: str = ... - tags: List[str] = ... - type: str = 'KEYWORD' - def __init__(self, name: str, attributes: Dict[str, Any], parent_type: Optional[str] = None) -> None: ... - def get_name(self) -> str: ... - def get_type(self) -> str: ... - def update(self, attributes: Dict[str, Any]) -> Keyword: ... - -class LogMessage(str): - attachment: Optional[Dict[str, str]] = ... - launch_log: bool = ... - item_id: Optional[str] = ... - level: str = ... - message: str = ... - def __init__(self, *args: Tuple, **kwargs: Dict) -> None: ... diff --git a/robotframework_reportportal/service.py b/robotframework_reportportal/service.py index b5bd69a..7aa16fb 100644 --- a/robotframework_reportportal/service.py +++ b/robotframework_reportportal/service.py @@ -120,7 +120,7 @@ def start_launch(self, launch: Launch, mode: Optional[str] = None, rerun: bool = :return: launch UUID """ sl_pt = { - 'attributes': self._get_launch_attributes(launch.attributes), + 'attributes': self._get_launch_attributes(launch.robot_attributes), 'description': launch.doc, 'name': launch.name, 'mode': mode, diff --git a/tests/unit/test_model.py b/tests/unit/test_model.py index 5d3ea6d..12a8cc7 100644 --- a/tests/unit/test_model.py +++ b/tests/unit/test_model.py @@ -25,7 +25,7 @@ ]) def test_keyword_get_type(kwd_attributes, self_type, parent_type, expected): """Test for the get_type() method of the Keyword model.""" - kwd = Keyword(name='Test keyword', attributes=kwd_attributes, + kwd = Keyword(name='Test keyword', robot_attributes=kwd_attributes, parent_type=parent_type) kwd.keyword_type = self_type assert kwd.get_type() == expected