Skip to content

Commit

Permalink
Merge pull request #245 from reportportal/develop
Browse files Browse the repository at this point in the history
Release
  • Loading branch information
HardNorth authored Nov 29, 2024
2 parents c44cb2a + e60998e commit 8a23dc3
Show file tree
Hide file tree
Showing 10 changed files with 70 additions and 29 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.8'
python-version: '3.10'

- name: Install dependencies
run: python -m pip install --upgrade pip setuptools wheel
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [ '3.7', '3.8', '3.9', '3.10', '3.11', '3.12' ]
python-version: [ '3.7', '3.8', '3.9', '3.10', '3.11', '3.12', '3.13' ]
steps:
- name: Checkout repository
uses: actions/checkout@v4
Expand All @@ -54,7 +54,7 @@ jobs:
run: tox

- name: Upload coverage to Codecov
if: matrix.python-version == 3.8 && success()
if: matrix.python-version == 3.10 && success()
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
# Changelog

## [Unreleased]
### Added
- Official `Python 3.13` support, by @HardNorth
### Fixed
- Issue [#244](https://github.com/reportportal/client-Python/issues/244): Client crash on different error responses, by @HardNorth

## [5.5.9]
### Fixed
- Empty parameter Dict conversion, by @HardNorth

Expand Down
7 changes: 6 additions & 1 deletion reportportal_client/core/rp_requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
"""

import asyncio
import json as json_converter
import logging
from dataclasses import dataclass
from typing import Callable, Optional, Union, List, Tuple, Any, TypeVar
Expand All @@ -43,6 +42,12 @@
from reportportal_client.core.rp_responses import RPResponse, AsyncRPResponse
from reportportal_client.helpers import dict_to_payload, await_if_necessary

try:
# noinspection PyPackageRequirements
import simplejson as json_converter
except ImportError:
import json as json_converter

logger = logging.getLogger(__name__)
T = TypeVar("T")

Expand Down
12 changes: 6 additions & 6 deletions reportportal_client/core/rp_responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,9 @@
"""

import logging
from json import JSONDecodeError
from typing import Any, Optional, Generator, Mapping, Tuple, Union

from aiohttp import ClientResponse
from aiohttp import ClientResponse, ClientError
from requests import Response

# noinspection PyProtectedMember
Expand All @@ -42,8 +41,9 @@ def _iter_json_messages(json: Any) -> Generator[str, None, None]:


def _get_json_decode_error_message(response: Union[Response, ClientResponse]) -> str:
status = getattr(response, 'status', getattr(response, 'status_code'))
return f'Unable to decode JSON response, got {"passed" if response.ok else "failed"} ' \
status = getattr(response, 'status', getattr(response, 'status_code', None))
ok = getattr(response, 'ok', None)
return f'Unable to decode JSON response, got {"passed" if ok else "failed"} ' \
f'response with code "{status}" please check your endpoint configuration or API key'


Expand Down Expand Up @@ -88,7 +88,7 @@ def json(self) -> Any:
if self.__json is NOT_SET:
try:
self.__json = self._resp.json()
except (JSONDecodeError, TypeError) as exc:
except (ValueError, TypeError) as exc:
logger.error(_get_json_decode_error_message(self._resp), exc_info=exc)
self.__json = None
return self.__json
Expand Down Expand Up @@ -156,7 +156,7 @@ async def json(self) -> Any:
if self.__json is NOT_SET:
try:
self.__json = await self._resp.json()
except (JSONDecodeError, TypeError) as exc:
except (ValueError, TypeError, ClientError) as exc:
logger.error(_get_json_decode_error_message(self._resp), exc_info=exc)
self.__json = None
return self.__json
Expand Down
7 changes: 6 additions & 1 deletion reportportal_client/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@

import asyncio
import inspect
import json
import logging
import sys
import threading
Expand All @@ -27,6 +26,12 @@

from reportportal_client.core.rp_file import RPFile

try:
# noinspection PyPackageRequirements
import simplejson as json
except ImportError:
import json

logger: logging.Logger = logging.getLogger(__name__)
_T = TypeVar('_T')
ATTRIBUTE_LENGTH_LIMIT: int = 128
Expand Down
6 changes: 3 additions & 3 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
aenum
requests>=2.28.0
aiohttp>=3.8.3
certifi>=2023.7.22
requests>=2.31.0
aiohttp>=3.8.6
certifi>=2024.8.30
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from setuptools import setup, find_packages

__version__ = '5.5.9'
__version__ = '5.5.10'

TYPE_STUBS = ['*.pyi']

Expand Down Expand Up @@ -46,6 +46,7 @@ def read_file(fname):
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'Programming Language :: Python :: 3.13',
],
install_requires=read_file('requirements.txt').splitlines(),
)
46 changes: 34 additions & 12 deletions tests/core/test_rp_responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,37 +20,59 @@
from reportportal_client.core.rp_responses import RPResponse, AsyncRPResponse


