mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
#229: Fix autodoc failures with members that raise errors
on ``getattr()``.
This commit is contained in:
3
CHANGES
3
CHANGES
@@ -1,6 +1,9 @@
|
|||||||
Release 0.6.3 (in development)
|
Release 0.6.3 (in development)
|
||||||
==============================
|
==============================
|
||||||
|
|
||||||
|
* #229: Fix autodoc failures with members that raise errors
|
||||||
|
on ``getattr()``.
|
||||||
|
|
||||||
* #205: When copying files, don't copy full stat info, only
|
* #205: When copying files, don't copy full stat info, only
|
||||||
modification times.
|
modification times.
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ from sphinx.util import rpartition, nested_parse_with_titles, force_decode
|
|||||||
from sphinx.pycode import ModuleAnalyzer, PycodeError
|
from sphinx.pycode import ModuleAnalyzer, PycodeError
|
||||||
from sphinx.application import ExtensionError
|
from sphinx.application import ExtensionError
|
||||||
from sphinx.util.compat import Directive
|
from sphinx.util.compat import Directive
|
||||||
|
from sphinx.util.inspect import isdescriptor, safe_getmembers, safe_getattr
|
||||||
from sphinx.util.docstrings import prepare_docstring
|
from sphinx.util.docstrings import prepare_docstring
|
||||||
|
|
||||||
|
|
||||||
@@ -194,25 +195,6 @@ def between(marker, what=None, keepempty=False):
|
|||||||
return process
|
return process
|
||||||
|
|
||||||
|
|
||||||
def safe_getattr(obj, name, *defargs):
|
|
||||||
try:
|
|
||||||
return getattr(obj, name, *defargs)
|
|
||||||
except Exception:
|
|
||||||
# this is a catch-all for all the weird things that some modules do
|
|
||||||
# with attribute access
|
|
||||||
if defargs:
|
|
||||||
return defargs[0]
|
|
||||||
raise AttributeError
|
|
||||||
|
|
||||||
|
|
||||||
def isdescriptor(x):
|
|
||||||
"""Check if the object is some kind of descriptor."""
|
|
||||||
for item in '__get__', '__set__', '__delete__':
|
|
||||||
if hasattr(safe_getattr(x, item, None), '__call__'):
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
class Documenter(object):
|
class Documenter(object):
|
||||||
"""
|
"""
|
||||||
A Documenter knows how to autodocument a single object type. When
|
A Documenter knows how to autodocument a single object type. When
|
||||||
@@ -486,9 +468,9 @@ class Documenter(object):
|
|||||||
% (mname, self.fullname))
|
% (mname, self.fullname))
|
||||||
return False, ret
|
return False, ret
|
||||||
elif self.options.inherited_members:
|
elif self.options.inherited_members:
|
||||||
# getmembers() uses dir() which pulls in members from all
|
# safe_getmembers() uses dir() which pulls in members from all
|
||||||
# base classes
|
# base classes
|
||||||
return False, inspect.getmembers(self.object)
|
return False, safe_getmembers(self.object)
|
||||||
else:
|
else:
|
||||||
# __dict__ contains only the members directly defined in
|
# __dict__ contains only the members directly defined in
|
||||||
# the class (but get them via getattr anyway, to e.g. get
|
# the class (but get them via getattr anyway, to e.g. get
|
||||||
@@ -728,7 +710,7 @@ class ModuleDocumenter(Documenter):
|
|||||||
if not hasattr(self.object, '__all__'):
|
if not hasattr(self.object, '__all__'):
|
||||||
# for implicit module members, check __module__ to avoid
|
# for implicit module members, check __module__ to avoid
|
||||||
# documenting imported objects
|
# documenting imported objects
|
||||||
return True, inspect.getmembers(self.object)
|
return True, safe_getmembers(self.object)
|
||||||
else:
|
else:
|
||||||
memberlist = self.object.__all__
|
memberlist = self.object.__all__
|
||||||
else:
|
else:
|
||||||
|
|||||||
43
sphinx/util/inspect.py
Normal file
43
sphinx/util/inspect.py
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
sphinx.util.inspect
|
||||||
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Helpers for inspecting Python modules.
|
||||||
|
|
||||||
|
:copyright: Copyright 2007-2009 by the Sphinx team, see AUTHORS.
|
||||||
|
:license: BSD, see LICENSE for details.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def isdescriptor(x):
|
||||||
|
"""Check if the object is some kind of descriptor."""
|
||||||
|
for item in '__get__', '__set__', '__delete__':
|
||||||
|
if hasattr(safe_getattr(x, item, None), '__call__'):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def safe_getattr(obj, name, *defargs):
|
||||||
|
"""A getattr() that turns all exceptions into AttributeErrors."""
|
||||||
|
try:
|
||||||
|
return getattr(obj, name, *defargs)
|
||||||
|
except Exception:
|
||||||
|
# this is a catch-all for all the weird things that some modules do
|
||||||
|
# with attribute access
|
||||||
|
if defargs:
|
||||||
|
return defargs[0]
|
||||||
|
raise AttributeError(name)
|
||||||
|
|
||||||
|
|
||||||
|
def safe_getmembers(object, predicate=None):
|
||||||
|
"""A version of inspect.getmembers() that uses safe_getattr()."""
|
||||||
|
results = []
|
||||||
|
for key in dir(object):
|
||||||
|
try:
|
||||||
|
value = safe_getattr(object, key, None)
|
||||||
|
except AttributeError:
|
||||||
|
continue
|
||||||
|
if not predicate or predicate(value):
|
||||||
|
results.append((key, value))
|
||||||
|
results.sort()
|
||||||
|
return results
|
||||||
Reference in New Issue
Block a user