Skip to content

Commit 74c49b2

Browse files
authored
Add tests for #8192, #8893, #9642, #9689, #9815, #9941 (#9981)
1 parent 07574db commit 74c49b2

10 files changed

+196
-3
lines changed

tests/functional/u/unnecessary/unnecessary_lambda.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# pylint: disable=undefined-variable, use-list-literal, unnecessary-lambda-assignment, use-dict-literal
1+
# pylint: disable=undefined-variable, use-list-literal, unnecessary-lambda-assignment, use-dict-literal, disallowed-name
22
"""test suspicious lambda expressions
33
"""
44

@@ -65,3 +65,23 @@ def f(d):
6565
_ = lambda x: x(x)
6666
_ = lambda x, y: x(x, y)
6767
_ = lambda x: z(lambda y: x + y)(x)
68+
69+
70+
# https://github.com/pylint-dev/pylint/issues/8192
71+
72+
# foo does not yet exist, so replacing lambda x: foo.get(x) with
73+
# foo.get will raise NameError
74+
g = lambda x: foo.get(x) # [unnecessary-lambda] FALSE POSITIVE
75+
76+
# an object is created and given the name 'foo'
77+
foo = {1: 2}
78+
assert g(1) == 2
79+
80+
# a new object is created and given the name 'foo'; first object is lost
81+
foo = {1: 3}
82+
assert g(1) == 3
83+
84+
# the name 'foo' is deleted; second object is lost; there is no foo
85+
del foo
86+
87+
assert g(1) == 3 # NameError: name 'foo' is not defined

tests/functional/u/unnecessary/unnecessary_lambda.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ unnecessary-lambda:23:4:23:53:<lambda>:Lambda may not be necessary:UNDEFINED
77
unnecessary-lambda:25:4:25:71:<lambda>:Lambda may not be necessary:UNDEFINED
88
unnecessary-lambda:29:4:29:31:<lambda>:Lambda may not be necessary:UNDEFINED
99
unnecessary-lambda:31:4:31:44:<lambda>:Lambda may not be necessary:UNDEFINED
10+
unnecessary-lambda:74:4:74:24:<lambda>:Lambda may not be necessary:UNDEFINED

tests/functional/u/used/used_before_assignment.py

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""Miscellaneous used-before-assignment cases"""
2-
# pylint: disable=consider-using-f-string, missing-function-docstring
2+
# pylint: disable=consider-using-f-string, missing-function-docstring, bare-except
33
import datetime
44
import sys
55
from typing import NoReturn
@@ -222,3 +222,62 @@ def print_platform_specific_command(self):
222222
self.skip("only runs on Linux/Windows")
223223

224224
print(cmd)
225+
226+
227+
# https://github.com/pylint-dev/pylint/issues/9941
228+
try:
229+
x = 1 / 0
230+
except ZeroDivisionError:
231+
print(x) # [used-before-assignment]
232+
233+
try:
234+
y = 1 / 0
235+
print(y)
236+
except ZeroDivisionError:
237+
print(y) # FALSE NEGATIVE
238+
239+
240+
# https://github.com/pylint-dev/pylint/issues/9642
241+
def __():
242+
for i in []:
243+
if i:
244+
fail1 = 42
245+
print(fail1) # [possibly-used-before-assignment]
246+
247+
for i in []:
248+
fail2 = 42
249+
print(fail2) # FALSE NEGATIVE
250+
251+
252+
# https://github.com/pylint-dev/pylint/issues/9689
253+
def outer_():
254+
a = 1
255+
256+
def inner_try():
257+
try:
258+
nonlocal a
259+
print(a) # [used-before-assignment] FALSE POSITIVE
260+
a = 2
261+
print(a)
262+
except:
263+
pass
264+
265+
def inner_while():
266+
i = 0
267+
while i < 2:
268+
i += 1
269+
nonlocal a
270+
print(a) # [used-before-assignment] FALSE POSITIVE
271+
a = 2
272+
print(a)
273+
274+
def inner_for():
275+
for _ in range(2):
276+
nonlocal a
277+
print(a)
278+
a = 2
279+
print(a)
280+
281+
inner_try()
282+
inner_while()
283+
inner_for()

tests/functional/u/used/used_before_assignment.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,7 @@ possibly-used-before-assignment:121:6:121:11::Possibly using variable 'VAR12' be
1313
used-before-assignment:152:10:152:14::Using variable 'SALE' before assignment:INFERENCE
1414
used-before-assignment:184:10:184:18::Using variable 'ALL_DONE' before assignment:INFERENCE
1515
used-before-assignment:195:6:195:24::Using variable 'NOT_ALWAYS_DEFINED' before assignment:INFERENCE
16+
used-before-assignment:231:10:231:11::Using variable 'x' before assignment:CONTROL_FLOW
17+
possibly-used-before-assignment:245:10:245:15:__:Possibly using variable 'fail1' before assignment:CONTROL_FLOW
18+
used-before-assignment:259:18:259:19:outer_.inner_try:Using variable 'a' before assignment:HIGH
19+
used-before-assignment:270:18:270:19:outer_.inner_while:Using variable 'a' before assignment:HIGH

tests/functional/u/used/used_before_assignment_postponed_evaluation.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""Tests for used-before-assignment when postponed evaluation of annotations is enabled"""
2-
# pylint: disable=missing-function-docstring, invalid-name
2+
# pylint: disable=missing-function-docstring, invalid-name, missing-class-docstring, too-few-public-methods
33
from __future__ import annotations
44
from typing import TYPE_CHECKING
55

