1
2
3
4
5
6
7
8
9 """
10 Parse docstrings and handle any fields it defines, such as C{@type}
11 and C{@author}. Fields are used to describe specific information
12 about an object. There are two classes of fields: X{simple fields}
13 and X{special fields}.
14
15 Simple fields are fields that get stored directly in an C{APIDoc}'s
16 metadata dictionary, without any special processing. The set of
17 simple fields is defined by the list L{STANDARD_FIELDS}, whose
18 elements are L{DocstringField}s.
19
20 Special fields are fields that perform some sort of processing on the
21 C{APIDoc}, or add information to attributes other than the metadata
22 dictionary. Special fields are are handled by field handler
23 functions, which are registered using L{register_field_handler}.
24 """
25 __docformat__ = 'epytext en'
26
27
28
29
30
31
32 import re, sys
33 from epydoc import markup
34 from epydoc.apidoc import *
35 from epydoc.docintrospecter import introspect_docstring_lineno
36 from epydoc.util import py_src_filename
37 from epydoc import log
38 import __builtin__, exceptions
39
40
41
42
43
45 """
46 A simple docstring field, which can be used to describe specific
47 information about an object, such as its author or its version.
48 Simple docstring fields are fields that take no arguments, and
49 are displayed as simple sections.
50
51 @ivar tags: The set of tags that can be used to identify this
52 field.
53 @ivar singular: The label that should be used to identify this
54 field in the output, if the field contains one value.
55 @ivar plural: The label that should be used to identify this
56 field in the output, if the field contains multiple values.
57 @ivar short: If true, then multiple values should be combined
58 into a single comma-delimited list. If false, then
59 multiple values should be listed separately in a bulleted
60 list.
61 @ivar multivalue: If true, then multiple values may be given
62 for this field; if false, then this field can only take a
63 single value, and a warning should be issued if it is
64 redefined.
65 @ivar takes_arg: If true, then this field expects an argument;
66 and a separate field section will be constructed for each
67 argument value. The label (and plural label) should include
68 a '%s' to mark where the argument's string rep should be
69 added.
70 """
71 - def __init__(self, tags, label, plural=None,
72 short=0, multivalue=1, takes_arg=0):
73 if type(tags) in (list, tuple):
74 self.tags = tuple(tags)
75 elif type(tags) is str:
76 self.tags = (tags,)
77 else: raise TypeError('Bad tags: %s' % tags)
78 self.singular = label
79 if plural is None: self.plural = label
80 else: self.plural = plural
81 self.multivalue = multivalue
82 self.short = short
83 self.takes_arg = takes_arg
84
86 if not isinstance(other, DocstringField): return -1
87 return cmp(self.tags, other.tags)
88
90 return hash(self.tags)
91
93 return '<Field: %s>' % self.tags[0]
94
95 STANDARD_FIELDS = [
96
97
98
99
100
101
102
103 DocstringField(['deprecated', 'depreciated'],
104 'Deprecated', multivalue=0),
105
106
107 DocstringField(['version'], 'Version', multivalue=0),
108 DocstringField(['date'], 'Date', multivalue=0),
109 DocstringField(['status'], 'Status', multivalue=0),
110
111
112 DocstringField(['author', 'authors'], 'Author', 'Authors', short=1),
113 DocstringField(['contact'], 'Contact', 'Contacts', short=1),
114 DocstringField(['organization', 'org'],
115 'Organization', 'Organizations'),
116 DocstringField(['copyright', '(c)'], 'Copyright', multivalue=0),
117 DocstringField(['license'], 'License', multivalue=0),
118
119
120 DocstringField(['bug'], 'Bug', 'Bugs'),
121 DocstringField(['warning', 'warn'], 'Warning', 'Warnings'),
122 DocstringField(['attention'], 'Attention'),
123 DocstringField(['note'], 'Note', 'Notes'),
124
125
126 DocstringField(['requires', 'require', 'requirement'], 'Requires'),
127 DocstringField(['precondition', 'precond'],
128 'Precondition', 'Preconditions'),
129 DocstringField(['postcondition', 'postcond'],
130 'Postcondition', 'Postconditions'),
131 DocstringField(['invariant'], 'Invariant'),
132
133
134 DocstringField(['since'], 'Since', multivalue=0),
135
136
137 DocstringField(['see', 'seealso'], 'See Also', short=1),
138
139
140 DocstringField(['todo'], 'To Do', takes_arg=True),
141
142
143 DocstringField(['permission', 'permissions'], 'Permission', 'Permissions')
144 ]
145
146
147
148
149
150 DEFAULT_DOCFORMAT = 'epytext'
151 """The name of the default markup languge used to process docstrings."""
152
153
154
155
156
158 """
159 Process the given C{APIDoc}'s docstring. In particular, populate
160 the C{APIDoc}'s C{descr} and C{summary} attributes, and add any
161 information provided by fields in the docstring.
162
163 @param docindex: A DocIndex, used to find the containing
164 module (to look up the docformat); and to find any
165 user docfields defined by containing objects.
166 """
167 if api_doc.metadata is not UNKNOWN:
168 log.debug("%s's docstring processed twice" % api_doc.canonical_name)
169 return
170
171 initialize_api_doc(api_doc)
172
173
174 if (api_doc.docstring in (None, UNKNOWN)):
175 return
176
177
178 api_doc.docstring = unindent_docstring(api_doc.docstring)
179
180
181
182 if isinstance(api_doc, RoutineDoc):
183 parse_function_signature(api_doc)
184
185
186
187 docformat = get_docformat(api_doc, docindex)
188 parse_errors = []
189 parsed_docstring = markup.parse(api_doc.docstring, docformat,
190 parse_errors)
191
192
193
194 descr, fields = parsed_docstring.split_fields(parse_errors)
195 api_doc.descr = descr
196
197
198 field_warnings = []
199 for field in fields:
200 try:
201 process_field(api_doc, docindex, field.tag(),
202 field.arg(), field.body())
203 except ValueError, e: field_warnings.append(str(e))
204
205
206 if api_doc.summary is None and api_doc.descr is not None:
207 api_doc.summary = api_doc.descr.summary()
208
209
210
211
212
213 report_errors(api_doc, docindex, parse_errors, field_warnings)
214
243
244 -def report_errors(api_doc, docindex, parse_errors, field_warnings):
245 """A helper function for L{parse_docstring()} that reports any
246 markup warnings and field warnings that we encountered while
247 processing C{api_doc}'s docstring."""
248 if not parse_errors and not field_warnings: return
249
250
251
252 name = api_doc.canonical_name
253 module = api_doc.defining_module
254 if module != UNKNOWN and module.filename not in (None, UNKNOWN):
255 try: filename = py_src_filename(module.filename)
256 except: filename = module.filename
257 else:
258 filename = '??'
259
260
261 if (isinstance(api_doc, ValueDoc) and api_doc != module and
262 (api_doc.pyval in __builtin__.__dict__.values() or
263 (module is not None and
264 module.pyval in (__builtin__, exceptions)))):
265 return
266
267
268 startline = api_doc.docstring_lineno
269 if startline in (None, UNKNOWN):
270 startline = introspect_docstring_lineno(api_doc)
271 if startline in (None, UNKNOWN):
272 startline = None
273
274
275 header = 'File %s, ' % filename
276 if startline is not None:
277 header += 'line %d, ' % startline
278 header += 'in %s' % name
279 log.start_block(header)
280
281
282
283
284 if startline is None:
285
286 dups = {}
287 for error in parse_errors:
288 message = error.descr()
289 if message not in dups:
290 log.docstring_warning(message)
291 dups[message] = 1
292 else:
293
294 messages = {}
295 for error in parse_errors:
296 error.set_linenum_offset(startline)
297 message = error.descr()
298 messages.setdefault(message, []).append(error.linenum())
299 message_items = messages.items()
300 message_items.sort(lambda a,b:cmp(min(a[1]), min(b[1])))
301 for message, linenums in message_items:
302 linenums = [n for n in linenums if n is not None]
303 if len(linenums) == 0:
304 log.docstring_warning(message)
305 elif len(linenums) == 1:
306 log.docstring_warning("Line %s: %s" % (linenums[0], message))
307 else:
308 linenums = ', '.join(['%s' % l for l in linenums])
309 log.docstring_warning("Lines %s: %s" % (linenums, message))
310
311
312 for warning in field_warnings:
313 log.docstring_warning(warning)
314
315
316 log.end_block()
317
318
319
320
321
322 UNEXPECTED_ARG = '%r did not expect an argument'
323 EXPECTED_ARG = '%r expected an argument'
324 EXPECTED_SINGLE_ARG = '%r expected a single argument'
325 BAD_CONTEXT = 'Invalid context for %r'
326 REDEFINED = 'Redefinition of %s'
327 UNKNOWN_TAG = 'Unknown field tag %r'
328
329
330
331
332
334 """
335 Process a single field, and use it to update C{api_doc}. If
336 C{tag} is the name of a special field, then call its handler
337 function. If C{tag} is the name of a simple field, then use
338 C{process_simple_field} to process it. Otherwise, check if it's a
339 user-defined field, defined in this docstring or the docstring of
340 a containing object; and if so, process it with
341 C{process_simple_field}.
342
343 @param tag: The field's tag, such as C{'author'}
344 @param arg: The field's optional argument
345 @param descr: The description following the field tag and
346 argument.
347 @raise ValueError: If a problem was encountered while processing
348 the field. The C{ValueError}'s string argument is an
349 explanation of the problem, which should be displayed as a
350 warning message.
351 """
352
353 if tag in _field_dispatch_table:
354 handler = _field_dispatch_table[tag]
355 handler(api_doc, docindex, tag, arg, descr)
356 return
357
358
359 for field in STANDARD_FIELDS + user_docfields(api_doc, docindex):
360 if tag in field.tags:
361
362 if not field.takes_arg:
363 _check(api_doc, tag, arg, expect_arg=False)
364 api_doc.metadata.append((field, arg, descr))
365 return
366
367
368 raise ValueError(UNKNOWN_TAG % tag)
369
371 """
372 Return a list of user defined fields that can be used for the
373 given object. This list is taken from the given C{api_doc}, and
374 any of its containing C{NamepaceDoc}s.
375
376 @bug: If a child's docstring is parsed before its parents, then
377 its parent won't yet have had its C{extra_docstring_fields}
378 attribute initialized.
379 """
380 docfields = []
381
382 if api_doc.extra_docstring_fields not in (None, UNKNOWN):
383 docfields += api_doc.extra_docstring_fields
384
385 for i in range(len(api_doc.canonical_name)-1, 0, -1):
386 ancestor = docindex.get_valdoc(api_doc.canonical_name.container())
387 if ancestor is not None \
388 and ancestor.extra_docstring_fields not in (None, UNKNOWN):
389 docfields += ancestor.extra_docstring_fields
390 return docfields
391
392 _field_dispatch_table = {}
394 """
395 Register the given field handler function for processing any
396 of the given field tags. Field handler functions should
397 have the following signature:
398
399 >>> def field_handler(api_doc, docindex, tag, arg, descr):
400 ... '''update api_doc in response to the field.'''
401
402 Where C{api_doc} is the documentation object to update;
403 C{docindex} is a L{DocIndex} that can be used to look up the
404 documentation for related objects; C{tag} is the field tag that
405 was used; C{arg} is the optional argument; and C{descr} is the
406 description following the field tag and argument.
407 """
408 for field_tag in field_tags:
409 _field_dispatch_table[field_tag] = handler
410
411
412
413
414
421
423 """Copy the docstring contents from the object named in C{descr}"""
424 _check(api_doc, tag, arg, expect_arg=False)
425
426
427
428
429
430
431
432
433 raise ValueError('%s not implemented yet' % tag)
434
436 """Remove any documentation for the variables named in C{descr}"""
437 _check(api_doc, tag, arg, context=NamespaceDoc, expect_arg=False)
438 for ident in _descr_to_identifiers(descr):
439 var_name_re = re.compile('^%s$' % ident.replace('*', '(.*)'))
440 for var_name, var_doc in api_doc.variables.items():
441 if var_name_re.match(var_name):
442
443 api_doc.variables.pop(var_name, None)
444
450
451
462
470
474
475
477
478 if isinstance(api_doc, NamespaceDoc):
479 _check(api_doc, tag, arg, expect_arg='single')
480 set_var_type(api_doc, arg, descr)
481
482
483 elif isinstance(api_doc, (VariableDoc, PropertyDoc)):
484 _check(api_doc, tag, arg, expect_arg=False)
485 if api_doc.type_descr is not None:
486 raise ValueError(REDEFINED % tag)
487 api_doc.type_descr = descr
488
489
490 elif isinstance(api_doc, RoutineDoc):
491 _check(api_doc, tag, arg, expect_arg='single')
492 if arg in api_doc.arg_types:
493 raise ValueError(REDEFINED % ('type for '+arg))
494 api_doc.arg_types[arg] = descr
495 else:
496 raise ValueError(BAD_CONTEXT % arg)
497
502
504
505
506 if (isinstance(api_doc, VariableDoc) and
507 isinstance(api_doc.container, ClassDoc)):
508 _check(api_doc, tag, arg, expect_arg=False)
509 api_doc.is_instvar = False
510 api_doc.descr = api_doc.descr.concatenate(descr)
511 api_doc.summary = descr.summary()
512
513
514 else:
515 _check(api_doc, tag, arg, context=ClassDoc, expect_arg=True)
516 for ident in re.split('[:;, ] *', arg):
517 set_var_descr(api_doc, ident, descr)
518 api_doc.variables[ident].is_instvar = False
519
521
522
523 if (isinstance(api_doc, VariableDoc) and
524 isinstance(api_doc.container, ClassDoc)):
525 _check(api_doc, tag, arg, expect_arg=False)
526
527 api_doc.is_instvar = True
528 api_doc.descr = api_doc.descr.concatenate(descr)
529 api_doc.summary = descr.summary()
530
531
532 else:
533 _check(api_doc, tag, arg, context=ClassDoc, expect_arg=True)
534 for ident in re.split('[:;, ] *', arg):
535 set_var_descr(api_doc, ident, descr)
536 api_doc.variables[ident].is_instvar = True
537
538
539
545
551
556
563
564 register_field_handler(process_group_field, 'group')
565 register_field_handler(process_deffield_field, 'deffield', 'newfield')
566 register_field_handler(process_sort_field, 'sort')
567 register_field_handler(process_summary_field, 'summary')
568 register_field_handler(process_undocumented_field, 'undocumented')
569 register_field_handler(process_include_field, 'include')
570 register_field_handler(process_var_field, 'var', 'variable')
571 register_field_handler(process_type_field, 'type')
572 register_field_handler(process_cvar_field, 'cvar', 'cvariable')
573 register_field_handler(process_ivar_field, 'ivar', 'ivariable')
574 register_field_handler(process_return_field, 'return', 'returns')
575 register_field_handler(process_rtype_field, 'rtype', 'returntype')
576 register_field_handler(process_arg_field, 'arg', 'argument',
577 'parameter', 'param')
578 register_field_handler(process_kwarg_field, 'kwarg', 'keyword', 'kwparam')
579 register_field_handler(process_raise_field, 'raise', 'raises',
580 'except', 'exception')
581
582
583
584
585
597
606
607 -def _check(api_doc, tag, arg, context=None, expect_arg=None):
608 if context is not None:
609 if not isinstance(api_doc, context):
610 raise ValueError(BAD_CONTEXT % tag)
611 if expect_arg is not None:
612 if expect_arg == True:
613 if arg is None:
614 raise ValueError(EXPECTED_ARG % tag)
615 elif expect_arg == False:
616 if arg is not None:
617 raise ValueError(UNEXPECTED_ARG % tag)
618 elif expect_arg == 'single':
619 if (arg is None or ' ' in arg):
620 raise ValueError(EXPECTED_SINGLE_ARG % tag)
621 else:
622 assert 0, 'bad value for expect_arg'
623
639
641
642
643
644 if docstring == '': return ''
645 lines = docstring.expandtabs().split('\n')
646
647
648 margin = sys.maxint
649 for line in lines[1:]:
650 content = len(line.lstrip())
651 if content:
652 indent = len(line) - content
653 margin = min(margin, indent)
654
655 if lines:
656 lines[0] = lines[0].lstrip()
657 if margin < sys.maxint:
658 for i in range(1, len(lines)): lines[i] = lines[i][margin:]
659
660 while lines and not lines[-1]:
661 lines.pop()
662
663
664 return '\n'.join(lines)
665
666 _IDENTIFIER_LIST_REGEXP = re.compile(r'^[\w.\*]+([\s,:;]\s*[\w.\*]+)*$')
668 """
669 Given a C{ParsedDocstring} that contains a list of identifiers,
670 return a list of those identifiers. This is used by fields such
671 as C{@group} and C{@sort}, which expect lists of identifiers as
672 their values. To extract the identifiers, the docstring is first
673 converted to plaintext, and then split. The plaintext content of
674 the docstring must be a a list of identifiers, separated by
675 spaces, commas, colons, or semicolons.
676
677 @rtype: C{list} of C{string}
678 @return: A list of the identifier names contained in C{descr}.
679 @type descr: L{markup.ParsedDocstring}
680 @param descr: A C{ParsedDocstring} containing a list of
681 identifiers.
682 @raise ValueError: If C{descr} does not contain a valid list of
683 identifiers.
684 """
685 idents = descr.to_plaintext(None).strip()
686 idents = re.sub(r'\s+', ' ', idents)
687 if not _IDENTIFIER_LIST_REGEXP.match(idents):
688 raise ValueError, 'Bad Identifier list: %r' % idents
689 rval = re.split('[:;, ] *', idents)
690 return rval
691
693 tags = [s.lower() for s in re.split('[:;, ] *', arg)]
694 descr = descr.to_plaintext(None).strip()
695 args = re.split('[:;,] *', descr)
696 if len(args) == 0 or len(args) > 3:
697 raise ValueError, 'Wrong number of arguments'
698 singular = args[0]
699 if len(args) >= 2: plural = args[1]
700 else: plural = None
701 short = 0
702 if len(args) >= 3:
703 if args[2] == 'short': short = 1
704 else: raise ValueError('Bad arg 2 (expected "short")')
705 return DocstringField(tags, singular, plural, short)
706
707
708
709
710
711
712 _SIGNATURE_RE = re.compile(
713
714 r'^\s*((?P<self>\w+)\.)?' +
715
716 r'(?P<func>\w+)' +
717
718 r'\((?P<params>(\s*\[?\s*\*{0,2}[\w\-\.]+(=.+?)?'+
719 r'(\s*\[?\s*,\s*\]?\s*\*{0,2}[\w\-\.]+(=.+?)?)*\]*)?)\s*\)' +
720
721 r'(\s*(->)\s*(?P<return>\S.*?))?'+
722
723 r'\s*(\n|\s+(--|<=+>)\s+|$|\.\s+|\.\n)')
724 """A regular expression that is used to extract signatures from
725 docstrings."""
726
728 """
729 Construct the signature for a builtin function or method from
730 its docstring. If the docstring uses the standard convention
731 of including a signature in the first line of the docstring
732 (and formats that signature according to standard
733 conventions), then it will be used to extract a signature.
734 Otherwise, the signature will be set to a single varargs
735 variable named C{"..."}.
736
737 @rtype: C{None}
738 """
739
740 if not func_doc.docstring: return False
741
742 m = _SIGNATURE_RE.match(func_doc.docstring)
743 if m is None: return False
744
745
746
747
748
749
750
751
752
753 params = m.group('params')
754 rtype = m.group('return')
755 selfparam = m.group('self')
756
757
758 func_doc.posargs = []
759 func_doc.vararg = None
760 func_doc.kwarg = None
761 if func_doc.posarg_defaults is UNKNOWN:
762 func_doc.posarg_defaults = []
763 if params:
764
765 while '[' in params or ']' in params:
766 m2 = re.match(r'(.*)\[([^\[\]]+)\](.*)', params)
767 if not m2: return False
768 (start, mid, end) = m2.groups()
769 mid = re.sub(r'((,|^)\s*[\w\-\.]+)', r'\1=...', mid)
770 params = start+mid+end
771
772 params = re.sub(r'=...=' , r'=', params)
773 for name in params.split(','):
774 if '=' in name:
775 (name, default_repr) = name.split('=',1)
776 default = GenericValueDoc(parse_repr=default_repr)
777 else:
778 default = None
779 name = name.strip()
780 if name == '...':
781 func_doc.vararg = '...'
782 elif name.startswith('**'):
783 func_doc.kwarg = name[2:]
784 elif name.startswith('*'):
785 func_doc.vararg = name[1:]
786 else:
787 func_doc.posargs.append(name)
788 if len(func_doc.posarg_defaults) < len(func_doc.posargs):
789 func_doc.posarg_defaults.append(default)
790 elif default is not None:
791 argnum = len(func_doc.posargs)-1
792 func_doc.posarg_defaults[argnum] = default
793
794
795 if rtype:
796 func_doc.return_descr = markup.parse(rtype, 'plaintext')
797
798
799 if selfparam:
800 func_doc.posargs.insert(0, selfparam)
801 func_doc.posarg_defaults.insert(0, None)
802
803
804 func_doc.docstring = func_doc.docstring[m.end():]
805
806
807 return True
808