Browse Source

Use Ruff static code analyzer for Github workflows

The MMGen Project 2 months ago
parent
commit
487678bce9

+ 7 - 16
.github/workflows/pylint.yaml → .github/workflows/ruff.yaml

@@ -1,9 +1,9 @@
-name: pylint
+name: ruff
 
 on:
   push:
     paths:
-      - '.github/workflows/pylint.yaml'
+      - '.github/workflows/ruff.yaml'
       - '.github/build-requirements.txt'
       - 'pyproject.toml'
       - 'setup.cfg'
@@ -19,13 +19,6 @@ jobs:
     strategy:
       matrix:
         python-version: ["3.9", "3.11", "3.12"]
-        include:
-          - python-version: "3.9"
-            pylint_ver: "3.1.1"
-          - python-version: "3.11"
-            pylint_ver: "3.1.1"
-          - python-version: "3.12"
-            pylint_ver: "3.1.1"
 
     steps:
     - uses: actions/checkout@v4
@@ -47,15 +40,13 @@ jobs:
       run: |
         python3 -m pip install pip setuptools build wheel
         python3 -m pip install gmpy2 cryptography pynacl ecdsa aiohttp requests pexpect scrypt semantic-version
-        python3 -m pip install pycryptodomex pysocks pycoin ipaddress varint pylint==${{ matrix.pylint_ver }}
-        python3 -m pip install --no-deps py_ecc==1.6.0 mypy_extensions==0.4.1 monero
+        python3 -m pip install pycryptodomex pysocks pycoin ipaddress varint ruff
+        python3 -m pip install py_ecc mypy_extensions monero eth-keys
         python3 setup.py build_ext --inplace
 
-    - name: Check the code with Pylint static code analyzer
+    - name: Check the code with Ruff static code analyzer
       env:
         PYTHONPATH: .
       run: |
-        pylint --errors-only --jobs=0 mmgen
-        pylint --errors-only --jobs=0 test
-        pylint --errors-only --jobs=0 examples
-        pylint --errors-only --jobs=0 --disable=relative-beyond-top-level test/cmdtest_d
+        ruff check --output-format=github mmgen
+        ruff check --output-format=github test

+ 0 - 1
mmgen/bip_hd/__init__.py

@@ -16,7 +16,6 @@ bip_hd: BIP-44/49/84, SLIP-44 hierarchical-deterministic key derivation library
 #   https://blog.unit410.com/bitcoin/bip32/bip39/kdf/2021/05/17/inconsistent-bip32-derivations.html
 
 import hmac
-from collections import namedtuple
 
 from ..cfg import Config
 from ..util import is_int, fmt

+ 1 - 0
mmgen/cfgfile.py

@@ -135,6 +135,7 @@ class cfg_file_sample(cfg_file):
 			hdr = True
 			chunk = []
 			in_chunk = False
+			last_nonblank = 0
 
 			for lineno, line in enumerate(lines, 1):
 

+ 1 - 1
mmgen/help/__init__.py

@@ -20,7 +20,7 @@
 help: help notes for MMGen suite commands
 """
 
-import sys, re
+import sys
 
 from ..cfg import gc
 

+ 0 - 1
mmgen/proto/btc/tx/new.py

@@ -69,7 +69,6 @@ class New(Base, TxBase.New):
 
 	# given network fee estimate in BTC/kB, return absolute fee using estimated tx size
 	def fee_est2abs(self, fee_per_kb, fe_type=None):
-		from decimal import Decimal
 		tx_size = self.estimate_size()
 		ret = self.proto.coin_amt('1') * (fee_per_kb * self.cfg.fee_adjust * tx_size / 1024)
 		if self.cfg.verbose:

+ 0 - 2
mmgen/tx/__init__.py

@@ -12,8 +12,6 @@
 tx.__init__: transaction class initializer
 """
 
-from ..objmethods import MMGenObject
-
 def _base_proto_subclass(clsname, modname, proto):
 	if proto:
 		clsname = ('Token' if proto.tokensym else '') + clsname

+ 1 - 1
mmgen/xmrwallet/ops/label.py

