Repository: sphinx-doc/sphinx

Issue:
autoclass doesn't work with nested/inner classes
This

```
.. autoclass:: module.SomeClass.NestedClass
```

fails with

```
WARNING: autodoc: failed to import class 'NestedClass' from module 'module.SomeClass'; the following exception was raised:
Traceback (most recent call last):
  File "/Users/brechtm/.pyenv/versions/rinoh-py35/lib/python3.5/site-packages/sphinx/ext/autodoc.py", line 518, in import_object
    __import__(self.modname)
ImportError: No module named 'module.SomeClass'
```


Discussion:

Patch:
diff --git a/CHANGES b/CHANGES
index e57a0dad6..114c34cf5 100644
--- a/CHANGES
+++ b/CHANGES
@@ -162,6 +162,7 @@ Features added
   if :confval:`latex_engine` is ``'xelatex'`` or ``'lualatex'``.
 * #4976: ``SphinxLoggerAdapter.info()`` now supports ``location`` parameter
 * #5122: setuptools: support nitpicky option
+* #2820: autoclass directive supports nested class
 
 Bugs fixed
 ----------
diff --git a/doc/usage/configuration.rst b/doc/usage/configuration.rst
index dd6fcfaef..7364cbadc 100644
--- a/doc/usage/configuration.rst
+++ b/doc/usage/configuration.rst
@@ -1765,39 +1765,32 @@ macros and environments, see also :doc:`/latex`.
    It must be a list of tuples ``(startdocname, targetname, title, author,
    documentclass, toctree_only)``, where the items are:
 
-   *startdocname*
-     String that specifies the :term:`document name` of the LaTeX file's master
-     document.  All documents referenced by the *startdoc* document in TOC trees
-     will be included in the LaTeX file.  (If you want to use the default master
-     document for your LaTeX build, provide your :confval:`master_doc` here.)
-
-   *targetname*
-     File name of the LaTeX file in the output directory.
-
-   *title*
-     LaTeX document title.  Can be empty to use the title of the *startdoc*
-     document.  This is inserted as LaTeX markup, so special characters like a
+   * *startdocname*: document name that is the "root" of the LaTeX file.  All
+     documents referenced by it in TOC trees will be included in the LaTeX file
+     too.  (If you want only one LaTeX file, use your :confval:`master_doc`
+     here.)
+   * *targetname*: file name of the LaTeX file in the output directory.
+   * *title*: LaTeX document title.  Can be empty to use the title of the
+     *startdoc*.  This is inserted as LaTeX markup, so special characters like a
      backslash or ampersand must be represented by the proper LaTeX commands if
      they are to be inserted literally.
-
-   *author*
-     Author for the LaTeX document.  The same LaTeX markup caveat as for *title*
-     applies.  Use ``\\and`` to separate multiple authors, as in:
-     ``'John \\and Sarah'`` (backslashes must be Python-escaped to reach LaTeX).
-
-   *documentclass*
-     Normally, one of ``'manual'`` or ``'howto'`` (provided by Sphinx and based
-     on ``'report'``, resp. ``'article'``; Japanese documents use ``'jsbook'``,
-     resp. ``'jreport'``.) "howto" (non-Japanese) documents will not get
-     appendices. Also they have a simpler title page.  Other document classes
-     can be given. Independently of the document class, the "sphinx" package is
-     always loaded in order to define Sphinx's custom LaTeX commands.
-
-   *toctree_only*
-     Must be ``True`` or ``False``.  If true, the *startdoc* document itself is
-     not included in the output, only the documents referenced by it via TOC
-     trees.  With this option, you can put extra stuff in the master document
-     that shows up in the HTML, but not the LaTeX output.
+   * *author*: Author for the LaTeX document.  The same LaTeX markup caveat as
+     for *title* applies.  Use ``\\and`` to separate multiple authors, as in:
+     ``'John \\and Sarah'`` (backslashes must be Python-escaped to reach
+     LaTeX).
+   * *documentclass*: Normally, one of ``'manual'`` or ``'howto'`` (provided
+     by Sphinx and based on ``'report'``, resp. ``'article'``; Japanese
+     documents use ``'jsbook'``, resp. ``'jreport'``.) "howto" (non-Japanese)
+     documents will not get appendices. Also they have a simpler title page.
+     Other document classes can be given. Independently of the document class,
+     the "sphinx" package is always loaded in order to define Sphinx's custom
+     LaTeX commands.
+
+   * *toctree_only*: Must be ``True`` or ``False``.  If true, the *startdoc*
+     document itself is not included in the output, only the documents
+     referenced by it via TOC trees.  With this option, you can put extra stuff
+     in the master document that shows up in the HTML, but not the LaTeX
+     output.
 
    .. versionadded:: 1.2
       In the past including your own document class required you to prepend the
