Repository: pylint-dev/astroid

Issue:
MRO failure on Python 3.7 with typing_extensions
### Steps to reproduce

Run the following script on Python 3.7:

```python
from astroid import parse
module = parse("""
import abc
import typing
import dataclasses

import typing_extensions

T = typing.TypeVar("T")

class MyProtocol(typing_extensions.Protocol): pass
class EarlyBase(typing.Generic[T], MyProtocol): pass
class Base(EarlyBase[T], abc.ABC): pass
class Final(Base[object]): pass
""")

#                    typing.Protocol
#                          |
# typing.Generic[T]    MyProtocol
#              \       /
#              EarlyBase     abc.ABC
#                       \    /
#                        Base
#                         |
#                        Final

final_def = module.body[-1]
final_def.mro()
```

### Current behavior

```
Traceback (most recent call last):
  File "xxx.py", line 31, in <module>
    print("mro:", final_def.mro())
  File "/home/rturner/astroid/astroid/nodes/scoped_nodes.py", line 3009, in mro
    return self._compute_mro(context=context)
  File "/home/rturner/astroid/astroid/nodes/scoped_nodes.py", line 2985, in _compute_mro
    mro = base._compute_mro(context=context)
  File "/home/rturner/astroid/astroid/nodes/scoped_nodes.py", line 2999, in _compute_mro
    return _c3_merge(unmerged_mro, self, context)
  File "/home/rturner/astroid/astroid/nodes/scoped_nodes.py", line 103, in _c3_merge
    context=context,
astroid.exceptions.InconsistentMroError: Cannot create a consistent method resolution order for MROs (tuple, object), (EarlyBase, tuple, Generic, object, MyProtocol), (ABC, object), (tuple, EarlyBase, ABC) of class <ClassDef.Base l.1347 at 0x7fa0efd52590>.
```

### Expected behavior

No MRO error is raised; Python 3.7 doesn't raise an error.

### `python -c "from astroid import __pkginfo__; print(__pkginfo__.version)"` output

2.6.7-dev0; the test case fails in pylint 2.9.6 and on the main branch at commit 6e8699cef0888631bd827b096533fc6e894d2fb2.


Discussion:

Patch:
diff --git a/astroid/const.py b/astroid/const.py
--- a/astroid/const.py
+++ b/astroid/const.py
@@ -8,6 +8,8 @@
 PY310_PLUS = sys.version_info >= (3, 10)
 BUILTINS = "builtins"  # TODO Remove in 2.8
 
+WIN32 = sys.platform == "win32"
+
 
 class Context(enum.Enum):
     Load = 1


Test patch:
diff --git a/tests/unittest_scoped_nodes.py b/tests/unittest_scoped_nodes.py
--- a/tests/unittest_scoped_nodes.py
+++ b/tests/unittest_scoped_nodes.py
@@ -43,9 +43,9 @@
 
 import pytest
 
-from astroid import MANAGER, builder, nodes, objects, test_utils, util
+from astroid import MANAGER, builder, nodes, objects, parse, test_utils, util
 from astroid.bases import BoundMethod, Generator, Instance, UnboundMethod
-from astroid.const import PY38_PLUS
+from astroid.const import PY38_PLUS, PY310_PLUS, WIN32
 from astroid.exceptions import (
     AttributeInferenceError,
     DuplicateBasesError,
@@ -1670,6 +1670,49 @@ class B(A[T], A[T]): ...
         with self.assertRaises(DuplicateBasesError):
             cls.mro()
 
+    @test_utils.require_version(minver="3.7")
+    def test_mro_typing_extensions(self):
+        """Regression test for mro() inference on typing_extesnions.
+
+        Regression reported in:
+        https://github.com/PyCQA/astroid/issues/1124
+        """
+        module = parse(
+            """
+        import abc
+        import typing
+        import dataclasses
+
+        import typing_extensions
+
+        T = typing.TypeVar("T")
+
+        class MyProtocol(typing_extensions.Protocol): pass
+        class EarlyBase(typing.Generic[T], MyProtocol): pass
+        class Base(EarlyBase[T], abc.ABC): pass
+        class Final(Base[object]): pass
+        """
+        )
+        class_names = [
+            "ABC",
+            "Base",
+            "EarlyBase",
+            "Final",
+            "Generic",
+            "MyProtocol",
+            "Protocol",
+            "object",
+        ]
+        if not PY38_PLUS:
+            class_names.pop(-2)
+        # typing_extensions is not installed on this combination of version
+        # and platform
+        if PY310_PLUS and WIN32:
+            class_names.pop(-2)
+
+        final_def = module.body[-1]
+        self.assertEqual(class_names, sorted(i.name for i in final_def.mro()))
+
     def test_generator_from_infer_call_result_parent(self) -> None:
         func = builder.extract_node(
             """