diff options
Diffstat (limited to 'gi/docstring.py')
-rw-r--r-- | gi/docstring.py | 181 |
1 files changed, 140 insertions, 41 deletions
diff --git a/gi/docstring.py b/gi/docstring.py index 713bb6e..08bcef9 100644 --- a/gi/docstring.py +++ b/gi/docstring.py @@ -23,9 +23,11 @@ from ._gi import \ VFuncInfo, \ FunctionInfo, \ - DIRECTION_IN, \ - DIRECTION_OUT, \ - DIRECTION_INOUT + CallableInfo, \ + ObjectInfo, \ + StructInfo, \ + Direction, \ + TypeTag #: Module storage for currently registered doc string generator function. @@ -35,21 +37,26 @@ _generate_doc_string_func = None def set_doc_string_generator(func): """Set doc string generator function - :Parameters: - func : callable - Function which takes a GIInfoStruct and returns - documentation for it. + :param callable func: + Callable which takes a GIInfoStruct and returns documentation for it. """ global _generate_doc_string_func _generate_doc_string_func = func def get_doc_string_generator(): + """Returns the currently registered doc string generator.""" return _generate_doc_string_func def generate_doc_string(info): - """Generator a doc string given a GIInfoStruct + """Generate a doc string given a GIInfoStruct. + + :param gi.types.BaseInfo info: + GI info instance to generate documentation for. + :returns: + Generated documentation as a string. + :rtype: str This passes the info struct to the currently registered doc string generator and returns the result. @@ -57,50 +64,142 @@ def generate_doc_string(info): return _generate_doc_string_func(info) -def split_function_info_args(info): - """Split a functions args into a tuple of two lists. - - Note that args marked as DIRECTION_INOUT will be in both lists. - - :Returns: - Tuple of (in_args, out_args) - """ - in_args = [] - out_args = [] - for arg in info.get_arguments(): - direction = arg.get_direction() - if direction in (DIRECTION_IN, DIRECTION_INOUT): - in_args.append(arg) - if direction in (DIRECTION_OUT, DIRECTION_INOUT): - out_args.append(arg) - return (in_args, out_args) - - -def _generate_callable_info_function_signature(info): - """Default doc string generator""" - in_args, out_args = split_function_info_args(info) +_type_tag_to_py_type = {TypeTag.BOOLEAN: bool, + TypeTag.INT8: int, + TypeTag.UINT8: int, + TypeTag.INT16: int, + TypeTag.UINT16: int, + TypeTag.INT32: int, + TypeTag.UINT32: int, + TypeTag.INT64: int, + TypeTag.UINT64: int, + TypeTag.FLOAT: float, + TypeTag.DOUBLE: float, + TypeTag.GLIST: list, + TypeTag.GSLIST: list, + TypeTag.ARRAY: list, + TypeTag.GHASH: dict, + TypeTag.UTF8: str, + TypeTag.FILENAME: str, + TypeTag.UNICHAR: str, + TypeTag.INTERFACE: None, + TypeTag.GTYPE: None, + TypeTag.ERROR: None, + TypeTag.VOID: None, + } + + +def _get_pytype_hint(gi_type): + type_tag = gi_type.get_tag() + py_type = _type_tag_to_py_type.get(type_tag, None) + + if py_type and hasattr(py_type, '__name__'): + return py_type.__name__ + elif type_tag == TypeTag.INTERFACE: + iface = gi_type.get_interface() + + info_name = iface.get_name() + if not info_name: + return gi_type.get_tag_as_string() + + return '%s.%s' % (iface.get_namespace(), info_name) + + return gi_type.get_tag_as_string() + + +def _generate_callable_info_doc(info): in_args_strs = [] if isinstance(info, VFuncInfo): in_args_strs = ['self'] elif isinstance(info, FunctionInfo): if info.is_method(): in_args_strs = ['self'] - elif info.is_constructor(): - in_args_strs = ['cls'] - for arg in in_args: - argstr = arg.get_name() + ':' + arg.get_pytype_hint() - if arg.is_optional(): + args = info.get_arguments() + hint_blacklist = ('void',) + + # Build lists of indices prior to adding the docs because it is possible + # the index retrieved comes before input arguments being used. + ignore_indices = {info.get_return_type().get_array_length()} + user_data_indices = set() + for arg in args: + ignore_indices.add(arg.get_destroy()) + ignore_indices.add(arg.get_type().get_array_length()) + user_data_indices.add(arg.get_closure()) + + # Build input argument strings + for i, arg in enumerate(args): + if arg.get_direction() == Direction.OUT: + continue # skip exclusively output args + if i in ignore_indices: + continue + argstr = arg.get_name() + hint = _get_pytype_hint(arg.get_type()) + if hint not in hint_blacklist: + argstr += ':' + hint + if arg.may_be_null() or i in user_data_indices: + # allow-none or user_data from a closure + argstr += '=None' + elif arg.is_optional(): argstr += '=<optional>' in_args_strs.append(argstr) in_args_str = ', '.join(in_args_strs) - if out_args: - out_args_str = ', '.join(arg.get_name() + ':' + arg.get_pytype_hint() - for arg in out_args) - return '%s(%s) -> %s' % (info.get_name(), in_args_str, out_args_str) + # Build return + output argument strings + out_args_strs = [] + return_hint = _get_pytype_hint(info.get_return_type()) + if not info.skip_return() and return_hint and return_hint not in hint_blacklist: + argstr = return_hint + if info.may_return_null(): + argstr += ' or None' + out_args_strs.append(argstr) + + for i, arg in enumerate(args): + if arg.get_direction() == Direction.IN: + continue # skip exclusively input args + if i in ignore_indices: + continue + argstr = arg.get_name() + hint = _get_pytype_hint(arg.get_type()) + if hint not in hint_blacklist: + argstr += ':' + hint + out_args_strs.append(argstr) + + if out_args_strs: + return '%s(%s) -> %s' % (info.__name__, in_args_str, ', '.join(out_args_strs)) + else: + return '%s(%s)' % (info.__name__, in_args_str) + + +def _generate_class_info_doc(info): + header = '\n:Constructors:\n\n::\n\n' # start with \n to avoid auto indent of other lines + doc = '' + + if isinstance(info, StructInfo): + # Don't show default constructor for disguised (0 length) structs + if info.get_size() > 0: + doc += ' ' + info.get_name() + '()\n' else: - return '%s(%s)' % (info.get_name(), in_args_str) + doc += ' ' + info.get_name() + '(**properties)\n' + + for method_info in info.get_methods(): + if method_info.is_constructor(): + doc += ' ' + _generate_callable_info_doc(method_info) + '\n' + + if doc: + return header + doc + else: + return '' + + +def _generate_doc_dispatch(info): + if isinstance(info, (ObjectInfo, StructInfo)): + return _generate_class_info_doc(info) + + elif isinstance(info, CallableInfo): + return _generate_callable_info_doc(info) + + return '' -set_doc_string_generator(_generate_callable_info_function_signature) +set_doc_string_generator(_generate_doc_dispatch) |