Skip to content

Commit 7092aab

Browse files
authored
Merge pull request #209 from reportportal/develop
Release
2 parents 45b8002 + 13f9b45 commit 7092aab

20 files changed

+337
-202
lines changed

.github/workflows/release.yml

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,19 @@ jobs:
7575
git tag -a ${{ env.RELEASE_VERSION }} -m "Release ${{ env.RELEASE_VERSION }}"
7676
git push --tags
7777
78+
- name: Checkout develop branch
79+
uses: actions/checkout@v3
80+
with:
81+
ref: 'develop'
82+
fetch-depth: 0
83+
84+
- name: Merge release branch into develop
85+
id: mergeIntoDevelop
86+
run: |
87+
git merge -m 'Merge master branch into develop after a release' origin/master
88+
git status | (! grep -Fq 'both modified:') || git status | grep -F 'both modified:' \
89+
| { echo -e 'Unable to merge master into develop, merge conflicts:'; (! grep -Eo '[^ ]+$') }
90+
7891
- name: Update CHANGELOG.md
7992
id: changelogUpdate
8093
run: |
@@ -103,19 +116,6 @@ jobs:
103116
name: Release ${{ env.RELEASE_VERSION }}
104117
body: ${{ steps.readChangelogEntry.outputs.changes }}
105118

106-
- name: Checkout develop branch
107-
uses: actions/checkout@v3
108-
with:
109-
ref: 'develop'
110-
fetch-depth: 0
111-
112-
- name: Merge release branch into develop
113-
id: mergeIntoDevelop
114-
run: |
115-
git merge -m 'Merge master branch into develop after a release' origin/master
116-
git status | (! grep -Fq 'both modified:') || git status | grep -F 'both modified:' \
117-
| { echo -e 'Unable to merge master into develop, merge conflicts:'; (! grep -Eo '[^ ]+$') }
118-
119119
- name: Update version file
120120
id: versionFileUpdate
121121
run: |

CHANGELOG.md

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

