Source code for gpi.docs

#!/usr/bin/env python

#    Copyright (C) 2014  Dignity Health
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Lesser General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Lesser General Public License for more details.
#
#    You should have received a copy of the GNU Lesser General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
#    NO CLINICAL USE.  THE SOFTWARE IS NOT INTENDED FOR COMMERCIAL PURPOSES
#    AND SHOULD BE USED ONLY FOR NON-COMMERCIAL RESEARCH PURPOSES.  THE
#    SOFTWARE MAY NOT IN ANY EVENT BE USED FOR ANY CLINICAL OR DIAGNOSTIC
#    PURPOSES.  YOU ACKNOWLEDGE AND AGREE THAT THE SOFTWARE IS NOT INTENDED FOR
#    USE IN ANY HIGH RISK OR STRICT LIABILITY ACTIVITY, INCLUDING BUT NOT
#    LIMITED TO LIFE SUPPORT OR EMERGENCY MEDICAL OPERATIONS OR USES.  LICENSOR
#    MAKES NO WARRANTY AND HAS NO LIABILITY ARISING FROM ANY USE OF THE
#    SOFTWARE IN ANY HIGH RISK OR STRICT LIABILITY ACTIVITIES.

PREFIX='/opt/anaconda1anaconda2anaconda3'

import os
import sys
import inspect

GPI_PKG=PREFIX
GPI_FRAMEWORK=GPI_PKG+'lib/'
sys.path.insert(0, GPI_FRAMEWORK) # gpi
sys.path.insert(0, GPI_PKG) # plugin

# for API related docs
from gpi import VERSION
from gpi import RELEASE_DATE
import gpi.nodeAPI
import gpi.widgets
import types
from types import *

# for node docs
from gpi.config import Config
from gpi.library import NodeCatalogItem
from gpi.catalog import Catalog
from gpi.defines import isGPIModFile