@@ -12,7 +12,7 @@
 xmrwallet.ops.label: Monero wallet ops for the MMGen Suite
 """
 
-from ...color import red, pink, cyan, gray
+from ...color import pink, cyan, gray
 from ...util import msg, ymsg, gmsg, die, make_timestr
 from ...ui import keypress_confirm
 from ...addr import CoinAddr

+ 1 - 1
mmgen/xmrwallet/rpc.py

@@ -16,7 +16,7 @@ from collections import namedtuple
 
 from ..obj import CoinTxID
 from ..color import red, cyan, pink
-from ..util import msg, msg_r, gmsg, gmsg_r, die, fmt
+from ..util import msg, msg_r, gmsg, gmsg_r, die
 from ..addr import CoinAddr
 
 from .include import gen_acct_addr_info, XMRWalletAddrSpec

+ 39 - 6
pyproject.toml

@@ -6,11 +6,44 @@ requires = [
 ]
 build-backend = "setuptools.build_meta"
 
+[tool.ruff.lint]
+ignore = [
+	"E401", # multiple imports per line
+	"E701", # multiple statements per line
+	"E721", # use isinstance()
+	"E731", # lambda instead of def
+	"E402", # module import not top of file
+	"E722", # bare except
+	"E713", # membership 'not in'
+	"E741", # ambiguous variable name
+]
+
+[tool.ruff.lint.per-file-ignores]
+"mmgen/proto/eth/pyethereum/*"  = [ "F401" ]         # imported but unused
+"mmgen/proto/eth/rlp/sedes/*"   = [ "F401" ]         # imported but unused
+"mmgen/addrgen.py"              = [ "F401" ]         # imported but unused
+"mmgen/tool/*"                  = [
+	"F722", # Syntax error in forward annotation
+	"F821"  # Undefined name `sstr`
+]
+"test/include/common.py"        = [ "F821" ]         # undefined name 'cfg'
+"test/misc/input_func.py"       = [ "F401" ]         # imported but unused
+"test/modtest_d/ut_cashaddr.py" = [ "F841" ]         # assigned to but never used
+"test/modtest_d/ut_dep.py"      = [ "F401" ]         # imported but unused
+"test/modtest_d/ut_testdep.py"  = [ "F401" ]         # imported but unused
+"test/modtest_d/ut_obj.py"      = [ "F841" ]         # assigned to but never used
+"test/objtest_d/*"              = [ "F401" ]         # imported but unused
+"test/objattrtest_d/*"          = [ "F401" ]         # imported but unused
+"test/overlay/fakemods/*"       = [ "F403", "F405" ] # `import *` used
+"test/*.py"                     = [ "F401" ]         # imported but unused
+"test/colortest.py"             = [ "F403", "F405" ] # `import *` used
+"test/tooltest2.py"             = [ "F403", "F405" ] # `import *` used
+
 [tool.pylint.format]
 indent-string = "\t"
 indent-after-paren = 2
 max-line-length = 116
- 
+
 [tool.pylint.main]
 recursive = true
 jobs = 0
@@ -28,7 +61,7 @@ ignored-modules = [ # ignored for no-member, otherwise checked
 	"msvcrt",
 	"gmpy2",
 ]
- 
+
 [tool.pylint."messages control"]
 disable = [
 	"raw-checker-failed",
@@ -50,7 +83,7 @@ disable = [
 
 [tool.pylint.miscellaneous]
 notes = ["FIXME", "TODO", "DEBUG", "WIP"]
- 
+
 [tool.pylint.typecheck]
 mixin-class-rgx = """.*[Mm]ixin|\
 	^(Hilite|InitErrors|DummyWIF|\
@@ -59,9 +92,9 @@ mixin-class-rgx = """.*[Mm]ixin|\
 	CmdTestShared)$"""
 
 ignored-classes = [ # ignored for no-member, otherwise checked
-	"optparse.Values", 
-	"thread._local", 
-	"_thread._local", 
+	"optparse.Values",
+	"thread._local",
+	"_thread._local",
 	"argparse.Namespace",
 # mmgen:
 	"baseconv",

+ 0 - 2
test/cmdtest_d/ct_automount.py

@@ -12,11 +12,9 @@
 test.cmdtest_d.ct_automount: autosigning with automount tests for the cmdtest.py test suite
 """
 import time
-from pathlib import Path
 
 from .ct_autosign import CmdTestAutosignThreaded
 from .ct_regtest import CmdTestRegtestBDBWallet, rt_pw
-from .common import get_file_with_ext
 from ..include.common import cfg
 
 class CmdTestAutosignAutomount(CmdTestAutosignThreaded, CmdTestRegtestBDBWallet):

+ 1 - 1
test/cmdtest_d/ct_base.py

@@ -55,7 +55,7 @@ class CmdTestBase:
 		self.coin = self.proto.coin.lower()
 		self.fork = 'btc' if self.coin == 'bch' and not cfg.cashaddr else self.coin
 		self.altcoin_pfx = '' if self.fork == 'btc' else f'-{self.proto.coin}'
-		self.testnet_opt = [f'--testnet=1'] if cfg.testnet else []
+		self.testnet_opt = ['--testnet=1'] if cfg.testnet else []
 		if len(self.tmpdir_nums) == 1:
 			self.tmpdir_num = self.tmpdir_nums[0]
 		if self.tr:

+ 3 - 2
test/daemontest_d/ut_tx.py

@@ -4,10 +4,10 @@
 test.daemontest_d.ut_tx: TX daemon tests for the MMGen suite
 """
 
-import os, json
+import json
 
 from mmgen.color import purple, cyan
-from mmgen.util import msg, Msg, Msg_r
+from mmgen.util import Msg, Msg_r
 from mmgen.devtools import Pmsg
 from mmgen.protocol import init_proto
 from mmgen.tx import CompletedTX
@@ -131,6 +131,7 @@ class unit_tests:
 		print_info(name, 'Bitcoin Core test vectors')
 
 		n = 1
+		desc = '(no description)'
 		for e in core_data:
 			if isinstance(e[0], list):
 				await test_tx(

+ 1 - 1
test/include/coin_daemon_control.py

@@ -18,7 +18,7 @@ from pathlib import PurePath
 sys.path[0] = str(PurePath(*PurePath(__file__).parts[:-3]))
 
 from mmgen.cfg import Config, gc
-from mmgen.util import msg, die, oneshot_warning, async_run
+from mmgen.util import msg, die, oneshot_warning
 from mmgen.protocol import init_proto
 from mmgen.daemon import CoinDaemon
 

+ 1 - 1
test/misc/term.py

@@ -48,7 +48,7 @@ available commands for platform {sys.platform!r}:
 
 cfg = Config(opts_data=opts_data)
 
-from mmgen.term import get_char, get_char_raw, get_terminal_size, get_term
+from mmgen.term import get_char_raw, get_terminal_size, get_term
 from mmgen.ui import line_input, keypress_confirm, do_license_msg
 import mmgen.term as term_mod
 

+ 2 - 1
test/modtest_d/ut_dep.py

@@ -7,7 +7,7 @@ test.modtest_d.ut_dep: dependency unit tests for the MMGen suite
   No data verification is performed.
 """
 
-import sys, time
+import sys
 
 from subprocess import run, PIPE
 
@@ -57,6 +57,7 @@ class unit_tests:
 
 	def py_ecc(self, name, ut): # ETH
 		from py_ecc.secp256k1 import privtopub
+		privtopub(b'f' * 32)
 		return True
 
 	def pysocks(self, name, ut):

+ 1 - 1
test/modtest_d/ut_testdep.py

@@ -4,7 +4,7 @@
 test.modtest_d.ut_testdep: test dependency unit tests for the MMGen suite
 """
 
-import sys, os
+import os
 from subprocess import run, DEVNULL
 
 from mmgen.util import ymsg, bmsg

+ 1 - 3
test/modtest_d/ut_tx.py

@@ -4,12 +4,10 @@
 test.modtest_d.ut_tx: TX unit tests for the MMGen suite
 """
 
-import os, re
+import os
 
-from mmgen.devtools import get_diff, get_ndiff
 from mmgen.tx import CompletedTX, UnsignedTX
 from mmgen.tx.file import MMGenTxFile
-from mmgen.protocol import init_proto
 from mmgen.cfg import Config
 
 from ..include.common import cfg, qmsg, vmsg

+ 0 - 1
test/overlay/fakemods/mmgen/proto/btc/tw/unspent.py

@@ -6,7 +6,6 @@ if overlay_fake_os.getenv('MMGEN_BOGUS_UNSPENT_DATA'):
 	class overlay_fake_BitcoinTwUnspentOutputs(BitcoinTwUnspentOutputs):
 
 		async def get_rpc_data(self):
-			from decimal import Decimal
 			import json
 			from ....fileutil import get_data_from_file
 			return json.loads(get_data_from_file(