docs: def generate_docstring(operation_name):
          """Make a google-style docstring.
  
          This is used to generate help() output.
  
          """
  
          if operation_name in Operation._docstring_cache:
              return Operation._docstring_cache[operation_name]
  
          op = Operation.new_from_name(operation_name)
          if (op.get_flags() & _OPERATION_DEPRECATED) != 0:
              raise Error('No such operator.',
                          'operator "{0}" is deprecated'.format(operation_name))
  
          # we are only interested in non-deprecated args
          args = [[name, flags] for name, flags in op.get_args()
                  if not flags & _DEPRECATED]
  
          # find the first required input image arg, if any ... that will be self
          member_x = None
          for name, flags in args:
              if ((flags & _INPUT) != 0 and
                      (flags & _REQUIRED) != 0 and
                      op.get_typeof(name) == GValue.image_type):
                  member_x = name
                  break
  
          required_input = [name for name, flags in args
                            if (flags & _INPUT) != 0 and
                            (flags & _REQUIRED) != 0 and
                            name != member_x]
  
          optional_input = [name for name, flags in args
                            if (flags & _INPUT) != 0 and
                               (flags & _REQUIRED) == 0]
  
          required_output = [name for name, flags in args
                             if ((flags & _OUTPUT) != 0 and
                                 (flags & _REQUIRED) != 0) or
                                ((flags & _INPUT) != 0 and
                                 (flags & _REQUIRED) != 0 and
                                 (flags & _MODIFY) != 0)]
  
          optional_output = [name for name, flags in args
                             if (flags & _OUTPUT) != 0 and
                                (flags & _REQUIRED) == 0]
  
          description = op.get_description()
          result = description[0].upper() + description[1:] + ".\n\n"
          result += "Example:\n"
  
          result += "   " + ", ".join(required_output) + " = "
          if member_x is not None:
              result += member_x + "." + operation_name + "("
          else:
              result += "pyvips.Image." + operation_name + "("
  
          result += ", ".join(required_input)
          if len(optional_input) > 0 and len(required_input) > 0:
              result += ", "
          result += ", ".join([x + " = " +
                               GValue.gtype_to_python(op.get_typeof(x))
                               for x in optional_input])
          result += ")\n"
  
          def argstr(name):
              return (u'    {0} ({1}): {2}\n'.
                      format(name,
                             GValue.gtype_to_python(op.get_typeof(name)),
                             op.get_blurb(name)))
  
          result += "\nReturns:\n"
          for name in required_output:
              result += argstr(name)
  
          names = []
          if member_x is not None:
              names += [member_x]
          names += required_input
  
          result += "\nArgs:\n"
          for name in names:
              result += argstr(name)
  
          if len(optional_input) > 0:
              result += "\nKeyword args:\n"
              for name in optional_input:
                  result += argstr(name)
  
          if len(optional_output) > 0:
              result += "\nOther Parameters:\n"
              for name in optional_output:
                  result += argstr(name)
  
          result += "\nRaises:\n    :class:`.Error`\n"
  
          # add to cache to save building again
          Operation._docstring_cache[operation_name] = result
  
          return result