Module transformnd.util
Utilities used elsewhere in the package.
Expand source code
"""Utilities used elsewhere in the package."""
from collections import deque
from typing import (
Any,
Callable,
Deque,
Hashable,
Iterable,
Iterator,
Optional,
Set,
Tuple,
)
import numpy as np
UNSPECIFIED_SPACE_NAME = "???"
TransformSignature = Callable[[np.ndarray], np.ndarray]
"""Type annotation of a function which can be used as a transform."""
SpaceRef = Hashable
"""Type annotation of things which can be used to refer to spaces"""
def none_eq(a: Optional[Any], b: Optional[Any]) -> bool:
"""Check whether either is None or both are equal.
Parameters
----------
a : Optional[Any]
b : Optional[Any]
Returns
-------
bool
"""
return a == b or a is None or b is None
NO_DEFAULT = object()
def chain_or(*args: Optional[Any], default=NO_DEFAULT):
"""Return the first of *args which is not None.
Can either error or return a default if there are no non-None args.
Parameters
----------
default : any, optional
By default, raises a ValueError if *args are exhausted.
If given, returns the given value instead.
Returns
-------
Any
One of the given args, or the default.
Raises
------
ValueError
If `default` is not given and there are no non-None args.
"""
for arg in args:
if arg is not None:
return arg
if default is NO_DEFAULT:
raise ValueError("No non-None arguments")
return default
def same_or_none(*args, default=NO_DEFAULT):
"""Check args are the same or None.
If so, return the non-None value.
Otherwise, raise a ValueError.
Parameters
----------
default : Any, optional
If given, return this instead of an error
if all *args are None.
Returns
-------
Any
The non-None arg value.
Raises
------
ValueError
Arguments are not None, or the same.
ValueError
No non-None arguments found and no default given.
"""
prev = None
for arg in args:
if arg is None:
continue
if prev is not None and prev != arg:
raise ValueError("Arguments are not None or the same")
prev = arg
if prev is None:
if default is NO_DEFAULT:
raise ValueError("No non-None arguments found")
return default
return prev
def window(iterable: Iterable, length: int) -> Iterator[Tuple[Any, ...]]:
"""Sliding window over iterable.
e.g. `(it[0], it[1]), (it[1], it[2]), (it[2], it[3]), ...`
Parameters
----------
iterable : Iterable
length : int
Length of windows to return.
Yields
-------
Tuple[Any, ...]
"""
it = iter(iterable)
q: Deque[Any] = deque(maxlen=length)
for _ in range(length):
try:
item = next(it)
except StopIteration:
return
q.append(item)
yield tuple(q)
for item in it:
q.append(item)
yield tuple(q)
def check_ndim(given_ndim: int, supported_ndim: Optional[Set[int]]):
"""Raise a ValueError if dimensionality is unsupported.
Parameters
----------
given_ndim : int
The dimensionality to check.
supported_ndim : Optional[Set[int]]
Which dimensions are supported.
If None, the check passes.
Raises
------
ValueError
If supported dimensions are defined and given_ndim is not in them.
"""
if supported_ndim is not None and given_ndim not in supported_ndim:
raise ValueError(
f"Transform supported for {format_dims(supported_ndim)}, not {given_ndim}"
)
def format_dims(supported):
"""Format supported dimensions for e.g. error messages.
Parameters
----------
supported : Iterable[int]
The supported dimensions.
Returns
-------
str
e.g. "2D/3D/4D"
"""
if supported is None:
return "ND"
if not len(supported):
return "nullD"
return "/".join(f"{d}D" for d in sorted(supported))
def space_str(space: Optional[SpaceRef]):
if space is None:
return UNSPECIFIED_SPACE_NAME
else:
return str(space)
def is_square(arr: np.ndarray) -> bool:
return arr.ndim == 2 and arr.shape[0] == arr.shape[1]
def dim_intersection(dims1: Optional[Set[int]], dims2: Optional[Set[int]]):
if dims1 is None:
return dims2
elif dims2 is None:
return dims1
else:
return dims1.intersection(dims2)
Global variables
var SpaceRef-
Type annotation of things which can be used to refer to spaces
var TransformSignature-
Type annotation of a function which can be used as a transform.
Functions
def chain_or(*args: Optional[Any], default=<object object>)-
Return the first of *args which is not None.
Can either error or return a default if there are no non-None args.
Parameters
default:any, optional- By default, raises a ValueError if *args are exhausted. If given, returns the given value instead.
Returns
Any- One of the given args, or the default.
Raises
ValueError- If
defaultis not given and there are no non-None args.
Expand source code
def chain_or(*args: Optional[Any], default=NO_DEFAULT): """Return the first of *args which is not None. Can either error or return a default if there are no non-None args. Parameters ---------- default : any, optional By default, raises a ValueError if *args are exhausted. If given, returns the given value instead. Returns ------- Any One of the given args, or the default. Raises ------ ValueError If `default` is not given and there are no non-None args. """ for arg in args: if arg is not None: return arg if default is NO_DEFAULT: raise ValueError("No non-None arguments") return default def check_ndim(given_ndim: int, supported_ndim: Optional[Set[int]])-
Raise a ValueError if dimensionality is unsupported.
Parameters
given_ndim:int- The dimensionality to check.
supported_ndim:Optional[Set[int]]- Which dimensions are supported. If None, the check passes.
Raises
ValueError- If supported dimensions are defined and given_ndim is not in them.
Expand source code
def check_ndim(given_ndim: int, supported_ndim: Optional[Set[int]]): """Raise a ValueError if dimensionality is unsupported. Parameters ---------- given_ndim : int The dimensionality to check. supported_ndim : Optional[Set[int]] Which dimensions are supported. If None, the check passes. Raises ------ ValueError If supported dimensions are defined and given_ndim is not in them. """ if supported_ndim is not None and given_ndim not in supported_ndim: raise ValueError( f"Transform supported for {format_dims(supported_ndim)}, not {given_ndim}" ) def dim_intersection(dims1: Optional[Set[int]], dims2: Optional[Set[int]])-
Expand source code
def dim_intersection(dims1: Optional[Set[int]], dims2: Optional[Set[int]]): if dims1 is None: return dims2 elif dims2 is None: return dims1 else: return dims1.intersection(dims2) def format_dims(supported)-
Format supported dimensions for e.g. error messages.
Parameters
supported:Iterable[int]- The supported dimensions.
Returns
str- e.g. "2D/3D/4D"
Expand source code
def format_dims(supported): """Format supported dimensions for e.g. error messages. Parameters ---------- supported : Iterable[int] The supported dimensions. Returns ------- str e.g. "2D/3D/4D" """ if supported is None: return "ND" if not len(supported): return "nullD" return "/".join(f"{d}D" for d in sorted(supported)) def is_square(arr: numpy.ndarray) ‑> bool-
Expand source code
def is_square(arr: np.ndarray) -> bool: return arr.ndim == 2 and arr.shape[0] == arr.shape[1] def none_eq(a: Optional[Any], b: Optional[Any]) ‑> bool-
Check whether either is None or both are equal.
Parameters
a:Optional[Any]b:Optional[Any]
Returns
bool
Expand source code
def none_eq(a: Optional[Any], b: Optional[Any]) -> bool: """Check whether either is None or both are equal. Parameters ---------- a : Optional[Any] b : Optional[Any] Returns ------- bool """ return a == b or a is None or b is None def same_or_none(*args, default=<object object>)-
Check args are the same or None.
If so, return the non-None value. Otherwise, raise a ValueError.
Parameters
default:Any, optional- If given, return this instead of an error if all *args are None.
Returns
Any- The non-None arg value.
Raises
ValueError- Arguments are not None, or the same.
ValueError- No non-None arguments found and no default given.
Expand source code
def same_or_none(*args, default=NO_DEFAULT): """Check args are the same or None. If so, return the non-None value. Otherwise, raise a ValueError. Parameters ---------- default : Any, optional If given, return this instead of an error if all *args are None. Returns ------- Any The non-None arg value. Raises ------ ValueError Arguments are not None, or the same. ValueError No non-None arguments found and no default given. """ prev = None for arg in args: if arg is None: continue if prev is not None and prev != arg: raise ValueError("Arguments are not None or the same") prev = arg if prev is None: if default is NO_DEFAULT: raise ValueError("No non-None arguments found") return default return prev def space_str(space: Optional[Hashable])-
Expand source code
def space_str(space: Optional[SpaceRef]): if space is None: return UNSPECIFIED_SPACE_NAME else: return str(space) def window(iterable: Iterable, length: int) ‑> Iterator[Tuple[Any, ...]]-
Sliding window over iterable.
e.g.
(it[0], it[1]), (it[1], it[2]), (it[2], it[3]), …Parameters
iterable:Iterablelength:int- Length of windows to return.
Yields
Tuple[Any, …]
Expand source code
def window(iterable: Iterable, length: int) -> Iterator[Tuple[Any, ...]]: """Sliding window over iterable. e.g. `(it[0], it[1]), (it[1], it[2]), (it[2], it[3]), ...` Parameters ---------- iterable : Iterable length : int Length of windows to return. Yields ------- Tuple[Any, ...] """ it = iter(iterable) q: Deque[Any] = deque(maxlen=length) for _ in range(length): try: item = next(it) except StopIteration: return q.append(item) yield tuple(q) for item in it: q.append(item) yield tuple(q)