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 build argument gives the name of a variable in the module whose documentation should be built, instead of bilding docs for the whole module.
>>> from epydoc.test.util import runbuilder>>> from epydoc.test.util import print_warnings >>> print_warnings()
The docstrings format can be selected using the __docformat__ module variable. In the second example below, where docformat='plaintext', the string "@ivar x: ..." will not be treated as a field, since the docstring format is plaintext.
>>> runbuilder(s=''' ... __docformat__ = 'epytext' ... class Foo: ... """@ivar x: description...""" ... ''', ... build='Foo', attribs='descr variables') ClassDoc for epydoc_test.Foo [0] +- descr = None +- variables +- x => VariableDoc for epydoc_test.Foo.x [1] +- descr = u'description...\n\n'>>> runbuilder(s=''' ... __docformat__ = 'plaintext' ... class Foo: ... """@var x: description...""" ... ''', ... build='Foo', attribs='descr variables') ClassDoc for epydoc_test.Foo [0] +- descr = u'@var x: description...\n' +- variables = {}
Stuff from future doesn't appear as variable.
>>> runbuilder(s=""" ... from __future__ import division ... from pickle import dump ... """, ... attribs='variables value') ModuleDoc for epydoc_test [0] +- variables +- dump => VariableDoc for epydoc_test.dump [1] +- value +- ValueDoc for pickle.dump [2]
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.""" ... ''', ... build="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.""" ... ''', ... build="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, a): ... pass ... ''', ... build="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
Exceptions can be put in the docstring class, and they are assigned to the constructor too.
>>> runbuilder(s=''' ... class Foo: ... """Foo(x, y) ... ... A class to ship rockets in outer space. ... ... @param x: first param ... @param y: second param ... @except ValueError: frobnication error ... """ ... def __init__(self, a, b): ... """__init__ doc""" ... pass ... ''', ... build="Foo", ... attribs="variables name value exception_descrs " ... "posargs vararg kwarg type arg_types arg_descrs docstring") ClassDoc for epydoc_test.Foo [0] +- docstring = u'A class to ship rockets in outer sp... +- 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'], u'first param'), ([u'y'], u... +- arg_types = {} +- docstring = u'__init__ doc' +- exception_descrs = [(DottedName(u'ValueError'), <epydoc.... +- kwarg = None +- posargs = [u'x', u'y'] +- 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 ... ''', ... build="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
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 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 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>
Currently, many variable reprs use the introspected form where it would really be better to use the parsed version. See SF bug #1653577. We intend to improve on this. This test documents the current behavior; but should be replaced when we change the behavior.
>>> from epydoc.test.util import buildvaluedoc >>> from epydoc.compat import * >>> def print_py_reprs(s): ... value_doc = buildvaluedoc(s) ... print 'Var Score Repr\n'+'-'*50 ... for (name, var_doc) in sorted(value_doc.variables.items()): ... if len(name) > 1: continue ... var_repr = var_doc.value.pyval_repr() ... print " %s %4s %r" % (name, var_repr.score, ... var_repr.to_plaintext(None))>>> print_py_reprs(''' ... import re ... class Foo: pass ... class Bar: ... def __repr__(self): return "<specialized repr>" ... class Baz: ... def __repr__(self): raise ValueError() ... a = Foo() # pyval score < 0; use parse repr. ... b = Bar() # pyval score > 0; use pyval repr. ... c = Baz() # pyval score < 0; use parse repr. ... d = [1, 2, 3] # pyval score > 0; use pyval repr. ... d.append(99) ... e = 3+5 # pyval score > 0; use pyval repr. ... f = re.compile('hi+') # pyval score > 0; use pyval repr. ... globals()['h'] = Baz() # pyval score < 0; can't be parsed. ... i = [Foo(), 1, 2] # pyval score < 0; use parse repr. ... j = [Foo(), 1, 2, 3] # pyval score = 0; use pyval repr. ... ''') Var Score Repr -------------------------------------------------- a 0 u'Foo()' b 1 u'<specialized repr>' c 0 u'Baz()' d 5 u'[1, 2, 3, 99]' e 1 u'8' f 1 u"re.compile(r'hi+')" h -99 u'??' i 0 u'[Foo(), 1, 2]' j 0 u'[<epydoc_test.Foo instance at ...>, 1, 2, 3]'
When we do both parsing & introspection, and merge the result, we should trust the introspected APIDoc's is_imported value more than the parsed APIDoc. In particular, in the following example, x should have is_imported=True. But if we can't tell from introspection, then use parse info -- so y should be imported, but z should not.
>>> import epydoc.docintrospecter >>> epydoc.docintrospecter.clear_cache() >>> runbuilder(s=''' ... import cStringIO ... from re import MULTILINE as y ... x = cStringIO ... z = y ... ''', attribs=("variables is_imported ")) ModuleDoc for epydoc_test [0] +- variables +- cStringIO => VariableDoc for epydoc_test.cStringIO [1] | +- is_imported = True +- x => VariableDoc for epydoc_test.x [2] | +- is_imported = True +- y => VariableDoc for epydoc_test.y [3] | +- is_imported = True +- z => VariableDoc for epydoc_test.z [4] +- is_imported = False
Test for the SF bug #1678046. Check that, in case of mismatch between parsed and introspected versions of a value, other values don't get damaged.
>>> runbuilder(s=''' ... foo = None ... bar = None ... ... def mangle(): ... global foo ... foo = 'foo' ... ... mangle() ... ''', ... build="bar", ... attribs="pyval") GenericValueDoc [0] +- pyval = None
Home | Installing Epydoc | Using Epydoc | Epytext |