From b161c47f9d29deaaab85bc37cabd076c01885e1f Mon Sep 17 00:00:00 2001 From: Torsten Marek Date: Fri, 25 Jul 2014 16:01:49 +0200 Subject: Port more testcases to the new framework. --- test/functional/cellvar_escaping_loop.py | 128 ++++++++++++++++++++ test/functional/cellvar_escaping_loop.txt | 8 ++ test/functional/ctor_arguments.py | 78 ++++++++++++ test/functional/undefined_variable.py | 116 ++++++++++++++++++ test/functional/undefined_variable.txt | 17 +++ test/input/func_ctor_arguments.py | 77 ------------ test/input/func_loopvar_in_closure.py | 132 --------------------- .../func_noerror_9215_lambda_arg_as_decorator.py | 29 ----- test/input/func_undefined_var.py | 119 ------------------- test/messages/func_ctor_arguments.txt | 17 --- test/messages/func_loopvar_in_closure.txt | 8 -- test/messages/func_undefined_var.txt | 14 --- 12 files changed, 347 insertions(+), 396 deletions(-) create mode 100644 test/functional/cellvar_escaping_loop.py create mode 100644 test/functional/cellvar_escaping_loop.txt create mode 100644 test/functional/ctor_arguments.py create mode 100644 test/functional/undefined_variable.py create mode 100644 test/functional/undefined_variable.txt delete mode 100644 test/input/func_ctor_arguments.py delete mode 100644 test/input/func_loopvar_in_closure.py delete mode 100644 test/input/func_noerror_9215_lambda_arg_as_decorator.py delete mode 100644 test/input/func_undefined_var.py delete mode 100644 test/messages/func_ctor_arguments.txt delete mode 100644 test/messages/func_loopvar_in_closure.txt delete mode 100644 test/messages/func_undefined_var.txt diff --git a/test/functional/cellvar_escaping_loop.py b/test/functional/cellvar_escaping_loop.py new file mode 100644 index 0000000..316bc47 --- /dev/null +++ b/test/functional/cellvar_escaping_loop.py @@ -0,0 +1,128 @@ +"""Tests for loopvar-in-closure.""" + +def good_case(): + """No problems here.""" + lst = [] + for i in range(10): + lst.append(i) + + +def good_case2(): + """No problems here.""" + return [i for i in range(10)] + + +def good_case3(): + """No problems here.""" + lst = [] + for i in range(10): # [unused-variable] + lst.append(lambda i=i: i) + + +def good_case4(): + """No problems here.""" + lst = [] + for i in range(10): + print i + lst.append(lambda i: i) + + +def good_case5(): + """No problems here.""" + return (i for i in range(10)) + + +def good_case6(): + """Accept use of the variable after the loop. + + There's already a warning about possibly undefined loop variables, and + the value will not change any more.""" + for i in range(10): + print i + return lambda: i # [undefined-loop-variable] + + +def good_case7(): + """Accept use of the variable inside return.""" + for i in range(10): + if i == 8: + return lambda: i + return lambda: -1 + + +def good_case8(): + """Lambda defined and called in loop.""" + for i in range(10): + print (lambda x: i + x)(1) + + +def good_case9(): + """Another eager binding of the cell variable.""" + funs = [] + for i in range(10): + def func(bound_i=i): + """Ignore.""" + return bound_i + funs.append(func) + return funs + + +def bad_case(): + """Closing over a loop variable.""" + lst = [] + for i in range(10): + print i + lst.append(lambda: i) # [cell-var-from-loop] + + +def bad_case2(): + """Closing over a loop variable.""" + return [lambda: i for i in range(10)] # [cell-var-from-loop] + + +def bad_case3(): + """Closing over variable defined in loop.""" + lst = [] + for i in range(10): + j = i * i + lst.append(lambda: j) # [cell-var-from-loop] + return lst + + +def bad_case4(): + """Closing over variable defined in loop.""" + lst = [] + for i in range(10): + def nested(): + """Nested function.""" + return i**2 # [cell-var-from-loop] + lst.append(nested) + return lst + + +def bad_case5(): + """Problematic case. + + If this function is used as + + >>> [x() for x in bad_case5()] + + it behaves 'as expected', i.e. the result is range(10). + + If it's used with + + >>> lst = list(bad_case5()) + >>> [x() for x in lst] + + the result is [9] * 10 again. + """ + return (lambda: i for i in range(10)) # [cell-var-from-loop] + + +def bad_case6(): + """Closing over variable defined in loop.""" + lst = [] + for i, j in zip(range(10), range(10, 20)): + print j + lst.append(lambda: i) # [cell-var-from-loop] + return lst diff --git a/test/functional/cellvar_escaping_loop.txt b/test/functional/cellvar_escaping_loop.txt new file mode 100644 index 0000000..4448d44 --- /dev/null +++ b/test/functional/cellvar_escaping_loop.txt @@ -0,0 +1,8 @@ +unused-variable:18:good_case3:Unused variable 'i' +undefined-loop-variable:42:good_case6.:Using possibly undefined loop variable 'i' +cell-var-from-loop:75:bad_case.:Cell variable i defined in loop +cell-var-from-loop:80:bad_case2.:Cell variable i defined in loop +cell-var-from-loop:88:bad_case3.:Cell variable j defined in loop +cell-var-from-loop:98:bad_case4.nested:Cell variable i defined in loop +cell-var-from-loop:119:bad_case5.:Cell variable i defined in loop +cell-var-from-loop:127:bad_case6.:Cell variable i defined in loop diff --git a/test/functional/ctor_arguments.py b/test/functional/ctor_arguments.py new file mode 100644 index 0000000..7dc0a09 --- /dev/null +++ b/test/functional/ctor_arguments.py @@ -0,0 +1,78 @@ +"""Test function argument checker on __init__ + +Based on test/functional/arguments.py +""" +# pylint: disable=C0111,R0903,W0231 + + +class Class1Arg(object): + def __init__(self, first_argument): + """one argument function""" + +class Class3Arg(object): + def __init__(self, first_argument, second_argument, third_argument): + """three arguments function""" + +class ClassDefaultArg(object): + def __init__(self, one=1, two=2): + """function with default value""" + +class Subclass1Arg(Class1Arg): + pass + +class ClassAllArgs(Class1Arg): + def __init__(self, *args, **kwargs): + pass + +class ClassMultiInheritance(Class1Arg, Class3Arg): + pass + +class ClassNew(object): + def __new__(cls, first_argument, kwarg=None): + return first_argument, kwarg + +Class1Arg(420) +Class1Arg() # [no-value-for-parameter] +Class1Arg(1337, 347) # [too-many-function-args] + +Class3Arg(420, 789) # [no-value-for-parameter] +# +1:[no-value-for-parameter,no-value-for-parameter,no-value-for-parameter] +Class3Arg() +Class3Arg(1337, 347, 456) +Class3Arg('bab', 'bebe', None, 5.6) # [too-many-function-args] + +ClassDefaultArg(1, two=5) +ClassDefaultArg(two=5) + +Class1Arg(bob=4) # [no-value-for-parameter,unexpected-keyword-arg] +ClassDefaultArg(1, 4, coin="hello") # [unexpected-keyword-arg] + +ClassDefaultArg(1, one=5) # [redundant-keyword-arg] + +Subclass1Arg(420) +Subclass1Arg() # [no-value-for-parameter] +Subclass1Arg(1337, 347) # [too-many-function-args] + +ClassAllArgs() +ClassAllArgs(1, 2, 3, even=4, more=5) + +ClassMultiInheritance(1) +ClassMultiInheritance(1, 2, 3) # [too-many-function-args] + +ClassNew(1, kwarg=1) +ClassNew(1, 2, 3) # [too-many-function-args] +ClassNew(one=2) # [no-value-for-parameter,unexpected-keyword-arg] + + +class Metaclass(type): + def __new__(mcs, name, bases, namespace): + return type.__new__(mcs, name, bases, namespace) + +def with_metaclass(meta, base=object): + """Create a new type that can be used as a metaclass.""" + return meta("NewBase", (base, ), {}) + +class ClassWithMeta(with_metaclass(Metaclass)): + pass + +ClassWithMeta() diff --git a/test/functional/undefined_variable.py b/test/functional/undefined_variable.py new file mode 100644 index 0000000..25f0145 --- /dev/null +++ b/test/functional/undefined_variable.py @@ -0,0 +1,116 @@ +"""Test warnings about access to undefined variables.""" +# pylint: disable=too-few-public-methods, no-init, no-self-use + +DEFINED = 1 + +if DEFINED != 1: + if DEFINED in (unknown, DEFINED): # [undefined-variable] + DEFINED += 1 + + +def in_method(var): + """method doc""" + var = nomoreknown # [undefined-variable] + assert var + +DEFINED = {DEFINED:__revision__} # [undefined-variable] +# +1:[undefined-variable] +DEFINED[__revision__] = OTHER = 'move this is astroid test' + +OTHER += '$' + +def bad_default(var, default=unknown2): # [undefined-variable] + """function with defaut arg's value set to an unexistant name""" + print var, default + print xxxx # [undefined-variable] + augvar += 1 # [undefined-variable,unused-variable] + del vardel # [undefined-variable] + +LMBD = lambda x, y=doesnotexist: x+y # [undefined-variable] +LMBD2 = lambda x, y: x+z # [undefined-variable] + +try: + POUET # don't catch me +except NameError: + POUET = 'something' + +try: + POUETT # don't catch me +except Exception: # pylint:disable = broad-except + POUETT = 'something' + +try: + POUETTT # don't catch me +except: # pylint:disable = bare-except + POUETTT = 'something' + +print POUET, POUETT, POUETTT + + +try: + PLOUF # [used-before-assignment] +except ValueError: + PLOUF = 'something' + +print PLOUF + +def if_branch_test(something): + """hop""" + if something == 0: + if xxx == 1: # [used-before-assignment] + pass + else: + print xxx + xxx = 3 + + +def decorator(arg): + """Decorator with one argument.""" + return lambda: list(arg) + + +@decorator(arg=[i * 2 for i in range(15)]) +def func1(): + """A function with a decorator that contains a listcomp.""" + +@decorator(arg=(i * 2 for i in range(15))) +def func2(): + """A function with a decorator that contains a genexpr.""" + +@decorator(lambda x: x > 0) +def main(): + """A function with a decorator that contains a lambda.""" + +# Test shared scope. + +def test_arguments(arg=TestClass): # [used-before-assignment] + """ TestClass isn't defined yet. """ + return arg + +class TestClass(Ancestor): # [used-before-assignment] + """ contains another class, which uses an undefined ancestor. """ + + class MissingAncestor(Ancestor1): # [used-before-assignment] + """ no op """ + + def test1(self): + """ It should trigger here, because the two classes + have the same scope. + """ + class UsingBeforeDefinition(Empty): # [used-before-assignment] + """ uses Empty before definition """ + class Empty(object): + """ no op """ + return UsingBeforeDefinition + + def test(self): + """ Ancestor isn't defined yet, but we don't care. """ + class MissingAncestor1(Ancestor): + """ no op """ + return MissingAncestor1 + +class Ancestor(object): + """ No op """ + +class Ancestor1(object): + """ No op """ diff --git a/test/functional/undefined_variable.txt b/test/functional/undefined_variable.txt new file mode 100644 index 0000000..5695be1 --- /dev/null +++ b/test/functional/undefined_variable.txt @@ -0,0 +1,17 @@ +undefined-variable:7::Undefined variable 'unknown' +undefined-variable:13:in_method:Undefined variable 'nomoreknown' +undefined-variable:16::Undefined variable '__revision__' +undefined-variable:18::Undefined variable '__revision__' +undefined-variable:22:bad_default:Undefined variable 'unknown2' +undefined-variable:25:bad_default:Undefined variable 'xxxx' +undefined-variable:26:bad_default:Undefined variable 'augvar' +unused-variable:26:bad_default:Unused variable 'augvar' +undefined-variable:27:bad_default:Undefined variable 'vardel' +undefined-variable:29::Undefined variable 'doesnotexist' +undefined-variable:30::Undefined variable 'z' +used-before-assignment:51::Using variable 'PLOUF' before assignment +used-before-assignment:60:if_branch_test:Using variable 'xxx' before assignment +used-before-assignment:86:test_arguments:Using variable 'TestClass' before assignment +used-before-assignment:90:TestClass:Using variable 'Ancestor' before assignment +used-before-assignment:93:TestClass.MissingAncestor:Using variable 'Ancestor1' before assignment +used-before-assignment:100:TestClass.test1.UsingBeforeDefinition:Using variable 'Empty' before assignment diff --git a/test/input/func_ctor_arguments.py b/test/input/func_ctor_arguments.py deleted file mode 100644 index f9a3430..0000000 --- a/test/input/func_ctor_arguments.py +++ /dev/null @@ -1,77 +0,0 @@ -"""Test function argument checker on __init__ - -Based on test/input/func_arguments.py -""" -# pylint: disable=C0111,R0903,W0231 -__revision__ = '' - -class Class1Arg(object): - def __init__(self, first_argument): - """one argument function""" - -class Class3Arg(object): - def __init__(self, first_argument, second_argument, third_argument): - """three arguments function""" - -class ClassDefaultArg(object): - def __init__(self, one=1, two=2): - """function with default value""" - -class Subclass1Arg(Class1Arg): - pass - -class ClassAllArgs(Class1Arg): - def __init__(self, *args, **kwargs): - pass - -class ClassMultiInheritance(Class1Arg, Class3Arg): - pass - -class ClassNew(object): - def __new__(cls, first_argument, kwarg=None): - return first_argument, kwarg - -Class1Arg(420) -Class1Arg() -Class1Arg(1337, 347) - -Class3Arg(420, 789) -Class3Arg() -Class3Arg(1337, 347, 456) -Class3Arg('bab', 'bebe', None, 5.6) - -ClassDefaultArg(1, two=5) -ClassDefaultArg(two=5) - -Class1Arg(bob=4) -ClassDefaultArg(1, 4, coin="hello") - -ClassDefaultArg(1, one=5) - -Subclass1Arg(420) -Subclass1Arg() -Subclass1Arg(1337, 347) - -ClassAllArgs() -ClassAllArgs(1, 2, 3, even=4, more=5) - -ClassMultiInheritance(1) -ClassMultiInheritance(1, 2, 3) - -ClassNew(1, kwarg=1) -ClassNew(1, 2, 3) -ClassNew(one=2) - - -class Metaclass(type): - def __new__(mcs, name, bases, namespace): - return type.__new__(mcs, name, bases, namespace) - -def with_metaclass(meta, base=object): - """Create a new type that can be used as a metaclass.""" - return meta("NewBase", (base, ), {}) - -class ClassWithMeta(with_metaclass(Metaclass)): - pass - -ClassWithMeta() diff --git a/test/input/func_loopvar_in_closure.py b/test/input/func_loopvar_in_closure.py deleted file mode 100644 index 3a791d3..0000000 --- a/test/input/func_loopvar_in_closure.py +++ /dev/null @@ -1,132 +0,0 @@ -"""Tests for loopvar-in-closure.""" - -__revision__ = 0 - - -def good_case(): - """No problems here.""" - lst = [] - for i in range(10): - lst.append(i) - - -def good_case2(): - """No problems here.""" - return [i for i in range(10)] - - -def good_case3(): - """No problems here.""" - lst = [] - for i in range(10): - lst.append(lambda i=i: i) - - -def good_case4(): - """No problems here.""" - lst = [] - for i in range(10): - print i - lst.append(lambda i: i) - - -def good_case5(): - """No problems here.""" - return (i for i in range(10)) - - -def good_case6(): - """Accept use of the variable after the loop. - - There's already a warning about possibly undefined loop variables, and - the value will not change any more.""" - for i in range(10): - print i - return lambda: i - - -def good_case7(): - """Accept use of the variable inside return.""" - for i in range(10): - if i == 8: - return lambda: i - return lambda: -1 - - -def good_case8(): - """Lambda defined and called in loop.""" - for i in range(10): - print (lambda x: i + x)(1) - - -def good_case9(): - """Another eager binding of the cell variable.""" - funs = [] - for i in range(10): - def func(bound_i=i): - """Ignore.""" - return bound_i - funs.append(func) - return funs - - -def bad_case(): - """Closing over a loop variable.""" - lst = [] - for i in range(10): - print i - lst.append(lambda: i) - - -def bad_case2(): - """Closing over a loop variable.""" - return [lambda: i for i in range(10)] - - -def bad_case3(): - """Closing over variable defined in loop.""" - lst = [] - for i in range(10): - j = i * i - lst.append(lambda: j) - return lst - - -def bad_case4(): - """Closing over variable defined in loop.""" - lst = [] - for i in range(10): - def nested(): - """Nested function.""" - return i**2 - lst.append(nested) - return lst - - -def bad_case5(): - """Problematic case. - - If this function is used as - - >>> [x() for x in bad_case5()] - - it behaves 'as expected', i.e. the result is range(10). - - If it's used with - - >>> lst = list(bad_case5()) - >>> [x() for x in lst] - - the result is [9] * 10 again. - """ - return (lambda: i for i in range(10)) - - -def bad_case6(): - """Closing over variable defined in loop.""" - lst = [] - for i, j in zip(range(10), range(10, 20)): - print j - lst.append(lambda: i) - return lst - diff --git a/test/input/func_noerror_9215_lambda_arg_as_decorator.py b/test/input/func_noerror_9215_lambda_arg_as_decorator.py deleted file mode 100644 index cbbc747..0000000 --- a/test/input/func_noerror_9215_lambda_arg_as_decorator.py +++ /dev/null @@ -1,29 +0,0 @@ -"""Demonstrate false undefined variable for lambda functions. - -http://www.logilab.org/ticket/9215 -""" - -__revision__ = None - -def decorator(expr): - """Function returning decorator.""" - def func(function): - """Pass-thru decorator.""" - return function - # use expr - expr(0) - return func - -# this lambda is flagged -# E0602: 16:main.: Undefined variable 'x' -@decorator(lambda x: x > 0) -def main(): - """Dummy function.""" - # this one is not flagged - decorator(lambda y: y > 0) - -if __name__ == "__main__": - main() - - - diff --git a/test/input/func_undefined_var.py b/test/input/func_undefined_var.py deleted file mode 100644 index fb5fc30..0000000 --- a/test/input/func_undefined_var.py +++ /dev/null @@ -1,119 +0,0 @@ -"""test access to undefined variables""" -# pylint: disable=too-few-public-methods, no-init, no-self-use -__revision__ = '$Id:' - -DEFINED = 1 - -if DEFINED != 1: - if DEFINED in (unknown, DEFINED): - DEFINED += 1 - - -def in_method(var): - """method doc""" - var = nomoreknown - assert var - -DEFINED = {DEFINED:__revision__} -DEFINED[__revision__] = OTHER = 'move this is astroid test' - -OTHER += '$' - -def bad_default(var, default=unknown2): - """function with defaut arg's value set to an unexistant name""" - print var, default - print xxxx - print xxxx #see story #1000 - augvar += 1 - del vardel - -# Warning for Attribute access to undefinde attributes ? -#class Attrs(object): - #"""dummy class for wrong attribute access""" -#AOU = Attrs() -#AOU.number *= 1.3 -#del AOU.badattr - -try: - POUET # don't catch me -except NameError: - POUET = 'something' - -try: - POUETT # don't catch me -except Exception: # pylint:disable = W0703 - POUETT = 'something' - -try: - POUETTT # don't catch me -except: # pylint:disable = W0702 - POUETTT = 'something' - -print POUET, POUETT, POUETTT - - -try: - PLOUF # catch me -except ValueError: - PLOUF = 'something' - -print PLOUF - -def if_branch_test(something): - """hop""" - if something == 0: - if xxx == 1: - pass - else: - print xxx - xxx = 3 - - -def decorator(arg): - """Decorator with one argument.""" - return lambda: list(arg) - - -@decorator(arg=[i * 2 for i in range(15)]) -def func1(): - """A function with a decorator that contains a listcomp.""" - pass - -@decorator(arg=(i * 2 for i in range(15))) -def func2(): - """A function with a decorator that contains a genexpr.""" - pass - -# Test shared scope. - -def test_arguments(arg=TestClass): - """ TestClass isn't defined yet. """ - return arg - -class TestClass(Ancestor): - """ contains another class, which uses an undefined ancestor. """ - - class MissingAncestor(Ancestor1): - """ no op """ - - def test1(self): - """ It should trigger here, because the two classes - have the same scope. - """ - class UsingBeforeDefinition(Empty): - """ uses Empty before definition """ - class Empty(object): - """ no op """ - return UsingBeforeDefinition - - def test(self): - """ Ancestor isn't defined yet, but we don't care. """ - class MissingAncestor1(Ancestor): - """ no op """ - return MissingAncestor1 - -class Ancestor(object): - """ No op """ - -class Ancestor1(object): - """ No op """ diff --git a/test/messages/func_ctor_arguments.txt b/test/messages/func_ctor_arguments.txt deleted file mode 100644 index b8d62b1..0000000 --- a/test/messages/func_ctor_arguments.txt +++ /dev/null @@ -1,17 +0,0 @@ -E: 35: No value for argument 'first_argument' in constructor call -E: 36: Too many positional arguments for constructor call -E: 38: No value for argument 'third_argument' in constructor call -E: 39: No value for argument 'first_argument' in constructor call -E: 39: No value for argument 'second_argument' in constructor call -E: 39: No value for argument 'third_argument' in constructor call -E: 41: Too many positional arguments for constructor call -E: 46: No value for argument 'first_argument' in constructor call -E: 46: Unexpected keyword argument 'bob' in constructor call -E: 47: Unexpected keyword argument 'coin' in constructor call -E: 49: Argument 'one' passed by position and keyword in constructor call -E: 52: No value for argument 'first_argument' in constructor call -E: 53: Too many positional arguments for constructor call -E: 59: Too many positional arguments for constructor call -E: 62: Too many positional arguments for constructor call -E: 63: No value for argument 'first_argument' in constructor call -E: 63: Unexpected keyword argument 'one' in constructor call diff --git a/test/messages/func_loopvar_in_closure.txt b/test/messages/func_loopvar_in_closure.txt deleted file mode 100644 index 5b068f4..0000000 --- a/test/messages/func_loopvar_in_closure.txt +++ /dev/null @@ -1,8 +0,0 @@ -W: 21:good_case3: Unused variable 'i' -W: 45:good_case6.: Using possibly undefined loop variable 'i' -W: 78:bad_case.: Cell variable i defined in loop -W: 83:bad_case2.: Cell variable i defined in loop -W: 91:bad_case3.: Cell variable j defined in loop -W:101:bad_case4.nested: Cell variable i defined in loop -W:122:bad_case5.: Cell variable i defined in loop -W:130:bad_case6.: Cell variable i defined in loop diff --git a/test/messages/func_undefined_var.txt b/test/messages/func_undefined_var.txt deleted file mode 100644 index 5505156..0000000 --- a/test/messages/func_undefined_var.txt +++ /dev/null @@ -1,14 +0,0 @@ -E: 8: Undefined variable 'unknown' -E: 14:in_method: Undefined variable 'nomoreknown' -E: 22:bad_default: Undefined variable 'unknown2' -E: 25:bad_default: Undefined variable 'xxxx' -E: 26:bad_default: Undefined variable 'xxxx' -E: 27:bad_default: Undefined variable 'augvar' -E: 28:bad_default: Undefined variable 'vardel' -E: 56: Using variable 'PLOUF' before assignment -E: 65:if_branch_test: Using variable 'xxx' before assignment -E: 89:test_arguments: Using variable 'TestClass' before assignment -E: 93:TestClass: Using variable 'Ancestor' before assignment -E: 96:TestClass.MissingAncestor: Using variable 'Ancestor1' before assignment -E:103:TestClass.test1.UsingBeforeDefinition: Using variable 'Empty' before assignment -W: 27:bad_default: Unused variable 'augvar' -- cgit v1.2.1