summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog3
-rw-r--r--astroid/brain/brain_unittest.py27
-rw-r--r--astroid/interpreter/_import/spec.py1
-rw-r--r--astroid/manager.py1
-rw-r--r--tests/unittest_brain_unittest.py30
5 files changed, 60 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index 799268d7..d88a1887 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -15,6 +15,9 @@ Release date: TBA
Closes PyCQA/pylint#2224
Closes PyCQA/pylint#2626
+* Adds a brain that deals with dynamic import of `IsolatedAsyncioTestCase` class of the `unittest` module.
+
+ Closes PyCQA/pylint#4060
What's New in astroid 2.6.7?
============================
diff --git a/astroid/brain/brain_unittest.py b/astroid/brain/brain_unittest.py
new file mode 100644
index 00000000..d371d38b
--- /dev/null
+++ b/astroid/brain/brain_unittest.py
@@ -0,0 +1,27 @@
+"""Astroid hooks for unittest module"""
+from astroid.brain.helpers import register_module_extender
+from astroid.builder import parse
+from astroid.const import PY38_PLUS
+from astroid.manager import AstroidManager
+
+
+def IsolatedAsyncioTestCaseImport():
+ """
+ In the unittest package, the IsolatedAsyncioTestCase class is imported lazily, i.e only
+ when the __getattr__ method of the unittest module is called with 'IsolatedAsyncioTestCase' as
+ argument. Thus the IsolatedAsyncioTestCase is not imported statically (during import time).
+ This function mocks a classical static import of the IsolatedAsyncioTestCase.
+
+ (see https://github.com/PyCQA/pylint/issues/4060)
+ """
+ return parse(
+ """
+ from .async_case import IsolatedAsyncioTestCase
+ """
+ )
+
+
+if PY38_PLUS:
+ register_module_extender(
+ AstroidManager(), "unittest", IsolatedAsyncioTestCaseImport
+ )
diff --git a/astroid/interpreter/_import/spec.py b/astroid/interpreter/_import/spec.py
index 6fa9074b..403aada4 100644
--- a/astroid/interpreter/_import/spec.py
+++ b/astroid/interpreter/_import/spec.py
@@ -291,7 +291,6 @@ def _precache_zipimporters(path=None):
req_paths = tuple(path or sys.path)
cached_paths = tuple(pic)
new_paths = _cached_set_diff(req_paths, cached_paths)
- # pylint: disable=no-member
for entry_path in new_paths:
try:
pic[entry_path] = zipimport.zipimporter(entry_path)
diff --git a/astroid/manager.py b/astroid/manager.py
index 5c436a83..306189db 100644
--- a/astroid/manager.py
+++ b/astroid/manager.py
@@ -229,7 +229,6 @@ class AstroidManager:
except ValueError:
continue
try:
- # pylint: disable=no-member
importer = zipimport.zipimporter(eggpath + ext)
# pylint: enable=no-member
zmodname = resource.replace(os.path.sep, ".")
diff --git a/tests/unittest_brain_unittest.py b/tests/unittest_brain_unittest.py
new file mode 100644
index 00000000..644614d8
--- /dev/null
+++ b/tests/unittest_brain_unittest.py
@@ -0,0 +1,30 @@
+import unittest
+
+from astroid import builder
+from astroid.test_utils import require_version
+
+
+class UnittestTest(unittest.TestCase):
+ """
+ A class that tests the brain_unittest module
+ """
+
+ @require_version(minver="3.8.0")
+ def test_isolatedasynciotestcase(self):
+ """
+ Tests that the IsolatedAsyncioTestCase class is statically imported
+ thanks to the brain_unittest module.
+ """
+ node = builder.extract_node(
+ """
+ from unittest import IsolatedAsyncioTestCase
+
+ class TestClass(IsolatedAsyncioTestCase):
+ pass
+ """
+ )
+ assert [n.qname() for n in node.ancestors()] == [
+ "unittest.async_case.IsolatedAsyncioTestCase",
+ "unittest.case.TestCase",
+ "builtins.object",
+ ]