Skip to content

Commit

Permalink
Merge branch '87-support-pythons-version-gte-3-9'
Browse files Browse the repository at this point in the history
Closes: #87
  • Loading branch information
c0r0n3r committed Jan 5, 2025
2 parents 4555001 + feac42f commit 9389580
Show file tree
Hide file tree
Showing 47 changed files with 318 additions and 432 deletions.
56 changes: 16 additions & 40 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,48 +14,19 @@ variables:
PYTHONPATH: "submodules/cryptodatahub"

pylint:
image: python:3.11-slim
image: python:3.12-slim
stage: earlytest
script: tox -e pylint

pep8:
image: python:3.12-slim
stage: earlytest
script: tox -e pep8

python2:
image: python:2.7-slim
stage: earlytest
script: tox -e py27

python3:
image: python:3.11-slim
image: python:3.12-slim
stage: earlytest
script: tox -e py311

python34:
image: python:3.4-slim
stage: fulltest
script: tox -e py34

python35:
image: python:3.5-slim
stage: fulltest
script: tox -e py35

python36:
image: python:3.6-slim
stage: fulltest
script: tox -e py36

python37:
image: python:3.7-slim
stage: fulltest
script: tox -e py37

python38:
image: python:3.8-slim
stage: fulltest
script: tox -e py38
script: tox -e py312

python39:
image: python:3.9-slim
Expand All @@ -67,23 +38,28 @@ python310:
stage: fulltest
script: tox -e py310

pythonrc:
image: python:3.12-rc-slim
python311:
image: python:3.11-slim
stage: fulltest
script: tox -e py312
script: tox -e py311

python313:
image: python:3.13-slim
stage: fulltest
script: tox -e py313

pypy:
image: pypy:2-slim
pythonrc:
image: python:3.14-rc-slim
stage: fulltest
script: tox -e pypy
script: tox -e py314

pypy3:
image: pypy:3-slim
stage: fulltest
script: tox -e pypy3

coveralls:
image: python:3.11-slim
image: python:3.12-slim
variables:
CI_NAME: gitlab
CI_BUILD_NUMBER: "${CI_JOB_ID}"
Expand Down
2 changes: 1 addition & 1 deletion .pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ max-line-length = 120

[MESSAGES CONTROL]

disable = missing-docstring,too-few-public-methods,too-many-ancestors,useless-object-inheritance,duplicate-code,super-with-arguments,consider-using-f-string
disable = missing-docstring,too-few-public-methods,too-many-ancestors,duplicate-code
4 changes: 2 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ Support
Python implementation
=====================

- CPython (2.7, 3.3+)
- PyPy (2.7, 3.5+)
- CPython (3.9+)
- PyPy (3.9+)

Operating systems
=================
Expand Down
70 changes: 29 additions & 41 deletions cryptoparser/common/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
from collections import OrderedDict

import attr
import six
import urllib3

