Repository: sphinx-doc/sphinx

Issue:
Autodoc attempts to document imports in "optional import" idiom
Autodoc-ing a module with the following idiom will result in trying to document the third-party OptionalClass. Pretty sure it's because it classifies it as not-imported data because of the assignment. Related to #6447 ?

```python
try:
   from xyz import OptionalClass
except ImportError:
  OptionalClass = None
```

This is happening on 2.1.0 and on the latest master. Let me know if you need more reproduction instructions and I'll put together a small testcase. Right now the very large testcase is in the angr project; error log is [here](https://travis-ci.org/angr/angr-doc/jobs/541906392#L1170), build tree is [here](https://github.com/angr/angr-doc/tree/c0e815b/api-doc) (conf.py is [here](https://github.com/angr/angr-doc/blob/c0e815b/api-doc/source/conf.py), relevant source is [here](https://raw.githubusercontent.com/angr/angr-doc/c0e815b/api-doc/source/angr.rst) (the relevant line is `.. automodule:: angr.engines.concrete`)) and the module source is [here](https://github.com/angr/angr/blob/48a7297/angr/engines/concrete.py#L11).

Discussion:

Patch:
diff --git a/CHANGES b/CHANGES
index 1c5749867..4df249167 100644
--- a/CHANGES
+++ b/CHANGES
@@ -19,6 +19,7 @@ Bugs fixed
 * #6442: LaTeX: admonitions of :rst:dir:`note` type can get separated from
   immediately preceding section title by pagebreak
 * #6448: autodoc: crashed when autodocumenting classes with ``__slots__ = None``
+* #6451: autodoc: generates docs for "optional import"ed modules as variables
 * #6452: autosummary: crashed when generating document of properties
 * #6455: napoleon: docstrings for properties are not processed
 * #6436: napoleon: "Unknown target name" error if variable name ends with
diff --git a/sphinx/pycode/parser.py b/sphinx/pycode/parser.py
index f9489e91a..1746537bb 100644
--- a/sphinx/pycode/parser.py
+++ b/sphinx/pycode/parser.py
@@ -357,6 +357,17 @@ def visit_Expr(self, node):
             except TypeError:
                 pass  # this assignment is not new definition!
 
+    def visit_Try(self, node):
+        # type: (ast.Try) -> None
+        """Handles Try node and processes body and else-clause.
+
+        .. note:: pycode parser ignores objects definition in except-clause.
+        """
+        for subnode in node.body:
+            self.visit(subnode)
+        for subnode in node.orelse:
+            self.visit(subnode)
+
     def visit_ClassDef(self, node):
         # type: (ast.ClassDef) -> None
         """Handles ClassDef node and set context."""


Test patch:
diff --git a/tests/test_pycode_parser.py b/tests/test_pycode_parser.py
index ba9778b80..8f8c6cbab 100644
--- a/tests/test_pycode_parser.py
+++ b/tests/test_pycode_parser.py
@@ -149,6 +149,21 @@ def test_complex_assignment_py3():
     assert parser.definitions == {}
 
 
+def test_assignment_in_try_clause():
+    source = ('try:\n'
+              '    a = None  #: comment\n'
+              'except:\n'
+              '    b = None  #: ignored\n'
+              'else:\n'
+              '    c = None  #: comment\n')
+    parser = Parser(source)
+    parser.parse()
+    assert parser.comments == {('', 'a'): 'comment',
+                               ('', 'c'): 'comment'}
+    assert parser.deforders == {'a': 0,
+                                'c': 1}
+
+
 def test_obj_assignment():
     source = ('obj = SomeObject()  #: some object\n'
               'obj.attr = 1  #: attr1\n'