class JSONDecodeError(ValueError):
pass


def json_error():
raise json.JSONDecodeError('Expecting value: line 1 column 1 (char 0)', '<html />', 0)


def custom_error():
raise JSONDecodeError('Expecting value: line 1 column 1 (char 0)')


@mock.patch('reportportal_client.core.rp_responses.logging.Logger.error')
def test_json_decode_error(error_log):
@pytest.mark.parametrize('ok, response_code, error_function, expected_message', [
(False, 404, json_error, 'Unable to decode JSON response, got failed response with code "404" please check your '
'endpoint configuration or API key'),
(True, 200, json_error, 'Unable to decode JSON response, got passed response with code "200" please check your '
'endpoint configuration or API key'),
(True, 200, custom_error, 'Unable to decode JSON response, got passed response with code "200" please check your '
'endpoint configuration or API key'),
])
def test_custom_decode_error(error_log, ok, response_code, error_function, expected_message):
response = mock.Mock()
response.ok = False
response.ok = ok
del response.status
response.status_code = 404
response.json.side_effect = json_error
response.status_code = response_code
response.json.side_effect = error_function

rp_response = RPResponse(response)
assert rp_response.json is None
error_log.assert_called_once()
assert error_log.call_args_list[0][0][0] == ('Unable to decode JSON response, got failed response with code "404" '
'please check your endpoint configuration or API key')
assert error_log.call_args_list[0][0][0] == expected_message


@pytest.mark.skipif(sys.version_info < (3, 8),
reason='the test requires AsyncMock which was introduced in Python 3.8')
@mock.patch('reportportal_client.core.rp_responses.logging.Logger.error')
@pytest.mark.asyncio
async def test_json_decode_error_async(error_log):
@pytest.mark.parametrize('ok, response_code, error_function, expected_message', [
(False, 404, json_error, 'Unable to decode JSON response, got failed response with code "404" please check your '
'endpoint configuration or API key'),
(True, 200, json_error, 'Unable to decode JSON response, got passed response with code "200" please check your '
'endpoint configuration or API key'),
(True, 200, custom_error, 'Unable to decode JSON response, got passed response with code "200" please check your '
'endpoint configuration or API key'),
])
async def test_json_decode_error_async(error_log, ok, response_code, error_function, expected_message):
response = mock.AsyncMock()
response.ok = False
response.status = 403
response.json.side_effect = json_error
response.ok = ok
response.status = response_code
response.json.side_effect = error_function

rp_response = AsyncRPResponse(response)
assert await rp_response.json is None
error_log.assert_called_once()
assert error_log.call_args_list[0][0][0] == ('Unable to decode JSON response, got failed response with code "403" '
'please check your endpoint configuration or API key')
assert error_log.call_args_list[0][0][0] == expected_message
6 changes: 4 additions & 2 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ envlist =
py310
py311
py312
py313

[testenv]
deps =
Expand All @@ -27,8 +28,9 @@ commands = pre-commit run --all-files --show-diff-on-failure
[gh-actions]
python =
3.7: py37
3.8: pep, py38
3.8: py38
3.9: py39
3.10: py310
3.10: pep, py310
3.11: py311
3.12: py312
3.13: py313

0 comments on commit 8a23dc3

Please sign in to comment.