def test_getcallargs_forhints(self):
        def func(a, b_c, *d):
            return a, b_c, d

        self.assertEqual({
            'a': Any,
            'b_c': Any,
            'd': Tuple[Any, ...]
        }, getcallargs_forhints(func, *[Any, Any]))
        self.assertEqual(
            {
                'a': Any,
                'b_c': Any,
                'd': self.relax_for_py2(Tuple[Union[int, str], ...])
            }, getcallargs_forhints(func, *[Any, Any, str, int]))
        self.assertEqual(
            {
                'a': int,
                'b_c': Tuple[str, Any],
                'd': Tuple[Any, ...]
            }, getcallargs_forhints(func, *[int, Tuple[str, Any]]))
        self.assertEqual(
            {
                'a': Any,
                'b_c': Any,
                'd': self.relax_for_py2(Tuple[str, ...])
            }, getcallargs_forhints(func, *[Any, Any, Tuple[str, ...]]))
        self.assertEqual(
            {
                'a': Any,
                'b_c': Any,
                'd': self.relax_for_py2(Tuple[Union[Tuple[str, ...], int],
                                              ...])
            }, getcallargs_forhints(func, *[Any, Any, Tuple[str, ...], int]))
  def type_check_inputs(self, pvalueish):
    type_hints = self.get_type_hints().input_types
    if type_hints:
      args, kwargs = self.raw_side_inputs

      def element_type(side_input):
        if isinstance(side_input, pvalue.AsSideInput):
          return side_input.element_type
        return instance_to_type(side_input)

      arg_types = [pvalueish.element_type] + [element_type(v) for v in args]
      kwargs_types = {k: element_type(v) for (k, v) in kwargs.items()}
      argspec_fn = self._process_argspec_fn()
      bindings = getcallargs_forhints(argspec_fn, *arg_types, **kwargs_types)
      hints = getcallargs_forhints(argspec_fn, *type_hints[0], **type_hints[1])
      for arg, hint in hints.items():
        if arg.startswith('%unknown%'):
          continue
        if hint is None:
          continue
        if not typehints.is_consistent_with(
            bindings.get(arg, typehints.Any), hint):
          raise TypeCheckError(
              'Type hint violation for \'%s\': requires %s but got %s for %s'
              % (self.label, hint, bindings[arg], arg))
Exemple #3
0
    def type_check_inputs(self, pvalueish):
        type_hints = self.get_type_hints().input_types
        if type_hints:
            args, kwargs = self.raw_side_inputs

            def element_type(side_input):
                if isinstance(side_input, pvalue.AsSideInput):
                    return side_input.element_type
                return instance_to_type(side_input)

            arg_types = [pvalueish.element_type
                         ] + [element_type(v) for v in args]
            kwargs_types = {k: element_type(v) for (k, v) in kwargs.items()}
            argspec_fn = self._process_argspec_fn()
            bindings = getcallargs_forhints(argspec_fn, *arg_types,
                                            **kwargs_types)
            hints = getcallargs_forhints(argspec_fn, *type_hints[0],
                                         **type_hints[1])
            for arg, hint in hints.items():
                if arg.startswith('%unknown%'):
                    continue
                if hint is None:
                    continue
                if not typehints.is_consistent_with(
                        bindings.get(arg, typehints.Any), hint):
                    raise TypeCheckError(
                        'Type hint violation for \'%s\': requires %s but got %s for %s'
                        % (self.label, hint, bindings[arg], arg))
Exemple #4
0
    def type_check_inputs(self, pvalueish):
        type_hints = self.get_type_hints()
        input_types = type_hints.input_types
        if input_types:
            args, kwargs = self.raw_side_inputs

            def element_type(side_input):
                if isinstance(side_input, pvalue.AsSideInput):
                    return side_input.element_type
                return instance_to_type(side_input)

            arg_types = [pvalueish.element_type
                         ] + [element_type(v) for v in args]
            kwargs_types = {k: element_type(v) for (k, v) in kwargs.items()}
            argspec_fn = self._process_argspec_fn()
            bindings = getcallargs_forhints(argspec_fn, *arg_types,
                                            **kwargs_types)
            hints = getcallargs_forhints(argspec_fn, *input_types[0],
                                         **input_types[1])
            for arg, hint in hints.items():
                if arg.startswith('__unknown__'):
                    continue
                if hint is None:
                    continue
                if not typehints.is_consistent_with(
                        bindings.get(arg, typehints.Any), hint):
                    raise TypeCheckError(
                        'Type hint violation for \'{label}\': requires {hint} but got '
                        '{actual_type} for {arg}\nFull type hint:\n{debug_str}'
                        .format(label=self.label,
                                hint=hint,
                                actual_type=bindings[arg],
                                arg=arg,
                                debug_str=type_hints.debug_str()))
  def test_getcallargs_forhints_varkw(self):
    def func(a, b_c, *d, **e):
      return a, b_c, d, e

    self.assertEqual({
        'a': Any,
        'b_c': Any,
        'd': Tuple[Any, ...],
        'e': Dict[str, Union[str, int]]
    },
                     getcallargs_forhints(
                         func, *[Any, Any], **{
                             'kw1': str, 'kw2': int
                         }))
    self.assertEqual({
        'a': Any,
        'b_c': Any,
        'd': Tuple[Any, ...],
        'e': Dict[str, Union[str, int]]
    },
                     getcallargs_forhints(
                         func, *[Any, Any], e=Dict[str, Union[int, str]]))
    self.assertEqual(
        {
            'a': Any,
            'b_c': Any,
            'd': Tuple[Any, ...],
            'e': Dict[str, Dict[str, Union[str, int]]]
        },
        # keyword is not 'e', thus the Dict is considered a value hint.
        getcallargs_forhints(func, *[Any, Any], kw1=Dict[str, Union[int, str]]))
