[Epydoc-commits] SF.net SVN: epydoc: [1374] branches/exp-args_in_class/epydoc/src/epydoc
Brought to you by:
edloper
From: <dva...@us...> - 2006-09-08 15:40:22
|
Revision: 1374 http://svn.sourceforge.net/epydoc/?rev=1374&view=rev Author: dvarrazzo Date: 2006-09-08 08:40:13 -0700 (Fri, 08 Sep 2006) Log Message: ----------- - __init__ signature can be described in the class docstring also when there is no __init__.__doc__ at all. - parse_function_signature() can receive two arguments: one whose docstring is to be parsed and one to be populated. So the constructor signature can be parsed from the class docstring. - Dropped generation of variables when there is a type w/o matching var. The issue is still to be defined consistently anyway. Modified Paths: -------------- branches/exp-args_in_class/epydoc/src/epydoc/docstringparser.py Added Paths: ----------- 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-08 10:38:55 UTC (rev 1373) +++ branches/exp-args_in_class/epydoc/src/epydoc/docstringparser.py 2006-09-08 15:40:13 UTC (rev 1374) @@ -174,8 +174,12 @@ initialize_api_doc(api_doc) # If there's no docstring, then there's nothing more to do. + # ...except in a case: an __init__ function that is to receive some + # documentation from the class docstring if (api_doc.docstring in (None, UNKNOWN)): - return + if not (isinstance(api_doc, RoutineDoc) + and api_doc.canonical_name[-1] == '__init__'): + return # Remove leading indentation from the docstring. api_doc.docstring = unindent_docstring(api_doc.docstring) @@ -184,6 +188,10 @@ # overrides any signature we got via introspection/parsing. if isinstance(api_doc, RoutineDoc): parse_function_signature(api_doc) + elif isinstance(api_doc, ClassDoc): + initvar = api_doc.variables.get('__init__') + if initvar: + parse_function_signature(initvar.value, api_doc) # Parse the docstring. Any errors encountered are stored as # `ParseError` objects in the errors list. @@ -694,9 +702,16 @@ def set_var_type(api_doc, ident, descr): if ident not in api_doc.variables: - api_doc.variables[ident] = VariableDoc( - container=api_doc, name=ident, - canonical_name=api_doc.canonical_name+ident) + # [xx] If there is a type w/o matching var, this would create + # a new var. The behavior is to be decied consistently also in other + # places in this sources (grep for [xx]). + # Currently disable the creation or else each "type" used in the + # class docstring to describe an __init__ parameter also generates + # an extra class variable. + #api_doc.variables[ident] = VariableDoc( + #container=api_doc, name=ident, + #canonical_name=api_doc.canonical_name+ident) + return var_doc = api_doc.variables[ident] if var_doc.type_descr not in (None, UNKNOWN): @@ -740,7 +755,7 @@ # [xx] copied from inspect.getdoc(); we can't use inspect.getdoc() # itself, since it expects an object, not a string. - if docstring == '': return '' + if not docstring: return '' lines = docstring.expandtabs().split('\n') # Find minimum indentation of any non-blank lines after first line. @@ -823,7 +838,7 @@ """A regular expression that is used to extract signatures from docstrings.""" -def parse_function_signature(func_doc): +def parse_function_signature(func_doc, doc_source=None): """ Construct the signature for a builtin function or method from its docstring. If the docstring uses the standard convention @@ -833,15 +848,26 @@ Otherwise, the signature will be set to a single varargs variable named C{"..."}. + @param func_doc: The target object where to store parsed signature. Also + container of the docstring to parse if doc_source is C{None} + @type L{RoutineDoc} + @param doc_source: Contains the docstring to parse. If C{None}, parse + L{func_doc} docstring instead + @type L{APIDoc} @rtype: C{None} """ + if doc_source is None: + doc_source = func_doc + # If there's no docstring, then don't do anything. - if not func_doc.docstring: return False + if not doc_source.docstring: return False - m = _SIGNATURE_RE.match(func_doc.docstring) + m = _SIGNATURE_RE.match(doc_source.docstring) if m is None: return False # Do I want to be this strict? + # Notice that __init__ must match the class name instead, if the signature + # comes from the class docstring # if not (m.group('func') == func_doc.canonical_name[-1] or # '_'+m.group('func') == func_doc.canonical_name[-1]): # log.warning("Not extracting function signature from %s's " @@ -900,7 +926,7 @@ func_doc.posarg_defaults.insert(0, None) # Remove the signature from the docstring. - func_doc.docstring = func_doc.docstring[m.end():] + doc_source.docstring = doc_source.docstring[m.end():] # We found a signature. return True Added: branches/exp-args_in_class/epydoc/src/epydoc/test/docbuilder.doctest =================================================================== --- branches/exp-args_in_class/epydoc/src/epydoc/test/docbuilder.doctest (rev 0) +++ branches/exp-args_in_class/epydoc/src/epydoc/test/docbuilder.doctest 2006-09-08 15:40:13 UTC (rev 1374) @@ -0,0 +1,171 @@ +Regression Testing for epydoc.docbuilder +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Test Function +============= +This test function takes a string containing the contents of a module. +It writes the string contents to a file, imports the file as a module, +and uses build_doc to build documentation, and pretty prints the resulting +ModuleDoc object. The `attribs` argument specifies which attributes +of the `APIDoc`s should be displayed. The `introspect` argument gives the +name of a variable in the module whose value should be introspected, +instead of introspecting the whole module. + + >>> import tempfile, re, os, os.path, textwrap, sys + >>> from epydoc.docbuilder import build_doc + >>> def runbuilder(s, attribs='', introspect=None, exclude=''): + ... # Write it to a temp file. + ... tmp_dir = tempfile.mkdtemp() + ... out = open(os.path.join(tmp_dir, 'epydoc_test.py'), 'w') + ... out.write(textwrap.dedent(s)) + ... out.close() + ... # Import it. + ... sys.path.insert(0, tmp_dir) + ... if introspect is None: + ... import epydoc_test as val + ... else: + ... exec("from epydoc_test import %s as val" % introspect) + ... del sys.path[0] + ... # Introspect it. + ... val_doc = build_doc(val) + ... # Display it. + ... 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) + ... s = re.sub(r"(<function \w+ at )0x\w+>", r"\1...>", s) + ... s = re.sub(r"(<\w+ object at )0x\w+>", r"\1...>", s) + ... print s + ... # Clean up. + ... os.unlink(os.path.join(tmp_dir, 'epydoc_test.py')) + ... try: os.unlink(os.path.join(tmp_dir, 'epydoc_test.pyc')) + ... except OSError: pass + ... os.rmdir(tmp_dir) + ... del sys.modules['epydoc_test'] + + +Specifying constructor signature in class docstring +=================================================== + +The class signature can be specified in the class docstring instead of __init__ + + >>> runbuilder(s=''' + ... class Foo: + ... """This is the object docstring + ... + ... @param a: init param. + ... @ivar a: instance var. + ... @type a: date + ... """ + ... def __init__(self, a): + ... """The ctor docstring. + ... + ... @type a: str + ... """ + ... pass + ... ''', + ... introspect="Foo", + ... attribs="variables name value " + ... "posargs vararg kwarg type arg_types arg_descrs") + ClassDoc for epydoc_test.Foo [0] + +- variables + +- __init__ => VariableDoc for epydoc_test.Foo.__init__ [1] + | +- name = '__init__' + | +- value + | +- RoutineDoc for epydoc_test.Foo.__init__ [2] + | +- arg_descrs = [([u'a'], ... + | +- arg_types = {u'a': ... + | +- kwarg = None + | +- posargs = ['self', 'a'] + | +- vararg = None + +- a => VariableDoc for epydoc_test.Foo.a [3] + +- name = u'a' + +- value = <UNKNOWN> + +Also keywords arguments can be put in the constructor + + >>> runbuilder(s=''' + ... class Foo: + ... """This is the object docstring + ... + ... @keyword a: a kwarg. + ... @type a: str + ... """ + ... def __init__(self, **kwargs): + ... """The ctor docstring. + ... + ... @type a: str + ... """ + ... ''', + ... introspect="Foo", + ... attribs="variables name value " + ... "posargs vararg kwarg type arg_types arg_descrs") + ClassDoc for epydoc_test.Foo [0] + +- variables + +- __init__ => VariableDoc for epydoc_test.Foo.__init__ [1] + +- name = '__init__' + +- value + +- RoutineDoc for epydoc_test.Foo.__init__ [2] + +- arg_descrs = [([u'a'], ... + +- arg_types = {u'a': ... + +- kwarg = 'kwargs' + +- posargs = ['self'] + +- vararg = None + +A missing docstring on the __init__ is not an issue. + >>> runbuilder(s=''' + ... class Foo: + ... """This is the object docstring + ... + ... @param a: a param. + ... @type a: str + ... """ + ... def __init__(self): + ... pass + ... ''', + ... introspect="Foo", + ... attribs="variables name value " + ... "posargs vararg kwarg type arg_types arg_descrs") + ClassDoc for epydoc_test.Foo [0] + +- variables + +- __init__ => VariableDoc for epydoc_test.Foo.__init__ [1] + +- name = '__init__' + +- value + +- RoutineDoc for epydoc_test.Foo.__init__ [2] + +- arg_descrs = [([u'a'], ... + +- arg_types = {u'a': ... + +- kwarg = None + +- posargs = ['self'] + +- vararg = None + +Epydoc can also grok the constructor signature from the class docstring + + >>> runbuilder(s=''' + ... class Foo: + ... """Foo(x, y) + ... + ... A class to ship rockets in outer space. + ... + ... @param x: first param + ... @param y: second param + ... """ + ... def __init__(self, a, b): + ... """__init__ doc""" + ... pass + ... ''', + ... introspect="Foo", + ... attribs="variables name value " + ... "posargs vararg kwarg type arg_types arg_descrs docstring") + ClassDoc for epydoc_test.Foo [0] + +- docstring = u'A class to ship rockets ... + +- variables + +- __init__ => VariableDoc for epydoc_test.Foo.__init__ [1] + +- docstring = <UNKNOWN> + +- name = '__init__' + +- value + +- RoutineDoc for epydoc_test.Foo.__init__ [2] + +- arg_descrs = [([u'x'], ... + +- arg_types = {} + +- docstring = u'__init__ doc' + +- kwarg = None + +- posargs = [u'x', u'y'] + +- vararg = None This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |