diff options
author | fanquake <fanquake@gmail.com> | 2023-11-17 11:03:15 +0000 |
---|---|---|
committer | fanquake <fanquake@gmail.com> | 2023-11-17 11:19:17 +0000 |
commit | 98b0acda0f00df3f62a61646d323c8367ddebd68 (patch) | |
tree | a79bc8c8d5009bbc27b7ee0918da2bcb68df7a3a | |
parent | 950af7c8767aaaf66fe329cb10deaf0aea8e6ed9 (diff) | |
parent | a478c817b2f62b7334b36e331a2e37fe8380c754 (diff) | |
download | bitcoin-98b0acda0f00df3f62a61646d323c8367ddebd68.tar.xz |
Merge bitcoin/bitcoin#28725: test: refactor: use built-in collection types for type hints (Python 3.9 / PEP 585)
a478c817b2f62b7334b36e331a2e37fe8380c754 test: replace `Callable`/`Iterable` with their `collections.abc` alternative (PEP 585) (stickies-v)
4b9afb18e6b9e16d7b299820f3a1382986a451d4 scripted-diff: use PEP 585 built-in collection types for verify-binary script (Sebastian Falbesoner)
d516cf83ed2da86dfefb395cd46f8a894907b88e test: use built-in collection types for type hints (Python 3.9 / PEP 585) (Sebastian Falbesoner)
Pull request description:
With Python 3.9 / [PEP 585](https://peps.python.org/pep-0585/), [type hinting has become a little less awkward](https://docs.python.org/3.9/whatsnew/3.9.html#type-hinting-generics-in-standard-collections), as for collection types one doesn't need to import the corresponding capitalized types (`Dict`, `List`, `Set`, `Tuple`, ...) anymore, but can use the built-in types directly (see https://peps.python.org/pep-0585/#implementation for the full list).
This PR applies the replacement for all Python scripts (i.e. in the contrib and test folders) for the basic types, i.e.:
- typing.Dict -> dict
- typing.List -> list
- typing.Set -> set
- typing.Tuple -> tuple
For an additional check, I ran mypy 1.6.1 on both master and the PR branch via
```
$ mypy --ignore-missing-imports --explicit-package-bases $(git ls-files "*.py")
```
and verified that the output is identical -- (from the 22 identified problems, most look like false-positives, it's probably worth it to go deeper here and address them in a follow-up though).
ACKs for top commit:
stickies-v:
ACK a478c817b2f62b7334b36e331a2e37fe8380c754
fanquake:
ACK a478c817b2f62b7334b36e331a2e37fe8380c754
Tree-SHA512: 6948c905f6abd644d84f09fcb3661d7edb2742e8f2b28560008697d251d77a61a1146ab4b070e65b0d27acede7a5256703da7bf6eb1c7c3a897755478c76c6e8
-rwxr-xr-x | contrib/devtools/circular-dependencies.py | 5 | ||||
-rwxr-xr-x | contrib/devtools/security-check.py | 3 | ||||
-rwxr-xr-x | contrib/devtools/symbol-check.py | 7 | ||||
-rwxr-xr-x | contrib/devtools/test-security-check.py | 3 | ||||
-rwxr-xr-x | contrib/devtools/test-symbol-check.py | 7 | ||||
-rwxr-xr-x | contrib/devtools/utils.py | 3 | ||||
-rwxr-xr-x | contrib/macdeploy/macdeployqtplus | 6 | ||||
-rwxr-xr-x | contrib/message-capture/message-capture-parser.py | 6 | ||||
-rw-r--r-- | contrib/seeds/asmap.py | 81 | ||||
-rwxr-xr-x | contrib/seeds/makeseeds.py | 16 | ||||
-rwxr-xr-x | contrib/verify-binaries/verify.py | 26 | ||||
-rwxr-xr-x | test/functional/interface_rest.py | 2 | ||||
-rw-r--r-- | test/functional/test_framework/script.py | 5 | ||||
-rwxr-xr-x | test/functional/test_framework/test_framework.py | 3 | ||||
-rw-r--r-- | test/functional/test_framework/util.py | 5 | ||||
-rw-r--r-- | test/functional/test_framework/wallet.py | 3 | ||||
-rwxr-xr-x | test/functional/wallet_fast_rescan.py | 4 | ||||
-rwxr-xr-x | test/lint/lint-files.py | 4 | ||||
-rwxr-xr-x | test/lint/lint-include-guards.py | 3 |
19 files changed, 91 insertions, 101 deletions
diff --git a/contrib/devtools/circular-dependencies.py b/contrib/devtools/circular-dependencies.py index b1d9f2b7db..b742a8cea6 100755 --- a/contrib/devtools/circular-dependencies.py +++ b/contrib/devtools/circular-dependencies.py @@ -5,7 +5,6 @@ import sys import re -from typing import Dict, List, Set MAPPING = { 'core_read.cpp': 'core_io.cpp', @@ -33,7 +32,7 @@ def module_name(path): return None files = dict() -deps: Dict[str, Set[str]] = dict() +deps: dict[str, set[str]] = dict() RE = re.compile("^#include <(.*)>") @@ -65,7 +64,7 @@ while True: shortest_cycle = None for module in sorted(deps.keys()): # Build the transitive closure of dependencies of module - closure: Dict[str, List[str]] = dict() + closure: dict[str, list[str]] = dict() for dep in deps[module]: closure[dep] = [] while True: diff --git a/contrib/devtools/security-check.py b/contrib/devtools/security-check.py index f90fa5785f..590c2ed87d 100755 --- a/contrib/devtools/security-check.py +++ b/contrib/devtools/security-check.py @@ -8,7 +8,6 @@ Exit status will be 0 if successful, and the program will be silent. Otherwise the exit status will be 1 and it will log which executables failed which checks. ''' import sys -from typing import List import lief @@ -255,7 +254,7 @@ if __name__ == '__main__': retval = 1 continue - failed: List[str] = [] + failed: list[str] = [] for (name, func) in CHECKS[etype][arch]: if not func(binary): failed.append(name) diff --git a/contrib/devtools/symbol-check.py b/contrib/devtools/symbol-check.py index a3d00bec95..e3e8e398c2 100755 --- a/contrib/devtools/symbol-check.py +++ b/contrib/devtools/symbol-check.py @@ -11,7 +11,6 @@ Example usage: find ../path/to/binaries -type f -executable | xargs python3 contrib/devtools/symbol-check.py ''' import sys -from typing import List, Dict import lief @@ -53,7 +52,7 @@ IGNORE_EXPORTS = { # Expected linker-loader names can be found here: # https://sourceware.org/glibc/wiki/ABIList?action=recall&rev=16 -ELF_INTERPRETER_NAMES: Dict[lief.ELF.ARCH, Dict[lief.ENDIANNESS, str]] = { +ELF_INTERPRETER_NAMES: dict[lief.ELF.ARCH, dict[lief.ENDIANNESS, str]] = { lief.ELF.ARCH.x86_64: { lief.ENDIANNESS.LITTLE: "/lib64/ld-linux-x86-64.so.2", }, @@ -72,7 +71,7 @@ ELF_INTERPRETER_NAMES: Dict[lief.ELF.ARCH, Dict[lief.ENDIANNESS, str]] = { }, } -ELF_ABIS: Dict[lief.ELF.ARCH, Dict[lief.ENDIANNESS, List[int]]] = { +ELF_ABIS: dict[lief.ELF.ARCH, dict[lief.ENDIANNESS, list[int]]] = { lief.ELF.ARCH.x86_64: { lief.ENDIANNESS.LITTLE: [3,2,0], }, @@ -302,7 +301,7 @@ if __name__ == '__main__': retval = 1 continue - failed: List[str] = [] + failed: list[str] = [] for (name, func) in CHECKS[etype]: if not func(binary): failed.append(name) diff --git a/contrib/devtools/test-security-check.py b/contrib/devtools/test-security-check.py index 92272cf8f9..64daabad4e 100755 --- a/contrib/devtools/test-security-check.py +++ b/contrib/devtools/test-security-check.py @@ -8,7 +8,6 @@ Test script for security-check.py import lief import os import subprocess -from typing import List import unittest from utils import determine_wellknown_cmd @@ -34,7 +33,7 @@ def call_security_check(cc: str, source: str, executable: str, options) -> tuple # # See the definitions for ac_link in autoconf's lib/autoconf/c.m4 file for # reference. - env_flags: List[str] = [] + env_flags: list[str] = [] for var in ['CFLAGS', 'CPPFLAGS', 'LDFLAGS']: env_flags += filter(None, os.environ.get(var, '').split(' ')) diff --git a/contrib/devtools/test-symbol-check.py b/contrib/devtools/test-symbol-check.py index fe8a99739f..0140decb25 100755 --- a/contrib/devtools/test-symbol-check.py +++ b/contrib/devtools/test-symbol-check.py @@ -7,18 +7,17 @@ Test script for symbol-check.py ''' import os import subprocess -from typing import List import unittest from utils import determine_wellknown_cmd -def call_symbol_check(cc: List[str], source, executable, options): +def call_symbol_check(cc: list[str], source, executable, options): # This should behave the same as AC_TRY_LINK, so arrange well-known flags # in the same order as autoconf would. # # See the definitions for ac_link in autoconf's lib/autoconf/c.m4 file for # reference. - env_flags: List[str] = [] + env_flags: list[str] = [] for var in ['CFLAGS', 'CPPFLAGS', 'LDFLAGS']: env_flags += filter(None, os.environ.get(var, '').split(' ')) @@ -28,7 +27,7 @@ def call_symbol_check(cc: List[str], source, executable, options): os.remove(executable) return (p.returncode, p.stdout.rstrip()) -def get_machine(cc: List[str]): +def get_machine(cc: list[str]): p = subprocess.run([*cc,'-dumpmachine'], stdout=subprocess.PIPE, text=True) return p.stdout.rstrip() diff --git a/contrib/devtools/utils.py b/contrib/devtools/utils.py index 68ad1c3aba..8b4c67c6c0 100755 --- a/contrib/devtools/utils.py +++ b/contrib/devtools/utils.py @@ -8,10 +8,9 @@ Common utility functions import shutil import sys import os -from typing import List -def determine_wellknown_cmd(envvar, progname) -> List[str]: +def determine_wellknown_cmd(envvar, progname) -> list[str]: maybe_env = os.getenv(envvar) maybe_which = shutil.which(progname) if maybe_env: diff --git a/contrib/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus index fa9b868349..4b1d72650d 100755 --- a/contrib/macdeploy/macdeployqtplus +++ b/contrib/macdeploy/macdeployqtplus @@ -20,7 +20,7 @@ import sys, re, os, platform, shutil, stat, subprocess, os.path from argparse import ArgumentParser from pathlib import Path from subprocess import PIPE, run -from typing import List, Optional +from typing import Optional # This is ported from the original macdeployqt with modifications @@ -181,7 +181,7 @@ class DeploymentInfo(object): return True return False -def getFrameworks(binaryPath: str, verbose: int) -> List[FrameworkInfo]: +def getFrameworks(binaryPath: str, verbose: int) -> list[FrameworkInfo]: if verbose: print(f"Inspecting with otool: {binaryPath}") otoolbin=os.getenv("OTOOL", "otool") @@ -285,7 +285,7 @@ def copyFramework(framework: FrameworkInfo, path: str, verbose: int) -> Optional return toPath -def deployFrameworks(frameworks: List[FrameworkInfo], bundlePath: str, binaryPath: str, strip: bool, verbose: int, deploymentInfo: Optional[DeploymentInfo] = None) -> DeploymentInfo: +def deployFrameworks(frameworks: list[FrameworkInfo], bundlePath: str, binaryPath: str, strip: bool, verbose: int, deploymentInfo: Optional[DeploymentInfo] = None) -> DeploymentInfo: if deploymentInfo is None: deploymentInfo = DeploymentInfo() diff --git a/contrib/message-capture/message-capture-parser.py b/contrib/message-capture/message-capture-parser.py index d6ddc1c149..0f409717d4 100755 --- a/contrib/message-capture/message-capture-parser.py +++ b/contrib/message-capture/message-capture-parser.py @@ -11,7 +11,7 @@ import sys from io import BytesIO import json from pathlib import Path -from typing import Any, List, Optional +from typing import Any, Optional sys.path.append(os.path.join(os.path.dirname(__file__), '../../test/functional')) @@ -92,7 +92,7 @@ def to_jsonable(obj: Any) -> Any: return obj -def process_file(path: str, messages: List[Any], recv: bool, progress_bar: Optional[ProgressBar]) -> None: +def process_file(path: str, messages: list[Any], recv: bool, progress_bar: Optional[ProgressBar]) -> None: with open(path, 'rb') as f_in: if progress_bar: bytes_read = 0 @@ -188,7 +188,7 @@ def main(): output = Path.cwd() / Path(args.output) if args.output else False use_progress_bar = (not args.no_progress_bar) and sys.stdout.isatty() - messages = [] # type: List[Any] + messages = [] # type: list[Any] if use_progress_bar: total_size = sum(capture.stat().st_size for capture in capturepaths) progress_bar = ProgressBar(total_size) diff --git a/contrib/seeds/asmap.py b/contrib/seeds/asmap.py index e28e5cf532..214805b5a5 100644 --- a/contrib/seeds/asmap.py +++ b/contrib/seeds/asmap.py @@ -10,11 +10,12 @@ import copy import ipaddress import random import unittest +from collections.abc import Callable, Iterable from enum import Enum from functools import total_ordering -from typing import Callable, Dict, Iterable, List, Optional, Tuple, Union, overload +from typing import Optional, Union, overload -def net_to_prefix(net: Union[ipaddress.IPv4Network,ipaddress.IPv6Network]) -> List[bool]: +def net_to_prefix(net: Union[ipaddress.IPv4Network,ipaddress.IPv6Network]) -> list[bool]: """ Convert an IPv4 or IPv6 network to a prefix represented as a list of bits. @@ -32,7 +33,7 @@ def net_to_prefix(net: Union[ipaddress.IPv4Network,ipaddress.IPv6Network]) -> Li assert (netrange & ((1 << (128 - num_bits)) - 1)) == 0 return [((netrange >> (127 - i)) & 1) != 0 for i in range(num_bits)] -def prefix_to_net(prefix: List[bool]) -> Union[ipaddress.IPv4Network,ipaddress.IPv6Network]: +def prefix_to_net(prefix: list[bool]) -> Union[ipaddress.IPv4Network,ipaddress.IPv6Network]: """The reverse operation of net_to_prefix.""" # Convert to number netrange = sum(b << (127 - i) for i, b in enumerate(prefix)) @@ -47,10 +48,10 @@ def prefix_to_net(prefix: List[bool]) -> Union[ipaddress.IPv4Network,ipaddress.I return ipaddress.IPv6Network((netrange, num_bits), True) # Shortcut for (prefix, ASN) entries. -ASNEntry = Tuple[List[bool], int] +ASNEntry = tuple[list[bool], int] # Shortcut for (prefix, old ASN, new ASN) entries. -ASNDiff = Tuple[List[bool], int, int] +ASNDiff = tuple[list[bool], int, int] class _VarLenCoder: """ @@ -75,7 +76,7 @@ class _VarLenCoder: other classes start one past the last element of the class before it. """ - def __init__(self, minval: int, clsbits: List[int]): + def __init__(self, minval: int, clsbits: list[int]): """Construct a new _VarLenCoder.""" self._minval = minval self._clsbits = clsbits @@ -85,7 +86,7 @@ class _VarLenCoder: """Check whether value val is in the range this coder supports.""" return self._minval <= val <= self._maxval - def encode(self, val: int, ret: List[int]) -> None: + def encode(self, val: int, ret: list[int]) -> None: """Append encoding of val onto integer list ret.""" assert self._minval <= val <= self._maxval @@ -120,7 +121,7 @@ class _VarLenCoder: break return ret + bits - def decode(self, stream, bitpos) -> Tuple[int,int]: + def decode(self, stream, bitpos) -> tuple[int,int]: """Decode a number starting at bitpos in stream, returning value and new bitpos.""" val = self._minval bits = 0 @@ -281,11 +282,11 @@ class ASMap: - mappings, represented by new trie nodes. """ - def update(self, prefix: List[bool], asn: int) -> None: + def update(self, prefix: list[bool], asn: int) -> None: """Update this ASMap object to map prefix to the specified asn.""" assert asn == 0 or _CODER_ASN.can_encode(asn) - def recurse(node: List, offset: int) -> None: + def recurse(node: list, offset: int) -> None: if offset == len(prefix): # Reached the end of prefix; overwrite this node. node.clear() @@ -306,7 +307,7 @@ class ASMap: node.append(oldasn) recurse(self._trie, 0) - def update_multi(self, entries: List[Tuple[List[bool], int]]) -> None: + def update_multi(self, entries: list[tuple[list[bool], int]]) -> None: """Apply multiple update operations, where longer prefixes take precedence.""" entries.sort(key=lambda entry: len(entry[0])) for prefix, asn in entries: @@ -314,7 +315,7 @@ class ASMap: def _set_trie(self, trie) -> None: """Set trie directly. Internal use only.""" - def recurse(node: List) -> None: + def recurse(node: list) -> None: if len(node) < 2: return recurse(node[0]) @@ -342,7 +343,7 @@ class ASMap: for prefix, asn in sorted(entries, key=entry_key): self.update(prefix, asn) - def lookup(self, prefix: List[bool]) -> Optional[int]: + def lookup(self, prefix: list[bool]) -> Optional[int]: """Look up a prefix. Returns ASN, or 0 if unassigned, or None if indeterminate.""" node = self._trie for bit in prefix: @@ -353,11 +354,11 @@ class ASMap: return node[0] return None - def _to_entries_flat(self, fill: bool = False) -> List[ASNEntry]: + def _to_entries_flat(self, fill: bool = False) -> list[ASNEntry]: """Convert an ASMap object to a list of non-overlapping (prefix, asn) objects.""" - prefix : List[bool] = [] + prefix : list[bool] = [] - def recurse(node: List) -> List[ASNEntry]: + def recurse(node: list) -> list[ASNEntry]: ret = [] if len(node) == 1: if node[0] > 0: @@ -375,24 +376,24 @@ class ASMap: return ret return recurse(self._trie) - def _to_entries_minimal(self, fill: bool = False) -> List[ASNEntry]: + def _to_entries_minimal(self, fill: bool = False) -> list[ASNEntry]: """Convert a trie to a minimal list of ASNEntry objects, exploiting overlap.""" - prefix : List[bool] = [] + prefix : list[bool] = [] - def recurse(node: List) -> (Tuple[Dict[Optional[int], List[ASNEntry]], bool]): + def recurse(node: list) -> (tuple[dict[Optional[int], list[ASNEntry]], bool]): if len(node) == 1 and node[0] == 0: return {None if fill else 0: []}, True if len(node) == 1: return {node[0]: [], None: [(list(prefix), node[0])]}, False - ret: Dict[Optional[int], List[ASNEntry]] = {} + ret: dict[Optional[int], list[ASNEntry]] = {} prefix.append(False) left, lhole = recurse(node[0]) prefix[-1] = True right, rhole = recurse(node[1]) prefix.pop() hole = not fill and (lhole or rhole) - def candidate(ctx: Optional[int], res0: Optional[List[ASNEntry]], - res1: Optional[List[ASNEntry]]): + def candidate(ctx: Optional[int], res0: Optional[list[ASNEntry]], + res1: Optional[list[ASNEntry]]): if res0 is not None and res1 is not None: if ctx not in ret or len(res0) + len(res1) < len(ret[ctx]): ret[ctx] = res0 + res1 @@ -417,7 +418,7 @@ class ASMap: """Convert this ASMap object to a string containing Python code constructing it.""" return f"ASMap({self._trie})" - def to_entries(self, overlapping: bool = True, fill: bool = False) -> List[ASNEntry]: + def to_entries(self, overlapping: bool = True, fill: bool = False) -> list[ASNEntry]: """ Convert the mappings in this ASMap object to a list of ASNEntry objects. @@ -448,7 +449,7 @@ class ASMap: assert max_asn >= 1 or unassigned_prob == 1 assert _CODER_ASN.can_encode(max_asn) assert 0.0 <= unassigned_prob <= 1.0 - trie: List = [] + trie: list = [] leaves = [trie] ret = ASMap() for i in range(1, num_leaves): @@ -472,12 +473,12 @@ class ASMap: def _to_binnode(self, fill: bool = False) -> _BinNode: """Convert a trie to a _BinNode object.""" - def recurse(node: List) -> Tuple[Dict[Optional[int], _BinNode], bool]: + def recurse(node: list) -> tuple[dict[Optional[int], _BinNode], bool]: if len(node) == 1 and node[0] == 0: return {(None if fill else 0): _BinNode.make_end()}, True if len(node) == 1: return {None: _BinNode.make_leaf(node[0]), node[0]: _BinNode.make_end()}, False - ret: Dict[Optional[int], _BinNode] = {} + ret: dict[Optional[int], _BinNode] = {} left, lhole = recurse(node[0]) right, rhole = recurse(node[1]) hole = (lhole or rhole) and not fill @@ -507,7 +508,7 @@ class ASMap: @staticmethod def _from_binnode(binnode: _BinNode) -> "ASMap": """Construct an ASMap object from a _BinNode. Internal use only.""" - def recurse(node: _BinNode, default: int) -> List: + def recurse(node: _BinNode, default: int) -> list: if node.ins == _Instruction.RETURN: return [node.arg1] if node.ins == _Instruction.JUMP: @@ -542,7 +543,7 @@ class ASMap: Returns: A bytes object with the encoding of this ASMap object. """ - bits: List[int] = [] + bits: list[int] = [] def recurse(node: _BinNode) -> None: _CODER_INS.encode(node.ins.value, bits) @@ -582,11 +583,11 @@ class ASMap: def from_binary(bindata: bytes) -> Optional["ASMap"]: """Decode an ASMap object from the provided binary encoding.""" - bits: List[int] = [] + bits: list[int] = [] for byte in bindata: bits.extend((byte >> i) & 1 for i in range(8)) - def recurse(bitpos: int) -> Tuple[_BinNode, int]: + def recurse(bitpos: int) -> tuple[_BinNode, int]: insval, bitpos = _CODER_INS.decode(bits, bitpos) ins = _Instruction(insval) if ins == _Instruction.RETURN: @@ -632,7 +633,7 @@ class ASMap: def extends(self, req: "ASMap") -> bool: """Determine whether this matches req for all subranges where req is assigned.""" - def recurse(actual: List, require: List) -> bool: + def recurse(actual: list, require: list) -> bool: if len(require) == 1 and require[0] == 0: return True if len(require) == 1: @@ -646,20 +647,20 @@ class ASMap: #pylint: disable=protected-access return recurse(self._trie, req._trie) - def diff(self, other: "ASMap") -> List[ASNDiff]: + def diff(self, other: "ASMap") -> list[ASNDiff]: """Compute the diff from self to other.""" - prefix: List[bool] = [] - ret: List[ASNDiff] = [] + prefix: list[bool] = [] + ret: list[ASNDiff] = [] - def recurse(old_node: List, new_node: List): + def recurse(old_node: list, new_node: list): if len(old_node) == 1 and len(new_node) == 1: if old_node[0] != new_node[0]: ret.append((list(prefix), old_node[0], new_node[0])) else: - old_left: List = old_node if len(old_node) == 1 else old_node[0] - old_right: List = old_node if len(old_node) == 1 else old_node[1] - new_left: List = new_node if len(new_node) == 1 else new_node[0] - new_right: List = new_node if len(new_node) == 1 else new_node[1] + old_left: list = old_node if len(old_node) == 1 else old_node[0] + old_right: list = old_node if len(old_node) == 1 else old_node[1] + new_left: list = new_node if len(new_node) == 1 else new_node[0] + new_right: list = new_node if len(new_node) == 1 else new_node[1] prefix.append(False) recurse(old_left, new_left) prefix[-1] = True @@ -760,7 +761,7 @@ class TestASMap(unittest.TestCase): # It starts off being equal to asmap. patched = copy.copy(asmap) # Keep a list of patches performed. - patches: List[ASNEntry] = [] + patches: list[ASNEntry] = [] # Initially there cannot be any difference. self.assertEqual(asmap.diff(patched), []) # Make 5 patches, each building on top of the previous ones. diff --git a/contrib/seeds/makeseeds.py b/contrib/seeds/makeseeds.py index af408c2df5..f03c2ab5e8 100755 --- a/contrib/seeds/makeseeds.py +++ b/contrib/seeds/makeseeds.py @@ -11,7 +11,7 @@ import collections import ipaddress import re import sys -from typing import List, Dict, Union +from typing import Union from asmap import ASMap, net_to_prefix @@ -117,14 +117,14 @@ def parseline(line: str) -> Union[dict, None]: 'sortkey': sortkey, } -def dedup(ips: List[Dict]) -> List[Dict]: +def dedup(ips: list[dict]) -> list[dict]: """ Remove duplicates from `ips` where multiple ips share address and port. """ d = {} for ip in ips: d[ip['ip'],ip['port']] = ip return list(d.values()) -def filtermultiport(ips: List[Dict]) -> List[Dict]: +def filtermultiport(ips: list[dict]) -> list[dict]: """ Filter out hosts with more nodes per IP""" hist = collections.defaultdict(list) for ip in ips: @@ -132,7 +132,7 @@ def filtermultiport(ips: List[Dict]) -> List[Dict]: return [value[0] for (key,value) in list(hist.items()) if len(value)==1] # Based on Greg Maxwell's seed_filter.py -def filterbyasn(asmap: ASMap, ips: List[Dict], max_per_asn: Dict, max_per_net: int) -> List[Dict]: +def filterbyasn(asmap: ASMap, ips: list[dict], max_per_asn: dict, max_per_net: int) -> list[dict]: """ Prunes `ips` by (a) trimming ips to have at most `max_per_net` ips from each net (e.g. ipv4, ipv6); and (b) trimming ips to have at most `max_per_asn` ips from each asn in each net. @@ -143,8 +143,8 @@ def filterbyasn(asmap: ASMap, ips: List[Dict], max_per_asn: Dict, max_per_net: i # Filter IPv46 by ASN, and limit to max_per_net per network result = [] - net_count: Dict[str, int] = collections.defaultdict(int) - asn_count: Dict[int, int] = collections.defaultdict(int) + net_count: dict[str, int] = collections.defaultdict(int) + asn_count: dict[int, int] = collections.defaultdict(int) for i, ip in enumerate(ips_ipv46): if net_count[ip['net']] == max_per_net: @@ -165,9 +165,9 @@ def filterbyasn(asmap: ASMap, ips: List[Dict], max_per_asn: Dict, max_per_net: i result.extend(ips_onion[0:max_per_net]) return result -def ip_stats(ips: List[Dict]) -> str: +def ip_stats(ips: list[dict]) -> str: """ Format and return pretty string from `ips`. """ - hist: Dict[str, int] = collections.defaultdict(int) + hist: dict[str, int] = collections.defaultdict(int) for ip in ips: if ip is not None: hist[ip['net']] += 1 diff --git a/contrib/verify-binaries/verify.py b/contrib/verify-binaries/verify.py index d0749f503f..12e6e10d8a 100755 --- a/contrib/verify-binaries/verify.py +++ b/contrib/verify-binaries/verify.py @@ -122,7 +122,7 @@ def download_with_wget(remote_file, local_file): return result.returncode == 0, result.stdout.decode().rstrip() -def download_lines_with_urllib(url) -> t.Tuple[bool, t.List[str]]: +def download_lines_with_urllib(url) -> tuple[bool, list[str]]: """Get (success, text lines of a file) over HTTP.""" try: return (True, [ @@ -138,7 +138,7 @@ def verify_with_gpg( filename, signature_filename, output_filename: t.Optional[str] = None -) -> t.Tuple[int, str]: +) -> tuple[int, str]: with tempfile.NamedTemporaryFile() as status_file: args = [ 'gpg', '--yes', '--verify', '--verify-options', 'show-primary-uid-only', "--status-file", status_file.name, @@ -177,12 +177,12 @@ class SigData: def parse_gpg_result( - output: t.List[str] -) -> t.Tuple[t.List[SigData], t.List[SigData], t.List[SigData]]: + output: list[str] +) -> tuple[list[SigData], list[SigData], list[SigData]]: """Returns good, unknown, and bad signatures from GPG stdout.""" - good_sigs: t.List[SigData] = [] - unknown_sigs: t.List[SigData] = [] - bad_sigs: t.List[SigData] = [] + good_sigs: list[SigData] = [] + unknown_sigs: list[SigData] = [] + bad_sigs: list[SigData] = [] total_resolved_sigs = 0 # Ensure that all lines we match on include a prefix that prevents malicious input @@ -265,7 +265,7 @@ def files_are_equal(filename1, filename2): def get_files_from_hosts_and_compare( - hosts: t.List[str], path: str, filename: str, require_all: bool = False + hosts: list[str], path: str, filename: str, require_all: bool = False ) -> ReturnCode: """ Retrieve the same file from a number of hosts and ensure they have the same contents. @@ -326,7 +326,7 @@ def get_files_from_hosts_and_compare( return ReturnCode.SUCCESS -def check_multisig(sums_file: str, sigfilename: str, args: argparse.Namespace) -> t.Tuple[int, str, t.List[SigData], t.List[SigData], t.List[SigData]]: +def check_multisig(sums_file: str, sigfilename: str, args: argparse.Namespace) -> tuple[int, str, list[SigData], list[SigData], list[SigData]]: # check signature # # We don't write output to a file because this command will almost certainly @@ -365,8 +365,8 @@ def prompt_yn(prompt) -> bool: def verify_shasums_signature( signature_file_path: str, sums_file_path: str, args: argparse.Namespace -) -> t.Tuple[ - ReturnCode, t.List[SigData], t.List[SigData], t.List[SigData], t.List[SigData] +) -> tuple[ + ReturnCode, list[SigData], list[SigData], list[SigData], list[SigData] ]: min_good_sigs = args.min_good_sigs gpg_allowed_codes = [0, 2] # 2 is returned when untrusted signatures are present. @@ -429,14 +429,14 @@ def verify_shasums_signature( return (ReturnCode.SUCCESS, good_trusted, good_untrusted, unknown, bad) -def parse_sums_file(sums_file_path: str, filename_filter: t.List[str]) -> t.List[t.List[str]]: +def parse_sums_file(sums_file_path: str, filename_filter: list[str]) -> list[list[str]]: # extract hashes/filenames of binaries to verify from hash file; # each line has the following format: "<hash> <binary_filename>" with open(sums_file_path, 'r', encoding='utf8') as hash_file: return [line.split()[:2] for line in hash_file if len(filename_filter) == 0 or any(f in line for f in filename_filter)] -def verify_binary_hashes(hashes_to_verify: t.List[t.List[str]]) -> t.Tuple[ReturnCode, t.Dict[str, str]]: +def verify_binary_hashes(hashes_to_verify: list[list[str]]) -> tuple[ReturnCode, dict[str, str]]: offending_files = [] files_to_hashes = {} diff --git a/test/functional/interface_rest.py b/test/functional/interface_rest.py index c0679c5ba9..b81eae2506 100755 --- a/test/functional/interface_rest.py +++ b/test/functional/interface_rest.py @@ -65,7 +65,7 @@ class RESTTest (BitcoinTestFramework): body: str = '', status: int = 200, ret_type: RetType = RetType.JSON, - query_params: Optional[typing.Dict[str, typing.Any]] = None, + query_params: Optional[dict[str, typing.Any]] = None, ) -> typing.Union[http.client.HTTPResponse, bytes, str, None]: rest_uri = '/rest' + uri if req_type in ReqType: diff --git a/test/functional/test_framework/script.py b/test/functional/test_framework/script.py index f4628bf4af..78d8580794 100644 --- a/test/functional/test_framework/script.py +++ b/test/functional/test_framework/script.py @@ -10,7 +10,6 @@ This file is modified from python-bitcoinlib. from collections import namedtuple import struct import unittest -from typing import List, Dict from .key import TaggedHash, tweak_add_pubkey, compute_xonly_pubkey @@ -110,8 +109,8 @@ class CScriptOp(int): _opcode_instances.append(super().__new__(cls, n)) return _opcode_instances[n] -OPCODE_NAMES: Dict[CScriptOp, str] = {} -_opcode_instances: List[CScriptOp] = [] +OPCODE_NAMES: dict[CScriptOp, str] = {} +_opcode_instances: list[CScriptOp] = [] # Populate opcode instance table for n in range(0xff + 1): diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index 70b3943478..0369b4be05 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -19,7 +19,6 @@ import sys import tempfile import time -from typing import List from .address import create_deterministic_address_bcrt1_p2tr_op_true from .authproxy import JSONRPCException from . import coverage @@ -97,7 +96,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): """Sets test framework defaults. Do not override this method. Instead, override the set_test_params() method""" self.chain: str = 'regtest' self.setup_clean_chain: bool = False - self.nodes: List[TestNode] = [] + self.nodes: list[TestNode] = [] self.extra_args = None self.network_thread = None self.rpc_timeout = 60 # Wait for up to 60 seconds for the RPC server to respond diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py index 104f158d92..c65e3e38e6 100644 --- a/test/functional/test_framework/util.py +++ b/test/functional/test_framework/util.py @@ -19,7 +19,8 @@ import time from . import coverage from .authproxy import AuthServiceProxy, JSONRPCException -from typing import Callable, Optional, Tuple +from collections.abc import Callable +from typing import Optional logger = logging.getLogger("TestFramework.utils") @@ -409,7 +410,7 @@ def get_datadir_path(dirname, n): return pathlib.Path(dirname) / f"node{n}" -def get_temp_default_datadir(temp_dir: pathlib.Path) -> Tuple[dict, pathlib.Path]: +def get_temp_default_datadir(temp_dir: pathlib.Path) -> tuple[dict, pathlib.Path]: """Return os-specific environment variables that can be set to make the GetDefaultDataDir() function return a datadir path under the provided temp_dir, as well as the complete path it would return.""" diff --git a/test/functional/test_framework/wallet.py b/test/functional/test_framework/wallet.py index 035a482f4c..53c8e1b0cc 100644 --- a/test/functional/test_framework/wallet.py +++ b/test/functional/test_framework/wallet.py @@ -9,7 +9,6 @@ from decimal import Decimal from enum import Enum from typing import ( Any, - List, Optional, ) from test_framework.address import ( @@ -284,7 +283,7 @@ class MiniWallet: def create_self_transfer_multi( self, *, - utxos_to_spend: Optional[List[dict]] = None, + utxos_to_spend: Optional[list[dict]] = None, num_outputs=1, amount_per_output=0, locktime=0, diff --git a/test/functional/wallet_fast_rescan.py b/test/functional/wallet_fast_rescan.py index 2f9c924e71..1315bccafd 100755 --- a/test/functional/wallet_fast_rescan.py +++ b/test/functional/wallet_fast_rescan.py @@ -4,8 +4,6 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test that fast rescan using block filters for descriptor wallets detects top-ups correctly and finds the same transactions than the slow variant.""" -from typing import List - from test_framework.address import address_to_scriptpubkey from test_framework.descriptors import descsum_create from test_framework.test_framework import BitcoinTestFramework @@ -32,7 +30,7 @@ class WalletFastRescanTest(BitcoinTestFramework): self.skip_if_no_wallet() self.skip_if_no_sqlite() - def get_wallet_txids(self, node: TestNode, wallet_name: str) -> List[str]: + def get_wallet_txids(self, node: TestNode, wallet_name: str) -> list[str]: w = node.get_wallet_rpc(wallet_name) txs = w.listtransactions('*', 1000000) return [tx['txid'] for tx in txs] diff --git a/test/lint/lint-files.py b/test/lint/lint-files.py index f2b5db681b..86fe727b06 100755 --- a/test/lint/lint-files.py +++ b/test/lint/lint-files.py @@ -11,7 +11,7 @@ import os import re import sys from subprocess import check_output -from typing import Dict, Optional, NoReturn +from typing import Optional, NoReturn CMD_TOP_LEVEL = ["git", "rev-parse", "--show-toplevel"] CMD_ALL_FILES = ["git", "ls-files", "-z", "--full-name", "--stage"] @@ -69,7 +69,7 @@ class FileMeta(object): return None -def get_git_file_metadata() -> Dict[str, FileMeta]: +def get_git_file_metadata() -> dict[str, FileMeta]: ''' Return a dictionary mapping the name of all files in the repository to git tree metadata. ''' diff --git a/test/lint/lint-include-guards.py b/test/lint/lint-include-guards.py index 48b918e9da..291e528c1d 100755 --- a/test/lint/lint-include-guards.py +++ b/test/lint/lint-include-guards.py @@ -11,7 +11,6 @@ Check include guards. import re import sys from subprocess import check_output -from typing import List HEADER_ID_PREFIX = 'BITCOIN_' @@ -28,7 +27,7 @@ EXCLUDE_FILES_WITH_PREFIX = ['contrib/devtools/bitcoin-tidy', 'src/test/fuzz/FuzzedDataProvider.h'] -def _get_header_file_lst() -> List[str]: +def _get_header_file_lst() -> list[str]: """ Helper function to get a list of header filepaths to be checked for include guards. """ |