summaryrefslogtreecommitdiff
path: root/tests/test_autodoc_py35.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test_autodoc_py35.py')
-rw-r--r--tests/test_autodoc_py35.py346
1 files changed, 346 insertions, 0 deletions
diff --git a/tests/test_autodoc_py35.py b/tests/test_autodoc_py35.py
new file mode 100644
index 000000000..9bacc3d65
--- /dev/null
+++ b/tests/test_autodoc_py35.py
@@ -0,0 +1,346 @@
+# -*- coding: utf-8 -*-
+"""
+ test_autodoc
+ ~~~~~~~~~~~~
+
+ Test the autodoc extension. This tests mainly the Documenters; the auto
+ directives are tested in a test source file translated by test_build.
+
+ :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+# "raises" imported for usage by autodoc
+from util import TestApp, Struct, raises, SkipTest
+from nose.tools import with_setup, eq_
+
+from six import StringIO
+from docutils.statemachine import ViewList
+
+from sphinx.ext.autodoc import AutoDirective, add_documenter, \
+ ModuleLevelDocumenter, FunctionDocumenter, cut_lines, between, ALL
+
+app = None
+
+def setup_module():
+ global app
+ app = TestApp()
+ app.builder.env.app = app
+ app.builder.env.temp_data['docname'] = 'dummy'
+ app.connect('autodoc-process-docstring', process_docstring)
+ app.connect('autodoc-process-signature', process_signature)
+ app.connect('autodoc-skip-member', skip_member)
+
+
+def teardown_module():
+ app.cleanup()
+
+
+directive = options = None
+
+def setup_test():
+ global options, directive
+ global processed_docstrings, processed_signatures, _warnings
+
+ options = Struct(
+ inherited_members = False,
+ undoc_members = False,
+ private_members = False,
+ special_members = False,
+ imported_members = False,
+ show_inheritance = False,
+ noindex = False,
+ annotation = None,
+ synopsis = '',
+ platform = '',
+ deprecated = False,
+ members = [],
+ member_order = 'alphabetic',
+ exclude_members = set(),
+ )
+
+ directive = Struct(
+ env = app.builder.env,
+ genopt = options,
+ result = ViewList(),
+ warn = warnfunc,
+ filename_set = set(),
+ )
+
+ processed_docstrings = []
+ processed_signatures = []
+ _warnings = []
+
+
+_warnings = []
+
+def warnfunc(msg):
+ _warnings.append(msg)
+
+
+processed_docstrings = []
+
+def process_docstring(app, what, name, obj, options, lines):
+ processed_docstrings.append((what, name))
+ if name == 'bar':
+ lines.extend(['42', ''])
+
+processed_signatures = []
+
+def process_signature(app, what, name, obj, options, args, retann):
+ processed_signatures.append((what, name))
+ if name == 'bar':
+ return '42', None
+
+
+def skip_member(app, what, name, obj, skip, options):
+ if name in ('__special1__', '__special2__'):
+ return skip
+ if name.startswith('_'):
+ return True
+ if name == 'skipmeth':
+ return True
+
+
+@with_setup(setup_test)
+def test_generate():
+ def assert_warns(warn_str, objtype, name, **kw):
+ inst = AutoDirective._registry[objtype](directive, name)
+ inst.generate(**kw)
+ assert len(directive.result) == 0, directive.result
+ assert len(_warnings) == 1, _warnings
+ assert warn_str in _warnings[0], _warnings
+ del _warnings[:]
+
+ def assert_works(objtype, name, **kw):
+ inst = AutoDirective._registry[objtype](directive, name)
+ inst.generate(**kw)
+ assert directive.result
+ #print '\n'.join(directive.result)
+ assert len(_warnings) == 0, _warnings
+ del directive.result[:]
+
+ def assert_processes(items, objtype, name, **kw):
+ del processed_docstrings[:]
+ del processed_signatures[:]
+ assert_works(objtype, name, **kw)
+ assert set(processed_docstrings) | set(processed_signatures) == \
+ set(items)
+
+ def assert_result_contains(item, objtype, name, **kw):
+ inst = AutoDirective._registry[objtype](directive, name)
+ inst.generate(**kw)
+ #print '\n'.join(directive.result)
+ assert len(_warnings) == 0, _warnings
+ assert item in directive.result
+ del directive.result[:]
+
+ def assert_order(items, objtype, name, member_order, **kw):
+ inst = AutoDirective._registry[objtype](directive, name)
+ inst.options.member_order = member_order
+ inst.generate(**kw)
+ assert len(_warnings) == 0, _warnings
+ items = list(reversed(items))
+ lineiter = iter(directive.result)
+ #for line in directive.result:
+ # if line.strip():
+ # print repr(line)
+ while items:
+ item = items.pop()
+ for line in lineiter:
+ if line == item:
+ break
+ else: # ran out of items!
+ assert False, 'item %r not found in result or not in the ' \
+ ' correct order' % item
+ del directive.result[:]
+
+ options.members = []
+
+ # no module found?
+ assert_warns("import for autodocumenting 'foobar'",
+ 'function', 'foobar', more_content=None)
+ # importing
+ assert_warns("failed to import module 'test_foobar'",
+ 'module', 'test_foobar', more_content=None)
+ # attributes missing
+ assert_warns("failed to import function 'foobar' from module 'util'",
+ 'function', 'util.foobar', more_content=None)
+ # method missing
+ assert_warns("failed to import method 'Class.foobar' from module 'test_autodoc_py35';",
+ 'method', 'test_autodoc_py35.Class.foobar', more_content=None)
+
+ # test auto and given content mixing
+ directive.env.ref_context['py:module'] = 'test_autodoc_py35'
+ assert_result_contains(' Function.', 'method', 'Class.meth')
+ add_content = ViewList()
+ add_content.append('Content.', '', 0)
+ assert_result_contains(' Function.', 'method',
+ 'Class.meth', more_content=add_content)
+ assert_result_contains(' Content.', 'method',
+ 'Class.meth', more_content=add_content)
+
+ # test check_module
+ inst = FunctionDocumenter(directive, 'raises')
+ inst.generate(check_module=True)
+ assert len(directive.result) == 0
+
+ # assert that exceptions can be documented
+ assert_works('exception', 'test_autodoc_py35.CustomEx', all_members=True)
+ assert_works('exception', 'test_autodoc_py35.CustomEx')
+
+ # test diverse inclusion settings for members
+ should = [('class', 'test_autodoc_py35.Class')]
+ assert_processes(should, 'class', 'Class')
+ should.extend([('method', 'test_autodoc_py35.Class.meth')])
+ options.members = ['meth']
+ options.exclude_members = set(['excludemeth'])
+ assert_processes(should, 'class', 'Class')
+ should.extend([('attribute', 'test_autodoc_py35.Class.prop'),
+ ('attribute', 'test_autodoc_py35.Class.descr'),
+ ('attribute', 'test_autodoc_py35.Class.attr'),
+ ('attribute', 'test_autodoc_py35.Class.docattr'),
+ ('attribute', 'test_autodoc_py35.Class.udocattr'),
+ ('attribute', 'test_autodoc_py35.Class.mdocattr'),
+ ('attribute', 'test_autodoc_py35.Class.inst_attr_comment'),
+ ('attribute', 'test_autodoc_py35.Class.inst_attr_inline'),
+ ('attribute', 'test_autodoc_py35.Class.inst_attr_string'),
+ ('method', 'test_autodoc_py35.Class.moore'),
+ ])
+ if six.PY3 and sys.version_info[:2] >= (3, 5):
+ should.extend([
+ ('method', 'test_autodoc_py35.Class.do_coroutine'),
+ ])
+ options.members = ALL
+ assert_processes(should, 'class', 'Class')
+ options.undoc_members = True
+ should.extend((('attribute', 'test_autodoc_py35.Class.skipattr'),
+ ('method', 'test_autodoc_py35.Class.undocmeth'),
+ ('method', 'test_autodoc_py35.Class.roger')))
+ assert_processes(should, 'class', 'Class')
+ options.inherited_members = True
+ should.append(('method', 'test_autodoc_py35.Class.inheritedmeth'))
+ assert_processes(should, 'class', 'Class')
+
+ # test special members
+ options.special_members = ['__special1__']
+ should.append(('method', 'test_autodoc_py35.Class.__special1__'))
+ assert_processes(should, 'class', 'Class')
+ options.special_members = ALL
+ should.append(('method', 'test_autodoc_py35.Class.__special2__'))
+ assert_processes(should, 'class', 'Class')
+ options.special_members = False
+
+
+# --- generate fodder ------------
+import six, sys
+
+__all__ = ['Class']
+
+#: documentation for the integer
+integer = 1
+
+class CustomEx(Exception):
+ """My custom exception."""
+
+ def f(self):
+ """Exception method."""
+
+class CustomDataDescriptor(object):
+ """Descriptor class docstring."""
+
+ def __init__(self, doc):
+ self.__doc__ = doc
+
+ def __get__(self, obj, type=None):
+ if obj is None:
+ return self
+ return 42
+
+ def meth(self):
+ """Function."""
+ return "The Answer"
+
+def _funky_classmethod(name, b, c, d, docstring=None):
+ """Generates a classmethod for a class from a template by filling out
+ some arguments."""
+ def template(cls, a, b, c, d=4, e=5, f=6):
+ return a, b, c, d, e, f
+ from functools import partial
+ function = partial(template, b=b, c=c, d=d)
+ function.__name__ = name
+ function.__doc__ = docstring
+ return classmethod(function)
+
+class Base(object):
+ def inheritedmeth(self):
+ """Inherited function."""
+
+if six.PY3 and sys.version_info[:2] >= (3, 5):
+
+ async def _other_coro_func():
+ return "run"
+
+
+class Class(Base):
+ """Class to document."""
+
+ descr = CustomDataDescriptor("Descriptor instance docstring.")
+
+ def meth(self):
+ """Function."""
+
+ def undocmeth(self):
+ pass
+
+ def skipmeth(self):
+ """Method that should be skipped."""
+
+ def excludemeth(self):
+ """Method that should be excluded."""
+
+ # should not be documented
+ skipattr = 'foo'
+
+ #: should be documented -- süß
+ attr = 'bar'
+
+ @property
+ def prop(self):
+ """Property."""
+
+ docattr = 'baz'
+ """should likewise be documented -- süß"""
+
+ udocattr = 'quux'
+ u"""should be documented as well - süß"""
+
+ # initialized to any class imported from another module
+ mdocattr = StringIO()
+ """should be documented as well - süß"""
+
+ roger = _funky_classmethod("roger", 2, 3, 4)
+
+ moore = _funky_classmethod("moore", 9, 8, 7,
+ docstring="moore(a, e, f) -> happiness")
+
+ def __init__(self, arg):
+ self.inst_attr_inline = None #: an inline documented instance attr
+ #: a documented instance attribute
+ self.inst_attr_comment = None
+ self.inst_attr_string = None
+ """a documented instance attribute"""
+
+ def __special1__(self):
+ """documented special method"""
+
+ def __special2__(self):
+ # undocumented special method
+ pass
+
+ if six.PY3 and sys.version_info[:2] >= (3, 5):
+
+ async def do_coroutine(self):
+ """A documented coroutine function"""
+
+ attr_coro_result = await _other_coro_func()