From 510537c8a9a61fd81ce1ec7e4eaf5efe24a593ce Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Sat, 15 Aug 2026 14:13:09 +0000 Subject: [PATCH] ruff fixes --- mmgen/contrib/keccak.py | 4 ++-- mmgen/devtools.py | 2 +- mmgen/proto/eth/rlp/codec.py | 6 ++--- mmgen/proto/eth/rlp/exceptions.py | 16 ++++++------- mmgen/proto/eth/rlp/sedes/big_endian_int.py | 2 +- mmgen/proto/eth/rlp/sedes/binary.py | 2 +- mmgen/proto/eth/rlp/sedes/boolean.py | 2 +- mmgen/proto/eth/rlp/sedes/lists.py | 2 +- mmgen/proto/eth/rlp/sedes/serializable.py | 26 ++++++++++----------- mmgen/tool/file.py | 7 ++++-- mmgen/tool/rpc.py | 4 ++-- mmgen/xmrwallet/__init__.py | 2 +- pyproject.toml | 13 +---------- test/modtest_d/testdep.py | 2 +- 14 files changed, 41 insertions(+), 49 deletions(-) diff --git a/mmgen/contrib/keccak.py b/mmgen/contrib/keccak.py index 95ebbaba..6e091043 100755 --- a/mmgen/contrib/keccak.py +++ b/mmgen/contrib/keccak.py @@ -6,7 +6,7 @@ # This is the old, pre-SHA3 version of Keccak used by Ethereum, which is not supported # by hashlib.sha3 -from math import log +from math import log2 from operator import xor from copy import deepcopy from functools import reduce @@ -98,7 +98,7 @@ def keccak_f(state): # iota A[0][0] ^= RC - l = int(log(state.lanew, 2)) + l = int(log2(state.lanew)) nr = 12 + 2 * l for ir in range(nr): diff --git a/mmgen/devtools.py b/mmgen/devtools.py index f7a32ed7..260cc212 100755 --- a/mmgen/devtools.py +++ b/mmgen/devtools.py @@ -57,7 +57,7 @@ def print_stack_trace(message=None, fh_list=[], sep='\n ', trim=4): res = get_stack_trace(message, ('\n' if fh_list else ''), sep, trim) if not fh_list: import os - fh_list.append(open(f'devtools.trace.{os.getpid()}', 'w')) + fh_list.append(open(f'devtools.trace.{os.getpid()}', 'w')) # noqa: SIM115 sys.stderr.write(res) fh_list[0].write(res) fh_list[0].flush() diff --git a/mmgen/proto/eth/rlp/codec.py b/mmgen/proto/eth/rlp/codec.py index 05253fef..708d6c6f 100644 --- a/mmgen/proto/eth/rlp/codec.py +++ b/mmgen/proto/eth/rlp/codec.py @@ -74,7 +74,7 @@ def encode_raw(item): payload = b''.join(encode_raw(x) for x in item) prefix_offset = 192 # list else: - msg = 'Cannot encode object of type {0}'.format(type(item).__name__) + msg = 'Cannot encode object of type {}'.format(type(item).__name__) raise EncodingError(msg, item) try: @@ -129,7 +129,7 @@ def consume_length_prefix(rlp, start): if rlp[start + 1:start + 2] == b'\x00': raise DecodingError('Length starts with zero bytes', rlp) len_prefix = rlp[start + 1:start + 1 + ll] - l = big_endian_to_int(len_prefix) # noqa: E741 + l = big_endian_to_int(len_prefix) if l < 56: raise DecodingError('Long string prefix used for short string', rlp) return (rlp[start:start + 1] + len_prefix, bytes, l, start + 1 + ll) @@ -140,7 +140,7 @@ def consume_length_prefix(rlp, start): if rlp[start + 1:start + 2] == b'\x00': raise DecodingError('Length starts with zero bytes', rlp) len_prefix = rlp[start + 1:start + 1 + ll] - l = big_endian_to_int(len_prefix) # noqa: E741 + l = big_endian_to_int(len_prefix) if l < 56: raise DecodingError('Long list prefix used for short list', rlp) return (rlp[start:start + 1] + len_prefix, list, l, start + 1 + ll) diff --git a/mmgen/proto/eth/rlp/exceptions.py b/mmgen/proto/eth/rlp/exceptions.py index 8efe40e1..bdb23e34 100644 --- a/mmgen/proto/eth/rlp/exceptions.py +++ b/mmgen/proto/eth/rlp/exceptions.py @@ -9,7 +9,7 @@ class EncodingError(RLPException): """ def __init__(self, message, obj): - super(EncodingError, self).__init__(message) + super().__init__(message) self.obj = obj @@ -20,7 +20,7 @@ class DecodingError(RLPException): """ def __init__(self, message, rlp): - super(DecodingError, self).__init__(message) + super().__init__(message) self.rlp = rlp @@ -31,7 +31,7 @@ class SerializationError(RLPException): """ def __init__(self, message, obj): - super(SerializationError, self).__init__(message) + super().__init__(message) self.obj = obj @@ -50,7 +50,7 @@ class ListSerializationError(SerializationError): assert element_exception is not None message = ('Serialization failed because of element at index {} ' '("{}")'.format(index, str(element_exception))) - super(ListSerializationError, self).__init__(message, obj) + super().__init__(message, obj) self.index = index self.element_exception = element_exception @@ -79,7 +79,7 @@ class ObjectSerializationError(SerializationError): '("{}")'.format(field, str(list_exception.element_exception))) else: field = None - super(ObjectSerializationError, self).__init__(message, obj) + super().__init__(message, obj) self.field = field self.list_exception = list_exception @@ -91,7 +91,7 @@ class DeserializationError(RLPException): """ def __init__(self, message, serial): - super(DeserializationError, self).__init__(message) + super().__init__(message) self.serial = serial @@ -110,7 +110,7 @@ class ListDeserializationError(DeserializationError): assert element_exception is not None message = ('Deserialization failed because of element at index {} ' '("{}")'.format(index, str(element_exception))) - super(ListDeserializationError, self).__init__(message, serial) + super().__init__(message, serial) self.index = index self.element_exception = element_exception @@ -137,7 +137,7 @@ class ObjectDeserializationError(DeserializationError): field = sedes._meta.field_names[list_exception.index] message = ('Deserialization failed because of field {} ' '("{}")'.format(field, str(list_exception.element_exception))) - super(ObjectDeserializationError, self).__init__(message, serial) + super().__init__(message, serial) self.sedes = sedes self.list_exception = list_exception self.field = field diff --git a/mmgen/proto/eth/rlp/sedes/big_endian_int.py b/mmgen/proto/eth/rlp/sedes/big_endian_int.py index 0afadd04..74c55847 100644 --- a/mmgen/proto/eth/rlp/sedes/big_endian_int.py +++ b/mmgen/proto/eth/rlp/sedes/big_endian_int.py @@ -2,7 +2,7 @@ from ...pyethereum.utils import int_to_big_endian,big_endian_to_int from ..exceptions import DeserializationError,SerializationError -class BigEndianInt(object): +class BigEndianInt: """A sedes for big endian integers. :param l: the size of the serialized representation in bytes or `None` to diff --git a/mmgen/proto/eth/rlp/sedes/binary.py b/mmgen/proto/eth/rlp/sedes/binary.py index 7b6df453..1389a78c 100644 --- a/mmgen/proto/eth/rlp/sedes/binary.py +++ b/mmgen/proto/eth/rlp/sedes/binary.py @@ -2,7 +2,7 @@ from ..exceptions import SerializationError,DeserializationError from ..atomic import Atomic -class Binary(object): +class Binary: """A sedes object for binary data of certain length. :param min_length: the minimal length in bytes or `None` for no lower limit diff --git a/mmgen/proto/eth/rlp/sedes/boolean.py b/mmgen/proto/eth/rlp/sedes/boolean.py index 2fef17a7..2f22b1bd 100644 --- a/mmgen/proto/eth/rlp/sedes/boolean.py +++ b/mmgen/proto/eth/rlp/sedes/boolean.py @@ -13,7 +13,7 @@ class Boolean: elif obj is True: return b'\x01' else: - raise Exception("Invariant: no other options for boolean values") + raise ValueError("Invariant: no other options for boolean values") def deserialize(self, serial): if serial == b'': diff --git a/mmgen/proto/eth/rlp/sedes/lists.py b/mmgen/proto/eth/rlp/sedes/lists.py index f37ca1d8..e7e23991 100644 --- a/mmgen/proto/eth/rlp/sedes/lists.py +++ b/mmgen/proto/eth/rlp/sedes/lists.py @@ -43,7 +43,7 @@ class List(list): """ def __init__(self, elements=None, strict=True): - super(List, self).__init__() + super().__init__() self.strict = strict if elements: diff --git a/mmgen/proto/eth/rlp/sedes/serializable.py b/mmgen/proto/eth/rlp/sedes/serializable.py index 5e9b6f91..ab425080 100644 --- a/mmgen/proto/eth/rlp/sedes/serializable.py +++ b/mmgen/proto/eth/rlp/sedes/serializable.py @@ -37,22 +37,22 @@ def _get_duplicates(values): def validate_args_and_kwargs(args, kwargs, arg_names, allow_missing=False): duplicate_arg_names = _get_duplicates(arg_names) if duplicate_arg_names: - raise TypeError("Duplicate argument names: {0}".format(sorted(duplicate_arg_names))) + raise TypeError("Duplicate argument names: {}".format(sorted(duplicate_arg_names))) needed_kwargs = arg_names[len(args):] used_kwargs = set(arg_names[:len(args)]) duplicate_kwargs = used_kwargs.intersection(kwargs.keys()) if duplicate_kwargs: - raise TypeError("Duplicate kwargs: {0}".format(sorted(duplicate_kwargs))) + raise TypeError("Duplicate kwargs: {}".format(sorted(duplicate_kwargs))) unknown_kwargs = set(kwargs.keys()).difference(arg_names) if unknown_kwargs: - raise TypeError("Unknown kwargs: {0}".format(sorted(unknown_kwargs))) + raise TypeError("Unknown kwargs: {}".format(sorted(unknown_kwargs))) missing_kwargs = set(needed_kwargs).difference(kwargs.keys()) if not allow_missing and missing_kwargs: - raise TypeError("Missing kwargs: {0}".format(sorted(missing_kwargs))) + raise TypeError("Missing kwargs: {}".format(sorted(missing_kwargs))) @to_tuple @@ -175,7 +175,7 @@ def Changeset(obj, changes): in obj._meta.field_names } cls = type( - "{0}Changeset".format(obj.__class__.__name__), + "{}Changeset".format(obj.__class__.__name__), (BaseChangeset,), namespace, ) @@ -191,7 +191,7 @@ class BaseSerializable(collections.abc.Sequence): if len(field_values) != len(self._meta.field_names): raise TypeError( - 'Argument count mismatch. expected {0} - got {1} - missing {2}'.format( + 'Argument count mismatch. expected {} - got {} - missing {}'.format( len(self._meta.field_names), len(field_values), ','.join(self._meta.field_names[len(field_values):]), @@ -220,7 +220,7 @@ class BaseSerializable(collections.abc.Sequence): elif isinstance(idx, str): return getattr(self, idx) else: - raise IndexError("Unsupported type for __getitem__: {0}".format(type(idx))) + raise IndexError("Unsupported type for __getitem__: {}".format(type(idx))) def __len__(self): return len(self._meta.fields) @@ -333,7 +333,7 @@ IDENTIFIER_REGEX = re.compile(r"^[^\d\W]\w*\Z", re.UNICODE) def _is_valid_identifier(value): - # Source: https://stackoverflow.com/questions/5474008/regular-expression-to-confirm-whether-a-string-is-a-valid-identifier-in-python # noqa: E501 + # Source: https://stackoverflow.com/questions/5474008/regular-expression-to-confirm-whether-a-string-is-a-valid-identifier-in-python if not isinstance(value, str): return False return bool(IDENTIFIER_REGEX.match(value)) @@ -349,7 +349,7 @@ def _get_class_namespace(cls): class SerializableBase(abc.ABCMeta): def __new__(cls, name, bases, attrs): - super_new = super(SerializableBase, cls).__new__ + super_new = super().__new__ serializable_bases = tuple(b for b in bases if isinstance(b, SerializableBase)) has_multiple_serializable_parents = len(serializable_bases) > 1 @@ -393,7 +393,7 @@ class SerializableBase(abc.ABCMeta): raise TypeError( "The following fields are duplicated in the `fields` " "declaration: " - "{0}".format(",".join(sorted(duplicate_field_names))) + "{}".format(",".join(sorted(duplicate_field_names))) ) # check that field names are valid identifiers @@ -405,8 +405,8 @@ class SerializableBase(abc.ABCMeta): } if invalid_field_names: raise TypeError( - "The following field names are not valid python identifiers: {0}".format( - ",".join("`{0}`".format(item) for item in sorted(invalid_field_names)) + "The following field names are not valid python identifiers: {}".format( + ",".join("`{}`".format(item) for item in sorted(invalid_field_names)) ) ) @@ -425,7 +425,7 @@ class SerializableBase(abc.ABCMeta): "Subclasses of `Serializable` **must** contain a full superset " "of the fields defined in their parent classes. The following " "fields are missing: " - "{0}".format(",".join(sorted(missing_fields))) + "{}".format(",".join(sorted(missing_fields))) ) # the actual field values are stored in separate *private* attributes. diff --git a/mmgen/tool/file.py b/mmgen/tool/file.py index 1d2f9fa7..5313828e 100755 --- a/mmgen/tool/file.py +++ b/mmgen/tool/file.py @@ -22,6 +22,9 @@ tool.file: Address and transaction file routines for the 'mmgen-tool' utility from .common import tool_cmd_base, options_annot_str +txview_sort_exp = options_annot_str(['addr', 'raw']) +txview_filesort_exp = options_annot_str(['mtime', 'ctime', 'atime']) + class tool_cmd(tool_cmd_base): "utilities for viewing/checking MMGen address and transaction files" @@ -84,8 +87,8 @@ class tool_cmd(tool_cmd_base): 'mmgen_tx_file(s)': str, 'pager': 'send output to pager', 'terse': 'produce compact tabular output', - 'sort': 'sort order for transaction inputs and outputs ' + options_annot_str(['addr', 'raw']), - 'filesort': 'file sort order ' + options_annot_str(['mtime', 'ctime', 'atime'])}}, + 'sort': f'sort order for transaction inputs and outputs {txview_sort_exp}', + 'filesort': f'file sort order {txview_filesort_exp}'}}, *infiles, **kwargs): "display specified raw or signed MMGen transaction files in human-readable form" diff --git a/mmgen/tool/rpc.py b/mmgen/tool/rpc.py index 48dddb9b..c8f5cf16 100755 --- a/mmgen/tool/rpc.py +++ b/mmgen/tool/rpc.py @@ -193,8 +193,8 @@ class tool_cmd(tool_cmd_base): return await (await TwCtl(self.cfg, self.proto, mode='w')).rescan_address(mmgen_or_coin_addr) async def rescan_blockchain(self, *, - start_block: int = None, - stop_block: int = None): + start_block: int = None, # noqa: RUF013 + stop_block: int = None): # noqa: RUF013 """ rescan the blockchain to update historical transactions in the tracking wallet diff --git a/mmgen/xmrwallet/__init__.py b/mmgen/xmrwallet/__init__.py index 96ceef98..707ff15e 100755 --- a/mmgen/xmrwallet/__init__.py +++ b/mmgen/xmrwallet/__init__.py @@ -31,7 +31,7 @@ uargs = namedtuple('xmrwallet_uargs', [ 'spec', 'compat_call']) -uarg_info = ( +uarg_info = ( # noqa: PLC3002 lambda e, hp: { 'daemon': e('HOST:PORT', hp), 'tx_relay_daemon': e('HOST:PORT[:PROXY_IP:PROXY_PORT]', rf'({hp})(?::({hp}))?'), diff --git a/pyproject.toml b/pyproject.toml index 3e83d6c7..194e2b3c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,19 +36,7 @@ ignore = [ [tool.ruff.lint.per-file-ignores] "protobuf.py" = [ "UP045" ] # Use `X | None` for type annotations "mmgen/rpc/backends/curl.py" = [ "ASYNC221" ] # blocking method in async function -"mmgen/xmrwallet/__init__.py" = [ "PLC3002" ] # Lambda expression called directly "mmgen/tool/*" = [ "F821" ] # Undefined name `sstr` -"mmgen/tool/file.py" = [ "B008" ] # function call in dfl args -"mmgen/tool/rpc.py" = [ "RUF013" ] # PEP 484 prohibits implicit `Optional` -"mmgen/contrib/keccak.py" = [ "FURB163" ] # `math.log` -> `math.log2(state.lanew)` -"mmgen/devtools.py" = [ "SIM115" ] # open() with context manager -"mmgen/proto/eth/rlp/*" = [ - "TRY002", # create your own exception - "UP004", # class `Binary` inherits from `object` - "UP008", # Use `super()` instead of `super(__class__, self)` - "UP030", # Use implicit references for positional format fields - "RUF100" # Unused `noqa` directive (non-enabled: `F401`) -] "examples/*" = [ "ASYNC230" ] # open() in async function @@ -58,6 +46,7 @@ ignore = [ "test/objattrtest_d/*" = [ "F401" ] # imported but unused "test/objtest_d/*" = [ "F401" ] # imported but unused "test/modtest_d/dep.py" = [ "F401" ] # imported but unused +"test/modtest_d/testdep.py" = [ "F401" ] # imported but unused "test/cmdtest_d/*" = [ "ASYNC251", # time.sleep() in async function "S102" # Use of `exec` detected diff --git a/test/modtest_d/testdep.py b/test/modtest_d/testdep.py index 565e598a..7636100e 100755 --- a/test/modtest_d/testdep.py +++ b/test/modtest_d/testdep.py @@ -73,7 +73,7 @@ class unit_tests: def eth_keys(self, name, ut): try: - from eth_keys import keys # noqa: F401 + from eth_keys import keys return True except ImportError: if get_ethkey():