diff options
author | Takeshi KOMIYA <i.tkomiya@gmail.com> | 2020-02-22 19:22:31 +0900 |
---|---|---|
committer | Takeshi KOMIYA <i.tkomiya@gmail.com> | 2020-02-22 19:22:31 +0900 |
commit | 754d04f80d89e6455c29cc45cf5fc5bf6eb07fc4 (patch) | |
tree | 0bfc5fc61372b12873c2c73240890e2c4e3bcf22 | |
parent | db20d923d19a8b29409b4f9eac97168bfb2421de (diff) | |
parent | 51ac09d7b42dc70825771d62b102be5becd0fc52 (diff) | |
download | sphinx-git-754d04f80d89e6455c29cc45cf5fc5bf6eb07fc4.tar.gz |
Merge branch '2.4.x' into 3.x
-rw-r--r-- | AUTHORS | 1 | ||||
-rw-r--r-- | CHANGES | 8 | ||||
-rw-r--r-- | doc/templating.rst | 13 | ||||
-rw-r--r-- | sphinx/ext/autodoc/type_comment.py | 4 | ||||
-rw-r--r-- | sphinx/ext/intersphinx.py | 3 | ||||
-rw-r--r-- | sphinx/ext/todo.py | 9 | ||||
-rw-r--r-- | sphinx/themes/basic/static/searchtools.js | 20 | ||||
-rw-r--r-- | sphinx/util/inspect.py | 21 | ||||
-rw-r--r-- | tests/roots/test-ext-autodoc/target/coroutine.py | 10 | ||||
-rw-r--r-- | tests/test_autodoc.py | 18 | ||||
-rw-r--r-- | tests/test_ext_intersphinx.py | 6 | ||||
-rw-r--r-- | tests/test_util_inspect.py | 10 | ||||
-rw-r--r-- | tests/test_util_inventory.py | 1 |
13 files changed, 106 insertions, 18 deletions
@@ -64,6 +64,7 @@ Other contributors, listed alphabetically, are: * \T. Powers -- HTML output improvements * Jeppe Pihl -- literalinclude improvements * Rob Ruana -- napoleon extension +* Vince Salvino -- JavaScript search improvements * Stefan Seefeld -- toctree improvements * Gregory Szorc -- performance improvements * Taku Shimizu -- epub3 builder @@ -93,6 +93,14 @@ Features added Bugs fixed ---------- +* #7184: autodoc: ``*args`` and ``**kwarg`` in type comments are not handled + properly +* #7189: autodoc: classmethod coroutines are not detected +* #7183: intersphinx: ``:attr:`` reference to property is broken +* #6244, #6387: html search: Search breaks/hangs when built with dirhtml builder +* #7195: todo: emit doctree-resolved event with non-document node incorrectly + + Testing -------- diff --git a/doc/templating.rst b/doc/templating.rst index 14fb31ed8..fd0f6b637 100644 --- a/doc/templating.rst +++ b/doc/templating.rst @@ -121,6 +121,17 @@ The following blocks exist in the ``layout.html`` template: The contents of the document itself. It contains the block "body" where the individual content is put by subtemplates like ``page.html``. + .. note:: + In order for the built-in JavaScript search to show a page preview on + the results page, the document or body content should be wrapped in an + HTML element containing the ``role="main"`` attribute. For example: + + .. sourcecode:: html+jinja + + <div role="main"> + {% block document %}{% endblock %} + </div> + `sidebar1` / `sidebar2` A possible location for a sidebar. `sidebar1` appears before the document and is empty by default, `sidebar2` after the document and contains the @@ -427,5 +438,3 @@ are in HTML form), these variables are also available: * ``includehidden`` (``False`` by default): if true, the TOC tree will also contain hidden entries. - - diff --git a/sphinx/ext/autodoc/type_comment.py b/sphinx/ext/autodoc/type_comment.py index a7eb2c4a2..e6a77f24d 100644 --- a/sphinx/ext/autodoc/type_comment.py +++ b/sphinx/ext/autodoc/type_comment.py @@ -56,7 +56,7 @@ def signature_from_ast(node: ast.FunctionDef, bound_method: bool, if node.args.vararg: param = Parameter(node.args.vararg.arg, Parameter.VAR_POSITIONAL, - annotation=arg.type_comment or Parameter.empty) + annotation=node.args.vararg.type_comment or Parameter.empty) params.append(param) for arg in node.args.kwonlyargs: @@ -66,7 +66,7 @@ def signature_from_ast(node: ast.FunctionDef, bound_method: bool, if node.args.kwarg: param = Parameter(node.args.kwarg.arg, Parameter.VAR_KEYWORD, - annotation=arg.type_comment or Parameter.empty) + annotation=node.args.kwarg.type_comment or Parameter.empty) params.append(param) # Remove first parameter when *obj* is bound_method diff --git a/sphinx/ext/intersphinx.py b/sphinx/ext/intersphinx.py index da0988b79..362583fa2 100644 --- a/sphinx/ext/intersphinx.py +++ b/sphinx/ext/intersphinx.py @@ -282,6 +282,9 @@ def missing_reference(app: Sphinx, env: BuildEnvironment, node: Element, contnod if 'std:cmdoption' in objtypes: # until Sphinx-1.6, cmdoptions are stored as std:option objtypes.append('std:option') + if 'py:attribute' in objtypes: + # Since Sphinx-2.1, properties are stored as py:method + objtypes.append('py:method') to_try = [(inventories.main_inventory, target)] if domain: full_qualified_name = env.get_domain(domain).get_full_qualified_name(node) diff --git a/sphinx/ext/todo.py b/sphinx/ext/todo.py index 69aaaf8b2..c5cacc437 100644 --- a/sphinx/ext/todo.py +++ b/sphinx/ext/todo.py @@ -28,7 +28,7 @@ from sphinx.environment import BuildEnvironment from sphinx.errors import NoUri from sphinx.locale import _, __ from sphinx.util import logging, texescape -from sphinx.util.docutils import SphinxDirective +from sphinx.util.docutils import SphinxDirective, new_document from sphinx.util.nodes import make_refnode from sphinx.writers.html import HTMLTranslator from sphinx.writers.latex import LaTeXTranslator @@ -159,6 +159,7 @@ class TodoListProcessor: def process(self, doctree: nodes.document, docname: str) -> None: todos = sum(self.domain.todos.values(), []) # type: List[todo_node] + document = new_document('') for node in doctree.traverse(todolist): if not self.config.todo_include_todos: node.parent.remove(node) @@ -175,7 +176,11 @@ class TodoListProcessor: new_todo['ids'].clear() # (Recursively) resolve references in the todo content - self.env.resolve_references(new_todo, todo['docname'], self.builder) # type: ignore # NOQA + # + # Note: To resolve references, it is needed to wrap it with document node + document += new_todo + self.env.resolve_references(document, todo['docname'], self.builder) + document.remove(new_todo) content.append(new_todo) todo_ref = self.create_todo_reference(todo, docname) diff --git a/sphinx/themes/basic/static/searchtools.js b/sphinx/themes/basic/static/searchtools.js index edef8acf5..d11b33a78 100644 --- a/sphinx/themes/basic/static/searchtools.js +++ b/sphinx/themes/basic/static/searchtools.js @@ -63,6 +63,11 @@ var Search = { htmlElement.innerHTML = htmlString; $(htmlElement).find('.headerlink').remove(); docContent = $(htmlElement).find('[role=main]')[0]; + if(docContent === undefined) { + console.warn("Content block not found. Sphinx search tries to obtain it " + + "via '[role=main]'. Could you check your theme or template."); + return ""; + } return docContent.textContent || docContent.innerText; }, @@ -245,6 +250,7 @@ var Search = { if (results.length) { var item = results.pop(); var listItem = $('<li style="display:none"></li>'); + var requestUrl = ""; if (DOCUMENTATION_OPTIONS.BUILDER === 'dirhtml') { // dirhtml builder var dirname = item[0] + '/'; @@ -253,15 +259,15 @@ var Search = { } else if (dirname == 'index/') { dirname = ''; } - listItem.append($('<a/>').attr('href', - DOCUMENTATION_OPTIONS.URL_ROOT + dirname + - highlightstring + item[2]).html(item[1])); + requestUrl = DOCUMENTATION_OPTIONS.URL_ROOT + dirname; + } else { // normal html builders - listItem.append($('<a/>').attr('href', - item[0] + DOCUMENTATION_OPTIONS.FILE_SUFFIX + - highlightstring + item[2]).html(item[1])); + requestUrl = DOCUMENTATION_OPTIONS.URL_ROOT + item[0] + DOCUMENTATION_OPTIONS.FILE_SUFFIX; } + listItem.append($('<a/>').attr('href', + requestUrl + + highlightstring + item[2]).html(item[1])); if (item[3]) { listItem.append($('<span> (' + item[3] + ')</span>')); Search.output.append(listItem); @@ -269,7 +275,7 @@ var Search = { displayNextItem(); }); } else if (DOCUMENTATION_OPTIONS.HAS_SOURCE) { - $.ajax({url: DOCUMENTATION_OPTIONS.URL_ROOT + item[0] + DOCUMENTATION_OPTIONS.FILE_SUFFIX, + $.ajax({url: requestUrl, dataType: "text", complete: function(jqxhr, textstatus) { var data = jqxhr.responseText; diff --git a/sphinx/util/inspect.py b/sphinx/util/inspect.py index 5bf3ffbbf..281ef4493 100644 --- a/sphinx/util/inspect.py +++ b/sphinx/util/inspect.py @@ -116,6 +116,19 @@ def getargspec(func: Callable) -> Any: kwonlyargs, kwdefaults, annotations) +def unwrap(obj: Any) -> Any: + """Get an original object from wrapped object.""" + while True: + if ispartial(obj): + obj = unpartial(obj) + elif isclassmethod(obj): + obj = obj.__func__ + elif isstaticmethod(obj): + obj = obj.__func__ + else: + return obj + + def isenumclass(x: Any) -> bool: """Check if the object is subclass of enum.""" return inspect.isclass(x) and issubclass(x, enum.Enum) @@ -146,7 +159,7 @@ def isclassmethod(obj: Any) -> bool: """Check if the object is classmethod.""" if isinstance(obj, classmethod): return True - elif inspect.ismethod(obj) and obj.__self__ is not None: + elif inspect.ismethod(obj) and obj.__self__ is not None and isclass(obj.__self__): return True return False @@ -213,17 +226,17 @@ def isattributedescriptor(obj: Any) -> bool: def isfunction(obj: Any) -> bool: """Check if the object is function.""" - return inspect.isfunction(unpartial(obj)) + return inspect.isfunction(unwrap(obj)) def isbuiltin(obj: Any) -> bool: """Check if the object is builtin.""" - return inspect.isbuiltin(unpartial(obj)) + return inspect.isbuiltin(unwrap(obj)) def iscoroutinefunction(obj: Any) -> bool: """Check if the object is coroutine-function.""" - obj = unpartial(obj) + obj = unwrap(obj) if hasattr(obj, '__code__') and inspect.iscoroutinefunction(obj): # check obj.__code__ because iscoroutinefunction() crashes for custom method-like # objects (see https://github.com/sphinx-doc/sphinx/issues/6605) diff --git a/tests/roots/test-ext-autodoc/target/coroutine.py b/tests/roots/test-ext-autodoc/target/coroutine.py index b3223a820..69602325d 100644 --- a/tests/roots/test-ext-autodoc/target/coroutine.py +++ b/tests/roots/test-ext-autodoc/target/coroutine.py @@ -3,6 +3,16 @@ class AsyncClass: """A documented coroutine function""" attr_coro_result = await _other_coro_func() # NOQA + @classmethod + async def do_coroutine2(cls): + """A documented coroutine classmethod""" + pass + + @staticmethod + async def do_coroutine3(): + """A documented coroutine staticmethod""" + pass + async def _other_coro_func(): return "run" diff --git a/tests/test_autodoc.py b/tests/test_autodoc.py index e6b4cc5b6..d81df8245 100644 --- a/tests/test_autodoc.py +++ b/tests/test_autodoc.py @@ -1356,7 +1356,23 @@ def test_coroutine(): ' :async:', ' ', ' A documented coroutine function', - ' ' + ' ', + ' ', + ' .. py:method:: AsyncClass.do_coroutine2()', + ' :module: target.coroutine', + ' :async:', + ' :classmethod:', + ' ', + ' A documented coroutine classmethod', + ' ', + ' ', + ' .. py:method:: AsyncClass.do_coroutine3()', + ' :module: target.coroutine', + ' :async:', + ' :staticmethod:', + ' ', + ' A documented coroutine staticmethod', + ' ', ] diff --git a/tests/test_ext_intersphinx.py b/tests/test_ext_intersphinx.py index 9f0f18663..53faa7a37 100644 --- a/tests/test_ext_intersphinx.py +++ b/tests/test_ext_intersphinx.py @@ -190,6 +190,12 @@ def test_missing_reference_pydomain(tempdir, app, status, warning): rn = missing_reference(app, app.env, node, contnode) assert rn.astext() == 'func()' + # py:attr context helps to search objects + kwargs = {'py:module': 'module1'} + node, contnode = fake_node('py', 'attr', 'Foo.bar', 'Foo.bar', **kwargs) + rn = missing_reference(app, app.env, node, contnode) + assert rn.astext() == 'Foo.bar' + def test_missing_reference_stddomain(tempdir, app, status, warning): inv_file = tempdir / 'inventory' diff --git a/tests/test_util_inspect.py b/tests/test_util_inspect.py index 5c9520370..627d20f54 100644 --- a/tests/test_util_inspect.py +++ b/tests/test_util_inspect.py @@ -435,6 +435,16 @@ def test_dict_customtype(): @pytest.mark.sphinx(testroot='ext-autodoc') +def test_isclassmethod(app): + from target.methods import Base, Inherited + + assert inspect.isclassmethod(Base.classmeth) is True + assert inspect.isclassmethod(Base.meth) is False + assert inspect.isclassmethod(Inherited.classmeth) is True + assert inspect.isclassmethod(Inherited.meth) is False + + +@pytest.mark.sphinx(testroot='ext-autodoc') def test_isstaticmethod(app): from target.methods import Base, Inherited diff --git a/tests/test_util_inventory.py b/tests/test_util_inventory.py index 7491b217d..2183313e1 100644 --- a/tests/test_util_inventory.py +++ b/tests/test_util_inventory.py @@ -31,6 +31,7 @@ inventory_v2 = '''\ module1 py:module 0 foo.html#module-module1 Long Module desc module2 py:module 0 foo.html#module-$ - module1.func py:function 1 sub/foo.html#$ - +module1.Foo.bar py:method 1 index.html#foo.Bar.baz - CFunc c:function 2 cfunc.html#CFunc - std cpp:type 1 index.html#std - std::uint8_t cpp:type 1 index.html#std_uint8_t - |