diff options
author | Takeshi KOMIYA <i.tkomiya@gmail.com> | 2018-01-08 20:19:36 +0900 |
---|---|---|
committer | Takeshi KOMIYA <i.tkomiya@gmail.com> | 2018-01-08 20:19:36 +0900 |
commit | 326d7e64cedb5280a9cf51a90c00266e1dab9e7b (patch) | |
tree | 0ce4e7845e09aa822da027fbe6401174458c47d9 /sphinx/ext/autodoc/importer.py | |
parent | 7a194f52960fe5ace04ef7daa72563e6d3bf094f (diff) | |
parent | 3965b1f023bbac932d0dfbf414386f0667ec002a (diff) | |
download | sphinx-git-326d7e64cedb5280a9cf51a90c00266e1dab9e7b.tar.gz |
Merge branch 'master' into dont_emit_system_message_on_autodoc_warning
Diffstat (limited to 'sphinx/ext/autodoc/importer.py')
-rw-r--r-- | sphinx/ext/autodoc/importer.py | 91 |
1 files changed, 89 insertions, 2 deletions
diff --git a/sphinx/ext/autodoc/importer.py b/sphinx/ext/autodoc/importer.py index 5c28f490d..101cb930f 100644 --- a/sphinx/ext/autodoc/importer.py +++ b/sphinx/ext/autodoc/importer.py @@ -5,7 +5,7 @@ Importer utilities for autodoc - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -13,13 +13,17 @@ import sys import warnings import traceback import contextlib +from collections import namedtuple from types import FunctionType, MethodType, ModuleType +from six import PY2 + from sphinx.util import logging +from sphinx.util.inspect import isenumclass, safe_getattr if False: # For type annotation - from typing import Any, Generator, List, Set # NOQA + from typing import Any, Callable, Dict, Generator, List, Optional, Set # NOQA logger = logging.getLogger(__name__) @@ -144,3 +148,86 @@ def import_module(modname, warningiserror=False): # Importing modules may cause any side effects, including # SystemExit, so we need to catch all errors. raise ImportError(exc, traceback.format_exc()) + + +def import_object(modname, objpath, objtype='', attrgetter=safe_getattr, warningiserror=False): + # type: (str, List[unicode], str, Callable[[Any, unicode], Any], bool) -> Any + if objpath: + logger.debug('[autodoc] from %s import %s', modname, '.'.join(objpath)) + else: + logger.debug('[autodoc] import %s', modname) + + try: + module = import_module(modname, warningiserror=warningiserror) + logger.debug('[autodoc] => %r', module) + obj = module + parent = None + object_name = None + for attrname in objpath: + parent = obj + logger.debug('[autodoc] getattr(_, %r)', attrname) + obj = attrgetter(obj, attrname) + logger.debug('[autodoc] => %r', obj) + object_name = attrname + return [module, parent, object_name, obj] + except (AttributeError, ImportError) as exc: + if objpath: + errmsg = ('autodoc: failed to import %s %r from module %r' % + (objtype, '.'.join(objpath), modname)) + else: + errmsg = 'autodoc: failed to import %s %r' % (objtype, modname) + + if isinstance(exc, ImportError): + # import_module() raises ImportError having real exception obj and + # traceback + real_exc, traceback_msg = exc.args + if isinstance(real_exc, SystemExit): + errmsg += ('; the module executes module level statement ' + 'and it might call sys.exit().') + elif isinstance(real_exc, ImportError): + errmsg += '; the following exception was raised:\n%s' % real_exc.args[0] + else: + errmsg += '; the following exception was raised:\n%s' % traceback_msg + else: + errmsg += '; the following exception was raised:\n%s' % traceback.format_exc() + + if PY2: + errmsg = errmsg.decode('utf-8') # type: ignore + logger.debug(errmsg) + raise ImportError(errmsg) + + +Attribute = namedtuple('Attribute', ['name', 'directly_defined', 'value']) + + +def get_object_members(subject, objpath, attrgetter, analyzer=None): + # type: (Any, List[unicode], Callable, Any) -> Dict[str, Attribute] # NOQA + """Get members and attributes of target object.""" + # the members directly defined in the class + obj_dict = attrgetter(subject, '__dict__', {}) + + # Py34 doesn't have enum members in __dict__. + if sys.version_info[:2] == (3, 4) and isenumclass(subject): + obj_dict = dict(obj_dict) + for name, value in subject.__members__.items(): + obj_dict[name] = value + + members = {} + for name in dir(subject): + try: + value = attrgetter(subject, name) + directly_defined = name in obj_dict + members[name] = Attribute(name, directly_defined, value) + except AttributeError: + continue + + if analyzer: + # append instance attributes (cf. self.attr1) if analyzer knows + from sphinx.ext.autodoc import INSTANCEATTR + + namespace = '.'.join(objpath) + for (ns, name) in analyzer.find_attr_docs(): + if namespace == ns and name not in members: + members[name] = Attribute(name, True, INSTANCEATTR) + + return members |