tptimer/env/lib/python2.7/site-packages/astroid/tests/unittest_brain.py

699 lines
24 KiB
Python

# Copyright (c) 2013-2014 Google, Inc.
# Copyright (c) 2014-2016 Claudiu Popa <pcmanticore@gmail.com>
# Copyright (c) 2015 Philip Lorenz <philip@bithub.de>
# Copyright (c) 2015 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
# Copyright (c) 2015 raylu <lurayl@gmail.com>
# Copyright (c) 2015-2016 Cara Vinson <ceridwenv@gmail.com>
# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html
# For details: https://github.com/PyCQA/astroid/blob/master/COPYING.LESSER
"""Tests for basic functionality in astroid.brain."""
try:
import multiprocessing # pylint: disable=unused-import
HAS_MULTIPROCESSING = True
except ImportError:
HAS_MULTIPROCESSING = False
import sys
import unittest
try:
import enum # pylint: disable=unused-import
HAS_ENUM = True
except ImportError:
try:
import enum34 as enum # pylint: disable=unused-import
HAS_ENUM = True
except ImportError:
HAS_ENUM = False
try:
import nose # pylint: disable=unused-import
HAS_NOSE = True
except ImportError:
HAS_NOSE = False
try:
import dateutil # pylint: disable=unused-import
HAS_DATEUTIL = True
except ImportError:
HAS_DATEUTIL = False
try:
import numpy # pylint: disable=unused-import
HAS_NUMPY = True
except ImportError:
HAS_NUMPY = False
try:
import pytest
HAS_PYTEST = True
except ImportError:
HAS_PYTEST = False
import six
from astroid import MANAGER
from astroid import bases
from astroid import builder
from astroid import nodes
from astroid import util
from astroid import test_utils
import astroid
class HashlibTest(unittest.TestCase):
def test_hashlib(self):
"""Tests that brain extensions for hashlib work."""
hashlib_module = MANAGER.ast_from_module_name('hashlib')
for class_name in ['md5', 'sha1']:
class_obj = hashlib_module[class_name]
self.assertIn('update', class_obj)
self.assertIn('digest', class_obj)
self.assertIn('hexdigest', class_obj)
self.assertIn('block_size', class_obj)
self.assertIn('digest_size', class_obj)
self.assertEqual(len(class_obj['__init__'].args.args), 2)
self.assertEqual(len(class_obj['__init__'].args.defaults), 1)
self.assertEqual(len(class_obj['update'].args.args), 2)
self.assertEqual(len(class_obj['digest'].args.args), 1)
self.assertEqual(len(class_obj['hexdigest'].args.args), 1)
class NamedTupleTest(unittest.TestCase):
def test_namedtuple_base(self):
klass = builder.extract_node("""
from collections import namedtuple
class X(namedtuple("X", ["a", "b", "c"])):
pass
""")
self.assertEqual(
[anc.name for anc in klass.ancestors()],
['X', 'tuple', 'object'])
for anc in klass.ancestors():
self.assertFalse(anc.parent is None)
def test_namedtuple_inference(self):
klass = builder.extract_node("""
from collections import namedtuple
name = "X"
fields = ["a", "b", "c"]
class X(namedtuple(name, fields)):
pass
""")
base = next(base for base in klass.ancestors()
if base.name == 'X')
self.assertSetEqual({"a", "b", "c"}, set(base.instance_attrs))
def test_namedtuple_inference_failure(self):
klass = builder.extract_node("""
from collections import namedtuple
def foo(fields):
return __(namedtuple("foo", fields))
""")
self.assertIs(util.Uninferable, next(klass.infer()))
def test_namedtuple_advanced_inference(self):
# urlparse return an object of class ParseResult, which has a
# namedtuple call and a mixin as base classes
result = builder.extract_node("""
import six
result = __(six.moves.urllib.parse.urlparse('gopher://'))
""")
instance = next(result.infer())
self.assertGreaterEqual(len(instance.getattr('scheme')), 1)
self.assertGreaterEqual(len(instance.getattr('port')), 1)
with self.assertRaises(astroid.AttributeInferenceError):
instance.getattr('foo')
self.assertGreaterEqual(len(instance.getattr('geturl')), 1)
self.assertEqual(instance.name, 'ParseResult')
def test_namedtuple_instance_attrs(self):
result = builder.extract_node('''
from collections import namedtuple
namedtuple('a', 'a b c')(1, 2, 3) #@
''')
inferred = next(result.infer())
for name, attr in inferred.instance_attrs.items():
self.assertEqual(attr[0].attrname, name)
def test_namedtuple_uninferable_fields(self):
node = builder.extract_node('''
x = [A] * 2
from collections import namedtuple
l = namedtuple('a', x)
l(1)
''')
inferred = next(node.infer())
self.assertIs(util.Uninferable, inferred)
def test_namedtuple_access_class_fields(self):
node = builder.extract_node("""
from collections import namedtuple
Tuple = namedtuple("Tuple", "field other")
Tuple #@
""")
inferred = next(node.infer())
self.assertIn('field', inferred.locals)
self.assertIn('other', inferred.locals)
def test_namedtuple_rename_keywords(self):
node = builder.extract_node("""
from collections import namedtuple
Tuple = namedtuple("Tuple", "abc def", rename=True)
Tuple #@
""")
inferred = next(node.infer())
self.assertIn('abc', inferred.locals)
self.assertIn('_1', inferred.locals)
def test_namedtuple_rename_duplicates(self):
node = builder.extract_node("""
from collections import namedtuple
Tuple = namedtuple("Tuple", "abc abc abc", rename=True)
Tuple #@
""")
inferred = next(node.infer())
self.assertIn('abc', inferred.locals)
self.assertIn('_1', inferred.locals)
self.assertIn('_2', inferred.locals)
def test_namedtuple_rename_uninferable(self):
node = builder.extract_node("""
from collections import namedtuple
Tuple = namedtuple("Tuple", "a b c", rename=UNINFERABLE)
Tuple #@
""")
inferred = next(node.infer())
self.assertIn('a', inferred.locals)
self.assertIn('b', inferred.locals)
self.assertIn('c', inferred.locals)
class DefaultDictTest(unittest.TestCase):
def test_1(self):
node = builder.extract_node('''
from collections import defaultdict
X = defaultdict(int)
X[0]
''')
inferred = next(node.infer())
self.assertIs(util.Uninferable, inferred)
class ModuleExtenderTest(unittest.TestCase):
def testExtensionModules(self):
transformer = MANAGER._transform
for extender, _ in transformer.transforms[nodes.Module]:
n = nodes.Module('__main__', None)
extender(n)
@unittest.skipUnless(HAS_NOSE, "This test requires nose library.")
class NoseBrainTest(unittest.TestCase):
def test_nose_tools(self):
methods = builder.extract_node("""
from nose.tools import assert_equal
from nose.tools import assert_equals
from nose.tools import assert_true
assert_equal = assert_equal #@
assert_true = assert_true #@
assert_equals = assert_equals #@
""")
assert_equal = next(methods[0].value.infer())
assert_true = next(methods[1].value.infer())
assert_equals = next(methods[2].value.infer())
self.assertIsInstance(assert_equal, astroid.BoundMethod)
self.assertIsInstance(assert_true, astroid.BoundMethod)
self.assertIsInstance(assert_equals, astroid.BoundMethod)
self.assertEqual(assert_equal.qname(),
'unittest.case.TestCase.assertEqual')
self.assertEqual(assert_true.qname(),
'unittest.case.TestCase.assertTrue')
self.assertEqual(assert_equals.qname(),
'unittest.case.TestCase.assertEqual')
class SixBrainTest(unittest.TestCase):
def test_attribute_access(self):
ast_nodes = builder.extract_node('''
import six
six.moves.http_client #@
six.moves.urllib_parse #@
six.moves.urllib_error #@
six.moves.urllib.request #@
''')
http_client = next(ast_nodes[0].infer())
self.assertIsInstance(http_client, nodes.Module)
self.assertEqual(http_client.name,
'http.client' if six.PY3 else 'httplib')
urllib_parse = next(ast_nodes[1].infer())
if six.PY3:
self.assertIsInstance(urllib_parse, nodes.Module)
self.assertEqual(urllib_parse.name, 'urllib.parse')
else:
# On Python 2, this is a fake module, the same behaviour
# being mimicked in brain's tip for six.moves.
self.assertIsInstance(urllib_parse, astroid.Instance)
urljoin = next(urllib_parse.igetattr('urljoin'))
urlencode = next(urllib_parse.igetattr('urlencode'))
if six.PY2:
# In reality it's a function, but our implementations
# transforms it into a method.
self.assertIsInstance(urljoin, astroid.BoundMethod)
self.assertEqual(urljoin.qname(), 'urlparse.urljoin')
self.assertIsInstance(urlencode, astroid.BoundMethod)
self.assertEqual(urlencode.qname(), 'urllib.urlencode')
else:
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())
if six.PY3:
self.assertIsInstance(urllib_error, nodes.Module)
self.assertEqual(urllib_error.name, 'urllib.error')
else:
# On Python 2, this is a fake module, the same behaviour
# being mimicked in brain's tip for six.moves.
self.assertIsInstance(urllib_error, astroid.Instance)
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())
if six.PY3:
self.assertIsInstance(urllib_request, nodes.Module)
self.assertEqual(urllib_request.name, 'urllib.request')
else:
self.assertIsInstance(urllib_request, astroid.Instance)
urlopen = next(urllib_request.igetattr('urlopen'))
urlretrieve = next(urllib_request.igetattr('urlretrieve'))
if six.PY2:
# In reality it's a function, but our implementations
# transforms it into a method.
self.assertIsInstance(urlopen, astroid.BoundMethod)
self.assertEqual(urlopen.qname(), 'urllib2.urlopen')
self.assertIsInstance(urlretrieve, astroid.BoundMethod)
self.assertEqual(urlretrieve.qname(), 'urllib.urlretrieve')
else:
self.assertIsInstance(urlopen, nodes.FunctionDef)
self.assertEqual(urlopen.qname(), 'urllib.request.urlopen')
self.assertIsInstance(urlretrieve, nodes.FunctionDef)
self.assertEqual(urlretrieve.qname(), 'urllib.request.urlretrieve')
def test_from_imports(self):
ast_node = builder.extract_node('''
from six.moves import http_client
http_client.HTTPSConnection #@
''')
inferred = next(ast_node.infer())
self.assertIsInstance(inferred, nodes.ClassDef)
if six.PY3:
qname = 'http.client.HTTPSConnection'
else:
qname = 'httplib.HTTPSConnection'
self.assertEqual(inferred.qname(), qname)
@unittest.skipUnless(HAS_MULTIPROCESSING,
'multiprocesing is required for this test, but '
'on some platforms it is missing '
'(Jython for instance)')
class MultiprocessingBrainTest(unittest.TestCase):
def test_multiprocessing_module_attributes(self):
# Test that module attributes are working,
# especially on Python 3.4+, where they are obtained
# from a context.
module = builder.extract_node("""
import multiprocessing
""")
module = module.do_import_module('multiprocessing')
cpu_count = next(module.igetattr('cpu_count'))
if sys.version_info < (3, 4):
self.assertIsInstance(cpu_count, nodes.FunctionDef)
else:
self.assertIsInstance(cpu_count, astroid.BoundMethod)
def test_module_name(self):
module = builder.extract_node("""
import multiprocessing
multiprocessing.SyncManager()
""")
inferred_sync_mgr = next(module.infer())
module = inferred_sync_mgr.root()
self.assertEqual(module.name, 'multiprocessing.managers')
def test_multiprocessing_manager(self):
# Test that we have the proper attributes
# for a multiprocessing.managers.SyncManager
module = builder.parse("""
import multiprocessing
manager = multiprocessing.Manager()
queue = manager.Queue()
joinable_queue = manager.JoinableQueue()
event = manager.Event()
rlock = manager.RLock()
bounded_semaphore = manager.BoundedSemaphore()
condition = manager.Condition()
barrier = manager.Barrier()
pool = manager.Pool()
list = manager.list()
dict = manager.dict()
value = manager.Value()
array = manager.Array()
namespace = manager.Namespace()
""")
queue = next(module['queue'].infer())
self.assertEqual(queue.qname(),
"{}.Queue".format(six.moves.queue.__name__))
joinable_queue = next(module['joinable_queue'].infer())
self.assertEqual(joinable_queue.qname(),
"{}.Queue".format(six.moves.queue.__name__))
event = next(module['event'].infer())
event_name = "threading.{}".format("Event" if six.PY3 else "_Event")
self.assertEqual(event.qname(), event_name)
rlock = next(module['rlock'].infer())
rlock_name = "threading._RLock"
self.assertEqual(rlock.qname(), rlock_name)
bounded_semaphore = next(module['bounded_semaphore'].infer())
semaphore_name = "threading.{}".format(
"BoundedSemaphore" if six.PY3 else "_BoundedSemaphore")
self.assertEqual(bounded_semaphore.qname(), semaphore_name)
pool = next(module['pool'].infer())
pool_name = "multiprocessing.pool.Pool"
self.assertEqual(pool.qname(), pool_name)
for attr in ('list', 'dict'):
obj = next(module[attr].infer())
self.assertEqual(obj.qname(),
"{}.{}".format(bases.BUILTINS, attr))
array = next(module['array'].infer())
self.assertEqual(array.qname(), "array.array")
manager = next(module['manager'].infer())
# Verify that we have these attributes
self.assertTrue(manager.getattr('start'))
self.assertTrue(manager.getattr('shutdown'))
class ThreadingBrainTest(unittest.TestCase):
def test_lock(self):
self._test_lock_object('Lock')
def test_rlock(self):
self._test_lock_object('RLock')
def test_semaphore(self):
self._test_lock_object('Semaphore')
def test_boundedsemaphore(self):
self._test_lock_object('BoundedSemaphore')
def _test_lock_object(self, object_name):
lock_instance = builder.extract_node("""
import threading
threading.{0}()
""".format(object_name))
inferred = next(lock_instance.infer())
self.assert_is_valid_lock(inferred)
def assert_is_valid_lock(self, inferred):
self.assertIsInstance(inferred, astroid.Instance)
self.assertEqual(inferred.root().name, 'threading')
for method in {'acquire', 'release', '__enter__', '__exit__'}:
self.assertIsInstance(next(inferred.igetattr(method)), astroid.BoundMethod)
@unittest.skipUnless(HAS_ENUM,
'The enum module was only added in Python 3.4. Support for '
'older Python versions may be available through the enum34 '
'compatibility module.')
class EnumBrainTest(unittest.TestCase):
def test_simple_enum(self):
module = builder.parse("""
import enum
class MyEnum(enum.Enum):
one = "one"
two = "two"
def mymethod(self, x):
return 5
""")
enumeration = next(module['MyEnum'].infer())
one = enumeration['one']
self.assertEqual(one.pytype(), '.MyEnum.one')
property_type = '{}.property'.format(bases.BUILTINS)
for propname in ('name', 'value'):
prop = next(iter(one.getattr(propname)))
self.assertIn(property_type, prop.decoratornames())
meth = one.getattr('mymethod')[0]
self.assertIsInstance(meth, astroid.FunctionDef)
def test_looks_like_enum_false_positive(self):
# Test that a class named Enumeration is not considered a builtin enum.
module = builder.parse('''
class Enumeration(object):
def __init__(self, name, enum_list):
pass
test = 42
''')
enumeration = module['Enumeration']
test = next(enumeration.igetattr('test'))
self.assertEqual(test.value, 42)
def test_enum_multiple_base_classes(self):
module = builder.parse("""
import enum
class Mixin:
pass
class MyEnum(Mixin, enum.Enum):
one = 1
""")
enumeration = next(module['MyEnum'].infer())
one = enumeration['one']
clazz = one.getattr('__class__')[0]
self.assertTrue(clazz.is_subtype_of('.Mixin'),
'Enum instance should share base classes with generating class')
def test_int_enum(self):
module = builder.parse("""
import enum
class MyEnum(enum.IntEnum):
one = 1
""")
enumeration = next(module['MyEnum'].infer())
one = enumeration['one']
clazz = one.getattr('__class__')[0]
int_type = '{}.{}'.format(bases.BUILTINS, 'int')
self.assertTrue(clazz.is_subtype_of(int_type),
'IntEnum based enums should be a subtype of int')
def test_enum_func_form_is_class_not_instance(self):
cls, instance = builder.extract_node('''
from enum import Enum
f = Enum('Audience', ['a', 'b', 'c'])
f #@
f(1) #@
''')
inferred_cls = next(cls.infer())
self.assertIsInstance(inferred_cls, bases.Instance)
inferred_instance = next(instance.infer())
self.assertIsInstance(inferred_instance, bases.Instance)
self.assertIsInstance(next(inferred_instance.igetattr('name')), nodes.Const)
self.assertIsInstance(next(inferred_instance.igetattr('value')), nodes.Const)
@unittest.skipUnless(HAS_DATEUTIL, "This test requires the dateutil library.")
class DateutilBrainTest(unittest.TestCase):
def test_parser(self):
module = builder.parse("""
from dateutil.parser import parse
d = parse('2000-01-01')
""")
d_type = next(module['d'].infer())
self.assertEqual(d_type.qname(), "datetime.datetime")
@unittest.skipUnless(HAS_NUMPY, "This test requires the numpy library.")
class NumpyBrainTest(unittest.TestCase):
def test_numpy(self):
node = builder.extract_node('''
import numpy
numpy.ones #@
''')
inferred = next(node.infer())
self.assertIsInstance(inferred, nodes.FunctionDef)
@unittest.skipUnless(HAS_PYTEST, "This test requires the pytest library.")
class PytestBrainTest(unittest.TestCase):
def test_pytest(self):
ast_node = builder.extract_node('''
import pytest
pytest #@
''')
module = next(ast_node.infer())
attrs = ['deprecated_call', 'warns', 'exit', 'fail', 'skip',
'importorskip', 'xfail', 'mark', 'raises', 'freeze_includes',
'set_trace', 'fixture', 'yield_fixture']
if pytest.__version__.split('.')[0] == '3':
attrs += ['approx', 'register_assert_rewrite']
for attr in attrs:
self.assertIn(attr, module)
class IOBrainTest(unittest.TestCase):
@unittest.skipUnless(six.PY3, 'Needs Python 3 io model')
def test_sys_streams(self):
for name in {'stdout', 'stderr', 'stdin'}:
node = astroid.extract_node('''
import sys
sys.{}
'''.format(name))
inferred = next(node.infer())
buffer_attr = next(inferred.igetattr('buffer'))
self.assertIsInstance(buffer_attr, astroid.Instance)
self.assertEqual(buffer_attr.name, 'BufferedWriter')
raw = next(buffer_attr.igetattr('raw'))
self.assertIsInstance(raw, astroid.Instance)
self.assertEqual(raw.name, 'FileIO')
@test_utils.require_version('3.6')
class TypingBrain(unittest.TestCase):
def test_namedtuple_base(self):
klass = builder.extract_node("""
from typing import NamedTuple
class X(NamedTuple("X", [("a", int), ("b", str), ("c", bytes)])):
pass
""")
self.assertEqual(
[anc.name for anc in klass.ancestors()],
['X', 'tuple', 'object'])
for anc in klass.ancestors():
self.assertFalse(anc.parent is None)
def test_namedtuple_inference(self):
klass = builder.extract_node("""
from typing import NamedTuple
class X(NamedTuple("X", [("a", int), ("b", str), ("c", bytes)])):
pass
""")
base = next(base for base in klass.ancestors()
if base.name == 'X')
self.assertSetEqual({"a", "b", "c"}, set(base.instance_attrs))
def test_namedtuple_inference_nonliteral(self):
# Note: NamedTuples in mypy only work with literals.
klass = builder.extract_node("""
from typing import NamedTuple
name = "X"
fields = [("a", int), ("b", str), ("c", bytes)]
NamedTuple(name, fields)
""")
inferred = next(klass.infer())
self.assertIsInstance(inferred, astroid.Instance)
self.assertEqual(inferred.qname(), "typing.NamedTuple")
def test_namedtuple_instance_attrs(self):
result = builder.extract_node('''
from typing import NamedTuple
NamedTuple("A", [("a", int), ("b", str), ("c", bytes)])(1, 2, 3) #@
''')
inferred = next(result.infer())
for name, attr in inferred.instance_attrs.items():
self.assertEqual(attr[0].attrname, name)
def test_namedtuple_simple(self):
result = builder.extract_node('''
from typing import NamedTuple
NamedTuple("A", [("a", int), ("b", str), ("c", bytes)])
''')
inferred = next(result.infer())
self.assertIsInstance(inferred, nodes.ClassDef)
self.assertSetEqual({"a", "b", "c"}, set(inferred.instance_attrs))
def test_namedtuple_few_args(self):
result = builder.extract_node('''
from typing import NamedTuple
NamedTuple("A")
''')
inferred = next(result.infer())
self.assertIsInstance(inferred, astroid.Instance)
self.assertEqual(inferred.qname(), "typing.NamedTuple")
def test_namedtuple_few_fields(self):
result = builder.extract_node('''
from typing import NamedTuple
NamedTuple("A", [("a",), ("b", str), ("c", bytes)])
''')
inferred = next(result.infer())
self.assertIsInstance(inferred, astroid.Instance)
self.assertEqual(inferred.qname(), "typing.NamedTuple")
def test_namedtuple_class_form(self):
result = builder.extract_node('''
from typing import NamedTuple
class Example(NamedTuple):
mything: int
Example(mything=1)
''')
inferred = next(result.infer())
self.assertIsInstance(inferred, astroid.Instance)
class ReBrainTest(unittest.TestCase):
def test_regex_flags(self):
import re
names = [name for name in dir(re) if name.isupper()]
re_ast = MANAGER.ast_from_module_name('re')
for name in names:
self.assertIn(name, re_ast)
self.assertEqual(next(re_ast[name].infer()).value, getattr(re, name))
if __name__ == '__main__':
unittest.main()