From 05710171cb5cee8ee5ea6b37213b4a64b84dcf53 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 9 Oct 2020 11:56:11 +1100 Subject: PyDoc: resolve duplicate module warnings Remove submodule listings from the module docstring, as this information already exists in the generator. --- doc/python_api/sphinx_doc_gen.py | 74 +++++++++++++++++++++++++++++++--------- 1 file changed, 58 insertions(+), 16 deletions(-) (limited to 'doc/python_api/sphinx_doc_gen.py') diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py index 38cc9ea8528..29570fedad5 100644 --- a/doc/python_api/sphinx_doc_gen.py +++ b/doc/python_api/sphinx_doc_gen.py @@ -495,6 +495,13 @@ else: bpy_struct = None +def import_value_from_module(module_name, import_name): + ns = {} + exec_str = "from %s import %s as value" % (module_name, import_name) + exec(exec_str, ns, ns) + return ns["value"] + + def escape_rst(text): """ Escape plain text which may contain characters used by RST. """ @@ -749,7 +756,7 @@ def pyprop2sphinx(ident, fw, identifier, py_prop): fw(ident + " (readonly)\n\n") -def pymodule2sphinx(basepath, module_name, module, title): +def pymodule2sphinx(basepath, module_name, module, title, module_all_extra): import types attribute_set = set() filepath = os.path.join(basepath, module_name + ".rst") @@ -796,22 +803,25 @@ def pymodule2sphinx(basepath, module_name, module, title): fw(module.__doc__.strip()) fw("\n\n") - write_example_ref("", fw, module_name) - # write submodules # we could also scan files but this ensures __all__ is used correctly - if module_all is not None: + if module_all or module_all_extra: submod_name = None submod = None submod_ls = [] - for submod_name in module_all: - ns = {} - exec_str = "from %s import %s as submod" % (module.__name__, submod_name) - exec(exec_str, ns, ns) - submod = ns["submod"] + for submod_name in (module_all or ()): + submod = import_value_from_module(module_name, submod_name) if type(submod) == types.ModuleType: submod_ls.append((submod_name, submod)) + for submod_name in module_all_extra: + if submod_name in attribute_set: + continue + submod = import_value_from_module(module_name, submod_name) + # No type checks, since there are non-module types we treat as modules + # such as `bpy.app.translations` & `bpy.app.handlers`. + submod_ls.append((submod_name, submod)) + del submod_name del submod @@ -821,17 +831,22 @@ def pymodule2sphinx(basepath, module_name, module, title): for submod_name, submod in submod_ls: submod_name_full = "%s.%s" % (module_name, submod_name) - fw(" %s.rst\n\n" % submod_name_full) + fw(" %s.rst\n" % submod_name_full) - pymodule2sphinx(basepath, submod_name_full, submod, "%s submodule" % module_name) + pymodule2sphinx(basepath, submod_name_full, submod, "%s submodule" % module_name, ()) + fw("\n") del submod_ls # done writing submodules! + write_example_ref("", fw, module_name) + # write members of the module # only tested with PyStructs which are not exactly modules for key, descr in sorted(type(module).__dict__.items()): if key.startswith("__"): continue + if key in module_all_extra: + continue # naughty, we also add getset's into PyStructs, this is not typical py but also not incorrect. # type_name is only used for examples and messages @@ -854,6 +869,8 @@ def pymodule2sphinx(basepath, module_name, module, title): # sort by the valye type descr_sorted.sort(key=lambda descr_data: str(descr_data[3])) for key, descr, value, value_type in descr_sorted: + if key in module_all_extra: + continue # must be documented as a submodule if is_struct_seq(value): @@ -895,6 +912,9 @@ def pymodule2sphinx(basepath, module_name, module, title): module_dir_value_type.sort(key=lambda triple: str(triple[2])) for attribute, value, value_type in module_dir_value_type: + if attribute in module_all_extra: + continue + if value_type == FunctionType: pyfunc2sphinx("", fw, module_name, None, attribute, value, is_class=False) # both the same at the moment but to be future proof @@ -1895,7 +1915,7 @@ def write_rst_msgbus(basepath): file.close() # Write the contents. - pymodule2sphinx(basepath, 'bpy.msgbus', bpy.msgbus, 'Message Bus') + pymodule2sphinx(basepath, 'bpy.msgbus', bpy.msgbus, 'Message Bus', ()) EXAMPLE_SET_USED.add("bpy.msgbus") @@ -1947,6 +1967,7 @@ def write_rst_importable_modules(basepath): "gpu.select": "GPU Select", "gpu.shader": "GPU Shader", "bmesh": "BMesh Module", + "bmesh.ops": "BMesh Operators", "bmesh.types": "BMesh Types", "bmesh.utils": "BMesh Utilities", "bmesh.geometry": "BMesh Geometry Utilities", @@ -1972,11 +1993,32 @@ def write_rst_importable_modules(basepath): "freestyle.shaders": "Freestyle Shaders", "freestyle.utils": "Freestyle Utilities", } + + # This is needed since some of the sub-modules listed above are not actual modules. + # Examples include `bpy.app.translations` & `bpy.app.handlers`. + # + # Most of these are `PyStructSequence` internally, + # however we don't want to document all of these as modules since some only contain + # a few values (version number for e.g). + # + # If we remove this logic and document all `PyStructSequence` as sub-modules it means + # `bpy.app.timers` for example would be presented on the same level as library information + # access such as `bpy.app.sdl` which doesn't seem useful since it hides more useful + # module-like objects among library data access. + importable_modules_parent_map = {} + for mod_name in importable_modules.keys(): + if mod_name in EXCLUDE_MODULES: + continue + if "." in mod_name: + mod_name, submod_name = mod_name.rsplit(".", 1) + importable_modules_parent_map.setdefault(mod_name, []).append(submod_name) + for mod_name, mod_descr in importable_modules.items(): - if mod_name not in EXCLUDE_MODULES: - module = __import__(mod_name, - fromlist=[mod_name.rsplit(".", 1)[-1]]) - pymodule2sphinx(basepath, mod_name, module, mod_descr) + if mod_name in EXCLUDE_MODULES: + continue + module_all_extra = importable_modules_parent_map.get(mod_name, ()) + module = __import__(mod_name, fromlist=[mod_name.rsplit(".", 1)[-1]]) + pymodule2sphinx(basepath, mod_name, module, mod_descr, module_all_extra) def copy_handwritten_rsts(basepath): -- cgit v1.2.3