mirror of
https://github.com/Gallopsled/pwntools.git
synced 2026-10-12 02:02:27 +00:00
* Add Type Annotations for parts of pwnlib/util * fix: use Callable in pwnlib/util/lists.py * fix: Import Errors * fix: use getLogger in pwnlib/util/net * feat: use collections.abc.Buffer where appropriate * fix: remove collections.abc.Buffer to use Sequence * add CHANGELOG.md entry * Improve packing and fiddling types * Introduce own `BytesLike` type instead of 3.12 Buffer * Improve web.wget types * Use TypedDict in util.net Specify generics properly. * Improve pwnlib.proc types * Improve pwnlib.util.lists types * Fix util.splash types * Make TypeVars private * Improve util.hexdump types * Remove partial types from packing.fit/flat Those require more work to be useful. * Fix implicit wget return * Fix term.text type export * Fix js_escape return type * Fix sh_string doctest types * Fix usage of ssh_channel as ssh_process We access the pid, so a plain ssh_channel is not enough. * Improve util.lists types * Improve packing.dd types * Fix relying on socket.AddressFamily type at runtime The type is only in typeshed and not the real socket module. Don't access it at runtime, only at type checking. * Fix lists.findall with string needle * Fix dd on two files * Update mypy-baseline.txt * Remove testing artifacts from mypy-baseline.txt --------- Co-authored-by: peace-maker <[email protected]>
242 lines
7.2 KiB
Python
242 lines
7.2 KiB
Python
import collections
|
|
from collections.abc import Iterable, Sequence
|
|
from typing import Any, Callable, Generator, Literal, TypeVar, overload
|
|
|
|
_T = TypeVar('_T')
|
|
_R = TypeVar('_R')
|
|
|
|
@overload
|
|
def partition(lst: Iterable[_T], f: Callable[[_T], _R], save_keys: Literal[True]) -> collections.OrderedDict[_R, list[_T]]: ...
|
|
@overload
|
|
def partition(lst: Iterable[_T], f: Callable[[_T], _R], save_keys: Literal[False]) -> list[list[_T]]: ...
|
|
def partition(lst: Iterable[_T], f: Callable[[_T], _R], save_keys: bool = False) -> list[list[_T]] | collections.OrderedDict[_R, list[_T]]:
|
|
"""partition(lst, f, save_keys = False) -> list
|
|
|
|
Partitions an iterable into sublists using a function to specify which
|
|
group they belong to.
|
|
|
|
It works by calling `f` on every element and saving the results into
|
|
an :class:`collections.OrderedDict`.
|
|
|
|
Arguments:
|
|
lst: The iterable to partition
|
|
f(function): The function to use as the partitioner.
|
|
save_keys(bool): Set this to True, if you want the OrderedDict
|
|
returned instead of just the values
|
|
|
|
Example:
|
|
|
|
>>> partition([1,2,3,4,5], lambda x: x&1)
|
|
[[1, 3, 5], [2, 4]]
|
|
>>> partition([1,2,3,4,5], lambda x: x%3, save_keys=True) == collections.OrderedDict([(1, [1, 4]), (2, [2, 5]), (0, [3])])
|
|
True
|
|
"""
|
|
d: collections.OrderedDict[_R, list[_T]] = collections.OrderedDict()
|
|
|
|
for l in lst:
|
|
c = f(l)
|
|
s = d.setdefault(c, [])
|
|
s.append(l)
|
|
if save_keys:
|
|
return d
|
|
else:
|
|
return list(d.values())
|
|
|
|
|
|
|
|
@overload
|
|
def group(n: int, lst: list[_T], underfull_action: Literal['ignore', 'drop', 'fill'] = 'ignore', fill_value: _T | None = None) -> list[list[_T]]: ...
|
|
@overload
|
|
def group(n: int, lst: tuple[_T, ...], underfull_action: Literal['ignore', 'drop', 'fill'] = 'ignore', fill_value: _T | None = None) -> list[tuple[_T, ...]]: ...
|
|
@overload
|
|
def group(n: int, lst: str, underfull_action: Literal['ignore', 'drop', 'fill'] = 'ignore', fill_value: str | None = None) -> list[str]: ...
|
|
@overload
|
|
def group(n: int, lst: bytes, underfull_action: Literal['ignore', 'drop', 'fill'] = 'ignore', fill_value: bytes | None = None) -> list[bytes]: ...
|
|
def group(n: int, lst: Sequence[_T], underfull_action: Literal['ignore', 'drop', 'fill'] = 'ignore', fill_value: _T | None = None) -> list[Any]:
|
|
"""group(n, lst, underfull_action = 'ignore', fill_value = None) -> list
|
|
|
|
Split sequence into subsequences of given size. If the values cannot be
|
|
evenly distributed among into groups, then the last group will either be
|
|
returned as is, thrown out or padded with the value specified in fill_value.
|
|
|
|
Arguments:
|
|
n (int): The size of resulting groups
|
|
lst: The list, tuple or string to group
|
|
underfull_action (str): The action to take in case of an underfull group at the end. Possible values are 'ignore', 'drop' or 'fill'.
|
|
fill_value: The value to fill into an underfull remaining group.
|
|
|
|
Returns:
|
|
A list containing the grouped values.
|
|
|
|
Example:
|
|
|
|
>>> group(3, "ABCDEFG")
|
|
['ABC', 'DEF', 'G']
|
|
>>> group(3, 'ABCDEFG', 'drop')
|
|
['ABC', 'DEF']
|
|
>>> group(3, 'ABCDEFG', 'fill', 'Z')
|
|
['ABC', 'DEF', 'GZZ']
|
|
>>> group(3, list('ABCDEFG'), 'fill')
|
|
[['A', 'B', 'C'], ['D', 'E', 'F'], ['G', None, None]]
|
|
>>> group(2, tuple('1234'), 'fill')
|
|
[('1', '2'), ('3', '4')]
|
|
"""
|
|
|
|
if underfull_action not in ['ignore', 'drop', 'fill']:
|
|
raise ValueError("group(): underfull_action must be either 'ignore', 'drop' or 'fill'")
|
|
|
|
fill: Any = fill_value
|
|
if underfull_action == 'fill':
|
|
if isinstance(lst, tuple):
|
|
fill = (fill_value,)
|
|
elif isinstance(lst, list):
|
|
fill = [fill_value]
|
|
elif isinstance(lst, (bytes, str)):
|
|
if not isinstance(fill_value, (bytes, str)):
|
|
raise ValueError("group(): cannot fill a string with a non-string")
|
|
else:
|
|
raise ValueError("group(): 'lst' must be either a tuple, list or string")
|
|
|
|
out: list[Any] = []
|
|
for i in range(0, len(lst), n):
|
|
chunk: Any = lst[i:i+n]
|
|
if len(chunk) < n:
|
|
if underfull_action == 'ignore':
|
|
pass
|
|
elif underfull_action == 'drop':
|
|
continue
|
|
else:
|
|
chunk = chunk + fill * (n - len(chunk))
|
|
out.append(chunk)
|
|
|
|
return out
|
|
|
|
def concat(l: list[list[Any]]) -> list[Any]:
|
|
"""concat(l) -> list
|
|
|
|
Concats a list of lists into a list.
|
|
|
|
Example:
|
|
|
|
>>> concat([[1, 2], [3]])
|
|
[1, 2, 3]
|
|
|
|
"""
|
|
|
|
res = []
|
|
for k in l:
|
|
res.extend(k)
|
|
|
|
return res
|
|
|
|
def concat_all(*args: Any) -> list[Any]:
|
|
"""concat_all(*args) -> list
|
|
|
|
Concats all the arguments together.
|
|
|
|
Example:
|
|
|
|
>>> concat_all(0, [1, (2, 3)], [([[4, 5, 6]])])
|
|
[0, 1, 2, 3, 4, 5, 6]
|
|
"""
|
|
|
|
def go(arg: Any, output: list[Any]) -> list[Any]:
|
|
if isinstance(arg, (tuple, list)):
|
|
for e in arg:
|
|
go(e, output)
|
|
else:
|
|
output.append(arg)
|
|
return output
|
|
|
|
return go(args, [])
|
|
|
|
def ordlist(s: str) -> list[int]:
|
|
"""ordlist(s) -> list
|
|
|
|
Turns a string into a list of the corresponding ascii values.
|
|
|
|
Example:
|
|
|
|
>>> ordlist("hello")
|
|
[104, 101, 108, 108, 111]
|
|
"""
|
|
return list(map(ord, s))
|
|
|
|
def unordlist(cs: list[int]) -> str:
|
|
"""unordlist(cs) -> str
|
|
|
|
Takes a list of ascii values and returns the corresponding string.
|
|
|
|
Example:
|
|
|
|
>>> unordlist([104, 101, 108, 108, 111])
|
|
'hello'
|
|
"""
|
|
return ''.join(chr(c) for c in cs)
|
|
|
|
def findall(haystack: Sequence[_T], needle: _T | Sequence[_T]) -> Generator[int, None, None]:
|
|
"""findall(l, e) -> l
|
|
|
|
Generate all indices of needle in haystack, using the
|
|
Knuth-Morris-Pratt algorithm.
|
|
|
|
Example:
|
|
|
|
>>> foo = findall([1,2,3,4,4,3,4,2,1], 4)
|
|
>>> next(foo)
|
|
3
|
|
>>> next(foo)
|
|
4
|
|
>>> next(foo)
|
|
6
|
|
>>> list(foo) # no more appearances
|
|
[]
|
|
>>> list(findall("aaabaaabc", "aab"))
|
|
[1, 5]
|
|
"""
|
|
def __kmp_table(W: Sequence[_T]) -> list[int]:
|
|
pos = 1
|
|
cnd = 0
|
|
T: list[int] = []
|
|
T.append(-1)
|
|
T.append(0)
|
|
while pos < len(W):
|
|
if W[pos] == W[cnd]:
|
|
cnd += 1
|
|
pos += 1
|
|
T.append(cnd)
|
|
elif cnd > 0:
|
|
cnd = T[cnd]
|
|
else:
|
|
pos += 1
|
|
T.append(0)
|
|
return T
|
|
|
|
def __kmp_search(S: Sequence[_T], W: Sequence[_T]) -> Generator[int, None, None]:
|
|
m = 0
|
|
i = 0
|
|
T = __kmp_table(W)
|
|
while m + i < len(S):
|
|
if S[m + i] == W[i]:
|
|
i += 1
|
|
if i == len(W):
|
|
yield m
|
|
m += i - T[i]
|
|
i = max(T[i], 0)
|
|
else:
|
|
m += i - T[i]
|
|
i = max(T[i], 0)
|
|
|
|
def __single_search(S: Sequence[_T], w: _T) -> Generator[int, None, None]:
|
|
for i, v in enumerate(S):
|
|
if v == w:
|
|
yield i
|
|
|
|
|
|
if not isinstance(needle, Sequence):
|
|
needle = [needle]
|
|
if len(needle) == 1:
|
|
return __single_search(haystack, needle[0])
|
|
else:
|
|
return __kmp_search(haystack, needle)
|