33
## [Unreleased]
4+
### Added
5+
- `MAX_LOG_BATCH_SIZE` constant into `log_manager` module, by @HardNorth
6+
### Fixed
7+
- Missed `verify_ssl` argument passing to `LogManager` class, by @rplevka
8+
### Changed
9+
- Statistics service was refactored, by @HardNorth
10+
11+
## [5.3.0]
412
### Fixed
513
- Issue [#198](https://github.com/reportportal/client-Python/issues/198): Python 3.8+ logging issue, by @HardNorth
614
- Issue [#200](https://github.com/reportportal/client-Python/issues/200): max_pool_size not worked without retries setting, by @ericscobell

README.md

Lines changed: 58 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,12 @@
1010

1111
Library used only for implementors of custom listeners for ReportPortal
1212

13-
1413
## Already implemented listeners:
1514

1615
- [PyTest Framework](https://github.com/reportportal/agent-python-pytest)
1716
- [Robot Framework](https://github.com/reportportal/agent-Python-RobotFramework)
1817
- [Behave Framework](https://github.com/reportportal/agent-python-behave)
19-
- [Nose Framework](https://github.com/reportportal/agent-python-nosetests)
20-
18+
- [Nose Framework (archived)](https://github.com/reportportal/agent-python-nosetests)
2119

2220
## Installation
2321

@@ -27,116 +25,60 @@ The latest stable version is available on PyPI:
2725
pip install reportportal-client
2826
```
2927

30-
**IMPORTANT!**
31-
The latest client version **does** not support Report Portal versions below
32-
5.0.0.
33-
34-
Version 3 is the latest one which supports Report Portal versions below 5.0.0
35-
to install it:
36-
37-
```
38-
pip install reportportal-client~=3.0
39-
```
40-
41-
42-
## Contribution
43-
44-
All the fixes for the client that supports Report Portal versions below 5.0.0
45-
should go into the v3 branch. The master branch will store the code base for
46-
the client for Report Portal versions 5 and above.
47-
48-
4928
## Usage
5029

51-
Main classes are:
52-
53-
- reportportal_client.ReportPortalService
54-
- reportportal_client.ReportPortalServiceAsync(Client version 3.x only)
55-
5630
Basic usage example:
5731

5832
```python
5933
import os
6034
import subprocess
61-
import traceback
6235
from mimetypes import guess_type
63-
from time import time
64-
65-
# Report Portal versions below 5.0.0:
66-
from reportportal_client import ReportPortalServiceAsync
67-
68-
# Report Portal versions >= 5.0.0:
69-
from reportportal_client import ReportPortalService
70-
71-
72-
def timestamp():
73-
return str(int(time() * 1000))
7436

37+
from reportportal_client import RPClient
38+
from reportportal_client.helpers import timestamp
7539

76-
endpoint = "http://10.6.40.6:8080"
40+
endpoint = "http://docker.local:8080"
7741
project = "default"
7842
# You can get UUID from user profile page in the Report Portal.
7943
token = "1adf271d-505f-44a8-ad71-0afbdf8c83bd"
8044
launch_name = "Test launch"
8145
launch_doc = "Testing logging with attachment."
8246

8347

84-
def my_error_handler(exc_info):
85-
"""
86-
This callback function will be called by async service client when error occurs.
87-
Return True if error is not critical and you want to continue work.
88-
:param exc_info: result of sys.exc_info() -> (type, value, traceback)
89-
:return:
90-
"""
91-
print("Error occurred: {}".format(exc_info[1]))
92-
traceback.print_exception(*exc_info)
48+
client = RPClient(endpoint=endpoint, project=project,
49+
token=token)
9350

94-
95-
# Report Portal versions below 5.0.0:
96-
service = ReportPortalServiceAsync(endpoint=endpoint, project=project,
97-
token=token, error_handler=my_error_handler)
98-
99-
# Report Portal versions >= 5.0.0:
100-
service = ReportPortalService(endpoint=endpoint, project=project,
101-
token=token)
51+
# Start log upload thread
52+
client.start()
10253

10354
# Start launch.
104-
launch = service.start_launch(name=launch_name,
105-
start_time=timestamp(),
106-
description=launch_doc)
107-
108-
# Start test item Report Portal versions below 5.0.0:
109-
test = service.start_test_item(name="Test Case",
110-
description="First Test Case",
111-
tags=["Image", "Smoke"],
112-
start_time=timestamp(),
113-
item_type="STEP",
114-
parameters={"key1": "val1",
115-
"key2": "val2"})
116-
117-
# Start test item Report Portal versions >= 5.0.0:
118-
item_id = service.start_test_item(name="Test Case",
119-
description="First Test Case",
120-
start_time=timestamp(),
121-
item_type="STEP",
122-
parameters={"key1": "val1",
123-
"key2": "val2"})
124-
55+
launch = client.start_launch(name=launch_name,
56+
start_time=timestamp(),
57+
description=launch_doc)
58+
59+
item_id = client.start_test_item(name="Test Case",
60+
description="First Test Case",
61+
start_time=timestamp(),
62+
attributes=[{"key": "key", "value": "value"},
63+
{"value", "tag"}],
64+
item_type="STEP",
65+
parameters={"key1": "val1",
66+
"key2": "val2"})
12567

12668
# Create text log message with INFO level.
127-
service.log(time=timestamp(),
128-
message="Hello World!",
129-
level="INFO")
69+
client.log(time=timestamp(),
70+
message="Hello World!",
71+
level="INFO")
13072

13173
# Create log message with attached text output and WARN level.
132-
service.log(time=timestamp(),
133-
message="Too high memory usage!",
134-
level="WARN",
135-
attachment={
136-
"name": "free_memory.txt",
137-
"data": subprocess.check_output("free -h".split()),
138-
"mime": "text/plain"
139-
})
74+
client.log(time=timestamp(),
75+
message="Too high memory usage!",
76+
level="WARN",
77+
attachment={
78+
"name": "free_memory.txt",
79+
"data": subprocess.check_output("free -h".split()),
80+
"mime": "text/plain"
81+
})
14082

14183
# Create log message with binary file, INFO level and custom mimetype.
14284
image = "/tmp/image.png"
@@ -146,57 +88,49 @@ with open(image, "rb") as fh:
14688
"data": fh.read(),
14789
"mime": guess_type(image)[0] or "application/octet-stream"
14890
}
149-
service.log(timestamp(), "Screen shot of issue.", "INFO", attachment)
150-
151-
# Create log message supplying only contents
152-
service.log(
153-
timestamp(),
154-
"running processes",
155-
"INFO",
156-
attachment=subprocess.check_output("ps aux".split()))
91+
client.log(timestamp(), "Screen shot of issue.", "INFO", attachment)
15792

158-
# Finish test item Report Portal versions below 5.0.0.
159-
service.finish_test_item(end_time=timestamp(), status="PASSED")
160-
161-
# Finish test item Report Portal versions >= 5.0.0.
162-
service.finish_test_item(item_id=item_id, end_time=timestamp(), status="PASSED")
93+
client.finish_test_item(item_id=item_id, end_time=timestamp(), status="PASSED")
16394

16495
# Finish launch.
165-
service.finish_launch(end_time=timestamp())
96+
client.finish_launch(end_time=timestamp())
16697

16798
# Due to async nature of the service we need to call terminate() method which
16899
# ensures all pending requests to server are processed.
169100
# Failure to call terminate() may result in lost data.
170-
service.terminate()
101+
client.terminate()
171102
```
172103

173-
174104
# Send attachment (screenshots)
175105

176-
[python-client](https://github.com/reportportal/client-Python/blob/64550693ec9c198b439f8f6e8b23413812d9adf1/reportportal_client/service.py#L259) uses `requests` library for working with RP and the same semantics to work with attachments (data).
106+
The client uses `requests` library for working with RP and the same semantics
107+
to work with attachments (data).
177108

178-
There are two ways to pass data as attachment:
109+
To log an attachment you need to pass file content and metadata to ``
179110

180-
### Case 1 - pass file-like object
181-
```
182-
with open(screenshot_file_path, "rb") as image_file:
183-
rp_logger.info("Some Text Here",
184-
attachment={"name": "test_name_screenshot.png",
185-
"data": image_file,
186-
"mime": "image/png"})
187-
```
111+
```python
112+
import logging
188113

189-
### Case 2 - pass file content itself (like you did)
190-
```
191-
with open(screenshot_file_path, "rb") as image_file:
192-
file_data = image_file.read()
114+
from reportportal_client import RPLogger, RPLogHandler
193115

194-
rp_logger.info("Some Text Here",
195-
attachment={"name": "test_name_screenshot.png",
196-
"data": file_data,
197-
"mime": "image/png"})
198-
```
116+
logging.setLoggerClass(RPLogger)
117+
rp_logger = logging.getLogger(__name__)
118+
rp_logger.setLevel(logging.DEBUG)
119+
rp_logger.addHandler(RPLogHandler())
120+
121+
screenshot_file_path = 'path/to/file.png'
199122

123+
with open(screenshot_file_path, "rb") as image_file:
124+
file_data = image_file.read()
125+
126+
# noinspection PyArgumentList
127+
rp_logger.info(
128+
"Some Text Here",
129+
attachment={"name": "test_name_screenshot.png",
130+
"data": file_data,
131+
"mime": "image/png"}
132+
)
133+
```
200134

201135
# Copyright Notice
202136

reportportal_client/client.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,8 @@ def __init__(self,
120120
self._log_manager = LogManager(
121121
self.endpoint, self.session, self.api_v2, self.launch_id,
122122
self.project, max_entry_number=log_batch_size,
123-
max_payload_size=log_batch_payload_size)
123+
max_payload_size=log_batch_payload_size,
124+
verify_ssl=self.verify_ssl)
124125

125126
def finish_launch(self,
126127
end_time,

reportportal_client/client.pyi

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ class RPClient:
9090
start_time: Text,
9191
item_type: Text,
9292
description: Text = ...,
93-
attributes: Optional[Union[List, Dict]] = ...,
93+
attributes: Optional[List[Dict]] = ...,
9494
parameters: Dict = ...,
9595
parent_item_id: Text = ...,
9696
has_stats: bool = ...,

reportportal_client/helpers.pyi

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ TYPICAL_MULTIPART_FOOTER_LENGTH: int
1515
def generate_uuid() -> Text: ...
1616
def convert_string(value: Text) -> Text: ...
1717
def dict_to_payload(dictionary: dict) -> list[dict]: ...
18-
def gen_attributes(rp_attributes: list) -> list[dict]: ...
18+
def gen_attributes(rp_attributes: List[Text]) -> List[Dict[Text, Text]]: ...
1919
def get_launch_sys_attrs()-> dict[Text]: ...
2020
def get_package_version(package_name:Text) -> Text: ...
2121
def uri_join(*uri_parts: Text) -> Text: ...

reportportal_client/logs/__init__.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -174,9 +174,8 @@ def emit(self, record):
174174
self.handleError(record)
175175

176176
log_level = self._get_rp_log_level(record.levelno)
177-
if self.rp_client:
178-
rp_client = self.rp_client
179-
else:
177+
rp_client = self.rp_client
178+
if not rp_client:
180179
rp_client = current()
181180
if rp_client:
182181
rp_client.log(

reportportal_client/logs/log_manager.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,15 @@
3030

3131
logger = logging.getLogger(__name__)
3232

33+
MAX_LOG_BATCH_SIZE = 20
3334
MAX_LOG_BATCH_PAYLOAD_SIZE = 65000000
3435

3536

3637
class LogManager(object):
3738
"""Manager of the log items."""
3839

3940
def __init__(self, rp_url, session, api_version, launch_id, project_name,
40-
max_entry_number=20, verify_ssl=True,
41+
max_entry_number=MAX_LOG_BATCH_SIZE, verify_ssl=True,
4142
max_payload_size=MAX_LOG_BATCH_PAYLOAD_SIZE):
4243
"""Initialize instance attributes.
4344

reportportal_client/logs/log_manager.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ from reportportal_client.core.worker import APIWorker as APIWorker
2525

2626
logger: Logger
2727

28+
MAX_LOG_BATCH_SIZE: int
2829
MAX_LOG_BATCH_PAYLOAD_SIZE: int
2930

3031

0 commit comments

Comments
 (0)