def type_match(src_type, tgt_type): """ Compares two type hints to see if they overlap. This does not require exact matches if the target type type_match( """ match = False if tgt_type == Any: match = True elif not issubclass(tgt_type.__class__, typing.GenericMeta): # if the target type is not a generic template, see if we have a subclass match match = issubclass(src_type, tgt_type) else: # check classes are the same match = src_type.__class__ == tgt_type.__class__ if match: src_origin = typing_inspect.get_last_origin(src_type) tgt_origin = typing_inspect.get_last_origin(tgt_type) match = typing_inspect.get_origin(Union[src_origin, tgt_origin]) != Union if not match: return False src_args = typing_inspect.get_last_args(src_type) tgt_args = typing_inspect.get_last_args(tgt_type) if len(tgt_args) == 0: return True if len(src_args) != len(tgt_args): return False for src_arg, tgt_arg in zip(src_args, tgt_args): if not type_match(src_arg, tgt_arg): return False return True
def test_last_origin(self): T = TypeVar('T') self.assertEqual(get_last_origin(int), None) self.assertEqual(get_last_origin(ClassVar[int]), None) self.assertEqual(get_last_origin(Generic[T]), Generic) self.assertEqual(get_last_origin(Union[T, int][str]), Union[T, int]) self.assertEqual(get_last_origin(List[Tuple[T, T]][int]), List[Tuple[T, T]]) self.assertEqual(get_last_origin(List), List)
def test_last_origin(self): T = TypeVar('T') self.assertEqual(get_last_origin(int), None) if WITH_CLASSVAR: self.assertEqual(get_last_origin(ClassVar[int]), None) self.assertEqual(get_last_origin(Generic[T]), Generic) if EXISTING_UNIONS_SUBSCRIPTABLE: self.assertEqual(get_last_origin(Union[T, int][str]), Union[T, int]) if GENERIC_TUPLE_PARAMETRIZABLE: tp = List[Tuple[T, T]][int] self.assertEqual(get_last_origin(tp), List[Tuple[T, T]]) self.assertEqual(get_last_origin(List), List)