code: def _parse_signature(func):
      
      if hasattr(func, "im_func"):
          func = func.im_func
  
      # if we have a cached validator for this function, return it
      parse = _signature_cache.get(func)
      if parse is not None:
          return parse
  
      # inspect the function signature and collect all the information
      if hasattr(inspect, "getfullargspec"):
          tup = inspect.getfullargspec(func)
      else:
          tup = inspect.getargspec(func)
      positional, vararg_var, kwarg_var, defaults = tup[:4]
      defaults = defaults or ()
      arg_count = len(positional)
      arguments = []
      for idx, name in enumerate(positional):
          if isinstance(name, list):
              raise TypeError(
                  "cannot parse functions that unpack tuples in the function signature"
              )
          try:
              default = defaults[idx - arg_count]
          except IndexError:
              param = (name, False, None)
          else:
              param = (name, True, default)
          arguments.append(param)
      arguments = tuple(arguments)
  
      def parse(args, kwargs):
          new_args = []
          missing = []
          extra = {}
  
          # consume as many arguments as positional as possible
          for idx, (name, has_default, default) in enumerate(arguments):
              try:
                  new_args.append(args[idx])
              except IndexError:
                  try:
                      new_args.append(kwargs.pop(name))
                  except KeyError:
                      if has_default:
                          new_args.append(default)
                      else:
                          missing.append(name)
              else:
                  if name in kwargs:
                      extra[name] = kwargs.pop(name)
  
          # handle extra arguments
          extra_positional = args[arg_count:]
          if vararg_var is not None:
              new_args.extend(extra_positional)
              extra_positional = ()
          if kwargs and kwarg_var is None:
              extra.update(kwargs)
              kwargs = {}
  
          return (
              new_args,
              kwargs,
              missing,
              extra,
              extra_positional,
              arguments,
              vararg_var,
              kwarg_var,
          )
  
      _signature_cache[func] = parse
      return parse
docs: Return a signature object for the function.