Source code for Stoner.tools.tests

# -*- coding: utf-8 -*-
"""Utility functions that test whether things are true or not."""

__all__ = [
    "all_size",
    "all_type",
    "isanynone",
    "isComparable",
    "isiterable",
    "isLikeList",
    "isnone",
    "isproperty",
    "isTuple",
    "isclass",
]
from typing import Optional, Iterable as IterableType, Tuple, Union, Any

from collections.abc import Iterable
from numpy import ndarray, dtype, isnan, logical_and  # pylint: disable=redefined-builtin

from ..compat import string_types
from ..core.Typing import NumericArray


[docs]def all_size(iterator: IterableType, size: Optional[Union[int, Tuple]] = None) -> bool: """Check whether each element of *iterator* is the same length/shape. Arguments: iterator (Iterable): list or other iterable of things with a length or shape Keyword Arguments: size(int, tuple or None): Required size of each item in iterator. Returns: True if all objects are the size specified (or the same size if size is None). """ if hasattr(iterator[0], "shape"): sizer = lambda x: x.shape else: sizer = len if size is None: size = sizer(iterator[0]) ret = False for i in iterator: if sizer(i) != size: break else: ret = True return ret
[docs]def all_type(iterator: IterableType, typ: type) -> bool: """Determine if an interable omnly contains a common type. Arguments: iterator (Iterable): The object to check if it is all iterable typ (class): The type to check for. Returns: True if all elements are of the type typ, or False if not. Notes: Routine will iterate the *iterator* and break when an element is not of the search type *typ*. """ ret = False if isinstance(iterator, ndarray): # Try to short circuit for arrays try: return iterator.dtype == dtype(typ) except TypeError: pass if isiterable(iterator): for i in iterator: if not isinstance(i, typ): break else: ret = True return ret
[docs]def isanynone(*args: Any) -> bool: """Intelligently check whether any of the inputs are None.""" for arg in args: if arg is None: return True return False
[docs]def isComparable(v1: NumericArray, v2: NumericArray) -> bool: """Return true if v1 and v2 can be compared sensibly. Args: v1,v2 (any): Two values to compare Returns: False if both v1 and v2 are numerical and both nan, otherwise True. """ try: return not (isnan(v1) and isnan(v2)) except TypeError: return True except ValueError: try: return not logical_and(isnan(v1), isnan(v2)).any() except TypeError: return False
[docs]def isiterable(value: Any) -> bool: """Chack to see if a value is iterable. Args: value : Entity to check if it is iterable Returns: (bool): True if value is an instance of collections.Iterable. """ return isinstance(value, Iterable)
[docs]def isLikeList(value: Any) -> bool: """Return True if value is an iterable but not a string.""" return isiterable(value) and not isinstance(value, string_types)
[docs]def isnone(iterator: Optional[IterableType]) -> bool: """Return True if input is None or an empty iterator, or an iterator of None. Args: iterator (None or Iterable): Returns: True if iterator is None, empty or full of None. """ if iterator is None: ret = True elif isiterable(iterator) and not isinstance(iterator, string_types): try: l = len(iterator) except TypeError: l = 0 if l == 0: # pylint: disable=len-as-condition ret = True else: for i in iterator: if i is not None: ret = False break else: ret = True else: ret = False return ret
[docs]def isproperty(obj: Any, name: str) -> bool: """Check whether an attribute of an object or class is a property. Args: obj (instance or class): Thing that has the attribute to check name (str): Name of the attribute that might be a property Returns: (bool): Whether the name is a property or not. """ if not isinstance(obj, type): obj = type(obj) elif not issubclass(obj, object): raise TypeError(f"Can only check for property status on attributes of an object or a class not a {type(obj)}") return hasattr(obj, name) and isinstance(getattr(obj, name), property)
[docs]def isTuple(obj: Any, *args: type, strict: bool = True) -> bool: """Determine if obj is a tuple of a certain signature. Args: obj(object): The object to check *args(type): Each of the succeeding arguments are used to determine the expected type of each element. Keywoprd Arguments: strict(bool): Whether the elements of the tuple have to be exactly the type specified or just castable as the type Returns: (bool): True if obj is a matching tuple. """ if not isinstance(obj, tuple): return False if args and len(obj) != len(args): return False for t, e in zip(args, obj): if strict: if not isinstance(e, t): bad = True break else: try: _ = t(e) except ValueError: bad = True break else: bad = False return not bad
[docs]def isclass(obj, cls): """Check whether obj is a class and if so whether it is a subclass of cls.""" return obj is not None and isinstance(obj, type) and issubclass(obj, cls)