Add support for documenting bindings API directly in code

This commit is contained in:
baldurk
2017-03-24 15:46:57 +00:00
parent bfa1153a40
commit 5adce29b44
9 changed files with 181 additions and 2 deletions
+69 -1
View File
@@ -21,6 +21,15 @@ import os
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
import struct
if struct.calcsize("P") == 8:
modulepath = '../x64/Development'
else:
modulepath = '../Win32/Development'
sys.path.insert(0, os.path.abspath(modulepath))
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
@@ -29,7 +38,7 @@ import os
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = []
extensions = ['sphinx.ext.autodoc']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
@@ -301,3 +310,62 @@ html_context = {
if(tags.has('htmlhelp')):
print("**** We require sphinx 1.5 for htmlhelp build to have the fix for issue #2550 ****")
needs_sphinx = '1.5'
def maybe_skip_member(app, what, name, obj, skip, options):
# Hide these SWIG internals
if name == "this" or name == "thisown":
return True
# Allow hiding free module functions, or only showing free module functions
if 'exclude-members' in options and what == "module":
if 'free_functions__' in options['exclude-members'] and 'built-in function' in repr(obj):
return True
if 'non_free_functions__' in options['exclude-members'] and 'built-in function' not in repr(obj):
return True
# Allow hiding enum constant members (i.e. int constants). These can then be documented explicitly
# as we don't have a way in SWIG to attach docstrings to constants directly.
if 'exclude-members' in options and 'enum_constants__' in options['exclude-members'] and isinstance(obj, int):
return True
# Allow arbitrary globbing as a hack to exclude or include members
if 'exclude-members' in options:
for exclude in options['exclude-members']:
# Look for a hack that describes a name match
if exclude.startswith('name_match__'):
match = exclude.replace('name_match__', '')
include_only = False
# see if it wants to include only matches, or exclude matches (default)
if match.startswith('include_only__'):
match = match.replace('include_only__', '')
include_only = True
objname = ""
if '__qualname__' in dir(obj):
objname = obj.__qualname__
else:
try:
objname = obj.__name__
except AttributeError:
objname = obj.__class__.__name__
ismatch = False
# see if we're matching a prefix, or doing just a glob
if match.startswith('startswith__'):
match = match.replace('startswith__', '')
ismatch = objname.startswith(match)
if match.startswith('in__'):
match = match.replace('in__', '')
ismatch = match in objname
# if we want to include only matches and it didn't match, skip this
if include_only and not ismatch:
return True
# If we want to exclude matches and it DID match, skip
if not include_only and ismatch:
return True
return None
def setup(app):
app.connect('autodoc-skip-member', maybe_skip_member)
+1
View File
@@ -18,6 +18,7 @@ Table of Contents
:maxdepth: 2
introduction
python_api/index
in_application_api
credits_acknowledgements
getting_started/index
+9
View File
@@ -0,0 +1,9 @@
Enums and Data Structures
=========================
.. automodule:: renderdoc
:members:
:undoc-members:
:imported-members:
:exclude-members: free_functions__, str
+3
View File
@@ -0,0 +1,3 @@
Functions
=========
+8
View File
@@ -0,0 +1,8 @@
Python API
==========
.. toctree::
main_ifaces
funcs
enums_data
qrenderdoc
+4
View File
@@ -0,0 +1,4 @@
Primary Interfaces
==================
+8
View File
@@ -0,0 +1,8 @@
QRenderDoc
==========
.. automodule:: qrenderdoc
:members:
:undoc-members:
:imported-members:
+75 -1
View File
@@ -1,6 +1,6 @@
%module(docstring="This is the API to RenderDoc's internals.") renderdoc
%feature("autodoc");
%feature("autodoc", "0");
// just define linux platform to make sure things compile with no extra __declspec attributes
#define RENDERDOC_PLATFORM_LINUX
@@ -8,6 +8,9 @@
// we don't need these for the interface, they just confuse things
#define NO_ENUM_CLASS_OPERATORS
// use documentation for docstrings
#define DOCUMENT(text) %feature("docstring") text
// ignore warning about base class rdctype::array<char> methods in rdctype::str
#pragma SWIG nowarn=401
@@ -127,6 +130,9 @@
%rename(D3D12_ResourceData) D3D12Pipe::ResourceData;
%rename(D3D12_State) D3D12Pipe::State;
// strip off the RENDERDOC_ namespace prefix, it's unnecessary
%rename("%(strip:[RENDERDOC_])s") "";
%fragment("pyconvert", "header") {
static char convert_error[1024] = {};
@@ -279,3 +285,71 @@ PyObject *PassObjectToPython(const char *type, void *obj)
%}
%header %{
#include <set>
%}
%init %{
// verify that docstrings aren't duplicated, which is a symptom of missing DOCUMENT()
// macros around newly added classes/members.
#if !defined(RELEASE)
static bool doc_checked = false;
if(!doc_checked)
{
doc_checked = true;
std::set<std::string> docstrings;
for(size_t i=0; i < sizeof(swig_type_initial)/sizeof(swig_type_initial[0]); i++)
{
SwigPyClientData *typeinfo = (SwigPyClientData *)swig_type_initial[i]->clientdata;
// opaque types have no typeinfo, skip these
if(!typeinfo) continue;
PyTypeObject *typeobj = typeinfo->pytype;
std::string typedoc = typeobj->tp_doc;
auto result = docstrings.insert(typedoc);
if(!result.second)
{
snprintf(convert_error, sizeof(convert_error)-1, "Duplicate docstring '%s' found on struct '%s' - are you missing a DOCUMENT()?", typedoc.c_str(), typeobj->tp_name);
RENDERDOC_LogMessage(LogType::Fatal, "QTRD", __FILE__, __LINE__, convert_error);
}
PyMethodDef *method = typeobj->tp_methods;
while(method->ml_doc)
{
std::string typedoc = method->ml_doc;
size_t i = 0;
while(typedoc[i] == '\n')
i++;
// skip the first line as it's autodoc generated
i = typedoc.find('\n', i);
if(i != std::string::npos)
{
while(typedoc[i] == '\n')
i++;
typedoc.erase(0, i);
result = docstrings.insert(typedoc);
if(!result.second)
{
snprintf(convert_error, sizeof(convert_error)-1, "Duplicate docstring '%s' found on method '%s' - are you missing a DOCUMENT()?", typedoc.c_str(), method->ml_name);
RENDERDOC_LogMessage(LogType::Fatal, "QTRD", __FILE__, __LINE__, convert_error);
}
}
method++;
}
}
}
#endif
%}
+4
View File
@@ -40,6 +40,10 @@ inline const char *TypeName();
typedef uint8_t byte;
typedef uint32_t bool32;
#ifndef DOCUMENT
#define DOCUMENT(text)
#endif
#if defined(RENDERDOC_PLATFORM_WIN32)
#ifdef RENDERDOC_EXPORTS