Skip to content

Commit dd3a8c1

Browse files
authored
Merge pull request #229 from reportportal/develop
Release
2 parents 6b04ee9 + a4e121a commit dd3a8c1

File tree

16 files changed

+140
-13
lines changed

16 files changed

+140
-13
lines changed

.github/workflows/release.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@ jobs:
3636
runs-on: ubuntu-latest
3737
steps:
3838
- name: Checkout repository
39-
uses: actions/checkout@v3
39+
uses: actions/checkout@v4
4040

4141
- name: Set up Python
42-
uses: actions/setup-python@v4
42+
uses: actions/setup-python@v5
4343
with:
4444
python-version: '3.8'
4545

@@ -76,7 +76,7 @@ jobs:
7676
git push --tags
7777
7878
- name: Checkout develop branch
79-
uses: actions/checkout@v3
79+
uses: actions/checkout@v4
8080
with:
8181
ref: 'develop'
8282
fetch-depth: 0

.github/workflows/tests.yml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,10 @@ jobs:
3737
python-version: [ '3.7', '3.8', '3.9', '3.10', '3.11' ]
3838
steps:
3939
- name: Checkout repository
40-
uses: actions/checkout@v3
40+
uses: actions/checkout@v4
4141

4242
- name: Set up Python ${{ matrix.python-version }}
43-
uses: actions/setup-python@v4
43+
uses: actions/setup-python@v5
4444
with:
4545
python-version: ${{ matrix.python-version }}
4646

@@ -55,8 +55,9 @@ jobs:
5555

5656
- name: Upload coverage to Codecov
5757
if: matrix.python-version == 3.8 && success()
58-
uses: codecov/codecov-action@v3
58+
uses: codecov/codecov-action@v4
5959
with:
60+
token: ${{ secrets.CODECOV_TOKEN }}
6061
files: coverage.xml
6162
flags: unittests
6263
name: codecov-client-reportportal

CHANGELOG.md

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

