[Epydoc-commits] SF.net SVN: epydoc: [1390] branches/exp-args_in_class/epydoc/src/epydoc
Brought to you by:
edloper
From: <dva...@us...> - 2006-09-15 01:48:02
|
Revision: 1390 http://svn.sourceforge.net/epydoc/?rev=1390&view=rev Author: dvarrazzo Date: 2006-09-14 18:47:53 -0700 (Thu, 14 Sep 2006) Log Message: ----------- - Checked in a new algorithm to split fields in the class docstring between class documentation and constructor documentation. The algorithm requires the `type` fields to appear after the related fields. - Added more test. Modified Paths: -------------- branches/exp-args_in_class/epydoc/src/epydoc/docstringparser.py branches/exp-args_in_class/epydoc/src/epydoc/test/docbuilder.doctest Modified: branches/exp-args_in_class/epydoc/src/epydoc/docstringparser.py =================================================================== --- branches/exp-args_in_class/epydoc/src/epydoc/docstringparser.py 2006-09-14 21:37:38 UTC (rev 1389) +++ branches/exp-args_in_class/epydoc/src/epydoc/docstringparser.py 2006-09-15 01:47:53 UTC (rev 1390) @@ -205,39 +205,75 @@ descr, fields = parsed_docstring.split_fields(parse_errors) api_doc.descr = descr + field_warnings = [] + # Handle the constructor fields that have been defined in the class # docstring. This code assumes that a class docstring is parsed before # the same class __init__ docstring. if isinstance(api_doc, ClassDoc): - # Put aside param-related fields, which are to be considered as - # __init__ fields. "type" fields are to be used in both contexts. - param_tags = ('arg', 'argument', 'parameter', 'param', - 'kwarg', 'keyword', 'kwparam') + + # Split fields in lists according to their argument + arg_fields = {} + args_order = [] i = 0 while i < len(fields): field = fields[i] - if field.tag() in param_tags: - api_doc.init_args.append(fields.pop(i)) + + # gather together all the fields with the same arg + if field.arg() is not None: + arg_fields.setdefault(field.arg(), []).append(fields.pop(i)) + args_order.append(field.arg()) + else: + i += 1 + + # Now check that for each argument there is at most a single variable + # and a single argument, and a single type for them. + for arg in args_order: + ff = arg_fields.pop(arg, None) + if ff is None: continue - elif field.tag() == 'type': - api_doc.init_args.append(field) - i += 1 + var = tvar = par = tpar = None + for field in ff: + if field.tag() in VAR_TAGS: + if var is None: + var = field + fields.append(field) + else: + field_warnings.append("there are more variables " + "named '%s'" % arg) + elif field.tag() in PARAM_TAGS: + if par is None: + par = field + api_doc.init_args.append(field) + else: + field_warnings.append("there are more parameters " + "named '%s'" % arg) + + elif field.tag() == 'type': + gone = False + if var is not None and tvar is None: + tvar = field + fields.append(field) + gone = True + if par is not None and tpar is None: + tpar = field + api_doc.init_args.append(field) + gone = True + if not gone: + field_warnings.append("type for '%s' doesn't apply " + "to any variable or argument" % arg) + + else: # Unespected field + fields.append(field) + elif (isinstance(api_doc, RoutineDoc) - and api_doc.canonical_name[-1] == '__init__'): - # __init__ can receive arguments descriptions from the class docstring - # if a type is specified in both docstring, __init__ wins. + and api_doc.canonical_name[-1] == '__init__'): class_doc = docindex.get_valdoc(api_doc.canonical_name[:-1]) if class_doc is not None and class_doc.init_args is not UNKNOWN: - init_types = [ field.arg() for field in fields - if field.tag() == 'type' ] - for field in class_doc.init_args: - if field.tag() == 'type' and field.arg() in init_types: - continue - fields.append(field) + fields.extend(class_doc.init_args) # Process fields - field_warnings = [] for field in fields: try: process_field(api_doc, docindex, field.tag(), @@ -671,6 +707,14 @@ register_field_handler(process_raise_field, 'raise', 'raises', 'except', 'exception') +# Tags related to function parameters +PARAM_TAGS = ('arg', 'argument', 'parameter', 'param', + 'kwarg', 'keyword', 'kwparam') + +# Tags related to variables in a class +VAR_TAGS = ('cvar', 'cvariable', + 'ivar', 'ivariable') + ###################################################################### #{ Helper Functions ###################################################################### Modified: branches/exp-args_in_class/epydoc/src/epydoc/test/docbuilder.doctest =================================================================== --- branches/exp-args_in_class/epydoc/src/epydoc/test/docbuilder.doctest 2006-09-14 21:37:38 UTC (rev 1389) +++ branches/exp-args_in_class/epydoc/src/epydoc/test/docbuilder.doctest 2006-09-15 01:47:53 UTC (rev 1390) @@ -14,6 +14,22 @@ >>> import tempfile, re, os, os.path, textwrap, sys >>> from epydoc.docbuilder import build_doc + >>> from epydoc.apidoc import ClassDoc, RoutineDoc + >>> from epydoc.markup import ParsedDocstring + + >>> def to_plain(docstring): + ... """Conver a parsed docstring into plain text""" + ... if isinstance(docstring, ParsedDocstring): + ... docstring = docstring.to_plaintext(None) + ... return docstring.rsplit() + + >>> def fun_to_plain(val_doc): + ... """Convert parsed docstrings in text from a RoutineDoc""" + ... for k, v in val_doc.arg_types.items(): + ... val_doc.arg_types[k] = to_plain(v) + ... for i, (k, v) in enumerate(val_doc.arg_descrs): + ... val_doc.arg_descrs[i] = (k, to_plain(v)) + >>> def runbuilder(s, attribs='', build=None, exclude=''): ... # Write it to a temp file. ... tmp_dir = tempfile.mkdtemp() @@ -24,6 +40,10 @@ ... val_doc = build_doc(os.path.join(tmp_dir, 'epydoc_test.py')) ... if build: val_doc = val_doc.variables[build].value ... # Display it. + ... if isinstance(val_doc, ClassDoc): + ... for val in val_doc.variables.values(): + ... if isinstance(val.value, RoutineDoc): + ... fun_to_plain(val.value) ... s = val_doc.pp(include=attribs.split(),exclude=exclude.split()) ... s = re.sub(r"(filename = ).*", r"\1...", s) ... s = re.sub(r"(<module 'epydoc_test' from ).*", r'\1...', s) @@ -116,11 +136,18 @@ +- descr = u'A property has no defining module' +- type_descr = u'int' +Stuff from future doesn't appear as variable. + >>> runbuilder(s=""" ... from __future__ import division ... from re import match ... """, ... attribs='variables value') + ModuleDoc for epydoc_test [0] + +- variables + +- match => VariableDoc for epydoc_test.match [1] + +- value + +- ValueDoc for sre.match [2] Specifying constructor signature in class docstring @@ -143,7 +170,7 @@ ... """ ... pass ... ''', - ... introspect="Foo", + ... build="Foo", ... attribs="variables name value " ... "posargs vararg kwarg type arg_types arg_descrs") ClassDoc for epydoc_test.Foo [0] @@ -176,7 +203,7 @@ ... @type a: str ... """ ... ''', - ... introspect="Foo", + ... build="Foo", ... attribs="variables name value " ... "posargs vararg kwarg type arg_types arg_descrs") ClassDoc for epydoc_test.Foo [0] @@ -192,6 +219,7 @@ +- vararg = None A missing docstring on the __init__ is not an issue. + >>> runbuilder(s=''' ... class Foo: ... """This is the object docstring @@ -202,7 +230,7 @@ ... def __init__(self): ... pass ... ''', - ... introspect="Foo", + ... build="Foo", ... attribs="variables name value " ... "posargs vararg kwarg type arg_types arg_descrs") ClassDoc for epydoc_test.Foo [0] @@ -232,7 +260,7 @@ ... """__init__ doc""" ... pass ... ''', - ... introspect="Foo", + ... build="Foo", ... attribs="variables name value " ... "posargs vararg kwarg type arg_types arg_descrs docstring") ClassDoc for epydoc_test.Foo [0] @@ -249,3 +277,108 @@ +- kwarg = None +- posargs = [u'x', u'y'] +- vararg = None + +A type can apply to both a param and a variable + + >>> runbuilder(s=''' + ... class Foo: + ... """This is the object docstring + ... + ... @param a: init param. + ... @ivar a: instance var. + ... @type a: date + ... """ + ... def __init__(self, a): + ... pass + ... ''', + ... build="Foo", + ... attribs="variables name value " + ... "posargs vararg kwarg type_descr arg_types arg_descrs") + ClassDoc for epydoc_test.Foo [0] + +- variables + +- __init__ => VariableDoc for epydoc_test.Foo.__init__ [1] + | +- name = '__init__' + | +- type_descr = None + | +- value + | +- RoutineDoc for epydoc_test.Foo.__init__ [2] + | +- arg_descrs = [([u'a'], [u'init', u'param.'])] + | +- arg_types = {u'a': [u'date']} + | +- kwarg = None + | +- posargs = ['self', 'a'] + | +- vararg = None + +- a => VariableDoc for epydoc_test.Foo.a [3] + +- name = u'a' + +- type_descr = u'date\n\n' + +- value = <UNKNOWN> + +But there can also be two different types + + >>> runbuilder(s=''' + ... class Foo: + ... """This is the object docstring + ... + ... @param a: init param. + ... @type a: string + ... @ivar a: instance var. + ... @type a: date + ... """ + ... def __init__(self, a): + ... pass + ... ''', + ... build="Foo", + ... attribs="variables name value " + ... "posargs vararg kwarg type_descr arg_types arg_descrs") + ClassDoc for epydoc_test.Foo [0] + +- variables + +- __init__ => VariableDoc for epydoc_test.Foo.__init__ [1] + | +- name = '__init__' + | +- type_descr = None + | +- value + | +- RoutineDoc for epydoc_test.Foo.__init__ [2] + | +- arg_descrs = [([u'a'], [u'init', u'param.'])] + | +- arg_types = {u'a': [u'string']} + | +- kwarg = None + | +- posargs = ['self', 'a'] + | +- vararg = None + +- a => VariableDoc for epydoc_test.Foo.a [3] + +- name = u'a' + +- type_descr = u'date\n\n' + +- value = <UNKNOWN> + +Also reST consolidated fields are not a problem. + + >>> runbuilder(s=''' + ... __docformat__ = 'restructuredtext' + ... class Foo: + ... """This is the object docstring + ... + ... :Parameters: + ... `a` : string + ... init param. + ... + ... :IVariables: + ... `a` : date + ... instance var. + ... """ + ... def __init__(self, a): + ... pass + ... ''', + ... build="Foo", + ... attribs="variables name value " + ... "posargs vararg kwarg type_descr arg_types arg_descrs") + ClassDoc for epydoc_test.Foo [0] + +- variables + +- __init__ => VariableDoc for epydoc_test.Foo.__init__ [1] + | +- name = '__init__' + | +- type_descr = None + | +- value + | +- RoutineDoc for epydoc_test.Foo.__init__ [2] + | +- arg_descrs = [([u'a'], [u'init', u'param.'])] + | +- arg_types = {u'a': [u'string']} + | +- kwarg = None + | +- posargs = ['self', 'a'] + | +- vararg = None + +- a => VariableDoc for epydoc_test.Foo.a [3] + +- name = u'a' + +- type_descr = u'date' + +- value = <UNKNOWN> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |