summaryrefslogtreecommitdiff
path: root/bin/reportlab/tools/docco/docpy.py
diff options
context:
space:
mode:
authorStephane Wirtel <stephane@tinyerp.com>2008-11-14 16:06:02 +0100
committerStephane Wirtel <stephane@tinyerp.com>2008-11-14 16:06:02 +0100
commit3dae09ac14990a82aa9ef8afc2a0429b877ab123 (patch)
treefd4e64f6f37c8f23f54119197fad7ea69de418e2 /bin/reportlab/tools/docco/docpy.py
parent882cd7027feca65405cfdf1337064aa676830d4b (diff)
Remove pydot, pychart and reportlab.
bzr revid: stephane@tinyerp.com-20081114150602-cpp1eeo3d0837fev
Diffstat (limited to 'bin/reportlab/tools/docco/docpy.py')
-rw-r--r--bin/reportlab/tools/docco/docpy.py1247
1 files changed, 0 insertions, 1247 deletions
diff --git a/bin/reportlab/tools/docco/docpy.py b/bin/reportlab/tools/docco/docpy.py
deleted file mode 100644
index 75a77efe773..00000000000
--- a/bin/reportlab/tools/docco/docpy.py
+++ /dev/null
@@ -1,1247 +0,0 @@
-#!/usr/bin/env python
-#Copyright ReportLab Europe Ltd. 2000-2004
-#see license.txt for license details
-#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/tools/docco/docpy.py
-
-"""Generate documentation from live Python objects.
-
-This is an evolving module that allows to generate documentation
-for python modules in an automated fashion. The idea is to take
-live Python objects and inspect them in order to use as much mean-
-ingful information as possible to write in some formatted way into
-different types of documents.
-
-In principle a skeleton captures the gathered information and
-makes it available via a certain API to formatters that use it
-in whatever way they like to produce something of interest. The
-API allows for adding behaviour in subclasses of these formatters,
-such that, e.g. for certain classes it is possible to trigger
-special actions like displaying a sample image of a class that
-represents some graphical widget, say.
-
-Type the following for usage info:
-
- python docpy.py -h
-"""
-
-# Much inspired by Ka-Ping Yee's htmldoc.py.
-# Needs the inspect module.
-
-# Dinu Gherman
-
-
-__version__ = '0.8'
-
-
-import sys, os, re, types, string, getopt, copy, time
-from string import find, join, split, replace, expandtabs, rstrip
-
-from reportlab.pdfgen import canvas
-from reportlab.lib import colors
-from reportlab.lib.units import inch, cm
-from reportlab.lib.pagesizes import A4
-from reportlab.lib import enums
-from reportlab.lib.enums import TA_CENTER, TA_LEFT
-from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
-from reportlab.platypus.flowables import Flowable, Spacer
-from reportlab.platypus.paragraph import Paragraph
-from reportlab.platypus.flowables \
- import Flowable, Preformatted,Spacer, Image, KeepTogether, PageBreak
-from reportlab.platypus.tableofcontents import TableOfContents
-from reportlab.platypus.xpreformatted import XPreformatted
-from reportlab.platypus.frames import Frame
-from reportlab.platypus.doctemplate \
- import PageTemplate, BaseDocTemplate
-from reportlab.platypus.tables import TableStyle, Table
-import inspect
-
-####################################################################
-#
-# Stuff needed for building PDF docs.
-#
-####################################################################
-
-
-def mainPageFrame(canvas, doc):
- "The page frame used for all PDF documents."
-
- canvas.saveState()
-
- pageNumber = canvas.getPageNumber()
- canvas.line(2*cm, A4[1]-2*cm, A4[0]-2*cm, A4[1]-2*cm)
- canvas.line(2*cm, 2*cm, A4[0]-2*cm, 2*cm)
- if pageNumber > 1:
- canvas.setFont('Times-Roman', 12)
- canvas.drawString(4 * inch, cm, "%d" % pageNumber)
- if hasattr(canvas, 'headerLine'): # hackish
- headerline = string.join(canvas.headerLine, ' \215 ') # bullet
- canvas.drawString(2*cm, A4[1]-1.75*cm, headerline)
-
- canvas.setFont('Times-Roman', 8)
- msg = "Generated with reportlab.lib.docpy. See http://www.reportlab.com!"
- canvas.drawString(2*cm, 1.65*cm, msg)
-
- canvas.restoreState()
-
-
-class MyTemplate(BaseDocTemplate):
- "The document template used for all PDF documents."
-
- _invalidInitArgs = ('pageTemplates',)
-
- def __init__(self, filename, **kw):
- frame1 = Frame(2.5*cm, 2.5*cm, 15*cm, 25*cm, id='F1')
- self.allowSplitting = 0
- apply(BaseDocTemplate.__init__, (self, filename), kw)
- self.addPageTemplates(PageTemplate('normal', [frame1], mainPageFrame))
-
-
- def afterFlowable(self, flowable):
- "Takes care of header line, TOC and outline entries."
-
- if flowable.__class__.__name__ == 'Paragraph':
- f = flowable
- name7 = f.style.name[:7]
- name8 = f.style.name[:8]
-
- # Build a list of heading parts.
- # So far, this is the *last* item on the *previous* page...
- if name7 == 'Heading' and not hasattr(self.canv, 'headerLine'):
- self.canv.headerLine = []
-
- if name8 == 'Heading0':
- self.canv.headerLine = [f.text] # hackish
- elif name8 == 'Heading1':
- if len(self.canv.headerLine) == 2:
- del self.canv.headerLine[-1]
- elif len(self.canv.headerLine) == 3:
- del self.canv.headerLine[-1]
- del self.canv.headerLine[-1]
- self.canv.headerLine.append(f.text)
- elif name8 == 'Heading2':
- if len(self.canv.headerLine) == 3:
- del self.canv.headerLine[-1]
- self.canv.headerLine.append(f.text)
-
- if name7 == 'Heading':
- # Register TOC entries.
- headLevel = int(f.style.name[7:])
- self.notify('TOCEntry', (headLevel, flowable.getPlainText(), self.page))
-
- # Add PDF outline entries.
- c = self.canv
- title = f.text
- key = str(hash(f))
-
- try:
- if headLevel == 0:
- isClosed = 0
- else:
- isClosed = 1
-
- c.bookmarkPage(key)
- c.addOutlineEntry(title, key, level=headLevel,
- closed=isClosed)
- except ValueError:
- pass
-
-
-####################################################################
-#
-# Utility functions (Ka-Ping Yee).
-#
-####################################################################
-
-def htmlescape(text):
- "Escape special HTML characters, namely &, <, >."
- return replace(replace(replace(text, '&', '&amp;'),
- '<', '&lt;'),
- '>', '&gt;')
-
-def htmlrepr(object):
- return htmlescape(repr(object))
-
-
-def defaultformat(object):
- return '=' + htmlrepr(object)
-
-
-def getdoc(object):
- result = inspect.getdoc(object)
- if not result:
- try:
- result = inspect.getcomments(object)
- except:
- pass
- return result and rstrip(result) + '\n' or ''
-
-
-def reduceDocStringLength(docStr):
- "Return first line of a multiline string."
-
- return split(docStr, '\n')[0]
-
-
-####################################################################
-#
-# More utility functions
-#
-####################################################################
-
-def makeHtmlSection(text, bgcolor='#FFA0FF'):
- """Create HTML code for a section.
-
- This is usually a header for all classes or functions.
-u """
- text = htmlescape(expandtabs(text))
- result = []
- result.append("""<TABLE WIDTH="100\%" BORDER="0">""")
- result.append("""<TR><TD BGCOLOR="%s" VALIGN="CENTER">""" % bgcolor)
- result.append("""<H2>%s</H2>""" % text)
- result.append("""</TD></TR></TABLE>""")
- result.append('')
-
- return join(result, '\n')
-
-
-def makeHtmlSubSection(text, bgcolor='#AAA0FF'):
- """Create HTML code for a subsection.
-
- This is usually a class or function name.
- """
- text = htmlescape(expandtabs(text))
- result = []
- result.append("""<TABLE WIDTH="100\%" BORDER="0">""")
- result.append("""<TR><TD BGCOLOR="%s" VALIGN="CENTER">""" % bgcolor)
- result.append("""<H3><TT><FONT SIZE="+2">%s</FONT></TT></H3>""" % text)
- result.append("""</TD></TR></TABLE>""")
- result.append('')
-
- return join(result, '\n')
-
-
-def makeHtmlInlineImage(text):
- """Create HTML code for an inline image.
- """
-
- return """<IMG SRC="%s" ALT="%s">""" % (text, text)
-
-
-####################################################################
-#
-# Core "standard" docpy classes
-#
-####################################################################
-
-class PackageSkeleton0:
- """A class collecting 'interesting' information about a package."""
- pass # Not yet!
-
-
-class ModuleSkeleton0:
- """A class collecting 'interesting' information about a module."""
-
- def __init__(self):
- # This is an ad-hoc, somewhat questionable 'data structure',
- # but for the time being it serves its purpose and is fairly
- # self-contained.
- self.module = {}
- self.functions = {}
- self.classes = {}
-
-
- # Might need more like this, later.
- def getModuleName(self):
- """Return the name of the module being treated."""
-
- return self.module['name']
-
-
- # These inspect methods all rely on the inspect module.
- def inspect(self, object):
- """Collect information about a given object."""
-
- self.moduleSpace = object
-
- # Very non-OO, left for later...
- if inspect.ismodule(object):
- self._inspectModule(object)
- elif inspect.isclass(object):
- self._inspectClass(object)
- elif inspect.ismethod(object):
- self._inspectMethod(object)
- elif inspect.isfunction(object):
- self._inspectFunction(object)
- elif inspect.isbuiltin(object):
- self._inspectBuiltin(object)
- else:
- msg = "Don't know how to document this kind of object."
- raise TypeError, msg
-
-
- def _inspectModule(self, object):
- """Collect information about a given module object."""
- name = object.__name__
-
- self.module['name'] = name
- if hasattr(object, '__version__'):
- self.module['version'] = object.__version__
-
- cadr = lambda list: list[1]
- modules = map(cadr, inspect.getmembers(object, inspect.ismodule))
-
- classes, cdict = [], {}
- for key, value in inspect.getmembers(object, inspect.isclass):
- if (inspect.getmodule(value) or object) is object:
- classes.append(value)
- cdict[key] = cdict[value] = '#' + key
-
- functions, fdict = [], {}
- for key, value in inspect.getmembers(object, inspect.isroutine):
- #if inspect.isbuiltin(value) or inspect.getmodule(value) is object:
- functions.append(value)
- fdict[key] = '#-' + key
- if inspect.isfunction(value): fdict[value] = fdict[key]
-
- for c in classes:
- for base in c.__bases__:
- key, modname = base.__name__, base.__module__
- if modname != name and sys.modules.has_key(modname):
- module = sys.modules[modname]
- if hasattr(module, key) and getattr(module, key) is base:
- if not cdict.has_key(key):
- cdict[key] = cdict[base] = modname + '.txt#' + key
-
-## doc = getdoc(object) or 'No doc string.'
- doc = getdoc(object)
- self.module['doc'] = doc
-
- if modules:
- self.module['importedModules'] = map(lambda m:m.__name__, modules)
-
- if classes:
- for item in classes:
- self._inspectClass(item, fdict, cdict)
-
- if functions:
- for item in functions:
- self._inspectFunction(item, fdict, cdict)
-
-
- def _inspectClass(self, object, functions={}, classes={}):
- """Collect information about a given class object."""
-
- name = object.__name__
- bases = object.__bases__
- results = []
-
- if bases:
- parents = []
- for base in bases:
- parents.append(base)
-
- self.classes[name] = {}
- if bases:
- self.classes[name]['bases'] = parents
-
- methods, mdict = [], {}
- for key, value in inspect.getmembers(object, inspect.ismethod):
- methods.append(value)
- mdict[key] = mdict[value] = '#' + name + '-' + key
-
- if methods:
- if not self.classes[name].has_key('methods'):
- self.classes[name]['methods'] = {}
- for item in methods:
- self._inspectMethod(item, functions, classes, mdict, name)
-
-## doc = getdoc(object) or 'No doc string.'
- doc = getdoc(object)
- self.classes[name]['doc'] = doc
-
-
- def _inspectMethod(self, object, functions={}, classes={}, methods={}, clname=''):
- """Collect information about a given method object."""
-
- self._inspectFunction(object.im_func, functions, classes, methods, clname)
-
-
- def _inspectFunction(self, object, functions={}, classes={}, methods={}, clname=''):
- """Collect information about a given function object."""
- try:
- args, varargs, varkw, defaults = inspect.getargspec(object)
- argspec = inspect.formatargspec(
- args, varargs, varkw, defaults,
- defaultformat=defaultformat)
- except TypeError:
- argspec = '( ... )'
-
-## doc = getdoc(object) or 'No doc string.'
- doc = getdoc(object)
-
- if object.__name__ == '<lambda>':
- decl = [' lambda ', argspec[1:-1]]
- # print ' %s' % decl
- # Do something with lambda functions as well...
- # ...
- else:
- decl = object.__name__
- if not clname:
- self.functions[object.__name__] = {'signature':argspec, 'doc':doc}
- else:
- theMethods = self.classes[clname]['methods']
- if not theMethods.has_key(object.__name__):
- theMethods[object.__name__] = {}
-
- theMethod = theMethods[object.__name__]
- theMethod['signature'] = argspec
- theMethod['doc'] = doc
-
-
- def _inspectBuiltin(self, object):
- """Collect information about a given built-in."""
-
- print object.__name__ + '( ... )'
-
-
- def walk(self, formatter):
- """Call event methods in a visiting formatter."""
-
- s = self
- f = formatter
-
- # The order is fixed, but could be made flexible
- # with one more template method...
-
- # Module
- modName = s.module['name']
- modDoc = s.module['doc']
- imported = s.module.get('importedModules', [])
- imported.sort()
- # f.indentLevel = f.indentLevel + 1
- f.beginModule(modName, modDoc, imported)
-
- # Classes
- f.indentLevel = f.indentLevel + 1
- f.beginClasses(s.classes.keys())
- items = s.classes.items()
- items.sort()
- for k, v in items:
- cDoc = s.classes[k]['doc']
- bases = s.classes[k].get('bases', [])
- f.indentLevel = f.indentLevel + 1
- f.beginClass(k, cDoc, bases)
-
- # This if should move out of this method.
- if not s.classes[k].has_key('methods'):
- s.classes[k]['methods'] = {}
-
- # Methods
- #f.indentLevel = f.indentLevel + 1
- f.beginMethods(s.classes[k]['methods'].keys())
- items = s.classes[k]['methods'].items()
- items.sort()
- for m, v in items:
- mDoc = v['doc']
- sig = v['signature']
- f.indentLevel = f.indentLevel + 1
- f.beginMethod(m, mDoc, sig)
- f.indentLevel = f.indentLevel - 1
- f.endMethod(m, mDoc, sig)
-
- #f.indentLevel = f.indentLevel - 1
- f.endMethods(s.classes[k]['methods'].keys())
-
- f.indentLevel = f.indentLevel - 1
- f.endClass(k, cDoc, bases)
-
- # And what about attributes?!
-
- f.indentLevel = f.indentLevel - 1
- f.endClasses(s.classes.keys())
-
- # Functions
- f.indentLevel = f.indentLevel + 1
- f.beginFunctions(s.functions.keys())
- items = s.functions.items()
- items.sort()
- for k, v in items:
- doc = v['doc']
- sig = v['signature']
- f.indentLevel = f.indentLevel + 1
- f.beginFunction(k, doc, sig)
- f.indentLevel = f.indentLevel - 1
- f.endFunction(k, doc, sig)
- f.indentLevel = f.indentLevel - 1
- f.endFunctions(s.functions.keys())
-
- #f.indentLevel = f.indentLevel - 1
- f.endModule(modName, modDoc, imported)
-
- # Constants?!
-
-
-####################################################################
-#
-# Core "standard" docpy document builders
-#
-####################################################################
-
-class DocBuilder0:
- """An abstract class to document the skeleton of a Python module.
-
- Instances take a skeleton instance s and call their s.walk()
- method. The skeleton, in turn, will walk over its tree structure
- while generating events and calling equivalent methods from a
- specific interface (begin/end methods).
- """
-
- fileSuffix = None
-
- def __init__(self, skeleton=None):
- self.skeleton = skeleton
- self.packageName = None
- self.indentLevel = 0
-
-
- def write(self, skeleton=None):
- if skeleton:
- self.skeleton = skeleton
- self.skeleton.walk(self)
-
-
- # Event-method API, called by associated skeleton instances.
- # In fact, these should raise a NotImplementedError, but for now we
- # just don't do anything here.
-
- # The following four methods are *not* called by skeletons!
- def begin(self, name='', typ=''): pass
- def end(self): pass
-
- # Methods for packaging should move into a future PackageSkeleton...
- def beginPackage(self, name):
- self.packageName = name
-
- def endPackage(self, name):
- pass
-
- # Only this subset is really called by associated skeleton instances.
-
- def beginModule(self, name, doc, imported): pass
- def endModule(self, name, doc, imported): pass
-
- def beginClasses(self, names): pass
- def endClasses(self, names): pass
-
- def beginClass(self, name, doc, bases): pass
- def endClass(self, name, doc, bases): pass
-
- def beginMethods(self, names): pass
- def endMethods(self, names): pass
-
- def beginMethod(self, name, doc, sig): pass
- def endMethod(self, name, doc, sig): pass
-
- def beginFunctions(self, names): pass
- def endFunctions(self, names): pass
-
- def beginFunction(self, name, doc, sig): pass
- def endFunction(self, name, doc, sig): pass
-
-
-class AsciiDocBuilder0(DocBuilder0):
- """Document the skeleton of a Python module in ASCII format.
-
- The output will be an ASCII file with nested lines representing
- the hiearchical module structure.
-
- Currently, no doc strings are listed.
- """
-
- fileSuffix = '.txt'
- outLines = []
- indentLabel = ' '
-
- def end(self):
- # This if should move into DocBuilder0...
- if self.packageName:
- self.outPath = self.packageName + self.fileSuffix
- elif self.skeleton:
- self.outPath = self.skeleton.getModuleName() + self.fileSuffix
- else:
- self.outPath = ''
-
- if self.outPath:
- file = open(self.outPath, 'w')
- for line in self.outLines:
- file.write(line + '\n')
- file.close()
-
-
- def beginPackage(self, name):
- DocBuilder0.beginPackage(self, name)
- lev, label = self.indentLevel, self.indentLabel
- self.outLines.append('%sPackage: %s' % (lev*label, name))
- self.outLines.append('')
-
-
- def beginModule(self, name, doc, imported):
- append = self.outLines.append
- lev, label = self.indentLevel, self.indentLabel
- self.outLines.append('%sModule: %s' % (lev*label, name))
-## self.outLines.append('%s%s' % ((lev+1)*label, reduceDocStringLength(doc)))
- append('')
-
- if imported:
- self.outLines.append('%sImported' % ((lev+1)*label))
- append('')
- for m in imported:
- self.outLines.append('%s%s' % ((lev+2)*label, m))
- append('')
-
-
- def beginClasses(self, names):
- if names:
- lev, label = self.indentLevel, self.indentLabel
- self.outLines.append('%sClasses' % (lev*label))
- self.outLines.append('')
-
-
- def beginClass(self, name, doc, bases):
- append = self.outLines.append
- lev, label = self.indentLevel, self.indentLabel
-
- if bases:
- bases = map(lambda b:b.__name__, bases) # hack
- append('%s%s(%s)' % (lev*label, name, join(bases, ', ')))
- else:
- append('%s%s' % (lev*label, name))
- return
-
-## append('%s%s' % ((lev+1)*label, reduceDocStringLength(doc)))
- self.outLines.append('')
-
-
- def endClass(self, name, doc, bases):
- self.outLines.append('')
-
-
- def beginMethod(self, name, doc, sig):
- append = self.outLines.append
- lev, label = self.indentLevel, self.indentLabel
- append('%s%s%s' % (lev*label, name, sig))
-## append('%s%s' % ((lev+1)*label, reduceDocStringLength(doc)))
-## append('')
-
-
- def beginFunctions(self, names):
- if names:
- lev, label = self.indentLevel, self.indentLabel
- self.outLines.append('%sFunctions' % (lev*label))
- self.outLines.append('')
-
-
- def endFunctions(self, names):
- self.outLines.append('')
-
-
- def beginFunction(self, name, doc, sig):
- append = self.outLines.append
- lev, label = self.indentLevel, self.indentLabel
- self.outLines.append('%s%s%s' % (lev*label, name, sig))
-## append('%s%s' % ((lev+1)*label, reduceDocStringLength(doc)))
-## append('')
-
-
-class HtmlDocBuilder0(DocBuilder0):
- "A class to write the skeleton of a Python source in HTML format."
-
- fileSuffix = '.html'
- outLines = []
-
- def begin(self, name='', typ=''):
- self.outLines.append("""<!doctype html public "-//W3C//DTD HTML 4.0 Transitional//EN">""")
- self.outLines.append("""<html>""")
-
-
- def end(self):
- if self.packageName:
- self.outPath = self.packageName + self.fileSuffix
- elif self.skeleton:
- self.outPath = self.skeleton.getModuleName() + self.fileSuffix
- else:
- self.outPath = ''
-
- if self.outPath:
- file = open(self.outPath, 'w')
- self.outLines.append('</body></html>')
- for line in self.outLines:
- file.write(line + '\n')
- file.close()
-
-
- def beginPackage(self, name):
- DocBuilder0.beginPackage(self, name)
-
- self.outLines.append("""<title>%s</title>""" % name)
- self.outLines.append("""<body bgcolor="#ffffff">""")
- self.outLines.append("""<H1>%s</H1>""" % name)
- self.outLines.append('')
-
-
- def beginModule(self, name, doc, imported):
- if not self.packageName:
- self.outLines.append("""<title>%s</title>""" % name)
- self.outLines.append("""<body bgcolor="#ffffff">""")
-
- self.outLines.append("""<H1>%s</H1>""" % name)
- self.outLines.append('')
- for line in split(doc, '\n'):
- self.outLines.append("""<FONT SIZE="-1">%s</FONT>""" % htmlescape(line))
- self.outLines.append('<BR>')
- self.outLines.append('')
-
- if imported:
- self.outLines.append(makeHtmlSection('Imported Modules'))
- self.outLines.append("""<ul>""")
- for m in imported:
- self.outLines.append("""<li>%s</li>""" % m)
- self.outLines.append("""</ul>""")
-
-
- def beginClasses(self, names):
- self.outLines.append(makeHtmlSection('Classes'))
-
-
- def beginClass(self, name, doc, bases):
- DocBuilder0.beginClass(self, name, doc, bases)
-
-## # Keep an eye on the base classes.
-## self.currentBaseClasses = bases
-
- if bases:
- bases = map(lambda b:b.__name__, bases) # hack
- self.outLines.append(makeHtmlSubSection('%s(%s)' % (name, join(bases, ', '))))
- else:
- self.outLines.append(makeHtmlSubSection('%s' % name))
- for line in split(doc, '\n'):
- self.outLines.append("""<FONT SIZE="-1">%s</FONT>""" % htmlescape(line))
- self.outLines.append('<BR>')
-
- self.outLines.append('')
-
-
- def beginMethods(self, names):
- pass
-## if names:
-## self.outLines.append('<H3>Method Interface</H3>')
-## self.outLines.append('')
-
-
- def beginMethod(self, name, doc, sig):
- self.beginFunction(name, doc, sig)
-
-
- def beginFunctions(self, names):
- self.outLines.append(makeHtmlSection('Functions'))
-
-
- def beginFunction(self, name, doc, sig):
- append = self.outLines.append
- append("""<DL><DL><DT><TT><STRONG>%s</STRONG>%s</TT></DT>""" % (name, sig))
- append('')
- for line in split(doc, '\n'):
- append("""<DD><FONT SIZE="-1">%s</FONT></DD>""" % htmlescape(line))
- append('<BR>')
- append('</DL></DL>')
- append('')
-
-
-class PdfDocBuilder0(DocBuilder0):
- "Document the skeleton of a Python module in PDF format."
-
- fileSuffix = '.pdf'
-
- def makeHeadingStyle(self, level, typ=None, doc=''):
- "Make a heading style for different types of module content."
-
- if typ in ('package', 'module', 'class'):
- style = ParagraphStyle(name='Heading'+str(level),
- fontName = 'Courier-Bold',
- fontSize=14,
- leading=18,
- spaceBefore=12,
- spaceAfter=6)
- elif typ in ('method', 'function'):
- if doc:
- style = ParagraphStyle(name='Heading'+str(level),
- fontName = 'Courier-Bold',
- fontSize=12,
- leading=18,
- firstLineIndent=-18,
- leftIndent=36,
- spaceBefore=0,
- spaceAfter=-3)
- else:
- style = ParagraphStyle(name='Heading'+str(level),
- fontName = 'Courier-Bold',
- fontSize=12,
- leading=18,
- firstLineIndent=-18,
- leftIndent=36,
- spaceBefore=0,
- spaceAfter=0)
-
- else:
- style = ParagraphStyle(name='Heading'+str(level),
- fontName = 'Times-Bold',
- fontSize=14,
- leading=18,
- spaceBefore=12,
- spaceAfter=6)
-
- return style
-
-
- def begin(self, name='', typ=''):
- styleSheet = getSampleStyleSheet()
- self.code = styleSheet['Code']
- self.bt = styleSheet['BodyText']
- self.story = []
-
- # Cover page
- t = time.gmtime(time.time())
- timeString = time.strftime("%Y-%m-%d %H:%M", t)
- self.story.append(Paragraph('<font size=18>Documentation for %s "%s"</font>' % (typ, name), self.bt))
- self.story.append(Paragraph('<font size=18>Generated by: docpy.py version %s</font>' % __version__, self.bt))
- self.story.append(Paragraph('<font size=18>Date generated: %s</font>' % timeString, self.bt))
- self.story.append(Paragraph('<font size=18>Format: PDF</font>', self.bt))
- self.story.append(PageBreak())
-
- # Table of contents
- toc = TableOfContents()
- self.story.append(toc)
- self.story.append(PageBreak())
-
-
- def end(self):
- if self.outPath is not None:
- pass
- elif self.packageName:
- self.outPath = self.packageName + self.fileSuffix
- elif self.skeleton:
- self.outPath = self.skeleton.getModuleName() + self.fileSuffix
- else:
- self.outPath = ''
- print 'output path is %s' % self.outPath
- if self.outPath:
- doc = MyTemplate(self.outPath)
- doc.multiBuild(self.story)
-
-
- def beginPackage(self, name):
- DocBuilder0.beginPackage(self, name)
- story = self.story
- story.append(Paragraph(name, self.makeHeadingStyle(self.indentLevel, 'package')))
-
-
- def beginModule(self, name, doc, imported):
- story = self.story
- bt = self.bt
- story.append(Paragraph(name, self.makeHeadingStyle(self.indentLevel, 'module')))
- if doc:
- story.append(XPreformatted(htmlescape(doc), bt))
- story.append(XPreformatted('', bt))
-
- if imported:
- story.append(Paragraph('Imported modules', self.makeHeadingStyle(self.indentLevel + 1)))
- for m in imported:
- p = Paragraph('<bullet>\201</bullet> %s' % m, bt)
- p.style.bulletIndent = 10
- p.style.leftIndent = 18
- story.append(p)
-
-
- def endModule(self, name, doc, imported):
- DocBuilder0.endModule(self, name, doc, imported)
- self.story.append(PageBreak())
-
-
- def beginClasses(self, names):
- self.story.append(Paragraph('Classes', self.makeHeadingStyle(self.indentLevel)))
-
-
- def beginClass(self, name, doc, bases):
- bt = self.bt
- story = self.story
- if bases:
- bases = map(lambda b:b.__name__, bases) # hack
- story.append(Paragraph('%s(%s)' % (name, join(bases, ', ')), self.makeHeadingStyle(self.indentLevel, 'class')))
- else:
- story.append(Paragraph(name, self.makeHeadingStyle(self.indentLevel, 'class')))
-
- if doc:
- story.append(XPreformatted(htmlescape(doc), bt))
- story.append(XPreformatted('', bt))
-
-
- def beginMethod(self, name, doc, sig):
- bt = self.bt
- story = self.story
- story.append(Paragraph(name+sig, self.makeHeadingStyle(self.indentLevel, 'method', doc)))
- if doc:
- story.append(XPreformatted(htmlescape(doc), bt))
- story.append(XPreformatted('', bt))
-
-
- def beginFunctions(self, names):
- if names:
- self.story.append(Paragraph('Functions', self.makeHeadingStyle(self.indentLevel)))
-
-
- def beginFunction(self, name, doc, sig):
- bt = self.bt
- story = self.story
- story.append(Paragraph(name+sig, self.makeHeadingStyle(self.indentLevel, 'function')))
- if doc:
- story.append(XPreformatted(htmlescape(doc), bt))
- story.append(XPreformatted('', bt))
-
-
-class UmlPdfDocBuilder0(PdfDocBuilder0):
- "Document the skeleton of a Python module with UML class diagrams."
-
- fileSuffix = '.pdf'
-
- def begin(self, name='', typ=''):
- styleSheet = getSampleStyleSheet()
- self.h1 = styleSheet['Heading1']
- self.h2 = styleSheet['Heading2']
- self.h3 = styleSheet['Heading3']
- self.code = styleSheet['Code']
- self.bt = styleSheet['BodyText']
- self.story = []
- self.classCompartment = ''
- self.methodCompartment = []
-
-
- def beginModule(self, name, doc, imported):
- story = self.story
- h1, h2, h3, bt = self.h1, self.h2, self.h3, self.bt
- styleSheet = getSampleStyleSheet()
- bt1 = styleSheet['BodyText']
-
- story.append(Paragraph(name, h1))
- story.append(XPreformatted(doc, bt1))
-
- if imported:
- story.append(Paragraph('Imported modules', self.makeHeadingStyle(self.indentLevel + 1)))
- for m in imported:
- p = Paragraph('<bullet>\201</bullet> %s' % m, bt1)
- p.style.bulletIndent = 10
- p.style.leftIndent = 18
- story.append(p)
-
-
- def endModule(self, name, doc, imported):
- self.story.append(PageBreak())
- PdfDocBuilder0.endModule(self, name, doc, imported)
-
-
- def beginClasses(self, names):
- h1, h2, h3, bt = self.h1, self.h2, self.h3, self.bt
- if names:
- self.story.append(Paragraph('Classes', h2))
-
-
- def beginClass(self, name, doc, bases):
- self.classCompartment = ''
- self.methodCompartment = []
-
- if bases:
- bases = map(lambda b:b.__name__, bases) # hack
- self.classCompartment = '%s(%s)' % (name, join(bases, ', '))
- else:
- self.classCompartment = name
-
-
- def endClass(self, name, doc, bases):
- h1, h2, h3, bt, code = self.h1, self.h2, self.h3, self.bt, self.code
- styleSheet = getSampleStyleSheet()
- bt1 = styleSheet['BodyText']
- story = self.story
-
- # Use only the first line of the class' doc string --
- # no matter how long! (Do the same later for methods)
- classDoc = reduceDocStringLength(doc)
-
- tsa = tableStyleAttributes = []
-
- # Make table with class and method rows
- # and add it to the story.
- p = Paragraph('<b>%s</b>' % self.classCompartment, bt)
- p.style.alignment = TA_CENTER
- rows = [(p,)]
- # No doc strings, now...
- # rows = rows + [(Paragraph('<i>%s</i>' % classDoc, bt1),)]
- lenRows = len(rows)
- tsa.append(('BOX', (0,0), (-1,lenRows-1), 0.25, colors.black))
- for name, doc, sig in self.methodCompartment:
- nameAndSig = Paragraph('<b>%s</b>%s' % (name, sig), bt1)
- rows.append((nameAndSig,))
- # No doc strings, now...
- # docStr = Paragraph('<i>%s</i>' % reduceDocStringLength(doc), bt1)
- # rows.append((docStr,))
- tsa.append(('BOX', (0,lenRows), (-1,-1), 0.25, colors.black))
- t = Table(rows, (12*cm,))
- tableStyle = TableStyle(tableStyleAttributes)
- t.setStyle(tableStyle)
- self.story.append(t)
- self.story.append(Spacer(1*cm, 1*cm))
-
-
- def beginMethod(self, name, doc, sig):
- self.methodCompartment.append((name, doc, sig))
-
-
- def beginFunctions(self, names):
- h1, h2, h3, bt = self.h1, self.h2, self.h3, self.bt
- if names:
- self.story.append(Paragraph('Functions', h2))
- self.classCompartment = chr(171) + ' Module-Level Functions ' + chr(187)
- self.methodCompartment = []
-
-
- def beginFunction(self, name, doc, sig):
- self.methodCompartment.append((name, doc, sig))
-
-
- def endFunctions(self, names):
- h1, h2, h3, bt, code = self.h1, self.h2, self.h3, self.bt, self.code
- styleSheet = getSampleStyleSheet()
- bt1 = styleSheet['BodyText']
- story = self.story
- if not names:
- return
-
- tsa = tableStyleAttributes = []
-
- # Make table with class and method rows
- # and add it to the story.
- p = Paragraph('<b>%s</b>' % self.classCompartment, bt)
- p.style.alignment = TA_CENTER
- rows = [(p,)]
- lenRows = len(rows)
- tsa.append(('BOX', (0,0), (-1,lenRows-1), 0.25, colors.black))
- for name, doc, sig in self.methodCompartment:
- nameAndSig = Paragraph('<b>%s</b>%s' % (name, sig), bt1)
- rows.append((nameAndSig,))
- # No doc strings, now...
- # docStr = Paragraph('<i>%s</i>' % reduceDocStringLength(doc), bt1)
- # rows.append((docStr,))
- tsa.append(('BOX', (0,lenRows), (-1,-1), 0.25, colors.black))
- t = Table(rows, (12*cm,))
- tableStyle = TableStyle(tableStyleAttributes)
- t.setStyle(tableStyle)
- self.story.append(t)
- self.story.append(Spacer(1*cm, 1*cm))
-
-
-####################################################################
-#
-# Main
-#
-####################################################################
-
-def printUsage():
- """docpy.py - Automated documentation for Python source code.
-
-Usage: python docpy.py [options]
-
- [options]
- -h Print this help message.
-
- -f name Use the document builder indicated by 'name',
- e.g. Ascii, Html, Pdf (default), UmlPdf.
-
- -m module Generate document for module named 'module'
- (default is 'docpy').
- 'module' may follow any of these forms:
- - docpy.py
- - docpy
- - c:\\test\\docpy
- and can be any of these:
- - standard Python modules
- - modules in the Python search path
- - modules in the current directory
-
- -p package Generate document for package named 'package'.
- 'package' may follow any of these forms:
- - reportlab
- - reportlab.platypus
- - c:\\test\\reportlab
- and can be any of these:
- - standard Python packages (?)
- - packages in the Python search path
- - packages in the current directory
-
- -s Silent mode (default is unset).
-
-Examples:
-
- python docpy.py -h
- python docpy.py -m docpy.py -f Ascii
- python docpy.py -m string -f Html
- python docpy.py -m signsandsymbols.py -f Pdf
- python docpy.py -p reportlab.platypus -f UmlPdf
- python docpy.py -p reportlab.lib -s -f UmlPdf
-"""
-
-
-def documentModule0(pathOrName, builder, opts={}):
- """Generate documentation for one Python file in some format.
-
- This handles Python standard modules like string, custom modules
- on the Python search path like e.g. docpy as well as modules
- specified with their full path like C:/tmp/junk.py.
-
- The doc file will always be saved in the current directory with
- a basename equal to that of the module, e.g. docpy.
- """
-
- cwd = os.getcwd()
-
- # Append directory to Python search path if we get one.
- dirName = os.path.dirname(pathOrName)
- if dirName:
- sys.path.append(dirName)
-
- # Remove .py extension from module name.
- if pathOrName[-3:] == '.py':
- modname = pathOrName[:-3]
- else:
- modname = pathOrName
-
- # Remove directory paths from module name.
- if dirName:
- modname = os.path.basename(modname)
-
- # Load the module.
- try:
- module = __import__(modname)
- except:
- print 'Failed to import %s.' % modname
- os.chdir(cwd)
- return
-
- # Do the real documentation work.
- s = ModuleSkeleton0()
- s.inspect(module)
- builder.write(s)
-
- # Remove appended directory from Python search path if we got one.
- if dirName:
- del sys.path[-1]
-
- os.chdir(cwd)
-
-
-def _packageWalkCallback((builder, opts), dirPath, files):
- "A callback function used when waking over a package tree."
-
- # Skip __init__ files.
- files = filter(lambda f:f != '__init__.py', files)
-
- files = filter(lambda f:f[-3:] == '.py', files)
- for f in files:
- path = os.path.join(dirPath, f)
- if not opts.get('isSilent', 0):
- print path
- builder.indentLevel = builder.indentLevel + 1
- documentModule0(path, builder)
- builder.indentLevel = builder.indentLevel - 1
-
-
-def documentPackage0(pathOrName, builder, opts={}):
- """Generate documentation for one Python package in some format.
-
- 'pathOrName' can be either a filesystem path leading to a Python
- package or package name whose path will be resolved by importing
- the top-level module.
-
- The doc file will always be saved in the current directory with
- a basename equal to that of the package, e.g. reportlab.lib.
- """
-
- # Did we get a package path with OS-dependant seperators...?
- if os.sep in pathOrName:
- path = pathOrName
- name = os.path.splitext(os.path.basename(path))[0]
- # ... or rather a package name?
- else:
- name = pathOrName
- package = __import__(name)
- # Some special care needed for dotted names.
- if '.' in name:
- subname = 'package' + name[find(name, '.'):]
- package = eval(subname)
- path = os.path.dirname(package.__file__)
-
- cwd = os.getcwd()
- builder.beginPackage(name)
- os.path.walk(path, _packageWalkCallback, (builder, opts))
- builder.endPackage(name)
- os.chdir(cwd)
-
-
-def main():
- "Handle command-line options and trigger corresponding action."
-
- opts, args = getopt.getopt(sys.argv[1:], 'hsf:m:p:')
-
- # Make an options dictionary that is easier to use.
- optsDict = {}
- for k, v in opts:
- optsDict[k] = v
- hasOpt = optsDict.has_key
-
- # On -h print usage and exit immediately.
- if hasOpt('-h'):
- print printUsage.__doc__
- sys.exit(0)
-
- # On -s set silent mode.
- isSilent = hasOpt('-s')
-
- # On -f set the appropriate DocBuilder to use or a default one.
- builderClassName = optsDict.get('-f', 'Pdf') + 'DocBuilder0'
- builder = eval(builderClassName + '()')
-
- # Set default module or package to document.
- if not hasOpt('-p') and not hasOpt('-m'):
- optsDict['-m'] = 'docpy'
-
- # Save a few options for further use.
- options = {'isSilent':isSilent}
-
- # Now call the real documentation functions.
- if hasOpt('-m'):
- nameOrPath = optsDict['-m']
- if not isSilent:
- print "Generating documentation for module %s..." % nameOrPath
- builder.begin(name=nameOrPath, typ='module')
- documentModule0(nameOrPath, builder, options)
- elif hasOpt('-p'):
- nameOrPath = optsDict['-p']
- if not isSilent:
- print "Generating documentation for package %s..." % nameOrPath
- builder.begin(name=nameOrPath, typ='package')
- documentPackage0(nameOrPath, builder, options)
- builder.end()
-
- if not isSilent:
- print "Saved %s." % builder.outPath
-
-
-if __name__ == '__main__':
- main()