diff --git a/python/src/com/jetbrains/python/inspections/PyUnboundLocalVariableInspection.java b/python/src/com/jetbrains/python/inspections/PyUnboundLocalVariableInspection.java
index adaece1caf4c..aa14acc58655 100644
--- a/python/src/com/jetbrains/python/inspections/PyUnboundLocalVariableInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PyUnboundLocalVariableInspection.java
@@ -129,7 +129,7 @@ public class PyUnboundLocalVariableInspection extends PyInspection {
return;
}
}
- if (resolvedUnderWithStatement(node, resolved)) {
+ if (resolvedUnderWithStatement(node, resolved) || resolvedUnderAssignmentExpressionAndCondition(node, resolved)) {
return;
}
if (PyUnreachableCodeInspection.hasAnyInterruptedControlFlowPaths(node)) {
@@ -159,6 +159,17 @@ public class PyUnboundLocalVariableInspection extends PyInspection {
PsiTreeUtil.getParentOfType(resolved, PyWithStatement.class, true, ScopeOwner.class) != null;
}
+ private static boolean resolvedUnderAssignmentExpressionAndCondition(@NotNull PyReferenceExpression node,
+ @Nullable PsiElement resolved) {
+ return resolved instanceof PyTargetExpression &&
+ PyUtil.inSameFile(node, resolved) &&
+ resolved.getParent() instanceof PyAssignmentExpression &&
+ PsiTreeUtil.getParentOfType(
+ PsiTreeUtil.getParentOfType(resolved.getParent(), PyComprehensionElement.class, true, PyConditionalStatementPart.class),
+ PyConditionalStatementPart.class
+ ) != null;
+ }
+
private static boolean isFirstUnboundRead(@NotNull PyReferenceExpression node, @NotNull ScopeOwner owner) {
final String nodeName = node.getReferencedName();
final Scope scope = ControlFlowCache.getScope(owner);
diff --git a/python/testSrc/com/jetbrains/python/inspections/PyUnboundLocalVariableInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyUnboundLocalVariableInspectionTest.java
index 30eae2ec1521..bdb054d352be 100644
--- a/python/testSrc/com/jetbrains/python/inspections/PyUnboundLocalVariableInspectionTest.java
+++ b/python/testSrc/com/jetbrains/python/inspections/PyUnboundLocalVariableInspectionTest.java
@@ -290,6 +290,40 @@ public class PyUnboundLocalVariableInspectionTest extends PyInspectionTestCase {
" print(val)");
}
+ // PY-33886
+ public void testAssignmentExpressions() {
+ runWithLanguageLevel(
+ LanguageLevel.getLatest(),
+ () -> doTestByText(
+ "def foo():\n" +
+ " if any((comment := line).startswith('#') for line in lines):\n" +
+ " print(\"First comment:\", comment)\n" +
+ " else:\n" +
+ " print(\"There are no comments\")\n" +
+ "\n" +
+ " if all((nonblank := line).strip() == '' for line in lines):\n" +
+ " print(\"All lines are blank\")\n" +
+ " else:\n" +
+ " print(\"First non-blank line:\", nonblank)\n" +
+ "\n" +
+ "\n" +
+ "def bar():\n" +
+ " [(comment := line).startswith('#') for line in lines]\n" +
+ " print(comment)\n" +
+ "\n" +
+ "\n" +
+ "def baz():\n" +
+ " while (line := input()) and any((first_digit := c).isdigit() for c in line):\n" +
+ " print(line, first_digit)\n" +
+ "\n" +
+ "\n" +
+ "def more():\n" +
+ " if (x := True) or (y := 'spam'):\n" +
+ " print(y)\n"
+ )
+ );
+ }
+
@NotNull
@Override
protected Class extends PyInspection> getInspectionClass() {