# Node docs
[docs]class NodeDocs(object): '''(Deprecated) For grabbing the Node documentation for of each node found in all connected libraries. This is used for listing all the nodes available. ''' def __init__(self): #self._docText = '\n\n'+34*'-'+' NODE DOCS '+35*'-'+'\n\n' self._docText = '' self._known_GPI_nodes = Catalog() for path in Config.GPI_LIBRARY_PATH: self.scanGPIModules(path, recursion_depth=2) self.extractDocs() def scanGPIModules(self, ipath, recursion_depth=1): ocnt = ipath.count('/') new_sys_paths = [] for path, dn, fn in os.walk(ipath): # TODO: instead of checking for hidden svn dirs, just choose any hidden dir if (path.count('/') - ocnt <= recursion_depth) and not path.count('/.svn'): for fil in os.listdir(path): fullpath = path+'/'+fil if isGPIModFile(fullpath): item = NodeCatalogItem(fullpath) item.load() # load check if item.valid(): self._known_GPI_nodes.append(item) else: print(("Failed to load: "+str(item))) def __str__(self): #return str(self._known_GPI_nodes) return self._docText def extractDocs(self): # look for ExternalNode cur_lib = '' cur_sub = '' for item in sorted(list(self._known_GPI_nodes.values()), key=lambda x: x.key().lower()): if hasattr(item.mod, 'ExternalNode'): cur_doc = str(inspect.getdoc(getattr(item.mod, 'ExternalNode'))) numSpaces = 4 cur_doc = "\n".join((numSpaces * " ") + i for i in cur_doc.splitlines()) #self._docText += '\n'+80*'*'+'\n' #self._docText += '\n\\subsection{'+str(item.key()).replace('_', '\_') +'}' + '\n\n' if item.third != cur_lib: self._docText += '\n# '+str(item.third)+'\n' cur_lib = item.third if item.second != cur_sub: self._docText += '\n## '+str(item.second)+'\n' cur_sub = item.second self._docText += '\n### '+str(item.name).replace('_', '\_') +'\n\n' #self._docText += '\n\\begin{lstlisting}\n' self._docText += str(cur_doc) self._docText += '\n\n' #self._docText += '\n\\end{lstlisting}\n' #self._docText += '\n'+80*'*'+'\n' else: print((str(item) + ' Doesnt have ExternalNode definition, skipping...'))
# API docs
[docs]class GPIdocs(object): '''(Deprecated) For gathering all the relevant API documentation used in Node development. ''' def __init__(self): self._docText = None self.parmList = [] self.generateHelpText() def __str__(self): #return str(self._known_GPI_nodes) return self._docText def generateHelpText(self): """Gather the __doc__ string of the ExternalNode derived class, all the set_ methods for each attached widget, and any attached GPI-types from each of the ports. """ # WIDGETS DOC # parm_doc = "" # contains parameter info wdg_doc = "\n\n# WIDGETS\n" # generic widget ref info wdg_doc += ''' \nThis is a list of widgets and their associated attributes to aid in parameterizing and declaring widget. ''' for name in dir(gpi.widgets): obj = getattr(gpi.widgets, name) if hasattr(obj, 'GPIWdgType'): self.parmList.append([name, obj]) # get the generic group to filter out base members generic_wdg = None for parm in self.parmList: if parm[0] == 'GenericWidgetGroup': generic_wdg = parm #print parm[1].__dict__ wdg_doc += "\n### " + parm[0] + "\n" numSpaces = 8 set_doc = "\n".join((" ") + i for i in str( parm[1].__doc__).splitlines()) wdg_doc += set_doc + "\n" wdg_doc += "attribute | type | description\n" wdg_doc += "--- | --- | ---\n" # set methods for member in dir(parm[1]): if member.startswith('set_'): #wdg_doc += (8 * " ") + member + inspect.formatargspec( # *inspect.getargspec(getattr(parm[1], member))) wdg_doc += (" ") + "" + member.split('set_')[1] + " | " set_doc = str(inspect.getdoc(getattr(parm[1], member))) numSpaces = 1 set_doc = " ".join(( numSpaces * " ") + i for i in set_doc.splitlines()) wdg_doc += "" + set_doc + "\n" # now do other members for parm in self.parmList: if parm[0] == 'GenericWidgetGroup': continue wdg_doc += "\n### " + parm[0] + "\n" numSpaces = 8 set_doc = "\n".join((" ") + i for i in str( parm[1].__doc__).splitlines()) wdg_doc += set_doc + "\n" wdg_doc += "attribute | type | description\n" wdg_doc += "--- | --- | ---\n" # set methods for member in dir(parm[1]): if member.startswith('set_'): if member not in generic_wdg[1].__dict__ or member == 'set_val': #wdg_doc += (8 * " ") + member + inspect.formatargspec( # *inspect.getargspec(getattr(parm[1], member))) wdg_doc += (" ") + "" + member.split('set_')[1] + " | " set_doc = str(inspect.getdoc(getattr(parm[1], member))) numSpaces = 1 set_doc = " ".join(( numSpaces * " ") + i for i in set_doc.splitlines()) wdg_doc += "" + set_doc + "\n" # PORTS DOC port_doc = "\n\n# PORT Types\n" # get the port type info port_doc += ''' \nThe following types are used to define a node port for limiting the connection between nodes to the predefined port-types. These labels are used when implementing `addInPort()` and `addOutPort()` port declaration functions. \n### PASS \nHas the affinity for any port type and allows any port connection. ''' gpitype_libs = [] for name in dir(plugin): if name.endswith('_GPITYPE'): gpitype_libs.append(name) gpitypes = [] for name in gpitype_libs: lib = getattr(plugin, name) for oname in dir(lib): obj = getattr(lib, oname) if hasattr(obj, 'GPIType') and (oname is not 'GPIDefaultType'): gpitypes.append([oname, obj]) #for port in self.node.getPorts(): for port in gpitypes: #typ = port.GPIType() #port_doc += "\n \'" + port.portTitle + "\': " + \ # str(typ.__class__) + "|" + str(type(port)) + "\n" port_doc += "\n### " + port[0] + "\n" # description numSpaces = 8 set_doc = "\n".join((" ") + i for i in str( port[1].__doc__).splitlines()) port_doc += set_doc + "\n" set_cnt = 0 for member in dir(port[1]): if member.startswith('set_'): set_cnt += 1 if set_cnt: port_doc += "attribute | type | description\n" port_doc += "--- | --- | ---\n" # set methods for member in dir(port[1]): if member.startswith('set_'): #port_doc += (8 * " ") + member + inspect.formatargspec( # *inspect.getargspec(getattr(port[1], member))) port_doc += (" ") + "" + member.split('set_')[1] + " | " set_doc = str(inspect.getdoc(getattr(port[1], member))) numSpaces = 16 set_doc = " ".join((" ") + i for i in set_doc.splitlines()) port_doc += "" + set_doc + "\n" port_doc += "\n" # GETTERS/SETTERS getset_doc = "\n\n# GETTERS & SETTERS\n\n" getset_doc += ''' \nGetters & Setters are functions that make up the node API. They provide access to the UI elements (i.e. in-ports, out-ports, widgets). ''' getset_doc += "\n## Node Initialization\n\n" getset_doc += ''' \nThese methods are used to declare in-ports, out-ports and widgets within the `initUI()` node method. ''' getset_doc += self.formatFuncDoc(gpi.nodeAPI.NodeAPI.addWidget) getset_doc += self.formatFuncDoc(gpi.nodeAPI.NodeAPI.addInPort) getset_doc += self.formatFuncDoc(gpi.nodeAPI.NodeAPI.addOutPort) getset_doc += "\n## Node Compute\n\n" getset_doc += ''' \nThese methods are used to reference data from in-ports, out-ports and widgets within the `compute()` routine. ''' getset_doc += self.formatFuncDoc(gpi.nodeAPI.NodeAPI.getVal) getset_doc += self.formatFuncDoc(gpi.nodeAPI.NodeAPI.getAttr) getset_doc += self.formatFuncDoc(gpi.nodeAPI.NodeAPI.setAttr) getset_doc += self.formatFuncDoc(gpi.nodeAPI.NodeAPI.getData) getset_doc += self.formatFuncDoc(gpi.nodeAPI.NodeAPI.setData) #self._docText = node_doc # + wdg_doc + port_doc + getset_doc self._docText = wdg_doc + port_doc + getset_doc #self.wdgabout.setPlainText(self._docText) def formatFuncDoc(self, func): """Generate auto-doc for passed func obj.""" numSpaces = 24 fdoc = inspect.getdoc(func) set_doc = "\n".join(( numSpaces * " ") + i for i in str(fdoc).splitlines()) rdoc = "\n### "+func.__name__+ "\n" + (16 * " ") + func.__name__ + \ inspect.formatargspec(*inspect.getargspec(func)) \ + "\n" + set_doc + "\n\n" return rdoc
if __name__ == '__main__': api_docs = GPIdocs() #print api_docs node_docs = NodeDocs() #print node_docs boiler = '<b>This file was auto-generated via the docs.py script (GPI '+VERSION+', '+RELEASE_DATE+').'+' Do not edit this file directly.</b>\n\n' # NodeAPI with open('NodeAPI.md','w') as f: print("Writing to NodeAPI.md...") preamble = '''# Node API\n''' f.write(boiler) f.write(preamble) f.write(str(api_docs)) # CoreNodes with open('CoreNodes.md','w') as f: print("Writing to CoreNodes.md...") preamble = '''This is the core node library. The following node usage information was generated from comments written into the node-code by the authors. ''' f.write(boiler) f.write(preamble) f.write(str(node_docs))