Repository: sphinx-doc/sphinx

Issue:
Python: Enum argument missing if it shares value with another
Thank you for this great library!

Subject: All members of a python Enum aren't rendered if some of them are sharing the same value

### Problem

Let this Python enum:

```py
class MyEnum(Enum):
    """Some docstring"""

    A = 1
    B = 2
    C = 3
    C_ = 3
```

Sphinx 1.7.5 with the autodoc extension generates:

```
 class my_module.MyEnum

    Bases: enum.Enum

    Some docstring

    B = 2
    C = 3
    A = 1
```

Another scenario:

```py
class MyEnum(Enum):
    """Some docstring"""

    A = 1
    B = 2
    C = 3
    C_ = 3       #:doc
```

gets generated into:


```
 class my_module.MyEnum

    Bases: enum.Enum

    Some docstring

    B = 2
    C_ = None
       doc
    C = 3
    A = 1
```


#### Procedure to reproduce the problem
```
make html
```
Makefile being generated by sphinx-quickstart 1.7.5.

#### Error logs / results
See above

#### Expected results


```
 class my_module.MyEnum

    Bases: enum.Enum

    Some docstring

    A = 1
    B = 2
    C = 3
    C_ = 3
```

### Reproducible project / your project
- https://github.com/mozilla-releng/mozilla-version/blob/46c1208623dd5fc78f69596ec05a06d87fad2e40/mozilla_version/version.py#L26
- https://mozilla-version.readthedocs.io/en/latest/mozilla_version.html#module-mozilla_version.version


### Environment info
- OS: Latest Arch Linux
- Python version: 3.6.5
- Sphinx version: 1.7.5

Discussion:

Patch:
diff --git a/CHANGES b/CHANGES
index e67684297..a6111ce45 100644
--- a/CHANGES
+++ b/CHANGES
@@ -42,6 +42,7 @@ Bugs fixed
 * autosummary: warnings of autosummary indicates wrong location (refs: #5146)
 * #5143: autodoc: crashed on inspecting dict like object which does not support
   sorting
+* #5139: autodoc: Enum argument missing if it shares value with another
 
 Testing
 --------
diff --git a/sphinx/ext/autodoc/importer.py b/sphinx/ext/autodoc/importer.py
index 7d2c67a4f..1dd17d3f3 100644
--- a/sphinx/ext/autodoc/importer.py
+++ b/sphinx/ext/autodoc/importer.py
@@ -219,12 +219,21 @@ def get_object_members(subject, objpath, attrgetter, analyzer=None):
         for name, value in subject.__members__.items():
             obj_dict[name] = value
 
-    members = {}
+    members = {}  # type: Dict[str, Attribute]
+
+    # enum members
+    if isenumclass(subject):
+        for name, value in subject.__members__.items():
+            if name not in members:
+                members[name] = Attribute(name, True, value)
+
+    # other members
     for name in dir(subject):
         try:
             value = attrgetter(subject, name)
             directly_defined = name in obj_dict
-            members[name] = Attribute(name, directly_defined, value)
+            if name not in members:
+                members[name] = Attribute(name, directly_defined, value)
         except AttributeError:
             continue
 


Test patch:
diff --git a/tests/roots/test-ext-autodoc/target/__init__.py b/tests/roots/test-ext-autodoc/target/__init__.py
index 2452d3d89..d94665bbf 100644
--- a/tests/roots/test-ext-autodoc/target/__init__.py
+++ b/tests/roots/test-ext-autodoc/target/__init__.py
@@ -233,3 +233,4 @@ class EnumCls(enum.Enum):
     val2 = 23  #: doc for val2
     val3 = 34
     """doc for val3"""
+    val4 = 34
diff --git a/tests/test_autodoc.py b/tests/test_autodoc.py
index ed6d050fa..53d8a1e14 100644
--- a/tests/test_autodoc.py
+++ b/tests/test_autodoc.py
@@ -873,13 +873,14 @@ def assert_order(items, objtype, name, member_order, **kw):
     # test members with enum attributes
     directive.env.ref_context['py:module'] = 'target'
     options.inherited_members = False
-    options.undoc_members = False
+    options.undoc_members = True
     options.members = ALL
     assert_processes([
         ('class', 'target.EnumCls'),
         ('attribute', 'target.EnumCls.val1'),
         ('attribute', 'target.EnumCls.val2'),
         ('attribute', 'target.EnumCls.val3'),
+        ('attribute', 'target.EnumCls.val4'),
     ], 'class', 'EnumCls')
     assert_result_contains(
         '   :annotation: = 12', 'attribute', 'EnumCls.val1')