[Epydoc-commits] SF.net SVN: epydoc: [1806] trunk/epydoc/src/epydoc/docwriter
Brought to you by:
edloper
|
From: <ed...@us...> - 2008-03-04 02:31:58
|
Revision: 1806
http://epydoc.svn.sourceforge.net/epydoc/?rev=1806&view=rev
Author: edloper
Date: 2008-03-03 18:31:57 -0800 (Mon, 03 Mar 2008)
Log Message:
-----------
- Assorted improvements to latex output
- EpydocFunction, EpydocVariable, and EpydocProperty commands now
use xkeyval to pass arguments in a more readable and extensible
manner.
- Adjusted the output to fix indentation, and make the generated
latex easier to read
- Always write classes to separate files; and use \input to read
them in.
- Added function to parse latex output & look for warnings
Modified Paths:
--------------
trunk/epydoc/src/epydoc/docwriter/latex.py
trunk/epydoc/src/epydoc/docwriter/latex_sty.py
Modified: trunk/epydoc/src/epydoc/docwriter/latex.py
===================================================================
--- trunk/epydoc/src/epydoc/docwriter/latex.py 2008-02-27 20:24:06 UTC (rev 1805)
+++ trunk/epydoc/src/epydoc/docwriter/latex.py 2008-03-04 02:31:57 UTC (rev 1806)
@@ -45,7 +45,7 @@
self.docindex = docindex
# Process keyword arguments
self._show_private = kwargs.get('show_private', 0)
- self._prj_name = kwargs.get('prj_name', None) or 'API Documentation'
+ self._prj_name = kwargs.get('prj_name', None)
self._show_crossrefs = kwargs.get('crossref', 1)
self._index = kwargs.get('index', 1)
self._hyperlink = kwargs.get('hyperlink', True)
@@ -124,8 +124,7 @@
if isinstance(val_doc, ModuleDoc):
filename = '%s-module.tex' % val_doc.canonical_name
self._write(self.write_module, directory, filename, val_doc)
- elif (isinstance(val_doc, ClassDoc) and
- self._list_classes_separately):
+ elif isinstance(val_doc, ClassDoc):
filename = '%s-class.tex' % val_doc.canonical_name
self._write(self.write_class, directory, filename, val_doc)
@@ -204,12 +203,8 @@
generate.
@rtype: C{int}
"""
- n = 1
- for doc in self.valdocs:
- if isinstance(doc, ModuleDoc): n += 1
- if isinstance(doc, ClassDoc) and self._list_classes_separately:
- n += 1
- return n
+ return 1 + len([doc for doc in self.valdocs
+ if isinstance(doc, (ClassDoc, ModuleDoc))])
def _mkdir(self, directory):
"""
@@ -229,22 +224,23 @@
self.write_header(out, 'Include File')
self.write_preamble(out)
out('\n\\begin{document}\n\n')
- self.write_start_of(out, 'Header')
+ out(self.start_of('Header'))
# Write the title.
- self.write_start_of(out, 'Title')
- out('\\title{%s}\n' % plaintext_to_latex(self._prj_name, 1))
+ out(self.start_of('Title'))
+ out('\\title{%s}\n' % plaintext_to_latex(
+ self._prj_name or 'API Documentation', 1))
out('\\author{API Documentation}\n')
out('\\maketitle\n')
# Add a table of contents.
- self.write_start_of(out, 'Table of Contents')
+ out(self.start_of('Table of Contents'))
out('\\addtolength{\\parskip}{-1ex}\n')
out('\\tableofcontents\n')
out('\\addtolength{\\parskip}{1ex}\n')
# Include documentation files.
- self.write_start_of(out, 'Includes')
+ out(self.start_of('Includes'))
for val_doc in self.valdocs:
if isinstance(val_doc, ModuleDoc):
out('\\include{%s-module}\n' % val_doc.canonical_name)
@@ -258,11 +254,11 @@
# Add the index, if requested.
if self._index:
- self.write_start_of(out, 'Index')
+ out(self.start_of('Index'))
out('\\printindex\n\n')
# Add the footer.
- self.write_start_of(out, 'Footer')
+ out(self.start_of('Footer'))
out('\\end{document}\n\n')
def write_preamble(self, out):
@@ -307,10 +303,10 @@
def write_module(self, out, doc):
self.write_header(out, doc)
- self.write_start_of(out, 'Module Description')
+ out(self.start_of('Section Heading', doc))
# Add this module to the index.
- out(' ' + self.indexterm(doc, 'start'))
+ out(self.indexterm(doc, 'start'))
# Add a section marker.
out(self.section('%s %s' % (self.doc_kind(doc),
@@ -319,12 +315,13 @@
# Add the module's description.
if doc.descr not in (None, UNKNOWN):
- out(' '*4 + '\\begin{EpydocModuleDescription}%\n')
+ out(self.start_of('Description', doc))
+ out('\\begin{EpydocModuleDescription}%\n')
out(self.docstring_to_latex(doc.descr, doc, 4))
- out(' '*4 + '\\end{EpydocModuleDescription}\n')
+ out('\\end{EpydocModuleDescription}\n')
# Add version, author, warnings, requirements, notes, etc.
- self.write_standard_fields(out, doc)
+ out(self.metadata(doc))
# If it's a package, list the sub-modules.
if (self._list_submodules and self._show_submodule_list and
@@ -342,39 +339,49 @@
if not self._list_classes_separately:
classes = doc.select_variables(imported=False, value_type='class',
public=self._public_filter)
- for var_doc in classes:
- self.write_class(out, var_doc.value)
+ if classes:
+ out(self.start_of('Classes', doc))
+ for var_doc in classes:
+ # don't use \include -- can't be nested.
+ out('\\input{%s-class}\n' % var_doc.value.canonical_name)
# Mark the end of the module (for the index)
- out(' ' + self.indexterm(doc, 'end'))
+ out(self.start_of('Footer', doc))
+ out(self.indexterm(doc, 'end'))
def render_graph(self, graph):
if graph is None: return ''
graph.caption = graph.title = None
return graph.to_latex(self._directory) or ''
- def write_class(self, out, doc, short_name=None):
- if short_name is None: short_name = doc.canonical_name[-1]
-
- if self._list_classes_separately:
- self.write_header(out, doc)
- self.write_start_of(out, 'Class Description')
+ def write_class(self, out, doc):
+ self.write_header(out, doc)
+ out(self.start_of('Section Heading', doc))
# Add this class to the index.
- out(' ' + self.indexterm(doc, 'start'))
+ out(self.indexterm(doc, 'start'))
- # Add a section marker.
+ # Decide on our short (contextualized) name.
if self._list_classes_separately:
+ short_name = doc.canonical_name
+ if doc.defining_module not in (None, UNKNOWN):
+ short_name = doc.canonical_name.contextualize(
+ doc.defining_module.canonical_name)
+ else:
+ short_name = doc.canonical_name[-1]
+
+ # Decidie on our initial section level.
+ if self._list_classes_separately:
seclevel = 0
- out(self.section('%s %s' % (self.doc_kind(doc),
- _dotted(doc.canonical_name)),
- seclevel, ref=doc))
else:
seclevel = 1
- out(self.section('%s %s' % (self.doc_kind(doc),
- _dotted(short_name)),
- seclevel, ref=doc))
+ # Add a section marker.
+ out(self.section('%s %s' % (self.doc_kind(doc), _dotted(short_name)),
+ seclevel, ref=doc))
+
+ # Display our base classes & subclasses
+ out(self.start_of('Class Tree', doc))
if ((doc.bases not in (UNKNOWN, None) and len(doc.bases) > 0) or
(doc.subclasses not in (UNKNOWN,None) and len(doc.subclasses)>0)):
# Display bases graphically, if requested.
@@ -402,12 +409,13 @@
# The class's description.
if doc.descr not in (None, UNKNOWN):
- out(' '*4 + '\\begin{EpydocClassDescription}\n')
- out(self.docstring_to_latex(doc.descr, doc))
- out(' '*4 + '\\end{EpydocClassDescription}\n')
+ out(self.start_of('Description', doc))
+ out('\\begin{EpydocClassDescription}%\n')
+ out(self.docstring_to_latex(doc.descr, doc, 4))
+ out('\\end{EpydocClassDescription}\n')
# Version, author, warnings, requirements, notes, etc.
- self.write_standard_fields(out, doc)
+ out(self.metadata(doc))
# Contents.
self.write_list(out, 'Methods', doc, 'EpydocFunctionList',
@@ -422,19 +430,24 @@
'instancevariable', seclevel+1)
# Mark the end of the class (for the index)
- out(' ' + self.indexterm(doc, 'end'))
+ out(self.start_of('Footer', doc))
+ out(self.indexterm(doc, 'end'))
# Write any nested classes. These will have their own
# section (at the same level as this section)
- for nested_class in doc.select_variables(imported=False,
- value_type='class',
- public=self._public_filter):
- if (nested_class.value.canonical_name != UNKNOWN and
- (nested_class.value.canonical_name[:-1] ==
- doc.canonical_name)):
- self.write_class(out, nested_class.value,
- DottedName(short_name,
- nested_class.canonical_name[-1]))
+ if not self._list_classes_separately:
+ nested_classes = doc.select_variables(
+ imported=False, value_type='class',
+ public=self._public_filter)
+ if nested_classes:
+ out(self.start_of('Nested Classes', doc))
+ for nested_class in nested_classes:
+ if (nested_class.value.canonical_name != UNKNOWN and
+ (nested_class.value.canonical_name[:-1] ==
+ doc.canonical_name)):
+ # don't use \include -- can't be nested.
+ out('\\input{%s-class}\n' %
+ nested_class.value.canonical_name)
#////////////////////////////////////////////////////////////
#{ Module hierarchy trees
@@ -456,7 +469,7 @@
def write_module_list(self, out, doc):
if len(doc.submodules) == 0: return
- self.write_start_of(out, 'Submodules')
+ out(self.start_of('Submodules', doc))
out(self.section('Submodules', 1))
out('\\begin{EpydocModuleList}\n')
@@ -479,10 +492,11 @@
@rtype: C{string}
"""
- out(' '*depth + '\\item[%s]' % _hyperlink(doc, doc.canonical_name[-1]))
+ out(' '*depth + '\\item[%s]\n' %
+ _hyperlink(doc, doc.canonical_name[-1]))
if doc.summary not in (None, UNKNOWN):
- out(' %s\n' % self.docstring_to_latex(doc.summary, doc))
+ out(self.docstring_to_latex(doc.summary, doc, depth+2))
out(self.crossref(doc) + '\n\n')
if doc.submodules != UNKNOWN and doc.submodules:
out(' '*depth + ' \\begin{EpydocModuleList}\n')
@@ -498,7 +512,9 @@
if width is None:
width = self._find_tree_width(doc)+2
linespec = []
- s = ('&'*(width-4)+'\\multicolumn{2}{l}{\\textbf{%s}}\n' %
+ s = (' %% Class tree line for this class (%s)\n ' %
+ doc.canonical_name + '&'*(width-4) +
+ '\\multicolumn{2}{l}{\\textbf{%s}}\n' %
_dotted('%s'%self._base_name(doc)))
s += '\\end{tabular}\n\n'
top = 1
@@ -534,36 +550,36 @@
return width
def _base_tree_line(self, doc, width, linespec):
+ # linespec is a list of booleans.
base_name = _dotted(self._base_name(doc))
- # linespec is a list of booleans.
- s = '%% Line for %s, linespec=%s\n' % (base_name, linespec)
-
+ s = ' %% Class tree line for base "%s"\n' % self._base_name(doc)
labelwidth = width-2*len(linespec)-2
# The base class name.
- s += ('\\multicolumn{%s}{r}{' % labelwidth)
- s += '\\settowidth{\\EpydocBCL}{%s}' % base_name
- s += ('\\multirow{2}{\\EpydocBCL}{%s}}\n' %
- _hyperlink(doc, self._base_name(doc)))
+ s += ' \\multicolumn{%s}{r}{\n' % labelwidth
+ s += ' \\settowidth{\\EpydocBCL}{%s}\n' % base_name
+ s += ' \\multirow{2}{\\EpydocBCL}{\n'
+ s += ' %s}}\n' % _hyperlink(doc, self._base_name(doc))
# The vertical bars for other base classes (top half)
for vbar in linespec:
- if vbar: s += '&&\\multicolumn{1}{|c}{}\n'
- else: s += '&&\n'
+ if vbar: s += ' &&\\multicolumn{1}{|c}{}\n'
+ else: s += ' &&\n'
# The horizontal line.
- s += ' \\\\\\cline{%s-%s}\n' % (labelwidth+1, labelwidth+1)
+ s += ' \\\\\\cline{%s-%s}\n' % (labelwidth+1, labelwidth+1)
# The vertical bar for this base class.
- s += ' ' + '&'*labelwidth
+ s += ' ' + '&'*labelwidth
s += '\\multicolumn{1}{c|}{}\n'
# The vertical bars for other base classes (bottom half)
for vbar in linespec:
- if vbar: s += '&\\multicolumn{1}{|c}{}&\n'
- else: s += '&&\n'
- s += ' \\\\\n'
+ if vbar: s += ' &\\multicolumn{1}{|c}{}&\n'
+ else: s += ' &&\n'
+
+ s += ' \\\\\n'
return s
@@ -583,7 +599,7 @@
if not groups: return
# Write a header.
- self.write_start_of(out, 'Classes')
+ out(self.start_of('Classes', doc))
out(self.section('Classes', 1))
out('\\begin{EpydocClassList}\n')
@@ -605,8 +621,8 @@
out(' ' + '\\item[%s]' % _hyperlink(var_doc.target,
var_doc.name))
if doc.summary not in (None, UNKNOWN):
- out(': %s\n' % self.docstring_to_latex(doc.summary, doc))
- out(self.crossref(doc) + '\n\n')
+ out(': %\n' + self.docstring_to_latex(doc.summary, doc))
+ out(self.crossref(doc))
#////////////////////////////////////////////////////////////
#{ Details Lists
@@ -627,8 +643,8 @@
if not groups: return
# Write a header.
- self.write_start_of(out, heading)
- out(' '+self.section(heading, seclevel))
+ out(self.start_of(heading, doc))
+ out(self.section(heading, seclevel))
out('\\begin{%s}\n' % list_type)
@@ -718,6 +734,15 @@
#////////////////////////////////////////////////////////////
#{ Function Details
#////////////////////////////////////////////////////////////
+
+ def replace_par(self, out):
+ def new_out(s):
+ s = re.sub('(?m)\n([ \t]*\n)+', '\\par\n', s)
+ s = re.sub(r'\\par\b', r'\\EpydocPar', s)
+ s = re.sub(r'(?m)^([ \t]*)([^ \t].*)\\EpydocPar\n',
+ r'\1\2\n\1\\EpydocPar\n', s)
+ out(s)
+ return new_out
def write_function(self, out, var_doc):
func_doc = var_doc.value
@@ -727,63 +752,73 @@
# select the containing section, and won't give a reference
# directly to the function.
if not is_inherited:
- out(' %s%%\n' % self.indexterm(func_doc))
+ out(' %s' % self.indexterm(func_doc))
- # This latex command takes 8 arguments.
- out('\\EpydocFunction{%\n')
+ out(' \\EpydocFunction{%% <<< %s >>>\n' % var_doc.name)
+ # We're passing arguments using xkeyval, which is unhappy if
+ # the arguments contain \par. So replace every occurence of
+ # \par with \EpydocPar (which is defined to just return \par).
+ out = self.replace_par(out)
+
# Argument 1: the function signature
- out(self.function_signature(var_doc))
- out('}{%\n')
+ out(' signature={%%\n%s }' %
+ self.function_signature(var_doc))
# Argument 2: the function description
if func_doc.descr not in (None, UNKNOWN):
- out(self.docstring_to_latex(func_doc.descr, func_doc, 4))
- out('}{%\n')
+ out(',\n description={%\n')
+ out(self.docstring_to_latex(func_doc.descr, func_doc, 6))
+ out(' }')
# Argument 3: the function parameter descriptions
if func_doc.arg_descrs or func_doc.arg_types:
+ out(',\n parameters={%\n')
self.write_function_parameters(out, var_doc)
- out('}{%\n')
+ out(' }')
# Argument 4: The return description
if func_doc.return_descr not in (None, UNKNOWN):
- out(self.docstring_to_latex(func_doc.return_descr,
- func_doc, 6))
- out('}{%\n')
+ out(',\n returndescr={%\n')
+ out(self.docstring_to_latex(func_doc.return_descr, func_doc, 6))
+ out(' }')
# Argument 5: The return type
if func_doc.return_type not in (None, UNKNOWN):
- out(self.docstring_to_latex(func_doc.return_type,
- func_doc, 6).strip())
- out('}{%\n')
+ out(',\n returntype={%\n')
+ out(self.docstring_to_latex(func_doc.return_type, func_doc, 6))
+ out(' }')
# Argument 6: The raises section
if func_doc.exception_descrs not in (None, UNKNOWN, [], ()):
+ out(',\n raises={%\n')
out(' '*6+'\\begin{EpydocFunctionRaises}\n')
for name, descr in func_doc.exception_descrs:
out(' '*10+'\\item[%s]\n\n' %
plaintext_to_latex('%s' % name))
out(self.docstring_to_latex(descr, func_doc, 10))
- out(' '*6+'\\end{EpydocFunctionRaises}\n\n')
- out('}{%\n')
+ out(' '*6+'\\end{EpydocFunctionRaises}\n')
+ out(' }')
# Argument 7: The overrides section
if var_doc.overrides not in (None, UNKNOWN):
+ out(',\n overrides={%\n')
out('\\EpydocFunctionOverrides')
if (func_doc.docstring in (None, UNKNOWN) and
var_doc.overrides.value.docstring not in (None, UNKNOWN)):
out('[1]')
- out('{%s}\n\n'
+ out('{%s}\n'
% _hyperlink(var_doc.overrides,
'%s' % var_doc.overrides.canonical_name))
- out('}{%\n')
+ out(' }')
# Argument 8: The metadata section
- self.write_standard_fields(out, func_doc)
- out('}\n')
-
+ metadata = self.metadata(func_doc, 6)
+ if metadata:
+ out(',\n metadata={%%\n%s }' % metadata)
+ out('}%\n')
+
def write_function_parameters(self, out, var_doc):
func_doc = var_doc.value
# Find the longest name.
@@ -803,7 +838,7 @@
# Display params
for (arg_names, arg_descr) in arg_descrs:
arg_name = plaintext_to_latex(', '.join(arg_names))
- out('%s\\item[%s]\n\n' % (' '*10, arg_name))
+ out('%s\\item[%s]\n' % (' '*8, arg_name))
if arg_descr:
out(self.docstring_to_latex(arg_descr, func_doc, 10))
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
@@ -816,16 +851,17 @@
lhs = 'type'
else:
lhs = 'type of %s' % arg_name
- rhs = self.docstring_to_latex(arg_typ, func_doc).strip()
- out('%s{\\it (%s=%s)}\n\n' % (' '*12, lhs, rhs))
- out(' '*6+'\\end{EpydocFunctionParameters}\n\n')
+ rhs = self.docstring_to_latex(arg_typ, func_doc, 14)
+ out('%s\\textit{ (%s=%%\n%s%s)}\n' % (' '*12, lhs,
+ rhs, ' '*12))
+ out(' '*6+'\\end{EpydocFunctionParameters}\n')
- def function_signature(self, var_doc):
+ def function_signature(self, var_doc, indent=6):
func_doc = var_doc.value
func_name = var_doc.name
- s = ('\\begin{EpydocFunctionSignature}{%s}%%\n' %
- _hypertarget(var_doc, func_name))
+ s = ('%s\\begin{EpydocFunctionSignature}%%\n%s {%s}%%\n' %
+ (indent*' ', indent*' ', _hypertarget(var_doc, func_name)))
# This should never happen, but just in case:
if func_doc not in (None, UNKNOWN):
@@ -842,9 +878,10 @@
plaintext_to_latex(func_doc.vararg))
if func_doc.kwarg:
args.append('\\KWArg{%s}' % plaintext_to_latex(func_doc.kwarg))
-
- s += ' '+'%\n \\and'.join(args)+'%\n'
- s += '\\end{EpydocFunctionSignature}%\n'
+
+ argindent = (indent*' '+' ')
+ s += argindent+('%%\n%s\\and' % argindent).join(args)+'%\n'
+ s += indent*' '+'\\end{EpydocFunctionSignature}%\n'
return s
@@ -869,66 +906,80 @@
#////////////////////////////////////////////////////////////
def write_var(self, out, var_doc):
+ # We're passing arguments using xkeyval, which is unhappy if
+ # the arguments contain \par. So replace every occurence of
+ # \par with \EpydocPar (which is defined to just return \par).
+ out = self.replace_par(out)
+
has_descr = var_doc.descr not in (None, UNKNOWN)
has_type = var_doc.type_descr not in (None, UNKNOWN)
has_repr = (var_doc.value not in (None, UNKNOWN) and
(var_doc.value.parse_repr is not UNKNOWN or
var_doc.value.pyval_repr() is not UNKNOWN))
-
- out('\\EpydocVariable{%s}{' % _hypertarget(var_doc, var_doc.name))
+
+ out(' \\EpydocVariable{%% <<< %s >>>\n' % var_doc.name)
+ out(' name={%s}' % _hypertarget(var_doc, var_doc.name))
if has_descr:
- out(self.docstring_to_latex(var_doc.descr, var_doc, 10).strip())
- out('}{')
+ out(',\n description={%%\n%s }' %
+ self.docstring_to_latex(var_doc.descr, var_doc, 6))
if has_type:
- out(self.docstring_to_latex(var_doc.type_descr,
- var_doc, 12).strip())
- out('}{')
+ out(',\n type={%%\n%s }' %
+ self.docstring_to_latex(var_doc.type_descr, var_doc, 6))
if has_repr:
- out(var_doc.value.summary_pyval_repr().to_latex(None))
- out('}\n')
+ out(',\n value={%s}' %
+ var_doc.value.summary_pyval_repr().to_latex(None))
+ metadata = self.metadata(var_doc, 6)
+ if metadata:
+ out(',\n metadata={%%\n%s }' % metadata)
+ out('}%\n')
#////////////////////////////////////////////////////////////
#{ Property Details
#////////////////////////////////////////////////////////////
def write_property(self, out, var_doc):
+ # We're passing arguments using xkeyval, which is unhappy if
+ # the arguments contain \par. So replace every occurence of
+ # \par with \EpydocPar (which is defined to just return \par).
+ out = self.replace_par(out)
+
prop_doc = var_doc.value
has_descr = prop_doc.descr not in (None, UNKNOWN)
has_type = prop_doc.type_descr not in (None, UNKNOWN)
- out('\\EpydocProperty{%s}{' % _hypertarget(var_doc, var_doc.name))
+
+ out(' \\EpydocProperty{%% <<< %s >>>\n' % var_doc.name)
+ out(' name={%s}' % _hypertarget(var_doc, var_doc.name))
if has_descr:
- out(self.docstring_to_latex(prop_doc.descr,
- prop_doc, 10).strip())
- out('}{')
+ out(',\n description={%%\n%s }' %
+ self.docstring_to_latex(prop_doc.descr, prop_doc, 6))
if has_type:
- out(self.docstring_to_latex(prop_doc.type_descr,
- prop_doc, 12).strip())
- out('}{')
+ out(',\n type={%%\n%s }' %
+ self.docstring_to_latex(prop_doc.type_descr, prop_doc, 6))
# [xx] What if the accessor is private and show_private=False?
- if (prop_doc.fget not in (None, UNKNOWN) and
- not prop_doc.fget.canonical_name[0].startswith('??')):
- out(_dotted(prop_doc.fget.canonical_name))
- out('}{')
- if (prop_doc.fset not in (None, UNKNOWN) and
- not prop_doc.fset.canonical_name[0].startswith('??')):
- out(_dotted(prop_doc.fset.canonical_name))
- out('}{')
- if (prop_doc.fdel not in (None, UNKNOWN) and
- not prop_doc.fdel.canonical_name[0].startswith('??')):
- out(_dotted(prop_doc.fdel.canonical_name))
- out('}\n')
+ for accessor in ('fget', 'fset', 'fdel'):
+ accessor_func = getattr(prop_doc, accessor)
+ if (accessor_func not in (None, UNKNOWN) and
+ not accessor_func.canonical_name[0].startswith('??')):
+ if isinstance(accessor_func, RoutineDoc):
+ suffix = '()'
+ else:
+ suffix = ''
+ out(',\n %s={%s%s}' %
+ (accessor, _dotted(accessor_func.canonical_name), suffix))
+ metadata = self.metadata(prop_doc, 6)
+ if metadata:
+ out(',\n metadata={%%\n%s }' % metadata)
+ out('}%\n')
#////////////////////////////////////////////////////////////
#{ Standard Fields
#////////////////////////////////////////////////////////////
- # Copied from HTMLWriter:
- def write_standard_fields(self, out, doc):
+ def metadata(self, doc, indent=0):
fields = []
field_values = {}
+ s = ''
- #if _sort_fields: fields = STANDARD_FIELD_NAMES [XX]
-
for (field, arg, descr) in doc.metadata:
if field not in field_values:
fields.append(field)
@@ -938,38 +989,49 @@
else:
field_values.setdefault(field,[]).append(descr)
+ if fields and indent == 0:
+ s += self.start_of('Metadata', doc)
+
for field in fields:
if field.takes_arg:
for arg, descrs in field_values[field].items():
- self.write_standard_field(out, doc, field, descrs, arg)
-
+ s += self.meatadata_field(doc, field, descrs,
+ indent, arg)
else:
- self.write_standard_field(out, doc, field, field_values[field])
+ s += self.meatadata_field(doc, field, field_values[field],
+ indent)
+ return s
+
- def write_standard_field(self, out, doc, field, descrs, arg=''):
+ def meatadata_field(self, doc, field, descrs, indent, arg=''):
singular = field.singular
plural = field.plural
if arg:
singular += ' (%s)' % arg
plural += ' (%s)' % arg
- out(self._descrlist([self.docstring_to_latex(d, doc) for d in descrs],
- field.singular, field.plural, field.short))
-
- def _descrlist(self, items, singular, plural=None, short=0):
+ return (' '*indent + '%% %s:\n' % field.singular +
+ self._descrlist([self.docstring_to_latex(d, doc, indent+2)
+ for d in descrs],
+ field.singular, field.plural, field.short,
+ indent))
+
+ # [xx] ignores indent for now
+ def _descrlist(self, items, singular, plural=None, short=0, indent=0):
+ ind = indent*' '
if plural is None: plural = singular
if len(items) == 0: return ''
if len(items) == 1 and singular is not None:
- return ('\\EpydocMetadataSingleValue{%s}{%s}\n\n' %
- (singular, items[0]))
+ return ('%s\\EpydocMetadataSingleValue{%s}{\n%s%s}\n' %
+ (ind, singular, items[0], ind))
if short:
- s = '\\begin{EpydocMetadataShortList}{%s}%%\n ' % plural
- s += '%\n \\and '.join([item.strip() for item in items])
- s += '%\n\\end{EpydocMetadataShortList}\n\n'
+ s = '%s\\begin{EpydocMetadataShortList}{%s}\n' % (ind, plural)
+ s += ('%s\\and\n' % ind).join(items)
+ s += '%s\\end{EpydocMetadataShortList}\n' % ind
return s
else:
- s = '\\begin{EpydocMetadataLongList}{%s}%%\n' % plural
- s += '\n\n'.join([' \item %s%%' % item for item in items])
- s += '\n\\end{EpydocMetadataLongList}\n\n'
+ s = '%s\\begin{EpydocMetadataLongList}{%s}\n' % (ind, plural)
+ s += ''.join(['%s \item\n%s' % (ind,item) for item in items])
+ s += '%s\\end{EpydocMetadataLongList}\n' % ind
return s
@@ -989,15 +1051,20 @@
_docstring_linker = _LatexDocstringLinker()
def docstring_to_latex(self, docstring, where, indent=0, breakany=0):
+ """
+ Return a latex string that renders the given docstring. This
+ string expects to start at the beginning of a line; and ends
+ with a newline.
+ """
if docstring is None: return ''
- s = docstring.to_latex(self._docstring_linker, indent=indent,
+ s = docstring.to_latex(self._docstring_linker, indent=indent+2,
directory=self._directory,
docindex=self.docindex,
context=where,
hyperref=self._hyperref)
- return (' '*indent + '\\begin{EpydocDescription}%\n' +
- s.strip() + '%\n' +
- ' '*indent + '\\end{EpydocDescription}\n\n')
+ return (' '*indent + '\\begin{EpydocDescription}\n' +
+ ' '*indent + ' ' + s.strip() + '%\n' +
+ ' '*indent + '\\end{EpydocDescription}\n')
#////////////////////////////////////////////////////////////
#{ Helpers
@@ -1013,10 +1080,10 @@
out('\n%%\n%% Generated by epydoc %s\n' % epydoc.__version__)
out('%% [%s]\n%%\n' % time.asctime(time.localtime(time.time())))
- def write_start_of(self, out, section_name):
- out('\n' + 75*'%' + '\n')
- out('%%' + section_name.center(71) + '%%\n')
- out(75*'%' + '\n\n')
+ def start_of(self, section_name, doc=None):
+ return ('\n' + 75*'%' + '\n' +
+ '%%' + section_name.center(71) + '%%\n' +
+ 75*'%' + '\n\n')
def section(self, title, depth=0, ref=None):
sec = self.SECTIONS[depth+self._top_section]
@@ -1058,8 +1125,9 @@
# [xx] list modules, classes, and functions as top-level index
# items. Methods are listed under their classes. Nested classes
# are listed under their classes.
- def indexterm(self, doc, pos='only'):
- """Mark a term or section for inclusion in the index."""
+ def indexterm(self, doc, pos='only', indent=0):
+ """Return a latex string that marks the given term or section
+ for inclusion in the index. This string ends with a newline."""
if not self._index: return ''
if isinstance(doc, RoutineDoc) and not self._index_functions:
return ''
@@ -1078,8 +1146,10 @@
pieces.reverse()
kinds.reverse()
for i in range(1, len(pieces)):
- pieces[i] = '%s.%s' % (pieces[i-1], pieces[i])
- pieces = ['\\EpydocIndex{%s}{%s}{%s}' % (piece.lower(), piece, kind)
+ if not kinds[i].endswith('method'):
+ pieces[i] = '%s.%s' % (pieces[i-1], pieces[i])
+ pieces = ['\\EpydocIndex{%s}{%s}{%s}' %
+ (_dotted(piece.lower()), _dotted(piece), kind)
for (piece, kind) in zip (pieces, kinds)]
if pos == 'only': modifier = ''
@@ -1087,9 +1157,7 @@
elif pos == 'end': modifier = '|)'
else: raise AssertionError('Bad index position %s' % pos)
- term = '\\index{%s%s}\n' % ('!'.join(pieces), modifier)
-
- return term
+ return '%s\\index{%s%s}%%\n' % (' '*indent, '!'.join(pieces), modifier)
#: Map the Python encoding representation into mismatching LaTeX ones.
latex_encodings = {
@@ -1104,16 +1172,26 @@
enc = self._encoding.lower()
return self.latex_encodings.get(enc, enc)
- def crossref(self, doc):
+ def crossref(self, doc, indent=0):
if (self._show_crossrefs and
((isinstance(doc, ModuleDoc) and doc in self.module_set) or
(isinstance(doc, ClassDoc) and doc in self.class_set))):
- return '\\CrossRef{%s}' % (_label(doc),)
+ return '%s\\CrossRef{%s}%%\n' % (' '*indent, _label(doc),)
else:
return ''
def _label(doc):
- return ':'.join(doc.canonical_name)
+ # Convert to a string & replace . and _.
+ s = '%s' % doc.canonical_name
+ s = s.replace('.', ':').replace('_','-')
+
+ # Get rid of any other characters. This is necessary only if
+ # we're processing a script (whose name can be just about
+ # anything), an unreachable value, or an object whose name has
+ # been mangled with black magic.
+ s = re.sub('[^\w:-]', '-', s)
+
+ return s
# [xx] this should get used more often than it does, I think:
def _hyperlink(target, name):
@@ -1124,5 +1202,90 @@
def _dotted(name):
if not name: return ''
+ name = '%s' % name
+ # There are a couple of characters that even \\EpydocDottedName
+ # can't cope with; so filter them out.
+ name = re.sub('[%#]|\^\^+|\n', '?', name)
return '\\EpydocDottedName{%s}' % name
+LATEX_WARNING_RE = re.compile('|'.join([
+ r'(?P<file>\([\.a-zA-Z_\-/\\ \n0-9]+[.\n][a-z]{2,3}\b)',
+ (r'(?P<pkgwarn>^(Package|Latex) (?P<pkgname>[\w-]+) '+
+ r'Warning:[^\n]*\n(\((?P=pkgname)\)[^\n]*\n)*)'),
+ r'(?P<overfull>^(Overfull|Underfull)[^\n]*\n[^\n]*)',
+ r'(?P<latexwarn>^LaTeX\s+Warning:\s+[^\n]*)',
+ r'(?P<otherwarn>^[^\n]*Warning:[^\n]*)',
+ r'(?P<paren>[()])']),
+ re.MULTILINE+re.IGNORECASE)
+
+OVERFULL_RE = re.compile(
+ r'(?P<typ>Underfull|Overfull)\s+\\(?P<boxtype>[vh]box)\s+'
+ r'\((?P<size>\d+)[^\n\)]+\)[^\n]+\s+lines\s+'
+ r'(?P<start>\d+)')
+
+IGNORE_WARNING_REGEXPS = [
+ re.compile(r'LaTeX\s+Font\s+Warning:\s+.*\n\(Font\)\s*using.*instead'),
+ re.compile(r'LaTeX\s+Font\s+Warning:\s+Some\s+font\s+shapes\s+'
+ r'were\s+not\s+available,\s+defaults\s+substituted.'),
+ ]
+
+def show_latex_warnings(s):
+ s = re.sub('(.{79,79})\n', r'\1', s)
+
+ #[xx] we should probably pay special attention to overfull \vboxes.
+ overfull = underfull = 0
+ filestack = ['latex']
+ for m in LATEX_WARNING_RE.finditer(s):
+ # Check if it's something we don't care about.
+ for regexp in IGNORE_WARNING_REGEXPS:
+ if regexp.match(m.group()):
+ m = None; break
+ if m is None: continue
+ # LaTeX started reading a new file:
+ if m.group('file'):
+ filename = ''.join(m.group('file')[1:].split())
+ filename = re.sub(r'^\./', '', filename)
+ filestack.append(filename)
+ # Latex reported an overfull/underfull warning:
+ elif m.group('overfull'):
+ msg = m.group('overfull').strip().split('\n')[0]
+ if msg.lower().startswith('overfull'): overfull += 1
+ else: underfull += 1
+ m2 = OVERFULL_RE.match(msg)
+ if m2:
+ if m2.group('boxtype') == 'vbox':
+ log.warning('%s: %s' % (filestack[-1], msg))
+ elif (m2.group('typ').lower()=='overfull' and
+ int(m2.group('size')) > 50):
+ log.warning('%s: %s' % (filestack[-1], msg))
+ else:
+ log.debug('%s: %s' % (filestack[-1], msg))
+ else:
+ log.debug('%s: %s' % (filestack[-1], msg))
+ # Latex reported a warning:
+ elif m.group('latexwarn'):
+ msg = m.group('latexwarn').strip()
+ log.warning('%s: %s' % (filestack[-1], msg))
+ # A package reported a warning:
+ elif m.group('pkgwarn'):
+ msg = m.group('pkgwarn').strip()
+ log.warning('%s:\n%s' % (filestack[-1], msg))
+ else:
+ # Display anything else that looks like a warning:
+ if m.group('otherwarn'):
+ msg = m.group('otherwarn').strip()
+ log.warning('%s: %s' % (filestack[-1], msg))
+ # Update to account for parens.
+ n = m.group().count('(') - m.group().count(')')
+ if n > 0: filestack += [None] * n
+ if n < 0: del filestack[n:]
+ if overfull or underfull:
+ msgs = []
+ if overfull == 1: msgs.append('1 overfull box')
+ elif overfull: msgs.append('%d overfull boxes' % overfull)
+ if underfull == 1: msgs.append('1 underfull box')
+ elif underfull: msgs.append('%d underfull boxes' % underfull)
+ log.warning('LaTeX reported %s' % ' and '.join(msgs))
+
+#log.register_logger(log.SimpleLogger(log.DEBUG))
+#show_latex_warnings(open('/tmp/po.test').read())
Modified: trunk/epydoc/src/epydoc/docwriter/latex_sty.py
===================================================================
--- trunk/epydoc/src/epydoc/docwriter/latex_sty.py 2008-02-27 20:24:06 UTC (rev 1805)
+++ trunk/epydoc/src/epydoc/docwriter/latex_sty.py 2008-03-04 02:31:57 UTC (rev 1806)
@@ -75,6 +75,7 @@
\RequirePackage[headings]{fullpage}
\RequirePackage[usenames]{color}
\RequirePackage{graphicx}
+\RequirePackage{url}
\@ifclassloaded{memoir}{%
\RequirePackage[other,notbib]{tocbibind}
@@ -130,6 +131,11 @@
% Create a 'base class' length named EpydocBCL for use in base trees.
\newlength{\EpydocBCL} % base class length, for base trees.
+% In xkeyval arguments, we're not allowed to use \par. But we *are*
+% allowed to use a command that evaluates to \par, so define such a
+% command.
+\newcommand{\EpydocPar}{\par}
+
% ======================================================================
% Sections inside docstring
@@ -192,17 +198,17 @@
% it to its default value).
\newenvironment{EpydocDescription}{%
\setlength{\parskip}{\EpydocParskip}%
- }{}
+ \ignorespaces}{\ignorespacesafterend}
% This environment is used to mark the description for a class
% (which comes from the function's docstring).
\newenvironment{EpydocClassDescription}{%
- }{}
+ \ignorespaces}{\ignorespacesafterend}
% This environment is used to mark the description for a module
% (which comes from the function's docstring).
\newenvironment{EpydocModuleDescription}{%
- }{}
+ \ignorespaces}{\ignorespacesafterend}
% ======================================================================
% Python Source Code Syntax Highlighting.
@@ -323,36 +329,31 @@
%
% All arguments except for the first (the signature) may be empty.
%
+\define@cmdkeys[Epydoc]{function}{signature,description,parameters,
+ returndescr,returntype,raises,
+ overrides,metadata}
\newenvironment{EpydocFunctionList}{%
- \newcommand{\EpydocFunction}[8]{
- \gdef\@EpydocFunctionSignature{##1}%
- \gdef\@EpydocFunctionDescription{##2}%
- \gdef\@EpydocFunctionParameters{##3}%
- \gdef\@EpydocFunctionReturnDescr{##4}%
- \gdef\@EpydocFunctionReturnType{##5}%
- \gdef\@EpydocFunctionRaises{##6}%
- \gdef\@EpydocFunctionOverrides{##7}%
- \gdef\@EpydocFunctionMetadata{##8}%
- {\Large\raggedright\@EpydocFunctionSignature\par}
- \begin{quote}%
- \setlength{\parskip}{\EpydocParskip}%
- \ifx\@EpydocFunctionDescription\empty\else
- \par\@EpydocFunctionDescription\fi%
- \ifx\@EpydocFunctionParameters\empty\else
- \par\@EpydocFunctionParameters\fi%
- \ifx\@EpydocFunctionReturnDescr\empty
- \par\@EpydocFunctionReturnDescr\fi%
- \ifx\@EpydocFunctionReturnType\empty
- \par\@EpydocFunctionReturnType\fi%
- \ifx\@EpydocFunctionRaises\empty\else
- \par\@EpydocFunctionRaises\fi%
- \ifx\@EpydocFunctionOverrides\empty\else
- \par\@EpydocFunctionOverrides\fi%
- \ifx\@EpydocFunctionMetadata\empty\else
- \par\@EpydocFunctionMetadata\fi%
- \end{quote}
-
- }}
+ \newcommand{\EpydocFunction}[1]{{%
+ \setkeys[Epydoc]{function}{##1}%
+ {\Large\raggedright\cmdEpydoc@function@signature\par}
+ \begin{quote}%
+ \setlength{\parskip}{\EpydocParskip}%
+ \@ifundefined{cmdEpydoc@function@description}{}{
+ \par\cmdEpydoc@function@description}
+ \@ifundefined{cmdEpydoc@function@parameters}{}{
+ \par\cmdEpydoc@function@parameters}
+ \@ifundefined{cmdEpydoc@function@returndescr}{}{
+ \par \textbf{Returns:} \cmdEpydoc@function@returndescr}
+ \@ifundefined{cmdEpydoc@function@returntype}{}{
+ \par \textbf{Return Type:} \cmdEpydoc@function@returntype}
+ \@ifundefined{cmdEpydoc@function@raises}{}{
+ \par\cmdEpydoc@function@raises}
+ \@ifundefined{cmdEpydoc@function@overrides}{}{
+ \par\cmdEpydoc@function@overrides}
+ \@ifundefined{cmdEpydoc@function@metadata}{}{
+ \ifx\cmdEpydoc@function@metadata\empty\else
+ \par\cmdEpydoc@function@metadata\fi}
+ \end{quote}\par}}}
{}
% The EpydocFunctionSignature environment is used to display a
@@ -382,7 +383,7 @@
\textit{##2}%
\ifthenelse{\equal{##1}{}}{}{=\texttt{##1}}}%
\@hangfrom{\textbf{#1}(}%
- }{)\par}
+ }{)}
% The EpydocFunctionParameters environment is used to display
% descriptions for the parameters that a function can take.
@@ -439,23 +440,23 @@
%
% If any of these arguments is not available, then the empty
% string will be used.
+\define@cmdkeys[Epydoc]{variable}{name,description,type,value,metadata}
\newenvironment{EpydocVariableList}{%
- \newcommand{\EpydocVariable}[4]{%
- \gdef\@EpydocVariableName{##1}%
- \gdef\@EpydocVariableDescription{##2}%
- \gdef\@EpydocVariableType{##3}%
- \gdef\@EpydocVariableValue{##4}%
- {\Large\raggedright\@EpydocVariableName\par}
- \begin{quote}
- \setlength{\parskip}{\EpydocParskip}%
- \ifx\@EpydocVariableDescription\empty\else
- \par\@EpydocVariableDescription\fi%
- \ifx\@EpydocVariableType\empty\else
- \par\textbf{Type:} \@EpydocVariableType\fi%
- \ifx\@EpydocVariableValue\empty
- \par\textbf{Value:} \texttt{\@EpydocVariableValue}\fi%
- \end{quote}
- }}
+ \newcommand{\EpydocVariable}[1]{{%
+ \setkeys[Epydoc]{variable}{##1}%
+ {\Large\raggedright\cmdEpydoc@variable@name\par}
+ \begin{quote}
+ \setlength{\parskip}{\EpydocParskip}%
+ \@ifundefined{cmdEpydoc@variable@description}{}{%
+ \par\cmdEpydoc@variable@description}%
+ \@ifundefined{cmdEpydoc@variable@type}{}{%
+ \par\textbf{Type:} \cmdEpydoc@variable@type}%
+ \@ifundefined{cmdEpydoc@variable@value}{}{%
+ \par\textbf{Value:} \cmdEpydoc@variable@value}%
+ \@ifundefined{cmdEpydoc@variable@metadata}{}{%
+ \ifx\cmdEpydoc@variable@metadata\empty\else
+ \par\cmdEpydoc@variable@metadata\fi}%
+ \end{quote}\par}}}
{}
% The EpydocClassVariableList environment is used the same way as
@@ -486,29 +487,28 @@
%
% If any of these arguments is not available, then the empty
% string will be used.
+\define@cmdkeys[Epydoc]{property}{name,description,type,fget,
+ fset,fdel,metadata}
\newenvironment{EpydocPropertyList}{%
- \newcommand{\EpydocProperty}[6]{%
- \gdef\@EpydocPropertyName{##1}%
- \gdef\@EpydocPropertyDescription{##2}%
- \gdef\@EpydocPropertyType{##3}%
- \gdef\@EpydocPropertyGet{##4}%
- \gdef\@EpydocPropertySet{##5}%
- \gdef\@EpydocPropertyDel{##6}%
- {\Large\raggedright\@EpydocPropertyName\par}
- \begin{quote}
- \setlength{\parskip}{\EpydocParskip}%
- \ifx\@EpydocPropertyDescription\empty\else
- \par\@EpydocPropertyDescription\fi%
- \ifx\@EpydocPropertyType\empty\else
- \par\textbf{Type:} \@EpydocPropertyType\fi%
- \ifx\@EpydocPropertyGet\empty
- \par\textbf{Get:} \texttt{\@EpydocPropertyGet}\fi%
- \ifx\@EpydocPropertySet\empty
- \par\textbf{Set:} \texttt{\@EpydocPropertySet}\fi%
- \ifx\@EpydocPropertyDel\empty
- \par\textbf{Delete:} \texttt{\@EpydocPropertyDel}\fi%
- \end{quote}
- }}
+ \newcommand{\EpydocProperty}[1]{{%
+ \setkeys[Epydoc]{property}{##1}%
+ {\Large\raggedright\cmdEpydoc@property@name\par}
+ \begin{quote}
+ \setlength{\parskip}{\EpydocParskip}%
+ \@ifundefined{cmdEpydoc@property@description}{}{
+ \par\cmdEpydoc@property@description}
+ \@ifundefined{cmdEpydoc@property@type}{}{
+ \par\textbf{Type:} \cmdEpydoc@property@type}
+ \@ifundefined{cmdEpydoc@property@fget}{}{
+ \par\textbf{Get:} \cmdEpydoc@property@fget}
+ \@ifundefined{cmdEpydoc@property@fset}{}{
+ \par\textbf{Set:} \cmdEpydoc@property@fset}
+ \@ifundefined{cmdEpydoc@property@fdel}{}{
+ \par\textbf{Delete:} \cmdEpydoc@property@fdel}
+ \@ifundefined{cmdEpydoc@property@metadata}{}{
+ \ifx\cmdEpydoc@property@metadata\empty\else
+ \par\cmdEpydoc@property@metadata\fi}
+ \end{quote}\par}}}
{}
% ======================================================================
@@ -516,28 +516,32 @@
% This command is used to display a metadata field with a single value
\newcommand{\EpydocMetadataSingleValue}[2]{%
+ \par
\begin{list}{}{\itemindent-\leftmargin}
\item \textbf{#1:} #2
- \end{list}
- }
+ \end{list}\par\ignorespaces}
% This environment is used to display a metadata field with multiple
% values when the field declares that short=True; i.e., that multiple
% values should be combined into a single comma-delimited list.
\newenvironment{EpydocMetadataShortList}[1]{%
\newcommand{\and}{, }%
- \textbf{#1: }}
- {}
+ \par
+ \begin{list}{}{\itemindent-\leftmargin}
+ \item \textbf{#1:} \ignorespaces}
+ {\end{list}\ignorespacesafterend\par}
% This list environment is used to display a metadata field with
% multiple values when the field declares that short=False; i.e., that
% multiple values should be listed separately in a bulleted list.
\newenvironment{EpydocMetadataLongList}[1]{%
+ \par
\textbf{#1:}
\setlength{\parskip}{0ex}
\begin{itemize}
- \setlength{\parskip}{\EpydocMetadataLongListParskip}}
- {\end{itemize}}
+ \setlength{\parskip}{\EpydocMetadataLongListParskip}
+ \ignorespaces}
+ {\end{itemize}\ignorespacesafterend\par}
% ======================================================================
% reStructuredText Admonitions
@@ -545,19 +549,16 @@
% This environment is used to display reStructuredText admonitions,
% such as ``..warning::'' and ``..note::''.
\newenvironment{reSTadmonition}[1][]{%
- \begin{center}\begin{sffamily}
- \begin{lrbox}{\@tempboxa}
- \begin{minipage}{\admonitionwidth}
- \textbf{\large #1}
- \vspace{2mm}
- }
- {
- \end{minipage}
- \end{lrbox}
- \fbox{\usebox{\@tempboxa}}
- \end{sffamily}
- \end{center}
- }
+ \begin{center}\begin{sffamily}%
+ \begin{lrbox}{\@tempboxa}%
+ \begin{minipage}{\admonitionwidth}%
+ \textbf{\large #1}%
+ \vspace{2mm}}%
+ {\end{minipage}%
+ \end{lrbox}%
+ \fbox{\usebox{\@tempboxa}}%
+ \end{sffamily}%
+ \end{center}}
% ======================================================================
% Name Formatting
@@ -565,27 +566,24 @@
% This section defines the EpydocDottedName command, which is used to
% display the names of Python objects.
-% Allows non-hyphenated wrapping at the '.' module separators. The
-% rest is a simplified version of url.sty's tt style.
-\RequirePackage{url}
-\def\Url@pydo{% style assignments for tt fonts or T1 encoding
-\def\UrlBreaks{\do\]\do\)\do\_}%
-\def\UrlBigBreaks{\do@url@hyp\do\.}%
-% \def\UrlNoBreaks{\do\(\do\[\do\{\do\<\do\_}% (unnecessary)
-\def\UrlNoBreaks{\do\(\do\[\do\{\do\<}% (unnecessary)
-\def\UrlSpecials{\do\ {\ }}%
-\def\UrlOrds{\do\*\do\-\do\~}% any ordinary characters that aren't usually
-}
+% The \EpydocDottedName command is used to escape dotted names. In
+% particular, it escapes all characters except '#', '%', and newlines,
+% and allows non-hyphenated wrapping at '.' separator characters.
+% [xx] this generates a warning for names containing _ -- we need
+% to somehow strip that out of the second argument.
+\newcommand\EpydocDottedName[1]{%
+ \texorpdfstring{\protect\Epydoc@DottedName{#1}}{#1}}
-\def\url@pystyle{%
-\@ifundefined{selectfont}{\def\UrlFont{\rm}}{\def\UrlFont{\rmfamily}}\Url@pydo
+\DeclareUrlCommand\Epydoc@DottedName{%
+ \urlstyle{rm}%
+ \def\UrlBigBreaks{\do\.}%
+ % We should never see most of these chars in a name, but handle
+ % them if they happen to show up (eg script names)
+ \def\UrlOrds{\do\@\do\#\do\%\do\^\do\&\do\(\do\)\do\-\do\_%
+ \do\|\do\\\do\"\do\/\do\?\do\>\do\<\do\{\do\}%
+ \do\`\do\~}
}
-\newcommand\pymodule{\begingroup \urlstyle{py}\Url}
-% The \EpydocDottedName command is used to escape dotted names. In
-% particular, it escapes underscores (_) and allows non-hyphenated
-% wrapping at '.' separator characters.
-\newcommand\EpydocDottedName[1]{\texorpdfstring{\protect\pymodule{#1}}{#1}}
"""+NIST_DISCLAIMER
######################################################################
######################################################################
@@ -607,15 +605,14 @@
% $Id:$
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{epydoc-boxes}[2008/02/26 v3.0.1 Epydoc Python Documentation]
-
+% Pass options to the epydoc base package.
\RequirePackage{xkeyval}
-\DeclareOptionX{index}{\PassOptionsToPackage{index}{epydoc-base}}
-\DeclareOptionX{hyperlink}{\PassOptionsToPackage{hyperlink}{epydoc-base}}
-\DeclareOptionX{title}[]{\PassOptionsToPackage{title={#1}}{epydoc-base}}
-\DeclareOptionX{creator}[]{\PassOptionsToPackage{creator={#1}}{epydoc-base}}
+\DeclareOptionX*{\PassOptionsToPackage{\CurrentOption}{epydoc-base}}
\ProcessOptionsX\relax
-
+% Load the base epydoc package
\RequirePackage{epydoc-base}
+
+% Use longtable for variable & property lists.
\RequirePackage{longtable}
% Double the standard size boxedminipage outlines.
@@ -636,60 +633,50 @@
\renewenvironment{EpydocFunctionList}{%
\def\@EpydocSeparator{%
\vspace{-2\EpydocParskip}
- \rule{\dimexpr \textwidth-2\fboxsep \relax}{0.5\fboxrule}
+ \rule{\dimexpr \textwidth-2\fboxsep}{0.5\fboxrule}
\aftergroup\def\aftergroup\@EpydocSeparator%
\aftergroup{\aftergroup}}%
- \newcommand{\EpydocFunction}[8]{
- \gdef\@EpydocFunctionSignature{##1}%
- \gdef\@EpydocFunctionDescription{##2}%
- \gdef\@EpydocFunctionParameters{##3}%
- \gdef\@EpydocFunctionReturnDescr{##4}%
- \gdef\@EpydocFunctionReturnType{##5}%
- \gdef\@EpydocFunctionRaises{##6}%
- \gdef\@EpydocFunctionOverrides{##7}%
- \gdef\@EpydocFunctionMetadata{##8}%
- \begin{boxedminipage}{\dimexpr \textwidth-2\fboxsep \relax}
- {\Large\raggedright\@EpydocFunctionSignature\par}
- \setlength{\parskip}{\EpydocParskip}
- \ifx\@EpydocFunctionDescription\empty\else%
- {\@EpydocSeparator}%
- \@EpydocFunctionDescription %
- \fi%
- \ifx\@EpydocFunctionParameters\empty\else%
- {\@EpydocSeparator}%
- \@EpydocFunctionParameters %
- \fi%
- \ifx\@EpydocFunctionReturnType\empty%
- \ifx\@EpydocFunctionReturnDescr\empty\else%
+ \newcommand{\EpydocFunction}[1]{{%
+ \setkeys[Epydoc]{function}{##1}%
+ \begin{boxedminipage}{\dimexpr \textwidth-2\fboxsep}
+ {\Large\raggedright\cmdEpydoc@function@signature\par}
+ \setlength{\parskip}{\EpydocParskip}
+ \@ifundefined{cmdEpydoc@function@description}{}{%
{\@EpydocSeparator}%
- \textbf{Return Value}%
- \vspace{-\EpydocParskip}%
- \begin{quote}\@EpydocFunctionReturnDescr\end{quote}%
- \fi%
- \else%
- {\@EpydocSeparator}%
- \textbf{Return Value}%
- \vspace{-\EpydocParskip}%
- \ifx\@EpydocFunctionReturnDescr\empty%
- \begin{quote}\it \@EpydocFunctionReturnType\end{quote}%
- \else%
- \begin{quote}\@EpydocFunctionReturnDescr%
- \textit{(type=\@EpydocFunctionReturnType)}\end{quote}%
- \fi%
- \fi%
- \ifx\@EpydocFunctionRaises\empty\else%
- {\@EpydocSeparator}%
- \@EpydocFunctionRaises %
- \fi%
- \ifx\@EpydocFunctionOverrides\empty\else%
- {\@EpydocSeparator}%
- \@EpydocFunctionOverrides %
- \fi%
- \ifx\@EpydocFunctionMetadata\empty\else%
- {\@EpydocSeparator}%
- \@EpydocFunctionMetadata %
- \fi%
- \end{boxedminipage}\par}}
+ \par\cmdEpydoc@function@description}%
+ \@ifundefined{cmdEpydoc@function@parameters}{}{%
+ {\@EpydocSeparator}%
+ \par\cmdEpydoc@function@parameters}%
+ \@ifundefined{cmdEpydoc@function@returntype}{
+ \@ifundefined{cmdEpydoc@function@returndescr}{}{
+ {\@EpydocSeparator}%
+ \par\textbf{Return Value}%
+ \par\vspace{-\EpydocParskip}%
+ \begin{quote}\cmdEpydoc@function@returndescr\end{quote}}%
+ }{
+ {\@EpydocSeparator}%
+ \par\textbf{Return Value}%
+ \par\vspace{-\EpydocParskip}%
+ \begin{quote}%
+ \@ifundefined{cmdEpydoc@function@returndescr}{
+ \textit{\cmdEpydoc@function@returntype}%
+ }{%
+ \cmdEpydoc@function@returndescr%
+ \textit{(type=\cmdEpydoc@function@returntype)}}%
+ \end{quote}%
+ }
+ \@ifundefined{cmdEpydoc@function@raises}{}{%
+ {\@EpydocSeparator}%
+ \par\cmdEpydoc@function@raises}%
+ \@ifundefined{cmdEpydoc@function@overrides}{}{%
+ {\@EpydocSeparator}%
+ \par\cmdEpydoc@function@overrides}%
+ \@ifundefined{cmdEpydoc@function@metadata}{}{%
+ \ifx\cmdEpydoc@property@metadata\empty\else
+ {\@EpydocSeparator}%
+ \par\cmdEpydoc@function@metadata%
+ \fi}%
+ \end{boxedminipage}\par}}}
{}
% ======================================================================
@@ -718,7 +705,7 @@
p{\EpydocVariableWidth}|
p{\dimexpr \textwidth%
-4\tabcolsep-7pt
- -\EpydocVariableWidth \relax}
+ -\EpydocVariableWidth}
@{\hspace \tabcolsep \vrule width \fboxrule}}
% Set up the headers & footer (this makes the table span
% multiple pages in a happy way).
@@ -738,28 +725,22 @@
% Variable Lists
\renewenvironment{EpydocVariableList}{%
- \newcommand{\EpydocVariable}[4]{%
- \gdef\@EpydocVariableName{##1}%
- \gdef\@EpydocVariableDescription{##2}%
- \gdef\@EpydocVariableType{##3}%
- \gdef\@EpydocVariableValue{##4}%
- \raggedright\@EpydocVariableName & %
+ \newcommand{\EpydocVariable}[1]{{%
+ \setkeys[Epydoc]{variable}{##1}%
+ \raggedright\cmdEpydoc@variable@name &%
+ \setkeys[Epydoc]{variable}{##1}%
\setlength{\parskip}{\EpydocParskip}\raggedright%
- \@EpydocVariableDescription %
- \ifx\@EpydocVariableValue\empty\relax%
- \ifx\@EpydocVariableType\empty\else%
- \ifx\@EpydocVariableDescription\empty\else\par\fi%
- \textit{(type=\texttt{\@EpydocVariableType})}%
- \fi%
- \else\relax%
- \ifx\@EpydocVariableDescription\empty\else\par\fi%
- \textbf{Value:} \texttt{\@EpydocVariableValue}%
- \ifx\@EpydocVariableType\empty\else%
- \textit{(type=\texttt{\@EpydocVariableType})}%
- \fi%
- \fi%
+ \@ifundefined{cmdEpydoc@variable@description}{}{%
+ \cmdEpydoc@variable@description\relax}%
+ \@ifundefined{cmdEpydoc@variable@value}{}{%
+ \@ifundefined{cmdEpydoc@variable@description}{}{\par}%
+ \textbf{Value:} \texttt{\cmdEpydoc@variable@value}}%
+ \@ifundefined{cmdEpydoc@variable@type}{}{%
+ \@ifundefined{cmdEpydoc@variable@description}{%
+ \@ifundefined{cmdEpydoc@variable@value}{}{ }}{ }%
+ \textit{(type=\texttt{\cmdEpydoc@variable@type})}}%
\tabularnewline
- \hline}%
+ \hline}}%
\begin{@EpydocGeneralList}%
}
{\end{@EpydocGeneralList}}
@@ -775,39 +756,30 @@
\renewenvironment{EpydocPropertyList}{%
\def\@EpydocSeparator{%
\aftergroup\def\aftergroup\@EpydocSeparator\aftergroup{%
- \aftergroup\\\aftergroup[\aftergroup\EpydocParskip\aftergroup]%
+ \aftergroup\par%
\aftergroup}}%
- \newcommand{\EpydocProperty}[6]{%
- \gdef\@EpydocPropertyName{##1}%
- \gdef\@EpydocPropertyDescription{##2}%
- \gdef\@EpydocPropertyType{##3}%
- \gdef\@EpydocPropertyGet{##4}%
- \gdef\@EpydocPropertySet{##5}%
- \gdef\@EpydocPropertyDel{##6}%
- \raggedright\@EpydocPropertyName & %
+ \newcommand{\EpydocProperty}[1]{{%
+ \setkeys[Epydoc]{property}{##1}%
+ \raggedright\cmdEpydoc@property@name & %
+ \setkeys[Epydoc]{property}{##1}%
\setlength{\parskip}{\EpydocParskip}\raggedright%
- \ifx\@EpydocPropertyDescription\empty\else%
+ \@ifundefined{cmdEpydoc@property@description}{}{%
{\@EpydocSeparator}%
- \@EpydocPropertyDescription %
- \fi%
- \ifx\@EpydocPropertyType\empty\else%
+ \cmdEpydoc@property@description\relax}%
+ \@ifundefined{cmdEpydoc@property@type}{}{%
{\@EpydocSeparator}%
- \textbf{Type:} \@EpydocPropertyType
- \fi%
- \ifx\@EpydocPropertyGet\empty\else%
+ \textbf{Type:} \cmdEpydoc@property@type\relax}%
+ \@ifundefined{cmdEpydoc@property@fget}{}{%
{\@EpydocSeparator}%
- \textbf{Get:} \@EpydocPropertyGet%
- \fi%
- \ifx\@EpydocPropertySet\empty\else%
+ \textbf{Get:} \cmdEpydoc@property@fget\relax}%
+ \@ifundefined{cmdEpydoc@property@fset}{}{%
{\@EpydocSeparator}%
- \textbf{Set:} \@EpydocPropertySet%
- \fi%
- \ifx\@EpydocPropertyDel\empty\else%
+ \te...
[truncated message content] |