def __init__(self, fset, fcall, out_dtype=None): """Initialize a new instance. Parameters ---------- fset : `FunctionSet` The set of functions this element lives in fcall : `callable` The actual instruction for out-of-place evaluation. It must return an `FunctionSet.range` element or a `numpy.ndarray` of such (vectorized call). out_d """ self._space = fset super().__init__(self._space.domain, self._space.range, linear=False) # Determine which type of implementation fcall is if isinstance(fcall, FunctionSetVector): call_has_out, call_out_optional, _ = _dispatch_call_args( bound_call=fcall._call) # Numpy Ufuncs and similar objects (e.g. Numba DUfuncs) elif hasattr(fcall, 'nin') and hasattr(fcall, 'nout'): if fcall.nin != 1: raise ValueError('ufunc {} has {} input parameter(s), ' 'expected 1' ''.format(fcall.__name__, fcall.nin)) if fcall.nout > 1: raise ValueError('ufunc {} has {} output parameter(s), ' 'expected at most 1' ''.format(fcall.__name__, fcall.nout)) call_has_out = call_out_optional = (fcall.nout == 1) elif isfunction(fcall): call_has_out, call_out_optional, _ = _dispatch_call_args( unbound_call=fcall) elif callable(fcall): call_has_out, call_out_optional, _ = _dispatch_call_args( bound_call=fcall.__call__) else: raise TypeError('type {!r} not callable') self._call_has_out = call_has_out self._call_out_optional = call_out_optional if not call_has_out: # Out-of-place only self._call_in_place = preload_first_arg(self, 'in-place')( _default_in_place) self._call_out_of_place = fcall elif call_out_optional: # Dual-use self._call_in_place = self._call_out_of_place = fcall else: # In-place only self._call_in_place = fcall # The default out-of-place method needs to guess the data # type, so we need a separate decorator to help it. self._call_out_of_place = preload_first_arg(self, 'out-of-place')( _default_out_of_place)
def test_dispatch_call_args(func): # Unbound functions true_has, true_opt = eval(func.__doc__.splitlines()[1].strip()) good = func.__doc__.splitlines()[2].strip() == 'good' if good: truespec = getargspec(func) truespec.args.insert(0, 'self') has, opt, spec = _dispatch_call_args(unbound_call=func) assert has == true_has assert opt == true_opt assert spec == truespec else: with pytest.raises(ValueError): _dispatch_call_args(unbound_call=func)
def test_dispatch_call_args_class(): # Two sneaky classes whose _call method would pass the signature check class WithStaticMethod(object): @staticmethod def _call(x, y, out): pass class WithClassMethod(object): @classmethod def _call(cls, x, out=None): pass with pytest.raises(TypeError): _dispatch_call_args(cls=WithStaticMethod) with pytest.raises(TypeError): _dispatch_call_args(cls=WithClassMethod)
def test_dispatch_call_args(func): import inspect py3 = sys.version_info.major > 2 getspec = inspect.getfullargspec if py3 else inspect.getargspec # Unbound functions true_has, true_opt = eval(func.__doc__.splitlines()[1].strip()) good = func.__doc__.splitlines()[2].strip() == 'good' if good: truespec = getspec(func) truespec.args.insert(0, 'self') has, opt, spec = _dispatch_call_args(unbound_call=func) assert has == true_has assert opt == true_opt assert spec == truespec else: with pytest.raises(ValueError): _dispatch_call_args(unbound_call=func)