@@ -2271,11 +2264,9 @@ These options influence manual page output.
    section)``, where the items are:
 
    *startdocname*
-     String that specifies the :term:`document name` of the manual page's master
-     document. All documents referenced by the *startdoc* document in TOC trees
-     will be included in the manual file.  (If you want to use the default
-     master document for your manual pages build, use your :confval:`master_doc`
-     here.)
+     Document name that is the "root" of the manual page.  All documents
+     referenced by it in TOC trees will be included in the manual file too.
+     (If you want one master manual page, use your :confval:`master_doc` here.)
 
    *name*
      Name of the manual page.  This should be a short string without spaces or
@@ -2318,19 +2309,17 @@ These options influence Texinfo output.
    are:
 
    *startdocname*
-     String that specifies the :term:`document name` of the the Texinfo file's
-     master document.  All documents referenced by the *startdoc* document in
-     TOC trees will be included in the Texinfo file.  (If you want to use the
-     default master document for your Texinfo build, provide your
-     :confval:`master_doc` here.)
+     Document name that is the "root" of the Texinfo file.  All documents
+     referenced by it in TOC trees will be included in the Texinfo file too.
+     (If you want only one Texinfo file, use your :confval:`master_doc` here.)
 
    *targetname*
      File name (no extension) of the Texinfo file in the output directory.
 
    *title*
-     Texinfo document title.  Can be empty to use the title of the *startdoc*
-     document.  Inserted as Texinfo markup, so special characters like ``@`` and
-     ``{}`` will need to be escaped to be inserted literally.
+     Texinfo document title.  Can be empty to use the title of the *startdoc*.
+     Inserted as Texinfo markup, so special characters like ``@`` and ``{}``
+     will need to be escaped to be inserted literally.
 
    *author*
      Author for the Texinfo document.  Inserted as Texinfo markup.  Use ``@*``
@@ -2499,21 +2488,12 @@ Options for the linkcheck builder
 
 .. confval:: linkcheck_anchors_ignore
 
