#!/usr/bin/env python
#
# $Id: __init__.py,v 1.5 2006/12/05 13:10:45 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.5 2006/12/05 13:10:45 doughellmann Exp $',
'creator' : 'Doug Hellmann',
'project' : 'HappyDoc',
'created' : 'Sun, 19-Jan-2003 16:38:01 EST',
#
# Current Information
#
'author' : '$Author: doughellmann $',
'version' : '$Revision: 1.5 $',
'date' : '$Date: 2006/12/05 13:10:45 $',
}
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='<pre>\n%s\n</pre>\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 = '<a href="%s">%s</a>' % (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 = '<a href="%s">%s</a>' % (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 = '<a href="%s">%s</a>' % (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,
}
|