Exemple #6
0
  def test_getcallargs_forhints_missing_arg(self):
    def fn(a, b=None, *args, foo, **kwargs):
      return a, b, args, foo, kwargs

    with self.assertRaisesRegex(decorators.TypeCheckError, "missing.*'a'"):
      decorators.getcallargs_forhints(fn, foo=List[int])
    with self.assertRaisesRegex(decorators.TypeCheckError, "missing.*'foo'"):
      decorators.getcallargs_forhints(fn, 5)
Exemple #7
0
 def test_getcallargs_forhints(self):
   func = lambda a, (b, c), *d: None
   self.assertEquals(
       {'a': Any, 'b': Any, 'c': Any, 'd': Tuple[Any, ...]},
       getcallargs_forhints(func, *[Any, Any]))
   self.assertEquals(
       {'a': Any, 'b': Any, 'c': Any, 'd': Tuple[Any, ...]},
       getcallargs_forhints(func, *[Any, Any, Any, int]))
   self.assertEquals(
       {'a': int, 'b': str, 'c': Any, 'd': Tuple[Any, ...]},
       getcallargs_forhints(func, *[int, Tuple[str, Any]]))
 def test_getcallargs_forhints(self):
   func = lambda a, (b, c), *d: None
   self.assertEquals(
       {'a': Any, 'b': Any, 'c': Any, 'd': Tuple[Any, ...]},
       getcallargs_forhints(func, *[Any, Any]))
   self.assertEquals(
       {'a': Any, 'b': Any, 'c': Any, 'd': Tuple[Any, ...]},
       getcallargs_forhints(func, *[Any, Any, Any, int]))
   self.assertEquals(
       {'a': int, 'b': str, 'c': Any, 'd': Tuple[Any, ...]},
       getcallargs_forhints(func, *[int, Tuple[str, Any]]))
 def test_getcallargs_forhints(self):
   def func(a, b_c, *d):
     b, c = b_c # pylint: disable=unused-variable
     return None
   self.assertEquals(
       {'a': Any, 'b_c': Any, 'd': Tuple[Any, ...]},
       getcallargs_forhints(func, *[Any, Any]))
   self.assertEquals(
       {'a': Any, 'b_c': Any, 'd': Tuple[Any, ...]},
       getcallargs_forhints(func, *[Any, Any, Any, int]))
   self.assertEquals(
       {'a': int, 'b_c': Tuple[str, Any], 'd': Tuple[Any, ...]},
       getcallargs_forhints(func, *[int, Tuple[str, Any]]))
Exemple #10
0
 def __init__(self, dofn, type_hints, label=None):
   super(TypeCheckWrapperDoFn, self).__init__(dofn)
   self._process_fn = self.dofn._process_argspec_fn()
   if type_hints.input_types:
     input_args, input_kwargs = type_hints.input_types
     self._input_hints = getcallargs_forhints(
         self._process_fn, *input_args, **input_kwargs)
   else:
     self._input_hints = None
   # TODO(robertwb): Multi-output.
   self._output_type_hint = type_hints.simple_output_type(label)
 def __init__(self, dofn, type_hints, label=None):
   super(TypeCheckWrapperDoFn, self).__init__(dofn)
   self._process_fn = self.dofn._process_argspec_fn()
   if type_hints.input_types:
     input_args, input_kwargs = type_hints.input_types
     self._input_hints = getcallargs_forhints(
         self._process_fn, *input_args, **input_kwargs)
   else:
     self._input_hints = None
   # TODO(robertwb): Multi-output.
   self._output_type_hint = type_hints.simple_output_type(label)
Exemple #12
0
 def test_getcallargs_forhints(self):
   def fn(a: int, b: str = None, *args: Tuple[T], foo: List[int],
          **kwargs: Dict[str, str]) -> Tuple[Any, ...]:
     return a, b, args, foo, kwargs
   callargs = decorators.getcallargs_forhints(fn, float, foo=List[str])
   self.assertDictEqual(callargs,
                        {'a': float,
                         'b': str,
                         'args': Tuple[T],
                         'foo': List[str],
                         'kwargs': Dict[str, str]})
