diff --git a/CHANGES b/CHANGES index f657ae9ab..e75ca3c3b 100644 --- a/CHANGES +++ b/CHANGES @@ -22,6 +22,10 @@ Bugs fixed * #5417: Sphinx fails to build with syntax error in Python 2.7.5 * #4911: add latexpdf to make.bat for non make-mode * #5436: Autodoc does not work with enum subclasses with properties/methods +* #5437: autodoc: crashed on modules importing eggs +* #5433: latex: ImportError: cannot import name 'DEFAULT_SETTINGS' +* #5431: autodoc: ``autofunction`` emits a warning for callable objects +* #5457: Fix TypeError in error message when override is prohibited Testing -------- diff --git a/sphinx/builders/latex/nodes.py b/sphinx/builders/latex/nodes.py index 32ac7c6a0..2dfba1b57 100644 --- a/sphinx/builders/latex/nodes.py +++ b/sphinx/builders/latex/nodes.py @@ -35,3 +35,12 @@ class math_reference(nodes.Inline, nodes.Referential, nodes.TextElement): class thebibliography(nodes.container): """A node for wrapping bibliographies.""" pass + + +HYPERLINK_SUPPORT_NODES = ( + nodes.figure, + nodes.literal_block, + nodes.table, + nodes.section, + captioned_literal_block, +) diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index 083e951e5..f82fe1be5 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -1055,7 +1055,13 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ # cannot introspect arguments of a C function or method return None try: - args = Signature(self.object).format_args() + if (not isfunction(self.object) and + not isbuiltin(self.object) and + not inspect.isclass(self.object) and + hasattr(self.object, '__call__')): + args = Signature(self.object.__call__).format_args() + else: + args = Signature(self.object).format_args() except TypeError: if (is_builtin_class_method(self.object, '__new__') and is_builtin_class_method(self.object, '__init__')): diff --git a/sphinx/registry.py b/sphinx/registry.py index 416edb2bc..0b17950b8 100644 --- a/sphinx/registry.py +++ b/sphinx/registry.py @@ -199,7 +199,7 @@ class SphinxComponentRegistry(object): directives = self.domain_directives.setdefault(domain, {}) if name in directives and not override: - raise ExtensionError(__('The %r directive is already registered to %d domain') % + raise ExtensionError(__('The %r directive is already registered to domain %s') % (name, domain)) if not isclass(obj) or not issubclass(obj, Directive): directives[name] = directive_helper(obj, has_content, argument_spec, **option_spec) @@ -213,7 +213,7 @@ class SphinxComponentRegistry(object): raise ExtensionError(__('domain %s not yet registered') % domain) roles = self.domain_roles.setdefault(domain, {}) if name in roles and not override: - raise ExtensionError(__('The %r role is already registered to %d domain') % + raise ExtensionError(__('The %r role is already registered to domain %s') % (name, domain)) roles[name] = role @@ -224,7 +224,7 @@ class SphinxComponentRegistry(object): raise ExtensionError(__('domain %s not yet registered') % domain) indices = self.domain_indices.setdefault(domain, []) if index in indices and not override: - raise ExtensionError(__('The %r index is already registered to %d domain') % + raise ExtensionError(__('The %r index is already registered to domain %s') % (index.name, domain)) indices.append(index) diff --git a/sphinx/util/__init__.py b/sphinx/util/__init__.py index 0c0c22c9c..2da685a97 100644 --- a/sphinx/util/__init__.py +++ b/sphinx/util/__init__.py @@ -314,8 +314,9 @@ def get_module_source(modname): filename += 'w' elif not (lfilename.endswith('.py') or lfilename.endswith('.pyw')): raise PycodeError('source is not a .py file: %r' % filename) - elif '.egg' in filename: - eggpath, _ = re.split('(?<=\\.egg)/', filename) + elif ('.egg' + os.path.sep) in filename: + pat = '(?<=\\.egg)' + re.escape(os.path.sep) + eggpath, _ = re.split(pat, filename, 1) if path.isfile(eggpath): return 'file', filename diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index cd222f1c7..993f77e21 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -24,7 +24,6 @@ from six import itervalues, text_type from sphinx import addnodes from sphinx import highlighting -from sphinx.builders.latex.nodes import captioned_literal_block, footnotetext from sphinx.deprecation import RemovedInSphinx30Warning from sphinx.errors import SphinxError from sphinx.locale import admonitionlabels, _, __ @@ -57,13 +56,6 @@ SHORTHANDOFF = r''' MAX_CITATION_LABEL_LENGTH = 8 LATEXSECTIONNAMES = ["part", "chapter", "section", "subsection", "subsubsection", "paragraph", "subparagraph"] -HYPERLINK_SUPPORT_NODES = ( - nodes.figure, - nodes.literal_block, - nodes.table, - nodes.section, - captioned_literal_block, -) ENUMERATE_LIST_STYLE = defaultdict(lambda: r'\arabic', { 'arabic': r'\arabic', @@ -2615,3 +2607,7 @@ class LaTeXTranslator(nodes.NodeVisitor): # # refs: https://github.com/sphinx-doc/sphinx/issues/4889 from sphinx.builders.latex.transforms import URI_SCHEMES, ShowUrlsTransform # NOQA + +# FIXME: Workaround to avoid circular import +# refs: https://github.com/sphinx-doc/sphinx/issues/5433 +from sphinx.builders.latex.nodes import HYPERLINK_SUPPORT_NODES, captioned_literal_block, footnotetext # NOQA diff --git a/tests/roots/test-ext-autodoc/target/callable.py b/tests/roots/test-ext-autodoc/target/callable.py new file mode 100644 index 000000000..f3358eafd --- /dev/null +++ b/tests/roots/test-ext-autodoc/target/callable.py @@ -0,0 +1,8 @@ +class Callable(): + """A callable object that behaves like a function.""" + + def __call__(self, arg1, arg2, **kwargs): + pass + + +function = Callable() diff --git a/tests/test_autodoc.py b/tests/test_autodoc.py index 554ad180f..18ef3b584 100644 --- a/tests/test_autodoc.py +++ b/tests/test_autodoc.py @@ -1346,6 +1346,19 @@ def test_descriptor_class(app): ] +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_autofunction_for_callable(app): + actual = do_autodoc(app, 'function', 'target.callable.function') + assert list(actual) == [ + '', + '.. py:function:: function(arg1, arg2, **kwargs)', + ' :module: target.callable', + '', + ' A callable object that behaves like a function.', + ' ' + ] + + @pytest.mark.sphinx('html', testroot='root') def test_mocked_module_imports(app): options = {"members": 'TestAutodoc,decoratedFunction'}