def test_get_signature(self): # Basic coverage only to make sure function works in Py2 and Py3. def fn(a, b=1, *c, **d): return a, b, c, d s = decorators.get_signature(fn) self.assertListEqual(list(s.parameters), ['a', 'b', 'c', 'd'])
def test_get_signature_builtin(self): # Tests a builtin function for 3.7+ and fallback result for older versions. s = decorators.get_signature(list) if sys.version_info < (3, 7): self.assertListEqual( list(s.parameters), ['_', '__unknown__varargs', '__unknown__keywords']) else: self.assertListEqual(list(s.parameters), ['iterable']) self.assertEqual(s.return_annotation, List[Any])
def fn_takes_side_inputs(fn): try: signature = get_signature(fn) except TypeError: # We can't tell; maybe it does. return True return ( len(signature.parameters) > 1 or any( p.kind == p.VAR_POSITIONAL or p.kind == p.VAR_KEYWORD for p in signature.parameters.values()))
def _run_repeat_test_bad(self, repeat): # Various mismatches. with self.assertRaises(typehints.TypeCheckError): ['a', 'bb', 'c'] | beam.Map(repeat, 'z') with self.assertRaises(typehints.TypeCheckError): ['a', 'bb', 'c'] | beam.Map(repeat, times='z') with self.assertRaises(typehints.TypeCheckError): ['a', 'bb', 'c'] | beam.Map(repeat, 3, 4) if all(param.default == param.empty for param in get_signature(repeat).parameters.values()): with self.assertRaisesRegex(typehints.TypeCheckError, r'(takes exactly|missing a required)'): ['a', 'bb', 'c'] | beam.Map(repeat)
def wrapper(*args, **kwargs): hints = get_type_hints(f) if hints.input_types: # pylint: disable=too-many-nested-blocks input_hints = getcallargs_forhints( f, *hints.input_types[0], **hints.input_types[1]) inputs = get_signature(f).bind(*args, **kwargs).arguments for var, hint in input_hints.items(): value = inputs[var] new_value = check_or_interleave(hint, value, var) if new_value is not value: if var in kwargs: kwargs[var] = new_value else: args = list(args) for ix, pvar in enumerate(get_signature(f).parameters): if pvar == var: args[ix] = new_value break else: raise NotImplementedError('Iterable in nested argument %s' % var) res = f(*args, **kwargs) return check_or_interleave(hints.simple_output_type('typecheck'), res, None)
def expand(self, pcoll): # Since the PTransform will be implemented entirely as a function # (once called), we need to pass through any type-hinting information that # may have been annotated via the .with_input_types() and # .with_output_types() methods. kwargs = dict(self._kwargs) args = tuple(self._args) # TODO(BEAM-5878) Support keyword-only arguments. try: if 'type_hints' in get_signature(self._fn).parameters: args = (self.get_type_hints(), ) + args except TypeError: # Might not be a function. pass return self._fn(pcoll, *args, **kwargs)