diff options
author | Pierre Sassoulas <pierre.sassoulas@gmail.com> | 2019-07-21 10:56:00 +0200 |
---|---|---|
committer | Claudiu Popa <pcmanticore@gmail.com> | 2019-09-10 11:20:16 +0200 |
commit | 997d9d1ec72fce84903da4784ac56fbe30e6da1e (patch) | |
tree | 9a0ddd3ba0975e045e408d9793cce096ecaeaa75 /tests/functional/s | |
parent | 676ec55ff9d8f10e52b740a57e4e62a3255d6709 (diff) | |
download | pylint-git-997d9d1ec72fce84903da4784ac56fbe30e6da1e.tar.gz |
[functional tests] Rename example_functional_tests.py => e/example_functional_tests.py
Permit to navigate in the functional tests easier.
Diffstat (limited to 'tests/functional/s')
75 files changed, 1563 insertions, 0 deletions
diff --git a/tests/functional/s/self_assigning_variable.py b/tests/functional/s/self_assigning_variable.py new file mode 100644 index 000000000..2c5148f63 --- /dev/null +++ b/tests/functional/s/self_assigning_variable.py @@ -0,0 +1,20 @@ +# pylint: disable=missing-docstring,too-few-public-methods +# pylint: disable=unpacking-non-sequence,attribute-defined-outside-init,invalid-name + +class Class: + pass + +CLS = Class() +FIRST = 1 +# Not enough values on the right hand side +FIRST, SECOND = FIRST +# Not enough values on the left hand side +FIRST = FIRST, SECOND +# Not equivalent to a self assignment +FIRST = (FIRST, ) +# Not assigning to an attribute +CLS.FIRST = FIRST +# Not a name on the right hand side +FIRST = Class() +FIRST = FIRST # [self-assigning-variable] +FIRST, SECOND = FIRST, CLS.FIRST # [self-assigning-variable] diff --git a/tests/functional/s/self_assigning_variable.txt b/tests/functional/s/self_assigning_variable.txt new file mode 100644 index 000000000..1787f1f47 --- /dev/null +++ b/tests/functional/s/self_assigning_variable.txt @@ -0,0 +1,2 @@ +self-assigning-variable:19::Assigning the same variable 'FIRST' to itself +self-assigning-variable:20::Assigning the same variable 'FIRST' to itself diff --git a/tests/functional/s/self_cls_assignment.py b/tests/functional/s/self_cls_assignment.py new file mode 100644 index 000000000..4e63bb422 --- /dev/null +++ b/tests/functional/s/self_cls_assignment.py @@ -0,0 +1,47 @@ +"""Warning about assigning self/cls variable.""" +from __future__ import print_function +# pylint: disable=too-few-public-methods, useless-object-inheritance + +class Foo(object): + """Class with methods that check for self/cls assignment""" + + # pylint: disable=no-self-argument,no-self-use + def self_foo(bar_): + """Instance method, should warn for bar""" + bar_ = 10 # [self-cls-assignment] + + # pylint: disable=no-self-use + def self_foofoo(self, lala): + """Instance method, should warn for self""" + self = lala # [self-cls-assignment] + + @classmethod + def cls_foo(cls): + """Class method, should warn for cls""" + cls = 'tada' # [self-cls-assignment] + + # pylint: disable=unused-argument + @staticmethod + def static_foo(lala): + """Static method, no warnings""" + lala = 10 + + +# pylint: disable=unused-argument +def free_foo(bar_, lala): + """Free function, no warnings""" + bar_ = lala + + +class TestNonLocal: + """Test class for nonlocal assignment of self""" + + def function(self, param): + """This function uses nonlocal to reassign self""" + + def _set_param(param): + nonlocal self + self = param # [self-cls-assignment] + + _set_param(param) + return self diff --git a/tests/functional/s/self_cls_assignment.txt b/tests/functional/s/self_cls_assignment.txt new file mode 100644 index 000000000..42a90340c --- /dev/null +++ b/tests/functional/s/self_cls_assignment.txt @@ -0,0 +1,4 @@ +self-cls-assignment:11:Foo.self_foo:Invalid assignment to bar_ in method +self-cls-assignment:16:Foo.self_foofoo:Invalid assignment to self in method +self-cls-assignment:21:Foo.cls_foo:Invalid assignment to cls in method +self-cls-assignment:44:TestNonLocal.function._set_param:Invalid assignment to self in method diff --git a/tests/functional/s/signature_differs.py b/tests/functional/s/signature_differs.py new file mode 100644 index 000000000..920611fd0 --- /dev/null +++ b/tests/functional/s/signature_differs.py @@ -0,0 +1,22 @@ +# pylint: disable=too-few-public-methods, missing-docstring, no-self-use, useless-object-inheritance + +class Abcd(object): + + def __init__(self): + self.aarg = False + + def abcd(self, aaa=1, bbbb=None): + return aaa, bbbb + + def args(self): + self.aarg = True + + +class Cdef(Abcd): + + def __init__(self, aaa): + Abcd.__init__(self) + self.aaa = aaa + + def abcd(self, aaa, bbbb=None): # [signature-differs] + return aaa, bbbb diff --git a/tests/functional/s/signature_differs.txt b/tests/functional/s/signature_differs.txt new file mode 100644 index 000000000..a9985e5fc --- /dev/null +++ b/tests/functional/s/signature_differs.txt @@ -0,0 +1 @@ +signature-differs:21:Cdef.abcd:Signature differs from overridden 'abcd' method diff --git a/tests/functional/s/simplifiable_if_expression.py b/tests/functional/s/simplifiable_if_expression.py new file mode 100644 index 000000000..bcfdf890b --- /dev/null +++ b/tests/functional/s/simplifiable_if_expression.py @@ -0,0 +1,27 @@ +"""Test that some if expressions can be simplified.""" + +# pylint: disable=missing-docstring, invalid-name + + +def test_simplifiable_1(arg): + # Simple test that can be replaced by bool(arg) + return True if arg else False # [simplifiable-if-expression] + +def test_simplifiable_2(arg): + # Simple test that can be replaced by not arg + return False if arg else True # [simplifiable-if-expression] + +def test_simplifiable_3(arg): + # Simple test that can be replaced by arg == 1 + return True if arg == 1 else False # [simplifiable-if-expression] + +def test_simplifiable_4(arg): + # Simple test that can be replaced by not (arg == 1) + return False if arg == 1 else True # [simplifiable-if-expression] + +def test_not_simplifiable(arg): + x = True if arg else True + y = 0 if arg else 1 + t = False if arg != 1 else False + t2 = None if arg > 3 else False + return x, y, t, t2 diff --git a/tests/functional/s/simplifiable_if_expression.txt b/tests/functional/s/simplifiable_if_expression.txt new file mode 100644 index 000000000..b35e08462 --- /dev/null +++ b/tests/functional/s/simplifiable_if_expression.txt @@ -0,0 +1,4 @@ +simplifiable-if-expression:8:test_simplifiable_1:The if expression can be replaced with 'bool(test)' +simplifiable-if-expression:12:test_simplifiable_2:The if expression can be replaced with 'not test' +simplifiable-if-expression:16:test_simplifiable_3:The if expression can be replaced with 'test' +simplifiable-if-expression:20:test_simplifiable_4:The if expression can be replaced with 'not test'
\ No newline at end of file diff --git a/tests/functional/s/simplifiable_if_statement.py b/tests/functional/s/simplifiable_if_statement.py new file mode 100644 index 000000000..4d4c8b5d4 --- /dev/null +++ b/tests/functional/s/simplifiable_if_statement.py @@ -0,0 +1,146 @@ +"""Test that some if statement tests can be simplified."""
+
+# pylint: disable=missing-docstring, invalid-name, no-else-return, arguments-out-of-order
+
+
+def test_simplifiable_1(arg):
+ # Simple test that can be replaced by bool(arg)
+ if arg: # [simplifiable-if-statement]
+ return True
+ else:
+ return False
+
+
+def test_simplifiable_2(arg, arg2):
+ # Can be reduced to bool(arg and not arg2)
+ if arg and not arg2: # [simplifiable-if-statement]
+ return True
+ else:
+ return False
+
+
+def test_simplifiable_3(arg, arg2):
+ # Can be reduced to bool(arg and not arg2)
+ if arg and not arg2: # [simplifiable-if-statement]
+ var = True
+ else:
+ var = False
+ return var
+
+
+def test_simplifiable_4(arg):
+ if arg:
+ var = True
+ else:
+ if arg == "arg1": # [simplifiable-if-statement]
+ return True
+ else:
+ return False
+ return var
+
+
+def test_not_necessarily_simplifiable_1(arg, arg2):
+ # Can be reduced to bool(not arg and not arg2) or to
+ # `not all(N)`, which is a bit harder to understand
+ # than `any(N)` when var should be False.
+ if arg or arg2:
+ var = False
+ else:
+ var = True
+ return var
+
+
+def test_not_necessarily_simplifiabile_2(arg):
+ # This could theoretically be reduced to `not arg or arg > 3`
+ # but the net result is that now the condition is harder to understand,
+ # because it requires understanding of an extra clause:
+ # * first, there is the negation of truthness with `not arg`
+ # * the second clause is `arg > 3`, which occurs when arg has a
+ # a truth value, but it implies that `arg > 3` is equivalent
+ # with `arg and arg > 3`, which means that the user must
+ # think about this assumption when evaluating `arg > 3`.
+ # The original form is easier to grasp.
+ if arg and arg <= 3:
+ return False
+ else:
+ return True
+
+
+def test_not_simplifiable_3(arg):
+ if arg:
+ test_not_necessarily_simplifiabile_2(arg)
+ test_not_necessarily_simplifiable_1(arg, arg)
+ return False
+ else:
+ if arg < 3:
+ test_simplifiable_3(arg, 42)
+ return True
+
+
+def test_not_simplifiable_4(arg):
+ # Not interested in multiple elifs
+ if arg == "any":
+ return True
+ elif test_not_simplifiable_3(arg) == arg:
+ return True
+ else:
+ return False
+
+
+def test_not_simplifiable_5(arg):
+ # Different actions in each branch
+ if arg == "any":
+ return True
+ else:
+ var = 42
+ return var
+
+
+def test_not_simplifiable_6(arg):
+ # Different actions in each branch
+ if arg == "any":
+ var = 42
+ else:
+ return True
+ return var
+
+def test_not_simplifiable_7(arg):
+ # Returning something different
+ if arg == "any":
+ return 4
+ else:
+ return 5
+
+
+def test_not_simplifiable_8(arg):
+ # Only one of the branch returns something boolean
+ if arg == "any":
+ return True
+ else:
+ return 0
+
+
+def test_not_simplifiable_9():
+ # Not the same targets
+ first = True
+ second = 1
+ third = [1]
+ fourth = False
+ fifth = False
+
+ if first and second in third:
+ fourth = True
+ else:
+ fifth = True
+ return fourth + fifth
+
+
+def test_not_simplifiable_10():
+ # Subscripts are not considered
+ object_type = 'read'
+ filter_kwargs = {}
+ if object_type == 'read':
+ filter_kwargs['a'] = True
+ else:
+ filter_kwargs['b'] = True
+ return filter_kwargs
diff --git a/tests/functional/s/simplifiable_if_statement.txt b/tests/functional/s/simplifiable_if_statement.txt new file mode 100644 index 000000000..1c5110908 --- /dev/null +++ b/tests/functional/s/simplifiable_if_statement.txt @@ -0,0 +1,4 @@ +simplifiable-if-statement:8:test_simplifiable_1:The if statement can be replaced with 'return bool(test)' +simplifiable-if-statement:16:test_simplifiable_2:The if statement can be replaced with 'return bool(test)' +simplifiable-if-statement:24:test_simplifiable_3:The if statement can be replaced with 'var = bool(test)' +simplifiable-if-statement:35:test_simplifiable_4:The if statement can be replaced with 'return bool(test)' diff --git a/tests/functional/s/simplify_chained_comparison.py b/tests/functional/s/simplify_chained_comparison.py new file mode 100644 index 000000000..4be9fbe3d --- /dev/null +++ b/tests/functional/s/simplify_chained_comparison.py @@ -0,0 +1,89 @@ +"""Test that some boolean expression statement tests can be simplified.""" + +# pylint: disable=missing-docstring, invalid-name, no-else-return, too-many-branches + + +def test_simplify_chained_comparison_1(): + a = 1 + b = 2 + c = 3 + return a < b and b < c # [chained-comparison] + + +def test_simplify_chained_comparison_2(): + a = 1 + return a < 10 and a > 1 # [chained-comparison] + + +def test_simplify_chained_comparison_3(): + a = 1 + b = 2 + c = 3 + d = 4 + if a < 10 and a > 1: # [chained-comparison] + pass + elif a > 1 and a < 10: # [chained-comparison] + pass + elif a > 1 and a <= 10: # [chained-comparison] + pass + elif a > 1 and a < 10 and b == 2: # [chained-comparison] + pass + elif a > 1 and c == b and a < 10: # [chained-comparison] + pass + elif a > 100 and c == b and a < 10: # [chained-comparison] + # In this comparison we are not checking whether left bound is actually + # lower than right bound or not. + pass + elif a < b and b < c: # [chained-comparison] + pass + elif a > b and b > c: # [chained-comparison] + pass + elif a < b and a == 1 and b < c: # [chained-comparison] + pass + elif a < b and b < c and c == 786: # [chained-comparison] + pass + elif a < b and b < 0 and c == 786: # [chained-comparison] + pass + elif a < b and c == 786 and b < 0: # [chained-comparison] + pass + elif c == 786 and b < 0 and a < b: # [chained-comparison] + pass + elif a < b < c and c < d: # [chained-comparison] + pass + elif b < c < d and a < b: # [chained-comparison] + pass + elif a < b < c and a < b and b < c: # [chained-comparison] + pass + + +def test_not_simplify_chained_comparison_1(): + a = 1 + b = 2 + c = 3 + d = 4 + if a < 10 and b > 1: + pass + elif a > 1 and b < 10: + pass + elif a > 1 and a == 10: + pass + elif a == 1 and b == 2: + pass + elif a > 1 and a > 10: + pass + elif a < 100 and a < 10: + pass + elif a < b and a < c: + pass + elif a < b and a == 1 and a < c: + pass + elif a < b and a < c and c == 786: + pass + elif a < b < c and b < d: + pass + elif a < b < c and a < d: + pass + elif b < c < d and a < c: + pass + elif b < c < d and a < d: + pass diff --git a/tests/functional/s/simplify_chained_comparison.txt b/tests/functional/s/simplify_chained_comparison.txt new file mode 100644 index 000000000..3107e60cb --- /dev/null +++ b/tests/functional/s/simplify_chained_comparison.txt @@ -0,0 +1,18 @@ +chained-comparison:10:test_simplify_chained_comparison_1:Simplify chained comparison between the operands +chained-comparison:15:test_simplify_chained_comparison_2:Simplify chained comparison between the operands +chained-comparison:23:test_simplify_chained_comparison_3:Simplify chained comparison between the operands +chained-comparison:25:test_simplify_chained_comparison_3:Simplify chained comparison between the operands +chained-comparison:27:test_simplify_chained_comparison_3:Simplify chained comparison between the operands +chained-comparison:29:test_simplify_chained_comparison_3:Simplify chained comparison between the operands +chained-comparison:31:test_simplify_chained_comparison_3:Simplify chained comparison between the operands +chained-comparison:33:test_simplify_chained_comparison_3:Simplify chained comparison between the operands +chained-comparison:37:test_simplify_chained_comparison_3:Simplify chained comparison between the operands +chained-comparison:39:test_simplify_chained_comparison_3:Simplify chained comparison between the operands +chained-comparison:41:test_simplify_chained_comparison_3:Simplify chained comparison between the operands +chained-comparison:43:test_simplify_chained_comparison_3:Simplify chained comparison between the operands +chained-comparison:45:test_simplify_chained_comparison_3:Simplify chained comparison between the operands +chained-comparison:47:test_simplify_chained_comparison_3:Simplify chained comparison between the operands +chained-comparison:49:test_simplify_chained_comparison_3:Simplify chained comparison between the operands +chained-comparison:51:test_simplify_chained_comparison_3:Simplify chained comparison between the operands +chained-comparison:53:test_simplify_chained_comparison_3:Simplify chained comparison between the operands +chained-comparison:55:test_simplify_chained_comparison_3:Simplify chained comparison between the operands diff --git a/tests/functional/s/singledispatch_functions.py b/tests/functional/s/singledispatch_functions.py new file mode 100644 index 000000000..cfd4d873c --- /dev/null +++ b/tests/functional/s/singledispatch_functions.py @@ -0,0 +1,76 @@ +# pylint: disable=missing-docstring,import-error,unused-import,assignment-from-no-return +# pylint: disable=invalid-name, too-few-public-methods, useless-object-inheritance +from __future__ import print_function +from UNINFERABLE import uninferable_func + +try: + from functools import singledispatch +except ImportError: + from singledispatch import singledispatch + +my_single_dispatch = singledispatch + + +class FakeSingleDispatch(object): + + @staticmethod + def register(function): + return function + + def __call__(self, function): + return function + +fake_singledispatch_decorator = FakeSingleDispatch() + +@singledispatch +def func(arg): + return arg + + +@func.register(str) +def _(arg): + return 42 + + +@func.register(float) +@func.register(int) +def _(arg): + return 42 + + +@my_single_dispatch +def func2(arg): + return arg + + +@func2.register(int) +def _(arg): + return 42 + + +@singledispatch +def with_extra_arg(arg, verbose=False): + if verbose: + print(arg) + return arg + + +@with_extra_arg.register(str) +def _(arg, verbose=False): + unused = 42 # [unused-variable] + return arg[::-1] + + +@fake_singledispatch_decorator +def not_single_dispatch(arg): # [unused-argument] + return 'not yet implemented' + + +@fake_singledispatch_decorator.register(str) +def bad_single_dispatch(arg): # [unused-argument] + return 42 + + +@fake_singledispatch_decorator.register(str) +def bad_single_dispatch(arg): # [unused-argument, function-redefined] + return 24 diff --git a/tests/functional/s/singledispatch_functions.rc b/tests/functional/s/singledispatch_functions.rc new file mode 100644 index 000000000..fc795dc6d --- /dev/null +++ b/tests/functional/s/singledispatch_functions.rc @@ -0,0 +1,3 @@ +[testoptions] +;http://bugs.python.org/issue10445 +max_pyver=3.0 diff --git a/tests/functional/s/singledispatch_functions.txt b/tests/functional/s/singledispatch_functions.txt new file mode 100644 index 000000000..568f41b31 --- /dev/null +++ b/tests/functional/s/singledispatch_functions.txt @@ -0,0 +1,5 @@ +unused-variable:60:_:Unused variable 'unused' +unused-argument:65:not_single_dispatch:Unused argument 'arg' +unused-argument:70:bad_single_dispatch:Unused argument 'arg' +function-redefined:75:bad_single_dispatch:function already defined line 70 +unused-argument:75:bad_single_dispatch:Unused argument 'arg'
\ No newline at end of file diff --git a/tests/functional/s/singledispatch_functions_py3.py b/tests/functional/s/singledispatch_functions_py3.py new file mode 100644 index 000000000..cfd4d873c --- /dev/null +++ b/tests/functional/s/singledispatch_functions_py3.py @@ -0,0 +1,76 @@ +# pylint: disable=missing-docstring,import-error,unused-import,assignment-from-no-return +# pylint: disable=invalid-name, too-few-public-methods, useless-object-inheritance +from __future__ import print_function +from UNINFERABLE import uninferable_func + +try: + from functools import singledispatch +except ImportError: + from singledispatch import singledispatch + +my_single_dispatch = singledispatch + + +class FakeSingleDispatch(object): + + @staticmethod + def register(function): + return function + + def __call__(self, function): + return function + +fake_singledispatch_decorator = FakeSingleDispatch() + +@singledispatch +def func(arg): + return arg + + +@func.register(str) +def _(arg): + return 42 + + +@func.register(float) +@func.register(int) +def _(arg): + return 42 + + +@my_single_dispatch +def func2(arg): + return arg + + +@func2.register(int) +def _(arg): + return 42 + + +@singledispatch +def with_extra_arg(arg, verbose=False): + if verbose: + print(arg) + return arg + + +@with_extra_arg.register(str) +def _(arg, verbose=False): + unused = 42 # [unused-variable] + return arg[::-1] + + +@fake_singledispatch_decorator +def not_single_dispatch(arg): # [unused-argument] + return 'not yet implemented' + + +@fake_singledispatch_decorator.register(str) +def bad_single_dispatch(arg): # [unused-argument] + return 42 + + +@fake_singledispatch_decorator.register(str) +def bad_single_dispatch(arg): # [unused-argument, function-redefined] + return 24 diff --git a/tests/functional/s/singledispatch_functions_py3.rc b/tests/functional/s/singledispatch_functions_py3.rc new file mode 100644 index 000000000..d43f6c339 --- /dev/null +++ b/tests/functional/s/singledispatch_functions_py3.rc @@ -0,0 +1,3 @@ +[testoptions] +;http://bugs.python.org/issue10445 +min_pyver=3.4 diff --git a/tests/functional/s/singledispatch_functions_py3.txt b/tests/functional/s/singledispatch_functions_py3.txt new file mode 100644 index 000000000..568f41b31 --- /dev/null +++ b/tests/functional/s/singledispatch_functions_py3.txt @@ -0,0 +1,5 @@ +unused-variable:60:_:Unused variable 'unused' +unused-argument:65:not_single_dispatch:Unused argument 'arg' +unused-argument:70:bad_single_dispatch:Unused argument 'arg' +function-redefined:75:bad_single_dispatch:function already defined line 70 +unused-argument:75:bad_single_dispatch:Unused argument 'arg'
\ No newline at end of file diff --git a/tests/functional/s/singleton_comparison.py b/tests/functional/s/singleton_comparison.py new file mode 100644 index 000000000..9a28c0e2e --- /dev/null +++ b/tests/functional/s/singleton_comparison.py @@ -0,0 +1,15 @@ +# pylint: disable=missing-docstring, invalid-name, misplaced-comparison-constant,literal-comparison, comparison-with-itself +x = 42 +a = x is None +b = x == None # [singleton-comparison] +c = x == True # [singleton-comparison] +d = x == False # [singleton-comparison] +e = True == True # [singleton-comparison] +f = x is 1 +g = 123 is "123" +h = None is x +i = None == x # [singleton-comparison] + +j = x != True # [singleton-comparison] +j1 = x != False # [singleton-comparison] +j2 = x != None # [singleton-comparison] diff --git a/tests/functional/s/singleton_comparison.txt b/tests/functional/s/singleton_comparison.txt new file mode 100644 index 000000000..533d71f63 --- /dev/null +++ b/tests/functional/s/singleton_comparison.txt @@ -0,0 +1,8 @@ +singleton-comparison:4::Comparison to None should be 'expr is None' +singleton-comparison:5::Comparison to True should be just 'expr' +singleton-comparison:6::Comparison to False should be 'not expr' +singleton-comparison:7::Comparison to True should be just 'expr' +singleton-comparison:11::Comparison to None should be 'expr is None' +singleton-comparison:13::Comparison to True should be just 'not expr' +singleton-comparison:14::Comparison to False should be 'expr' +singleton-comparison:15::Comparison to None should be 'expr is not None' diff --git a/tests/functional/s/slots_checks.py b/tests/functional/s/slots_checks.py new file mode 100644 index 000000000..64a439f33 --- /dev/null +++ b/tests/functional/s/slots_checks.py @@ -0,0 +1,105 @@ +""" Checks that classes uses valid __slots__ """ + +# pylint: disable=too-few-public-methods, missing-docstring, no-absolute-import, useless-object-inheritance +# pylint: disable=using-constant-test, wrong-import-position, no-else-return, line-too-long +from collections import deque + +def func(): + if True: + return ("a", "b", "c") + else: + return [str(var) for var in range(3)] + + +class NotIterable(object): + def __iter_(self): + """ do nothing """ + +class Good(object): + __slots__ = () + +class SecondGood(object): + __slots__ = [] + +class ThirdGood(object): + __slots__ = ['a'] + +class FourthGood(object): + __slots__ = ('a%s' % i for i in range(10)) + +class FifthGood(object): + __slots__ = deque(["a", "b", "c"]) + +class SixthGood(object): + __slots__ = {"a": "b", "c": "d"} + +class Bad(object): # [invalid-slots] + __slots__ = list + +class SecondBad(object): # [invalid-slots] + __slots__ = 1 + +class ThirdBad(object): + __slots__ = ('a', 2) # [invalid-slots-object] + +class FourthBad(object): # [invalid-slots] + __slots__ = NotIterable() + +class FifthBad(object): + __slots__ = ("a", "b", "") # [invalid-slots-object] + +class SixthBad(object): # [single-string-used-for-slots] + __slots__ = "a" + +class SeventhBad(object): # [single-string-used-for-slots] + __slots__ = ('foo') + +class EighthBad(object): # [single-string-used-for-slots] + __slots__ = deque.__name__ + +class PotentiallyGood(object): + __slots__ = func() + +class PotentiallySecondGood(object): + __slots__ = ('a', deque.__name__) + + +import six + + +class Metaclass(type): + + def __iter__(cls): + for value in range(10): + yield str(value) + + +@six.add_metaclass(Metaclass) +class IterableClass(object): + pass + +class PotentiallyThirdGood(object): + __slots__ = IterableClass + +class PotentiallyFourthGood(object): + __slots__ = Good.__slots__ + + +class ValueInSlotConflict(object): + __slots__ = ('first', 'second', 'third', 'fourth') # [class-variable-slots-conflict, class-variable-slots-conflict, class-variable-slots-conflict] + first = None + + @property + def third(self): + return 42 + + def fourth(self): + return self.third + + +class Parent(object): + first = 42 + + +class ChildNotAffectedByValueInSlot(Parent): + __slots__ = ('first', ) diff --git a/tests/functional/s/slots_checks.txt b/tests/functional/s/slots_checks.txt new file mode 100644 index 000000000..b3d71afcc --- /dev/null +++ b/tests/functional/s/slots_checks.txt @@ -0,0 +1,11 @@ +invalid-slots:36:Bad:Invalid __slots__ object +invalid-slots:39:SecondBad:Invalid __slots__ object +invalid-slots-object:43:ThirdBad:Invalid object '2' in __slots__, must contain only non empty strings +invalid-slots:45:FourthBad:Invalid __slots__ object +invalid-slots-object:49:FifthBad:"Invalid object ""''"" in __slots__, must contain only non empty strings" +single-string-used-for-slots:51:SixthBad:Class __slots__ should be a non-string iterable +single-string-used-for-slots:54:SeventhBad:Class __slots__ should be a non-string iterable +single-string-used-for-slots:57:EighthBad:Class __slots__ should be a non-string iterable +class-variable-slots-conflict:89:ValueInSlotConflict:Value 'first' in slots conflicts with class variable +class-variable-slots-conflict:89:ValueInSlotConflict:Value 'fourth' in slots conflicts with class variable +class-variable-slots-conflict:89:ValueInSlotConflict:Value 'third' in slots conflicts with class variable diff --git a/tests/functional/s/socketerror_import.py b/tests/functional/s/socketerror_import.py new file mode 100644 index 000000000..df5de2957 --- /dev/null +++ b/tests/functional/s/socketerror_import.py @@ -0,0 +1,6 @@ +"""ds""" +from __future__ import absolute_import, print_function +from socket import error +__revision__ = '$Id: socketerror_import.py,v 1.2 2005-12-28 14:58:22 syt Exp $' + +print(error) diff --git a/tests/functional/s/star_needs_assignment_target.py b/tests/functional/s/star_needs_assignment_target.py new file mode 100644 index 000000000..5421c226b --- /dev/null +++ b/tests/functional/s/star_needs_assignment_target.py @@ -0,0 +1,4 @@ +"""Test for a = *b"""
+
+FIRST = *[1, 2] # [star-needs-assignment-target]
+*THIRD, FOURTH = [1, 2, 3,]
diff --git a/tests/functional/s/star_needs_assignment_target.rc b/tests/functional/s/star_needs_assignment_target.rc new file mode 100644 index 000000000..c093be204 --- /dev/null +++ b/tests/functional/s/star_needs_assignment_target.rc @@ -0,0 +1,2 @@ +[testoptions] +min_pyver=3.0 diff --git a/tests/functional/s/star_needs_assignment_target.txt b/tests/functional/s/star_needs_assignment_target.txt new file mode 100644 index 000000000..b66975c97 --- /dev/null +++ b/tests/functional/s/star_needs_assignment_target.txt @@ -0,0 +1 @@ +star-needs-assignment-target:3::Can use starred expression only in assignment target
diff --git a/tests/functional/s/star_needs_assignment_target_py35.py b/tests/functional/s/star_needs_assignment_target_py35.py new file mode 100644 index 000000000..fb5eea86a --- /dev/null +++ b/tests/functional/s/star_needs_assignment_target_py35.py @@ -0,0 +1,15 @@ +""" +Test PEP 0448 -- Additional Unpacking Generalizations +https://www.python.org/dev/peps/pep-0448/ +""" + +# pylint: disable=superfluous-parens, unnecessary-comprehension + +UNPACK_TUPLE = (*range(4), 4) +UNPACK_LIST = [*range(4), 4] +UNPACK_SET = {*range(4), 4} +UNPACK_DICT = {'a': 1, **{'b': '2'}} +UNPACK_DICT2 = {**UNPACK_DICT, "x": 1, "y": 2} +UNPACK_DICT3 = {**{'a': 1}, 'a': 2, **{'a': 3}} + +UNPACK_IN_COMP = {elem for elem in (*range(10))} # [star-needs-assignment-target] diff --git a/tests/functional/s/star_needs_assignment_target_py35.rc b/tests/functional/s/star_needs_assignment_target_py35.rc new file mode 100644 index 000000000..71de8b630 --- /dev/null +++ b/tests/functional/s/star_needs_assignment_target_py35.rc @@ -0,0 +1,2 @@ +[testoptions] +min_pyver=3.5 diff --git a/tests/functional/s/star_needs_assignment_target_py35.txt b/tests/functional/s/star_needs_assignment_target_py35.txt new file mode 100644 index 000000000..07770523b --- /dev/null +++ b/tests/functional/s/star_needs_assignment_target_py35.txt @@ -0,0 +1 @@ +star-needs-assignment-target:15::Can use starred expression only in assignment target
\ No newline at end of file diff --git a/tests/functional/s/statement_without_effect.py b/tests/functional/s/statement_without_effect.py new file mode 100644 index 000000000..bac4f6795 --- /dev/null +++ b/tests/functional/s/statement_without_effect.py @@ -0,0 +1,75 @@ +"""Test for statements without effects.""" +# pylint: disable=too-few-public-methods, useless-object-inheritance, unnecessary-comprehension + +# +1:[pointless-string-statement] +"""inline doc string should use a separated message""" + +__revision__ = '' + +__revision__ # [pointless-statement] + +__revision__ <= 1 # [pointless-statement] + +__revision__.lower() + +[i for i in __revision__] # [pointless-statement] + +# +1:[pointless-string-statement] +"""inline doc string should use a separated message""" + + +__revision__.lower(); # [unnecessary-semicolon] + +list() and tuple() # [expression-not-assigned] + +def to_be(): + """return 42""" + return "42" + +ANSWER = to_be() # ok +ANSWER == to_be() # [expression-not-assigned] + +to_be() or not to_be() # [expression-not-assigned] +to_be().title # [expression-not-assigned] + +GOOD_ATTRIBUTE_DOCSTRING = 42 +"""Module level attribute docstring is fine. """ + +class ClassLevelAttributeTest(object): + """ test attribute docstrings. """ + + good_attribute_docstring = 24 + """ class level attribute docstring is fine either. """ + second_good_attribute_docstring = 42 + # Comments are good. + + # empty lines are good, too. + """ Still a valid class level attribute docstring. """ + + def __init__(self): + self.attr = 42 + """ Good attribute docstring """ + attr = 24 + """ Still a good __init__ level attribute docstring. """ + val = 0 + for val in range(42): + val += attr + # +1:[pointless-string-statement] + """ Invalid attribute docstring """ + self.val = val + + def test(self): + """ invalid attribute docstrings here. """ + self.val = 42 + # +1:[pointless-string-statement] + """ this is an invalid attribute docstring. """ + + +def ellipsis(): + """Test that an Ellipsis as a body does not trigger the error""" + ... + + +class EllipsisBody: + """Test that an Ellipsis as a body does not trigger the error""" + ... diff --git a/tests/functional/s/statement_without_effect.txt b/tests/functional/s/statement_without_effect.txt new file mode 100644 index 000000000..bda6eaea9 --- /dev/null +++ b/tests/functional/s/statement_without_effect.txt @@ -0,0 +1,60 @@ +pointless-string-statement:5::String statement has no effect +pointless-statement:6::"""Statement seems to have no effect +"" +" +pointless-statement:8::"""Statement seems to have no effect +"" +" +pointless-statement:9::Statement seems to have no effect +pointless-statement:11::Statement seems to have no effect +pointless-statement:12::"""Statement seems to have no effect +"" +" +pointless-statement:15::Statement seems to have no effect +pointless-string-statement:15::"""String statement has no effect +"" +" +unnecessary-semicolon:17::"""Unnecessary semicolon +"" +" +pointless-string-statement:18::String statement has no effect +unnecessary-semicolon:18::"""Unnecessary semicolon +"" +" +expression-not-assigned:19::"""Expression """"list() and tuple()"""" is assigned to nothing +"" +" +expression-not-assigned:20::"""Expression """"list() and tuple()"""" is assigned to nothing +"" +" +unnecessary-semicolon:21::Unnecessary semicolon +expression-not-assigned:23::"Expression ""list() and tuple()"" is assigned to nothing" +expression-not-assigned:26::"""Expression """"ANSWER == to_be()"""" is assigned to nothing +"" +" +expression-not-assigned:27::"""Expression """"ANSWER == to_be()"""" is assigned to nothing +"" +" +expression-not-assigned:28::"""Expression """"to_be() or not to_be()"""" is assigned to nothing +"" +" +expression-not-assigned:29::"""Expression """"to_be() or not to_be()"""" is assigned to nothing +"" +" +expression-not-assigned:30::"Expression ""ANSWER == to_be()"" is assigned to nothing" +expression-not-assigned:32::"Expression ""to_be() or not to_be()"" is assigned to nothing" +expression-not-assigned:33::"Expression ""to_be().title"" is assigned to nothing" +pointless-string-statement:54:ClassLevelAttributeTest.__init__:"""String statement has no effect +"" +" +pointless-string-statement:55:ClassLevelAttributeTest.__init__:"""String statement has no effect +"" +" +pointless-string-statement:58:ClassLevelAttributeTest.__init__:String statement has no effect +pointless-string-statement:61:ClassLevelAttributeTest.test:"""String statement has no effect +"" +" +pointless-string-statement:62:ClassLevelAttributeTest.test:"""String statement has no effect +"" +" +pointless-string-statement:65:ClassLevelAttributeTest.test:String statement has no effect diff --git a/tests/functional/s/statement_without_effect_py36.py b/tests/functional/s/statement_without_effect_py36.py new file mode 100644 index 000000000..59745ce2b --- /dev/null +++ b/tests/functional/s/statement_without_effect_py36.py @@ -0,0 +1,18 @@ +"""Test for statements without effects.""" +# pylint: disable=too-few-public-methods, useless-object-inheritance + + +class ClassLevelAttributeTest(object): + """ test attribute docstrings. """ + + some_variable: int = 42 + """Data docstring""" + + some_other_variable: int = 42 + """Data docstring""" + + def func(self): + """Some Empty Docstring""" + + # +1: [pointless-string-statement] + """useless""" diff --git a/tests/functional/s/statement_without_effect_py36.rc b/tests/functional/s/statement_without_effect_py36.rc new file mode 100644 index 000000000..0ba2b6333 --- /dev/null +++ b/tests/functional/s/statement_without_effect_py36.rc @@ -0,0 +1,2 @@ +[testoptions] +min_pyver=3.6 diff --git a/tests/functional/s/statement_without_effect_py36.txt b/tests/functional/s/statement_without_effect_py36.txt new file mode 100644 index 000000000..6b782923b --- /dev/null +++ b/tests/functional/s/statement_without_effect_py36.txt @@ -0,0 +1 @@ +pointless-string-statement:18:ClassLevelAttributeTest:String statement has no effect
\ No newline at end of file diff --git a/tests/functional/s/stop_iteration_inside_generator.py b/tests/functional/s/stop_iteration_inside_generator.py new file mode 100644 index 000000000..a51f2d3e7 --- /dev/null +++ b/tests/functional/s/stop_iteration_inside_generator.py @@ -0,0 +1,129 @@ +""" +Test that no StopIteration is raised inside a generator +""" +# pylint: disable=missing-docstring,invalid-name,import-error, try-except-raise, wrong-import-position +import asyncio + +class RebornStopIteration(StopIteration): + """ + A class inheriting from StopIteration exception + """ + +# This one is ok +def gen_ok(): + yield 1 + yield 2 + yield 3 + +# pylint should warn about this one +# because of a direct raising of StopIteration inside generator +def gen_stopiter(): + yield 1 + yield 2 + yield 3 + raise StopIteration # [stop-iteration-return] + +# pylint should warn about this one +# because of a direct raising of an exception inheriting from StopIteration inside generator +def gen_stopiterchild(): + yield 1 + yield 2 + yield 3 + raise RebornStopIteration # [stop-iteration-return] + +# pylint should warn here +# because of the possibility that next raises a StopIteration exception +def gen_next_raises_stopiter(): + g = gen_ok() + while True: + yield next(g) # [stop-iteration-return] + +# This one is the same as gen_next_raises_stopiter +# but is ok because the next function is inside +# a try/except block handling StopIteration +def gen_next_inside_try_except(): + g = gen_ok() + while True: + try: + yield next(g) + except StopIteration: + return + +# This one is the same as gen_next_inside_try_except +# but is not ok because the next function is inside +# a try/except block that don't handle StopIteration +def gen_next_inside_wrong_try_except(): + g = gen_ok() + while True: + try: + yield next(g) # [stop-iteration-return] + except ValueError: + return + +# This one is the same as gen_next_inside_try_except +# but is not ok because the next function is inside +# a try/except block that handle StopIteration but reraise it +def gen_next_inside_wrong_try_except2(): + g = gen_ok() + while True: + try: + yield next(g) + except StopIteration: + raise StopIteration # [stop-iteration-return] + +# Those two last are ok +def gen_in_for(): + for el in gen_ok(): + yield el + +def gen_yield_from(): + yield from gen_ok() + + +def gen_dont_crash_on_no_exception(): + g = gen_ok() + while True: + try: + yield next(g) # [stop-iteration-return] + except ValueError: + raise + + +def gen_dont_crash_on_uninferable(): + # https://github.com/PyCQA/pylint/issues/1779 + yield from iter() + raise asyncio.TimeoutError() + + +# https://github.com/PyCQA/pylint/issues/1830 +def gen_next_with_sentinel(): + yield next([], 42) # No bad return + + +from itertools import count + +# https://github.com/PyCQA/pylint/issues/2158 +def generator_using_next(): + counter = count() + number = next(counter) + yield number * 2 + + +# pylint: disable=no-self-use,too-few-public-methods +class SomeClassWithNext: + def next(self): + return iter([1, 2, 3]) + def some_gen(self): + for value in self.next(): + yield value + + +SomeClassWithNext().some_gen() + + +def something_invalid(): + raise Exception('cannot iterate this') + + +def invalid_object_passed_to_next(): + yield next(something_invalid()) # [stop-iteration-return] diff --git a/tests/functional/s/stop_iteration_inside_generator.rc b/tests/functional/s/stop_iteration_inside_generator.rc new file mode 100644 index 000000000..c093be204 --- /dev/null +++ b/tests/functional/s/stop_iteration_inside_generator.rc @@ -0,0 +1,2 @@ +[testoptions] +min_pyver=3.0 diff --git a/tests/functional/s/stop_iteration_inside_generator.txt b/tests/functional/s/stop_iteration_inside_generator.txt new file mode 100644 index 000000000..107d563b6 --- /dev/null +++ b/tests/functional/s/stop_iteration_inside_generator.txt @@ -0,0 +1,7 @@ +stop-iteration-return:24:gen_stopiter:Do not raise StopIteration in generator, use return statement instead +stop-iteration-return:32:gen_stopiterchild:Do not raise StopIteration in generator, use return statement instead +stop-iteration-return:39:gen_next_raises_stopiter:Do not raise StopIteration in generator, use return statement instead +stop-iteration-return:59:gen_next_inside_wrong_try_except:Do not raise StopIteration in generator, use return statement instead +stop-iteration-return:72:gen_next_inside_wrong_try_except2:Do not raise StopIteration in generator, use return statement instead +stop-iteration-return:87:gen_dont_crash_on_no_exception:Do not raise StopIteration in generator, use return statement instead +stop-iteration-return:129:invalid_object_passed_to_next:Do not raise StopIteration in generator, use return statement instead diff --git a/tests/functional/s/string_formatting.py b/tests/functional/s/string_formatting.py new file mode 100644 index 000000000..7e60d9fd9 --- /dev/null +++ b/tests/functional/s/string_formatting.py @@ -0,0 +1,188 @@ +"""test for Python 3 string formatting error
+"""
+# pylint: disable=too-few-public-methods, import-error, unused-argument, line-too-long, no-absolute-import, useless-object-inheritance
+import os
+from missing import Missing
+
+__revision__ = 1
+
+class Custom(object):
+ """ Has a __getattr__ """
+ def __getattr__(self, _):
+ return self
+
+class Test(object):
+ """ test format attribute access """
+ custom = Custom()
+ ids = [1, 2, 3, [4, 5, 6]]
+
+class Getitem(object):
+ """ test custom getitem for lookup access """
+ def __getitem__(self, index):
+ return 42
+
+class ReturnYes(object):
+ """ can't be properly infered """
+ missing = Missing()
+
+def log(message, message_type="error"):
+ """ Test """
+ return message
+
+def print_good():
+ """ Good format strings """
+ "{0} {1}".format(1, 2)
+ "{0!r:20}".format("Hello")
+ "{!r:20}".format("Hello")
+ "{a!r:20}".format(a="Hello")
+ "{pid}".format(pid=os.getpid())
+ str("{}").format(2)
+ "{0.missing.length}".format(ReturnYes())
+ "{1.missing.length}".format(ReturnYes())
+ "{a.ids[3][1]}".format(a=Test())
+ "{a[0][0]}".format(a=[[1]])
+ "{[0][0]}".format({0: {0: 1}})
+ "{a.test}".format(a=Custom())
+ "{a.__len__}".format(a=[])
+ "{a.ids.__len__}".format(a=Test())
+ "{a[0]}".format(a=Getitem())
+ "{a[0][0]}".format(a=[Getitem()])
+ "{[0][0]}".format(["test"])
+ # these are skipped
+ "{0} {1}".format(*[1, 2])
+ "{a} {b}".format(**{'a': 1, 'b': 2})
+ "{a}".format(a=Missing())
+
+def pprint_bad():
+ """Test string format """
+ "{{}}".format(1) # [too-many-format-args]
+ "{} {".format() # [bad-format-string]
+ "{} }".format() # [bad-format-string]
+ "{0} {}".format(1, 2) # [format-combined-specification]
+ # +1: [missing-format-argument-key, unused-format-string-argument]
+ "{a} {b}".format(a=1, c=2)
+ "{} {a}".format(1, 2) # [missing-format-argument-key]
+ "{} {}".format(1) # [too-few-format-args]
+ "{} {}".format(1, 2, 3) # [too-many-format-args]
+ # +1: [missing-format-argument-key,missing-format-argument-key,missing-format-argument-key]
+ "{a} {b} {c}".format()
+ "{} {}".format(a=1, b=2) # [too-few-format-args]
+ # +1: [missing-format-argument-key, missing-format-argument-key]
+ "{a} {b}".format(1, 2)
+ "{0} {1} {a}".format(1, 2, 3) # [missing-format-argument-key]
+ # +1: [missing-format-attribute]
+ "{a.ids.__len__.length}".format(a=Test())
+ "{a.ids[3][400]}".format(a=Test()) # [invalid-format-index]
+ "{a.ids[3]['string']}".format(a=Test()) # [invalid-format-index]
+ "{[0][1]}".format(["a"]) # [invalid-format-index]
+ "{[0][0]}".format(((1, ))) # [invalid-format-index]
+ # +1: [missing-format-argument-key, unused-format-string-argument]
+ "{b[0]}".format(a=23)
+ "{a[0]}".format(a=object) # [invalid-format-index]
+ log("{}".format(2, "info")) # [too-many-format-args]
+ "{0.missing}".format(2) # [missing-format-attribute]
+ "{0} {1} {2}".format(1, 2) # [too-few-format-args]
+ "{0} {1}".format(1, 2, 3) # [too-many-format-args]
+ "{0} {a}".format(a=4) # [too-few-format-args]
+ "{[0]} {}".format([4]) # [too-few-format-args]
+ "{[0]} {}".format([4], 5, 6) # [too-many-format-args]
+
+def good_issue288(*args, **kwargs):
+ """ Test that using kwargs does not emit a false
+ positive.
+ """
+ 'Hello John Doe {0[0]}'.format(args)
+ 'Hello {0[name]}'.format(kwargs)
+
+def good_issue287():
+ """ Test that the string format checker skips
+ format nodes which don't have a string as a parent
+ (but a subscript, name etc).
+ """
+ name = 'qwerty'
+ ret = {'comment': ''}
+ ret['comment'] = 'MySQL grant {0} is set to be revoked'
+ ret['comment'] = ret['comment'].format(name)
+ return ret, name
+
+def nested_issue294():
+ """ Test nested format fields. """
+ '{0:>{1}}'.format(42, 24)
+ '{0:{a[1]}} {a}'.format(1, a=[1, 2])
+ '{:>{}}'.format(42, 24)
+ '{0:>{1}}'.format(42) # [too-few-format-args]
+ '{0:>{1}}'.format(42, 24, 54) # [too-many-format-args]
+ '{0:{a[1]}}'.format(1) # [missing-format-argument-key]
+ '{0:{a.x}}'.format(1, a=2) # [missing-format-attribute]
+
+def issue310():
+ """ Test a regression using duplicate manual position arguments. """
+ '{0} {1} {0}'.format(1, 2)
+ '{0} {1} {0}'.format(1) # [too-few-format-args]
+
+def issue322():
+ """ Test a regression using mixed manual position arguments
+ and attribute access arguments.
+ """
+ '{0}{1[FOO]}'.format(123, {'FOO': 456})
+ '{0}{1[FOO]}'.format(123, {'FOO': 456}, 321) # [too-many-format-args]
+ '{0}{1[FOO]}'.format(123) # [too-few-format-args]
+
+def issue338():
+ """
+ Check that using a namedtuple subclass doesn't crash when
+ trying to infer EmptyNodes (resulted after mocking the
+ members of namedtuples).
+ """
+ from collections import namedtuple
+
+ class Crash(namedtuple("C", "foo bar")):
+ """ Looking for attributes in __str__ will crash,
+ because EmptyNodes can't be infered.
+ """
+ def __str__(self):
+ return "{0.foo}: {0.bar}".format(self)
+ return Crash
+
+def issue351():
+ """
+ Check that the format method can be assigned to a variable, ie:
+ """
+ fmt = 'test {} {}'.format
+ fmt('arg1') # [too-few-format-args]
+ fmt('arg1', 'arg2')
+ fmt('arg1', 'arg2', 'arg3') # [too-many-format-args]
+
+def issue373():
+ """
+ Ignore any object coming from an argument.
+ """
+ class SomeClass(object):
+ """ empty docstring. """
+ def __init__(self, opts=None):
+ self.opts = opts
+
+ def dunc(self, arg):
+ """Don't try to analyze this."""
+ return "A{0}{1}".format(arg, self.opts)
+
+ def func(self):
+ """Don't try to analyze the following string."""
+ return 'AAA{0[iface]}BBB{0[port]}'.format(self.opts)
+
+ return SomeClass
+
+def issue_463():
+ """
+ Mix positional arguments, `{0}`, with positional
+ arguments with attribute access, `{0.__x__}`.
+ """
+ data = "{0.__class__.__name__}: {0}".format(42)
+ data2 = "{0[0]}: {0}".format([1])
+ return (data, data2)
+
+
+def avoid_empty_attribute():
+ """The following string is invalid, avoid crashing."""
+
+ return "There are {.:2f} undiscovered errors.".format(1) # [bad-format-string]
diff --git a/tests/functional/s/string_formatting.txt b/tests/functional/s/string_formatting.txt new file mode 100644 index 000000000..9801de1a7 --- /dev/null +++ b/tests/functional/s/string_formatting.txt @@ -0,0 +1,41 @@ +too-many-format-args:58:pprint_bad:Too many arguments for format string +bad-format-string:59:pprint_bad:Invalid format string +bad-format-string:60:pprint_bad:Invalid format string +format-combined-specification:61:pprint_bad:Format string contains both automatic field numbering and manual field specification +missing-format-argument-key:63:pprint_bad:Missing keyword argument 'b' for format string +unused-format-string-argument:63:pprint_bad:Unused format argument 'c' +missing-format-argument-key:64:pprint_bad:Missing keyword argument 'a' for format string +too-few-format-args:65:pprint_bad:Not enough arguments for format string +too-many-format-args:66:pprint_bad:Too many arguments for format string +missing-format-argument-key:68:pprint_bad:Missing keyword argument 'a' for format string +missing-format-argument-key:68:pprint_bad:Missing keyword argument 'b' for format string +missing-format-argument-key:68:pprint_bad:Missing keyword argument 'c' for format string +too-few-format-args:69:pprint_bad:Not enough arguments for format string +missing-format-argument-key:71:pprint_bad:Missing keyword argument 'a' for format string +missing-format-argument-key:71:pprint_bad:Missing keyword argument 'b' for format string +missing-format-argument-key:72:pprint_bad:Missing keyword argument 'a' for format string +missing-format-attribute:74:pprint_bad:Missing format attribute 'length' in format specifier 'a.ids.__len__.length' +invalid-format-index:75:pprint_bad:Using invalid lookup key 400 in format specifier 'a.ids[3][400]' +invalid-format-index:76:pprint_bad:"Using invalid lookup key ""'string'"" in format specifier 'a.ids[3][""\'string\'""]'" +invalid-format-index:77:pprint_bad:Using invalid lookup key 1 in format specifier '0[0][1]' +invalid-format-index:78:pprint_bad:Using invalid lookup key 0 in format specifier '0[0][0]' +missing-format-argument-key:80:pprint_bad:Missing keyword argument 'b' for format string +unused-format-string-argument:80:pprint_bad:Unused format argument 'a' +invalid-format-index:81:pprint_bad:Using invalid lookup key 0 in format specifier 'a[0]' +too-many-format-args:82:pprint_bad:Too many arguments for format string +missing-format-attribute:83:pprint_bad:Missing format attribute 'missing' in format specifier '0.missing' +too-few-format-args:84:pprint_bad:Not enough arguments for format string +too-many-format-args:85:pprint_bad:Too many arguments for format string +too-few-format-args:86:pprint_bad:Not enough arguments for format string +too-few-format-args:87:pprint_bad:Not enough arguments for format string +too-many-format-args:88:pprint_bad:Too many arguments for format string +too-few-format-args:113:nested_issue294:Not enough arguments for format string +too-many-format-args:114:nested_issue294:Too many arguments for format string +missing-format-argument-key:115:nested_issue294:Missing keyword argument 'a' for format string +missing-format-attribute:116:nested_issue294:Missing format attribute 'x' in format specifier 'a.x' +too-few-format-args:121:issue310:Not enough arguments for format string +too-many-format-args:128:issue322:Too many arguments for format string +too-few-format-args:129:issue322:Not enough arguments for format string +too-few-format-args:152:issue351:Not enough arguments for format string +too-many-format-args:154:issue351:Too many arguments for format string +bad-format-string:188:avoid_empty_attribute:Invalid format string
\ No newline at end of file diff --git a/tests/functional/s/string_formatting_disable.py b/tests/functional/s/string_formatting_disable.py new file mode 100644 index 000000000..096c84734 --- /dev/null +++ b/tests/functional/s/string_formatting_disable.py @@ -0,0 +1 @@ +"a {} {".format(1) # [bad-format-string]
\ No newline at end of file diff --git a/tests/functional/s/string_formatting_disable.rc b/tests/functional/s/string_formatting_disable.rc new file mode 100644 index 000000000..0193339de --- /dev/null +++ b/tests/functional/s/string_formatting_disable.rc @@ -0,0 +1,3 @@ +[Messages Control] +disable=all +enable=bad-format-string diff --git a/tests/functional/s/string_formatting_disable.txt b/tests/functional/s/string_formatting_disable.txt new file mode 100644 index 000000000..2c8f6db59 --- /dev/null +++ b/tests/functional/s/string_formatting_disable.txt @@ -0,0 +1 @@ +bad-format-string:1::Invalid format string
\ No newline at end of file diff --git a/tests/functional/s/string_formatting_failed_inference.py b/tests/functional/s/string_formatting_failed_inference.py new file mode 100644 index 000000000..c5add58c8 --- /dev/null +++ b/tests/functional/s/string_formatting_failed_inference.py @@ -0,0 +1,4 @@ +""" Testing string format with a failed inference. This should not crash. """ +# pylint: disable=using-constant-test +import collections +"{dict[0]}".format(dict=collections.defaultdict(int)) diff --git a/tests/functional/s/string_formatting_failed_inference_py35.py b/tests/functional/s/string_formatting_failed_inference_py35.py new file mode 100644 index 000000000..a511ff80e --- /dev/null +++ b/tests/functional/s/string_formatting_failed_inference_py35.py @@ -0,0 +1,6 @@ +""" Testing string format with a failed inference. This should not crash. """ +# pylint: disable=using-constant-test +import collections +"{dict[0]}".format(dict=collections.defaultdict(int)) + +COMMENT = "message %s %s %s" % (0, *(1 if "cond" else 2,) * 2) diff --git a/tests/functional/s/string_formatting_failed_inference_py35.rc b/tests/functional/s/string_formatting_failed_inference_py35.rc new file mode 100644 index 000000000..71de8b630 --- /dev/null +++ b/tests/functional/s/string_formatting_failed_inference_py35.rc @@ -0,0 +1,2 @@ +[testoptions] +min_pyver=3.5 diff --git a/tests/functional/s/string_formatting_py27.py b/tests/functional/s/string_formatting_py27.py new file mode 100644 index 000000000..eab042c07 --- /dev/null +++ b/tests/functional/s/string_formatting_py27.py @@ -0,0 +1,22 @@ +"""test for Python 2 string formatting error
+"""
+from __future__ import unicode_literals
+# pylint: disable=line-too-long
+__revision__ = 1
+
+def pprint_bad():
+ """Test string format """
+ "{{}}".format(1) # [too-many-format-args]
+ "{} {".format() # [bad-format-string]
+ "{} }".format() # [bad-format-string]
+ "{0} {}".format(1, 2) # [format-combined-specification]
+ # +1: [missing-format-argument-key, unused-format-string-argument]
+ "{a} {b}".format(a=1, c=2)
+ "{} {a}".format(1, 2) # [missing-format-argument-key]
+ "{} {}".format(1) # [too-few-format-args]
+ "{} {}".format(1, 2, 3) # [too-many-format-args]
+ # +1: [missing-format-argument-key,missing-format-argument-key,missing-format-argument-key]
+ "{a} {b} {c}".format()
+ "{} {}".format(a=1, b=2) # [too-few-format-args]
+ # +1: [missing-format-argument-key, missing-format-argument-key]
+ "{a} {b}".format(1, 2)
diff --git a/tests/functional/s/string_formatting_py27.rc b/tests/functional/s/string_formatting_py27.rc new file mode 100644 index 000000000..80170b777 --- /dev/null +++ b/tests/functional/s/string_formatting_py27.rc @@ -0,0 +1,3 @@ +[testoptions] +min_pyver=2.7
+max_pyver=3.0
\ No newline at end of file diff --git a/tests/functional/s/string_formatting_py27.txt b/tests/functional/s/string_formatting_py27.txt new file mode 100644 index 000000000..47f21ded0 --- /dev/null +++ b/tests/functional/s/string_formatting_py27.txt @@ -0,0 +1,15 @@ +too-many-format-args:9:pprint_bad:Too many arguments for format string +bad-format-string:10:pprint_bad:Invalid format string +bad-format-string:11:pprint_bad:Invalid format string +format-combined-specification:12:pprint_bad:Format string contains both automatic field numbering and manual field specification +missing-format-argument-key:14:pprint_bad:Missing keyword argument u'b' for format string +unused-format-string-argument:14:pprint_bad:Unused format argument 'c' +missing-format-argument-key:15:pprint_bad:Missing keyword argument u'a' for format string +too-few-format-args:16:pprint_bad:Not enough arguments for format string +too-many-format-args:17:pprint_bad:Too many arguments for format string +missing-format-argument-key:19:pprint_bad:Missing keyword argument u'a' for format string +missing-format-argument-key:19:pprint_bad:Missing keyword argument u'b' for format string +missing-format-argument-key:19:pprint_bad:Missing keyword argument u'c' for format string +too-few-format-args:20:pprint_bad:Not enough arguments for format string +missing-format-argument-key:22:pprint_bad:Missing keyword argument u'a' for format string +missing-format-argument-key:22:pprint_bad:Missing keyword argument u'b' for format string diff --git a/tests/functional/s/string_formatting_py3.py b/tests/functional/s/string_formatting_py3.py new file mode 100644 index 000000000..c27e9719e --- /dev/null +++ b/tests/functional/s/string_formatting_py3.py @@ -0,0 +1,21 @@ +# pylint: disable=missing-docstring,import-error + + +def issue_957_good(): + meat = ['spam', 'ham'] + print('%s%s%s' % ('eggs', *meat)) + + +def issue_957_bad1(): + meat = ['spam', 'ham', 'monty python'] + print('%s%s%s' % ('eggs', *meat)) # [too-many-format-args] + + +def issue_957_bad2(): + meat = ['spam'] + print('%s%s%s' % ('eggs', *meat)) # [too-few-format-args] + + +def issue_957_uninferable(): + from butchery import meat + print('%s%s%s' % ('eggs', *meat)) diff --git a/tests/functional/s/string_formatting_py3.rc b/tests/functional/s/string_formatting_py3.rc new file mode 100644 index 000000000..a2ab06c50 --- /dev/null +++ b/tests/functional/s/string_formatting_py3.rc @@ -0,0 +1,2 @@ +[testoptions] +min_pyver=3.0
\ No newline at end of file diff --git a/tests/functional/s/string_formatting_py3.txt b/tests/functional/s/string_formatting_py3.txt new file mode 100644 index 000000000..45975899a --- /dev/null +++ b/tests/functional/s/string_formatting_py3.txt @@ -0,0 +1,2 @@ +too-many-format-args:11:issue_957_bad1:Too many arguments for format string +too-few-format-args:16:issue_957_bad2:Not enough arguments for format string diff --git a/tests/functional/s/subprocess_popen_preexec_fn.py b/tests/functional/s/subprocess_popen_preexec_fn.py new file mode 100644 index 000000000..e785abc76 --- /dev/null +++ b/tests/functional/s/subprocess_popen_preexec_fn.py @@ -0,0 +1,11 @@ +# pylint: disable=blacklisted-name,no-value-for-parameter,missing-docstring + +import subprocess + +def foo(): + pass + + +subprocess.Popen(preexec_fn=foo) # [subprocess-popen-preexec-fn] + +subprocess.Popen() diff --git a/tests/functional/s/subprocess_popen_preexec_fn.txt b/tests/functional/s/subprocess_popen_preexec_fn.txt new file mode 100644 index 000000000..cd237a442 --- /dev/null +++ b/tests/functional/s/subprocess_popen_preexec_fn.txt @@ -0,0 +1 @@ +subprocess-popen-preexec-fn:9::Using preexec_fn keyword which may be unsafe in the presence of threads diff --git a/tests/functional/s/subprocess_run_check35.py b/tests/functional/s/subprocess_run_check35.py new file mode 100644 index 000000000..f123fb20d --- /dev/null +++ b/tests/functional/s/subprocess_run_check35.py @@ -0,0 +1,6 @@ +# pylint: disable=blacklisted-name,no-value-for-parameter,missing-docstring + +import subprocess + + +subprocess.run() # [subprocess-run-check] diff --git a/tests/functional/s/subprocess_run_check35.rc b/tests/functional/s/subprocess_run_check35.rc new file mode 100644 index 000000000..71de8b630 --- /dev/null +++ b/tests/functional/s/subprocess_run_check35.rc @@ -0,0 +1,2 @@ +[testoptions] +min_pyver=3.5 diff --git a/tests/functional/s/subprocess_run_check35.txt b/tests/functional/s/subprocess_run_check35.txt new file mode 100644 index 000000000..31e5dbfc1 --- /dev/null +++ b/tests/functional/s/subprocess_run_check35.txt @@ -0,0 +1 @@ +subprocess-run-check:6::Using subprocess.run without explicitly set `check` is not recommended. diff --git a/tests/functional/s/super_checks.py b/tests/functional/s/super_checks.py new file mode 100644 index 000000000..3888488fe --- /dev/null +++ b/tests/functional/s/super_checks.py @@ -0,0 +1,125 @@ +# pylint: disable=too-few-public-methods,import-error, no-absolute-import,missing-docstring, useless-object-inheritance +# pylint: disable=useless-super-delegation,wrong-import-position,invalid-name, wrong-import-order + +from unknown import Missing + +class Aaaa: + """old style""" + def hop(self): + """hop""" + super(Aaaa, self).hop() # >=3.0:[no-member] + + def __init__(self): + super(Aaaa, self).__init__() + +class NewAaaa(object): + """old style""" + def hop(self): + """hop""" + super(NewAaaa, self).hop() # [no-member] + + def __init__(self): + super(Aaaa, self).__init__() # [bad-super-call] + +class Py3kAaaa(NewAaaa): + """new style""" + def __init__(self): + super().__init__() # <3.0:[missing-super-argument] + +class Py3kWrongSuper(Py3kAaaa): + """new style""" + def __init__(self): + super(NewAaaa, self).__init__() # [bad-super-call] + +class WrongNameRegression(Py3kAaaa): + """ test a regression with the message """ + def __init__(self): + super(Missing, self).__init__() # [bad-super-call] + +class Getattr(object): + """ crash """ + name = NewAaaa + +class CrashSuper(object): + """ test a crash with this checker """ + def __init__(self): + super(Getattr.name, self).__init__() # [bad-super-call] + +class Empty(object): + """Just an empty class.""" + +class SuperDifferentScope(object): + """Don'emit bad-super-call when the super call is in another scope. + For reference, see https://bitbucket.org/logilab/pylint/issue/403. + """ + @staticmethod + def test(): + """Test that a bad-super-call is not emitted for this case.""" + class FalsePositive(Empty): + """The following super is in another scope than `test`.""" + def __init__(self, arg): + super(FalsePositive, self).__init__(arg) + super(object, 1).__init__() # [bad-super-call] + + +class UnknownBases(Missing): + """Don't emit if we don't know all the bases.""" + def __init__(self): + super(UnknownBases, self).__init__() + super(UnknownBases, self).test() + super(Missing, self).test() # [bad-super-call] + + +# Test that we are detecting proper super errors. + +class BaseClass(object): + + not_a_method = 42 + + def function(self, param): + return param + self.not_a_method + + def __getattr__(self, attr): + return attr + + +class InvalidSuperChecks(BaseClass): + + def __init__(self): + super(InvalidSuperChecks, self).not_a_method() # [not-callable] + super(InvalidSuperChecks, self).attribute_error() # [no-member] + super(InvalidSuperChecks, self).function(42) + super(InvalidSuperChecks, self).function() # [no-value-for-parameter] + super(InvalidSuperChecks, self).function(42, 24, 24) # [too-many-function-args] + # +1: [unexpected-keyword-arg,no-value-for-parameter] + super(InvalidSuperChecks, self).function(lala=42) + # Even though BaseClass has a __getattr__, that won't + # be called. + super(InvalidSuperChecks, self).attribute_error() # [no-member] + + + +# Regression for PyCQA/pylint/issues/773 +import subprocess + +# The problem was related to astroid not filtering statements +# at scope level properly, basically not doing strong updates. +try: + TimeoutExpired = subprocess.TimeoutExpired +except AttributeError: + class TimeoutExpired(subprocess.CalledProcessError): + def __init__(self): + returncode = -1 + self.timeout = -1 + super(TimeoutExpired, self).__init__(returncode) + + +class SuperWithType(object): + """type(self) may lead to recursion loop in derived classes""" + def __init__(self): + super(type(self), self).__init__() # [bad-super-call] + +class SuperWithSelfClass(object): + """self.__class__ may lead to recursion loop in derived classes""" + def __init__(self): + super(self.__class__, self).__init__() # [bad-super-call] diff --git a/tests/functional/s/super_checks.txt b/tests/functional/s/super_checks.txt new file mode 100644 index 000000000..4911a6c86 --- /dev/null +++ b/tests/functional/s/super_checks.txt @@ -0,0 +1,18 @@ +no-member:10:Aaaa.hop:Super of 'Aaaa' has no 'hop' member:INFERENCE +no-member:19:NewAaaa.hop:Super of 'NewAaaa' has no 'hop' member:INFERENCE +bad-super-call:22:NewAaaa.__init__:Bad first argument 'Aaaa' given to super() +missing-super-argument:27:Py3kAaaa.__init__:Missing argument to super() +bad-super-call:32:Py3kWrongSuper.__init__:Bad first argument 'NewAaaa' given to super() +bad-super-call:37:WrongNameRegression.__init__:Bad first argument 'Missing' given to super() +bad-super-call:46:CrashSuper.__init__:Bad first argument 'NewAaaa' given to super() +bad-super-call:62:SuperDifferentScope.test:Bad first argument 'object' given to super() +bad-super-call:70:UnknownBases.__init__:Bad first argument 'Missing' given to super() +not-callable:89:InvalidSuperChecks.__init__:super(InvalidSuperChecks, self).not_a_method is not callable +no-member:90:InvalidSuperChecks.__init__:Super of 'InvalidSuperChecks' has no 'attribute_error' member:INFERENCE +no-value-for-parameter:92:InvalidSuperChecks.__init__:No value for argument 'param' in method call +too-many-function-args:93:InvalidSuperChecks.__init__:Too many positional arguments for method call +no-value-for-parameter:95:InvalidSuperChecks.__init__:No value for argument 'param' in method call +unexpected-keyword-arg:95:InvalidSuperChecks.__init__:Unexpected keyword argument 'lala' in method call +no-member:98:InvalidSuperChecks.__init__:Super of 'InvalidSuperChecks' has no 'attribute_error' member:INFERENCE +bad-super-call:120:SuperWithType.__init__:Bad first argument 'type' given to super() +bad-super-call:125:SuperWithSelfClass.__init__:Bad first argument 'self.__class__' given to super() diff --git a/tests/functional/s/superfluous_parens.py b/tests/functional/s/superfluous_parens.py new file mode 100644 index 000000000..13418cd78 --- /dev/null +++ b/tests/functional/s/superfluous_parens.py @@ -0,0 +1,19 @@ +"""Test the superfluous-parens warning.""" +from __future__ import print_function +# pylint: disable=unneeded-not +i = 3 +if (i == 5): # [superfluous-parens] + pass +if not (i == 5): # [superfluous-parens] + pass +if not (3 or 5): + pass +for (x) in (1, 2, 3): # [superfluous-parens] + print(x) +if (1) in (1, 2, 3): # [superfluous-parens] + pass +if (1, 2) in (1, 2, 3): + pass +DICT = {'a': 1, 'b': 2} +del(DICT['b']) # [superfluous-parens] +del DICT['a'] diff --git a/tests/functional/s/superfluous_parens.txt b/tests/functional/s/superfluous_parens.txt new file mode 100644 index 000000000..57e1019c3 --- /dev/null +++ b/tests/functional/s/superfluous_parens.txt @@ -0,0 +1,5 @@ +superfluous-parens:5::Unnecessary parens after 'if' keyword +superfluous-parens:7::Unnecessary parens after 'not' keyword +superfluous-parens:11::Unnecessary parens after 'for' keyword +superfluous-parens:13::Unnecessary parens after 'if' keyword +superfluous-parens:18::Unnecessary parens after 'del' keyword diff --git a/tests/functional/s/suspicious_str_strip_call.py b/tests/functional/s/suspicious_str_strip_call.py new file mode 100644 index 000000000..bc3a27c27 --- /dev/null +++ b/tests/functional/s/suspicious_str_strip_call.py @@ -0,0 +1,10 @@ +"""Suspicious str.strip calls.""" +__revision__ = 1 + +''.strip('yo') +''.strip() + +u''.strip('http://') # [bad-str-strip-call] +u''.lstrip('http://') # [bad-str-strip-call] +b''.rstrip('http://') # [bad-str-strip-call] +"some_sensible_string".strip(None) # Don't crash diff --git a/tests/functional/s/suspicious_str_strip_call.rc b/tests/functional/s/suspicious_str_strip_call.rc new file mode 100644 index 000000000..a65023393 --- /dev/null +++ b/tests/functional/s/suspicious_str_strip_call.rc @@ -0,0 +1,2 @@ +[testoptions] +max_pyver=3.0 diff --git a/tests/functional/s/suspicious_str_strip_call.txt b/tests/functional/s/suspicious_str_strip_call.txt new file mode 100644 index 000000000..ad714cc6b --- /dev/null +++ b/tests/functional/s/suspicious_str_strip_call.txt @@ -0,0 +1,3 @@ +bad-str-strip-call:7::Suspicious argument in unicode.strip call +bad-str-strip-call:8::Suspicious argument in unicode.lstrip call +bad-str-strip-call:9::Suspicious argument in str.rstrip call diff --git a/tests/functional/s/suspicious_str_strip_call_py3.py b/tests/functional/s/suspicious_str_strip_call_py3.py new file mode 100644 index 000000000..e859f25f8 --- /dev/null +++ b/tests/functional/s/suspicious_str_strip_call_py3.py @@ -0,0 +1,9 @@ +"""Suspicious str.strip calls.""" +__revision__ = 1 + +''.strip('yo') +''.strip() + +u''.strip('http://') # [bad-str-strip-call] +u''.lstrip('http://') # [bad-str-strip-call] +b''.rstrip('http://') # [bad-str-strip-call] diff --git a/tests/functional/s/suspicious_str_strip_call_py3.rc b/tests/functional/s/suspicious_str_strip_call_py3.rc new file mode 100644 index 000000000..c093be204 --- /dev/null +++ b/tests/functional/s/suspicious_str_strip_call_py3.rc @@ -0,0 +1,2 @@ +[testoptions] +min_pyver=3.0 diff --git a/tests/functional/s/suspicious_str_strip_call_py3.txt b/tests/functional/s/suspicious_str_strip_call_py3.txt new file mode 100644 index 000000000..81f32cf4e --- /dev/null +++ b/tests/functional/s/suspicious_str_strip_call_py3.txt @@ -0,0 +1,3 @@ +bad-str-strip-call:7::Suspicious argument in str.strip call +bad-str-strip-call:8::Suspicious argument in str.lstrip call +bad-str-strip-call:9::Suspicious argument in bytes.rstrip call diff --git a/tests/functional/s/syntax_error.py b/tests/functional/s/syntax_error.py new file mode 100644 index 000000000..c93df6b05 --- /dev/null +++ b/tests/functional/s/syntax_error.py @@ -0,0 +1 @@ +def toto # [syntax-error] diff --git a/tests/functional/s/syntax_error.rc b/tests/functional/s/syntax_error.rc new file mode 100644 index 000000000..58b5a9413 --- /dev/null +++ b/tests/functional/s/syntax_error.rc @@ -0,0 +1 @@ +[testoptions] diff --git a/tests/functional/s/syntax_error.txt b/tests/functional/s/syntax_error.txt new file mode 100644 index 000000000..f14ae39dd --- /dev/null +++ b/tests/functional/s/syntax_error.txt @@ -0,0 +1 @@ +syntax-error:1::invalid syntax (<unknown>, line 1)
\ No newline at end of file diff --git a/tests/functional/s/syntax_error_jython.py b/tests/functional/s/syntax_error_jython.py new file mode 100644 index 000000000..c93df6b05 --- /dev/null +++ b/tests/functional/s/syntax_error_jython.py @@ -0,0 +1 @@ +def toto # [syntax-error] diff --git a/tests/functional/s/syntax_error_jython.rc b/tests/functional/s/syntax_error_jython.rc new file mode 100644 index 000000000..29bd3facf --- /dev/null +++ b/tests/functional/s/syntax_error_jython.rc @@ -0,0 +1,2 @@ +[testoptions] +except_implementations=CPython, PyPy diff --git a/tests/functional/s/syntax_error_jython.txt b/tests/functional/s/syntax_error_jython.txt new file mode 100644 index 000000000..e532aece7 --- /dev/null +++ b/tests/functional/s/syntax_error_jython.txt @@ -0,0 +1 @@ +syntax-error:1::"mismatched input '\n\n\n\n' expecting LPAREN"
\ No newline at end of file diff --git a/tests/functional/s/sys_stream_regression_1004.py b/tests/functional/s/sys_stream_regression_1004.py new file mode 100644 index 000000000..c0391859d --- /dev/null +++ b/tests/functional/s/sys_stream_regression_1004.py @@ -0,0 +1,7 @@ +'''Regression for issue https://github.com/PyCQA/pylint/issues/1004''' +# pylint: disable=missing-docstring, pointless-statement + +import sys +sys.__stdout__.buffer.write('test') +sys.__stdout__.buff # [no-member] +sys.__stdout__.buffer.write1 # [no-member] diff --git a/tests/functional/s/sys_stream_regression_1004.rc b/tests/functional/s/sys_stream_regression_1004.rc new file mode 100644 index 000000000..182fae81c --- /dev/null +++ b/tests/functional/s/sys_stream_regression_1004.rc @@ -0,0 +1,3 @@ +[testoptions] +min_pyver=3.5 +except_implementations=PyPy
\ No newline at end of file diff --git a/tests/functional/s/sys_stream_regression_1004.txt b/tests/functional/s/sys_stream_regression_1004.txt new file mode 100644 index 000000000..b68af46fa --- /dev/null +++ b/tests/functional/s/sys_stream_regression_1004.txt @@ -0,0 +1,2 @@ +no-member:6::Instance of 'TextIOWrapper' has no 'buff' member:INFERENCE +no-member:7::Instance of 'BufferedWriter' has no 'write1' member; maybe 'write'?:INFERENCE
\ No newline at end of file |