docs: def opt_func(options, check_mandatory=True):
      """
      Restore argument checks for functions that takes options dicts as arguments
  
      Functions that take the option dictionary produced by :meth:`Options.parse`
      as `kwargs` loose the argument checking usually performed by the python
      interpretor. They also loose the ability to take default values for
      their keyword arguments. Such function is basically unusable without the
      full dictionary produced by the option parser.
  
      This is a decorator that restores argument checking and default values
      assignment on the basis of an :class:`Options` instance.
  
          options = Options([
              (0, "-f", "input",    str, 1, None, MULTI, "Input file"),
              (0, "-o", "output",   str, 1, None,    MA, "Output file"),
              (0, "-p", "topology", str, 1, None,     0, "Optional topology"),
          ])
  
          @opt_func(options)
          def process_things(**arguments):
              # Do something
              return
  
          # The function can be called with the arguments
          # from the argument parser
          arguments = options.parse()
          process_things(**arguments)
  
          # It can be called with only part of the arguments,
          # the other arguments will be set to their default as defined by
          # the Options instance
          process_things(output='output.gro')
  
          # If the function is called with an unknown argument, the decorator
          # raises a TypeError
          process_things(unknown=None)
  
          # Likewise, if the function is called without the mandatory arguments,
          # the decorator raises a TypeError
          process_things(topology='topology.top')
  
          # The check for mandatory arguments can be deactivated
          @opt_func(options, check_mandatory=False)
          def process_things(**arguments):
              # Do things
              return
  
      Note that the decorator cannot be used on functions that accept Other
      arguments than the one defined in the :class:`Options` instance. Also, the
      arguments have to be given as keyword arguments. Positional arguments
      will cause the decorator to raise a `TypeError`.
      """
      # A function `my_function` decorated with `opt_func` is replaced by
      # `opt_func(options)(my_function)`. This is equivalent to
      # `validate_arguments(my_function)` using the `options` argument provided
      # to the decorator. A call to `my_function` results in a call to
      # `opt_func(options)(my_function)(*args, **kwargs)`
      # ^^^^^^^^^^^^^^^^^^ validate_arguments
      # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ wrap
      def validate_arguments(func):
          @functools.wraps(func)
          def wrap(*args, **kwargs):
              if args:
                  raise TypeError('{0.__name__}() takes 0 positional arguments '
                                  'but {1} was given'.format(func, len(args)))
              keys = set(kwargs.keys())
              missing = options.mandatory_keys - keys
              if missing and check_mandatory:
                  raise TypeError('{0.__name__}() is missing the following '
                                  'mandatory keyword arguments: {1}'
                                  .format(func, ', '.join(missing)))
              arguments = options._default_dict()
              unknown = keys - set(arguments.keys())
              if unknown:
                  raise TypeError('{0.__name__}() received the following '
                                  'unexpected arguments: {1}'
                                  .format(func, ', '.join(unknown)))
              arguments.update(**kwargs)
              return func(**arguments)
          return wrap
      return validate_arguments