summaryrefslogtreecommitdiff
path: root/sphinx/ext/autodoc.py
diff options
context:
space:
mode:
authorGeorg Brandl <georg@python.org>2014-01-19 11:15:24 +0100
committerGeorg Brandl <georg@python.org>2014-01-19 11:15:24 +0100
commit6a5de08f929ef4dc58f68122dea364af4ed212e5 (patch)
treefc43faa61088ceb82e3a7e8025240d8c685111b1 /sphinx/ext/autodoc.py
parentd413fd5731de449c1f69a6c8f4898fd7645fd494 (diff)
parent88a6b565ac65a33f2798b8cbc504eb147b9a9d87 (diff)
downloadsphinx-6a5de08f929ef4dc58f68122dea364af4ed212e5.tar.gz
Merged in saschpe/sphinx (pull request #193)
BuildDoc shouldn't fail on Unicode paths.
Diffstat (limited to 'sphinx/ext/autodoc.py')
-rw-r--r--sphinx/ext/autodoc.py84
1 files changed, 71 insertions, 13 deletions
diff --git a/sphinx/ext/autodoc.py b/sphinx/ext/autodoc.py
index 348c072c..86837ff8 100644
--- a/sphinx/ext/autodoc.py
+++ b/sphinx/ext/autodoc.py
@@ -28,8 +28,8 @@ from sphinx.application import ExtensionError
from sphinx.util.nodes import nested_parse_with_titles
from sphinx.util.compat import Directive
from sphinx.util.inspect import getargspec, isdescriptor, safe_getmembers, \
- safe_getattr, safe_repr
-from sphinx.util.pycompat import base_exception, class_types
+ safe_getattr, safe_repr, is_builtin_class_method
+from sphinx.util.pycompat import class_types
from sphinx.util.docstrings import prepare_docstring
@@ -70,6 +70,35 @@ class Options(dict):
return None
+class _MockModule(object):
+ """Used by autodoc_mock_imports."""
+ def __init__(self, *args, **kwargs):
+ pass
+
+ def __call__(self, *args, **kwargs):
+ return _MockModule()
+
+ @classmethod
+ def __getattr__(cls, name):
+ if name in ('__file__', '__path__'):
+ return '/dev/null'
+ elif name[0] == name[0].upper():
+ # Not very good, we assume Uppercase names are classes...
+ mocktype = type(name, (), {})
+ mocktype.__module__ = __name__
+ return mocktype
+ else:
+ return _MockModule()
+
+def mock_import(modname):
+ if '.' in modname:
+ pkg, _n, mods = modname.rpartition('.')
+ mock_import(pkg)
+ mod = _MockModule()
+ sys.modules[modname] = mod
+ return mod
+
+
ALL = object()
INSTANCEATTR = object()
@@ -332,6 +361,9 @@ class Documenter(object):
self.modname, '.'.join(self.objpath))
try:
dbg('[autodoc] import %s', self.modname)
+ for modname in self.env.config.autodoc_mock_imports:
+ dbg('[autodoc] adding a mock module %s!', self.modname)
+ mock_import(modname)
__import__(self.modname)
parent = None
obj = self.module = sys.modules[self.modname]
@@ -450,9 +482,10 @@ class Documenter(object):
# into lines
if isinstance(docstring, unicode):
return [prepare_docstring(docstring, ignore)]
- elif docstring:
+ elif isinstance(docstring, str): # this will not trigger on Py3
return [prepare_docstring(force_decode(docstring, encoding),
ignore)]
+ # ... else it is something strange, let's ignore it
return []
def process_doc(self, docstrings):
@@ -957,6 +990,10 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter):
try:
argspec = getargspec(self.object)
except TypeError:
+ if (is_builtin_class_method(self.object, '__new__') and
+ is_builtin_class_method(self.object, '__init__')):
+ raise TypeError('%r is a builtin class' % self.object)
+
# if a class should be documented as function (yay duck
# typing) we try to use the constructor signature as function
# signature without the first argument.
@@ -1009,8 +1046,9 @@ class ClassDocumenter(ModuleLevelDocumenter):
initmeth = self.get_attr(self.object, '__init__', None)
# classes without __init__ method, default __init__ or
# __init__ written in C?
- if initmeth is None or initmeth is object.__init__ or not \
- (inspect.ismethod(initmeth) or inspect.isfunction(initmeth)):
+ if initmeth is None or \
+ is_builtin_class_method(self.object, '__init__') or \
+ not(inspect.ismethod(initmeth) or inspect.isfunction(initmeth)):
return None
try:
argspec = getargspec(initmeth)
@@ -1047,7 +1085,7 @@ class ClassDocumenter(ModuleLevelDocumenter):
# add inheritance info, if wanted
if not self.doc_as_attr and self.options.show_inheritance:
self.add_line(u'', '<autodoc>')
- if len(self.object.__bases__):
+ if hasattr(self.object, '__bases__') and len(self.object.__bases__):
bases = [b.__module__ == '__builtin__' and
u':class:`%s`' % b.__name__ or
u':class:`%s.%s`' % (b.__module__, b.__name__)
@@ -1066,10 +1104,21 @@ class ClassDocumenter(ModuleLevelDocumenter):
# for classes, what the "docstring" is can be controlled via a
# config value; the default is only the class docstring
if content in ('both', 'init'):
- initdocstring = self.get_attr(
- self.get_attr(self.object, '__init__', None), '__doc__')
+ # get __init__ method document from __init__.__doc__
+ if self.env.config.autodoc_docstring_signature:
+ # only act if the feature is enabled
+ init_doc = MethodDocumenter(self.directive, '__init__')
+ init_doc.object = self.get_attr(self.object, '__init__', None)
+ init_doc.objpath = ['__init__']
+ init_doc._find_signature() # this effects to get_doc() result
+ initdocstring = '\n'.join(
+ ['\n'.join(l) for l in init_doc.get_doc(encoding)])
+ else:
+ initdocstring = self.get_attr(
+ self.get_attr(self.object, '__init__', None), '__doc__')
# for new-style classes, no __init__ means default __init__
- if initdocstring == object.__init__.__doc__:
+ if (initdocstring == object.__init__.__doc__ or # for pypy
+ initdocstring.strip() == object.__init__.__doc__): #for !pypy
initdocstring = None
if initdocstring:
if content == 'init':
@@ -1113,7 +1162,7 @@ class ExceptionDocumenter(ClassDocumenter):
@classmethod
def can_document_member(cls, member, membername, isattr, parent):
return isinstance(member, class_types) and \
- issubclass(member, base_exception)
+ issubclass(member, BaseException)
class DataDocumenter(ModuleLevelDocumenter):
@@ -1228,7 +1277,8 @@ class AttributeDocumenter(ClassLevelDocumenter):
def can_document_member(cls, member, membername, isattr, parent):
isdatadesc = isdescriptor(member) and not \
isinstance(member, cls.method_types) and not \
- type(member).__name__ in ("type", "method_descriptor")
+ type(member).__name__ in ("type", "method_descriptor",
+ "instancemethod")
return isdatadesc or (not isinstance(parent, ModuleDocumenter)
and not inspect.isroutine(member)
and not isinstance(member, class_types))
@@ -1368,8 +1418,15 @@ class AutoDirective(Directive):
not negated:
self.options[flag] = None
# process the options with the selected documenter's option_spec
- self.genopt = Options(assemble_option_dict(
- self.options.items(), doc_class.option_spec))
+ try:
+ self.genopt = Options(assemble_option_dict(
+ self.options.items(), doc_class.option_spec))
+ except (KeyError, ValueError, TypeError), err:
+ # an option is either unknown or has a wrong type
+ msg = self.reporter.error('An option to %s is either unknown or '
+ 'has an invalid value: %s' % (self.name, err),
+ line=self.lineno)
+ return [msg]
# generate the output
documenter = doc_class(self, self.arguments[0])
documenter.generate(more_content=self.content)
@@ -1428,6 +1485,7 @@ def setup(app):
app.add_config_value('autodoc_member_order', 'alphabetic', True)
app.add_config_value('autodoc_default_flags', [], True)
app.add_config_value('autodoc_docstring_signature', True, True)
+ app.add_config_value('autodoc_mock_imports', [], True)
app.add_event('autodoc-process-docstring')
app.add_event('autodoc-process-signature')
app.add_event('autodoc-skip-member')