diff options
| author | hippo91 <guillaume.peillex@gmail.com> | 2020-06-20 11:37:37 +0200 |
|---|---|---|
| committer | hippo91 <guillaume.peillex@gmail.com> | 2020-06-20 11:37:37 +0200 |
| commit | 1322e5d7790b7e3aa629a4e86e3b9f9b5846886b (patch) | |
| tree | a6041c102f12f5cbb2a9f9f9e57edfb573d4a37f /tests | |
| parent | 14de71c7838e4bae329292035f1a225aa5218317 (diff) | |
| parent | 92f556842c84a2b3cc33a1638fc625b4f67d0d1f (diff) | |
| download | astroid-git-1322e5d7790b7e3aa629a4e86e3b9f9b5846886b.tar.gz | |
Merge branch 'master' into sum_and_multiply
Diffstat (limited to 'tests')
87 files changed, 725 insertions, 962 deletions
diff --git a/tests/resources.py b/tests/resources.py index ee57b9fe..7113f2b1 100644 --- a/tests/resources.py +++ b/tests/resources.py @@ -1,7 +1,8 @@ # Copyright (c) 2014 Google, Inc. -# Copyright (c) 2015-2016 Claudiu Popa <pcmanticore@gmail.com> +# Copyright (c) 2015-2016, 2018-2019 Claudiu Popa <pcmanticore@gmail.com> # Copyright (c) 2016 Ceridwen <ceridwenv@gmail.com> # Copyright (c) 2018 Nick Drozd <nicholasdrozd@gmail.com> +# Copyright (c) 2019 Ashley Whetter <ashley@awhetter.co.uk> # 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 @@ -14,7 +15,7 @@ from astroid import MANAGER from astroid.bases import BUILTINS -DATA_DIR = os.path.join("testdata", "python{}".format(sys.version_info[0])) +DATA_DIR = os.path.join("testdata", "python3") RESOURCE_PATH = os.path.join(os.path.dirname(__file__), DATA_DIR, "data") diff --git a/tests/testdata/python2/data/MyPyPa-0.1.0-py2.5.egg b/tests/testdata/python2/data/MyPyPa-0.1.0-py2.5.egg Binary files differdeleted file mode 100644 index f62599c7..00000000 --- a/tests/testdata/python2/data/MyPyPa-0.1.0-py2.5.egg +++ /dev/null diff --git a/tests/testdata/python2/data/MyPyPa-0.1.0-py2.5.zip b/tests/testdata/python2/data/MyPyPa-0.1.0-py2.5.zip Binary files differdeleted file mode 100644 index f62599c7..00000000 --- a/tests/testdata/python2/data/MyPyPa-0.1.0-py2.5.zip +++ /dev/null diff --git a/tests/testdata/python2/data/SSL1/Connection1.py b/tests/testdata/python2/data/SSL1/Connection1.py deleted file mode 100644 index 1307b239..00000000 --- a/tests/testdata/python2/data/SSL1/Connection1.py +++ /dev/null @@ -1,5 +0,0 @@ - -class Connection: - - def __init__(self, ctx, sock=None): - print('init Connection') diff --git a/tests/testdata/python2/data/SSL1/__init__.py b/tests/testdata/python2/data/SSL1/__init__.py deleted file mode 100644 index a007b049..00000000 --- a/tests/testdata/python2/data/SSL1/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from Connection1 import Connection diff --git a/tests/testdata/python2/data/__init__.py b/tests/testdata/python2/data/__init__.py deleted file mode 100644 index 332e2e72..00000000 --- a/tests/testdata/python2/data/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__revision__="$Id: __init__.py,v 1.1 2005-06-13 20:55:20 syt Exp $" diff --git a/tests/testdata/python2/data/absimp/__init__.py b/tests/testdata/python2/data/absimp/__init__.py deleted file mode 100644 index b98444df..00000000 --- a/tests/testdata/python2/data/absimp/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -"""a package with absolute import activated -""" - -from __future__ import absolute_import - diff --git a/tests/testdata/python2/data/absimp/sidepackage/__init__.py b/tests/testdata/python2/data/absimp/sidepackage/__init__.py deleted file mode 100644 index 239499a6..00000000 --- a/tests/testdata/python2/data/absimp/sidepackage/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -"""a side package with nothing in it -""" - diff --git a/tests/testdata/python2/data/absimp/string.py b/tests/testdata/python2/data/absimp/string.py deleted file mode 100644 index e68e7496..00000000 --- a/tests/testdata/python2/data/absimp/string.py +++ /dev/null @@ -1,3 +0,0 @@ -from __future__ import absolute_import, print_function -import string -print(string) diff --git a/tests/testdata/python2/data/absimport.py b/tests/testdata/python2/data/absimport.py deleted file mode 100644 index f98effa6..00000000 --- a/tests/testdata/python2/data/absimport.py +++ /dev/null @@ -1,3 +0,0 @@ -from __future__ import absolute_import -import email -from email import message diff --git a/tests/testdata/python2/data/all.py b/tests/testdata/python2/data/all.py deleted file mode 100644 index 23f7d2b6..00000000 --- a/tests/testdata/python2/data/all.py +++ /dev/null @@ -1,9 +0,0 @@ - -name = 'a' -_bla = 2 -other = 'o' -class Aaa: pass - -def func(): print 'yo' - -__all__ = 'Aaa', '_bla', 'name' diff --git a/tests/testdata/python2/data/appl/__init__.py b/tests/testdata/python2/data/appl/__init__.py deleted file mode 100644 index d652ffd9..00000000 --- a/tests/testdata/python2/data/appl/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -""" -Init -""" diff --git a/tests/testdata/python2/data/appl/myConnection.py b/tests/testdata/python2/data/appl/myConnection.py deleted file mode 100644 index 5b24b259..00000000 --- a/tests/testdata/python2/data/appl/myConnection.py +++ /dev/null @@ -1,12 +0,0 @@ -from __future__ import print_function -from data import SSL1 -class MyConnection(SSL1.Connection): - - """An SSL connection.""" - - def __init__(self, dummy): - print('MyConnection init') - -if __name__ == '__main__': - myConnection = MyConnection(' ') - raw_input('Press Enter to continue...') diff --git a/tests/testdata/python2/data/contribute_to_namespace/namespace_pep_420/submodule.py b/tests/testdata/python2/data/contribute_to_namespace/namespace_pep_420/submodule.py deleted file mode 100644 index 6fbcff41..00000000 --- a/tests/testdata/python2/data/contribute_to_namespace/namespace_pep_420/submodule.py +++ /dev/null @@ -1 +0,0 @@ -var = 42
\ No newline at end of file diff --git a/tests/testdata/python2/data/descriptor_crash.py b/tests/testdata/python2/data/descriptor_crash.py deleted file mode 100644 index 11fbb4a2..00000000 --- a/tests/testdata/python2/data/descriptor_crash.py +++ /dev/null @@ -1,11 +0,0 @@ - -import urllib - -class Page(object): - _urlOpen = staticmethod(urllib.urlopen) - - def getPage(self, url): - handle = self._urlOpen(url) - data = handle.read() - handle.close() - return data diff --git a/tests/testdata/python2/data/email.py b/tests/testdata/python2/data/email.py deleted file mode 100644 index dc593564..00000000 --- a/tests/testdata/python2/data/email.py +++ /dev/null @@ -1 +0,0 @@ -"""fake email module to test absolute import doesn't grab this one""" diff --git a/tests/testdata/python2/data/find_test/module.py b/tests/testdata/python2/data/find_test/module.py deleted file mode 100644 index e69de29b..00000000 --- a/tests/testdata/python2/data/find_test/module.py +++ /dev/null diff --git a/tests/testdata/python2/data/find_test/module2.py b/tests/testdata/python2/data/find_test/module2.py deleted file mode 100644 index e69de29b..00000000 --- a/tests/testdata/python2/data/find_test/module2.py +++ /dev/null diff --git a/tests/testdata/python2/data/find_test/noendingnewline.py b/tests/testdata/python2/data/find_test/noendingnewline.py deleted file mode 100644 index e69de29b..00000000 --- a/tests/testdata/python2/data/find_test/noendingnewline.py +++ /dev/null diff --git a/tests/testdata/python2/data/find_test/nonregr.py b/tests/testdata/python2/data/find_test/nonregr.py deleted file mode 100644 index e69de29b..00000000 --- a/tests/testdata/python2/data/find_test/nonregr.py +++ /dev/null diff --git a/tests/testdata/python2/data/foogle/fax/__init__.py b/tests/testdata/python2/data/foogle/fax/__init__.py deleted file mode 100644 index e69de29b..00000000 --- a/tests/testdata/python2/data/foogle/fax/__init__.py +++ /dev/null diff --git a/tests/testdata/python2/data/foogle/fax/a.py b/tests/testdata/python2/data/foogle/fax/a.py deleted file mode 100644 index 3d2b4b14..00000000 --- a/tests/testdata/python2/data/foogle/fax/a.py +++ /dev/null @@ -1 +0,0 @@ -x = 1
\ No newline at end of file diff --git a/tests/testdata/python2/data/foogle_fax-0.12.5-py2.7-nspkg.pth b/tests/testdata/python2/data/foogle_fax-0.12.5-py2.7-nspkg.pth deleted file mode 100644 index eeb7ecac..00000000 --- a/tests/testdata/python2/data/foogle_fax-0.12.5-py2.7-nspkg.pth +++ /dev/null @@ -1,2 +0,0 @@ -import sys, types, os;p = os.path.join(sys._getframe(1).f_locals['sitedir'], *('foogle',));ie = os.path.exists(os.path.join(p,'__init__.py'));m = not ie and sys.modules.setdefault('foogle', types.ModuleType('foogle'));mp = (m or []) and m.__dict__.setdefault('__path__',[]);(p not in mp) and mp.append(p) -import sys, types, os;p = os.path.join(sys._getframe(1).f_locals['sitedir'], *('foogle','crank'));ie = os.path.exists(os.path.join(p,'__init__.py'));m = not ie and sys.modules.setdefault('foogle.crank', types.ModuleType('foogle.crank'));mp = (m or []) and m.__dict__.setdefault('__path__',[]);(p not in mp) and mp.append(p) diff --git a/tests/testdata/python2/data/format.py b/tests/testdata/python2/data/format.py deleted file mode 100644 index 73797061..00000000 --- a/tests/testdata/python2/data/format.py +++ /dev/null @@ -1,34 +0,0 @@ -"""A multiline string -""" - -function('aeozrijz\ -earzer', hop) -# XXX write test -x = [i for i in range(5) - if i % 4] - -fonction(1, - 2, - 3, - 4) - -def definition(a, - b, - c): - return a + b + c - -class debile(dict, - object): - pass - -if aaaa: pass -else: - aaaa,bbbb = 1,2 - aaaa,bbbb = bbbb,aaaa -# XXX write test -hop = \ - aaaa - - -__revision__.lower(); - diff --git a/tests/testdata/python2/data/invalid_encoding.py b/tests/testdata/python2/data/invalid_encoding.py deleted file mode 100644 index dddd208e..00000000 --- a/tests/testdata/python2/data/invalid_encoding.py +++ /dev/null @@ -1 +0,0 @@ -# -*- coding: lala -*-
\ No newline at end of file diff --git a/tests/testdata/python2/data/lmfp/__init__.py b/tests/testdata/python2/data/lmfp/__init__.py deleted file mode 100644 index 74b26b82..00000000 --- a/tests/testdata/python2/data/lmfp/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# force a "direct" python import -from . import foo diff --git a/tests/testdata/python2/data/lmfp/foo.py b/tests/testdata/python2/data/lmfp/foo.py deleted file mode 100644 index 8f7de1e8..00000000 --- a/tests/testdata/python2/data/lmfp/foo.py +++ /dev/null @@ -1,6 +0,0 @@ -import sys -if not getattr(sys, 'bar', None): - sys.just_once = [] -# there used to be two numbers here because -# of a load_module_from_path bug -sys.just_once.append(42) diff --git a/tests/testdata/python2/data/module.py b/tests/testdata/python2/data/module.py deleted file mode 100644 index 1205c1dd..00000000 --- a/tests/testdata/python2/data/module.py +++ /dev/null @@ -1,90 +0,0 @@ -"""test module for astroid -""" - -__revision__ = '$Id: module.py,v 1.2 2005-11-02 11:56:54 syt Exp $' -from astroid.node_classes import Name as NameNode -from astroid import modutils -from astroid.utils import * -import os.path -MY_DICT = {} - -def global_access(key, val): - """function test""" - local = 1 - MY_DICT[key] = val - for i in val: - if i: - del MY_DICT[i] - continue - else: - break - else: - return local - - -class YO: - """hehe - haha""" - a = 1 - - def __init__(self): - try: - self.yo = 1 - except ValueError, ex: - pass - except (NameError, TypeError): - raise XXXError() - except: - raise - - - -class YOUPI(YO): - class_attr = None - - def __init__(self): - self.member = None - - def method(self): - """method - test""" - global MY_DICT - try: - MY_DICT = {} - local = None - autre = [a for (a, b) in MY_DICT if b] - if b in autre: - return b - elif a in autre: - return a - global_access(local, val=autre) - finally: - return local - - def static_method(): - """static method test""" - assert MY_DICT, '???' - static_method = staticmethod(static_method) - - def class_method(cls): - """class method test""" - exec a in b - class_method = classmethod(class_method) - - -def four_args(a, b, c, d): - """four arguments (was nested_args)""" - pass - while 1: - if a: - break - a += +1 - else: - b += -2 - if c: - d = a and (b or c) - else: - c = a and b or d - map(lambda x, y: (y, x), a) -redirect = four_args - diff --git a/tests/testdata/python2/data/module1abs/__init__.py b/tests/testdata/python2/data/module1abs/__init__.py deleted file mode 100644 index 42949a44..00000000 --- a/tests/testdata/python2/data/module1abs/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -from __future__ import absolute_import, print_function -from . import core -from .core import * -print(sys.version) diff --git a/tests/testdata/python2/data/module1abs/core.py b/tests/testdata/python2/data/module1abs/core.py deleted file mode 100644 index de101117..00000000 --- a/tests/testdata/python2/data/module1abs/core.py +++ /dev/null @@ -1 +0,0 @@ -import sys diff --git a/tests/testdata/python2/data/module2.py b/tests/testdata/python2/data/module2.py deleted file mode 100644 index 7042a4c1..00000000 --- a/tests/testdata/python2/data/module2.py +++ /dev/null @@ -1,143 +0,0 @@ -from data.module import YO, YOUPI -import data - - -class Specialization(YOUPI, YO): - pass - - - -class Metaclass(type): - pass - - - -class Interface: - pass - - - -class MyIFace(Interface): - pass - - - -class AnotherIFace(Interface): - pass - - - -class MyException(Exception): - pass - - - -class MyError(MyException): - pass - - - -class AbstractClass(object): - - def to_override(self, whatever): - raise NotImplementedError() - - def return_something(self, param): - if param: - return 'toto' - return - - - -class Concrete0: - __implements__ = MyIFace - - - -class Concrete1: - __implements__ = (MyIFace, AnotherIFace) - - - -class Concrete2: - __implements__ = (MyIFace, AnotherIFace) - - - -class Concrete23(Concrete1): - pass - -del YO.member -del YO -[SYN1, SYN2] = (Concrete0, Concrete1) -assert '1' -b = (1 | 2) & (3 ^ 8) -bb = 1 | (two | 6) -ccc = one & two & three -dddd = x ^ (o ^ r) -exec 'c = 3' -exec 'c = 3' in {}, {} - -def raise_string(a=2, *args, **kwargs): - raise Exception, 'yo' - yield 'coucou' - yield -a = b + 2 -c = b * 2 -c = b / 2 -c = b // 2 -c = b - 2 -c = b % 2 -c = b**2 -c = b << 2 -c = b >> 2 -c = ~b -c = not b -d = [c] -e = d[:] -e = d[a:b:c] -raise_string(*args, **kwargs) -print >> stream, 'bonjour' -print >> stream, 'salut', - -def make_class(any, base=data.module.YO, *args, **kwargs): - """check base is correctly resolved to Concrete0""" - - - class Aaaa(base): - """dynamic class""" - - - return Aaaa -from os.path import abspath -import os as myos - - -class A: - pass - - - -class A(A): - pass - - -def generator(): - """A generator.""" - yield - -def not_a_generator(): - """A function that contains generator, but is not one.""" - - def generator(): - yield - genl = lambda: (yield) - -def with_metaclass(meta, *bases): - return meta('NewBase', bases, {}) - - -class NotMetaclass(with_metaclass(Metaclass)): - pass - - diff --git a/tests/testdata/python2/data/namespace_pep_420/module.py b/tests/testdata/python2/data/namespace_pep_420/module.py deleted file mode 100644 index a4d111e6..00000000 --- a/tests/testdata/python2/data/namespace_pep_420/module.py +++ /dev/null @@ -1 +0,0 @@ -from namespace_pep_420.submodule import var
\ No newline at end of file diff --git a/tests/testdata/python2/data/noendingnewline.py b/tests/testdata/python2/data/noendingnewline.py deleted file mode 100644 index e1d6e4a1..00000000 --- a/tests/testdata/python2/data/noendingnewline.py +++ /dev/null @@ -1,36 +0,0 @@ -import unittest - - -class TestCase(unittest.TestCase): - - def setUp(self): - unittest.TestCase.setUp(self) - - - def tearDown(self): - unittest.TestCase.tearDown(self) - - def testIt(self): - self.a = 10 - self.xxx() - - - def xxx(self): - if False: - pass - print 'a' - - if False: - pass - pass - - if False: - pass - print 'rara' - - -if __name__ == '__main__': - print 'test2' - unittest.main() - - diff --git a/tests/testdata/python2/data/nonregr.py b/tests/testdata/python2/data/nonregr.py deleted file mode 100644 index 813469fe..00000000 --- a/tests/testdata/python2/data/nonregr.py +++ /dev/null @@ -1,57 +0,0 @@ -from __future__ import generators, print_function - -try: - enumerate = enumerate -except NameError: - - def enumerate(iterable): - """emulates the python2.3 enumerate() function""" - i = 0 - for val in iterable: - yield i, val - i += 1 - -def toto(value): - for k, v in value: - print(v.get('yo')) - - -import imp -fp, mpath, desc = imp.find_module('optparse',a) -s_opt = imp.load_module('std_optparse', fp, mpath, desc) - -class OptionParser(s_opt.OptionParser): - - def parse_args(self, args=None, values=None, real_optparse=False): - if real_optparse: - pass -## return super(OptionParser, self).parse_args() - else: - import optcomp - optcomp.completion(self) - - -class Aaa(object): - """docstring""" - def __init__(self): - self.__setattr__('a','b') - pass - - def one_public(self): - """docstring""" - pass - - def another_public(self): - """docstring""" - pass - -class Ccc(Aaa): - """docstring""" - - class Ddd(Aaa): - """docstring""" - pass - - class Eee(Ddd): - """docstring""" - pass diff --git a/tests/testdata/python2/data/notall.py b/tests/testdata/python2/data/notall.py deleted file mode 100644 index 042491e0..00000000 --- a/tests/testdata/python2/data/notall.py +++ /dev/null @@ -1,7 +0,0 @@ -name = 'a' -_bla = 2 -other = 'o' -class Aaa: pass - -def func(): return 'yo' - diff --git a/tests/testdata/python2/data/notamodule/file.py b/tests/testdata/python2/data/notamodule/file.py deleted file mode 100644 index e69de29b..00000000 --- a/tests/testdata/python2/data/notamodule/file.py +++ /dev/null diff --git a/tests/testdata/python2/data/operator_precedence.py b/tests/testdata/python2/data/operator_precedence.py deleted file mode 100644 index 07a3c772..00000000 --- a/tests/testdata/python2/data/operator_precedence.py +++ /dev/null @@ -1,27 +0,0 @@ -assert not not True == True -assert (not False or True) == True -assert True or False and True -assert (True or False) and True - -assert True is not (False is True) == False -assert True is (not False is True == False) - -assert 1 + 2 + 3 == 6 -assert 5 - 4 + 3 == 4 -assert 4 - 5 - 6 == -7 -assert 7 - (8 - 9) == 8 -assert 2**3**4 == 2**81 -assert (2**3)**4 == 8**4 - -assert 1 + 2 if (0.5 if True else 0.2) else 1 if True else 2 == 3 -assert (0 if True else 1) if False else 2 == 2 -assert lambda x: x if (0 if False else 0) else 0 if False else 0 -assert (lambda x: x) if (0 if True else 0.2) else 1 if True else 2 == 1 - -assert ('1' + '2').replace('1', '3') == '32' -assert (lambda x: x)(1) == 1 -assert ([0] + [1])[1] == 1 -assert (lambda x: lambda: x + 1)(2)() == 3 - -f = lambda x, y, z: y(x, z) -assert f(1, lambda x, y: x + y[1], (2, 3)) == 4 diff --git a/tests/testdata/python2/data/package/__init__.py b/tests/testdata/python2/data/package/__init__.py deleted file mode 100644 index 575d18b1..00000000 --- a/tests/testdata/python2/data/package/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -"""package's __init__ file""" - - -from . import subpackage diff --git a/tests/testdata/python2/data/package/absimport.py b/tests/testdata/python2/data/package/absimport.py deleted file mode 100644 index 33ed117c..00000000 --- a/tests/testdata/python2/data/package/absimport.py +++ /dev/null @@ -1,6 +0,0 @@ -from __future__ import absolute_import, print_function -import import_package_subpackage_module # fail -print(import_package_subpackage_module) - -from . import hello as hola - diff --git a/tests/testdata/python2/data/package/hello.py b/tests/testdata/python2/data/package/hello.py deleted file mode 100644 index b154c844..00000000 --- a/tests/testdata/python2/data/package/hello.py +++ /dev/null @@ -1,2 +0,0 @@ -"""hello module""" - diff --git a/tests/testdata/python2/data/package/import_package_subpackage_module.py b/tests/testdata/python2/data/package/import_package_subpackage_module.py deleted file mode 100644 index ad442c16..00000000 --- a/tests/testdata/python2/data/package/import_package_subpackage_module.py +++ /dev/null @@ -1,49 +0,0 @@ -# pylint: disable-msg=I0011,C0301,W0611 -"""I found some of my scripts trigger off an AttributeError in pylint -0.8.1 (with common 0.12.0 and astroid 0.13.1). - -Traceback (most recent call last): - File "/usr/bin/pylint", line 4, in ? - lint.Run(sys.argv[1:]) - File "/usr/lib/python2.4/site-packages/pylint/lint.py", line 729, in __init__ - linter.check(args) - File "/usr/lib/python2.4/site-packages/pylint/lint.py", line 412, in check - self.check_file(filepath, modname, checkers) - File "/usr/lib/python2.4/site-packages/pylint/lint.py", line 426, in check_file - astroid = self._check_file(filepath, modname, checkers) - File "/usr/lib/python2.4/site-packages/pylint/lint.py", line 450, in _check_file - self.check_astroid_module(astroid, checkers) - File "/usr/lib/python2.4/site-packages/pylint/lint.py", line 494, in check_astroid_module - self.astroid_events(astroid, [checker for checker in checkers - File "/usr/lib/python2.4/site-packages/pylint/lint.py", line 511, in astroid_events - self.astroid_events(child, checkers, _reversed_checkers) - File "/usr/lib/python2.4/site-packages/pylint/lint.py", line 511, in astroid_events - self.astroid_events(child, checkers, _reversed_checkers) - File "/usr/lib/python2.4/site-packages/pylint/lint.py", line 508, in astroid_events - checker.visit(astroid) - File "/usr/lib/python2.4/site-packages/logilab/astroid/utils.py", line 84, in visit - method(node) - File "/usr/lib/python2.4/site-packages/pylint/checkers/variables.py", line 295, in visit_import - self._check_module_attrs(node, module, name_parts[1:]) - File "/usr/lib/python2.4/site-packages/pylint/checkers/variables.py", line 357, in _check_module_attrs - self.add_message('E0611', args=(name, module.name), -AttributeError: Import instance has no attribute 'name' - - -You can reproduce it by: -(1) create package structure like the following: - -package/ - __init__.py - subpackage/ - __init__.py - module.py - -(2) in package/__init__.py write: - -import subpackage - -(3) run pylint with a script importing package.subpackage.module. -""" -__revision__ = '$Id: import_package_subpackage_module.py,v 1.1 2005-11-10 15:59:32 syt Exp $' -import package.subpackage.module diff --git a/tests/testdata/python2/data/package/subpackage/__init__.py b/tests/testdata/python2/data/package/subpackage/__init__.py deleted file mode 100644 index dc4782e6..00000000 --- a/tests/testdata/python2/data/package/subpackage/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""package.subpackage""" diff --git a/tests/testdata/python2/data/package/subpackage/module.py b/tests/testdata/python2/data/package/subpackage/module.py deleted file mode 100644 index 4b7244ba..00000000 --- a/tests/testdata/python2/data/package/subpackage/module.py +++ /dev/null @@ -1 +0,0 @@ -"""package.subpackage.module""" diff --git a/tests/testdata/python2/data/path_pkg_resources_1/package/__init__.py b/tests/testdata/python2/data/path_pkg_resources_1/package/__init__.py deleted file mode 100644 index b0d64337..00000000 --- a/tests/testdata/python2/data/path_pkg_resources_1/package/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__import__('pkg_resources').declare_namespace(__name__)
\ No newline at end of file diff --git a/tests/testdata/python2/data/path_pkg_resources_1/package/foo.py b/tests/testdata/python2/data/path_pkg_resources_1/package/foo.py deleted file mode 100644 index e69de29b..00000000 --- a/tests/testdata/python2/data/path_pkg_resources_1/package/foo.py +++ /dev/null diff --git a/tests/testdata/python2/data/path_pkg_resources_2/package/__init__.py b/tests/testdata/python2/data/path_pkg_resources_2/package/__init__.py deleted file mode 100644 index b0d64337..00000000 --- a/tests/testdata/python2/data/path_pkg_resources_2/package/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__import__('pkg_resources').declare_namespace(__name__)
\ No newline at end of file diff --git a/tests/testdata/python2/data/path_pkg_resources_2/package/bar.py b/tests/testdata/python2/data/path_pkg_resources_2/package/bar.py deleted file mode 100644 index e69de29b..00000000 --- a/tests/testdata/python2/data/path_pkg_resources_2/package/bar.py +++ /dev/null diff --git a/tests/testdata/python2/data/path_pkg_resources_3/package/__init__.py b/tests/testdata/python2/data/path_pkg_resources_3/package/__init__.py deleted file mode 100644 index b0d64337..00000000 --- a/tests/testdata/python2/data/path_pkg_resources_3/package/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__import__('pkg_resources').declare_namespace(__name__)
\ No newline at end of file diff --git a/tests/testdata/python2/data/path_pkg_resources_3/package/baz.py b/tests/testdata/python2/data/path_pkg_resources_3/package/baz.py deleted file mode 100644 index e69de29b..00000000 --- a/tests/testdata/python2/data/path_pkg_resources_3/package/baz.py +++ /dev/null diff --git a/tests/testdata/python2/data/path_pkgutil_1/package/__init__.py b/tests/testdata/python2/data/path_pkgutil_1/package/__init__.py deleted file mode 100644 index 0bfb5a62..00000000 --- a/tests/testdata/python2/data/path_pkgutil_1/package/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from pkgutil import extend_path -__path__ = extend_path(__path__, __name__)
\ No newline at end of file diff --git a/tests/testdata/python2/data/path_pkgutil_1/package/foo.py b/tests/testdata/python2/data/path_pkgutil_1/package/foo.py deleted file mode 100644 index e69de29b..00000000 --- a/tests/testdata/python2/data/path_pkgutil_1/package/foo.py +++ /dev/null diff --git a/tests/testdata/python2/data/path_pkgutil_2/package/__init__.py b/tests/testdata/python2/data/path_pkgutil_2/package/__init__.py deleted file mode 100644 index 0bfb5a62..00000000 --- a/tests/testdata/python2/data/path_pkgutil_2/package/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from pkgutil import extend_path -__path__ = extend_path(__path__, __name__)
\ No newline at end of file diff --git a/tests/testdata/python2/data/path_pkgutil_2/package/bar.py b/tests/testdata/python2/data/path_pkgutil_2/package/bar.py deleted file mode 100644 index e69de29b..00000000 --- a/tests/testdata/python2/data/path_pkgutil_2/package/bar.py +++ /dev/null diff --git a/tests/testdata/python2/data/path_pkgutil_3/package/__init__.py b/tests/testdata/python2/data/path_pkgutil_3/package/__init__.py deleted file mode 100644 index 0bfb5a62..00000000 --- a/tests/testdata/python2/data/path_pkgutil_3/package/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from pkgutil import extend_path -__path__ = extend_path(__path__, __name__)
\ No newline at end of file diff --git a/tests/testdata/python2/data/path_pkgutil_3/package/baz.py b/tests/testdata/python2/data/path_pkgutil_3/package/baz.py deleted file mode 100644 index e69de29b..00000000 --- a/tests/testdata/python2/data/path_pkgutil_3/package/baz.py +++ /dev/null diff --git a/tests/testdata/python2/data/recursion.py b/tests/testdata/python2/data/recursion.py deleted file mode 100644 index a34dad32..00000000 --- a/tests/testdata/python2/data/recursion.py +++ /dev/null @@ -1,3 +0,0 @@ -""" For issue #25 """
-class Base(object):
- pass
\ No newline at end of file diff --git a/tests/testdata/python2/data/tmp__init__.py b/tests/testdata/python2/data/tmp__init__.py deleted file mode 100644 index e69de29b..00000000 --- a/tests/testdata/python2/data/tmp__init__.py +++ /dev/null diff --git a/tests/testdata/python2/data/unicode_package/__init__.py b/tests/testdata/python2/data/unicode_package/__init__.py deleted file mode 100644 index 713e5591..00000000 --- a/tests/testdata/python2/data/unicode_package/__init__.py +++ /dev/null @@ -1 +0,0 @@ -x = "șțîâ"
\ No newline at end of file diff --git a/tests/testdata/python2/data/unicode_package/core/__init__.py b/tests/testdata/python2/data/unicode_package/core/__init__.py deleted file mode 100644 index e69de29b..00000000 --- a/tests/testdata/python2/data/unicode_package/core/__init__.py +++ /dev/null diff --git a/tests/testdata/python2/data/find_test/__init__.py b/tests/testdata/python3/data/metaclass_recursion/__init__.py index e69de29b..e69de29b 100644 --- a/tests/testdata/python2/data/find_test/__init__.py +++ b/tests/testdata/python3/data/metaclass_recursion/__init__.py diff --git a/tests/testdata/python3/data/metaclass_recursion/monkeypatch.py b/tests/testdata/python3/data/metaclass_recursion/monkeypatch.py new file mode 100644 index 00000000..757bb3f8 --- /dev/null +++ b/tests/testdata/python3/data/metaclass_recursion/monkeypatch.py @@ -0,0 +1,17 @@ +# https://github.com/PyCQA/astroid/issues/749 +# Not an actual module but allows us to reproduce the issue +from tests.testdata.python3.data.metaclass_recursion import parent + +class MonkeyPatchClass(parent.OriginalClass): + _original_class = parent.OriginalClass + + @classmethod + def patch(cls): + if parent.OriginalClass != MonkeyPatchClass: + cls._original_class = parent.OriginalClass + parent.OriginalClass = MonkeyPatchClass + + @classmethod + def unpatch(cls): + if parent.OriginalClass == MonkeyPatchClass: + parent.OriginalClass = cls._original_class diff --git a/tests/testdata/python3/data/metaclass_recursion/parent.py b/tests/testdata/python3/data/metaclass_recursion/parent.py new file mode 100644 index 00000000..5cff73e0 --- /dev/null +++ b/tests/testdata/python3/data/metaclass_recursion/parent.py @@ -0,0 +1,3 @@ +# https://github.com/PyCQA/astroid/issues/749 +class OriginalClass: + pass diff --git a/tests/unittest_brain.py b/tests/unittest_brain.py index 1a082d12..0a833664 100644 --- a/tests/unittest_brain.py +++ b/tests/unittest_brain.py @@ -1,20 +1,28 @@ # -*- coding: utf-8 -*- # Copyright (c) 2013-2014 Google, Inc. -# Copyright (c) 2014-2018 Claudiu Popa <pcmanticore@gmail.com> +# Copyright (c) 2014-2020 Claudiu Popa <pcmanticore@gmail.com> # Copyright (c) 2015-2016 Ceridwen <ceridwenv@gmail.com> # Copyright (c) 2015 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr> # Copyright (c) 2015 raylu <lurayl@gmail.com> # Copyright (c) 2015 Philip Lorenz <philip@bithub.de> # Copyright (c) 2016 Florian Bruhin <me@the-compiler.org> -# Copyright (c) 2017 Łukasz Rogalski <rogalski.91@gmail.com> # Copyright (c) 2017-2018 Bryce Guinta <bryce.paul.guinta@gmail.com> -# Copyright (c) 2017 hippo91 <guillaume.peillex@gmail.com> +# Copyright (c) 2017-2018 hippo91 <guillaume.peillex@gmail.com> +# Copyright (c) 2017 Łukasz Rogalski <rogalski.91@gmail.com> # Copyright (c) 2017 David Euresti <github@euresti.com> # Copyright (c) 2017 Derek Gustafson <degustaf@gmail.com> +# Copyright (c) 2018 Tomas Gavenciak <gavento@ucw.cz> +# Copyright (c) 2018 David Poirier <david-poirier-csn@users.noreply.github.com> +# Copyright (c) 2018 Ville Skyttä <ville.skytta@iki.fi> # Copyright (c) 2018 Nick Drozd <nicholasdrozd@gmail.com> # Copyright (c) 2018 Anthony Sottile <asottile@umich.edu> # Copyright (c) 2018 Ioana Tagirta <ioana.tagirta@gmail.com> # Copyright (c) 2018 Ahmed Azzaoui <ahmed.azzaoui@engie.com> +# Copyright (c) 2019 Ashley Whetter <ashley@awhetter.co.uk> +# Copyright (c) 2019 Tomas Novak <ext.Tomas.Novak@skoda-auto.cz> +# Copyright (c) 2019 Hugo van Kemenade <hugovk@users.noreply.github.com> +# Copyright (c) 2019 Grygorii Iermolenko <gyermolenko@gmail.com> +# Copyright (c) 2019 Bryce Guinta <bryce.guinta@protonmail.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 @@ -323,6 +331,18 @@ class NamedTupleTest(unittest.TestCase): self.assertIsInstance(inferred.bases[0], astroid.Name) self.assertEqual(inferred.bases[0].name, "tuple") + def test_invalid_label_does_not_crash_inference(self): + code = """ + import collections + a = collections.namedtuple( 'a', ['b c'] ) + a + """ + node = builder.extract_node(code) + inferred = next(node.infer()) + assert isinstance(inferred, astroid.ClassDef) + assert "b" not in inferred.locals + assert "c" not in inferred.locals + class DefaultDictTest(unittest.TestCase): def test_1(self): @@ -622,6 +642,21 @@ class EnumBrainTest(unittest.TestCase): test = next(enumeration.igetattr("test")) self.assertEqual(test.value, 42) + def test_ignores_with_nodes_from_body_of_enum(self): + code = """ + import enum + + class Error(enum.Enum): + Foo = "foo" + Bar = "bar" + with "error" as err: + pass + """ + node = builder.extract_node(code) + inferred = next(node.infer()) + assert "err" in inferred.locals + assert len(inferred.locals["err"]) == 1 + def test_enum_multiple_base_classes(self): module = builder.parse( """ @@ -1633,10 +1668,13 @@ class TestLenBuiltinInference: ) assert next(node.infer()).as_string() == "3" - @pytest.mark.xfail(reason="Can't retrieve subclassed type value ") def test_int_subclass_result(self): - """I am unable to figure out the value of an - object which subclasses int""" + """Check that a subclass of an int can still be inferred + + This test does not properly infer the value passed to the + int subclass (5) but still returns a proper integer as we + fake the result of the `len()` call. + """ node = astroid.extract_node( """ class IntSubclass(int): @@ -1648,7 +1686,7 @@ class TestLenBuiltinInference: len(F()) """ ) - assert next(node.infer()).as_string() == "5" + assert next(node.infer()).as_string() == "0" @pytest.mark.xfail(reason="Can't use list special astroid fields") def test_int_subclass_argument(self): diff --git a/tests/unittest_brain_numpy_core_fromnumeric.py b/tests/unittest_brain_numpy_core_fromnumeric.py index 16d73e2e..fd571f30 100644 --- a/tests/unittest_brain_numpy_core_fromnumeric.py +++ b/tests/unittest_brain_numpy_core_fromnumeric.py @@ -1,5 +1,6 @@ # -*- encoding=utf-8 -*- -# Copyright (c) 2017-2018 hippo91 <guillaume.peillex@gmail.com> +# Copyright (c) 2019 Ashley Whetter <ashley@awhetter.co.uk> +# Copyright (c) 2019 hippo91 <guillaume.peillex@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 diff --git a/tests/unittest_brain_numpy_core_function_base.py b/tests/unittest_brain_numpy_core_function_base.py index 06a940c8..109238a2 100644 --- a/tests/unittest_brain_numpy_core_function_base.py +++ b/tests/unittest_brain_numpy_core_function_base.py @@ -1,5 +1,6 @@ # -*- encoding=utf-8 -*- -# Copyright (c) 2017-2018 hippo91 <guillaume.peillex@gmail.com> +# Copyright (c) 2019 Ashley Whetter <ashley@awhetter.co.uk> +# Copyright (c) 2019 hippo91 <guillaume.peillex@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 diff --git a/tests/unittest_brain_numpy_core_multiarray.py b/tests/unittest_brain_numpy_core_multiarray.py index e02db6cc..9e945d21 100644 --- a/tests/unittest_brain_numpy_core_multiarray.py +++ b/tests/unittest_brain_numpy_core_multiarray.py @@ -1,5 +1,6 @@ # -*- encoding=utf-8 -*- -# Copyright (c) 2017-2018 hippo91 <guillaume.peillex@gmail.com> +# Copyright (c) 2019 hippo91 <guillaume.peillex@gmail.com> +# Copyright (c) 2019 Ashley Whetter <ashley@awhetter.co.uk> # 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 diff --git a/tests/unittest_brain_numpy_core_numeric.py b/tests/unittest_brain_numpy_core_numeric.py index 56b7d0d6..a39fb19e 100644 --- a/tests/unittest_brain_numpy_core_numeric.py +++ b/tests/unittest_brain_numpy_core_numeric.py @@ -1,5 +1,6 @@ # -*- encoding=utf-8 -*- -# Copyright (c) 2017-2018 hippo91 <guillaume.peillex@gmail.com> +# Copyright (c) 2019 Ashley Whetter <ashley@awhetter.co.uk> +# Copyright (c) 2019 hippo91 <guillaume.peillex@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 diff --git a/tests/unittest_brain_numpy_core_numerictypes.py b/tests/unittest_brain_numpy_core_numerictypes.py index 768a5570..db4fdd23 100644 --- a/tests/unittest_brain_numpy_core_numerictypes.py +++ b/tests/unittest_brain_numpy_core_numerictypes.py @@ -1,7 +1,8 @@ # -*- encoding=utf-8 -*- -# Copyright (c) 2017-2018 hippo91 <guillaume.peillex@gmail.com> -# Copyright (c) 2017 Claudiu Popa <pcmanticore@gmail.com> +# Copyright (c) 2017-2020 hippo91 <guillaume.peillex@gmail.com> +# Copyright (c) 2017-2018 Claudiu Popa <pcmanticore@gmail.com> # Copyright (c) 2018 Bryce Guinta <bryce.paul.guinta@gmail.com> +# Copyright (c) 2019 Ashley Whetter <ashley@awhetter.co.uk> # 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 @@ -314,6 +315,34 @@ class NumpyBrainCoreNumericTypesTest(unittest.TestCase): with self.subTest(attr=attr): self.assertNotEqual(len(inferred.getattr(attr)), 0) + def test_datetime_astype_return(self): + """ + Test that the return of astype method of the datetime object + is inferred as a ndarray. + + PyCQA/pylint#3332 + """ + node = builder.extract_node( + """ + import numpy as np + import datetime + test_array = np.datetime64(1, 'us') + test_array.astype(datetime.datetime) + """ + ) + licit_array_types = ".ndarray" + inferred_values = list(node.infer()) + self.assertTrue( + len(inferred_values) == 1, + msg="Too much inferred value for {:s}".format("datetime64.astype"), + ) + self.assertTrue( + inferred_values[-1].pytype() in licit_array_types, + msg="Illicit type for {:s} ({})".format( + "datetime64.astype", inferred_values[-1].pytype() + ), + ) + if __name__ == "__main__": unittest.main() diff --git a/tests/unittest_brain_numpy_core_umath.py b/tests/unittest_brain_numpy_core_umath.py index e6fb1c5e..3db3f149 100644 --- a/tests/unittest_brain_numpy_core_umath.py +++ b/tests/unittest_brain_numpy_core_umath.py @@ -1,5 +1,6 @@ # -*- encoding=utf-8 -*- -# Copyright (c) 2017-2018 hippo91 <guillaume.peillex@gmail.com> +# Copyright (c) 2019 hippo91 <guillaume.peillex@gmail.com> +# Copyright (c) 2019 Ashley Whetter <ashley@awhetter.co.uk> # 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 diff --git a/tests/unittest_brain_numpy_ndarray.py b/tests/unittest_brain_numpy_ndarray.py index d982f7f6..defce47d 100644 --- a/tests/unittest_brain_numpy_ndarray.py +++ b/tests/unittest_brain_numpy_ndarray.py @@ -1,7 +1,8 @@ # -*- encoding=utf-8 -*- -# Copyright (c) 2017-2018 hippo91 <guillaume.peillex@gmail.com> -# Copyright (c) 2017 Claudiu Popa <pcmanticore@gmail.com> +# Copyright (c) 2017-2020 hippo91 <guillaume.peillex@gmail.com> +# Copyright (c) 2017-2018 Claudiu Popa <pcmanticore@gmail.com> # Copyright (c) 2018 Bryce Guinta <bryce.paul.guinta@gmail.com> +# Copyright (c) 2019 Ashley Whetter <ashley@awhetter.co.uk> # 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 @@ -117,6 +118,18 @@ class NumpyBrainNdarrayTest(unittest.TestCase): ) return node.infer() + def _inferred_ndarray_attribute(self, attr_name): + node = builder.extract_node( + """ + import numpy as np + test_array = np.ndarray((2, 2)) + test_array.{:s} + """.format( + attr_name + ) + ) + return node.infer() + def test_numpy_function_calls_inferred_as_ndarray(self): """ Test that some calls to numpy functions are inferred as numpy.ndarray @@ -136,6 +149,25 @@ class NumpyBrainNdarrayTest(unittest.TestCase): ), ) + def test_numpy_ndarray_attribute_inferred_as_ndarray(self): + """ + Test that some numpy ndarray attributes are inferred as numpy.ndarray + """ + licit_array_types = ".ndarray" + for attr_ in ("real", "imag"): + with self.subTest(typ=attr_): + inferred_values = list(self._inferred_ndarray_attribute(attr_)) + self.assertTrue( + len(inferred_values) == 1, + msg="Too much inferred value for {:s}".format(attr_), + ) + self.assertTrue( + inferred_values[-1].pytype() in licit_array_types, + msg="Illicit type for {:s} ({})".format( + attr_, inferred_values[-1].pytype() + ), + ) + if __name__ == "__main__": unittest.main() diff --git a/tests/unittest_brain_numpy_random_mtrand.py b/tests/unittest_brain_numpy_random_mtrand.py index 4ca296f1..20a5d310 100644 --- a/tests/unittest_brain_numpy_random_mtrand.py +++ b/tests/unittest_brain_numpy_random_mtrand.py @@ -1,7 +1,6 @@ # -*- encoding=utf-8 -*- -# Copyright (c) 2017-2018 hippo91 <guillaume.peillex@gmail.com> -# Copyright (c) 2017 Claudiu Popa <pcmanticore@gmail.com> -# Copyright (c) 2018 Bryce Guinta <bryce.paul.guinta@gmail.com> +# Copyright (c) 2019 Ashley Whetter <ashley@awhetter.co.uk> +# Copyright (c) 2019 hippo91 <guillaume.peillex@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 diff --git a/tests/unittest_builder.py b/tests/unittest_builder.py index 9ea597c8..22e49e60 100644 --- a/tests/unittest_builder.py +++ b/tests/unittest_builder.py @@ -1,14 +1,17 @@ # -*- coding: utf-8 -*- # Copyright (c) 2006-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr> -# Copyright (c) 2014-2018 Claudiu Popa <pcmanticore@gmail.com> +# Copyright (c) 2014-2019 Claudiu Popa <pcmanticore@gmail.com> # Copyright (c) 2014-2015 Google, Inc. # Copyright (c) 2015-2016 Ceridwen <ceridwenv@gmail.com> # Copyright (c) 2015 Florian Bruhin <me@the-compiler.org> # Copyright (c) 2016 Jakub Wilk <jwilk@jwilk.net> # Copyright (c) 2017 Bryce Guinta <bryce.paul.guinta@gmail.com> # Copyright (c) 2017 Łukasz Rogalski <rogalski.91@gmail.com> +# Copyright (c) 2018 Ville Skyttä <ville.skytta@iki.fi> # Copyright (c) 2018 brendanator <brendan.maginnis@gmail.com> # Copyright (c) 2018 Anthony Sottile <asottile@umich.edu> +# Copyright (c) 2019 Ashley Whetter <ashley@awhetter.co.uk> +# Copyright (c) 2019 Hugo van Kemenade <hugovk@users.noreply.github.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 diff --git a/tests/unittest_helpers.py b/tests/unittest_helpers.py index 8ed07ede..ced5fc0a 100644 --- a/tests/unittest_helpers.py +++ b/tests/unittest_helpers.py @@ -1,5 +1,6 @@ -# Copyright (c) 2015-2016, 2018 Claudiu Popa <pcmanticore@gmail.com> +# Copyright (c) 2015-2016, 2018, 2020 Claudiu Popa <pcmanticore@gmail.com> # Copyright (c) 2015-2016 Ceridwen <ceridwenv@gmail.com> +# Copyright (c) 2019 Ashley Whetter <ashley@awhetter.co.uk> # 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 @@ -192,21 +193,6 @@ class TestHelpers(unittest.TestCase): self.assertFalse(helpers.is_subtype(cls_a, cls_b)) self.assertFalse(helpers.is_subtype(cls_a, cls_b)) - @test_utils.require_version(maxver="3.0") - def test_is_subtype_supertype_old_style_classes(self): - cls_a, cls_b = builder.extract_node( - """ - class A: #@ - pass - class B(A): #@ - pass - """ - ) - self.assertFalse(helpers.is_subtype(cls_a, cls_b)) - self.assertFalse(helpers.is_subtype(cls_b, cls_a)) - self.assertFalse(helpers.is_supertype(cls_a, cls_b)) - self.assertFalse(helpers.is_supertype(cls_b, cls_a)) - def test_is_subtype_supertype_mro_error(self): cls_e, cls_f = builder.extract_node( """ diff --git a/tests/unittest_inference.py b/tests/unittest_inference.py index b541eb28..b3df5f6c 100644 --- a/tests/unittest_inference.py +++ b/tests/unittest_inference.py @@ -2,7 +2,7 @@ # Copyright (c) 2006-2015 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr> # Copyright (c) 2007 Marien Zwart <marienz@gentoo.org> # Copyright (c) 2013-2014 Google, Inc. -# Copyright (c) 2014-2018 Claudiu Popa <pcmanticore@gmail.com> +# Copyright (c) 2014-2020 Claudiu Popa <pcmanticore@gmail.com> # Copyright (c) 2014 Eevee (Alex Munroe) <amunroe@yelp.com> # Copyright (c) 2015-2016 Ceridwen <ceridwenv@gmail.com> # Copyright (c) 2015 Dmitry Pribysh <dmand@yandex.ru> @@ -14,8 +14,14 @@ # Copyright (c) 2017 Calen Pennington <calen.pennington@gmail.com> # Copyright (c) 2017 David Euresti <david@dropbox.com> # Copyright (c) 2017 Derek Gustafson <degustaf@gmail.com> +# Copyright (c) 2018 Daniel Martin <daniel.martin@crowdstrike.com> +# Copyright (c) 2018 Ville Skyttä <ville.skytta@iki.fi> # Copyright (c) 2018 Bryce Guinta <bryce.paul.guinta@gmail.com> # Copyright (c) 2018 Anthony Sottile <asottile@umich.edu> +# Copyright (c) 2019 Stanislav Levin <slev@altlinux.org> +# Copyright (c) 2019 David Liu <david@cs.toronto.edu> +# Copyright (c) 2019 Ashley Whetter <ashley@awhetter.co.uk> +# Copyright (c) 2019 Hugo van Kemenade <hugovk@users.noreply.github.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 @@ -24,6 +30,7 @@ """ # pylint: disable=too-many-lines import platform +import textwrap from functools import partial import unittest from unittest.mock import patch @@ -499,18 +506,7 @@ class InferenceTest(resources.SysPathSetup, unittest.TestCase): self.assertEqual(inferred.name, "set") self.assertIn("remove", inferred._proxied.locals) - @test_utils.require_version(maxver="3.0") - def test_unicode_type(self): - code = '''u = u""''' - ast = parse(code, __name__) - n = ast["u"] - inferred = next(n.infer()) - self.assertIsInstance(inferred, nodes.Const) - self.assertIsInstance(inferred, Instance) - self.assertEqual(inferred.name, "unicode") - self.assertIn("lower", inferred._proxied.locals) - - @unittest.expectedFailure + @pytest.mark.xfail(reason="Descriptors are not properly inferred as callable") def test_descriptor_are_callable(self): code = """ class A: @@ -1701,7 +1697,9 @@ class InferenceTest(resources.SysPathSetup, unittest.TestCase): pass """ ) - self.assertIn("object", [base.name for base in klass.ancestors()]) + ancestors = [base.name for base in klass.ancestors()] + expected_subset = ["datetime", "date"] + self.assertEqual(expected_subset, ancestors[:2]) def test_stop_iteration_leak(self): code = """ @@ -3256,7 +3254,7 @@ class InferenceTest(resources.SysPathSetup, unittest.TestCase): self.assertIsInstance(inferred, Instance) self.assertEqual(inferred.name, "B") - @unittest.expectedFailure + @pytest.mark.xfail(reason="String interpolation is incorrect for modulo formatting") def test_string_interpolation(self): ast_nodes = extract_node( """ @@ -3628,7 +3626,7 @@ class InferenceTest(resources.SysPathSetup, unittest.TestCase): ] self.assertEqual(titles, ["Catch 22", "Ubik", "Grimus"]) - @unittest.expectedFailure + @pytest.mark.xfail(reason="Does not support function metaclasses") def test_function_metaclasses(self): # These are not supported right now, although # they will be in the future. @@ -3776,7 +3774,7 @@ class InferenceTest(resources.SysPathSetup, unittest.TestCase): second = next(ast_nodes[1].infer()) self.assertIsInstance(second, Instance) - @unittest.expectedFailure + @pytest.mark.xfail(reason="Metaclass arguments not inferred as classes") def test_metaclass_arguments_are_classes_not_instances(self): ast_node = extract_node( """ @@ -3859,19 +3857,6 @@ class InferenceTest(resources.SysPathSetup, unittest.TestCase): inferred.getattr("teta") inferred.getattr("a") - @test_utils.require_version(maxver="3.0") - def test_delayed_attributes_with_old_style_classes(self): - ast_node = extract_node( - """ - class A: - __slots__ = ('a', ) - a = A() - a.teta = 42 - a #@ - """ - ) - next(ast_node.infer()).getattr("teta") - def test_lambda_as_methods(self): ast_node = extract_node( """ @@ -3906,7 +3891,7 @@ class InferenceTest(resources.SysPathSetup, unittest.TestCase): self.assertIsInstance(inferred, nodes.Const) self.assertEqual(inferred.value, 25) - @unittest.expectedFailure + @pytest.mark.xfail(reason="Cannot reuse inner value due to inference context reuse") def test_inner_value_redefined_by_subclass_with_mro(self): # This might work, but it currently doesn't due to not being able # to reuse inference contexts. @@ -5169,10 +5154,25 @@ def test_builtin_inference_list_of_exceptions(): inferred = next(node.infer()) assert isinstance(inferred, nodes.Tuple) assert len(inferred.elts) == 2 - assert isinstance(inferred.elts[0], nodes.ClassDef) - assert inferred.elts[0].name == "ValueError" - assert isinstance(inferred.elts[1], nodes.ClassDef) - assert inferred.elts[1].name == "TypeError" + assert isinstance(inferred.elts[0], nodes.EvaluatedObject) + assert isinstance(inferred.elts[0].value, nodes.ClassDef) + assert inferred.elts[0].value.name == "ValueError" + assert isinstance(inferred.elts[1], nodes.EvaluatedObject) + assert isinstance(inferred.elts[1].value, nodes.ClassDef) + assert inferred.elts[1].value.name == "TypeError" + + # Test that inference of evaluated objects returns what is expected + first_elem = next(inferred.elts[0].infer()) + assert isinstance(first_elem, nodes.ClassDef) + assert first_elem.name == "ValueError" + + second_elem = next(inferred.elts[1].infer()) + assert isinstance(second_elem, nodes.ClassDef) + assert second_elem.name == "TypeError" + + # Test that as_string() also works + as_string = inferred.as_string() + assert as_string.strip() == "(ValueError, TypeError)" @test_utils.require_version(minver="3.6") @@ -5478,6 +5478,28 @@ def test_property_inference(): assert isinstance(inferred, nodes.FunctionDef) +def test_property_as_string(): + code = """ + class A: + @property + def test(self): + return 42 + + A.test #@ + """ + node = extract_node(code) + inferred = next(node.infer()) + assert isinstance(inferred, objects.Property) + property_body = textwrap.dedent( + """ + @property + def test(self): + return 42 + """ + ) + assert inferred.as_string().strip() == property_body.strip() + + def test_property_callable_inference(): code = """ class A: @@ -5517,5 +5539,330 @@ def test_recursion_error_inferring_builtin_containers(): helpers.safe_infer(node.targets[0]) +def test_inferaugassign_picking_parent_instead_of_stmt(): + code = """ + from collections import namedtuple + SomeClass = namedtuple('SomeClass', ['name']) + items = [SomeClass(name='some name')] + + some_str = '' + some_str += ', '.join(__(item) for item in items) + """ + # item needs to be inferrd as `SomeClass` but it was inferred + # as a string because the entire `AugAssign` node was inferred + # as a string. + node = extract_node(code) + inferred = next(node.infer()) + assert isinstance(inferred, Instance) + assert inferred.name == "SomeClass" + + +def test_classmethod_from_builtins_inferred_as_bound(): + code = """ + import builtins + + class Foo(): + @classmethod + def bar1(cls, text): + pass + + @builtins.classmethod + def bar2(cls, text): + pass + + Foo.bar1 #@ + Foo.bar2 #@ + """ + first_node, second_node = extract_node(code) + assert isinstance(next(first_node.infer()), BoundMethod) + assert isinstance(next(second_node.infer()), BoundMethod) + + +def test_infer_dict_passes_context(): + code = """ + k = {} + (_ for k in __(dict(**k))) + """ + node = extract_node(code) + inferred = next(node.infer()) + assert isinstance(inferred, Instance) + assert inferred.qname() == "builtins.dict" + + +@pytest.mark.parametrize( + "code,obj,obj_type", + [ + ( + """ + def klassmethod1(method): + @classmethod + def inner(cls): + return method(cls) + return inner + + class X(object): + @klassmethod1 + def x(cls): + return 'X' + X.x + """, + BoundMethod, + "classmethod", + ), + ( + """ + def staticmethod1(method): + @staticmethod + def inner(cls): + return method(cls) + return inner + + class X(object): + @staticmethod1 + def x(cls): + return 'X' + X.x + """, + nodes.FunctionDef, + "staticmethod", + ), + ( + """ + def klassmethod1(method): + def inner(cls): + return method(cls) + return classmethod(inner) + + class X(object): + @klassmethod1 + def x(cls): + return 'X' + X.x + """, + BoundMethod, + "classmethod", + ), + ( + """ + def staticmethod1(method): + def inner(cls): + return method(cls) + return staticmethod(inner) + + class X(object): + @staticmethod1 + def x(cls): + return 'X' + X.x + """, + nodes.FunctionDef, + "staticmethod", + ), + ], +) +def test_custom_decorators_for_classmethod_and_staticmethods(code, obj, obj_type): + node = extract_node(code) + inferred = next(node.infer()) + assert isinstance(inferred, obj) + assert inferred.type == obj_type + + +@pytest.mark.skipif(sys.version_info < (3, 8), reason="Needs dataclasses available") +def test_dataclasses_subscript_inference_recursion_error(): + code = """ + from dataclasses import dataclass, replace + + @dataclass + class ProxyConfig: + auth: str = "/auth" + + + a = ProxyConfig("") + test_dict = {"proxy" : {"auth" : "", "bla" : "f"}} + + foo = test_dict['proxy'] + replace(a, **test_dict['proxy']) # This fails + """ + node = extract_node(code) + # Reproduces only with safe_infer() + assert helpers.safe_infer(node) is None + + +def test_self_reference_infer_does_not_trigger_recursion_error(): + # Prevents https://github.com/PyCQA/pylint/issues/1285 + code = """ + def func(elems): + return elems + + class BaseModel(object): + + def __init__(self, *args, **kwargs): + self._reference = func(*self._reference.split('.')) + BaseModel()._reference + """ + node = extract_node(code) + inferred = next(node.infer()) + assert inferred is util.Uninferable + + +def test_inferring_properties_multiple_time_does_not_mutate_locals_multiple_times(): + code = """ + class A: + @property + def a(self): + return 42 + + A() + """ + node = extract_node(code) + # Infer the class + cls = next(node.infer()) + prop, = cls.getattr("a") + + # Try to infer the property function *multiple* times. `A.locals` should be modified only once + for _ in range(3): + prop.inferred() + a_locals = cls.locals["a"] + # [FunctionDef, Property] + assert len(a_locals) == 2 + + +def test_getattr_fails_on_empty_values(): + code = """ + import collections + collections + """ + node = extract_node(code) + inferred = next(node.infer()) + with pytest.raises(exceptions.InferenceError): + next(inferred.igetattr("")) + + with pytest.raises(exceptions.AttributeInferenceError): + inferred.getattr("") + + +def test_infer_first_argument_of_static_method_in_metaclass(): + code = """ + class My(type): + @staticmethod + def test(args): + args #@ + """ + node = extract_node(code) + inferred = next(node.infer()) + assert inferred is util.Uninferable + + +def test_recursion_error_metaclass_monkeypatching(): + module = resources.build_file( + "data/metaclass_recursion/monkeypatch.py", "data.metaclass_recursion" + ) + cls = next(module.igetattr("MonkeyPatchClass")) + assert isinstance(cls, nodes.ClassDef) + assert cls.declared_metaclass() is None + + +@pytest.mark.xfail(reason="Cannot fully infer all the base classes properly.") +def test_recursion_error_self_reference_type_call(): + # Fix for https://github.com/PyCQA/astroid/issues/199 + code = """ + class A(object): + pass + class SomeClass(object): + route_class = A + def __init__(self): + self.route_class = type('B', (self.route_class, ), {}) + self.route_class() #@ + """ + node = extract_node(code) + inferred = next(node.infer()) + assert isinstance(inferred, Instance) + assert inferred.name == "B" + # TODO: Cannot infer [B, A, object] but at least the recursion error is gone. + assert [cls.name for cls in inferred.mro()] == ["B", "A", "object"] + + +def test_allow_retrieving_instance_attrs_and_special_attrs_for_functions(): + code = """ + class A: + def test(self): + "a" + # Add `__doc__` to `FunctionDef.instance_attrs` via an `AugAssign` + test.__doc__ += 'b' + test #@ + """ + node = extract_node(code) + inferred = next(node.infer()) + attrs = inferred.getattr("__doc__") + # One from the `AugAssign`, one from the special attributes + assert len(attrs) == 2 + + +def test_implicit_parameters_bound_method(): + code = """ + class A(type): + @classmethod + def test(cls, first): return first + def __new__(cls, name, bases, dictionary): + return super().__new__(cls, name, bases, dictionary) + + A.test #@ + A.__new__ #@ + """ + test, dunder_new = extract_node(code) + test = next(test.infer()) + assert isinstance(test, BoundMethod) + assert test.implicit_parameters() == 1 + + dunder_new = next(dunder_new.infer()) + assert isinstance(dunder_new, BoundMethod) + assert dunder_new.implicit_parameters() == 0 + + +def test_super_inference_of_abstract_property(): + code = """ + from abc import abstractmethod + + class A: + @property + def test(self): + return "super" + + class C: + @property + @abstractmethod + def test(self): + "abstract method" + + class B(A, C): + + @property + def test(self): + super() #@ + + """ + node = extract_node(code) + inferred = next(node.infer()) + test = inferred.getattr("test") + assert len(test) == 2 + + +def test_infer_generated_setter(): + code = """ + class A: + @property + def test(self): + pass + A.test.setter + """ + node = extract_node(code) + inferred = next(node.infer()) + assert isinstance(inferred, nodes.FunctionDef) + assert isinstance(inferred.args, nodes.Arguments) + # This line used to crash because property generated functions + # did not have args properly set + assert list(inferred.nodes_of_class(nodes.Const)) == [] + + if __name__ == "__main__": unittest.main() diff --git a/tests/unittest_lookup.py b/tests/unittest_lookup.py index 58effd53..84fd5433 100644 --- a/tests/unittest_lookup.py +++ b/tests/unittest_lookup.py @@ -1,8 +1,10 @@ # Copyright (c) 2007-2013 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr> # Copyright (c) 2010 Daniel Harding <dharding@gmail.com> -# Copyright (c) 2014-2016, 2018 Claudiu Popa <pcmanticore@gmail.com> +# Copyright (c) 2014-2016, 2018-2019 Claudiu Popa <pcmanticore@gmail.com> # Copyright (c) 2014 Google, Inc. # Copyright (c) 2015-2016 Ceridwen <ceridwenv@gmail.com> +# Copyright (c) 2019 Ashley Whetter <ashley@awhetter.co.uk> +# Copyright (c) 2019 Hugo van Kemenade <hugovk@users.noreply.github.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 diff --git a/tests/unittest_manager.py b/tests/unittest_manager.py index b56a0580..d7878b59 100644 --- a/tests/unittest_manager.py +++ b/tests/unittest_manager.py @@ -1,12 +1,17 @@ +# -*- coding: utf-8 -*- # Copyright (c) 2006, 2009-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr> # Copyright (c) 2013 AndroWiiid <androwiiid@gmail.com> -# Copyright (c) 2014-2018 Claudiu Popa <pcmanticore@gmail.com> +# Copyright (c) 2014-2019 Claudiu Popa <pcmanticore@gmail.com> # Copyright (c) 2014 Google, Inc. # Copyright (c) 2015-2016 Ceridwen <ceridwenv@gmail.com> # Copyright (c) 2017 Chris Philip <chrisp533@gmail.com> # Copyright (c) 2017 Hugo <hugovk@users.noreply.github.com> # Copyright (c) 2017 ioanatia <ioanatia@users.noreply.github.com> +# Copyright (c) 2018 Ville Skyttä <ville.skytta@iki.fi> # Copyright (c) 2018 Bryce Guinta <bryce.paul.guinta@gmail.com> +# Copyright (c) 2019 Ashley Whetter <ashley@awhetter.co.uk> +# Copyright (c) 2019 Hugo van Kemenade <hugovk@users.noreply.github.com> +# Copyright (c) 2020 Anubhav <35621759+anubh-v@users.noreply.github.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 @@ -67,6 +72,17 @@ class AstroidManagerTest( exceptions.AstroidBuildingError, self.manager.ast_from_file, "unhandledName" ) + def test_ast_from_string(self): + filepath = unittest.__file__ + dirname = os.path.dirname(filepath) + modname = os.path.basename(dirname) + with open(filepath, "r") as file: + data = file.read() + ast = self.manager.ast_from_string(data, modname, filepath) + self.assertEqual(ast.name, "unittest") + self.assertEqual(ast.file, filepath) + self.assertIn("unittest", self.manager.astroid_cache) + def test_do_not_expose_main(self): obj = self.manager.ast_from_module_name("__main__") self.assertEqual(obj.name, "__main__") diff --git a/tests/unittest_modutils.py b/tests/unittest_modutils.py index 1747dc22..b5c41bf0 100644 --- a/tests/unittest_modutils.py +++ b/tests/unittest_modutils.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2014-2016 Claudiu Popa <pcmanticore@gmail.com> +# Copyright (c) 2014-2016, 2018-2020 Claudiu Popa <pcmanticore@gmail.com> # Copyright (c) 2014 Google, Inc. # Copyright (c) 2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr> # Copyright (c) 2015 Florian Bruhin <me@the-compiler.org> @@ -7,6 +7,9 @@ # Copyright (c) 2016 Ceridwen <ceridwenv@gmail.com> # Copyright (c) 2018 Mario Corchero <mcorcherojim@bloomberg.net> # Copyright (c) 2018 Mario Corchero <mariocj89@gmail.com> +# Copyright (c) 2019 Ashley Whetter <ashley@awhetter.co.uk> +# Copyright (c) 2019 Hugo van Kemenade <hugovk@users.noreply.github.com> +# Copyright (c) 2019 markmcclain <markmcclain@users.noreply.github.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 @@ -127,14 +130,6 @@ class ModPathFromFileTest(unittest.TestCase): ["xml", "etree", "ElementTree"], ) - def test_knownValues_modpath_from_file_2(self): - self.assertEqual( - modutils.modpath_from_file( - "unittest_modutils.py", {os.getcwd(): "arbitrary.pkg"} - ), - ["arbitrary", "pkg", "unittest_modutils"], - ) - def test_raise_modpath_from_file_Exception(self): self.assertRaises(Exception, modutils.modpath_from_file, "/turlututu") diff --git a/tests/unittest_nodes.py b/tests/unittest_nodes.py index 5fbef628..5b6a39e3 100644 --- a/tests/unittest_nodes.py +++ b/tests/unittest_nodes.py @@ -1,6 +1,6 @@ # Copyright (c) 2006-2007, 2009-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr> # Copyright (c) 2012 FELD Boris <lothiraldan@gmail.com> -# Copyright (c) 2013-2018 Claudiu Popa <pcmanticore@gmail.com> +# Copyright (c) 2013-2020 Claudiu Popa <pcmanticore@gmail.com> # Copyright (c) 2014 Google, Inc. # Copyright (c) 2014 Eevee (Alex Munroe) <amunroe@yelp.com> # Copyright (c) 2015-2016 Ceridwen <ceridwenv@gmail.com> @@ -8,9 +8,13 @@ # Copyright (c) 2016 Jakub Wilk <jwilk@jwilk.net> # Copyright (c) 2017 rr- <rr-@sakuya.pl> # Copyright (c) 2017 Derek Gustafson <degustaf@gmail.com> +# Copyright (c) 2018 Serhiy Storchaka <storchaka@gmail.com> # Copyright (c) 2018 brendanator <brendan.maginnis@gmail.com> # Copyright (c) 2018 Bryce Guinta <bryce.paul.guinta@gmail.com> # Copyright (c) 2018 Anthony Sottile <asottile@umich.edu> +# Copyright (c) 2019-2020 Ashley Whetter <ashley@awhetter.co.uk> +# Copyright (c) 2019 Alex Hall <alex.mojaki@gmail.com> +# Copyright (c) 2019 Hugo van Kemenade <hugovk@users.noreply.github.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 @@ -22,6 +26,7 @@ import sys import textwrap import unittest import copy +import platform import pytest import six @@ -147,21 +152,20 @@ def function(var): ast = abuilder.string_build(code) self.assertEqual(ast.as_string(), code) - @test_utils.require_version("3.0") - @unittest.expectedFailure def test_3k_annotations_and_metaclass(self): - code_annotations = textwrap.dedent( - ''' - def function(var:int): + code = ''' + def function(var: int): nonlocal counter class Language(metaclass=Natural): """natural language""" ''' - ) + code_annotations = textwrap.dedent(code) + # pylint: disable=line-too-long + expected = 'def function(var: int):\n nonlocal counter\n\n\nclass Language(metaclass=Natural):\n """natural language"""' ast = abuilder.string_build(code_annotations) - self.assertEqual(ast.as_string(), code_annotations) + self.assertEqual(ast.as_string().strip(), expected) def test_ellipsis(self): ast = abuilder.string_build("a[...]").body[0] @@ -254,7 +258,12 @@ class D(metaclass=abc.ABCMeta): ast = abuilder.string_build(code) self.assertEqual(ast.as_string().strip(), code.strip()) - @pytest.mark.skipif(sys.version_info[:2] < (3, 6), reason="needs f-string support") + # This test is disabled on PyPy because we cannot get a proper release on TravisCI that has + # proper support for f-strings (we need 7.2 at least) + @pytest.mark.skipif( + sys.version_info[:2] < (3, 6) or platform.python_implementation() == "PyPy", + reason="Needs f-string support.", + ) def test_f_strings(self): code = r''' a = f"{'a'}" @@ -1131,6 +1140,47 @@ def test_type_comments_arguments(): assert actual_arg.as_string() == expected_arg +@pytest.mark.skipif( + not PY38, reason="needs to be able to parse positional only arguments" +) +def test_type_comments_posonly_arguments(): + module = builder.parse( + """ + def f_arg_comment( + a, # type: int + b, # type: int + /, + c, # type: Optional[int] + d, # type: Optional[int] + *, + e, # type: float + f, # type: float + ): + # type: (...) -> None + pass + """ + ) + expected_annotations = [ + [["int", "int"], ["Optional[int]", "Optional[int]"], ["float", "float"]] + ] + for node, expected_types in zip(module.body, expected_annotations): + assert len(node.type_comment_args) == 1 + if PY38: + assert isinstance(node.type_comment_args[0], astroid.Const) + assert node.type_comment_args[0].value == Ellipsis + else: + assert isinstance(node.type_comment_args[0], astroid.Ellipsis) + type_comments = [ + node.args.type_comment_posonlyargs, + node.args.type_comment_args, + node.args.type_comment_kwonlyargs, + ] + for expected_args, actual_args in zip(expected_types, type_comments): + assert len(expected_args) == len(actual_args) + for expected_arg, actual_arg in zip(expected_args, actual_args): + assert actual_arg.as_string() == expected_arg + + def test_is_generator_for_yield_assignments(): node = astroid.extract_node( """ @@ -1285,5 +1335,30 @@ def test_const_itered(): assert [elem.value for elem in itered] == list("string") +def test_is_generator_for_yield_in_while(): + code = """ + def paused_iter(iterable): + while True: + # Continue to yield the same item until `next(i)` or `i.send(False)` + while (yield value): + pass + """ + node = astroid.extract_node(code) + assert bool(node.is_generator()) + + +def test_is_generator_for_yield_in_if(): + code = """ + import asyncio + + def paused_iter(iterable): + if (yield from asyncio.sleep(0.01)): + pass + return + """ + node = astroid.extract_node(code) + assert bool(node.is_generator()) + + if __name__ == "__main__": unittest.main() diff --git a/tests/unittest_object_model.py b/tests/unittest_object_model.py index ac42485a..5301a992 100644 --- a/tests/unittest_object_model.py +++ b/tests/unittest_object_model.py @@ -1,8 +1,9 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2016-2018 Claudiu Popa <pcmanticore@gmail.com> +# Copyright (c) 2016-2020 Claudiu Popa <pcmanticore@gmail.com> # Copyright (c) 2016 Derek Gustafson <degustaf@gmail.com> # Copyright (c) 2017 Łukasz Rogalski <rogalski.91@gmail.com> # Copyright (c) 2018 Bryce Guinta <bryce.paul.guinta@gmail.com> +# Copyright (c) 2019 Ashley Whetter <ashley@awhetter.co.uk> # 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 @@ -58,7 +59,7 @@ class InstanceModelTest(unittest.TestCase): self.assertIsInstance(attr, astroid.Const) self.assertEqual(attr.value, 42) - @unittest.expectedFailure + @pytest.mark.xfail(reason="Instance lookup cannot override object model") def test_instance_local_attributes_overrides_object_model(self): # The instance lookup needs to be changed in order for this to work. ast_node = builder.extract_node( @@ -144,30 +145,6 @@ class ClassModelTest(unittest.TestCase): self.assertIsInstance(inferred, astroid.Const) self.assertEqual(inferred.value, "first") - @test_utils.require_version(maxver="3.0") - def test__mro__old_style(self): - ast_node = builder.extract_node( - """ - class A: - pass - A.__mro__ - """ - ) - with self.assertRaises(exceptions.InferenceError): - next(ast_node.infer()) - - @test_utils.require_version(maxver="3.0") - def test__subclasses__old_style(self): - ast_node = builder.extract_node( - """ - class A: - pass - A.__subclasses__ - """ - ) - with self.assertRaises(exceptions.InferenceError): - next(ast_node.infer()) - def test_class_model_correct_mro_subclasses_proxied(self): ast_nodes = builder.extract_node( """ @@ -354,7 +331,7 @@ class FunctionModelTest(unittest.TestCase): inferred = next(node.infer()) assert inferred is util.Uninferable - @unittest.expectedFailure + @pytest.mark.xfail(reason="Descriptors cannot infer what self is") def test_descriptor_not_inferrring_self(self): # We can't infer __get__(X, Y)() when the bounded function # uses self, because of the tree's parent not being propagating good enough. @@ -506,37 +483,6 @@ class FunctionModelTest(unittest.TestCase): self.assertIsInstance(kwdefaults, astroid.Dict) # self.assertEqual(kwdefaults.getitem('f').value, 'lala') - @test_utils.require_version(maxver="3.0") - def test_function_model_for_python2(self): - ast_nodes = builder.extract_node( - """ - def test(a=1): - "a" - - test.func_name #@ - test.func_doc #@ - test.func_dict #@ - test.func_globals #@ - test.func_defaults #@ - test.func_code #@ - test.func_closure #@ - """ - ) - name = next(ast_nodes[0].infer()) - self.assertIsInstance(name, astroid.Const) - self.assertEqual(name.value, "test") - doc = next(ast_nodes[1].infer()) - self.assertIsInstance(doc, astroid.Const) - self.assertEqual(doc.value, "a") - pydict = next(ast_nodes[2].infer()) - self.assertIsInstance(pydict, astroid.Dict) - pyglobals = next(ast_nodes[3].infer()) - self.assertIsInstance(pyglobals, astroid.Dict) - defaults = next(ast_nodes[4].infer()) - self.assertIsInstance(defaults, astroid.Tuple) - for node in ast_nodes[5:]: - self.assertIs(next(node.infer()), astroid.Uninferable) - @test_utils.require_version(minver="3.8") def test_annotation_positional_only(self): ast_node = builder.extract_node( @@ -640,6 +586,17 @@ class ExceptionModelTest(unittest.TestCase): assert isinstance(inferred, astroid.Const) assert inferred.value == value + def test_unicodedecodeerror(self): + code = """ + try: + raise UnicodeDecodeError("utf-8", "blob", 0, 1, "reason") + except UnicodeDecodeError as error: + error.object[:1] #@ + """ + node = builder.extract_node(code) + inferred = next(node.infer()) + assert isinstance(inferred, astroid.Const) + def test_import_error(self): ast_nodes = builder.extract_node( """ diff --git a/tests/unittest_objects.py b/tests/unittest_objects.py index 8c56c9fd..a9de6eb2 100644 --- a/tests/unittest_objects.py +++ b/tests/unittest_objects.py @@ -1,6 +1,7 @@ -# Copyright (c) 2015-2016 Claudiu Popa <pcmanticore@gmail.com> +# Copyright (c) 2015-2016, 2018, 2020 Claudiu Popa <pcmanticore@gmail.com> # Copyright (c) 2015-2016 Ceridwen <ceridwenv@gmail.com> # Copyright (c) 2018 Bryce Guinta <bryce.paul.guinta@gmail.com> +# Copyright (c) 2019 Ashley Whetter <ashley@awhetter.co.uk> # 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 @@ -96,28 +97,6 @@ class SuperTests(unittest.TestCase): self.assertIsInstance(second, bases.Instance) self.assertEqual(second.qname(), "%s.super" % bases.BUILTINS) - @test_utils.require_version(maxver="3.0") - def test_super_on_old_style_class(self): - # super doesn't work on old style class, but leave - # that as an error for pylint. We'll infer Super objects, - # but every call will result in a failure at some point. - node = builder.extract_node( - """ - class OldStyle: - def __init__(self): - super(OldStyle, self) #@ - """ - ) - old = next(node.infer()) - self.assertIsInstance(old, objects.Super) - self.assertIsInstance(old.mro_pointer, nodes.ClassDef) - self.assertEqual(old.mro_pointer.name, "OldStyle") - with self.assertRaises(exceptions.SuperError) as cm: - old.super_mro() - self.assertEqual( - str(cm.exception), "Unable to call super on old-style classes." - ) - @test_utils.require_version(minver="3.0") def test_no_arguments_super(self): ast_nodes = builder.extract_node( diff --git a/tests/unittest_protocols.py b/tests/unittest_protocols.py index 1b70a423..babff51e 100644 --- a/tests/unittest_protocols.py +++ b/tests/unittest_protocols.py @@ -1,9 +1,10 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2015-2018 Claudiu Popa <pcmanticore@gmail.com> +# Copyright (c) 2015-2019 Claudiu Popa <pcmanticore@gmail.com> # Copyright (c) 2015-2016 Ceridwen <ceridwenv@gmail.com> # Copyright (c) 2016 Jakub Wilk <jwilk@jwilk.net> # Copyright (c) 2017 Łukasz Rogalski <rogalski.91@gmail.com> # Copyright (c) 2018 Nick Drozd <nicholasdrozd@gmail.com> +# Copyright (c) 2019 Ashley Whetter <ashley@awhetter.co.uk> # 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 diff --git a/tests/unittest_python3.py b/tests/unittest_python3.py index bc450227..b1759f03 100644 --- a/tests/unittest_python3.py +++ b/tests/unittest_python3.py @@ -5,8 +5,9 @@ # Copyright (c) 2014 Google, Inc. # Copyright (c) 2015-2016 Ceridwen <ceridwenv@gmail.com> # Copyright (c) 2016 Jared Garst <jgarst@users.noreply.github.com> +# Copyright (c) 2017, 2019 Łukasz Rogalski <rogalski.91@gmail.com> # Copyright (c) 2017 Hugo <hugovk@users.noreply.github.com> -# Copyright (c) 2017 Łukasz Rogalski <rogalski.91@gmail.com> +# Copyright (c) 2019 Ashley Whetter <ashley@awhetter.co.uk> # 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 diff --git a/tests/unittest_raw_building.py b/tests/unittest_raw_building.py index db32e7da..f782cdb2 100644 --- a/tests/unittest_raw_building.py +++ b/tests/unittest_raw_building.py @@ -1,9 +1,10 @@ # Copyright (c) 2013 AndroWiiid <androwiiid@gmail.com> -# Copyright (c) 2014-2016, 2018 Claudiu Popa <pcmanticore@gmail.com> +# Copyright (c) 2014-2016, 2018-2019 Claudiu Popa <pcmanticore@gmail.com> # Copyright (c) 2014 Google, Inc. # Copyright (c) 2015-2016 Ceridwen <ceridwenv@gmail.com> # Copyright (c) 2018 Anthony Sottile <asottile@umich.edu> # Copyright (c) 2018 Bryce Guinta <bryce.paul.guinta@gmail.com> +# Copyright (c) 2019 Ashley Whetter <ashley@awhetter.co.uk> # 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 diff --git a/tests/unittest_regrtest.py b/tests/unittest_regrtest.py index 91fa8f16..79a86cb2 100644 --- a/tests/unittest_regrtest.py +++ b/tests/unittest_regrtest.py @@ -1,12 +1,13 @@ # Copyright (c) 2006-2008, 2010-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr> # Copyright (c) 2007 Marien Zwart <marienz@gentoo.org> # Copyright (c) 2013-2014 Google, Inc. -# Copyright (c) 2014-2016, 2018 Claudiu Popa <pcmanticore@gmail.com> +# Copyright (c) 2014-2016, 2018-2020 Claudiu Popa <pcmanticore@gmail.com> # Copyright (c) 2014 Eevee (Alex Munroe) <amunroe@yelp.com> # Copyright (c) 2015-2016 Ceridwen <ceridwenv@gmail.com> # Copyright (c) 2016 Jakub Wilk <jwilk@jwilk.net> # Copyright (c) 2018 Nick Drozd <nicholasdrozd@gmail.com> # Copyright (c) 2018 Anthony Sottile <asottile@umich.edu> +# Copyright (c) 2019 Ashley Whetter <ashley@awhetter.co.uk> # 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 @@ -306,25 +307,41 @@ def test(): ) next(node.infer()) - @require_version(maxver="3.0") - def test_reassignment_in_except_handler(self): - node = extract_node( - """ - import exceptions - try: - {}["a"] - except KeyError, exceptions.IndexError: - pass - - IndexError #@ + def test_regression_inference_of_self_in_lambda(self): + code = """ + class A: + @b(lambda self: __(self)) + def d(self): + pass """ - ) - self.assertEqual(len(node.inferred()), 1) + node = extract_node(code) + inferred = next(node.infer()) + assert isinstance(inferred, Instance) + assert inferred.qname() == ".A" class Whatever: a = property(lambda x: x, lambda x: x) +def test_ancestor_looking_up_redefined_function(): + code = """ + class Foo: + def _format(self): + pass + + def format(self): + self.format = self._format + self.format() + Foo + """ + node = extract_node(code) + inferred = next(node.infer()) + ancestor = next(inferred.ancestors()) + _, found = ancestor.lookup("format") + assert len(found) == 1 + assert isinstance(found[0], nodes.FunctionDef) + + if __name__ == "__main__": unittest.main() diff --git a/tests/unittest_scoped_nodes.py b/tests/unittest_scoped_nodes.py index d70b7351..c4597fa6 100644 --- a/tests/unittest_scoped_nodes.py +++ b/tests/unittest_scoped_nodes.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # Copyright (c) 2006-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr> # Copyright (c) 2011, 2013-2015 Google, Inc. -# Copyright (c) 2013-2018 Claudiu Popa <pcmanticore@gmail.com> +# Copyright (c) 2013-2020 Claudiu Popa <pcmanticore@gmail.com> # Copyright (c) 2013 Phil Schaf <flying-sheep@web.de> # Copyright (c) 2014 Eevee (Alex Munroe) <amunroe@yelp.com> # Copyright (c) 2015-2016 Ceridwen <ceridwenv@gmail.com> @@ -9,11 +9,16 @@ # Copyright (c) 2015 Florian Bruhin <me@the-compiler.org> # Copyright (c) 2015 Philip Lorenz <philip@bithub.de> # Copyright (c) 2016 Jakub Wilk <jwilk@jwilk.net> +# Copyright (c) 2017, 2019 Łukasz Rogalski <rogalski.91@gmail.com> # Copyright (c) 2017-2018 Bryce Guinta <bryce.paul.guinta@gmail.com> -# Copyright (c) 2017 Łukasz Rogalski <rogalski.91@gmail.com> # Copyright (c) 2017 Derek Gustafson <degustaf@gmail.com> +# Copyright (c) 2018-2019 Ville Skyttä <ville.skytta@iki.fi> # Copyright (c) 2018 brendanator <brendan.maginnis@gmail.com> # Copyright (c) 2018 Anthony Sottile <asottile@umich.edu> +# Copyright (c) 2019 Ashley Whetter <ashley@awhetter.co.uk> +# Copyright (c) 2019 Hugo van Kemenade <hugovk@users.noreply.github.com> +# Copyright (c) 2019 Peter de Blanc <peter@standard.ai> +# Copyright (c) 2019 hippo91 <guillaume.peillex@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 @@ -1005,19 +1010,6 @@ class ClassNodeTest(ModuleLoader, unittest.TestCase): self.assertEqual(astroid["g2"].fromlineno, 9) self.assertEqual(astroid["g2"].tolineno, 10) - @test_utils.require_version(maxver="3.0") - def test_simple_metaclass(self): - astroid = builder.parse( - """ - class Test(object): - __metaclass__ = type - """ - ) - klass = astroid["Test"] - metaclass = klass.metaclass() - self.assertIsInstance(metaclass, scoped_nodes.ClassDef) - self.assertEqual(metaclass.name, "type") - def test_metaclass_error(self): astroid = builder.parse( """ @@ -1028,21 +1020,6 @@ class ClassNodeTest(ModuleLoader, unittest.TestCase): klass = astroid["Test"] self.assertFalse(klass.metaclass()) - @test_utils.require_version(maxver="3.0") - def test_metaclass_imported(self): - astroid = builder.parse( - """ - from abc import ABCMeta - class Test(object): - __metaclass__ = ABCMeta - """ - ) - klass = astroid["Test"] - - metaclass = klass.metaclass() - self.assertIsInstance(metaclass, scoped_nodes.ClassDef) - self.assertEqual(metaclass.name, "ABCMeta") - def test_metaclass_yes_leak(self): astroid = builder.parse( """ @@ -1056,100 +1033,6 @@ class ClassNodeTest(ModuleLoader, unittest.TestCase): klass = astroid["Meta"] self.assertIsNone(klass.metaclass()) - @test_utils.require_version(maxver="3.0") - def test_newstyle_and_metaclass_good(self): - astroid = builder.parse( - """ - from abc import ABCMeta - class Test: - __metaclass__ = ABCMeta - """ - ) - klass = astroid["Test"] - self.assertTrue(klass.newstyle) - self.assertEqual(klass.metaclass().name, "ABCMeta") - astroid = builder.parse( - """ - from abc import ABCMeta - __metaclass__ = ABCMeta - class Test: - pass - """ - ) - klass = astroid["Test"] - self.assertTrue(klass.newstyle) - self.assertEqual(klass.metaclass().name, "ABCMeta") - - @test_utils.require_version(maxver="3.0") - def test_nested_metaclass(self): - astroid = builder.parse( - """ - from abc import ABCMeta - class A(object): - __metaclass__ = ABCMeta - class B: pass - - __metaclass__ = ABCMeta - class C: - __metaclass__ = type - class D: pass - """ - ) - a = astroid["A"] - b = a.locals["B"][0] - c = astroid["C"] - d = c.locals["D"][0] - self.assertEqual(a.metaclass().name, "ABCMeta") - self.assertFalse(b.newstyle) - self.assertIsNone(b.metaclass()) - self.assertEqual(c.metaclass().name, "type") - self.assertEqual(d.metaclass().name, "ABCMeta") - - @test_utils.require_version(maxver="3.0") - def test_parent_metaclass(self): - astroid = builder.parse( - """ - from abc import ABCMeta - class Test: - __metaclass__ = ABCMeta - class SubTest(Test): pass - """ - ) - klass = astroid["SubTest"] - self.assertTrue(klass.newstyle) - metaclass = klass.metaclass() - self.assertIsInstance(metaclass, scoped_nodes.ClassDef) - self.assertEqual(metaclass.name, "ABCMeta") - - @test_utils.require_version(maxver="3.0") - def test_metaclass_ancestors(self): - astroid = builder.parse( - """ - from abc import ABCMeta - - class FirstMeta(object): - __metaclass__ = ABCMeta - - class SecondMeta(object): - __metaclass__ = type - - class Simple(object): - pass - - class FirstImpl(FirstMeta): pass - class SecondImpl(FirstImpl): pass - class ThirdImpl(Simple, SecondMeta): - pass - """ - ) - classes = {"ABCMeta": ("FirstImpl", "SecondImpl"), "type": ("ThirdImpl",)} - for metaclass, names in classes.items(): - for name in names: - impl = astroid[name] - meta = impl.metaclass() - self.assertIsInstance(meta, nodes.ClassDef) - self.assertEqual(meta.name, metaclass) - def test_metaclass_type(self): klass = builder.extract_node( """ @@ -1314,33 +1197,6 @@ class ClassNodeTest(ModuleLoader, unittest.TestCase): else: self.assertEqual(list(expected_value), [node.value for node in slots]) - @test_utils.require_version(maxver="3.0") - def test_slots_py2(self): - module = builder.parse( - """ - class UnicodeSlots(object): - __slots__ = (u"a", u"b", "c") - """ - ) - slots = module["UnicodeSlots"].slots() - self.assertEqual(len(slots), 3) - self.assertEqual(slots[0].value, "a") - self.assertEqual(slots[1].value, "b") - self.assertEqual(slots[2].value, "c") - - @test_utils.require_version(maxver="3.0") - def test_slots_py2_not_implemented(self): - module = builder.parse( - """ - class OldStyle: - __slots__ = ("a", "b") - """ - ) - msg = "The concept of slots is undefined for old-style classes." - with self.assertRaises(NotImplementedError) as cm: - module["OldStyle"].slots() - self.assertEqual(str(cm.exception), msg) - def test_slots_for_dict_keys(self): module = builder.parse( """ @@ -1397,73 +1253,23 @@ class ClassNodeTest(ModuleLoader, unittest.TestCase): cls = module["B"] self.assertIsNone(cls.slots()) - def assertEqualMro(self, klass, expected_mro): - self.assertEqual([member.name for member in klass.mro()], expected_mro) + def test_slots_added_dynamically_still_inferred(self): + code = """ + class NodeBase(object): + __slots__ = "a", "b" - @test_utils.require_version(maxver="3.0") - def test_no_mro_for_old_style(self): - node = builder.extract_node( - """ - class Old: pass""" - ) - with self.assertRaises(NotImplementedError) as cm: - node.mro() - self.assertEqual( - str(cm.exception), "Could not obtain mro for " "old-style classes." - ) + if Options.isFullCompat(): + __slots__ += ("c",) - @test_utils.require_version(maxver="3.0") - def test_mro_for_classes_with_old_style_in_mro(self): - node = builder.extract_node( - """ - class Factory: - pass - class ClientFactory(Factory): - pass - class ReconnectingClientFactory(ClientFactory): - pass - class WebSocketAdapterFactory(object): - pass - class WebSocketClientFactory(WebSocketAdapterFactory, ClientFactory): - pass - class WampWebSocketClientFactory(WebSocketClientFactory): - pass - class RetryFactory(WampWebSocketClientFactory, ReconnectingClientFactory): - pas """ - ) - self.assertEqualMro( - node, - [ - "RetryFactory", - "WampWebSocketClientFactory", - "WebSocketClientFactory", - "WebSocketAdapterFactory", - "object", - "ReconnectingClientFactory", - "ClientFactory", - "Factory", - ], - ) + node = builder.extract_node(code) + inferred = next(node.infer()) + slots = inferred.slots() + assert len(slots) == 3, slots + assert [slot.value for slot in slots] == ["a", "b", "c"] - @test_utils.require_version(maxver="3.0") - def test_combined_newstyle_oldstyle_in_mro(self): - node = builder.extract_node( - """ - class Old: - pass - class New(object): - pass - class New1(object): - pass - class New2(New, New1): - pass - class NewOld(New2, Old): #@ - pass - """ - ) - self.assertEqualMro(node, ["NewOld", "New2", "New", "New1", "object", "Old"]) - self.assertTrue(node.newstyle) + def assertEqualMro(self, klass, expected_mro): + self.assertEqual([member.name for member in klass.mro()], expected_mro) def test_with_metaclass_mro(self): astroid = builder.parse( @@ -1741,15 +1547,6 @@ class ClassNodeTest(ModuleLoader, unittest.TestCase): static = next(acls.igetattr("static")) self.assertIsInstance(static, scoped_nodes.FunctionDef) - @test_utils.require_version(maxver="3.0") - def test_implicit_metaclass_is_none(self): - cls = builder.extract_node( - """ - class A: pass - """ - ) - self.assertIsNone(cls.implicit_metaclass()) - def test_local_attr_invalid_mro(self): cls = builder.extract_node( """ @@ -2021,6 +1818,12 @@ def test_metaclass_cannot_infer_call_yields_an_instance(): pass """ ), + textwrap.dedent( + """ + def __init__(self: int, other: float, /, **kw): + pass + """ + ), ], ) @test_utils.require_version("3.8") diff --git a/tests/unittest_transforms.py b/tests/unittest_transforms.py index 5df7ffad..922f10f9 100644 --- a/tests/unittest_transforms.py +++ b/tests/unittest_transforms.py @@ -1,7 +1,8 @@ -# Copyright (c) 2015-2017 Claudiu Popa <pcmanticore@gmail.com> +# Copyright (c) 2015-2018 Claudiu Popa <pcmanticore@gmail.com> # Copyright (c) 2015-2016 Ceridwen <ceridwenv@gmail.com> # Copyright (c) 2016 Jakub Wilk <jwilk@jwilk.net> # Copyright (c) 2018 Bryce Guinta <bryce.paul.guinta@gmail.com> +# Copyright (c) 2019 Ashley Whetter <ashley@awhetter.co.uk> # 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 diff --git a/tests/unittest_utils.py b/tests/unittest_utils.py index 3ae3d6b7..428026b1 100644 --- a/tests/unittest_utils.py +++ b/tests/unittest_utils.py @@ -1,8 +1,9 @@ # Copyright (c) 2008-2010, 2013 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr> # Copyright (c) 2014 Google, Inc. -# Copyright (c) 2015-2016 Claudiu Popa <pcmanticore@gmail.com> +# Copyright (c) 2015-2016, 2018 Claudiu Popa <pcmanticore@gmail.com> # Copyright (c) 2016 Ceridwen <ceridwenv@gmail.com> # Copyright (c) 2016 Dave Baum <dbaum@google.com> +# Copyright (c) 2019 Ashley Whetter <ashley@awhetter.co.uk> # 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 |
