Skip to content

Commit 5c94b4b

Browse files
authored
Merge pull request #406 from reportportal/develop
Release
2 parents 2a03062 + 655740c commit 5c94b4b

File tree

20 files changed

+297
-201
lines changed

20 files changed

+297
-201
lines changed

.github/workflows/tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
runs-on: ubuntu-latest
2121
strategy:
2222
matrix:
23-
python-version: [ '3.8', '3.9', '3.10', '3.11', '3.12', '3.13' ]
23+
python-version: [ '3.9', '3.10', '3.11', '3.12', '3.13', '3.14' ]
2424
steps:
2525
- name: Checkout repository
2626
uses: actions/checkout@v4

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,3 +132,6 @@ dmypy.json
132132

133133
# Pyre type checker
134134
.pyre/
135+
136+
AGENTS.md
137+
PROMPTS.md

CHANGELOG.md

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

33
## [Unreleased]
44
### Added
5+
- Official `Python 3.14` support, by @HardNorth
6+
- Issue [#396](https://github.com/reportportal/agent-python-pytest/issues/396) parametrize marker IDs, by @HardNorth
7+
- Custom log level handling with `rp_log_custom_levels` configuration parameter, by @HardNorth
8+
### Removed
9+
- `Python 3.8` support, by @HardNorth
10+
- Deprecated `retries` parameter, by @HardNorth
11+
12+
## [5.5.4]
13+
### Added
514
- Return back deprecated `rp_log_batch_payload_size` parameter for sake of backward compatibility, by @HardNorth
615

716
## [5.5.3]

README.md

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,20 @@ py.test -c config.cfg
3434

3535
The `pytest.ini` file should have next mandatory fields:
3636

37-
- `rp_api_key` - value could be found in the User Profile section
3837
- `rp_project` - name of project in ReportPortal
3938
- `rp_endpoint` - address of ReportPortal Server
4039

40+
And one type of authorization: API Key or OAuth 2.0 Password grant. You can do this by setting:
41+
- `rp_api_key` or `RP_API_KEY` environment variable. You can get it in the User Profile section on the UI.
42+
43+
Or:
44+
- `rp_oauth_uri` - OAuth 2.0 token endpoint URL for password grant authentication. **Required** if API key is not used.
45+
- `rp_oauth_username` - OAuth 2.0 username for password grant authentication. **Required** if OAuth 2.0 is used.
46+
- `rp_oauth_password` - OAuth 2.0 password for password grant authentication. **Required** if OAuth 2.0 is used.
47+
- `rp_oauth_client_id` - OAuth 2.0 client identifier. **Required** if OAuth 2.0 is used.
48+
- `rp_oauth_client_secret` - OAuth 2.0 client secret. **Optional** for OAuth 2.0 authentication.
49+
- `rp_oauth_scope` - OAuth 2.0 access token scope. **Optional** for OAuth 2.0 authentication.
50+
4151
Example of `pytest.ini`:
4252

4353
```text
@@ -51,8 +61,6 @@ rp_launch_description = 'Smoke test'
5161
rp_ignore_attributes = 'xfail' 'usefixture'
5262
```
5363

54-
- The `rp_api_key` can also be set with the environment variable `RP_API_KEY`. This will override the value set for `rp_api_key` in pytest.ini
55-
5664
There are also optional parameters:
5765
https://reportportal.io/docs/log-data-in-reportportal/test-framework-integration/Python/pytest/
5866

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
"""A simple example test with Test Case ID decorator and parameters."""
2+
3+
# Copyright (c) 2022 https://reportportal.io .
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# https://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License
15+
16+
import pytest
17+
18+
TEST_CASE_ID = "ISSUE-231"
19+
20+
21+
@pytest.mark.parametrize(("param1", "param2"), [("value1", "value2")], ids=[TEST_CASE_ID])
22+
def test_case_id_decorator(param1, param2):
23+
assert True

examples/test_rp_custom_logging.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Copyright (c) 2022 https://reportportal.io .
2+
# Licensed under the Apache License, Version 2.0 (the "License");
3+
# you may not use this file except in compliance with the License.
4+
# You may obtain a copy of the License at
5+
#
6+
# https://www.apache.org/licenses/LICENSE-2.0
7+
#
8+
# Unless required by applicable law or agreed to in writing, software
9+
# distributed under the License is distributed on an "AS IS" BASIS,
10+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
# See the License for the specific language governing permissions and
12+
# limitations under the License
13+
14+
import logging
15+
16+
logging.basicConfig(level=logging.INFO)
17+
18+
logger = logging.getLogger(__name__)
19+
20+
LOG_LEVEL: int = 35
21+
LOG_MESSAGE: str = "Assertion error"
22+
23+
24+
def test_report_portal_logging():
25+
logger.log(LOG_LEVEL, LOG_MESSAGE)

pyproject.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,8 @@ skip_gitignore = true
1515
[tool.black]
1616
line-length = 119
1717
target-version = ["py310"]
18+
19+
[tool.pytest.ini_options]
20+
minversion = "6.0"
21+
required_plugins = "pytest-cov"
22+
testpaths = ["tests"]

pytest_reportportal/config.py

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
import warnings
1717
from os import getenv
18-
from typing import Any, List, Optional, Tuple, Union
18+
from typing import Any, Optional, Union
1919

2020
from _pytest.config import Config
2121
from reportportal_client import ClientType, OutputType
@@ -50,8 +50,8 @@ class AgentConfig:
5050
rp_bts_url: str
5151
rp_launch: str
5252
rp_launch_id: Optional[str]
53-
rp_launch_attributes: Optional[List[str]]
54-
rp_tests_attributes: Optional[List[str]]
53+
rp_launch_attributes: Optional[list[str]]
54+
rp_tests_attributes: Optional[list[str]]
5555
rp_launch_description: str
5656
rp_log_batch_size: int
5757
rp_log_batch_payload_limit: int
@@ -78,9 +78,12 @@ class AgentConfig:
7878
rp_launch_timeout: int
7979
rp_launch_uuid_print: bool
8080
rp_launch_uuid_print_output: Optional[OutputType]
81-
rp_http_timeout: Optional[Union[Tuple[float, float], float]]
81+
rp_http_timeout: Optional[Union[tuple[float, float], float]]
8282
rp_report_fixtures: bool
8383

84+
# Custom log levels and overrides
85+
rp_log_custom_levels: Optional[dict[int, str]]
86+
8487
def __init__(self, pytest_config: Config) -> None:
8588
"""Initialize required attributes."""
8689
self.rp_enabled = to_bool(getattr(pytest_config.option, "rp_enabled", True))
@@ -138,25 +141,8 @@ def __init__(self, pytest_config: Config) -> None:
138141
self.rp_project = self.find_option(pytest_config, "rp_project")
139142
self.rp_rerun_of = self.find_option(pytest_config, "rp_rerun_of")
140143

141-
rp_api_retries_str = self.find_option(pytest_config, "rp_api_retries")
142-
rp_api_retries = rp_api_retries_str and int(rp_api_retries_str)
143-
if rp_api_retries and rp_api_retries > 0:
144-
self.rp_api_retries = rp_api_retries
145-
else:
146-
rp_api_retries_str = self.find_option(pytest_config, "retries")
147-
rp_api_retries = rp_api_retries_str and int(rp_api_retries_str)
148-
if rp_api_retries and rp_api_retries > 0:
149-
self.rp_api_retries = rp_api_retries
150-
warnings.warn(
151-
"Parameter `retries` is deprecated since 5.1.9 "
152-
"and will be subject for removing in the next "
153-
"major version. Use `rp_api_retries` argument "
154-
"instead.",
155-
DeprecationWarning,
156-
2,
157-
)
158-
else:
159-
self.rp_api_retries = 0
144+
rp_api_retries_str = self.find_option(pytest_config, "rp_api_retries", "0")
145+
self.rp_api_retries = rp_api_retries_str and int(rp_api_retries_str)
160146

161147
# API key auth parameter
162148
self.rp_api_key = getenv("RP_API_KEY") or self.find_option(pytest_config, "rp_api_key")
@@ -194,6 +180,16 @@ def __init__(self, pytest_config: Config) -> None:
194180
self.rp_http_timeout = connect_timeout or read_timeout
195181
self.rp_report_fixtures = to_bool(self.find_option(pytest_config, "rp_report_fixtures", False))
196182

183+
# Custom log levels and overrides
184+
log_custom_levels = self.find_option(pytest_config, "rp_log_custom_levels")
185+
self.rp_log_custom_levels = None
186+
if log_custom_levels:
187+
levels = {}
188+
for custom_level in log_custom_levels:
189+
level, level_name = str(custom_level).split(":", maxsplit=1)
190+
levels[int(level)] = level_name
191+
self.rp_log_custom_levels = levels
192+
197193
# noinspection PyMethodMayBeStatic
198194
def find_option(self, pytest_config: Config, option_name: str, default: Any = None) -> Any:
199195
"""

pytest_reportportal/plugin.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import os.path
1818
import time
1919
from logging import Logger
20-
from typing import Any, Callable, Dict, Generator
20+
from typing import Any, Callable, Generator
2121

2222
import _pytest.logging
2323
import dill as pickle
@@ -254,6 +254,7 @@ def pytest_runtest_protocol(item: Item) -> Generator[None, Any, None]:
254254
filter_client_logs=True,
255255
endpoint=agent_config.rp_endpoint,
256256
ignored_record_names=("reportportal_client", "pytest_reportportal"),
257+
custom_levels=agent_config.rp_log_custom_levels,
257258
)
258259
log_format = agent_config.rp_log_format
259260
if log_format:
@@ -410,7 +411,7 @@ def pytest_bdd_after_step(
410411
scenario: Scenario,
411412
step: Step,
412413
step_func: Callable[..., Any],
413-
step_func_args: Dict[str, Any],
414+
step_func_args: dict[str, Any],
414415
) -> Generator[None, Any, None]:
415416
"""Report BDD step finish.
416417
@@ -439,7 +440,7 @@ def pytest_bdd_step_error(
439440
scenario: Scenario,
440441
step: Step,
441442
step_func: Callable[..., Any],
442-
step_func_args: Dict[str, Any],
443+
step_func_args: dict[str, Any],
443444
exception,
444445
) -> Generator[None, Any, None]:
445446
"""Report BDD step error.
@@ -600,6 +601,12 @@ def add_shared_option(name, help_str, default=None, action="store"):
600601
"rp_log_batch_payload_size",
601602
help="DEPRECATED: Maximum payload size in bytes of async batch log requests",
602603
)
604+
parser.addini(
605+
"rp_log_custom_levels",
606+
type="args",
607+
help="Custom log levels specified as 'int level:string'. E.G.: '35:ASSERTION'. Overrides existing level if int"
608+
" level matches.",
609+
)
603610
parser.addini("rp_ignore_attributes", type="args", help="Ignore specified pytest markers, i.e parametrize")
604611
parser.addini(
605612
"rp_is_skipped_an_issue", default=True, type="bool", help="Treat skipped tests as required investigation"
@@ -646,7 +653,6 @@ def add_shared_option(name, help_str, default=None, action="store"):
646653
"directory with certificates of trusted CAs.",
647654
)
648655
parser.addini("rp_issue_id_marks", type="bool", default=True, help="Add tag with issue id to the test")
649-
parser.addini("retries", default="0", help="Deprecated: use `rp_api_retries` instead")
650656
parser.addini("rp_api_retries", default="0", help="Amount of retries for performing REST calls to RP server")
651657
parser.addini(
652658
"rp_launch_timeout",

pytest_reportportal/rp_logging.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
import threading
1919
from contextlib import contextmanager
2020
from functools import wraps
21-
from typing import Any, Dict, List
21+
from typing import Any
2222

2323
from reportportal_client import RPLogger, current, set_current
2424
from reportportal_client.core.worker import APIWorker
@@ -114,7 +114,7 @@ def patching_logger_class():
114114

115115
def wrap_log(original_func):
116116
@wraps(original_func)
117-
def _log(self, *args: List[Any], **kwargs: Dict[str, Any]):
117+
def _log(self, *args: list[Any], **kwargs: dict[str, Any]):
118118
my_kwargs = kwargs.copy()
119119
attachment = my_kwargs.pop("attachment", None)
120120
if attachment is not None:

0 commit comments

Comments
 (0)