33
## [Unreleased]
44
### Added
5+
- `is_binary` method in `helpers` module, by @HardNorth
6+
- `guess_content_type_from_bytes` method in `helpers` module, by @HardNorth
7+
8+
## [5.5.4]
9+
### Added
510
- Issue [#225](https://github.com/reportportal/client-Python/issues/225): JSON decoding error logging, by @HardNorth
611
### Fixed
712
- Issue [#226](https://github.com/reportportal/client-Python/issues/226): Logging batch flush on client close, by @HardNorth

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
[![Python versions](https://img.shields.io/pypi/pyversions/reportportal-client.svg)](https://pypi.org/project/reportportal-client)
55
[![Build Status](https://github.com/reportportal/client-Python/actions/workflows/tests.yml/badge.svg)](https://github.com/reportportal/client-Python/actions/workflows/tests.yml)
66
[![codecov.io](https://codecov.io/gh/reportportal/client-Python/branch/develop/graph/badge.svg)](https://codecov.io/gh/reportportal/client-Python)
7-
[![Join Slack chat!](https://slack.epmrpp.reportportal.io/badge.svg)](https://slack.epmrpp.reportportal.io/)
7+
[![Join Slack chat!](https://img.shields.io/badge/slack-join-brightgreen.svg)](https://slack.epmrpp.reportportal.io/)
88
[![stackoverflow](https://img.shields.io/badge/reportportal-stackoverflow-orange.svg?style=flat)](http://stackoverflow.com/questions/tagged/reportportal)
99
[![Build with Love](https://img.shields.io/badge/build%20with-❤%EF%B8%8F%E2%80%8D-lightgrey.svg)](http://reportportal.io?style=flat)
1010

reportportal_client/_internal/static/abstract.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,16 +40,14 @@ class Implementation(Interface):
4040
def __call__(cls, *args, **kwargs):
4141
"""Disable instantiation for the interface classes."""
4242
if cls.__name__ in AbstractBaseClass._abc_registry:
43-
raise TypeError("No instantiation allowed for Interface-Class"
44-
" '{}'. Please inherit.".format(cls.__name__))
43+
raise TypeError("No instantiation allowed for Interface-Class '{}'. Please inherit.".format(cls.__name__))
4544

4645
result = super(AbstractBaseClass, cls).__call__(*args, **kwargs)
4746
return result
4847

4948
def __new__(mcs, name, bases, namespace):
5049
"""Register instance of the implementation class."""
51-
class_ = super(AbstractBaseClass, mcs).__new__(mcs, name,
52-
bases, namespace)
50+
class_ = super(AbstractBaseClass, mcs).__new__(mcs, name, bases, namespace)
5351
if namespace.get("__metaclass__") is AbstractBaseClass:
5452
mcs._abc_registry.append(name)
5553
return class_

reportportal_client/helpers.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,3 +391,78 @@ async def await_if_necessary(obj: Optional[Any]) -> Optional[Any]:
391391
elif asyncio.iscoroutinefunction(obj):
392392
return await obj()
393393
return obj
394+
395+
396+
def is_binary(iterable: Union[bytes, bytearray, str]) -> bool:
397+
"""Check if given iterable is binary.
398+
399+
:param iterable: iterable to check
400+
:return: True if iterable contains binary bytes, False otherwise
401+
"""
402+
if isinstance(iterable, str):
403+
byte_iterable = iterable.encode('utf-8')
404+
else:
405+
byte_iterable = iterable
406+
407+
if 0x00 in byte_iterable:
408+
return True
409+
return False
410+
411+
412+
def guess_content_type_from_bytes(data: Union[bytes, bytearray, List[int]]) -> str:
413+
"""Guess content type from bytes.
414+
415+
:param data: bytes or bytearray
416+
:return: content type
417+
"""
418+
my_data = data
419+
if isinstance(data, list):
420+
my_data = bytes(my_data)
421+
422+
if len(my_data) >= 128:
423+
my_data = my_data[:128]
424+
425+
if not is_binary(my_data):
426+
return 'text/plain'
427+
428+
# images
429+
if my_data.startswith(b'\xff\xd8\xff'):
430+
return 'image/jpeg'
431+
if my_data.startswith(b'\x89PNG\r\n\x1a\n'):
432+
return 'image/png'
433+
if my_data.startswith(b'GIF8'):
434+
return 'image/gif'
435+
if my_data.startswith(b'BM'):
436+
return 'image/bmp'
437+
if my_data.startswith(b'\x00\x00\x01\x00'):
438+
return 'image/vnd.microsoft.icon'
439+
if my_data.startswith(b'RIFF') and b'WEBP' in my_data:
440+
return 'image/webp'
441+
442+
# audio
443+
if my_data.startswith(b'ID3'):
444+
return 'audio/mpeg'
445+
if my_data.startswith(b'RIFF') and b'WAVE' in my_data:
446+
return 'audio/wav'
447+
448+
# video
449+
if my_data.startswith(b'\x00\x00\x01\xba'):
450+
return 'video/mpeg'
451+
if my_data.startswith(b'RIFF') and b'AVI LIST' in my_data:
452+
return 'video/avi'
453+
if my_data.startswith(b'\x1aE\xdf\xa3'):
454+
return 'video/webm'
455+
456+
# archives
457+
if my_data.startswith(b'PK\x03\x04'):
458+
if my_data.startswith(b'PK\x03\x04\x14\x00\x08'):
459+
return 'application/java-archive'
460+
return 'application/zip'
461+
if my_data.startswith(b'PK\x05\x06'):
462+
return 'application/zip'
463+
464+
# office
465+
if my_data.startswith(b'%PDF'):
466+
return 'application/pdf'
467+
468+
return 'application/octet-stream'

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from setuptools import setup, find_packages
66

7-
__version__ = '5.5.4'
7+
__version__ = '5.5.5'
88

99
TYPE_STUBS = ['*.pyi']
1010

test_res/files/demo.zip

126 Bytes
Binary file not shown.

test_res/files/image.png

19.2 KB
Loading

test_res/files/simple.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
HTTP/1.1 407 Proxy Authentication Required
2+
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
3+
Expires: 0
4+
Pragma: no-cache
5+
X-Content-Type-Options: nosniff
6+
X-Frame-Options: DENY
7+
X-Xss-Protection: 1; mode=block
8+
Content-Length: 0

0 commit comments

Comments
 (0)