Source code for abipy.tools.duck

# coding: utf-8
"""Duck-typing tests"""
import collections
import warnings
import numpy as np


[docs]def is_string(s): """True if s behaves like a string (duck typing test).""" try: s + " " return True except Exception: return False
[docs]def is_intlike(obj): """ True if obj represents an integer (float such as 1.0 are included as well). """ # isinstance(i, numbers.Integral) try: # This to get rid of warnings about casting complex to real. if np.iscomplexobj(obj) and np.isreal(obj): return int(obj.real) == obj else: with warnings.catch_warnings(): warnings.simplefilter("ignore") return int(obj) == obj except (ValueError, TypeError): return False return False
[docs]def is_number_like(obj): """True if obj represents a number.""" try: obj - 1 return True except TypeError: return False
[docs]def is_listlike(obj): #if isinstance(branch, (list, tuple, np.ndarray)): if isinstance(obj, np.ndarray): return True if not isinstance(obj, collections.abc.Sequence): return False if is_string(obj): return False try: obj[:0] return True except TypeError: return False
[docs]def list_ints(arg): """ Always return a list of int, given a int or list of integers as input. :Examples: >>> list_ints(1) [1] """ l = np.array(arg, dtype=int) return [int(l)] if l.size == 1 else l.tolist()
[docs]def torange(obj): """ Convert obj into a range. Accepts integer, slice object or any object with an __iter__ method. Note that an integer is converted into range(int, int+1) >>> list(torange(1)) [1] >>> list(torange(slice(0, 4, 2))) [0, 2] >>> list(torange([1, 4, 2])) [1, 4, 2] """ if is_intlike(obj): return range(obj, obj + 1) elif isinstance(obj, slice): start = obj.start if obj.start is not None else 0 step = obj.step if obj.step is not None else 1 return range(start, obj.stop, step) else: try: return obj.__iter__() except Exception: raise TypeError("Don't know how to convert %s into a range object" % str(obj))
[docs]def as_slice(obj): """ Convert an integer, a string or a slice object into slice. >>> assert as_slice(5) == slice(5, 6, 1) >>> assert as_slice("[1:4]") == slice(1, 4, 1) >>> assert as_slice("1::2") == slice(1, None, 2) """ if isinstance(obj, slice) or obj is None: return obj try: # integer. if int(obj) == float(obj): return slice(int(obj), int(obj)+1, 1) except Exception: # assume string defining a python slice [start:stop:step] if not obj: return None if obj.count("[") + obj.count("]") not in (0, 2): raise ValueError("Invalid string %s" % obj) obj = obj.replace("[", "").replace("]", "") n = obj.count(":") if n == 0: obj = int(obj) return slice(obj, obj+1) tokens = [int(f) if f else None for f in obj.split(":")] if len(tokens) == 2: tokens.append(1) if tokens[2] is None: tokens[2] = 1 return slice(*tokens) raise ValueError("Cannot convert %s into a slice:\n%s" % (type(obj), obj))
[docs]class NoDefaultProvided(object): pass
[docs]def hasattrd(obj, name): """ The arguments are an object and a string. The result is True if the string is the name of one of the object’s attributes, False if not. Unlike the builtin hasattr, hasattrd supports dot notation e.g. hasattr(int, "__class__.__name__") (This is implemented by calling getattrd(object, name) and seeing whether it raises an exception or not.) """ try: getattrd(obj, name) return True except AttributeError: return False
[docs]def getattrd(obj, name, default=NoDefaultProvided): """ Same as getattr(), but allows dot notation lookup e.g. getattrd(obj, "a.b") Raises: AttributeError if ``name`` is not found and ``default`` is not given. Discussed in: http://stackoverflow.com/questions/11975781 """ from functools import reduce try: return reduce(getattr, name.split("."), obj) except AttributeError: if default is not NoDefaultProvided: return default raise