Skip to content

Commit

Permalink
Add tests for #8192, #8893, #9642, #9689, #9815, #9941 (#9981)
Browse files Browse the repository at this point in the history
  • Loading branch information
nickdrozd authored Oct 1, 2024
1 parent 07574db commit 74c49b2
Show file tree
Hide file tree
Showing 10 changed files with 196 additions and 3 deletions.
22 changes: 21 additions & 1 deletion tests/functional/u/unnecessary/unnecessary_lambda.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# pylint: disable=undefined-variable, use-list-literal, unnecessary-lambda-assignment, use-dict-literal
# pylint: disable=undefined-variable, use-list-literal, unnecessary-lambda-assignment, use-dict-literal, disallowed-name
"""test suspicious lambda expressions
"""

Expand Down Expand Up @@ -65,3 +65,23 @@ def f(d):
_ = lambda x: x(x)
_ = lambda x, y: x(x, y)
_ = lambda x: z(lambda y: x + y)(x)


# https://github.com/pylint-dev/pylint/issues/8192

# foo does not yet exist, so replacing lambda x: foo.get(x) with
# foo.get will raise NameError
g = lambda x: foo.get(x) # [unnecessary-lambda] FALSE POSITIVE

# an object is created and given the name 'foo'
foo = {1: 2}
assert g(1) == 2

# a new object is created and given the name 'foo'; first object is lost
foo = {1: 3}
assert g(1) == 3

# the name 'foo' is deleted; second object is lost; there is no foo
del foo

assert g(1) == 3 # NameError: name 'foo' is not defined
1 change: 1 addition & 0 deletions tests/functional/u/unnecessary/unnecessary_lambda.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ unnecessary-lambda:23:4:23:53:<lambda>:Lambda may not be necessary:UNDEFINED
unnecessary-lambda:25:4:25:71:<lambda>:Lambda may not be necessary:UNDEFINED
unnecessary-lambda:29:4:29:31:<lambda>:Lambda may not be necessary:UNDEFINED
unnecessary-lambda:31:4:31:44:<lambda>:Lambda may not be necessary:UNDEFINED
unnecessary-lambda:74:4:74:24:<lambda>:Lambda may not be necessary:UNDEFINED
61 changes: 60 additions & 1 deletion tests/functional/u/used/used_before_assignment.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""Miscellaneous used-before-assignment cases"""
# pylint: disable=consider-using-f-string, missing-function-docstring
# pylint: disable=consider-using-f-string, missing-function-docstring, bare-except
import datetime
import sys
from typing import NoReturn
Expand Down Expand Up @@ -222,3 +222,62 @@ def print_platform_specific_command(self):
self.skip("only runs on Linux/Windows")

print(cmd)


# https://github.com/pylint-dev/pylint/issues/9941
try:
x = 1 / 0
except ZeroDivisionError:
print(x) # [used-before-assignment]

try:
y = 1 / 0
print(y)
except ZeroDivisionError:
print(y) # FALSE NEGATIVE


# https://github.com/pylint-dev/pylint/issues/9642
def __():
for i in []:
if i:
fail1 = 42
print(fail1) # [possibly-used-before-assignment]

for i in []:
fail2 = 42
print(fail2) # FALSE NEGATIVE


# https://github.com/pylint-dev/pylint/issues/9689
def outer_():
a = 1

def inner_try():
try:
nonlocal a
print(a) # [used-before-assignment] FALSE POSITIVE
a = 2
print(a)
except:
pass

def inner_while():
i = 0
while i < 2:
i += 1
nonlocal a
print(a) # [used-before-assignment] FALSE POSITIVE
a = 2
print(a)

def inner_for():
for _ in range(2):
nonlocal a
print(a)
a = 2
print(a)

inner_try()
inner_while()
inner_for()
4 changes: 4 additions & 0 deletions tests/functional/u/used/used_before_assignment.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,7 @@ possibly-used-before-assignment:121:6:121:11::Possibly using variable 'VAR12' be
used-before-assignment:152:10:152:14::Using variable 'SALE' before assignment:INFERENCE
used-before-assignment:184:10:184:18::Using variable 'ALL_DONE' before assignment:INFERENCE
used-before-assignment:195:6:195:24::Using variable 'NOT_ALWAYS_DEFINED' before assignment:INFERENCE
used-before-assignment:231:10:231:11::Using variable 'x' before assignment:CONTROL_FLOW
possibly-used-before-assignment:245:10:245:15:__:Possibly using variable 'fail1' before assignment:CONTROL_FLOW
used-before-assignment:259:18:259:19:outer_.inner_try:Using variable 'a' before assignment:HIGH
used-before-assignment:270:18:270:19:outer_.inner_while:Using variable 'a' before assignment:HIGH
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""Tests for used-before-assignment when postponed evaluation of annotations is enabled"""
# pylint: disable=missing-function-docstring, invalid-name
# pylint: disable=missing-function-docstring, invalid-name, missing-class-docstring, too-few-public-methods
from __future__ import annotations
from typing import TYPE_CHECKING