from cryptodatahub.common.exception import InvalidValue
Expand Down Expand Up @@ -49,17 +48,17 @@ def _default(
json.JSONEncoder.default = _default


class SerializableTextEncoder(object):
class SerializableTextEncoder():
def __call__(self, obj, level):
if isinstance(obj, six.string_types):
if isinstance(obj, str):
string_result = obj
else:
string_result = str(obj)

return False, string_result


class Serializable(object): # pylint: disable=too-few-public-methods
class Serializable(): # pylint: disable=too-few-public-methods
_MARKDOWN_RESULT_STRING_CLASSES = (
ipaddress.IPv4Network,
ipaddress.IPv6Network,
Expand Down Expand Up @@ -117,7 +116,7 @@ def _json_result(obj):
result = obj.name
else:
result = {obj.name: obj.value}
elif isinstance(obj, six.string_types + six.integer_types + (float, bool, )) or obj is None:
elif isinstance(obj, (str, int, float, bool, )) or obj is None:
result = obj
elif isinstance(obj, (bytes, bytearray)):
result = bytes_to_hex_string(obj, separator=':', lowercase=False)
Expand Down Expand Up @@ -158,7 +157,7 @@ def _markdown_human_readable_names(cls, obj, dict_value):
name_dict = {}
fields_dict = attr.fields_dict(type(obj)) if attr.has(type(obj)) else {}
for name in dict_value:
if isinstance(name, six.string_types):
if isinstance(name, str):
if name in fields_dict and 'human_readable_name' in fields_dict[name].metadata:
human_readable_name = fields_dict[name].metadata['human_readable_name']
else:
Expand Down Expand Up @@ -189,12 +188,12 @@ def _markdown_result_complex(cls, obj, level=0):
result = ''
name_dict = cls._markdown_human_readable_names(obj, dict_value)
for name, value in dict_value.items():
result += '{indent}* {name}'.format(indent=indent, name=name_dict[name])
result += f'{indent}* {name_dict[name]}'
multiline, markdnow_result = cls._markdown_result(value, level + 1)
if multiline:
result += ':\n{result}'.format(result=markdnow_result)
result += f':\n{markdnow_result}'
else:
result += ': {result}\n'.format(result=markdnow_result)
result += f': {markdnow_result}\n'

if not result:
return False, '-'
Expand All @@ -211,19 +210,15 @@ def _markdown_result_list(cls, obj, level=0):
result = ''
for index, item in enumerate(obj):
multiline, markdnow_result = cls._markdown_result(item, level + 1)
result += '{indent}{index}.{separator}{value}{newline}'.format(
indent=indent,
index=index + 1,
separator='\n' if multiline else ' ',
value=markdnow_result,
newline='' if multiline else '\n',
)
separator = '\n' if multiline else ' '
newline = '' if multiline else '\n'
result += f'{indent}{index + 1}.{separator}{markdnow_result}{newline}'

return True, result

@staticmethod
def _markdown_is_directly_printable(obj):
return not isinstance(obj, enum.Enum) and isinstance(obj, six.string_types + six.integer_types + (float, ))
return not isinstance(obj, enum.Enum) and isinstance(obj, (str, int, float, ))

@classmethod
def _markdown_result(cls, obj, level=0): # pylint: disable=too-many-branches,too-many-return-statements
Expand Down Expand Up @@ -371,7 +366,7 @@ def _parse(cls, parsable):


@attr.s
class VectorParamBase(object): # pylint: disable=too-few-public-methods
class VectorParamBase(): # pylint: disable=too-few-public-methods
min_byte_num = attr.ib(validator=attr.validators.instance_of(int))
max_byte_num = attr.ib(validator=attr.validators.instance_of(int))
item_num_size = attr.ib(init=False, validator=attr.validators.instance_of(int))
Expand All @@ -398,16 +393,16 @@ def get_item_size(self, item):
@attr.s(init=False)
class OpaqueParam(VectorParamNumeric): # pylint: disable=too-few-public-methods
def __init__(self, min_byte_num, max_byte_num):
super(OpaqueParam, self).__init__(min_byte_num, max_byte_num, 1)
super().__init__(min_byte_num, max_byte_num, 1)

def get_item_size(self, item):
return 1


@attr.s
class VectorParamString(VectorParamBase): # pylint: disable=too-few-public-methods
separator = attr.ib(validator=attr.validators.instance_of(six.string_types), default=',')
encoding = attr.ib(validator=attr.validators.instance_of(six.string_types), default='ascii')
separator = attr.ib(validator=attr.validators.instance_of(str), default=',')
encoding = attr.ib(validator=attr.validators.instance_of(str), default='ascii')
item_class = attr.ib(validator=attr.validators.instance_of((type, types.FunctionType)), default=str)
fallback_class = attr.ib(
default=None,
Expand All @@ -419,7 +414,7 @@ def get_item_size(self, item):
return len(item.compose())
if isinstance(item, CryptoDataEnumCodedBase):
return item.value.get_code_size()
if isinstance(item, six.string_types):
if isinstance(item, str):
return len(item)

raise NotImplementedError(type(item))
Expand Down Expand Up @@ -463,10 +458,7 @@ class ArrayBase(ParsableBase, MutableSequence, Serializable):
param = attr.ib(init=False, default=None)

def __attrs_post_init__(self):
if isinstance(self._items, six.binary_type):
items = six.iterbytes(bytes(self._items))
else:
items = self._items
items = self._items

self.param = self.get_param()
self._items = []
Expand Down Expand Up @@ -856,9 +848,9 @@ def _parse(cls, parsable):
enum_items.sort(key=lambda color: len(color.value.code), reverse=True)

try:
code = six.ensure_text(bytes(parsable), 'ascii')
code = bytes(parsable).decode('ascii')
except UnicodeDecodeError as e:
six.raise_from(InvalidValue(parsable, cls), e)
raise InvalidValue(parsable, cls) from e

for enum_item in enum_items:
if cls._code_eq(enum_item.value.code, code[:len(enum_item.value.code)]):
Expand All @@ -867,7 +859,7 @@ def _parse(cls, parsable):
raise InvalidValue(parsable, cls, 'code')

def compose(self):
return six.ensure_binary(self._asdict(), 'ascii')
return self._asdict().encode('ascii')

def _asdict(self):
return getattr(self, 'value').code
Expand All @@ -885,8 +877,7 @@ def _code_eq(cls, item_code, parsed_code):
return item_code.lower() == parsed_code.lower()


@six.add_metaclass(abc.ABCMeta)
class ProtocolVersionBase(Serializable, ParsableBase):
class ProtocolVersionBase(Serializable, ParsableBase, metaclass=abc.ABCMeta):
@classmethod
@abc.abstractmethod
def _parse(cls, parsable):
Expand Down Expand Up @@ -947,14 +938,14 @@ def compose(self):

@property
def identifier(self):
return '{}_{}'.format(self.major, self.minor)
return f'{self.major}_{self.minor}'

def __str__(self):
return '{}.{}'.format(self.major, self.minor)
return f'{self.major}.{self.minor}'


@attr.s
class ListParamParsable(object): # pylint: disable=too-few-public-methods
class ListParamParsable(): # pylint: disable=too-few-public-methods
item_class = attr.ib(validator=attr.validators.instance_of(type))
fallback_class = attr.ib(validator=attr.validators.optional(attr.validators.instance_of(type)))
separator_class = attr.ib(attr.validators.instance_of(ParsableBase))
Expand Down Expand Up @@ -1003,10 +994,7 @@ class OpaqueEnumParsable(Vector):
@classmethod
def _parse(cls, parsable):
opaque, parsed_length = super(OpaqueEnumParsable, cls)._parse(parsable)
code = six.ensure_text(
b''.join([six.int2byte(opaque_item) for opaque_item in opaque]),
cls.get_encoding()
)
code = b''.join([bytes((opaque_item,)) for opaque_item in opaque]).decode(cls.get_encoding())

try:
parsed_object = next(iter([
Expand All @@ -1015,7 +1003,7 @@ def _parse(cls, parsable):
if enum_item.value.code == code
]))
except StopIteration as e:
six.raise_from(InvalidValue(code, cls), e)
raise InvalidValue(code, cls) from e

return parsed_object, parsed_length

Expand All @@ -1035,7 +1023,7 @@ def __repr__(self):

def compose(self):
composer = ComposerBinary()
value = six.ensure_binary(self.value.code, self.get_encoding()) # pylint: disable=no-member
value = self.value.code.encode(self.get_encoding()) # pylint: disable=no-member

composer.compose_bytes(value, 1)

Expand All @@ -1048,7 +1036,7 @@ def get_encoding(cls):

@attr.s
class NumericRangeParsableBase(ParsableBase, Serializable):
value = attr.ib(validator=attr.validators.instance_of(six.integer_types))
value = attr.ib(validator=attr.validators.instance_of(int))

@value.validator
def _validator_variant(self, _, value):
Expand Down
4 changes: 2 additions & 2 deletions cryptoparser/common/exception.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ class InvalidDataLength(Exception):
@attr.s
class NotEnoughData(InvalidDataLength):
def __str__(self):
return 'not enough data received from target; missing_byte_count="{}"'.format(self.bytes_needed)
return f'not enough data received from target; missing_byte_count="{self.bytes_needed}"'


@attr.s
class TooMuchData(InvalidDataLength):
def __str__(self):
return 'too much data received from target; rest_byte_count="{}"'.format(self.bytes_needed)
return f'too much data received from target; rest_byte_count="{self.bytes_needed}"'


class InvalidType(Exception):
Expand Down
Loading

0 comments on commit 9389580

Please sign in to comment.