blob: 45a40e552a3d51fbb89eef4b16ddb65ae729be53 [file] [log] [blame]
# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html
# For details: https://github.com/pylint-dev/astroid/blob/main/LICENSE
# Copyright (c) https://github.com/pylint-dev/astroid/blob/main/CONTRIBUTORS.txt
from __future__ import annotations
import unittest
from typing import Any
import astroid
from astroid import MANAGER, builder, nodes
from astroid.nodes.scoped_nodes import ClassDef
try:
import six # type: ignore[import] # pylint: disable=unused-import
HAS_SIX = True
except ImportError:
HAS_SIX = False
@unittest.skipUnless(HAS_SIX, "These tests require the six library")
class SixBrainTest(unittest.TestCase):
def test_attribute_access(self) -> None:
ast_nodes = builder.extract_node(
"""
import six
six.moves.http_client #@
six.moves.urllib_parse #@
six.moves.urllib_error #@
six.moves.urllib.request #@
from six.moves import StringIO
StringIO #@
"""
)
assert isinstance(ast_nodes, list)
http_client = next(ast_nodes[0].infer())
self.assertIsInstance(http_client, nodes.Module)
self.assertEqual(http_client.name, "http.client")
urllib_parse = next(ast_nodes[1].infer())
self.assertIsInstance(urllib_parse, nodes.Module)
self.assertEqual(urllib_parse.name, "urllib.parse")
urljoin = next(urllib_parse.igetattr("urljoin"))
urlencode = next(urllib_parse.igetattr("urlencode"))
self.assertIsInstance(urljoin, nodes.FunctionDef)
self.assertEqual(urljoin.qname(), "urllib.parse.urljoin")
self.assertIsInstance(urlencode, nodes.FunctionDef)
self.assertEqual(urlencode.qname(), "urllib.parse.urlencode")
urllib_error = next(ast_nodes[2].infer())
self.assertIsInstance(urllib_error, nodes.Module)
self.assertEqual(urllib_error.name, "urllib.error")
urlerror = next(urllib_error.igetattr("URLError"))
self.assertIsInstance(urlerror, nodes.ClassDef)
content_too_short = next(urllib_error.igetattr("ContentTooShortError"))
self.assertIsInstance(content_too_short, nodes.ClassDef)
urllib_request = next(ast_nodes[3].infer())
self.assertIsInstance(urllib_request, nodes.Module)
self.assertEqual(urllib_request.name, "urllib.request")
urlopen = next(urllib_request.igetattr("urlopen"))
urlretrieve = next(urllib_request.igetattr("urlretrieve"))
self.assertIsInstance(urlopen, nodes.FunctionDef)
self.assertEqual(urlopen.qname(), "urllib.request.urlopen")
self.assertIsInstance(urlretrieve, nodes.FunctionDef)
self.assertEqual(urlretrieve.qname(), "urllib.request.urlretrieve")
StringIO = next(ast_nodes[4].infer())
self.assertIsInstance(StringIO, nodes.ClassDef)
self.assertEqual(StringIO.qname(), "_io.StringIO")
self.assertTrue(StringIO.callable())
def test_attribute_access_with_six_moves_imported(self) -> None:
astroid.MANAGER.clear_cache()
astroid.MANAGER._mod_file_cache.clear()
import six.moves # type: ignore[import] # pylint: disable=import-outside-toplevel,unused-import,redefined-outer-name
self.test_attribute_access()
def test_from_imports(self) -> None:
ast_node = builder.extract_node(
"""
from six.moves import http_client
http_client.HTTPSConnection #@
"""
)
inferred = next(ast_node.infer())
self.assertIsInstance(inferred, nodes.ClassDef)
qname = "http.client.HTTPSConnection"
self.assertEqual(inferred.qname(), qname)
def test_from_submodule_imports(self) -> None:
"""Make sure ulrlib submodules can be imported from
See pylint-dev/pylint#1640 for relevant issue
"""
ast_node = builder.extract_node(
"""
from six.moves.urllib.parse import urlparse
urlparse #@
"""
)
inferred = next(ast_node.infer())
self.assertIsInstance(inferred, nodes.FunctionDef)
def test_with_metaclass_subclasses_inheritance(self) -> None:
ast_node = builder.extract_node(
"""
class A(type):
def test(cls):
return cls
class C:
pass
import six
class B(six.with_metaclass(A, C)):
pass
B #@
"""
)
inferred = next(ast_node.infer())
self.assertIsInstance(inferred, nodes.ClassDef)
self.assertEqual(inferred.name, "B")
self.assertIsInstance(inferred.bases[0], nodes.Call)
ancestors = tuple(inferred.ancestors())
self.assertIsInstance(ancestors[0], nodes.ClassDef)
self.assertEqual(ancestors[0].name, "C")
self.assertIsInstance(ancestors[1], nodes.ClassDef)
self.assertEqual(ancestors[1].name, "object")
@staticmethod
def test_six_with_metaclass_enum_ancestor() -> None:
code = """
import six
from enum import Enum, EnumMeta
class FooMeta(EnumMeta):
pass
class Foo(six.with_metaclass(FooMeta, Enum)): #@
bar = 1
"""
klass = astroid.extract_node(code)
assert next(klass.ancestors()).name == "Enum"
def test_six_with_metaclass_with_additional_transform(self) -> None:
def transform_class(cls: Any) -> ClassDef:
if cls.name == "A":
cls._test_transform = 314
return cls
MANAGER.register_transform(nodes.ClassDef, transform_class)
try:
ast_node = builder.extract_node(
"""
import six
class A(six.with_metaclass(type, object)):
pass
A #@
"""
)
inferred = next(ast_node.infer())
assert getattr(inferred, "_test_transform", None) == 314
finally:
MANAGER.unregister_transform(nodes.ClassDef, transform_class)