Expand All @@ -11,3 +11,29 @@

def function_one(m: math): # no error for annotations
return m

# https://github.com/pylint-dev/pylint/issues/8893
if TYPE_CHECKING:
import datetime

def f():
return datetime.datetime.now() # [used-before-assignment]

def g() -> datetime.datetime:
return datetime.datetime.now() # FALSE NEGATIVE

if TYPE_CHECKING:
class X:
pass

def h():
return X() # FALSE NEGATIVE

def i() -> X:
return X() # FALSE NEGATIVE

if TYPE_CHECKING:
from mod import Y

def j():
return {Y() for _ in range(1)} # FALSE NEGATIVE
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
used-before-assignment:10:6:10:9::Using variable 'var' before assignment:INFERENCE
used-before-assignment:20:11:20:19:f:Using variable 'datetime' before assignment:INFERENCE
69 changes: 69 additions & 0 deletions tests/functional/u/used/used_before_assignment_py310.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,72 @@
print("x used to cause used-before-assignment!")
case _:
print("good thing it doesn't now!")


# pylint: disable = missing-function-docstring, redefined-outer-name, missing-class-docstring

# https://github.com/pylint-dev/pylint/issues/9668
from enum import Enum
from pylint.constants import PY311_PLUS
if PY311_PLUS:
from typing import assert_never # pylint: disable=no-name-in-module
else:
from typing_extensions import assert_never

class Example(Enum):
FOO = 1
BAR = 2

def check_value_if_then_match_return(example: Example, should_check: bool) -> str | None:
if should_check:
result = None
else:
match example:
case Example.FOO:
result = "foo"
case Example.BAR:
result = "bar"
case _:
return None

return result # [possibly-used-before-assignment] FALSE POSITIVE

def check_value_if_then_match_raise(example: Example, should_check: bool) -> str | None:
if should_check:
result = None
else:
match example:
case Example.FOO:
result = "foo"
case Example.BAR:
result = "bar"
case _:
raise ValueError("Not a valid enum")

return result # [possibly-used-before-assignment] FALSE POSITIVE

def check_value_if_then_match_assert_never(example: Example, should_check: bool) -> str | None:
if should_check:
result = None
else:
match example:
case Example.FOO:
result = "foo"
case Example.BAR:
result = "bar"
case _:
assert_never(example)

return result # [possibly-used-before-assignment] FALSE POSITIVE

def g(x):
if x is None:
y = 0
else:
match x:
case int():
y = x
case _:
raise TypeError(type(x))

return y # [possibly-used-before-assignment] FALSE POSITIVE
4 changes: 4 additions & 0 deletions tests/functional/u/used/used_before_assignment_py310.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
possibly-used-before-assignment:36:11:36:17:check_value_if_then_match_return:Possibly using variable 'result' before assignment:CONTROL_FLOW
possibly-used-before-assignment:50:11:50:17:check_value_if_then_match_raise:Possibly using variable 'result' before assignment:CONTROL_FLOW
possibly-used-before-assignment:64:11:64:17:check_value_if_then_match_assert_never:Possibly using variable 'result' before assignment:CONTROL_FLOW
possibly-used-before-assignment:76:11:76:12:g:Possibly using variable 'y' before assignment:CONTROL_FLOW
8 changes: 8 additions & 0 deletions tests/functional/u/used/used_before_assignment_py312.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,11 @@
type Point[T] = tuple[T, ...]
type Alias[*Ts] = tuple[*Ts]
type Alias[**P] = Callable[P]

# pylint: disable = invalid-name, missing-class-docstring, too-few-public-methods

# https://github.com/pylint-dev/pylint/issues/9815
type IntOrX = int | X # [used-before-assignment] FALSE POSITIVE

class X:
pass
1 change: 1 addition & 0 deletions tests/functional/u/used/used_before_assignment_py312.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
used-before-assignment:11:20:11:21::Using variable 'X' before assignment:HIGH

0 comments on commit 74c49b2

Please sign in to comment.