1
2
3
4
5
6
7
8
9 """
10 The LaTeX output generator for epydoc. The main interface provided by
11 this module is the L{LatexWriter} class.
12
13 @todo: Inheritance=listed
14 """
15 __docformat__ = 'epytext en'
16
17 import os.path, sys, time, re, textwrap, codecs
18
19 from epydoc.apidoc import *
20 from epydoc.compat import *
21 import epydoc
22 from epydoc import log
23 from epydoc import markup
24 from epydoc.util import plaintext_to_latex
25 import epydoc.markup
26 from epydoc.docwriter.dotgraph import *
27 from epydoc.docwriter.latex_sty import STYLESHEETS
28
30
31 PREAMBLE = [
32 "\\documentclass{article}",
33 "\\usepackage[%s]{%s}",
34 ]
35
36 SECTIONS = ['\\part{%s}', '\\chapter{%s}', '\\section{%s}',
37 '\\subsection{%s}', '\\subsubsection{%s}',
38 '\\textbf{%s}']
39
40 STAR_SECTIONS = ['\\part*{%s}', '\\chapter*{%s}', '\\section*{%s}',
41 '\\subsection*{%s}', '\\subsubsection*{%s}',
42 '\\textbf{%s}']
43
45 self.docindex = docindex
46
47 self._show_private = kwargs.get('show_private', 0)
48 self._show_deprecated = kwargs.get('show_deprecated', True)
49 self._prj_name = kwargs.get('prj_name', None)
50 self._show_crossrefs = kwargs.get('crossref', 1)
51 self._index = kwargs.get('index', 1)
52 self._hyperlink = kwargs.get('hyperlink', True)
53 self._list_classes_separately=kwargs.get('list_classes_separately',0)
54 self._inheritance = kwargs.get('inheritance', 'listed')
55 self._exclude = kwargs.get('exclude', 1)
56 self._list_submodules = kwargs.get('list_submodules', 1)
57 self._sty = kwargs.get('sty')
58 self._top_section = 2
59 self._index_functions = 1
60 self._hyperref = 1
61 self._show_submodule_list = kwargs.get('show_submodule_list', True)
62 self._graph_types = kwargs.get('graphs', ()) or ()
63 """Graphs that we should include in our output."""
64
65
66
67
68 self._encoding = kwargs.get('encoding', 'utf-8')
69
70 self.valdocs = valdocs = sorted(docindex.reachable_valdocs(
71 imports=False, packages=False, bases=False, submodules=False,
72 subclasses=False, private=self._show_private))
73 if not self._show_deprecated:
74 self.valdocs = valdocs = self._filter_deprecated(valdocs)
75 self._num_files = self.num_files()
76
77 if self._show_private: self._public_filter = None
78 else: self._public_filter = True
79
80 self.class_list = [d for d in valdocs if isinstance(d, ClassDoc)]
81 """The list of L{ClassDoc}s for the documented classes."""
82 self.class_set = set(self.class_list)
83 """The set of L{ClassDoc}s for the documented classes."""
84 self.module_list = [d for d in valdocs if isinstance(d, ModuleDoc)]
85 """The list of L{ModuleDoc}s for the documented modules."""
86 self.module_set = set(self.module_list)
87 """The set of L{ModuleDoc}s for the documented modules."""
88
89 - def write(self, directory=None):
90 """
91 Write the API documentation for the entire project to the
92 given directory.
93
94 @type directory: C{string}
95 @param directory: The directory to which output should be
96 written. If no directory is specified, output will be
97 written to the current directory. If the directory does
98 not exist, it will be created.
99 @rtype: C{None}
100 @raise OSError: If C{directory} cannot be created,
101 @raise OSError: If any file cannot be created or written to.
102 """
103
104 self._files_written = 0.
105
106
107 orig_valdoc_defaults = (ValueDoc.SUMMARY_REPR_LINELEN,
108 ValueDoc.REPR_LINELEN,
109 ValueDoc.REPR_MAXLINES)
110 ValueDoc.SUMMARY_REPR_LINELEN = 60
111 ValueDoc.REPR_LINELEN = 52
112 ValueDoc.REPR_MAXLINES = 5
113
114
115 if not directory: directory = os.curdir
116 self._mkdir(directory)
117 self._directory = directory
118
119
120 self._write_sty(directory, self._sty)
121
122
123 self._write(self.write_topfile, directory, 'api.tex')
124
125
126 for val_doc in self.valdocs:
127 if isinstance(val_doc, ModuleDoc):
128 filename = '%s-module.tex' % val_doc.canonical_name
129 self._write(self.write_module, directory, filename, val_doc)
130 elif isinstance(val_doc, ClassDoc):
131 filename = '%s-class.tex' % val_doc.canonical_name
132 self._write(self.write_class, directory, filename, val_doc)
133
134
135 (ValueDoc.SUMMARY_REPR_LINELEN, ValueDoc.REPR_LINELEN,
136 ValueDoc.REPR_MAXLINES) = orig_valdoc_defaults
137
139 """
140 Copy the requested LaTeX stylesheet to the target directory.
141 The stylesheet can be specified as a name (i.e., a key from
142 the STYLESHEETS directory); a filename; or None for the default
143 stylesheet. If any stylesheet *other* than the default
144 stylesheet is selected, then the default stylesheet will be
145 copied to 'epydoc-default.sty', which makes it possible to
146 reference it via \RequirePackage.
147 """
148
149 for (name, sty) in STYLESHEETS.items():
150 out = open(os.path.join(directory, 'epydoc-%s.sty' % name), 'wb')
151 out.write(sty)
152 out.close()
153
154
155 if stylesheet is None:
156 self._epydoc_sty_package = 'epydoc-default'
157
158
159 elif stylesheet in STYLESHEETS:
160 self._epydoc_sty_package = 'epydoc-%s' % stylesheet
161
162
163 elif os.path.exists(stylesheet):
164 try: sty = open(stylesheet, 'rb').read()
165 except: raise IOError("Can't open LaTeX style file: %r" %
166 stylesheet)
167 out = open(os.path.join(directory, 'epydoc-custom.sty'), 'wb')
168 out.write(sty)
169 out.close()
170 self._epydoc_sty_package = 'epydoc-custom'
171
172 else:
173 raise IOError("Can't find LaTeX style file: %r" % stylesheet)
174
175 - def _write(self, write_func, directory, filename, *args):
176
177 self._files_written += 1
178 log.progress(self._files_written/self._num_files, filename)
179
180 path = os.path.join(directory, filename)
181 if self._encoding == 'utf-8':
182 f = codecs.open(path, 'w', 'utf-8')
183 write_func(f.write, *args)
184 f.close()
185 else:
186 result = []
187 write_func(result.append, *args)
188 s = u''.join(result)
189 try:
190 s = s.encode(self._encoding)
191 except UnicodeError:
192 log.error("Output could not be represented with the "
193 "given encoding (%r). Unencodable characters "
194 "will be displayed as '?'. It is recommended "
195 "that you use a different output encoding (utf-8, "
196 "if it's supported by latex on your system)."
197 % self._encoding)
198 s = s.encode(self._encoding, 'replace')
199 f = open(path, 'w')
200 f.write(s)
201 f.close()
202
204 """
205 @return: The number of files that this C{LatexFormatter} will
206 generate.
207 @rtype: C{int}
208 """
209 return 1 + len([doc for doc in self.valdocs
210 if isinstance(doc, (ClassDoc, ModuleDoc))])
211
213 """
214 If the given directory does not exist, then attempt to create it.
215 @rtype: C{None}
216 """
217 if not os.path.isdir(directory):
218 if os.path.exists(directory):
219 raise OSError('%r is not a directory' % directory)
220 os.mkdir(directory)
221
222
223
224
225
227 self.write_header(out, 'Include File')
228 self.write_preamble(out)
229 out('\n\\begin{document}\n\n')
230 out(self.start_of('Header'))
231
232
233 out(self.start_of('Title'))
234 out('\\title{%s}\n' % plaintext_to_latex(
235 self._prj_name or 'API Documentation', 1))
236 out('\\author{API Documentation}\n')
237 out('\\maketitle\n')
238
239
240 out(self.start_of('Table of Contents'))
241 out('\\addtolength{\\parskip}{-1ex}\n')
242 out('\\tableofcontents\n')
243 out('\\addtolength{\\parskip}{1ex}\n')
244
245
246 out(self.start_of('Includes'))
247 for val_doc in self.valdocs:
248 if isinstance(val_doc, ModuleDoc):
249 out('\\include{%s-module}\n' % val_doc.canonical_name)
250
251
252
253 if self._list_classes_separately:
254 for val_doc in self.valdocs:
255 if isinstance(val_doc, ClassDoc):
256 out('\\include{%s-class}\n' % val_doc.canonical_name)
257
258
259 if self._index:
260 out(self.start_of('Index'))
261 out('\\printindex\n\n')
262
263
264 out(self.start_of('Footer'))
265 out('\\end{document}\n\n')
266
268
269 options = []
270 options.append('creator={epydoc %s}' % epydoc.__version__)
271 options.append('title={%s}' % plaintext_to_latex(self._prj_name or ''))
272 if self._index: options.append('index')
273 if self._hyperlink: options.append('hyperlink')
274 out('\n'.join(self.PREAMBLE) % (','.join(options),
275 self._epydoc_sty_package) + '\n')
276
277
278 out('\\usepackage[%s]{inputenc}\n' % self.get_latex_encoding())
279
280
281
282 if self._hyperref:
283 out('\\definecolor{UrlColor}{rgb}{0,0.08,0.45}\n')
284
285
286
287 if 'restructuredtext' in epydoc.markup.MARKUP_LANGUAGES_USED:
288 from epydoc.markup import restructuredtext
289 rst_head = restructuredtext.latex_head_prefix()
290 rst_head = ''.join(rst_head).split('\n')
291 for line in rst_head[1:]:
292 m = re.match(r'\\usepackage(\[.*?\])?{(.*?)}', line)
293 if m and m.group(2) in (
294 'babel', 'hyperref', 'color', 'alltt', 'parskip',
295 'fancyhdr', 'boxedminipage', 'makeidx',
296 'multirow', 'longtable', 'tocbind', 'assymb',
297 'fullpage', 'inputenc'):
298 pass
299 else:
300 out(line+'\n')
301
302
303
304
305
306
308 self.write_header(out, doc)
309 out(self.start_of('Section Heading', doc))
310
311
312 out(self.indexterm(doc, 'start'))
313
314
315 out(self.section('%s %s' % (self.doc_kind(doc),
316 _dotted(doc.canonical_name)),
317 ref=doc))
318
319
320 if doc.descr not in (None, UNKNOWN):
321 out(self.start_of('Description', doc))
322 out('\\begin{EpydocModuleDescription}%\n')
323 out(self.docstring_to_latex(doc.descr, doc, 4))
324 out('\\end{EpydocModuleDescription}\n')
325
326
327 out(self.metadata(doc))
328
329
330 if (self._list_submodules and self._show_submodule_list and
331 doc.submodules != UNKNOWN and doc.submodules):
332 self.write_module_list(out, doc)
333
334
335 if self._list_classes_separately:
336 self.write_class_list(out, doc)
337 self.write_list(out, 'Functions', doc, 'EpydocFunctionList',
338 'function')
339 self.write_list(out, 'Variables', doc, 'EpydocVariableList', 'other')
340
341
342 if not self._list_classes_separately:
343 classes = doc.select_variables(imported=False, value_type='class',
344 public=self._public_filter)
345 classes = self._filter_deprecated(classes)
346
347 classes = [c for c in classes if c.defining_module is doc]
348
349 if classes:
350 out(self.start_of('Classes', doc))
351 for var_doc in classes:
352
353 out('\\input{%s-class}\n' % var_doc.value.canonical_name)
354
355
356 out(self.start_of('Footer', doc))
357 out(self.indexterm(doc, 'end'))
358
363
365 self.write_header(out, doc)
366 out(self.start_of('Section Heading', doc))
367
368
369 out(self.indexterm(doc, 'start'))
370
371
372 if self._list_classes_separately:
373 short_name = doc.canonical_name
374 if doc.defining_module not in (None, UNKNOWN):
375 short_name = doc.canonical_name.contextualize(
376 doc.defining_module.canonical_name)
377 else:
378 short_name = doc.canonical_name[-1]
379
380
381 if self._list_classes_separately:
382 seclevel = 0
383 else:
384 seclevel = 1
385
386
387 out(self.section('%s %s' % (self.doc_kind(doc), _dotted(short_name)),
388 seclevel, ref=doc))
389
390
391 out(self.start_of('Class Tree', doc))
392 if ((doc.bases not in (UNKNOWN, None) and len(doc.bases) > 0) or
393 (doc.subclasses not in (UNKNOWN,None) and len(doc.subclasses)>0)):
394
395 if 'umlclasstree' in self._graph_types:
396 graph = uml_class_tree_graph(doc, self._docstring_linker, doc)
397 out(self.render_graph(graph))
398
399 elif 'classtree' in self._graph_types:
400 graph = class_tree_graph([doc], self._docstring_linker, doc)
401 out(self.render_graph(graph))
402
403
404 else:
405
406
407 if doc.bases not in (UNKNOWN, None) and len(doc.bases) > 0:
408 out(self.base_tree(doc))
409
410
411 if (doc.subclasses not in (UNKNOWN, None) and
412 len(doc.subclasses) > 0):
413 sc_items = [_hyperlink(sc, '%s' % sc.canonical_name)
414 for sc in doc.subclasses]
415 out('{\\raggedright%\n')
416 out(self._descrlist(sc_items, 'Known Subclasses', short=1))
417 out('}%\n')
418
419
420 if doc.descr not in (None, UNKNOWN):
421 out(self.start_of('Description', doc))
422 out('\\begin{EpydocClassDescription}%\n')
423 out(self.docstring_to_latex(doc.descr, doc, 4))
424 out('\\end{EpydocClassDescription}\n')
425
426
427 out(self.metadata(doc))
428
429
430 self.write_list(out, 'Methods', doc, 'EpydocFunctionList',
431 'method', seclevel+1)
432 self.write_list(out, 'Properties', doc, 'EpydocPropertyList',
433 'property', seclevel+1)
434 self.write_list(out, 'Class Variables', doc,
435 'EpydocClassVariableList',
436 'classvariable', seclevel+1)
437 self.write_list(out, 'Instance Variables', doc,
438 'EpydocInstanceVariableList',
439 'instancevariable', seclevel+1)
440
441
442 out(self.start_of('Footer', doc))
443 out(self.indexterm(doc, 'end'))
444
445
446
447 if not self._list_classes_separately:
448 nested_classes = self._filter_deprecated(doc.select_variables(
449 imported=False, value_type='class',
450 public=self._public_filter))
451 if nested_classes:
452 out(self.start_of('Nested Classes', doc))
453 for nested_class in nested_classes:
454 if (nested_class.value.canonical_name != UNKNOWN and
455 (nested_class.value.canonical_name[:-1] ==
456 doc.canonical_name)):
457
458 out('\\input{%s-class}\n' %
459 nested_class.value.canonical_name)
460
461
462
463
464
466 modules = [doc for doc in self.valdocs
467 if isinstance(doc, ModuleDoc)]
468 if not modules: return
469
470
471 out('\\begin{itemize}\n')
472 out('\\setlength{\\parskip}{0ex}\n')
473 for doc in modules:
474 if (doc.package in (None, UNKNOWN) or
475 doc.package not in self.valdocs):
476 self.write_module_tree_item(out, doc)
477 return s +'\\end{itemize}\n'
478
480 if len(doc.submodules) == 0: return
481 out(self.start_of('Submodules', doc))
482
483 out(self.section('Submodules', 1))
484 out('\\begin{EpydocModuleList}\n')
485
486 for group_name in doc.group_names():
487 if not doc.submodule_groups[group_name]: continue
488 if group_name:
489 out(' \\EpydocGroup{%s}\n' % group_name)
490
491 for submodule in doc.submodule_groups[group_name]:
492 self.write_module_tree_item(out, submodule)
493
494
495
496 out('\\end{EpydocModuleList}\n\n')
497
499 """
500 Helper function for L{write_module_tree} and L{write_module_list}.
501
502 @rtype: C{string}
503 """
504 out(' '*depth + '\\EpydocModule{%% <<<%s>>>\n' % doc.canonical_name)
505 out(' '*depth + ' name={%s}' %
506 _hyperlink(doc, doc.canonical_name[-1]))
507 if doc.summary not in (None, UNKNOWN):
508 out(',\n' + ' '*depth+' summary={\n')
509 out(self.docstring_to_latex(doc.summary, doc, depth+4))
510 out(' '*depth+' }')
511 out(',\n' + ' '*depth + ' crossref={\n')
512 out(self.crossref(doc, depth+4) + ' '*depth+' }')
513 out('}%\n')
514 if doc.submodules != UNKNOWN and doc.submodules:
515 out(' '*depth+'\\begin{EpydocModuleList}%\n')
516 for submodule in doc.submodules:
517 self.write_module_tree_item(out, submodule, depth+4)
518 out(' '*depth+'\\end{EpydocModuleList}%\n')
519
520
521
522
523
524
525 - def base_tree(self, doc, width=None, linespec=None):
526 if width is None:
527 width = self._find_tree_width(doc)+2
528 linespec = []
529 s = (' %% Class tree line for this class (%s)\n ' %
530 doc.canonical_name + '&'*(width-4) +
531 '\\multicolumn{2}{l}{\\textbf{%s}}\n' %
532 _dotted('%s'%self._base_name(doc)))
533 s += '\\end{tabular}\n\n'
534 top = 1
535 else:
536 s = self._base_tree_line(doc, width, linespec)
537 top = 0
538
539 if isinstance(doc, ClassDoc):
540 for i in range(len(doc.bases)-1, -1, -1):
541 base = doc.bases[i]
542 spec = (i > 0)
543 s = self.base_tree(base, width, [spec]+linespec) + s
544
545 if top:
546 s = '\\begin{tabular}{%s}\n' % (width*'c') + s
547
548 return s
549
558
560 if not isinstance(doc, ClassDoc): return 2
561 width = 2
562 for base in doc.bases:
563 width = max(width, self._find_tree_width(base)+2)
564 return width
565
567
568 base_name = _dotted(self._base_name(doc))
569
570 s = ' %% Class tree line for base "%s"\n' % self._base_name(doc)
571 labelwidth = width-2*len(linespec)-2
572
573
574 s += ' \\multicolumn{%s}{r}{\n' % labelwidth
575 s += ' \\settowidth{\\EpydocBCL}{%s}\n' % base_name
576 s += ' \\multirow{2}{\\EpydocBCL}{\n'
577 s += ' %s}}\n' % _hyperlink(doc, self._base_name(doc))
578
579
580 for vbar in linespec:
581 if vbar: s += ' &&\\multicolumn{1}{|c}{}\n'
582 else: s += ' &&\n'
583
584
585 s += ' \\\\\\cline{%s-%s}\n' % (labelwidth+1, labelwidth+1)
586
587
588 s += ' ' + '&'*labelwidth
589 s += '\\multicolumn{1}{c|}{}\n'
590
591
592 for vbar in linespec:
593 if vbar: s += ' &\\multicolumn{1}{|c}{}&\n'
594 else: s += ' &&\n'
595
596 s += ' \\\\\n'
597
598 return s
599
600
601
602
603
605 groups = [(plaintext_to_latex(group_name),
606 self._filter_deprecated(
607 doc.select_variables(group=group_name, imported=False,
608 value_type='class',
609 public=self._public_filter)))
610 for group_name in doc.group_names()]
611
612
613 groups = [(g,vars) for (g,vars) in groups if vars]
614 if not groups: return
615
616
617 out(self.start_of('Classes', doc))
618 out(self.section('Classes', 1))
619 out('\\begin{EpydocClassList}\n')
620
621 for name, var_docs in groups:
622 if name:
623 out(' \\EpydocGroup{%s}\n' % name)
624
625
626 for var_doc in var_docs:
627 self.write_class_list_line(out, var_doc)
628
629
630
631 out('\\end{EpydocClassList}\n')
632
644
645
646
647
648
649
650 - def write_list(self, out, heading, doc, list_type,
651 value_type, seclevel=1):
652
653 groups = [(plaintext_to_latex(group_name),
654 self._filter_deprecated(
655 doc.select_variables(group=group_name, imported=False,
656 value_type=value_type,
657 public=self._public_filter)))
658 for group_name in doc.group_names()]
659
660
661 groups = [(g,vars) for (g,vars) in groups if vars]
662 if not groups: return
663
664
665 out(self.start_of(heading, doc))
666 out(self.section(heading, seclevel))
667
668 out('\\begin{%s}\n' % list_type)
669
670
671 grouped_inh_vars = {}
672 for name, var_docs in groups:
673 self.write_list_group(out, doc, name, var_docs, grouped_inh_vars)
674
675
676
677 if grouped_inh_vars:
678 for base in doc.mro():
679 if base in grouped_inh_vars:
680 hdr = ('Inherited from %s' %
681 plaintext_to_latex('%s' % base.canonical_name))
682 out(self.crossref(base) + '\n\n')
683 out('\\EpydocGroup{%s}\n' % hdr)
684 for var_doc in grouped_inh_vars[base]:
685 if isinstance(var_doc.value, RoutineDoc):
686 self.write_function(out, var_doc)
687 elif isinstance(var_doc.value, PropertyDoc):
688 self.write_property(out, var_doc)
689 else:
690 self.write_var(out, var_doc)
691
692 out('\\end{%s}\n\n' % list_type)
693
695
696
697
698
699
700 listed_inh_vars = {}
701 normal_vars = []
702 for var_doc in var_docs:
703 if var_doc.container != doc:
704 base = var_doc.container
705 if (base not in self.class_set or
706 self._inheritance == 'listed'):
707 listed_inh_vars.setdefault(base,[]).append(var_doc)
708 elif self._inheritance == 'grouped':
709 grouped_inh_vars.setdefault(base,[]).append(var_doc)
710 elif self._inheritance == 'hidden':
711 pass
712 else:
713 normal_vars.append(var_doc)
714 else:
715 normal_vars.append(var_doc)
716
717
718 if name:
719 out('\\EpydocGroup{%s}\n' % name)
720
721 for var_doc in normal_vars:
722 if isinstance(var_doc.value, RoutineDoc):
723 self.write_function(out, var_doc)
724 elif isinstance(var_doc.value, PropertyDoc):
725 self.write_property(out, var_doc)
726 else:
727 self.write_var(out, var_doc)
728
729 if listed_inh_vars:
730 self.write_inheritance_list(out, doc, listed_inh_vars)
731
733 for base in doc.mro():
734 if base not in listed_inh_vars: continue
735
736 var_docs = listed_inh_vars[base]
737 if not self._show_private:
738 var_docs = [v for v in var_docs if v.is_public]
739 if not self._show_deprecated:
740 var_docs = self._filter_deprecated(var_docs)
741 if var_docs:
742 out('\\EpydocInheritanceList{')
743 out(plaintext_to_latex('%s' % base.canonical_name))
744 out(self.crossref(base))
745 out('}{')
746 out(', '.join(['%s' % plaintext_to_latex(var_doc.name) +
747 self._parens_if_func(var_doc)
748 for var_doc in var_docs]))
749 out('}\n')
750
752 if isinstance(var_doc.value, RoutineDoc): return '()'
753 else: return ''
754
755
756
757
758
760 def new_out(s):
761 s = re.sub('(?m)\n([ \t]*\n)+', '\\par\n', s)
762 s = re.sub(r'\\par\b', r'\\EpydocPar', s)
763 s = re.sub(r'(?m)^([ \t]*)([^ \t].*)\\EpydocPar\n',
764 r'\1\2\n\1\\EpydocPar\n', s)
765 out(s)
766 return new_out
767
769 func_doc = var_doc.value
770 is_inherited = (var_doc.overrides not in (None, UNKNOWN))
771
772
773
774
775 if not is_inherited:
776 out(' %s' % self.indexterm(func_doc))
777
778 out(' \\EpydocFunction{%% <<< %s >>>\n' % var_doc.name)
779
780
781
782
783 out = self.replace_par(out)
784
785
786 out(' signature={%%\n%s }' %
787 self.function_signature(var_doc))
788
789
790 if func_doc.descr not in (None, UNKNOWN):
791 out(',\n description={%\n')
792 out(self.docstring_to_latex(func_doc.descr, func_doc, 6))
793 out(' }')
794
795
796 if func_doc.arg_descrs or func_doc.arg_types:
797 out(',\n parameters={%\n')
798 self.write_function_parameters(out, var_doc)
799 out(' }')
800
801
802 if func_doc.return_descr not in (None, UNKNOWN):
803 out(',\n returndescr={%\n')
804 out(self.docstring_to_latex(func_doc.return_descr, func_doc, 6))
805 out(' }')
806
807
808 if func_doc.return_type not in (None, UNKNOWN):
809 out(',\n returntype={%\n')
810 out(self.docstring_to_latex(func_doc.return_type, func_doc, 6))
811 out(' }')
812
813
814 if func_doc.exception_descrs not in (None, UNKNOWN, [], ()):
815 out(',\n raises={%\n')
816 out(' '*6+'\\begin{EpydocFunctionRaises}\n')
817 for name, descr in func_doc.exception_descrs:
818 out(' '*10+'\\item[%s]\n\n' %
819 plaintext_to_latex('%s' % name))
820 out(self.docstring_to_latex(descr, func_doc, 10))
821 out(' '*6+'\\end{EpydocFunctionRaises}\n')
822 out(' }')
823
824
825 if var_doc.overrides not in (None, UNKNOWN):
826 out(',\n overrides={%\n')
827 out('\\EpydocFunctionOverrides')
828 if (func_doc.docstring in (None, UNKNOWN) and
829 var_doc.overrides.value.docstring not in (None, UNKNOWN)):
830 out('[1]')
831 out('{%s}\n'
832 % _hyperlink(var_doc.overrides,
833 '%s' % var_doc.overrides.canonical_name))
834 out(' }')
835
836
837 metadata = self.metadata(func_doc, 6)
838 if metadata:
839 out(',\n metadata={%%\n%s }' % metadata)
840
841 out('}%\n')
842
844 func_doc = var_doc.value
845
846 longest = max([0]+[len(n) for n in func_doc.arg_types])
847 for names, descrs in func_doc.arg_descrs:
848 longest = max([longest]+[len(n) for n in names])
849
850 out(' '*6+'\\begin{EpydocFunctionParameters}{%s}\n' % (longest*'x'))
851
852 arg_descrs = list(func_doc.arg_descrs)
853 args = set()
854 for arg_names, arg_descr in arg_descrs:
855 args.update(arg_names)
856 for arg in var_doc.value.arg_types:
857 if arg not in args:
858 arg_descrs.append( ([arg],None) )
859
860 for (arg_names, arg_descr) in arg_descrs:
861 arg_name = plaintext_to_latex(', '.join(arg_names))
862 out('%s\\item[%s]\n' % (' '*8, arg_name))
863 if arg_descr:
864 out(self.docstring_to_latex(arg_descr, func_doc, 10))
865
866
867
868 for arg_name in arg_names:
869 arg_typ = func_doc.arg_types.get(arg_name)
870 if arg_typ is not None:
871 if len(arg_names) == 1:
872 lhs = 'type'
873 else:
874 lhs = 'type of %s' % arg_name
875 rhs = self.docstring_to_latex(arg_typ, func_doc, 14)
876 out('%s\\textit{ (%s=%%\n%s%s)}\n' % (' '*12, lhs,
877 rhs, ' '*12))
878 out(' '*6+'\\end{EpydocFunctionParameters}\n')
879
881 func_doc = var_doc.value
882 func_name = var_doc.name
883
884 s = ('%s\\begin{EpydocFunctionSignature}%%\n%s {%s}%%\n' %
885 (indent*' ', indent*' ', _hypertarget(var_doc, func_name)))
886
887
888 if func_doc not in (None, UNKNOWN):
889 if func_doc.posargs == UNKNOWN:
890 args = ['\\GenericArg{}']
891 else:
892 args = [self.func_arg(name, default) for (name, default)
893 in zip(func_doc.posargs, func_doc.posarg_defaults)]
894 if func_doc.vararg:
895 if func_doc.vararg == '...':
896 args.append('\\GenericArg{}')
897 else:
898 args.append('\\VarArg{%s}' %
899 plaintext_to_latex(func_doc.vararg))
900 if func_doc.kwarg:
901 args.append('\\KWArg{%s}' % plaintext_to_latex(func_doc.kwarg))
902
903 argindent = (indent*' '+' ')
904 s += argindent+('%%\n%s\\and' % argindent).join(args)+'%\n'
905 s += indent*' '+'\\end{EpydocFunctionSignature}%\n'
906
907 return s
908
917
924
925
926
927
928
930
931
932
933 out = self.replace_par(out)
934
935 has_descr = var_doc.descr not in (None, UNKNOWN)
936 has_type = var_doc.type_descr not in (None, UNKNOWN)
937 has_repr = (var_doc.value not in (None, UNKNOWN) and
938 (var_doc.value.parse_repr is not UNKNOWN or
939 var_doc.value.pyval_repr() is not UNKNOWN))
940
941 out(' \\EpydocVariable{%% <<< %s >>>\n' % var_doc.name)
942 out(' name={%s}' % _hypertarget(var_doc, var_doc.name))
943 if has_descr:
944 out(',\n description={%%\n%s }' %
945 self.docstring_to_latex(var_doc.descr, var_doc, 6))
946 if has_type:
947 out(',\n type={%%\n%s }' %
948 self.docstring_to_latex(var_doc.type_descr, var_doc, 6))
949 if has_repr:
950 out(',\n value={%s}' %
951 var_doc.value.summary_pyval_repr().to_latex(None))
952 metadata = self.metadata(var_doc, 6)
953 if metadata:
954 out(',\n metadata={%%\n%s }' % metadata)
955 out('}%\n')
956
957
958
959
960
962
963
964
965 out = self.replace_par(out)
966
967 prop_doc = var_doc.value
968 has_descr = prop_doc.descr not in (None, UNKNOWN)
969 has_type = prop_doc.type_descr not in (None, UNKNOWN)
970
971 out(' \\EpydocProperty{%% <<< %s >>>\n' % var_doc.name)
972 out(' name={%s}' % _hypertarget(var_doc, var_doc.name))
973 if has_descr:
974 out(',\n description={%%\n%s }' %
975 self.docstring_to_latex(prop_doc.descr, prop_doc, 6))
976 if has_type:
977 out(',\n type={%%\n%s }' %
978 self.docstring_to_latex(prop_doc.type_descr, prop_doc, 6))
979
980 for accessor in ('fget', 'fset', 'fdel'):
981 accessor_func = getattr(prop_doc, accessor)
982 if (accessor_func not in (None, UNKNOWN) and
983 not accessor_func.canonical_name[0].startswith('??')):
984 if isinstance(accessor_func, RoutineDoc):
985 suffix = '()'
986 else:
987 suffix = ''
988 out(',\n %s={%s%s}' %
989 (accessor, _dotted(accessor_func.canonical_name), suffix))
990 metadata = self.metadata(prop_doc, 6)
991 if metadata:
992 out(',\n metadata={%%\n%s }' % metadata)
993 out('}%\n')
994
995
996
997
998
1025
1026
1028 singular = field.singular
1029 plural = field.plural
1030 if arg:
1031 singular += ' (%s)' % arg
1032 plural += ' (%s)' % arg
1033 return (' '*indent + '%% %s:\n' % field.singular +
1034 self._descrlist([self.docstring_to_latex(d, doc, indent+2)
1035 for d in descrs],
1036 field.singular, field.plural, field.short,
1037 indent))
1038
1039
1040 - def _descrlist(self, items, singular, plural=None, short=0, indent=0):
1041 ind = indent*' '
1042 if plural is None: plural = singular
1043 if len(items) == 0: return ''
1044 if len(items) == 1 and singular is not None:
1045 return ('%s\\EpydocMetadataSingleValue{%s}{\n%s%s}\n' %
1046 (ind, singular, items[0], ind))
1047 if short:
1048 s = '%s\\begin{EpydocMetadataShortList}{%s}\n' % (ind, plural)
1049 s += ('%s\\and\n' % ind).join(items)
1050 s += '%s\\end{EpydocMetadataShortList}\n' % ind
1051 return s
1052 else:
1053 s = '%s\\begin{EpydocMetadataLongList}{%s}\n' % (ind, plural)
1054 s += ''.join(['%s \item\n%s' % (ind,item) for item in items])
1055 s += '%s\\end{EpydocMetadataLongList}\n' % ind
1056 return s
1057
1058
1059
1060
1061
1062
1063
1066 indexstr = re.sub(r'["!|@]', r'"\1', indexterm.to_latex(self))
1067 return ('\\index{%s}\\textit{%s}' % (indexstr, indexstr))
1071
1072 _docstring_linker = _LatexDocstringLinker()
1073
1075 """
1076 Return a latex string that renders the given docstring. This
1077 string expects to start at the beginning of a line; and ends
1078 with a newline.
1079 """
1080 if docstring is None: return ''
1081 s = docstring.to_latex(self._docstring_linker, indent=indent+2,
1082 directory=self._directory,
1083 docindex=self.docindex,
1084 context=where,
1085 hyperref=self._hyperref)
1086 return (' '*indent + '\\begin{EpydocDescription}\n' +
1087 ' '*indent + ' ' + s.strip() + '%\n' +
1088 ' '*indent + '\\end{EpydocDescription}\n')
1089
1090
1091
1092
1093
1095 out('%\n% API Documentation')
1096 if self._prj_name: out(' for %s' % self._prj_name)
1097 if isinstance(where, APIDoc):
1098 out('\n%% %s %s' % (self.doc_kind(where), where.canonical_name))
1099 else:
1100 out('\n%% %s' % where)
1101 out('\n%%\n%% Generated by epydoc %s\n' % epydoc.__version__)
1102 out('%% [%s]\n%%\n' % time.asctime(time.localtime(time.time())))
1103
1104 - def start_of(self, section_name, doc=None):
1105 return ('\n' + 75*'%' + '\n' +
1106 '%%' + section_name.center(71) + '%%\n' +
1107 75*'%' + '\n\n')
1108
1109 - def section(self, title, depth=0, ref=None):
1110 sec = self.SECTIONS[depth+self._top_section]
1111 text = (sec % title) + '%\n'
1112 if ref:
1113 text += _hypertarget(ref, "") + '%\n'
1114 return text
1115
1116
1118 sec = self.STARSECTIONS[depth+self._top_section]
1119 text = (sec % title) + '%\n'
1120 if ref:
1121 text += _hypertarget(ref, "") + '%\n'
1122 return text
1123
1125 if isinstance(doc, ModuleDoc) and doc.is_package == True:
1126 return 'Package'
1127 elif (isinstance(doc, ModuleDoc) and
1128 doc.canonical_name[0].startswith('script')):
1129 return 'Script'
1130 elif isinstance(doc, ModuleDoc):
1131 return 'Module'
1132 elif isinstance(doc, ClassDoc):
1133 return 'Class'
1134 elif isinstance(doc, ClassMethodDoc):
1135 return 'Class Method'
1136 elif isinstance(doc, StaticMethodDoc):
1137 return 'Static Method'
1138 elif isinstance(doc, RoutineDoc):
1139 if isinstance(self.docindex.container(doc), ClassDoc):
1140 return 'Method'
1141 else:
1142 return 'Function'
1143 else:
1144 return 'Variable'
1145
1146
1147
1148
1149 - def indexterm(self, doc, pos='only', indent=0):
1150 """Return a latex string that marks the given term or section
1151 for inclusion in the index. This string ends with a newline."""
1152 if not self._index: return ''
1153 if isinstance(doc, RoutineDoc) and not self._index_functions:
1154 return ''
1155
1156 pieces = []
1157 kinds = []
1158 while True:
1159 if doc.canonical_name in (None, UNKNOWN): return ''
1160 pieces.append(doc.canonical_name[-1])
1161 kinds.append(self.doc_kind(doc).lower())
1162 doc = self.docindex.container(doc)
1163 if isinstance(doc, ModuleDoc): break
1164 if doc is None: break
1165 if doc == UNKNOWN: return ''
1166
1167 pieces.reverse()
1168 kinds.reverse()
1169 for i in range(1, len(pieces)):
1170 if not kinds[i].endswith('method'):
1171 pieces[i] = '%s.%s' % (pieces[i-1], pieces[i])
1172 pieces = ['\\EpydocIndex{%s}{%s}{%s}' %
1173 (_dotted(piece.lower()), _dotted(piece), kind)
1174 for (piece, kind) in zip (pieces, kinds)]
1175
1176 if pos == 'only': modifier = ''
1177 elif pos == 'start': modifier = '|('
1178 elif pos == 'end': modifier = '|)'
1179 else: raise AssertionError('Bad index position %s' % pos)
1180
1181 return '%s\\index{%s%s}%%\n' % (' '*indent, '!'.join(pieces), modifier)
1182
1183
1184 latex_encodings = {
1185 'utf-8': 'utf8x',
1186 }
1187
1189 """
1190 @return: The LaTeX representation of the selected encoding.
1191 @rtype: C{str}
1192 """
1193 enc = self._encoding.lower()
1194 return self.latex_encodings.get(enc, enc)
1195
1197 if (self._show_crossrefs and
1198 ((isinstance(doc, ModuleDoc) and doc in self.module_set) or
1199 (isinstance(doc, ClassDoc) and doc in self.class_set))):
1200 return '%s\\CrossRef{%s}%%\n' % (' '*indent, _label(doc),)
1201 else:
1202 return ''
1203
1205 if self._show_deprecated:
1206 return docs
1207 else:
1208 return [d for d in docs if not self._is_deprecated(d)]
1209
1219
1220
1222
1223 s = '%s' % doc.canonical_name
1224 s = s.replace('.', ':').replace('_','-')
1225
1226
1227
1228
1229
1230 s = re.sub('[^\w:-]', '-', s)
1231
1232 return s
1233
1234
1237
1239 return '\\EpydocHypertarget{%s}{%s}' % (_label(uid), _dotted(sig))
1240
1244
1245 LATEX_WARNING_RE = re.compile('|'.join([
1246 r'(?P<file>\([\.a-zA-Z_\-/\\0-9]+[.\n][a-z]{2,3}\b)',
1247 (r'(?P<pkgwarn>^(Package|Latex) (?P<pkgname>[\w-]+) '+
1248 r'Warning:[^\n]*\n(\((?P=pkgname)\)[^\n]*\n)*)'),
1249 r'(?P<overfull>^(Overfull|Underfull)[^\n]*\n[^\n]*)',
1250 r'(?P<latexwarn>^LaTeX\s+Warning:\s+[^\n]*)',
1251 r'(?P<otherwarn>^[^\n]*Warning:[^\n]*)',
1252 r'(?P<paren>[()])',
1253 r'(?P<pageno>\[\d+({[^\}]+})?\])']),
1254 re.MULTILINE+re.IGNORECASE)
1255
1256 OVERFULL_RE = re.compile(
1257 r'(?P<typ>Underfull|Overfull)\s+\\(?P<boxtype>[vh]box)\s+'
1258 r'\((?P<size>\d+)[^\n\)]+\)[^\n]+\s+lines\s+'
1259 r'(?P<start>\d+)')
1260
1261 IGNORE_WARNING_REGEXPS = [
1262 re.compile(r'LaTeX\s+Font\s+Warning:\s+.*\n\(Font\)\s*using.*instead'),
1263 re.compile(r'LaTeX\s+Font\s+Warning:\s+Some\s+font\s+shapes\s+'
1264 r'were\s+not\s+available,\s+defaults\s+substituted.'),
1265 ]
1266
1268 filestack = ['latex']
1269 pageno = 1
1270 for m in LATEX_WARNING_RE.finditer(s):
1271 if m.group('file'):
1272 filename = ''.join(m.group('file')[1:].split())
1273 filename = re.sub(r'^\./', '', filename)
1274 if filename == 'api.toc': filename = 'Table of contents (api.toc)'
1275 if filename == 'api.ind': filename = 'Index (api.ind)'
1276 filestack.append(filename)
1277 elif m.group('pageno'):
1278 if pageno == int(m.group()[1:-1].split('{')[0]):
1279 pageno += 1
1280 elif m.group('overfull'): pass
1281 elif m.group('latexwarn'): pass
1282 elif m.group('pkgwarn'): pass
1283 else:
1284
1285 n = m.group().count('(') - m.group().count(')')
1286 if n > 0: filestack += [None] * n
1287 if n < 0: del filestack[n:]
1288
1289 if not filestack: filestack.append('latex')
1290
1291 return filestack[-1], pageno
1292
1294 s = re.sub('(.{79,79})\n', r'\1', s)
1295
1296
1297 overfull = underfull = 0
1298 filestack = ['latex']
1299 block = None
1300 BLOCK = 'LaTeX Warnings: %s'
1301 pageno = 1
1302 for m in LATEX_WARNING_RE.finditer(s):
1303
1304
1305 for regexp in IGNORE_WARNING_REGEXPS:
1306 if regexp.match(m.group()):
1307 m = None; break
1308 if m is None: continue
1309
1310 if m.group('file'):
1311 filename = ''.join(m.group('file')[1:].split())
1312 filename = re.sub(r'^\./', '', filename)
1313 if filename == 'api.toc': filename = 'Table of contents (api.toc)'
1314 if filename == 'api.ind': filename = 'Index (api.ind)'
1315 filestack.append(filename)
1316 if block is not None: epydoc.log.end_block()
1317 epydoc.log.start_block(BLOCK % filename)
1318 block = filename
1319
1320 elif m.group('pageno'):
1321 if pageno == int(m.group()[1:-1].split('{')[0]):
1322 pageno += 1
1323
1324 elif m.group('overfull'):
1325 msg = m.group('overfull').strip().split('\n')[0]
1326 msg = re.sub(r'(\d+)\.\d+', r'\1', msg)
1327 msg = re.sub(r'(lines \d+)--(\d+)', r'\1-\2', msg)
1328 if msg.lower().startswith('overfull'): overfull += 1
1329 else: underfull += 1
1330 log.warning(msg)
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343 elif m.group('latexwarn'):
1344 log.warning(m.group('latexwarn').strip()+' (page %d)' % pageno)
1345
1346 elif m.group('pkgwarn'):
1347 log.warning(m.group('pkgwarn').strip())
1348 else:
1349
1350 if m.group('otherwarn'):
1351 log.warning(m.group('otherwarn').strip())
1352
1353 n = m.group().count('(') - m.group().count(')')
1354 if n > 0: filestack += [None] * n
1355 if n < 0: del filestack[n:]
1356
1357 if not filestack: filestack.append('latex')
1358 if (filestack[-1] is not None and
1359 block is not None and block != filestack[-1]):
1360 epydoc.log.end_block()
1361 epydoc.log.start_block(BLOCK % filestack[-1])
1362
1363 if block:
1364 epydoc.log.end_block()
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376