Exemple #13
0
 def test_getcallargs_forhints_default_arg(self):
   # Default args are not necessarily types, so they should be ignored.
   def fn(a=List[int], b=None, *args, foo=(), **kwargs) -> Tuple[Any, ...]:
     return a, b, args, foo, kwargs
   callargs = decorators.getcallargs_forhints(fn)
   self.assertDictEqual(callargs,
                        {'a': Any,
                         'b': Any,
                         'args': Tuple[Any, ...],
                         'foo': Any,
                         'kwargs': Dict[Any, Any]})
    def test_getcallargs_forhints(self):
        def func(a, b_c, *d):
            b, c = b_c  # pylint: disable=unused-variable
            return None

        self.assertEqual({
            'a': Any,
            'b_c': Any,
            'd': Tuple[Any, ...]
        }, getcallargs_forhints(func, *[Any, Any]))
        self.assertEqual({
            'a': Any,
            'b_c': Any,
            'd': Tuple[Any, ...]
        }, getcallargs_forhints(func, *[Any, Any, Any, int]))
        self.assertEqual(
            {
                'a': int,
                'b_c': Tuple[str, Any],
                'd': Tuple[Any, ...]
            }, getcallargs_forhints(func, *[int, Tuple[str, Any]]))
 def test_getcallargs_forhints_builtins(self):
     if sys.version_info < (3, 7):
         # Signatures for builtins are not supported in 3.5 and 3.6.
         self.assertEqual(
             {
                 '_': str,
                 '__unknown__varargs': Tuple[Any, ...],
                 '__unknown__keywords': typehints.Dict[Any, Any]
             }, getcallargs_forhints(str.upper, str))
         self.assertEqual(
             {
                 '_': str,
                 '__unknown__varargs': Tuple[str, ...],
                 '__unknown__keywords': typehints.Dict[Any, Any]
             }, getcallargs_forhints(str.strip, str, str))
         self.assertEqual(
             {
                 '_': str,
                 '__unknown__varargs': Tuple[typehints.List[int], ...],
                 '__unknown__keywords': typehints.Dict[Any, Any]
             }, getcallargs_forhints(str.join, str, typehints.List[int]))
     else:
         self.assertEqual({'self': str},
                          getcallargs_forhints(str.upper, str))
         # str.strip has an optional second argument.
         self.assertEqual({
             'self': str,
             'chars': Any
         }, getcallargs_forhints(str.strip, str))
         self.assertEqual({
             'self': str,
             'iterable': typehints.List[int]
         }, getcallargs_forhints(str.join, str, typehints.List[int]))
Exemple #16
0
def test_monkey_patch_signature(f, args, kwargs):
    arg_types = [instance_to_type(v) for v in args]
    kwargs_types = {k: instance_to_type(v) for (k, v) in kwargs.items()}
    f_temp = _wrap_task_call(f)
    try:
        getcallargs_forhints(f, *arg_types, **kwargs_types)
    except Exception:
        print("Failed on {} with parameters {}, {}".format(f, args, kwargs))
        raise
    try:
        getcallargs_forhints(f_temp, *arg_types, **kwargs_types)
    except Exception:
        print("Failed on {} with parameters {}, {}".format(
            f_temp, args, kwargs))
        raise
    try:
        expected_signature = inspect.signature(f)
        test_signature = inspect.signature(f_temp)
        assert (expected_signature == test_signature
                ), "Failed on {}, signature {} does not match {}".format(
                    f, expected_signature, test_signature)
    except Exception:
        # expected to pass for py2.7
        pass
Exemple #17
0
 def __init__(self, dofn, type_hints, label=None):
   super(TypeCheckWrapperDoFn, self).__init__()
   self._dofn = dofn
   self._label = label
   self._process_fn = self._dofn.process_argspec_fn()
   if type_hints.input_types:
     input_args, input_kwargs = type_hints.input_types
     self._input_hints = getcallargs_forhints(
         self._process_fn, *input_args, **input_kwargs)
   else:
     self._input_hints = None
   # TODO(robertwb): Actually extract this.
   self.context_var = 'context'
   # TODO(robertwb): Multi-output.
   self._output_type_hint = type_hints.simple_output_type(label)
Exemple #18
0
 def wrapper(*args, **kwargs):
   hints = get_type_hints(f)
   if hints.input_types:
     input_hints = getcallargs_forhints(
         f, *hints.input_types[0], **hints.input_types[1])
     inputs = inspect.getcallargs(f, *args, **kwargs)
     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(inspect.getargspec(f).args):
             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)
Exemple #19
0
 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 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 = inspect.getcallargs(f, *args, **kwargs)
     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(getfullargspec(f).args):
             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)