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 type_check_inputs_or_outputs(self, pvalueish, input_or_output): hints = getattr(self.get_type_hints(), input_or_output + '_types') if not hints: return arg_hints, kwarg_hints = hints if arg_hints and kwarg_hints: raise TypeCheckError( 'PTransform cannot have both positional and keyword type hints ' 'without overriding %s._type_check_%s()' % (self.__class__, input_or_output)) root_hint = (arg_hints[0] if len(arg_hints) == 1 else arg_hints or kwarg_hints) for context, pvalue_, hint in _ZipPValues().visit( pvalueish, root_hint): if pvalue_.element_type is None: # TODO(robertwb): It's a bug that we ever get here. (typecheck) continue if hint and not typehints.is_consistent_with( pvalue_.element_type, hint): at_context = ' %s %s' % (input_or_output, context) if context else '' raise TypeCheckError( '%s type hint violation at %s%s: expected %s, got %s' % (input_or_output.title(), self.label, at_context, hint, pvalue_.element_type))
def type_check_inputs_or_outputs(self, pvalueish, input_or_output): type_hints = self.get_type_hints() hints = getattr(type_hints, input_or_output + '_types') if hints is None or not any(hints): return arg_hints, kwarg_hints = hints if arg_hints and kwarg_hints: raise TypeCheckError( 'PTransform cannot have both positional and keyword type hints ' 'without overriding %s._type_check_%s()' % (self.__class__, input_or_output)) root_hint = (arg_hints[0] if len(arg_hints) == 1 else arg_hints or kwarg_hints) for context, pvalue_, hint in _ZipPValues().visit( pvalueish, root_hint): if isinstance(pvalue_, DoOutputsTuple): continue if pvalue_.element_type is None: # TODO(robertwb): It's a bug that we ever get here. (typecheck) continue if hint and not typehints.is_consistent_with( pvalue_.element_type, hint): at_context = ' %s %s' % (input_or_output, context) if context else '' raise TypeCheckError( '{type} type hint violation at {label}{context}: expected {hint}, ' 'got {actual_type}\nFull type hint:\n{debug_str}'.format( type=input_or_output.title(), label=self.label, context=at_context, hint=hint, actual_type=pvalue_.element_type, debug_str=type_hints.debug_str()))
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))
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))
def test_hint_helper(self): self.assertTrue(is_consistent_with(Any, int)) self.assertTrue(is_consistent_with(int, Any)) self.assertTrue(is_consistent_with(str, object)) self.assertFalse(is_consistent_with(object, str)) self.assertTrue(is_consistent_with(str, Union[str, int])) self.assertFalse(is_consistent_with(Union[str, int], str))
def test_hint_helper(self): self.assertTrue(is_consistent_with(Any, int)) self.assertTrue(is_consistent_with(int, Any)) self.assertTrue(is_consistent_with(str, object)) self.assertFalse(is_consistent_with(object, str)) self.assertTrue(is_consistent_with(str, Union[str, int])) self.assertFalse(is_consistent_with(Union[str, int], str))
def _unpack_positional_arg_hints(arg, hint): """Unpacks the given hint according to the nested structure of arg. For example, if arg is [[a, b], c] and hint is Tuple[Any, int], then this function would return ((Any, Any), int) so it can be used in conjunction with inspect.getcallargs. """ if isinstance(arg, list): tuple_constraint = typehints.Tuple[[typehints.Any] * len(arg)] if not typehints.is_consistent_with(hint, tuple_constraint): raise TypeCheckError('Bad tuple arguments for %s: expected %s, got %s' % (arg, tuple_constraint, hint)) if isinstance(hint, typehints.TupleConstraint): return tuple(_unpack_positional_arg_hints(a, t) for a, t in zip(arg, hint.tuple_types)) return (typehints.Any,) * len(arg) return hint
def _unpack_positional_arg_hints(arg, hint): """Unpacks the given hint according to the nested structure of arg. For example, if arg is [[a, b], c] and hint is Tuple[Any, int], than this function would return ((Any, Any), int) so it can be used in conjunction with inspect.getcallargs. """ if isinstance(arg, list): tuple_constraint = typehints.Tuple[[typehints.Any] * len(arg)] if not typehints.is_consistent_with(hint, tuple_constraint): raise TypeCheckError('Bad tuple arguments for %s: expected %s, got %s' % (arg, tuple_constraint, hint)) if isinstance(hint, typehints.TupleConstraint): return tuple(_unpack_positional_arg_hints(a, t) for a, t in zip(arg, hint.tuple_types)) return (typehints.Any,) * len(arg) return hint
def type_check_inputs_or_outputs(self, pvalueish, input_or_output): hints = getattr(self.get_type_hints(), input_or_output + '_types') if not hints: return arg_hints, kwarg_hints = hints if arg_hints and kwarg_hints: raise TypeCheckError( 'PTransform cannot have both positional and keyword type hints ' 'without overriding %s._type_check_%s()' % ( self.__class__, input_or_output)) root_hint = ( arg_hints[0] if len(arg_hints) == 1 else arg_hints or kwarg_hints) for context, pvalue_, hint in _ZipPValues().visit(pvalueish, root_hint): if pvalue_.element_type is None: # TODO(robertwb): It's a bug that we ever get here. (typecheck) continue if hint and not typehints.is_consistent_with(pvalue_.element_type, hint): at_context = ' %s %s' % (input_or_output, context) if context else '' raise TypeCheckError( '%s type hint violation at %s%s: expected %s, got %s' % ( input_or_output.title(), self.label, at_context, hint, pvalue_.element_type))
def assertNotCompatible(self, base, sub): # pylint: disable=invalid-name self.assertFalse(is_consistent_with(sub, base), '%s is consistent with %s' % (sub, base))
def assertNotCompatible(self, base, sub): # pylint: disable=invalid-name base, sub = native_type_compatibility.convert_to_beam_type([base, sub]) self.assertFalse(is_consistent_with(sub, base), '%s is consistent with %s' % (sub, base))
def assertCompatible(self, base, sub): # pylint: disable=invalid-name self.assertTrue( is_consistent_with(sub, base), '%s is not consistent with %s' % (sub, base))
def _consistent_with_check_(self, sub): return (isinstance(sub, self.__class__) and typehints.is_consistent_with(sub.key_type, self.key_type))