--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/tools/codegrab.py Mon Jun 05 16:38:53 2000 +0000
@@ -0,0 +1,201 @@
+#codegrab.py
+"""
+This grabs various Python class, method and function
+headers and their doc strings to include in documents
+"""
+
+import imp
+import types
+import string
+import os
+import sys
+
+class Struct:
+ pass
+
+def getObjectsDefinedIn(modulename, directory=None):
+ """Returns two tuple of (functions, classes) defined
+ in the given module. 'directory' must be the directory
+ containing the script; modulename should not include
+ the .py suffix"""
+
+ if directory:
+ searchpath = [directory]
+ else:
+ searchpath = sys.path # searches usual Python path
+
+ #might be a package. If so, check the top level
+ #package is there, then recalculate the path needed
+ words = string.split(modulename, '.')
+ if len(words) > 1:
+ packagename = words[0]
+ packagefound = imp.find_module(packagename, searchpath)
+ assert packagefound, "Package %s not found" % packagename
+ (file, packagepath, description) = packagefound
+ #now the full path should be known, if it is in the
+ #package
+
+ directory = apply(os.path.join, [packagepath] + words[1:-1])
+ modulename = words[-1]
+ searchpath = [directory]
+
+
+
+ #find and import the module.
+ found = imp.find_module(modulename, searchpath)
+ assert found, "Module %s not found" % modulename
+ (file, pathname, description) = found
+ mod = imp.load_module(modulename, file, pathname, description)
+
+ #grab the code too, minus trailing newlines
+ lines = open(pathname, 'r').readlines()
+ lines = map(string.rstrip, lines)
+
+ result = Struct()
+ result.functions = []
+ result.classes = []
+ for name in dir(mod):
+ value = getattr(mod, name)
+ if type(value) is types.FunctionType:
+ #we're possibly interested in it
+ if os.path.splitext(value.func_code.co_filename)[0] == modulename:
+ #it was defined here
+ funcObj = value
+ fn = Struct()
+ fn.name = name
+ fn.proto = getFunctionPrototype(funcObj, lines)
+ if funcObj.__doc__:
+ fn.doc = dedent(funcObj.__doc__)
+ else:
+ fn.doc = '(no documentation string)'
+ result.functions.append(fn)
+ elif type(value) == types.ClassType:
+ if value.__module__ == modulename:
+ cl = Struct()
+ cl.name = name
+ if value.__doc__:
+ cl.doc = dedent(value.__doc__)
+ else:
+ cl.doc = "(no documentation string)"
+
+ cl.bases = []
+ for base in value.__bases__:
+ cl.bases.append(base.__name__)
+
+ cl.methods = []
+ #loop over dict finding methods defined here
+ # Q - should we show all methods?
+ # loop over dict finding methods defined here
+ items = value.__dict__.items()
+ items.sort()
+ for (key2, value2) in items:
+ if type(value2) <> types.FunctionType:
+ continue # not a method
+ elif os.path.splitext(value2.func_code.co_filename)[0] == modulename:
+ continue # defined in base class
+ else:
+ #we want it
+ meth = Struct()
+ meth.name = key2
+ meth.proto = getFunctionPrototype(value2, lines)
+ if value2.__doc__:
+ meth.doc = dedent(value2.__doc__)
+ else:
+ meth.doc = "(no documentation string)"
+ #is it official?
+ if key2[0:1] == '_':
+ meth.status = 'private'
+ elif key2[-1] in '0123456789':
+ meth.status = 'experimental'
+ else:
+ meth.status = 'official'
+ cl.methods.append(meth)
+ result.classes.append(cl)
+ return result
+
+
+def getFunctionPrototype(f, lines):
+ """Pass in the function object and list of lines;
+ it extracts the header as a multiline text block."""
+ firstLineNo = f.func_code.co_firstlineno - 1
+ lineNo = firstLineNo
+ brackets = 0
+ while 1:
+ line = lines[lineNo]
+ for char in line:
+ if char == '(':
+ brackets = brackets + 1
+ elif char == ')':
+ brackets = brackets - 1
+ if brackets == 0:
+ break
+ else:
+ lineNo = lineNo + 1
+
+ usefulLines = lines[firstLineNo:lineNo+1]
+ return string.join(usefulLines, '\n')
+
+
+def dedent(comment):
+ """Attempts to dedent the lines to the edge. Looks at no.
+ of leading spaces in line 2, and removes up to that number
+ of blanks from other lines."""
+ commentLines = string.split(comment, '\n')
+ if len(commentLines) < 2:
+ cleaned = map(string.lstrip, commentLines)
+ else:
+ spc = 0
+ for char in commentLines[1]:
+ if char in string.whitespace:
+ spc = spc + 1
+ else:
+ break
+ #now check other lines
+ cleaned = []
+ for line in commentLines:
+ for i in range(min(len(line),spc)):
+ if line[0] in string.whitespace:
+ line = line[1:]
+ cleaned.append(line)
+ return string.join(cleaned, '\n')
+
+
+
+def dumpDoc(modulename, directory=None):
+ """Test support. Just prints docco on the module
+ to standard output."""
+ docco = getObjectsDefinedIn(modulename, directory)
+ print 'codegrab.py - ReportLab Documentation Utility'
+ print 'documenting', modulename + '.py'
+ print '-------------------------------------------------------'
+ print
+ if docco.functions == []:
+ print 'No functions found'
+ else:
+ print 'Functions:'
+ for f in docco.functions:
+ print f.proto
+ print ' ' + f.doc
+
+ if docco.classes == []:
+ print 'No classes found'
+ else:
+ print 'Classes:'
+ for c in docco.classes:
+ print c.name
+ print ' ' + c.doc
+ for m in c.methods:
+ print m.proto # it is already indented in the file!
+ print ' ' + m.doc
+ print
+
+def test():
+ dumpDoc('reportlab.platypus.paragraph')
+
+if __name__=='__main__':
+ import sys
+ print 'Path to search:'
+ for line in sys.path:
+ print ' ',line
+ test()
+