PY-24792 Fix for incorrect formatting of a multiline return statements

Fix pycodestyle-violating alignment in multiline binary statements in return and yield expressions
Fix pycodestyle-violating alignment in multiline tuple expressions in return, yield and assignment expressions
Tests for it
Merge-request: IJ-MR-35686
Merged-by: Daniil Kalinin <Daniil.Kalinin@jetbrains.com>

GitOrigin-RevId: 989b4f4aeb61b43d3215a0ad74f7a9d9685464b8
This commit is contained in:
Daniil Kalinin
2022-10-13 09:44:57 +00:00
committed by intellij-monorepo-bot
parent b3d585e63a
commit 3d3da180b8
17 changed files with 137 additions and 9 deletions

View File

@@ -272,15 +272,21 @@ public class PyBlock implements ASTBlock {
childAlignment = binaryParentBlock.getChildAlignment();
}
final boolean parenthesised = binaryParentType == PyElementTypes.PARENTHESIZED_EXPRESSION;
if (childAlignment == null && topmostBinary != null &&
!(parenthesised && isIfCondition(binaryParentNode)) &&
!(isCondition(topmostBinary.myNode) && !ALIGN_CONDITIONS_WITHOUT_PARENTHESES)) {
childAlignment = topmostBinary.getAlignmentForChildren();
if (binaryParentType != PyElementTypes.RETURN_STATEMENT &&
binaryParentType != PyElementTypes.YIELD_EXPRESSION) {
if (childAlignment == null && topmostBinary != null &&
!(parenthesised && isIfCondition(binaryParentNode)) &&
!(isCondition(topmostBinary.myNode) && !ALIGN_CONDITIONS_WITHOUT_PARENTHESES)) {
childAlignment = topmostBinary.getAlignmentForChildren();
}
// We omit indentation for the binary expression itself in this case (similarly to PyTupleExpression inside
// PyParenthesisedExpression) because we indent individual operands and operators inside rather than
// the whole contained expression.
childIndent = parenthesised ? Indent.getContinuationIndent() : Indent.getContinuationWithoutFirstIndent();
}
else {
childIndent = Indent.getNormalIndent();
}
// We omit indentation for the binary expression itself in this case (similarly to PyTupleExpression inside
// PyParenthesisedExpression) because we indent individual operands and operators inside rather than
// the whole contained expression.
childIndent = parenthesised ? Indent.getContinuationIndent() : Indent.getContinuationWithoutFirstIndent();
}
}
else if (parentType == PyElementTypes.OR_PATTERN) {
@@ -774,6 +780,12 @@ public class PyBlock implements ASTBlock {
if (myNode.getElementType() == PyElementTypes.WITH_STATEMENT) {
return myNode.findChildByType(PyTokenTypes.LPAR) != null && !hasHangingIndent(myNode.getPsi());
}
if (myNode.getElementType() == PyElementTypes.TUPLE_EXPRESSION) {
final ASTNode prevNode = myNode.getTreeParent();
if (prevNode.getElementType() != PyElementTypes.PARENTHESIZED_EXPRESSION) {
return false;
}
}
return myContext.getPySettings().ALIGN_COLLECTIONS_AND_COMPREHENSIONS && !hasHangingIndent(myNode.getPsi());
}

View File

@@ -0,0 +1,5 @@
def some_method():
a = b = c = d = True
return a == b and \
b == c and \
c == d

View File

@@ -0,0 +1,5 @@
def some_method():
a = b = c = d = True
return a == b and \
b == c and \
c == d

View File

@@ -0,0 +1,5 @@
def some_method():
a = b = c = d = True
return a == b and \
b == c and \
c == d

View File

@@ -0,0 +1,5 @@
def some_method():
a = b = c = d = True
return a == b and \
b == c and \
c == d

View File

@@ -0,0 +1,5 @@
def some_method():
a = b = c = d = True
yield a == b and \
b == c and \
c == d

View File

@@ -0,0 +1,5 @@
def some_method():
a = b = c = d = True
yield a == b and \
b == c and \
c == d

View File

@@ -0,0 +1,6 @@
def some_method():
a = 1
b = 2
test = False
return a + \
(b if test else 0)

View File

@@ -0,0 +1,6 @@
def some_method():
a = 1
b = 2
test = False
return a + \
(b if test else 0)

View File

@@ -0,0 +1,8 @@
def fun():
abc = 1
xyz = 2
zzz = 3
sdf = 4
out = abc, xyz, \
zzz, sdf
pass

View File

@@ -0,0 +1,8 @@
def fun():
abc = 1
xyz = 2
zzz = 3
sdf = 4
out = abc, xyz, \
zzz, sdf
pass

View File

@@ -0,0 +1,7 @@
def fun():
abc = 1
xyz = 2
zzz = 3
sdf = 4
return abc, xyz, \
zzz, sdf

View File

@@ -0,0 +1,7 @@
def fun():
abc = 1
xyz = 2
zzz = 3
sdf = 4
return abc, xyz, \
zzz, sdf

View File

@@ -0,0 +1,7 @@
def gen():
abc = 1
xyz = 2
zzz = 3
sdf = 4
yield abc, xyz, \
zzz, sdf

View File

@@ -0,0 +1,7 @@
def gen():
abc = 1
xyz = 2
zzz = 3
sdf = 4
yield abc, xyz, \
zzz, sdf

View File

@@ -242,7 +242,7 @@ public class PyEditingTest extends PyTestCase {
}
public void testEnterInTuple() {
doTestEnter("for x in 'a', <caret>'b': pass", "for x in 'a', \\\n 'b': pass");
doTestEnter("for x in 'a', <caret>'b': pass", "for x in 'a', \\\n 'b': pass");
}
public void testEnterInCodeWithErrorElements() {

View File

@@ -1261,4 +1261,34 @@ public class PyFormatterTest extends PyTestCase {
public void testMultiLineCallChainSplitByBackslashes() {
doTest();
}
// PY-24792
public void testNoAlignmentForMultilineBinaryExpressionInReturnStatement() {
doTest();
}
// PY-24792
public void testNoAlignmentForMultilineBinaryExpressionInYieldStatement() {
doTest();
}
// PY-24792
public void testNoAlignmentForPartlyParenthesizedMultiLineReturnStatement() {
doTest();
}
// PY-24792
public void testNoAlignmentForSplitByBackslashesTupleInReturnStatement() {
doTest();
}
// PY-24792
public void testNoAlignmentForSplitByBackslashesTupleInAssignmentStatement() {
doTest();
}
// PY-24792
public void testNoAlignmentForSplitByBackslashesTupleInYieldStatement() {
doTest();
}
}