#!/usr/bin/env python # # $Id: __init__.py,v 1.4 2003/03/16 23:43:23 doughellmann Exp $ # # Copyright 2003 Doug Hellmann. # # # All Rights Reserved # # Permission to use, copy, modify, and distribute this software and # its documentation for any purpose and without fee is hereby # granted, provided that the above copyright notice appear in all # copies and that both that copyright notice and this permission # notice appear in supporting documentation, and that the name of Doug # Hellmann not be used in advertising or publicity pertaining to # distribution of the software without specific, written prior # permission. # # DOUG HELLMANN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, # INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN # NO EVENT SHALL DOUG HELLMANN BE LIABLE FOR ANY SPECIAL, INDIRECT OR # CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS # OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # """TAL-based documentation set writer. """ __rcs_info__ = { # # Creation Information # 'module_name' : '$RCSfile: __init__.py,v $', 'rcs_id' : '$Id: __init__.py,v 1.4 2003/03/16 23:43:23 doughellmann Exp $', 'creator' : 'Doug Hellmann ', 'project' : 'HappyDoc', 'created' : 'Sun, 19-Jan-2003 16:38:01 EST', # # Current Information # 'author' : '$Author: doughellmann $', 'version' : '$Revision: 1.4 $', 'date' : '$Date: 2003/03/16 23:43:23 $', } try: __version__ = __rcs_info__['version'].split(' ')[1] except: __version__ = '0.0' # # Import system modules # import os import sys # # Import Local modules # import happydoclib from happydoclib.docset import base from happydoclib.docset.docset_TAL.templateset import TemplateSet from happydoclib.docstring import getConverterFactoryForFile, \ getConverterFactory from happydoclib.sysmodules import getPythonSystemModuleURL from happydoclib.trace import trace # # Module # TRACE_LEVEL=0 class TALDocset(base.MultiFileDocSet): """TAL Template Docset Writer Parameters """ CONVERTER_HEADER_START_LEVEL = 2 DEFAULT_TEMPLATE_SET = 'default' DEFAULT_TEMPLATE_PATH = os.path.join(os.path.dirname(__file__), 'templates', ) def __init__(self, scanner, title, outputDirectory, includeComments=1, includePrivateNames=1, sortNames=0, statusMessageFunc=None, extraParameters={}, ): trace.into('TALDocset', '__init__', scanner=scanner, title=title, outputDirectory=outputDirectory, includeComments=includeComments, includePrivateNames=includePrivateNames, sortNames=sortNames, extraParameters=extraParameters, outputLevel=TRACE_LEVEL, ) base.MultiFileDocSet.__init__(self, scanner, title=title, outputDirectory=outputDirectory, includeComments=includeComments, includePrivateNames=includePrivateNames, sortNames=sortNames, statusMessageFunc=statusMessageFunc, extraParameters=extraParameters, ) self.template_name = extraParameters.get('template_name', self.DEFAULT_TEMPLATE_SET) self.template_path = extraParameters.get('template_path', self.DEFAULT_TEMPLATE_PATH) self.template_set = TemplateSet(os.path.join(self.template_path, self.template_name) ) trace.outof(outputLevel=TRACE_LEVEL) return def getOutputFilenameForPackageTreeNode(self, packageTreeNode, includePath=1): """Returns a filename where documentation for packageTreeNode should be written. The filename will be in the output directory, possibly in a subdirectory based on the path from the input root to the input file. For example:: input_directory : /foo/input containing : /foo/input/bar.py output_directory : /foo/output results in : /foo/output/input/bar.py """ trace.into('TALDocset', 'getOutputFilenameForPackageTreeNode', outputLevel=TRACE_LEVEL) filename = base.MultiFileDocSet.getOutputFilenameForPackageTreeNode( self, packageTreeNode, includePath=includePath, ) if packageTreeNode.getMimeType() == ('application/x-directory', None): # # This is a directory. # filename_with_extension = os.path.join(filename, 'index.html') else: # # This is not a directory (file, module, class, etc.). # filename_with_extension = '%s.html' % filename trace.outof(filename_with_extension, outputLevel=TRACE_LEVEL) return filename_with_extension def _initializeWriters(self): """Hook to allow subclasses to register writers without having to override __init__ with all of its arguments. """ base.MultiFileDocSet._initializeWriters(self) return def renderTemplateToFile(self, template, outputFilename, packageTreeNode, **extraContext): context = {} context.update(extraContext) context['node'] = packageTreeNode context['docset'] = self rendered_text = template.render(context) output = self.openOutput(outputFilename, packageTreeNode) try: output.write(rendered_text) finally: output.close() return def writeTOCFile(self, packageTreeNode): """Write the table of contents for a directory. Subclasses must implement this method. The packageTreeNode is a directory, and the table of contents for that directory should be written as appropriate. """ trace.into('TALDocset', 'writeTOCFile', packageTreeNode=packageTreeNode, outputLevel=TRACE_LEVEL, ) output_filename = self.getOutputFilenameForPackageTreeNode( packageTreeNode) template = self.template_set['toc.pt'] readme_text, text_format = packageTreeNode.getDocStringAndFormat() description = self.formatText(readme_text, text_format) self.renderTemplateToFile( template, output_filename, packageTreeNode, title=self.title, subtitle=packageTreeNode.getRelativeFilename(), description=description, ) trace.outof(outputLevel=TRACE_LEVEL) return def writeFileHeader(self, output, packageTreeNode, title='', subtitle=''): """Does nothing. """ return def writeFileFooter(self, output): """Does nothing. """ return def processPythonFile(self, packageTreeNode): """Handler for text/x-python nodes. """ self.statusMessage('processPythonFile needs work') #raise NotImplementedError('processPythonFile') return def processPlainTextFile(self, packageTreeNode): """Handler for text/x-structured and text/plain nodes. Converts the input file to the output file format and generates the output. The output directory is assumed to already exist. """ trace.into('TALDocset', 'processPlainTextFile', packageTreeNode=packageTreeNode, outputLevel=TRACE_LEVEL, ) canonical_path = packageTreeNode.getPath(1) canonical_filename = apply(os.path.join, canonical_path) output_filename = self.getOutputFilenameForPackageTreeNode( packageTreeNode) self.statusMessage('Translating: "%s"\n to: "%s"' % ( canonical_filename, output_filename, )) template = self.template_set['plain_text.pt'] converter_factory = getConverterFactoryForFile(canonical_filename) converter = converter_factory() input_file = converter.getExternalDocumentationFile(canonical_filename) raw_body = str(input_file) cooked_body = converter.convert(raw_body, 'html', level=2) from happydoclib.docset.docset_TAL.TAL.HTMLParser import HTMLParseError try: self.renderTemplateToFile( template, output_filename, packageTreeNode, title=self.title, subtitle=packageTreeNode.getRelativeFilename(), raw_body=raw_body, cooked_body=cooked_body, ) except HTMLParseError, msg: # # Could not handle cooked body. # self.warningMessage('Error converting %s' % canonical_filename) self.warningMessage('%s' % msg) self.renderTemplateToFile( template, output_filename, packageTreeNode, title=self.title, subtitle=packageTreeNode.getRelativeFilename(), raw_body=raw_body, cooked_body='
\n%s\n
\n' % raw_body, ) trace.outof(outputLevel=TRACE_LEVEL) return def processPythonClass(self, packageTreeNode): """Writes information about classes in this module to the output stream. """ self.statusMessage('processPythonClass needs work') #raise NotImplementedError('processPythonClass') return ## ## METHODS USED BY TEMPLATES ## def getHREFToNode(self, source, destination): """Returns the HREF pointing to destination from the current node. """ href = self._computeRelativeHREF(source, destination) return href def getPythonSubNodes(self, node): """Return a list of subnodes with mimetype text/x-python, filtering out __init__.py if it is present. """ subnodes = node.getSubNodes(['text/x-python']) subnodes = filter(lambda x: x.getName() != '__init__.py', subnodes, ) return subnodes def getImportData(self, packageTreeNode): """Retrieves the import data for the node, and converts the data structure to something that is easier to work with in the template. """ trace.into('TALDocset', 'getImportData', packageTreeNode=packageTreeNode, outputLevel=TRACE_LEVEL) import_data = packageTreeNode.getImportData() sortable_import_data = [ (m.lower(), m, s) for (m, s) in import_data ] sortable_import_data.sort() import_data = [ (m, s) for (ignore, m, s) in sortable_import_data ] response = [] for module_name, symbol_names in import_data: trace.writeVar(module_name=module_name, symbol_names=symbol_names, outputLevel=TRACE_LEVEL) url = getPythonSystemModuleURL(module_name) if url: trace.write('Python module', outputLevel=TRACE_LEVEL) link = '%s' % (url, module_name) response.append( (link, symbol_names) ) continue referenced_module = packageTreeNode.findNodeFromDottedName(module_name) if referenced_module is not None: trace.write('Reference to another scanned module', outputLevel=TRACE_LEVEL) # # Get the link to the module # module_url = self.getHREFToNode(packageTreeNode, referenced_module, ) module_link = '%s' % (module_url, module_name) if not symbol_names: trace.write('No symbol names', outputLevel=TRACE_LEVEL) response.append( (module_link, symbol_names) ) continue # # Get links to the symbols, if we can. # name_urls = [] for symbol_name in symbol_names: symbol_node = referenced_module.findNodeFromDottedName(symbol_name) if symbol_node is None: name_urls.append(symbol_name) continue symbol_url = self.getHREFToNode(packageTreeNode, symbol_node, ) symbol_link = '%s' % (symbol_url, symbol_name, ) name_urls.append(symbol_link) response.append( (module_link, name_urls) ) else: trace.write('Unknown module', outputLevel=TRACE_LEVEL) # # We do not know the module, so just take # the names as they were given. # response.append( (module_name, symbol_names) ) trace.outof(outputLevel=TRACE_LEVEL) return response def entryPoint(): return { 'name':'TAL', 'factory':TALDocset, }