add
This commit is contained in:
188
ccxt/static_dependencies/ethereum/utils/humanize.py
Normal file
188
ccxt/static_dependencies/ethereum/utils/humanize.py
Normal file
@@ -0,0 +1,188 @@
|
||||
from typing import (
|
||||
Any,
|
||||
Iterable,
|
||||
Iterator,
|
||||
Tuple,
|
||||
Union,
|
||||
)
|
||||
from urllib import (
|
||||
parse,
|
||||
)
|
||||
|
||||
from ..typing import (
|
||||
URI,
|
||||
Hash32,
|
||||
)
|
||||
|
||||
from .currency import (
|
||||
denoms,
|
||||
from_wei,
|
||||
)
|
||||
|
||||
from .toolz import (
|
||||
sliding_window,
|
||||
take,
|
||||
)
|
||||
|
||||
|
||||
def humanize_seconds(seconds: Union[float, int]) -> str:
|
||||
if int(seconds) == 0:
|
||||
return "0s"
|
||||
|
||||
unit_values = _consume_leading_zero_units(_humanize_seconds(int(seconds)))
|
||||
|
||||
return "".join((f"{amount}{unit}" for amount, unit in take(3, unit_values)))
|
||||
|
||||
|
||||
SECOND = 1
|
||||
MINUTE = 60
|
||||
HOUR = 60 * 60
|
||||
DAY = 24 * HOUR
|
||||
YEAR = 365 * DAY
|
||||
MONTH = YEAR // 12
|
||||
WEEK = 7 * DAY
|
||||
|
||||
|
||||
UNITS = (
|
||||
(YEAR, "y"),
|
||||
(MONTH, "m"),
|
||||
(WEEK, "w"),
|
||||
(DAY, "d"),
|
||||
(HOUR, "h"),
|
||||
(MINUTE, "m"),
|
||||
(SECOND, "s"),
|
||||
)
|
||||
|
||||
|
||||
def _consume_leading_zero_units(
|
||||
units_iter: Iterator[Tuple[int, str]]
|
||||
) -> Iterator[Tuple[int, str]]:
|
||||
for amount, unit in units_iter:
|
||||
if amount == 0:
|
||||
continue
|
||||
else:
|
||||
yield (amount, unit)
|
||||
break
|
||||
|
||||
yield from units_iter
|
||||
|
||||
|
||||
def _humanize_seconds(seconds: int) -> Iterator[Tuple[int, str]]:
|
||||
remainder = seconds
|
||||
|
||||
for duration, unit in UNITS:
|
||||
if not remainder:
|
||||
break
|
||||
|
||||
num = remainder // duration
|
||||
yield num, unit
|
||||
|
||||
remainder %= duration
|
||||
|
||||
|
||||
DISPLAY_HASH_CHARS = 4
|
||||
|
||||
|
||||
def humanize_bytes(value: bytes) -> str:
|
||||
if len(value) <= DISPLAY_HASH_CHARS + 1:
|
||||
return value.hex()
|
||||
value_as_hex = value.hex()
|
||||
head = value_as_hex[:DISPLAY_HASH_CHARS]
|
||||
tail = value_as_hex[-1 * DISPLAY_HASH_CHARS :]
|
||||
return f"{head}..{tail}"
|
||||
|
||||
|
||||
def humanize_hash(value: Hash32) -> str:
|
||||
return humanize_bytes(value)
|
||||
|
||||
|
||||
def humanize_ipfs_uri(uri: URI) -> str:
|
||||
if not is_ipfs_uri(uri):
|
||||
raise TypeError(
|
||||
f"{uri} does not look like a valid IPFS uri. Currently, "
|
||||
"only CIDv0 hash schemes are supported."
|
||||
)
|
||||
|
||||
parsed = parse.urlparse(uri)
|
||||
ipfs_hash = parsed.netloc
|
||||
head = ipfs_hash[:DISPLAY_HASH_CHARS]
|
||||
tail = ipfs_hash[-1 * DISPLAY_HASH_CHARS :]
|
||||
return f"ipfs://{head}..{tail}"
|
||||
|
||||
|
||||
def is_ipfs_uri(value: Any) -> bool:
|
||||
if not isinstance(value, str):
|
||||
return False
|
||||
|
||||
parsed = parse.urlparse(value)
|
||||
if parsed.scheme != "ipfs" or not parsed.netloc:
|
||||
return False
|
||||
|
||||
return _is_CIDv0_ipfs_hash(parsed.netloc)
|
||||
|
||||
|
||||
def _is_CIDv0_ipfs_hash(ipfs_hash: str) -> bool:
|
||||
if ipfs_hash.startswith("Qm") and len(ipfs_hash) == 46:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _find_breakpoints(*values: int) -> Iterator[int]:
|
||||
yield 0
|
||||
for index, (left, right) in enumerate(sliding_window(2, values), 1):
|
||||
if left + 1 == right:
|
||||
continue
|
||||
else:
|
||||
yield index
|
||||
yield len(values)
|
||||
|
||||
|
||||
def _extract_integer_ranges(*values: int) -> Iterator[Tuple[int, int]]:
|
||||
"""
|
||||
Return a tuple of consecutive ranges of integers.
|
||||
|
||||
:param values: a sequence of ordered integers
|
||||
|
||||
- fn(1, 2, 3) -> ((1, 3),)
|
||||
- fn(1, 2, 3, 7, 8, 9) -> ((1, 3), (7, 9))
|
||||
- fn(1, 7, 8, 9) -> ((1, 1), (7, 9))
|
||||
"""
|
||||
for left, right in sliding_window(2, _find_breakpoints(*values)):
|
||||
chunk = values[left:right]
|
||||
yield chunk[0], chunk[-1]
|
||||
|
||||
|
||||
def _humanize_range(bounds: Tuple[int, int]) -> str:
|
||||
left, right = bounds
|
||||
if left == right:
|
||||
return str(left)
|
||||
else:
|
||||
return f"{left}-{right}"
|
||||
|
||||
|
||||
def humanize_integer_sequence(values_iter: Iterable[int]) -> str:
|
||||
"""
|
||||
Return a concise, human-readable string representing a sequence of integers.
|
||||
|
||||
- fn((1, 2, 3)) -> '1-3'
|
||||
- fn((1, 2, 3, 7, 8, 9)) -> '1-3|7-9'
|
||||
- fn((1, 2, 3, 5, 7, 8, 9)) -> '1-3|5|7-9'
|
||||
- fn((1, 7, 8, 9)) -> '1|7-9'
|
||||
"""
|
||||
values = tuple(values_iter)
|
||||
if not values:
|
||||
return "(empty)"
|
||||
else:
|
||||
return "|".join(map(_humanize_range, _extract_integer_ranges(*values)))
|
||||
|
||||
|
||||
def humanize_wei(number: int) -> str:
|
||||
if number >= denoms.finney:
|
||||
unit = "ether"
|
||||
elif number >= denoms.mwei:
|
||||
unit = "gwei"
|
||||
else:
|
||||
unit = "wei"
|
||||
amount = from_wei(number, unit)
|
||||
x = f"{str(amount)} {unit}"
|
||||
return x
|
||||
Reference in New Issue
Block a user