def check_strict_json_compat()

in tfx/dsl/component/experimental/json_compat.py [0:0]


def check_strict_json_compat(
    in_type: Any, expect_type: Type) -> bool:  # pylint: disable=g-bare-generic
  """Check if in_type conforms with expect_type.

  Args:
    in_type: Input type hint. It can be any JSON-compatible type. It can also be
    an instance.
    expect_type: Expected type hint. It can be any JSON-compatible type.

  Returns:
    True if in_type is valid w.r.t. expect_type.
  """
  check_instance = False
  if getattr(in_type, '__module__', None) not in {'typing', 'builtins'}:
    check_instance = True

  def _check(in_type: Any, expect_type: Type) -> bool:  # pylint: disable=g-bare-generic
    """Check if in_type conforms with expect_type."""
    if in_type is Any:
      return expect_type is Any
    elif expect_type is Any:
      return True

    in_obj = None
    if check_instance:
      in_obj, in_type = in_type, type(in_type)

    in_args = getattr(in_type, '__args__', ())
    in_origin = getattr(in_type, '__origin__', in_type)
    expect_args = getattr(expect_type, '__args__', ())
    expect_origin = getattr(expect_type, '__origin__', expect_type)

    if in_origin is Union:
      return all(_check(arg, expect_type) for arg in in_args)
    if expect_origin is Union:
      if check_instance:
        return any(_check(in_obj, arg) for arg in expect_args)
      else:
        return any(_check(in_type, arg) for arg in expect_args)

    if in_origin != expect_origin:
      return False
    elif in_origin in (
        dict, list
    ) and expect_args and expect_args[0].__class__.__name__ == 'TypeVar':
      return True
    elif check_instance:
      if isinstance(in_obj, list):
        return not expect_args or all(
            [_check(o, expect_args[0]) for o in in_obj])
      elif isinstance(in_obj, dict):
        return not expect_args or (
            all(_check(k, expect_args[0]) for k in in_obj.keys()) and
            all(_check(v, expect_args[1]) for v in in_obj.values()))
      else:
        return True
    # For List -> List[X] and Dict -> Dict[X, Y].
    elif len(in_args) < len(expect_args):
      return False
    # For Python 3.7, where Dict and List have args KT, KV, T. Return True
    # whenever the expect type is Dict or List.
    else:
      return all(_check(*arg) for arg in zip(in_args, expect_args))

  return _check(in_type, expect_type)