directscripts: bring Python documentation generation up-to-date

Fixes #484
This commit is contained in:
rdb 2018-12-23 15:47:44 +01:00
parent a24c817144
commit c0c202a423
2 changed files with 82 additions and 52 deletions

View File

@ -665,7 +665,9 @@ EXCLUDE_SYMLINKS = NO
# for example use the pattern */test/* # for example use the pattern */test/*
EXCLUDE_PATTERNS = */Opt*-*/* \ EXCLUDE_PATTERNS = */Opt*-*/* \
*/CVS/* */CVS/* \
*/.git/* \
*/__pycache__/*
# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
# (namespaces, classes, functions, etc.) that should be excluded from the # (namespaces, classes, functions, etc.) that should be excluded from the

View File

@ -9,9 +9,20 @@ from __future__ import print_function
__all__ = [] __all__ = []
import os import os, sys
from distutils import sysconfig
import panda3d, pandac import panda3d, pandac
from panda3d.dtoolconfig import * from panda3d.interrogatedb import *
if 'interrogate_element_is_sequence' not in globals():
def interrogate_element_is_sequence(element):
return False
if 'interrogate_element_is_mapping' not in globals():
def interrogate_element_is_mapping(element):
return False
LICENSE = """PANDA 3D SOFTWARE LICENSE = """PANDA 3D SOFTWARE
Copyright (c) Carnegie Mellon University. All rights reserved. Copyright (c) Carnegie Mellon University. All rights reserved.
@ -19,6 +30,16 @@ All use of this software is subject to the terms of the revised BSD
license. You should have received a copy of this license along license. You should have received a copy of this license along
with this source code in a file named \"LICENSE.\"""".split("\n") with this source code in a file named \"LICENSE.\"""".split("\n")
MAINPAGE = """@mainpage Panda3D Python API Reference
Welcome to the Panda3D API reference.
Use the links at the top of this page to browse through the list of modules or
the list of classes.
This reference is automatically generated from comments in the source code.
"""
def comment(code): def comment(code):
if not code: if not code:
return "" return ""
@ -45,49 +66,16 @@ def comment(code):
return '' return ''
def block_comment(code): def block_comment(code):
if not code: code = code.strip()
if not code.startswith('///<') and '@verbatim' not in code:
code = code.replace('<', '\\<').replace('>', '\\>')
if not code or code[0] != '/':
# Not really a comment; get rid of it.
return "" return ""
lines = code.split("\n") return code
newlines = []
indent = 0
reading_desc = False
for line in lines:
if line.startswith("////"):
continue
line = line.rstrip()
strline = line.lstrip('/ \t')
if ':' in strline:
pre, post = strline.split(':', 1)
pre = pre.rstrip()
if pre == "Description":
strline = post.lstrip()
elif pre in ("Class", "Access", "Function", "Created by", "Enum"):
continue
if strline or len(newlines) > 0:
newlines.append('/// ' + strline)
#if reading_desc:
# newlines.append('/// ' + line[min(indent, len(line) - len(strline)):])
#else:
# # A "Description:" text starts the description.
# if strline.startswith("Description"):
# strline = strline[11:].lstrip(': \t')
# indent = len(line) - len(strline)
# reading_desc = True
# newlines.append('/// ' + strline)
# else:
# print line
newcode = '\n'.join(newlines)
if len(newcode) > 0:
return newcode
else:
return ""
def translateFunctionName(name): def translateFunctionName(name):
if name.startswith("__"): if name.startswith("__"):
@ -139,11 +127,17 @@ def translated_type_name(type, scoped=True):
return "object" return "object"
elif typename == "PN_stdfloat": elif typename == "PN_stdfloat":
return "float" return "float"
elif typename == "size_t":
return "int"
if interrogate_type_is_atomic(type): if interrogate_type_is_atomic(type):
token = interrogate_type_atomic_token(type) token = interrogate_type_atomic_token(type)
if token == 7: if token == 7:
return 'str' return 'str'
elif token == 8:
return 'long'
elif token == 9:
return 'NoneType'
else: else:
return typename return typename
@ -156,12 +150,25 @@ def translated_type_name(type, scoped=True):
else: else:
return typename return typename
def processElement(handle, element): def processElement(handle, element):
if interrogate_element_has_comment(element): if interrogate_element_has_comment(element):
print(comment(interrogate_element_comment(element)), file=handle) print(comment(interrogate_element_comment(element)), file=handle)
elif interrogate_element_has_getter(element):
# If the property has no comment, use the comment of the getter.
getter = interrogate_element_getter(element)
if interrogate_function_has_comment(getter):
print(block_comment(interrogate_function_comment(getter)), file=handle)
if interrogate_element_is_mapping(element) or \
interrogate_element_is_sequence(element):
suffix = "[]"
else:
suffix = ""
print(translated_type_name(interrogate_element_type(element)), end=' ', file=handle) print(translated_type_name(interrogate_element_type(element)), end=' ', file=handle)
print(interrogate_element_name(element) + ';', file=handle) print(interrogate_element_name(element) + suffix + ';', file=handle)
def processFunction(handle, function, isConstructor = False): def processFunction(handle, function, isConstructor = False):
for i_wrapper in range(interrogate_function_number_of_python_wrappers(function)): for i_wrapper in range(interrogate_function_number_of_python_wrappers(function)):
@ -195,6 +202,7 @@ def processFunction(handle, function, isConstructor = False):
print(");", file=handle) print(");", file=handle)
def processType(handle, type): def processType(handle, type):
typename = translated_type_name(type, scoped=False) typename = translated_type_name(type, scoped=False)
derivations = [ translated_type_name(interrogate_type_get_derivation(type, n)) for n in range(interrogate_type_number_of_derivations(type)) ] derivations = [ translated_type_name(interrogate_type_get_derivation(type, n)) for n in range(interrogate_type_number_of_derivations(type)) ]
@ -211,8 +219,10 @@ def processType(handle, type):
print(interrogate_type_enum_value_name(type, i_value), "=", interrogate_type_enum_value(type, i_value), ",", file=handle) print(interrogate_type_enum_value_name(type, i_value), "=", interrogate_type_enum_value(type, i_value), ",", file=handle)
elif interrogate_type_is_typedef(type): elif interrogate_type_is_typedef(type):
wrapped_type = translated_type_name(interrogate_type_wrapped_type(type)) wrapped_type = interrogate_type_wrapped_type(type)
print("typedef %s %s;" % (wrapped_type, typename), file=handle) if interrogate_type_is_global(wrapped_type):
wrapped_type_name = translated_type_name(wrapped_type)
print("typedef %s %s;" % (wrapped_type_name, typename), file=handle)
return return
else: else:
if interrogate_type_is_struct(type): if interrogate_type_is_struct(type):
@ -249,6 +259,7 @@ def processType(handle, type):
print("};", file=handle) print("};", file=handle)
def processModule(handle, package): def processModule(handle, package):
print("Processing module %s" % (package))
print("namespace %s {" % package, file=handle) print("namespace %s {" % package, file=handle)
if package != "core": if package != "core":
@ -280,22 +291,39 @@ def processModule(handle, package):
if __name__ == "__main__": if __name__ == "__main__":
handle = open("pandadoc.hpp", "w") handle = open("pandadoc.hpp", "w")
mainpage = MAINPAGE.strip()
if mainpage:
print("/**\n * " + mainpage.replace('\n', '\n * ') + '\n */', file=handle)
print(comment("Panda3D modules that are implemented in C++."), file=handle) print(comment("Panda3D modules that are implemented in C++."), file=handle)
print("namespace panda3d {", file=handle) print("namespace panda3d {", file=handle)
# Determine the path to the interrogatedb files # Determine the path to the interrogatedb files
interrogate_add_search_directory(os.path.join(os.path.dirname(pandac.__file__), "..", "..", "etc")) pandac = os.path.dirname(pandac.__file__)
interrogate_add_search_directory(os.path.join(os.path.dirname(pandac.__file__), "input")) interrogate_add_search_directory(os.path.join(pandac, "..", "..", "etc"))
interrogate_add_search_directory(os.path.join(pandac, "input"))
import panda3d.core import panda3d.core
processModule(handle, "core") processModule(handle, "core")
# Determine the suffix for the extension modules.
if sys.version_info >= (3, 0):
import _imp
ext_suffix = _imp.extension_suffixes()[0]
elif sys.platform == "win32":
ext_suffix = ".pyd"
else:
ext_suffix = ".so"
for lib in os.listdir(os.path.dirname(panda3d.__file__)): for lib in os.listdir(os.path.dirname(panda3d.__file__)):
if lib.endswith(('.pyd', '.so')) and not lib.startswith('core.'): if lib.endswith(ext_suffix) and not lib.startswith('core.'):
module_name = os.path.splitext(lib)[0] module_name = lib[:-len(ext_suffix)]
__import__("panda3d." + module_name) __import__("panda3d." + module_name)
processModule(handle, module_name) processModule(handle, module_name)
print("}", file=handle) print("}", file=handle)
handle.close() handle.close()
print("Wrote output to pandadoc.hpp. You can now run:")
print()
print(" doxygen built/direct/directscripts/Doxyfile.python")