"""Utilities for numeric operations."""
from __future__ import annotations
import ctypes
from typing import Optional
[docs]
int_8_max = (1 << 8) - 1
[docs]
int_16_max = (1 << 16) - 1
[docs]
int_32_max = (1 << 32) - 1
[docs]
int_64_max = (1 << 64) - 1
[docs]
def int_(s: Optional[str], falsy_as_none: bool = True) -> Optional[int]:
"""
Convert a string `s` to an integer. If `s` is `None` return `None`
instead of raising an exception.
Parameters
----------
s : str, optional
The string to convert.
falsy_as_none : bool, default=True
If `True` all falsy values of `s` (other than ``0``) will return
`None`, otherwise only `None` values will be passed through and
an exception will be raised.
Returns
-------
int, optional
`None` if `s` is `None`, otherwise an integer if `s` is not `None` and
is parseable.
Raises
------
ValueError
If the string cannot be parsed.
"""
# Note `int` strips whitespace
if falsy_as_none:
return int(s) if s else None
return int(s) if s is not None else None
[docs]
def float_(s: Optional[str], falsy_as_none: bool = True) -> Optional[float]:
"""
Convert a string `s` to a float. If `s` is `None` return `None`
instead of raising an exception.
Parameters
----------
s : str, optional
The string to convert.
falsy_as_none : bool, default=True
If `True` all falsy values of `s` will return `None` (other than ``0``),
otherwise only `None` values will be passed through and an exception
will be raised..
Returns
-------
float, optional
`None` if `s` is `None`, otherwise a float if `s` is not `None` and
is parseable.
Raises
------
ValueError
If the string cannot be parsed.
"""
if falsy_as_none:
return float(s) if s else None
return float(s) if s is not None else None
[docs]
def to_signed(value: int) -> int:
"""
If the value is positive, this will return a signed version of the number
that fits in the same size integer type. For example, ``129`` is a valid
8-bit signed integer, but a 16-bit unsigned integer. This method will
convert the number to the corresponding signed integer that still fits
in 8-bits. In this case ``127``.
Parameters
----------
value : int
The value to convert.
Returns
-------
int
The signed version.
Raises
------
ValueError
If the ``value`` is more than 64-bits.
"""
if value > int_64_max:
raise ValueError(f"Only 64-bit values or smaller are supported. Got: {value}")
if value <= 0:
return value
if value <= int_8_max:
return ctypes.c_int8(value).value
if value <= int_16_max:
return ctypes.c_int16(value).value
if value <= int_32_max:
return ctypes.c_int32(value).value
if value <= int_64_max:
return ctypes.c_int64(value).value