[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.
|