Skip to content

Commit 1db0ca3

Browse files
authored
Merge pull request #186 from reportportal/develop
Release
2 parents b7701e4 + 0b43da9 commit 1db0ca3

File tree

14 files changed

+321
-321
lines changed

14 files changed

+321
-321
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22

33
## [Unreleased]
44
### Added
5+
- Issue [#178](https://github.com/reportportal/agent-Python-RobotFramework/issues/178) Metadata attributes handling, by @HardNorth
6+
### Changed
7+
- Client version updated on [5.5.6](https://github.com/reportportal/client-Python/releases/tag/5.5.6), by @HardNorth
8+
### Removed
9+
- `model.pyi`, `static.pyi` stub files, as we don't really need them anymore, by @HardNorth
10+
11+
## [5.5.2]
12+
### Added
513
- Binary data escaping in `listener` module (enhancing `Get Binary File` keyword logging), by @HardNorth
614
### Changed
715
- Client version updated on [5.5.5](https://github.com/reportportal/client-Python/releases/tag/5.5.5), by @HardNorth

examples/suite_metadata.robot

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
*** Settings ***
2+
Metadata Author John Doe
3+
4+
*** Test Cases ***
5+
Simple test
6+
Log Hello, world!

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
# Basic dependencies
22
python-dateutil~=2.8.1
3-
reportportal-client~=5.5.5
3+
reportportal-client~=5.5.6
44
robotframework

robotframework_reportportal/listener.py

Lines changed: 23 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -20,38 +20,19 @@
2020
import re
2121
from functools import wraps
2222
from mimetypes import guess_type
23-
from types import MappingProxyType
2423
from typing import Optional, Dict, Union, Any
2524
from warnings import warn
2625

27-
from reportportal_client.helpers import gen_attributes, LifoQueue, is_binary, guess_content_type_from_bytes
26+
from reportportal_client.helpers import LifoQueue, is_binary, guess_content_type_from_bytes
2827

2928
from .model import Keyword, Launch, Test, LogMessage, Suite
3029
from .service import RobotService
31-
from .static import MAIN_SUITE_ID, PABOT_WIHOUT_LAUNCH_ID_MSG
30+
from .static import MAIN_SUITE_ID, PABOT_WITHOUT_LAUNCH_ID_MSG
3231
from .variables import Variables
3332

3433
logger = logging.getLogger(__name__)
3534
VARIABLE_PATTERN = r'^\s*\${[^}]*}\s*=\s*'
3635
TRUNCATION_SIGN = "...'"
37-
CONTENT_TYPE_TO_EXTENSIONS = MappingProxyType({
38-
'application/pdf': 'pdf',
39-
'application/zip': 'zip',
40-
'application/java-archive': 'jar',
41-
'image/jpeg': 'jpg',
42-
'image/png': 'png',
43-
'image/gif': 'gif',
44-
'image/bmp': 'bmp',
45-
'image/vnd.microsoft.icon': 'ico',
46-
'image/webp': 'webp',
47-
'audio/mpeg': 'mp3',
48-
'audio/wav': 'wav',
49-
'video/mpeg': 'mpeg',
50-
'video/avi': 'avi',
51-
'video/webm': 'webm',
52-
'text/plain': 'txt',
53-
'application/octet-stream': 'bin'
54-
})
5536

5637

5738
def _unescape(binary_string: str, stop_at: int = -1):
@@ -106,9 +87,9 @@ def wrap(*args, **kwargs):
10687
class listener:
10788
"""Robot Framework listener interface for reporting to ReportPortal."""
10889

109-
_items: LifoQueue = ...
110-
_service: Optional[RobotService] = ...
111-
_variables: Optional[Variables] = ...
90+
_items: LifoQueue
91+
_service: Optional[RobotService]
92+
_variables: Optional[Variables]
11293
ROBOT_LISTENER_API_VERSION = 2
11394

11495
def __init__(self) -> None:
@@ -165,7 +146,7 @@ def log_message(self, message: Dict) -> None:
165146
msg.message = (f'Binary data of type "{content_type}" logging skipped, as it was processed as text and'
166147
' hence corrupted.')
167148
msg.level = 'WARN'
168-
logger.debug('ReportPortal - Log Message: {0}'.format(message))
149+
logger.debug(f'ReportPortal - Log Message: {message}')
169150
self.service.log(message=msg)
170151

171152
@check_rp_enabled
@@ -182,8 +163,7 @@ def log_message_with_image(self, msg: Dict, image: str):
182163
'data': fh.read(),
183164
'mime': guess_type(image)[0] or 'application/octet-stream'
184165
}
185-
logger.debug('ReportPortal - Log Message with Image: {0} {1}'
186-
.format(mes, image))
166+
logger.debug(f'ReportPortal - Log Message with Image: {mes} {image}')
187167
self.service.log(message=mes)
188168

189169
@property
@@ -207,18 +187,17 @@ def variables(self) -> Variables:
207187
return self._variables
208188

209189
@check_rp_enabled
210-
def start_launch(self, attributes: Dict, ts: Optional[Any] = None) -> None:
190+
def start_launch(self, attributes: Dict[str, Any], ts: Optional[Any] = None) -> None:
211191
"""Start a new launch at the ReportPortal.
212192
213193
:param attributes: Dictionary passed by the Robot Framework
214194
:param ts: Timestamp(used by the ResultVisitor)
215195
"""
216-
launch = Launch(self.variables.launch_name, attributes)
217-
launch.attributes = gen_attributes(self.variables.launch_attributes)
196+
launch = Launch(self.variables.launch_name, attributes, self.variables.launch_attributes)
218197
launch.doc = self.variables.launch_doc or launch.doc
219198
if self.variables.pabot_used:
220-
warn(PABOT_WIHOUT_LAUNCH_ID_MSG, stacklevel=2)
221-
logger.debug('ReportPortal - Start Launch: {0}'.format(launch.attributes))
199+
warn(PABOT_WITHOUT_LAUNCH_ID_MSG, stacklevel=2)
200+
logger.debug(f'ReportPortal - Start Launch: {launch.robot_attributes}')
222201
self.service.start_launch(
223202
launch=launch,
224203
mode=self.variables.mode,
@@ -237,10 +216,10 @@ def start_suite(self, name: str, attributes: Dict, ts: Optional[Any] = None) ->
237216
if attributes['id'] == MAIN_SUITE_ID:
238217
self.start_launch(attributes, ts)
239218
if self.variables.pabot_used:
240-
name += '.{0}'.format(self.variables.pabot_pool_id)
241-
logger.debug('ReportPortal - Create global Suite: {0}'.format(attributes))
219+
name = f'{name}.{self.variables.pabot_pool_id}'
220+
logger.debug(f'ReportPortal - Create global Suite: {attributes}')
242221
else:
243-
logger.debug('ReportPortal - Start Suite: {0}'.format(attributes))
222+
logger.debug(f'ReportPortal - Start Suite: {attributes}')
244223
suite = Suite(name, attributes)
245224
suite.rp_parent_item_id = self.parent_id
246225
suite.rp_item_id = self.service.start_suite(suite=suite, ts=ts)
@@ -255,12 +234,11 @@ def end_suite(self, _: Optional[str], attributes: Dict, ts: Optional[Any] = None
255234
:param ts: Timestamp(used by the ResultVisitor)
256235
"""
257236
suite = self._remove_current_item().update(attributes)
258-
logger.debug('ReportPortal - End Suite: {0}'.format(suite.attributes))
237+
logger.debug(f'ReportPortal - End Suite: {suite.robot_attributes}')
259238
self.service.finish_suite(suite=suite, ts=ts)
260239
if attributes['id'] == MAIN_SUITE_ID:
261-
launch = Launch(self.variables.launch_name, attributes)
262-
logger.debug(
263-
msg='ReportPortal - End Launch: {0}'.format(attributes))
240+
launch = Launch(self.variables.launch_name, attributes, None)
241+
logger.debug(msg=f'ReportPortal - End Launch: {attributes}')
264242
self.service.finish_launch(launch=launch, ts=ts)
265243

266244
@check_rp_enabled
@@ -275,9 +253,8 @@ def start_test(self, name: str, attributes: Dict, ts: Optional[Any] = None) -> N
275253
# no 'source' parameter at this level for Robot versions < 4
276254
attributes = attributes.copy()
277255
attributes['source'] = getattr(self.current_item, 'source', None)
278-
test = Test(name=name, attributes=attributes)
279-
logger.debug('ReportPortal - Start Test: {0}'.format(attributes))
280-
test.attributes = gen_attributes(self.variables.test_attributes + test.tags)
256+
test = Test(name=name, robot_attributes=attributes, test_attributes=self.variables.test_attributes)
257+
logger.debug(f'ReportPortal - Start Test: {attributes}')
281258
test.rp_parent_item_id = self.parent_id
282259
test.rp_item_id = self.service.start_test(test=test, ts=ts)
283260
self._add_current_item(test)
@@ -291,13 +268,11 @@ def end_test(self, _: Optional[str], attributes: Dict, ts: Optional[Any] = None)
291268
:param ts: Timestamp(used by the ResultVisitor)
292269
"""
293270
test = self.current_item.update(attributes)
294-
test.attributes = gen_attributes(
295-
self.variables.test_attributes + test.tags)
296271
if not test.critical and test.status == 'FAIL':
297272
test.status = 'SKIP'
298273
if test.message:
299274
self.log_message({'message': test.message, 'level': 'DEBUG'})
300-
logger.debug('ReportPortal - End Test: {0}'.format(test.attributes))
275+
logger.debug(f'ReportPortal - End Test: {test.robot_attributes}')
301276
self._remove_current_item()
302277
self.service.finish_test(test=test, ts=ts)
303278

@@ -309,9 +284,9 @@ def start_keyword(self, name: str, attributes: Dict, ts: Optional[Any] = None) -
309284
:param attributes: Dictionary passed by the Robot Framework
310285
:param ts: Timestamp(used by the ResultVisitor)
311286
"""
312-
kwd = Keyword(name=name, parent_type=self.current_item.type, attributes=attributes)
287+
kwd = Keyword(name=name, parent_type=self.current_item.type, robot_attributes=attributes)
313288
kwd.rp_parent_item_id = self.parent_id
314-
logger.debug('ReportPortal - Start Keyword: {0}'.format(attributes))
289+
logger.debug(f'ReportPortal - Start Keyword: {attributes}')
315290
kwd.rp_item_id = self.service.start_keyword(keyword=kwd, ts=ts)
316291
self._add_current_item(kwd)
317292

@@ -324,7 +299,7 @@ def end_keyword(self, _: Optional[str], attributes: Dict, ts: Optional[Any] = No
324299
:param ts: Timestamp(used by the ResultVisitor)
325300
"""
326301
kwd = self._remove_current_item().update(attributes)
327-
logger.debug('ReportPortal - End Keyword: {0}'.format(kwd.attributes))
302+
logger.debug(f'ReportPortal - End Keyword: {kwd.robot_attributes}')
328303
self.service.finish_keyword(keyword=kwd, ts=ts)
329304

330305
def log_file(self, log_path: str) -> None:

robotframework_reportportal/logger.py

Lines changed: 25 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -35,29 +35,29 @@ def log_free_memory(self):
3535
},
3636
)
3737
"""
38+
from typing import Optional, Dict
3839

3940
from robot.api import logger
4041

4142
from .model import LogMessage
4243

4344

44-
def write(msg, level='INFO', html=False, attachment=None, launch_log=False):
45+
def write(msg: str, level: str = 'INFO', html: bool = False, attachment: Optional[Dict[str, str]] = None,
46+
launch_log: bool = False) -> None:
4547
"""Write the message to the log file using the given level.
4648
47-
Valid log levels are ``TRACE``, ``DEBUG``, ``INFO`` (default since RF
48-
2.9.1), ``WARN``, and ``ERROR`` (new in RF 2.9). Additionally it is
49-
possible to use ``HTML`` pseudo log level that logs the message as HTML
50-
using the ``INFO`` level.
49+
Valid log levels are ``TRACE``, ``DEBUG``, ``INFO`` (default since RF 2.9.1), ``WARN``,
50+
and ``ERROR`` (new in RF 2.9). Additionally, it is possible to use ``HTML`` pseudo log level that logs the message
51+
as HTML using the ``INFO`` level.
5152
52-
Attachment should contain a dict with "name", "data" and "mime" values
53-
defined. See module example.
53+
Attachment should contain a dict with "name", "data" and "mime" values defined. See module example.
5454
55-
Instead of using this method, it is generally better to use the level
56-
specific methods such as ``info`` and ``debug`` that have separate
55+
Instead of using this method, it is generally better to use the level specific methods such as ``info`` and
56+
``debug`` that have separate
5757
58-
:param msg: argument to control the message format.
59-
:param level: log level
60-
:param html: format or not format the message as html.
58+
:param msg: argument to control the message format.
59+
:param level: log level
60+
:param html: format or not format the message as html.
6161
:param attachment: a binary content to attach to the log entry
6262
:param launch_log: put the log entry on Launch level
6363
"""
@@ -68,46 +68,43 @@ def write(msg, level='INFO', html=False, attachment=None, launch_log=False):
6868
logger.write(log_message, level, html)
6969

7070

71-
def trace(msg, html=False, attachment=None, launch_log=False):
71+
def trace(msg: str, html: bool = False, attachment: Optional[Dict[str, str]] = None, launch_log: bool = False) -> None:
7272
"""Write the message to the log file using the ``TRACE`` level."""
7373
write(msg, "TRACE", html, attachment, launch_log)
7474

7575

76-
def debug(msg, html=False, attachment=None, launch_log=False):
76+
def debug(msg: str, html: bool = False, attachment: Optional[Dict[str, str]] = None, launch_log: bool = False) -> None:
7777
"""Write the message to the log file using the ``DEBUG`` level."""
7878
write(msg, "DEBUG", html, attachment, launch_log)
7979

8080

81-
def info(msg, html=False, also_console=False, attachment=None,
82-
launch_log=False):
81+
def info(msg: str, html: bool = False, also_console: bool = False, attachment: Optional[Dict[str, str]] = None,
82+
launch_log: bool = False):
8383
"""Write the message to the log file using the ``INFO`` level.
8484
85-
If ``also_console`` argument is set to ``True``, the message is
86-
written both to the log file and to the console.
85+
If ``also_console`` argument is set to ``True``, the message is written both to the log file and to the console.
8786
"""
8887
write(msg, "INFO", html, attachment, launch_log)
8988
if also_console:
9089
console(msg)
9190

9291

93-
def warn(msg, html=False, attachment=None, launch_log=False):
92+
def warn(msg: str, html: bool = False, attachment: Optional[Dict[str, str]] = None, launch_log: bool = False) -> None:
9493
"""Write the message to the log file using the ``WARN`` level."""
95-
write(msg, "WARN", html, attachment, launch_log)
94+
write(msg, 'WARN', html, attachment, launch_log)
9695

9796

98-
def error(msg, html=False, attachment=None, launch_log=False):
97+
def error(msg: str, html: bool = False, attachment: Optional[Dict[str, str]] = None, launch_log: bool = False) -> None:
9998
"""Write the message to the log file using the ``ERROR`` level."""
100-
write(msg, "ERROR", html, attachment, launch_log)
99+
write(msg, 'ERROR', html, attachment, launch_log)
101100

102101

103-
def console(msg, newline=True, stream="stdout"):
102+
def console(msg: str, newline: bool = True, stream: str = 'stdout') -> None:
104103
"""Write the message to the console.
105104
106-
If the ``newline`` argument is ``True``, a newline character is
107-
automatically added to the message.
105+
If the ``newline`` argument is ``True``, a newline character is automatically added to the message.
108106
109-
By default the message is written to the standard output stream.
110-
Using the standard error stream is possibly by giving the ``stream``
111-
argument value ``'stderr'``.
107+
By default, the message is written to the standard output stream.
108+
Using the standard error stream is possibly by giving the ``stream`` argument value ``'stderr'``.
112109
"""
113110
logger.console(msg, newline, stream)

0 commit comments

Comments
 (0)