code: def ensure_annotations(f):
      
  
      if f.__defaults__:
          for rpos, value in enumerate(f.__defaults__):
              pos = f.__code__.co_argcount - len(f.__defaults__) + rpos
              arg = f.__code__.co_varnames[pos]
              _check_default_argument(f, arg, value)
      if f.__kwdefaults__:
          for arg, value in f.__kwdefaults__.items():
              _check_default_argument(f, arg, value)
  
      arg_properties = []
      for pos, arg in enumerate(f.__code__.co_varnames):
          if pos >= f.__code__.co_argcount + f.__code__.co_kwonlyargcount:
              break
          elif arg in f.__annotations__:
              templ = f.__annotations__[arg]
              if pos >= f.__code__.co_argcount:
                  arg_properties.append((arg, templ, None))
              else:
                  arg_properties.append((arg, templ, pos))
  
      if 'return' in f.__annotations__:
          return_templ = f.__annotations__['return']
          return WrappedFunctionReturn(arg_properties, f, return_templ)
      else:
          return WrappedFunction(arg_properties, f)
docs: Decorator to be used on functions with annotations. Runs type checks to enforce annotations. Raises
      :class:`EnsureError` if any argument passed to *f* is not of the type specified by the annotation. Also raises
      :class:`EnsureError` if the return value of *f* is not of the type specified by the annotation. Examples:
  
      .. code-block:: python
  
          from ensure import ensure_annotations
  
          @ensure_annotations
          def f(x: int, y: float) -> float:
              return x+y
  
          print(f(1, y=2.2))
  
          >>> 3.2
  
          print(f(1, y=2))
  
          >>> ensure.EnsureError: Argument y of type <class 'int'> to
          <function f at 0x109b7c710> does not match annotation type <class 'float'>