@@ -11,3 +11,29 @@
1111

1212
def function_one(m: math): # no error for annotations
1313
return m
14+
15+
# https://github.com/pylint-dev/pylint/issues/8893
16+
if TYPE_CHECKING:
17+
import datetime
18+
19+
def f():
20+
return datetime.datetime.now() # [used-before-assignment]
21+
22+
def g() -> datetime.datetime:
23+
return datetime.datetime.now() # FALSE NEGATIVE
24+
25+
if TYPE_CHECKING:
26+
class X:
27+
pass
28+
29+
def h():
30+
return X() # FALSE NEGATIVE
31+
32+
def i() -> X:
33+
return X() # FALSE NEGATIVE
34+
35+
if TYPE_CHECKING:
36+
from mod import Y
37+
38+
def j():
39+
return {Y() for _ in range(1)} # FALSE NEGATIVE
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
used-before-assignment:10:6:10:9::Using variable 'var' before assignment:INFERENCE
2+
used-before-assignment:20:11:20:19:f:Using variable 'datetime' before assignment:INFERENCE

tests/functional/u/used/used_before_assignment_py310.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,72 @@
55
print("x used to cause used-before-assignment!")
66
case _:
77
print("good thing it doesn't now!")
8+
9+
10+
# pylint: disable = missing-function-docstring, redefined-outer-name, missing-class-docstring
11+
12+
# https://github.com/pylint-dev/pylint/issues/9668
13+
from enum import Enum
14+
from pylint.constants import PY311_PLUS
15+
if PY311_PLUS:
16+
from typing import assert_never # pylint: disable=no-name-in-module
17+
else:
18+
from typing_extensions import assert_never
19+
20+
class Example(Enum):
21+
FOO = 1
22+
BAR = 2
23+
24+
def check_value_if_then_match_return(example: Example, should_check: bool) -> str | None:
25+
if should_check:
26+
result = None
27+
else:
28+
match example:
29+
case Example.FOO:
30+
result = "foo"
31+
case Example.BAR:
32+
result = "bar"
33+
case _:
34+
return None
35+
36+
return result # [possibly-used-before-assignment] FALSE POSITIVE
37+
38+
def check_value_if_then_match_raise(example: Example, should_check: bool) -> str | None:
39+
if should_check:
40+
result = None
41+
else:
42+
match example:
43+
case Example.FOO:
44+
result = "foo"
45+
case Example.BAR:
46+
result = "bar"
47+
case _:
48+
raise ValueError("Not a valid enum")
49+
50+
return result # [possibly-used-before-assignment] FALSE POSITIVE
51+
52+
def check_value_if_then_match_assert_never(example: Example, should_check: bool) -> str | None:
53+
if should_check:
54+
result = None
55+
else:
56+
match example:
57+
case Example.FOO:
58+
result = "foo"
59+
case Example.BAR:
60+
result = "bar"
61+
case _:
62+
assert_never(example)
63+
64+
return result # [possibly-used-before-assignment] FALSE POSITIVE
65+
66+
def g(x):
67+
if x is None:
68+
y = 0
69+
else:
70+
match x:
71+
case int():
72+
y = x
73+
case _:
74+
raise TypeError(type(x))
75+
76+
return y # [possibly-used-before-assignment] FALSE POSITIVE
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
possibly-used-before-assignment:36:11:36:17:check_value_if_then_match_return:Possibly using variable 'result' before assignment:CONTROL_FLOW
2+
possibly-used-before-assignment:50:11:50:17:check_value_if_then_match_raise:Possibly using variable 'result' before assignment:CONTROL_FLOW
3+
possibly-used-before-assignment:64:11:64:17:check_value_if_then_match_assert_never:Possibly using variable 'result' before assignment:CONTROL_FLOW
4+
possibly-used-before-assignment:76:11:76:12:g:Possibly using variable 'y' before assignment:CONTROL_FLOW

tests/functional/u/used/used_before_assignment_py312.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,11 @@
44
type Point[T] = tuple[T, ...]
55
type Alias[*Ts] = tuple[*Ts]
66
type Alias[**P] = Callable[P]
7+
8+
# pylint: disable = invalid-name, missing-class-docstring, too-few-public-methods
9+
10+
# https://github.com/pylint-dev/pylint/issues/9815
11+
type IntOrX = int | X # [used-before-assignment] FALSE POSITIVE
12+
13+
class X:
14+
pass
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
used-before-assignment:11:20:11:21::Using variable 'X' before assignment:HIGH

0 commit comments

Comments
 (0)