-   A list of regular expressions that match anchors Sphinx should skip when
-   checking the validity of anchors in links. This allows skipping anchors that
-   a website's JavaScript adds to control dynamic pages or when triggering an
-   internal REST request. Default is ``["^!"]``.
-
-   .. note::
-
-      If you want to ignore anchors of a specific page or of pages that match a
-      specific pattern (but still check occurrences of the same page(s) that
-      don't have anchors), use :confval:`linkcheck_ignore` instead, for example
-      as follows::
-
-         linkcheck_ignore = [
-            'http://www.sphinx-doc.org/en/1.7/intro.html#'
-         ]
+   A list of regular expressions that match URIs that should skip checking
+   the validity of anchors in links. This allows skipping entire sites, where
+   anchors are used to control dynamic pages, or just specific anchors within
+   a page, where JavaScript is used to add anchors dynamically, or use the
+   fragment as part of to trigger an internal REST request. Default is
+   ``["/#!"]``.
 
    .. versionadded:: 1.5
 
diff --git a/sphinx/ext/autodoc/importer.py b/sphinx/ext/autodoc/importer.py
index 20d448506..4b92a7b59 100644
--- a/sphinx/ext/autodoc/importer.py
+++ b/sphinx/ext/autodoc/importer.py
@@ -167,8 +167,21 @@ def import_object(modname, objpath, objtype='', attrgetter=safe_getattr, warning
         logger.debug('[autodoc] import %s', modname)
 
     try:
-        module = import_module(modname, warningiserror=warningiserror)
-        logger.debug('[autodoc] => %r', module)
+        module = None
+        objpath = list(objpath)
+        while module is None:
+            try:
+                module = import_module(modname, warningiserror=warningiserror)
+                logger.debug('[autodoc] import %s => %r', modname, module)
+            except ImportError:
+                logger.debug('[autodoc] import %s => failed', modname)
+                if '.' in modname:
+                    # retry with parent module
+                    modname, name = modname.rsplit('.', 1)
+                    objpath.insert(0, name)
+                else:
+                    raise
+
         obj = module
         parent = None
         object_name = None


Test patch:
diff --git a/tests/roots/test-linkcheck/links.txt b/tests/roots/test-linkcheck/links.txt
index d5057e08e..36376bef4 100644
--- a/tests/roots/test-linkcheck/links.txt
+++ b/tests/roots/test-linkcheck/links.txt
@@ -9,5 +9,3 @@ Some additional anchors to exercise ignore code
 * `Example Bar invalid <http://example.com/#!bar>`_
 * `Example Bar invalid <http://example.com#!bar>`_ tests that default ignore anchor of #! does not need to be prefixed with /
 * `Example Bar invalid <http://example.com/#top>`_
-* `Example anchor invalid <http://www.sphinx-doc.org/en/1.7/intro.html#does-not-exist>`_
-* `Complete nonsense <https://localhost:7777/doesnotexist>`_
diff --git a/tests/test_autodoc.py b/tests/test_autodoc.py
index 53d8a1e14..a42210a4c 100644
--- a/tests/test_autodoc.py
+++ b/tests/test_autodoc.py
@@ -771,6 +771,9 @@ def assert_order(items, objtype, name, member_order, **kw):
                       ('class', 'target.Outer.Inner'),
                       ('method', 'target.Outer.Inner.meth')],
                      'class', 'Outer', all_members=True)
+    assert_processes([('class', 'target.Outer.Inner'),
+                      ('method', 'target.Outer.Inner.meth')],
+                     'class', 'target.Outer.Inner', all_members=True)
 
     # test descriptor docstrings
     assert_result_contains('   Descriptor instance docstring.',
diff --git a/tests/test_build_linkcheck.py b/tests/test_build_linkcheck.py
index 1716a0c42..839a15628 100644
--- a/tests/test_build_linkcheck.py
+++ b/tests/test_build_linkcheck.py
@@ -21,21 +21,14 @@ def test_defaults(app, status, warning):
     content = (app.outdir / 'output.txt').text()
 
     print(content)
-    # looking for '#top' and 'does-not-exist' not found should fail
+    # looking for #top should fail
     assert "Anchor 'top' not found" in content
-    assert "Anchor 'does-not-exist' not found" in content
-    # looking for non-existent URL should fail
-    assert " Max retries exceeded with url: /doesnotexist" in content
-    assert len(content.splitlines()) == 3
+    assert len(content.splitlines()) == 1
 
 
 @pytest.mark.sphinx(
     'linkcheck', testroot='linkcheck', freshenv=True,
-    confoverrides={'linkcheck_anchors_ignore': ["^!", "^top$"],
-                   'linkcheck_ignore': [
-                       'https://localhost:7777/doesnotexist',
-                       'http://www.sphinx-doc.org/en/1.7/intro.html#']
-                   })
+    confoverrides={'linkcheck_anchors_ignore': ["^!", "^top$"]})
 def test_anchors_ignored(app, status, warning):
     app.builder.build_all()