diff --git a/tests/functional/u/unnecessary/unnecessary_lambda.py b/tests/functional/u/unnecessary/unnecessary_lambda.py index 85c30fef28..6b379165fa 100644 --- a/tests/functional/u/unnecessary/unnecessary_lambda.py +++ b/tests/functional/u/unnecessary/unnecessary_lambda.py @@ -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 """ @@ -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 diff --git a/tests/functional/u/unnecessary/unnecessary_lambda.txt b/tests/functional/u/unnecessary/unnecessary_lambda.txt index 87f80872cf..4278090250 100644 --- a/tests/functional/u/unnecessary/unnecessary_lambda.txt +++ b/tests/functional/u/unnecessary/unnecessary_lambda.txt @@ -7,3 +7,4 @@ unnecessary-lambda:23:4:23:53::Lambda may not be necessary:UNDEFINED unnecessary-lambda:25:4:25:71::Lambda may not be necessary:UNDEFINED unnecessary-lambda:29:4:29:31::Lambda may not be necessary:UNDEFINED unnecessary-lambda:31:4:31:44::Lambda may not be necessary:UNDEFINED +unnecessary-lambda:74:4:74:24::Lambda may not be necessary:UNDEFINED diff --git a/tests/functional/u/used/used_before_assignment.py b/tests/functional/u/used/used_before_assignment.py index b398afa370..09d6f50099 100644 --- a/tests/functional/u/used/used_before_assignment.py +++ b/tests/functional/u/used/used_before_assignment.py @@ -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 @@ -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() diff --git a/tests/functional/u/used/used_before_assignment.txt b/tests/functional/u/used/used_before_assignment.txt index eacf082399..42362a801e 100644 --- a/tests/functional/u/used/used_before_assignment.txt +++ b/tests/functional/u/used/used_before_assignment.txt @@ -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 diff --git a/tests/functional/u/used/used_before_assignment_postponed_evaluation.py b/tests/functional/u/used/used_before_assignment_postponed_evaluation.py index 4ff22470cc..8c2acc8498 100644 --- a/tests/functional/u/used/used_before_assignment_postponed_evaluation.py +++ b/tests/functional/u/used/used_before_assignment_postponed_evaluation.py @@ -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 @@ -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 diff --git a/tests/functional/u/used/used_before_assignment_postponed_evaluation.txt b/tests/functional/u/used/used_before_assignment_postponed_evaluation.txt index 15681c6dba..1546b40b5f 100644 --- a/tests/functional/u/used/used_before_assignment_postponed_evaluation.txt +++ b/tests/functional/u/used/used_before_assignment_postponed_evaluation.txt @@ -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 diff --git a/tests/functional/u/used/used_before_assignment_py310.py b/tests/functional/u/used/used_before_assignment_py310.py index 14f46b61e9..3734cc2d55 100644 --- a/tests/functional/u/used/used_before_assignment_py310.py +++ b/tests/functional/u/used/used_before_assignment_py310.py @@ -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 diff --git a/tests/functional/u/used/used_before_assignment_py310.txt b/tests/functional/u/used/used_before_assignment_py310.txt new file mode 100644 index 0000000000..75ae6e6774 --- /dev/null +++ b/tests/functional/u/used/used_before_assignment_py310.txt @@ -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 diff --git a/tests/functional/u/used/used_before_assignment_py312.py b/tests/functional/u/used/used_before_assignment_py312.py index f47e005b85..7da2a8d0b1 100644 --- a/tests/functional/u/used/used_before_assignment_py312.py +++ b/tests/functional/u/used/used_before_assignment_py312.py @@ -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 diff --git a/tests/functional/u/used/used_before_assignment_py312.txt b/tests/functional/u/used/used_before_assignment_py312.txt new file mode 100644 index 0000000000..e045f5ae43 --- /dev/null +++ b/tests/functional/u/used/used_before_assignment_py312.txt @@ -0,0 +1 @@ +used-before-assignment:11:20:11:21::Using variable 'X' before assignment:HIGH