refactor: Add `Documenter.config` as a shortcut to access the config object

This commit is contained in:
Takeshi KOMIYA 2020-11-09 02:47:22 +09:00
parent 7db3633778
commit 51da043791
3 changed files with 42 additions and 39 deletions

View File

@ -21,6 +21,7 @@ Features added
* #8119: autodoc: Allow to determine whether a member not included in * #8119: autodoc: Allow to determine whether a member not included in
``__all__`` attribute of the module should be documented or not via ``__all__`` attribute of the module should be documented or not via
:event:`autodoc-skip-member` event :event:`autodoc-skip-member` event
* autodoc: Add ``Documenter.config`` as a shortcut to access the config object
* #6914: Add a new event :event:`warn-missing-reference` to custom warning * #6914: Add a new event :event:`warn-missing-reference` to custom warning
messages when failed to resolve a cross-reference messages when failed to resolve a cross-reference
* #6914: Emit a detailed warning when failed to resolve a ``:ref:`` reference * #6914: Emit a detailed warning when failed to resolve a ``:ref:`` reference

View File

@ -325,6 +325,7 @@ class Documenter:
def __init__(self, directive: "DocumenterBridge", name: str, indent: str = '') -> None: def __init__(self, directive: "DocumenterBridge", name: str, indent: str = '') -> None:
self.directive = directive self.directive = directive
self.config = directive.env.config
self.env = directive.env # type: BuildEnvironment self.env = directive.env # type: BuildEnvironment
self.options = directive.genopt self.options = directive.genopt
self.name = name self.name = name
@ -395,7 +396,7 @@ class Documenter:
modname = None modname = None
parents = [] parents = []
with mock(self.env.config.autodoc_mock_imports): with mock(self.config.autodoc_mock_imports):
self.modname, self.objpath = self.resolve_name(modname, parents, path, base) self.modname, self.objpath = self.resolve_name(modname, parents, path, base)
if not self.modname: if not self.modname:
@ -413,11 +414,11 @@ class Documenter:
Returns True if successful, False if an error occurred. Returns True if successful, False if an error occurred.
""" """
with mock(self.env.config.autodoc_mock_imports): with mock(self.config.autodoc_mock_imports):
try: try:
ret = import_object(self.modname, self.objpath, self.objtype, ret = import_object(self.modname, self.objpath, self.objtype,
attrgetter=self.get_attr, attrgetter=self.get_attr,
warningiserror=self.env.config.autodoc_warningiserror) warningiserror=self.config.autodoc_warningiserror)
self.module, self.parent, self.object_name, self.object = ret self.module, self.parent, self.object_name, self.object = ret
return True return True
except ImportError as exc: except ImportError as exc:
@ -545,8 +546,7 @@ class Documenter:
warnings.warn("The 'ignore' argument to autodoc.%s.get_doc() is deprecated." warnings.warn("The 'ignore' argument to autodoc.%s.get_doc() is deprecated."
% self.__class__.__name__, % self.__class__.__name__,
RemovedInSphinx50Warning, stacklevel=2) RemovedInSphinx50Warning, stacklevel=2)
docstring = getdoc(self.object, self.get_attr, docstring = getdoc(self.object, self.get_attr, self.config.autodoc_inherit_docstrings,
self.env.config.autodoc_inherit_docstrings,
self.parent, self.object_name) self.parent, self.object_name)
if docstring: if docstring:
tab_width = self.directive.state.document.settings.tab_width tab_width = self.directive.state.document.settings.tab_width
@ -688,7 +688,7 @@ class Documenter:
else: else:
isattr = False isattr = False
doc = getdoc(member, self.get_attr, self.env.config.autodoc_inherit_docstrings, doc = getdoc(member, self.get_attr, self.config.autodoc_inherit_docstrings,
self.parent, self.object_name) self.parent, self.object_name)
if not isinstance(doc, str): if not isinstance(doc, str):
# Ignore non-string __doc__ # Ignore non-string __doc__
@ -816,7 +816,7 @@ class Documenter:
documenter = classes[-1](self.directive, full_mname, self.indent) documenter = classes[-1](self.directive, full_mname, self.indent)
memberdocumenters.append((documenter, isattr)) memberdocumenters.append((documenter, isattr))
member_order = self.options.member_order or self.env.config.autodoc_member_order member_order = self.options.member_order or self.config.autodoc_member_order
memberdocumenters = self.sort_members(memberdocumenters, member_order) memberdocumenters = self.sort_members(memberdocumenters, member_order)
for documenter, isattr in memberdocumenters: for documenter, isattr in memberdocumenters:
@ -1209,7 +1209,7 @@ class DocstringSignatureMixin:
return super().get_doc(None, ignore) # type: ignore return super().get_doc(None, ignore) # type: ignore
def format_signature(self, **kwargs: Any) -> str: def format_signature(self, **kwargs: Any) -> str:
if self.args is None and self.env.config.autodoc_docstring_signature: # type: ignore if self.args is None and self.config.autodoc_docstring_signature: # type: ignore
# only act if a signature is not explicitly given already, and if # only act if a signature is not explicitly given already, and if
# the feature is enabled # the feature is enabled
result = self._find_signature() result = self._find_signature()
@ -1228,7 +1228,7 @@ class DocstringStripSignatureMixin(DocstringSignatureMixin):
feature of stripping any function signature from the docstring. feature of stripping any function signature from the docstring.
""" """
def format_signature(self, **kwargs: Any) -> str: def format_signature(self, **kwargs: Any) -> str:
if self.args is None and self.env.config.autodoc_docstring_signature: # type: ignore if self.args is None and self.config.autodoc_docstring_signature: # type: ignore
# only act if a signature is not explicitly given already, and if # only act if a signature is not explicitly given already, and if
# the feature is enabled # the feature is enabled
result = self._find_signature() result = self._find_signature()
@ -1255,13 +1255,12 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ
(inspect.isroutine(member) and isinstance(parent, ModuleDocumenter))) (inspect.isroutine(member) and isinstance(parent, ModuleDocumenter)))
def format_args(self, **kwargs: Any) -> str: def format_args(self, **kwargs: Any) -> str:
if self.env.config.autodoc_typehints in ('none', 'description'): if self.config.autodoc_typehints in ('none', 'description'):
kwargs.setdefault('show_annotation', False) kwargs.setdefault('show_annotation', False)
try: try:
self.env.app.emit('autodoc-before-process-signature', self.object, False) self.env.app.emit('autodoc-before-process-signature', self.object, False)
sig = inspect.signature(self.object, sig = inspect.signature(self.object, type_aliases=self.config.autodoc_type_aliases)
type_aliases=self.env.config.autodoc_type_aliases)
args = stringify_signature(sig, **kwargs) args = stringify_signature(sig, **kwargs)
except TypeError as exc: except TypeError as exc:
logger.warning(__("Failed to get a function signature for %s: %s"), logger.warning(__("Failed to get a function signature for %s: %s"),
@ -1270,7 +1269,7 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ
except ValueError: except ValueError:
args = '' args = ''
if self.env.config.strip_signature_backslash: if self.config.strip_signature_backslash:
# escape backslashes for reST # escape backslashes for reST
args = args.replace('\\', '\\\\') args = args.replace('\\', '\\\\')
return args return args
@ -1289,7 +1288,7 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ
sigs = [] sigs = []
if (self.analyzer and if (self.analyzer and
'.'.join(self.objpath) in self.analyzer.overloads and '.'.join(self.objpath) in self.analyzer.overloads and
self.env.config.autodoc_typehints == 'signature'): self.config.autodoc_typehints == 'signature'):
# Use signatures for overloaded functions instead of the implementation function. # Use signatures for overloaded functions instead of the implementation function.
overloaded = True overloaded = True
else: else:
@ -1313,7 +1312,7 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ
__globals__ = safe_getattr(self.object, '__globals__', {}) __globals__ = safe_getattr(self.object, '__globals__', {})
for overload in self.analyzer.overloads.get('.'.join(self.objpath)): for overload in self.analyzer.overloads.get('.'.join(self.objpath)):
overload = evaluate_signature(overload, __globals__, overload = evaluate_signature(overload, __globals__,
self.env.config.autodoc_type_aliases) self.config.autodoc_type_aliases)
sig = stringify_signature(overload, **kwargs) sig = stringify_signature(overload, **kwargs)
sigs.append(sig) sigs.append(sig)
@ -1323,7 +1322,7 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ
def annotate_to_first_argument(self, func: Callable, typ: Type) -> None: def annotate_to_first_argument(self, func: Callable, typ: Type) -> None:
"""Annotate type hint to the first argument of function if needed.""" """Annotate type hint to the first argument of function if needed."""
try: try:
sig = inspect.signature(func, type_aliases=self.env.config.autodoc_type_aliases) sig = inspect.signature(func, type_aliases=self.config.autodoc_type_aliases)
except TypeError as exc: except TypeError as exc:
logger.warning(__("Failed to get a function signature for %s: %s"), logger.warning(__("Failed to get a function signature for %s: %s"),
self.fullname, exc) self.fullname, exc)
@ -1455,7 +1454,7 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
self.env.app.emit('autodoc-before-process-signature', call, True) self.env.app.emit('autodoc-before-process-signature', call, True)
try: try:
sig = inspect.signature(call, bound_method=True, sig = inspect.signature(call, bound_method=True,
type_aliases=self.env.config.autodoc_type_aliases) type_aliases=self.config.autodoc_type_aliases)
return type(self.object), '__call__', sig return type(self.object), '__call__', sig
except ValueError: except ValueError:
pass pass
@ -1471,7 +1470,7 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
self.env.app.emit('autodoc-before-process-signature', new, True) self.env.app.emit('autodoc-before-process-signature', new, True)
try: try:
sig = inspect.signature(new, bound_method=True, sig = inspect.signature(new, bound_method=True,
type_aliases=self.env.config.autodoc_type_aliases) type_aliases=self.config.autodoc_type_aliases)
return self.object, '__new__', sig return self.object, '__new__', sig
except ValueError: except ValueError:
pass pass
@ -1482,7 +1481,7 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
self.env.app.emit('autodoc-before-process-signature', init, True) self.env.app.emit('autodoc-before-process-signature', init, True)
try: try:
sig = inspect.signature(init, bound_method=True, sig = inspect.signature(init, bound_method=True,
type_aliases=self.env.config.autodoc_type_aliases) type_aliases=self.config.autodoc_type_aliases)
return self.object, '__init__', sig return self.object, '__init__', sig
except ValueError: except ValueError:
pass pass
@ -1494,7 +1493,7 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
self.env.app.emit('autodoc-before-process-signature', self.object, False) self.env.app.emit('autodoc-before-process-signature', self.object, False)
try: try:
sig = inspect.signature(self.object, bound_method=False, sig = inspect.signature(self.object, bound_method=False,
type_aliases=self.env.config.autodoc_type_aliases) type_aliases=self.config.autodoc_type_aliases)
return None, None, sig return None, None, sig
except ValueError: except ValueError:
pass pass
@ -1504,7 +1503,7 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
return None, None, None return None, None, None
def format_args(self, **kwargs: Any) -> str: def format_args(self, **kwargs: Any) -> str:
if self.env.config.autodoc_typehints in ('none', 'description'): if self.config.autodoc_typehints in ('none', 'description'):
kwargs.setdefault('show_annotation', False) kwargs.setdefault('show_annotation', False)
try: try:
@ -1528,13 +1527,13 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
sigs = [] sigs = []
overloads = self.get_overloaded_signatures() overloads = self.get_overloaded_signatures()
if overloads and self.env.config.autodoc_typehints == 'signature': if overloads and self.config.autodoc_typehints == 'signature':
# Use signatures for overloaded methods instead of the implementation method. # Use signatures for overloaded methods instead of the implementation method.
method = safe_getattr(self._signature_class, self._signature_method_name, None) method = safe_getattr(self._signature_class, self._signature_method_name, None)
__globals__ = safe_getattr(method, '__globals__', {}) __globals__ = safe_getattr(method, '__globals__', {})
for overload in overloads: for overload in overloads:
overload = evaluate_signature(overload, __globals__, overload = evaluate_signature(overload, __globals__,
self.env.config.autodoc_type_aliases) self.config.autodoc_type_aliases)
parameters = list(overload.parameters.values()) parameters = list(overload.parameters.values())
overload = overload.replace(parameters=parameters[1:], overload = overload.replace(parameters=parameters[1:],
@ -1594,7 +1593,7 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
if lines is not None: if lines is not None:
return lines return lines
content = self.env.config.autoclass_content content = self.config.autoclass_content
docstrings = [] docstrings = []
attrdocstring = self.get_attr(self.object, '__doc__', None) attrdocstring = self.get_attr(self.object, '__doc__', None)
@ -1606,7 +1605,7 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
if content in ('both', 'init'): if content in ('both', 'init'):
__init__ = self.get_attr(self.object, '__init__', None) __init__ = self.get_attr(self.object, '__init__', None)
initdocstring = getdoc(__init__, self.get_attr, initdocstring = getdoc(__init__, self.get_attr,
self.env.config.autodoc_inherit_docstrings, self.config.autodoc_inherit_docstrings,
self.parent, self.object_name) self.parent, self.object_name)
# for new-style classes, no __init__ means default __init__ # for new-style classes, no __init__ means default __init__
if (initdocstring is not None and if (initdocstring is not None and
@ -1617,7 +1616,7 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
# try __new__ # try __new__
__new__ = self.get_attr(self.object, '__new__', None) __new__ = self.get_attr(self.object, '__new__', None)
initdocstring = getdoc(__new__, self.get_attr, initdocstring = getdoc(__new__, self.get_attr,
self.env.config.autodoc_inherit_docstrings, self.config.autodoc_inherit_docstrings,
self.parent, self.object_name) self.parent, self.object_name)
# for new-style classes, no __new__ means default __new__ # for new-style classes, no __new__ means default __new__
if (initdocstring is not None and if (initdocstring is not None and
@ -1885,7 +1884,7 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
return ret return ret
def format_args(self, **kwargs: Any) -> str: def format_args(self, **kwargs: Any) -> str:
if self.env.config.autodoc_typehints in ('none', 'description'): if self.config.autodoc_typehints in ('none', 'description'):
kwargs.setdefault('show_annotation', False) kwargs.setdefault('show_annotation', False)
try: try:
@ -1899,11 +1898,11 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
if inspect.isstaticmethod(self.object, cls=self.parent, name=self.object_name): if inspect.isstaticmethod(self.object, cls=self.parent, name=self.object_name):
self.env.app.emit('autodoc-before-process-signature', self.object, False) self.env.app.emit('autodoc-before-process-signature', self.object, False)
sig = inspect.signature(self.object, bound_method=False, sig = inspect.signature(self.object, bound_method=False,
type_aliases=self.env.config.autodoc_type_aliases) type_aliases=self.config.autodoc_type_aliases)
else: else:
self.env.app.emit('autodoc-before-process-signature', self.object, True) self.env.app.emit('autodoc-before-process-signature', self.object, True)
sig = inspect.signature(self.object, bound_method=True, sig = inspect.signature(self.object, bound_method=True,
type_aliases=self.env.config.autodoc_type_aliases) type_aliases=self.config.autodoc_type_aliases)
args = stringify_signature(sig, **kwargs) args = stringify_signature(sig, **kwargs)
except TypeError as exc: except TypeError as exc:
logger.warning(__("Failed to get a method signature for %s: %s"), logger.warning(__("Failed to get a method signature for %s: %s"),
@ -1912,7 +1911,7 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
except ValueError: except ValueError:
args = '' args = ''
if self.env.config.strip_signature_backslash: if self.config.strip_signature_backslash:
# escape backslashes for reST # escape backslashes for reST
args = args.replace('\\', '\\\\') args = args.replace('\\', '\\\\')
return args return args
@ -1940,7 +1939,7 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
sigs = [] sigs = []
if (self.analyzer and if (self.analyzer and
'.'.join(self.objpath) in self.analyzer.overloads and '.'.join(self.objpath) in self.analyzer.overloads and
self.env.config.autodoc_typehints == 'signature'): self.config.autodoc_typehints == 'signature'):
# Use signatures for overloaded methods instead of the implementation method. # Use signatures for overloaded methods instead of the implementation method.
overloaded = True overloaded = True
else: else:
@ -1966,7 +1965,7 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
__globals__ = safe_getattr(self.object, '__globals__', {}) __globals__ = safe_getattr(self.object, '__globals__', {})
for overload in self.analyzer.overloads.get('.'.join(self.objpath)): for overload in self.analyzer.overloads.get('.'.join(self.objpath)):
overload = evaluate_signature(overload, __globals__, overload = evaluate_signature(overload, __globals__,
self.env.config.autodoc_type_aliases) self.config.autodoc_type_aliases)
if not inspect.isstaticmethod(self.object, cls=self.parent, if not inspect.isstaticmethod(self.object, cls=self.parent,
name=self.object_name): name=self.object_name):
@ -1980,7 +1979,7 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
def annotate_to_first_argument(self, func: Callable, typ: Type) -> None: def annotate_to_first_argument(self, func: Callable, typ: Type) -> None:
"""Annotate type hint to the first argument of function if needed.""" """Annotate type hint to the first argument of function if needed."""
try: try:
sig = inspect.signature(func, type_aliases=self.env.config.autodoc_type_aliases) sig = inspect.signature(func, type_aliases=self.config.autodoc_type_aliases)
except TypeError as exc: except TypeError as exc:
logger.warning(__("Failed to get a method signature for %s: %s"), logger.warning(__("Failed to get a method signature for %s: %s"),
self.fullname, exc) self.fullname, exc)
@ -2135,11 +2134,11 @@ class AttributeDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter):
# Disable `autodoc_inherit_docstring` temporarily to avoid to obtain # Disable `autodoc_inherit_docstring` temporarily to avoid to obtain
# a docstring from the value which descriptor returns unexpectedly. # a docstring from the value which descriptor returns unexpectedly.
# ref: https://github.com/sphinx-doc/sphinx/issues/7805 # ref: https://github.com/sphinx-doc/sphinx/issues/7805
orig = self.env.config.autodoc_inherit_docstrings orig = self.config.autodoc_inherit_docstrings
self.env.config.autodoc_inherit_docstrings = False # type: ignore self.config.autodoc_inherit_docstrings = False # type: ignore
return super().get_doc(encoding, ignore) return super().get_doc(encoding, ignore)
finally: finally:
self.env.config.autodoc_inherit_docstrings = orig # type: ignore self.config.autodoc_inherit_docstrings = orig # type: ignore
def add_content(self, more_content: Any, no_docstring: bool = False) -> None: def add_content(self, more_content: Any, no_docstring: bool = False) -> None:
if not self._datadescriptor: if not self._datadescriptor:
@ -2248,11 +2247,11 @@ class SlotsAttributeDocumenter(AttributeDocumenter):
self.objtype = 'attribute' self.objtype = 'attribute'
self._datadescriptor = True self._datadescriptor = True
with mock(self.env.config.autodoc_mock_imports): with mock(self.config.autodoc_mock_imports):
try: try:
ret = import_object(self.modname, self.objpath[:-1], 'class', ret = import_object(self.modname, self.objpath[:-1], 'class',
attrgetter=self.get_attr, attrgetter=self.get_attr,
warningiserror=self.env.config.autodoc_warningiserror) warningiserror=self.config.autodoc_warningiserror)
self.module, _, _, self.parent = ret self.module, _, _, self.parent = ret
return True return True
except ImportError as exc: except ImportError as exc:

View File

@ -72,6 +72,7 @@ from docutils.statemachine import StringList
import sphinx import sphinx
from sphinx import addnodes from sphinx import addnodes
from sphinx.application import Sphinx from sphinx.application import Sphinx
from sphinx.config import Config
from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warning from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warning
from sphinx.environment import BuildEnvironment from sphinx.environment import BuildEnvironment
from sphinx.environment.adapters.toctree import TocTree from sphinx.environment.adapters.toctree import TocTree
@ -177,8 +178,10 @@ class FakeDirective(DocumenterBridge):
def __init__(self) -> None: def __init__(self) -> None:
settings = Struct(tab_width=8) settings = Struct(tab_width=8)
document = Struct(settings=settings) document = Struct(settings=settings)
env = BuildEnvironment()
env.config = Config()
state = Struct(document=document) state = Struct(document=document)
super().__init__({}, None, Options(), 0, state) # type: ignore super().__init__(env, None, Options(), 0, state)
def get_documenter(app: Sphinx, obj: Any, parent: Any) -> "Type[Documenter]": def get_documenter(app: Sphinx, obj: Any, parent: Any) -> "Type[Documenter]":