[Checkins] SVN: grok/branches/ulif-reference/doc/reference/ Add
tool to introspect/format the grok API. Update
reference-README in ulif-reference-branch.
Uli Fouquet
uli at mediamorphose.org
Thu May 31 10:19:57 EDT 2007
Log message for revision 76046:
Add tool to introspect/format the grok API. Update reference-README in ulif-reference-branch.
Changed:
U grok/branches/ulif-reference/doc/reference/README.txt
A grok/branches/ulif-reference/doc/reference/mkgrokref.py
-=-
Modified: grok/branches/ulif-reference/doc/reference/README.txt
===================================================================
--- grok/branches/ulif-reference/doc/reference/README.txt 2007-05-31 06:30:03 UTC (rev 76045)
+++ grok/branches/ulif-reference/doc/reference/README.txt 2007-05-31 14:19:55 UTC (rev 76046)
@@ -41,3 +41,34 @@
This script will be located in::
/usr/lib/python2.4/doc/tools/mkhowto
+
+
+Generating the grok reference from grok source code
+---------------------------------------------------
+
+.. warning:: This is work-in-progress and may lead to disappointing
+ results.
+
+The script mkgrokref.py is able to generate the sources for grok
+reference from the grok source code. It must be run with the
+appropriate PYTHONPATH set (i.e.: including the grok package to scan,
+all packages required by grok, namely the zope 3 packages, and the
+python standard packages). See the header of the script for further
+documentation. There are currently no commandline options supported by
+mkgrokref.py.
+
+To get a very plain reference::
+
+ $ python2.4 mkgrokref.py > myreference.txt
+
+This will produce a ReST formatted text file. Go on with::
+
+ $ rst2latex myreference.txt myreference.tex
+
+Transform the ReStructucturedText to LaTeX. Now we got a LaTeX source,
+which can be further processed as described above. For example::
+
+ $ mkhowto --pdf myreference.tex
+
+The rst2latex script is part of the python docutils package.
+
Added: grok/branches/ulif-reference/doc/reference/mkgrokref.py
===================================================================
--- grok/branches/ulif-reference/doc/reference/mkgrokref.py (rev 0)
+++ grok/branches/ulif-reference/doc/reference/mkgrokref.py 2007-05-31 14:19:55 UTC (rev 76046)
@@ -0,0 +1,374 @@
+"""Create grok reference introspecting the grok package.
+
+This script is able to generate reference docs for grok. It consists
+of three classes:
+
+ - DocMetaData:
+
+ Pure data collector to collect als configuration drivers.
+
+ - APIParser:
+
+ The introspector. Examines the grok package and delivers the
+ elements found as a nested dictionary.
+
+ - APIFormatter:
+
+ Formats api-dicts as generated by APIParser in a manner suitable
+ for further processing. Supported formats:
+
+ - LaTeX
+
+ - ReStructured Text
+
+ - Plain text
+
+The generated output must be processed further to get end-user
+documents, for example by using rst2latex or mkhowto.
+
+To make this script working, the PYTHONPATH environment variable must
+be set properly. It must include the grok sources that should be
+documented.
+
+
+"""
+
+import grok
+import types
+from zope.app.apidoc import utilities, component, interface
+from zope.app.apidoc.classregistry import ClassRegistry
+from grok.interfaces import *
+
+class DocMetaData:
+ """Meta data for API-doc generation.
+
+ """
+
+ complete = True
+ """Generate docs with title and header or only the chapters."""
+
+ pedantic = False
+ """Generate warnings if missing docstrings are found"""
+
+ latex_optimized = False
+ """Generate output more suitable for LaTeX """
+
+ sections={"Components":IGrokBaseClasses,
+ "Grok Errors":IGrokErrors,
+ "Directives":IGrokDirectives,
+ "Decorators":IGrokDecorators,
+ "Events":IGrokEvents,
+ "View":IGrokView,
+ "Form":IGrokForm,
+ "Application":IApplication
+ }
+ """Sections we want to see in the reference."""
+
+ doc_data = {
+ 'title' : "grok reference",
+ 'authoraddress' : ("The grok team","<grok-dev at zope.org>"),
+ 'release' : "unreleased",
+ 'motto' : """``Grok means to understand so thoroughly that the observer becomes a part of the observed -- merge, blend, intermarry, lose identity in group experience. It means almost everything that we mean by religion, philosophy, and science -- it means as little to us (because we are from Earth) as color means to a blind man.'' - Robert A. Heinlein, Stranger in a Strange Land """,
+ 'abstract' : """This is the grok reference documentation. It is organized by the Python artefacts that implement the concepts.
+
+ Grok makes Zope 3 concepts more accessible for application developers. This reference is not intended as introductory material for those concepts. Please refer to the original Zope 3 documentation and the grok tutorial for introductory material."""}
+ """Meta data to incorporate into the reference."""
+
+
+class APIParser:
+ """Create a nested dict of API elements.
+ """
+
+ meta = DocMetaData()
+
+ def getAttrDocAsDict(self, cls, attrname ):
+ """Examine attribute.
+ """
+ result = {'name':attrname,
+ 'type':None,
+ 'sig':None,
+ 'doc':None}
+ obj = getattr(cls,attrname)
+ typeofobj = type(obj)
+ sig = ""
+ if isinstance(obj, (types.FunctionType, types.MethodType)):
+ sig = utilities.getFunctionSignature(obj)
+ result['type'] = typeofobj
+ result['sig'] = sig
+
+ doc = ""
+ if (not hasattr(obj, '__doc__')) or (obj.__doc__ is None):
+ if self.meta.pedantic:
+ doc = "\nXXX docstring documentation of attribute missing.\n"
+ else:
+ doc = utilities.dedentString( obj.__doc__ )
+ #doc = replaceEvilChars(doc,self.meta.latex_optimized)
+ result = {'name':attrname,
+ 'type':typeofobj,
+ 'sig':sig,
+ 'doc':doc }
+ return result
+
+ def getClassDocAsDict(self, clsname):
+ """Examine class of classname.
+ """
+ result = {"name":"grok."+clsname}
+
+ if clsname[0] == "_":
+ return None
+
+ if clsname in grok.__dict__.keys():
+ cls = grok.__dict__[clsname]
+ reg[clsname] = cls
+ else:
+ # Not a real class, but it might help to keep
+ # informed...
+ return None
+
+ cls_path = "Could not get path"
+ try:
+ cls_path = utilities.getPythonPath(cls)
+ except:
+ pass
+ result['path'] = cls_path
+
+ doc = ""
+ if not hasattr(cls, '__doc__') or cls.__doc__ is None:
+ if self.meta.pedantic:
+ doc = "\nXXX docstring documentation of class missing.\n"
+ else:
+ doc = utilities.dedentString( cls.__doc__ )
+
+ result['doc'] = doc
+
+ apidoc_parse = ""
+ if hasattr( cls, 'factory'):
+ apidoc_parse = component.getAdapterInfoDictionary(cls)
+ if hasattr( cls, 'component'):
+ apidoc_parse = component.getUtilityInfoDictionary(cls)
+
+ result['elems'] = []
+ elemlist = utilities.getPublicAttributes(cls)
+ result['elems'] = [self.getAttrDocAsDict(cls,x) for x in elemlist]
+ result['elems'].sort()
+ return result
+
+
+ def getAPIDict(self,groups_dict):
+ """Get a nested directory containing the grok API
+
+ """
+ result_groups = []
+ for (key,group) in groups_dict.items():
+ result = {'group':key}
+ classes = [x for x in group]
+ classes.sort()
+ result['classes'] = []
+ for clsname in classes:
+ class_api = self.getClassDocAsDict(clsname)
+ if class_api is not None:
+ result['classes'].append( class_api )
+ result_groups.append( result )
+ return result_groups
+
+
+class APIFormatter:
+ """Helpers to generate readable API doc in various formats.
+ """
+
+ meta = DocMetaData()
+ api_data = None
+
+ def indentText(self,text,num):
+ """Indent long strings.
+
+ XXX broken
+ """
+ result = ""
+ for line in text.split("\n"):
+ result += "%s%s\n" % (" "*num,line)
+ return result
+
+ def replaceEvilChars(self,text):
+ """ Replace evil characters.
+ """
+ replace_tuples = [('$','\$')]
+ for subst in replace_tuples:
+ text = text.replace( subst[0], subst[1] )
+ if self.meta.latex_optimized:
+ replace_tuples = ( (
+ ("\n", "\n\n"),
+ ('\\$\\rightarrow\\$','$\\rightarrow$'),
+ ('->', '$\\rightarrow$'),
+ ('\$>\$', '>'),('\$<\$', '<'),
+ ('>','$>$'), ('<','$<$')) )
+ for subst in replace_tuples:
+ text = text.replace( subst[0], subst[1] )
+ return text
+
+
+ def prepareDocString(self,doc,num):
+ """Indent text lines and split headline from body.
+ """
+ doc = self.indentText(doc,num)
+ doc = self.replaceEvilChars(doc)
+ lines = doc.split('\n')
+ head = doc
+ body = doc
+ if len(lines):
+ head = lines[0]
+ body = '\n'.join(lines[1:])
+ if len(head) > 1:
+ head = " -- %s" % head
+ return (head,body)
+
+ def getTexOutput(self,api_dict):
+ """Transfom api_dict to TeX compatible output.
+ """
+ result = ""
+ if self.meta.complete:
+ result = '''
+\documentclass{manual}
+\RequirePackage[latin9]{inputenc}
+\usepackage{graphicx}
+\\title{%s}
+\\authoraddress{
+ %s
+ Email: %s
+}
+\\date{\\today}
+\\release{%s}
+\makeindex
+\\begin{document}
+\maketitle
+
+%s
+
+\\begin{abstract}
+
+%s
+
+\end{abstract}
+
+\\tableofcontents
+
+\include{core}
+
+''' % (self.meta.doc_data['title'],
+ self.meta.doc_data['authoraddress'][0],
+ self.replaceEvilChars(self.meta.doc_data['authoraddress'][1]),
+ self.meta.doc_data['release'],
+ self.meta.doc_data['motto'],
+ self.meta.doc_data['abstract'],
+ )
+ for group in api_dict:
+ result += "\chapter{%s}\n\n" % group['group']
+ for cls in group['classes']:
+ (head,body) = self.prepareDocString(
+ cls['doc'], 6)
+ body = "\ "+body
+ result += " \section{\class{%s%s}}\n\n" % (
+ cls['name'],head)
+ result += " \\begin{classdesc*}{%s%s}\n\n" % (
+ cls['name'],head)
+ result += "%s\n"%body
+ for elem in cls['elems']:
+ result += " \\begin{memberdesc}{%s%s}\n"% (
+ elem['name'], elem['sig'] )
+ result += self.replaceEvilChars(elem['doc']) + "\n\n"
+ result += " \end{memberdesc}\n\n"
+ result += " \end{classdesc*}\n\n"
+
+ if self.meta.complete:
+ result += "\n\end{document}"
+ return result
+
+
+ def getPlainOutput(self,api_dict):
+ """Grok API as plain text
+
+ Returns a long string representing the api_dict given.
+ """
+ result = ""
+ for section in api_dict:
+ print section['group']
+ for cls in section['classes']:
+ print " " + cls['name']
+ doc = self.indentText( cls['doc'], 6)
+ print "%s" % doc
+ for elem in cls['elems']:
+ print " " + elem['name'] + elem['sig']
+ doc = self.indentText( elem['doc'], 10)
+ print doc
+ return result
+
+ def getReSTOutput(self,api_dict):
+ """Grok API as ReStructuredText.
+
+ Returns a long string representing the api_dict given.
+ """
+ result = ""
+ doc_data = self.meta.doc_data
+
+ if self.meta.complete:
+ # Generate header...
+ result += "\n%s %s\n\n%s\n\n%s\n\n%s\n%s\n%s\n\n" % (
+ ".. title ", doc_data['title'],
+ ".. sectnum::",
+ ".. |date| date::",
+ "="*len(doc_data['title']),
+ doc_data['title'],
+ "="*len(doc_data['title']))
+
+ # Add table of contents...
+ result += "%s\n\n" % (
+ ".. contents:: Table of Contents",
+ )
+
+ for section in api_dict:
+ result += "%s\n%s\n\n" % (
+ section['group'],
+ "=" * len(section['group']))
+ for cls in section['classes']:
+ result += "\n%s\n%s\n\n" % (
+ cls['name'],
+ "-" * len(cls['name']))
+ doc = self.indentText( cls['doc'], 0)
+ result += "%s\n\nMethods and Attributes:\n\n" % (doc,)
+ for elem in cls['elems']:
+ result += " - %s%s:\n\n" %( elem['name'], elem['sig'] )
+ doc = self.indentText( elem['doc'], 10)
+ result += "%s\n" % (doc,)
+ return result
+
+# Fill class registry with all grok elements...
+reg = ClassRegistry()
+for name in grok.__dict__.keys():
+ if name[0] == "_":
+ continue
+ reg[name] = grok.__dict__[name]
+
+
+if __name__ == "__main__":
+ meta = DocMetaData()
+ parser = APIParser()
+ parser.meta = meta
+ api_dict = parser.getAPIDict(meta.sections)
+
+
+ #for section in result:
+ # print section['group']
+ # for cls in section['classes']:
+ # print " " + cls['name']
+ # for elem in cls['elems']:
+ # print " " + elem['name'] + elem['sig']
+
+ formatter = APIFormatter()
+ formatter.meta = meta
+ tex_output = formatter.getTexOutput( api_dict )
+ #print tex_output
+
+ #formatter.getPlainOutput( api_dict )
+
+ rest_output = formatter.getReSTOutput( api_dict )
+ print rest_output
More information about the Checkins
mailing list