| Home | Trees | Indices | Help |
|
|---|
|
|
1 # epydoc -- Docstring processing
2 #
3 # Copyright (C) 2005 Edward Loper
4 # Author: Edward Loper <edloper@loper.org>
5 # URL: <http://epydoc.sf.net>
6 #
7 # $Id: docstringparser.py 1715 2008-02-13 19:19:47Z edloper $
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 ## Imports
30 ######################################################################
31
32 import re, sys
33 from epydoc import markup
34 from epydoc.markup import epytext
35 from epydoc.apidoc import *
36 from epydoc.docintrospecter import introspect_docstring_lineno
37 from epydoc.util import py_src_filename
38 from epydoc import log
39 import epydoc.docparser
40 import __builtin__, exceptions
41
42 ######################################################################
43 # Docstring Fields
44 ######################################################################
45
47 """
48 A simple docstring field, which can be used to describe specific
49 information about an object, such as its author or its version.
50 Simple docstring fields are fields that take no arguments, and
51 are displayed as simple sections.
52
53 @ivar tags: The set of tags that can be used to identify this
54 field.
55 @ivar singular: The label that should be used to identify this
56 field in the output, if the field contains one value.
57 @ivar plural: The label that should be used to identify this
58 field in the output, if the field contains multiple values.
59 @ivar short: If true, then multiple values should be combined
60 into a single comma-delimited list. If false, then
61 multiple values should be listed separately in a bulleted
62 list.
63 @ivar multivalue: If true, then multiple values may be given
64 for this field; if false, then this field can only take a
65 single value, and a warning should be issued if it is
66 redefined.
67 @ivar takes_arg: If true, then this field expects an argument;
68 and a separate field section will be constructed for each
69 argument value. The label (and plural label) should include
70 a '%s' to mark where the argument's string rep should be
71 added.
72 """
73 - def __init__(self, tags, label, plural=None,
74 short=0, multivalue=1, takes_arg=0,
75 varnames=None):
76 if type(tags) in (list, tuple):
77 self.tags = tuple(tags)
78 elif type(tags) is str:
79 self.tags = (tags,)
80 else: raise TypeError('Bad tags: %s' % tags)
81 self.singular = label
82 if plural is None: self.plural = label
83 else: self.plural = plural
84 self.multivalue = multivalue
85 self.short = short
86 self.takes_arg = takes_arg
87 self.varnames = varnames or []
88
92
95
98
99 STANDARD_FIELDS = [
100 #: A list of the standard simple fields accepted by epydoc. This
101 #: list can be augmented at run-time by a docstring with the special
102 #: C{@deffield} field. The order in which fields are listed here
103 #: determines the order in which they will be displayed in the
104 #: output.
105
106 # If it's deprecated, put that first.
107 DocstringField(['deprecated', 'depreciated'],
108 'Deprecated', multivalue=0, varnames=['__deprecated__']),
109
110 # Status info
111 DocstringField(['version'], 'Version', multivalue=0,
112 varnames=['__version__']),
113 DocstringField(['date'], 'Date', multivalue=0,
114 varnames=['__date__']),
115 DocstringField(['status'], 'Status', multivalue=0),
116
117 # Bibliographic Info
118 DocstringField(['author', 'authors'], 'Author', 'Authors', short=1,
119 varnames=['__author__', '__authors__']),
120 DocstringField(['contact'], 'Contact', 'Contacts', short=1,
121 varnames=['__contact__']),
122 DocstringField(['organization', 'org'],
123 'Organization', 'Organizations'),
124 DocstringField(['copyright', '(c)'], 'Copyright', multivalue=0,
125 varnames=['__copyright__']),
126 DocstringField(['license'], 'License', multivalue=0,
127 varnames=['__license__']),
128
129 # Various warnings etc.
130 DocstringField(['bug'], 'Bug', 'Bugs'),
131 DocstringField(['warning', 'warn'], 'Warning', 'Warnings'),
132 DocstringField(['attention'], 'Attention'),
133 DocstringField(['note'], 'Note', 'Notes'),
134
135 # Formal conditions
136 DocstringField(['requires', 'require', 'requirement'], 'Requires'),
137 DocstringField(['precondition', 'precond'],
138 'Precondition', 'Preconditions'),
139 DocstringField(['postcondition', 'postcond'],
140 'Postcondition', 'Postconditions'),
141 DocstringField(['invariant'], 'Invariant'),
142
143 # When was it introduced (version # or date)
144 DocstringField(['since'], 'Since', multivalue=0),
145
146 # Changes made
147 DocstringField(['change', 'changed'], 'Change Log'),
148
149 # Crossreferences
150 DocstringField(['see', 'seealso'], 'See Also', short=1),
151
152 # Future Work
153 DocstringField(['todo'], 'To Do', takes_arg=True),
154
155 # Permissions (used by zope-based projects)
156 DocstringField(['permission', 'permissions'], 'Permission', 'Permissions')
157 ]
158
159 ######################################################################
160 #{ Docstring Parsing
161 ######################################################################
162
163 DEFAULT_DOCFORMAT = 'epytext'
164 """The name of the default markup languge used to process docstrings."""
165
166 # [xx] keep track of which ones we've already done, in case we're
167 # asked to process one twice? e.g., for @include we might have to
168 # parse the included docstring earlier than we might otherwise..??
169
171 """
172 Process the given C{APIDoc}'s docstring. In particular, populate
173 the C{APIDoc}'s C{descr} and C{summary} attributes, and add any
174 information provided by fields in the docstring.
175
176 @param docindex: A DocIndex, used to find the containing
177 module (to look up the docformat); and to find any
178 user docfields defined by containing objects.
179 @param suppress_warnings: A set of objects for which docstring
180 warnings should be suppressed.
181 """
182 if api_doc.metadata is not UNKNOWN:
183 if not (isinstance(api_doc, RoutineDoc)
184 and api_doc.canonical_name[-1] == '__init__'):
185 log.debug("%s's docstring processed twice" %
186 api_doc.canonical_name)
187 return
188
189 initialize_api_doc(api_doc)
190
191 # If there's no docstring, then check for special variables (e.g.,
192 # __version__), and then return -- there's nothing else to do.
193 if (api_doc.docstring in (None, UNKNOWN)):
194 if isinstance(api_doc, NamespaceDoc):
195 for field in STANDARD_FIELDS + user_docfields(api_doc, docindex):
196 add_metadata_from_var(api_doc, field)
197 return
198
199 # Remove leading indentation from the docstring.
200 api_doc.docstring = unindent_docstring(api_doc.docstring)
201
202 # Decide which docformat is used by this module.
203 docformat = get_docformat(api_doc, docindex)
204
205 # A list of markup errors from parsing.
206 parse_errors = []
207
208 # Extract a signature from the docstring, if it has one. This
209 # overrides any signature we got via introspection/parsing.
210 if isinstance(api_doc, RoutineDoc):
211 parse_function_signature(api_doc, None, docformat, parse_errors)
212
213 # Parse the docstring. Any errors encountered are stored as
214 # `ParseError` objects in the errors list.
215 parsed_docstring = markup.parse(api_doc.docstring, docformat,
216 parse_errors)
217
218 # Divide the docstring into a description and a list of
219 # fields.
220 descr, fields = parsed_docstring.split_fields(parse_errors)
221 api_doc.descr = descr
222
223 field_warnings = []
224
225 # Handle the constructor fields that have been defined in the class
226 # docstring. This code assumes that a class docstring is parsed before
227 # the same class __init__ docstring.
228 if isinstance(api_doc, ClassDoc):
229
230 # Parse ahead the __init__ docstring for this class
231 initvar = api_doc.variables.get('__init__')
232 if initvar and isinstance(initvar.value, RoutineDoc):
233 init_api_doc = initvar.value
234 parse_docstring(init_api_doc, docindex, suppress_warnings)
235
236 parse_function_signature(init_api_doc, api_doc,
237 docformat, parse_errors)
238 init_fields = split_init_fields(fields, field_warnings)
239
240 # Process fields
241 for field in init_fields:
242 try:
243 process_field(init_api_doc, docindex, field.tag(),
244 field.arg(), field.body())
245 except ValueError, e: field_warnings.append(str(e))
246
247 # Process fields
248 for field in fields:
249 try:
250 process_field(api_doc, docindex, field.tag(),
251 field.arg(), field.body())
252 except ValueError, e: field_warnings.append(str(e))
253
254 # Check to make sure that all type parameters correspond to
255 # some documented parameter.
256 check_type_fields(api_doc, field_warnings)
257
258 # Check for special variables (e.g., __version__)
259 if isinstance(api_doc, NamespaceDoc):
260 for field in STANDARD_FIELDS + user_docfields(api_doc, docindex):
261 add_metadata_from_var(api_doc, field)
262
263 # Extract a summary
264 if api_doc.summary is None and api_doc.descr is not None:
265 api_doc.summary, api_doc.other_docs = api_doc.descr.summary()
266
267 # If the summary is empty, but the return field is not, then use
268 # the return field to generate a summary description.
269 if (isinstance(api_doc, RoutineDoc) and api_doc.summary is None and
270 api_doc.return_descr is not None):
271 s, o = api_doc.return_descr.summary()
272 api_doc.summary = RETURN_PDS + s
273 api_doc.other_docs = o
274
275 # [XX] Make sure we don't have types/param descrs for unknown
276 # vars/params?
277
278 # Report any errors that occured
279 if api_doc in suppress_warnings:
280 if parse_errors or field_warnings:
281 log.info("Suppressing docstring warnings for %s, since it "
282 "is not included in the documented set." %
283 api_doc.canonical_name)
284 else:
285 report_errors(api_doc, docindex, parse_errors, field_warnings)
286
288 for varname in field.varnames:
289 # Check if api_doc has a variable w/ the given name.
290 if varname not in api_doc.variables: continue
291
292 # Check moved here from before the for loop because we expect to
293 # reach rarely this point. The loop below is to be performed more than
294 # once only for fields with more than one varname, which currently is
295 # only 'author'.
296 for md in api_doc.metadata:
297 if field == md[0]:
298 return # We already have a value for this metadata.
299
300 var_doc = api_doc.variables[varname]
301 if var_doc.value is UNKNOWN: continue
302 val_doc = var_doc.value
303 value = []
304
305 # Try extracting the value from the pyval.
306 ok_types = (basestring, int, float, bool, type(None))
307 if val_doc.pyval is not UNKNOWN:
308 if isinstance(val_doc.pyval, ok_types):
309 value = [val_doc.pyval]
310 elif field.multivalue:
311 if isinstance(val_doc.pyval, (tuple, list)):
312 for elt in val_doc.pyval:
313 if not isinstance(elt, ok_types): break
314 else:
315 value = list(val_doc.pyval)
316
317 # Try extracting the value from the parse tree.
318 elif val_doc.toktree is not UNKNOWN:
319 try: value = [epydoc.docparser.parse_string(val_doc.toktree)]
320 except KeyboardInterrupt: raise
321 except: pass
322 if field.multivalue and not value:
323 try: value = epydoc.docparser.parse_string_list(val_doc.toktree)
324 except KeyboardInterrupt: raise
325 except: pass
326
327 # Add any values that we found.
328 for elt in value:
329 if isinstance(elt, str):
330 elt = decode_with_backslashreplace(elt)
331 else:
332 elt = unicode(elt)
333 elt = epytext.ParsedEpytextDocstring(
334 epytext.parse_as_para(elt), inline=True)
335
336 # Add in the metadata and remove from the variables
337 api_doc.metadata.append( (field, varname, elt) )
338
339 # Remove the variable itself (unless it's documented)
340 if var_doc.docstring in (None, UNKNOWN):
341 del api_doc.variables[varname]
342 if api_doc.sort_spec is not UNKNOWN:
343 try: api_doc.sort_spec.remove(varname)
344 except ValueError: pass
345
347 """A helper function for L{parse_docstring()} that initializes
348 the attributes that C{parse_docstring()} will write to."""
349 if api_doc.descr is UNKNOWN:
350 api_doc.descr = None
351 if api_doc.summary is UNKNOWN:
352 api_doc.summary = None
353 if api_doc.metadata is UNKNOWN:
354 api_doc.metadata = []
355 if isinstance(api_doc, RoutineDoc):
356 if api_doc.arg_descrs is UNKNOWN:
357 api_doc.arg_descrs = []
358 if api_doc.arg_types is UNKNOWN:
359 api_doc.arg_types = {}
360 if api_doc.return_descr is UNKNOWN:
361 api_doc.return_descr = None
362 if api_doc.return_type is UNKNOWN:
363 api_doc.return_type = None
364 if api_doc.exception_descrs is UNKNOWN:
365 api_doc.exception_descrs = []
366 if isinstance(api_doc, (VariableDoc<