aboutsummaryrefslogtreecommitdiff
path: root/contrib
diff options
context:
space:
mode:
authorSebastian Falbesoner <sebastian.falbesoner@gmail.com>2023-10-25 00:55:17 +0200
committerSebastian Falbesoner <sebastian.falbesoner@gmail.com>2023-10-25 01:10:21 +0200
commitd516cf83ed2da86dfefb395cd46f8a894907b88e (patch)
treefc6f864676dc1820a705583c9f518b694dd8a635 /contrib
parentd53400e75e2a4573229dba7f1a0da88eb936811c (diff)
test: use built-in collection types for type hints (Python 3.9 / PEP 585)
Since Python 3.9, type hinting has become a little less awkward, 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. [1] [2] This commit applies the replacement for all Python scripts (i.e. in the contrib and test folders) for the basic types: - typing.Dict -> dict - typing.List -> list - typing.Set -> set - typing.Tuple -> tuple [1] https://docs.python.org/3.9/whatsnew/3.9.html#type-hinting-generics-in-standard-collections [2] https://peps.python.org/pep-0585/#implementation for a list of type
Diffstat (limited to 'contrib')
-rwxr-xr-xcontrib/devtools/circular-dependencies.py5
-rwxr-xr-xcontrib/devtools/security-check.py3
-rwxr-xr-xcontrib/devtools/symbol-check.py7
-rwxr-xr-xcontrib/devtools/test-security-check.py3
-rwxr-xr-xcontrib/devtools/test-symbol-check.py7
-rwxr-xr-xcontrib/devtools/utils.py3
-rwxr-xr-xcontrib/macdeploy/macdeployqtplus6
-rwxr-xr-xcontrib/message-capture/message-capture-parser.py6
-rw-r--r--contrib/seeds/asmap.py80
-rwxr-xr-xcontrib/seeds/makeseeds.py16
10 files changed, 65 insertions, 71 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 802bf9fd30..bb900ec3d1 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..84e1811ede 100644
--- a/contrib/seeds/asmap.py
+++ b/contrib/seeds/asmap.py
@@ -12,9 +12,9 @@ import random
import unittest
from enum import Enum
from functools import total_ordering
-from typing import Callable, Dict, Iterable, List, Optional, Tuple, Union, overload
+from typing import Callable, Iterable, 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 +32,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 +47,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 +75,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 +85,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 +120,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 +281,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 +306,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 +314,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 +342,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 +353,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 +375,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 +417,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 +448,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 +472,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 +507,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 +542,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 +582,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 +632,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 +646,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 +760,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