PY-42200 Support parenthesized context managers in Python 3.9+

In case of syntactic ambiguity with previous versions of the grammar, such as
"with (expr)" or "with (expr1, expr2)", PyWithStatement is still parsed as
having its own parentheses, not a parenthesized expression or a tuple as
a single context expression. The latter case, even though syntactically legal,
is still reported by the compatibility inspection in Python <3.9.

These changes also include proper formatter and editing support (e.g. not
inserting backslashes on line breaks inside parentheses), as well as
Complete Current Statement, which now takes possible parentheses into account
while inserting a missing colon.

The changes in the formatter are somewhat ad-hoc, intended to minimize the effect
on other constructs. "With" statement is somewhat special in the sense that it's
the first compound statement (having a statement list) with its own list-like
part in parentheses.

Existing tests on with statement processing were expanded and uniformly named.

Co-authored-by: Semyon Proshev <semyon.proshev@jetbrains.com>

GitOrigin-RevId: 15c33e97f177e81b5ed23891063555df016feb05
This commit is contained in:
Mikhail Golubev
2022-05-02 16:55:02 +03:00
committed by intellij-monorepo-bot
parent 379444cdda
commit 97b22aaa13
60 changed files with 1581 additions and 164 deletions

View File

@@ -806,6 +806,7 @@ INSP.compatibility.old.dict.methods.not.available.in.py3=dict.iterkeys(), dict.i
INSP.compatibility.basestring.type.not.available.in.py3=basestring type is not available in Python 3 INSP.compatibility.basestring.type.not.available.in.py3=basestring type is not available in Python 3
INSP.compatibility.new.union.syntax.not.available.in.earlier.version=allow writing union types as X | Y INSP.compatibility.new.union.syntax.not.available.in.earlier.version=allow writing union types as X | Y
INSP.compatibility.feature.support.match.statements=support match statements INSP.compatibility.feature.support.match.statements=support match statements
INSP.compatibility.feature.support.parenthesized.context.expressions=support parenthesized context expressions
# PyUnnecessaryBackslashInspection # PyUnnecessaryBackslashInspection
INSP.NAME.unnecessary.backslash=Unnecessary backslash INSP.NAME.unnecessary.backslash=Unnecessary backslash

View File

@@ -12,6 +12,7 @@ import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet; import com.intellij.psi.tree.TokenSet;
import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ArrayUtil; import com.intellij.util.ArrayUtil;
import com.intellij.util.ObjectUtils;
import com.jetbrains.python.PyElementTypes; import com.jetbrains.python.PyElementTypes;
import com.jetbrains.python.PyTokenTypes; import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.PythonCodeStyleService; import com.jetbrains.python.PythonCodeStyleService;
@@ -74,7 +75,8 @@ public class PyBlock implements ASTBlock {
PyElementTypes.FROM_IMPORT_STATEMENT, PyElementTypes.FROM_IMPORT_STATEMENT,
PyElementTypes.SEQUENCE_PATTERN, PyElementTypes.SEQUENCE_PATTERN,
PyElementTypes.MAPPING_PATTERN, PyElementTypes.MAPPING_PATTERN,
PyElementTypes.PATTERN_ARGUMENT_LIST); PyElementTypes.PATTERN_ARGUMENT_LIST,
PyElementTypes.WITH_STATEMENT);
private static final boolean ALIGN_CONDITIONS_WITHOUT_PARENTHESES = false; private static final boolean ALIGN_CONDITIONS_WITHOUT_PARENTHESES = false;
@@ -456,6 +458,18 @@ public class PyBlock implements ASTBlock {
} }
} }
if (parentType == PyElementTypes.WITH_STATEMENT && isInsideWithStatementParentheses(myNode, child)) {
if (needListAlignment(child)) {
childAlignment = getAlignmentForChildren();
}
else {
childIndent = Indent.getNormalIndent();
}
if (childType == PyTokenTypes.RPAR && !settings.HANG_CLOSING_BRACKETS) {
childIndent = Indent.getNoneIndent();
}
}
ASTNode prev = child.getTreePrev(); ASTNode prev = child.getTreePrev();
while (prev != null && prev.getElementType() == TokenType.WHITE_SPACE) { while (prev != null && prev.getElementType() == TokenType.WHITE_SPACE) {
if (prev.textContains('\\') && if (prev.textContains('\\') &&
@@ -475,6 +489,23 @@ public class PyBlock implements ASTBlock {
return new PyBlock(this, child, childAlignment, childIndent, childWrap, myContext); return new PyBlock(this, child, childAlignment, childIndent, childWrap, myContext);
} }
private static boolean isInsideWithStatementParentheses(@NotNull ASTNode withStatement, @NotNull ASTNode node) {
ASTNode openingParenthesis = withStatement.findChildByType(PyTokenTypes.LPAR);
if (openingParenthesis == null) {
return false;
}
if (node.getStartOffset() < openingParenthesis.getStartOffset()) {
return false;
}
ASTNode closingParenthesis = withStatement.findChildByType(PyTokenTypes.RPAR);
if (closingParenthesis != null) {
return node.getStartOffset() <= closingParenthesis.getStartOffset();
}
ASTNode afterParentheses = ObjectUtils.chooseNotNull(withStatement.findChildByType(PyTokenTypes.COLON),
withStatement.findChildByType(PyElementTypes.STATEMENT_LIST));
return afterParentheses == null || node.getStartOffset() < afterParentheses.getStartOffset();
}
private static boolean isIfCondition(@NotNull ASTNode node) { private static boolean isIfCondition(@NotNull ASTNode node) {
@NotNull PsiElement element = node.getPsi(); @NotNull PsiElement element = node.getPsi();
final PyIfPart ifPart = as(element.getParent(), PyIfPart.class); final PyIfPart ifPart = as(element.getParent(), PyIfPart.class);
@@ -556,6 +587,9 @@ public class PyBlock implements ASTBlock {
if (elem instanceof PyFromImportStatement) { if (elem instanceof PyFromImportStatement) {
firstChild = ((PyFromImportStatement)elem).getLeftParen(); firstChild = ((PyFromImportStatement)elem).getLeftParen();
} }
else if (elem instanceof PyWithStatement) {
firstChild = PyPsiUtils.getFirstChildOfType(elem, PyTokenTypes.LPAR);
}
else { else {
firstChild = elem.getFirstChild(); firstChild = elem.getFirstChild();
} }
@@ -585,6 +619,10 @@ public class PyBlock implements ASTBlock {
final PyExpression value = ((PyKeyValueExpression)firstItem).getValue(); final PyExpression value = ((PyKeyValueExpression)firstItem).getValue();
return value != null && hasHangingIndent(value); return value != null && hasHangingIndent(value);
} }
else if (firstItem instanceof PyWithItem) {
PyExpression contextExpression = ((PyWithItem)firstItem).getExpression();
return contextExpression != null && hasHangingIndent(contextExpression);
}
return hasHangingIndent(firstItem); return hasHangingIndent(firstItem);
} }
} }
@@ -608,6 +646,9 @@ public class PyBlock implements ASTBlock {
else if (elem instanceof PyFromImportStatement) { else if (elem instanceof PyFromImportStatement) {
items = ((PyFromImportStatement)elem).getImportElements(); items = ((PyFromImportStatement)elem).getImportElements();
} }
else if (elem instanceof PyWithStatement) {
items = ((PyWithStatement)elem).getWithItems();
}
else if (elem instanceof PyParenthesizedExpression) { else if (elem instanceof PyParenthesizedExpression) {
final PyExpression containedExpression = ((PyParenthesizedExpression)elem).getContainedExpression(); final PyExpression containedExpression = ((PyParenthesizedExpression)elem).getContainedExpression();
if (containedExpression instanceof PyTupleExpression) { if (containedExpression instanceof PyTupleExpression) {
@@ -730,6 +771,9 @@ public class PyBlock implements ASTBlock {
return false; return false;
} }
} }
if (myNode.getElementType() == PyElementTypes.WITH_STATEMENT) {
return myNode.findChildByType(PyTokenTypes.LPAR) != null && !hasHangingIndent(myNode.getPsi());
}
return myContext.getPySettings().ALIGN_COLLECTIONS_AND_COMPREHENSIONS && !hasHangingIndent(myNode.getPsi()); return myContext.getPySettings().ALIGN_COLLECTIONS_AND_COMPREHENSIONS && !hasHangingIndent(myNode.getPsi());
} }
@@ -968,6 +1012,21 @@ public class PyBlock implements ASTBlock {
final ASTNode prevNode = insertAfterBlock.getNode(); final ASTNode prevNode = insertAfterBlock.getNode();
final PsiElement prevElt = prevNode.getPsi(); final PsiElement prevElt = prevNode.getPsi();
// TODO Use the same approach for other list-like constructs
if (myNode.getElementType() == PyElementTypes.WITH_STATEMENT && isInsideWithStatementParentheses(myNode, prevNode)) {
ASTNode openingParenthesis = myNode.findChildByType(PyTokenTypes.LPAR);
for (int i = newChildIndex - 1; i >= 0 ; i--) {
PyBlock prevBlock = mySubBlocks.get(i);
if (prevBlock.myNode == openingParenthesis) {
break;
}
if (prevBlock.getAlignment() != null) {
return new ChildAttributes(Indent.getNormalIndent(), prevBlock.getAlignment());
}
}
return new ChildAttributes(Indent.getNormalIndent(), null);
}
// stmt lists, parts and definitions should also think for themselves // stmt lists, parts and definitions should also think for themselves
if (prevElt instanceof PyStatementList) { if (prevElt instanceof PyStatementList) {
if (dedentAfterLastStatement((PyStatementList)prevElt)) { if (dedentAfterLastStatement((PyStatementList)prevElt)) {
@@ -1079,6 +1138,9 @@ public class PyBlock implements ASTBlock {
return null; return null;
} }
} }
if (elem instanceof PyWithStatement && PyPsiUtils.getFirstChildOfType(elem, PyTokenTypes.LPAR) == null) {
return null;
}
return getAlignmentForChildren(); return getAlignmentForChildren();
} }
return null; return null;

View File

@@ -838,27 +838,68 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper {
private void parseWithStatement(SyntaxTreeBuilder.Marker endMarker) { private void parseWithStatement(SyntaxTreeBuilder.Marker endMarker) {
assertCurrentToken(PyTokenTypes.WITH_KEYWORD); assertCurrentToken(PyTokenTypes.WITH_KEYWORD);
myBuilder.advanceLexer(); myBuilder.advanceLexer();
while (true) { if (!parseParenthesizedWithItems()) {
SyntaxTreeBuilder.Marker withItem = myBuilder.mark(); if (!parseWithItems(false)) {
if (!getExpressionParser().parseSingleExpression(false)) {
myBuilder.error(PyPsiBundle.message("PARSE.expected.expression")); myBuilder.error(PyPsiBundle.message("PARSE.expected.expression"));
} }
if (myBuilder.getTokenType() == PyTokenTypes.AS_KEYWORD) {
myBuilder.advanceLexer();
if (!getExpressionParser().parseSingleExpression(true)) {
myBuilder.error(PyPsiBundle.message("PARSE.expected.identifier"));
// 'as' is followed by a target
}
}
withItem.done(PyElementTypes.WITH_ITEM);
if (!matchToken(PyTokenTypes.COMMA)) {
break;
}
} }
parseColonAndSuite(); parseColonAndSuite();
endMarker.done(PyElementTypes.WITH_STATEMENT); endMarker.done(PyElementTypes.WITH_STATEMENT);
} }
private boolean parseParenthesizedWithItems() {
if (!atToken(PyTokenTypes.LPAR)) {
return false;
}
final SyntaxTreeBuilder.Marker leftPar = myBuilder.mark();
nextToken();
// Reparse empty parentheses as an empty tuple
if (!parseWithItems(true)) {
leftPar.rollbackTo();
return false;
}
if (!matchToken(PyTokenTypes.RPAR)) {
myBuilder.error(PyPsiBundle.message("PARSE.expected.rpar"));
}
// Reparse something like "(foo()) as bar" or (foo()).bar as a single WithItem
if (!atAnyOfTokens(PyTokenTypes.COLON, PyTokenTypes.STATEMENT_BREAK)) {
leftPar.rollbackTo();
return false;
}
leftPar.drop();
return true;
}
private boolean parseWithItems(boolean insideParentheses) {
if (!parseWithItem()) {
return false;
}
while (matchToken(PyTokenTypes.COMMA)) {
if (!parseWithItem()) {
if (!insideParentheses) {
myBuilder.error(PyPsiBundle.message("PARSE.expected.expression"));
}
break;
}
}
return true;
}
private boolean parseWithItem() {
SyntaxTreeBuilder.Marker withItem = myBuilder.mark();
if (!getExpressionParser().parseSingleExpression(false)) {
withItem.drop();
return false;
}
if (matchToken(PyTokenTypes.AS_KEYWORD)) {
if (!getExpressionParser().parseSingleExpression(true)) {
myBuilder.error(PyPsiBundle.message("PARSE.expected.identifier"));
}
}
withItem.done(PyElementTypes.WITH_ITEM);
return true;
}
private void parseClassDeclaration() { private void parseClassDeclaration() {
final SyntaxTreeBuilder.Marker classMarker = myBuilder.mark(); final SyntaxTreeBuilder.Marker classMarker = myBuilder.mark();
parseClassDeclaration(classMarker); parseClassDeclaration(classMarker);

View File

@@ -317,9 +317,33 @@ public abstract class CompatibilityVisitor extends PyAnnotator {
@Override @Override
public void visitPyWithStatement(@NotNull PyWithStatement node) { public void visitPyWithStatement(@NotNull PyWithStatement node) {
super.visitPyWithStatement(node); super.visitPyWithStatement(node);
checkParenthesizedWithItems(node);
checkAsyncKeyword(node); checkAsyncKeyword(node);
} }
private void checkParenthesizedWithItems(@NotNull PyWithStatement node) {
final PsiElement lpar = PyPsiUtils.getFirstChildOfType(node, PyTokenTypes.LPAR);
final PsiElement rpar = PyPsiUtils.getFirstChildOfType(node, PyTokenTypes.RPAR);
if (lpar == null && rpar == null) {
return;
}
// Context expressions such as "(foo(), bar())" or "(foo(),)" are valid in Python < 3.9, but most likely indicate an error anyway
PyWithItem[] withItems = node.getWithItems();
boolean canBeParsedAsSingleParenthesizedExpression = (
withItems.length == 1 &&
PyPsiUtils.getFirstChildOfType(withItems[0], PyTokenTypes.AS_KEYWORD) == null &&
PyPsiUtils.getFirstChildOfType(node, PyTokenTypes.COMMA) == null
);
if (canBeParsedAsSingleParenthesizedExpression) {
return;
}
for (PsiElement parenthesis : ContainerUtil.packNullables(lpar, rpar)) {
registerForAllMatchingVersions(level -> level.isOlderThan(LanguageLevel.PYTHON39) && registerForLanguageLevel(level),
PyPsiBundle.message("INSP.compatibility.feature.support.parenthesized.context.expressions"),
parenthesis);
}
}
@Override @Override
public void visitPyForStatement(@NotNull PyForStatement node) { public void visitPyForStatement(@NotNull PyForStatement node) {
super.visitPyForStatement(node); super.visitPyForStatement(node);
@@ -690,8 +714,8 @@ public abstract class CompatibilityVisitor extends PyAnnotator {
@Override @Override
public void visitPyMatchStatement(@NotNull PyMatchStatement matchStatement) { public void visitPyMatchStatement(@NotNull PyMatchStatement matchStatement) {
registerForAllMatchingVersions(level -> level.isOlderThan(LanguageLevel.PYTHON310), registerForAllMatchingVersions(level -> level.isOlderThan(LanguageLevel.PYTHON310),
PyPsiBundle.message("INSP.compatibility.feature.support.match.statements"), PyPsiBundle.message("INSP.compatibility.feature.support.match.statements"),
matchStatement.getFirstChild()); matchStatement.getFirstChild());
} }

View File

@@ -18,11 +18,12 @@ package com.jetbrains.python.codeInsight.editorActions.smartEnter.fixers;
import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.Editor;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ArrayUtil; import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException; import com.intellij.util.IncorrectOperationException;
import com.jetbrains.python.PyTokenTypes; import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.codeInsight.editorActions.smartEnter.PySmartEnterProcessor; import com.jetbrains.python.codeInsight.editorActions.smartEnter.PySmartEnterProcessor;
import com.jetbrains.python.psi.PyExpression;
import com.jetbrains.python.psi.PyWithItem; import com.jetbrains.python.psi.PyWithItem;
import com.jetbrains.python.psi.PyWithStatement; import com.jetbrains.python.psi.PyWithStatement;
import com.jetbrains.python.psi.impl.PyPsiUtils; import com.jetbrains.python.psi.impl.PyPsiUtils;
@@ -38,34 +39,38 @@ public class PyWithFixer extends PyFixer<PyWithStatement> {
@Override @Override
public void doApply(@NotNull Editor editor, @NotNull PySmartEnterProcessor processor, @NotNull PyWithStatement withStatement) throws IncorrectOperationException { public void doApply(@NotNull Editor editor, @NotNull PySmartEnterProcessor processor, @NotNull PyWithStatement withStatement) throws IncorrectOperationException {
final PsiElement colonToken = PyPsiUtils.getFirstChildOfType(withStatement, PyTokenTypes.COLON);
final PsiElement withToken = PyPsiUtils.getFirstChildOfType(withStatement, PyTokenTypes.WITH_KEYWORD); final PsiElement withToken = PyPsiUtils.getFirstChildOfType(withStatement, PyTokenTypes.WITH_KEYWORD);
assert withToken != null;
final Document document = editor.getDocument(); final Document document = editor.getDocument();
if (colonToken == null && withToken != null) { final PsiElement colonToken = PyPsiUtils.getFirstChildOfType(withStatement, PyTokenTypes.COLON);
int insertAt = withToken.getTextRange().getEndOffset(); if (colonToken == null) {
String textToInsert = ":"; PsiElement closingParenthesis = PyPsiUtils.getFirstChildOfType(withStatement, PyTokenTypes.RPAR);
final PyWithItem lastItem = ArrayUtil.getLastElement(withStatement.getWithItems()); PyWithItem lastWithItem = ArrayUtil.getLastElement(withStatement.getWithItems());
if (lastItem == null || lastItem.getExpression() == null) { PsiElement rightmostElement = closingParenthesis != null ? closingParenthesis :
textToInsert = " :"; lastWithItem != null ? lastWithItem :
processor.registerUnresolvedError(insertAt + 1); withToken;
} document.insertString(rightmostElement.getTextRange().getEndOffset(), ":");
else { }
final PyExpression expression = lastItem.getExpression();
insertAt = expression.getTextRange().getEndOffset(); if (withStatement.getWithItems().length != 0) {
final PsiElement asToken = PyPsiUtils.getFirstChildOfType(lastItem, PyTokenTypes.AS_KEYWORD); for (PyWithItem withItem : withStatement.getWithItems()) {
if (asToken != null) { final PsiElement asToken = PyPsiUtils.getFirstChildOfType(withItem, PyTokenTypes.AS_KEYWORD);
insertAt = asToken.getTextRange().getEndOffset(); if (asToken != null && withItem.getTarget() == null) {
final PyExpression target = lastItem.getTarget(); int asKeywordEndOffset = asToken.getTextRange().getEndOffset();
if (target != null) { if (!(PsiTreeUtil.nextLeaf(asToken, true) instanceof PsiWhiteSpace)) {
insertAt = target.getTextRange().getEndOffset(); document.insertString(asKeywordEndOffset," ");
}
else {
textToInsert = " :";
processor.registerUnresolvedError(insertAt + 1);
} }
processor.registerUnresolvedError(asKeywordEndOffset + 1);
break;
} }
} }
document.insertString(insertAt, textToInsert); }
else {
int withKeywordEndOffset = withToken.getTextRange().getEndOffset();
if (!(PsiTreeUtil.nextLeaf(withToken, true) instanceof PsiWhiteSpace)) {
document.insertString(withKeywordEndOffset, " ");
processor.registerUnresolvedError(withKeywordEndOffset + 1);
}
} }
} }
} }

View File

@@ -25,6 +25,7 @@ import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.codeInsight.PyCodeInsightSettings; import com.jetbrains.python.codeInsight.PyCodeInsightSettings;
import com.jetbrains.python.documentation.docstrings.*; import com.jetbrains.python.documentation.docstrings.*;
import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyPsiUtils;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -189,7 +190,8 @@ public class PythonEnterHandler extends EnterHandlerDelegateAdapter {
// if we're in middle of typing, it's expected that we will have error elements // if we're in middle of typing, it's expected that we will have error elements
} }
if (inFromImportParentheses(statementBefore, nodeAtCaret.getTextRange().getStartOffset())) { final int offset = nodeAtCaret.getTextRange().getStartOffset();
if (inFromImportParentheses(statementBefore, offset) || inWithItemsParentheses(statementBefore, offset)) {
return false; return false;
} }
@@ -314,6 +316,15 @@ public class PythonEnterHandler extends EnterHandlerDelegateAdapter {
return false; return false;
} }
private static boolean inWithItemsParentheses(@NotNull PsiElement statement, int offset) {
if (!(statement instanceof PyWithStatement)) {
return false;
}
final PsiElement leftParen = PyPsiUtils.getFirstChildOfType(statement, PyTokenTypes.LPAR);
return leftParen != null && offset >= leftParen.getTextRange().getEndOffset();
}
@Override @Override
public Result postProcessEnter(@NotNull PsiFile file, public Result postProcessEnter(@NotNull PsiFile file,
@NotNull Editor editor, @NotNull Editor editor,

View File

@@ -0,0 +1,2 @@
with (foo() as,
bar())<caret>:

View File

@@ -0,0 +1,2 @@
with (foo() as <caret>,
bar()):

View File

@@ -0,0 +1,3 @@
with (foo()<caret>,
bar() as):
pass

View File

@@ -0,0 +1,3 @@
with (foo(),
bar() as <caret>):
pass

View File

@@ -0,0 +1,2 @@
with (foo(),
bar() as baz<caret>):

View File

@@ -0,0 +1,3 @@
with (foo(),
bar() as baz):
<caret>

View File

@@ -0,0 +1 @@
with (foo()<caret>)

View File

@@ -0,0 +1,2 @@
with (foo()):
<caret>

View File

@@ -0,0 +1,6 @@
with (
foo(),
bar(),
baz()
):
pass

View File

@@ -0,0 +1,6 @@
with (
foo(),
bar(),
baz()
):
pass

View File

@@ -0,0 +1,13 @@
with (foo(),
bar(),
# comment
baz()):
pass
with (
# comment
foo(),
bar(),
baz()
):
pass

View File

@@ -0,0 +1,26 @@
if (foo(
1,
2
), foo(
3,
4
)):
pass
while [foo(
1,
2
), foo(
3,
4
)]:
pass
with (foo(
1,
2
), foo(
3,
4
)):
pass

View File

@@ -0,0 +1,26 @@
if (foo(
1,
2
), foo(
3,
4
)):
pass
while [foo(
1,
2
), foo(
3,
4
)]:
pass
with (foo(
1,
2
), foo(
3,
4
)):
pass

View File

@@ -0,0 +1,3 @@
with (foo() as bar,
foo() as bar):
pass

View File

@@ -0,0 +1,3 @@
with (foo() as bar,
foo() as bar):
pass

View File

@@ -0,0 +1,13 @@
with (foo(),
bar(),
# comment
baz()):
pass
with (
# comment
foo(),
bar(),
baz()
):
pass

View File

@@ -0,0 +1,17 @@
with <warning descr="Python versions 2.7, 3.5, 3.6, 3.7, 3.8 do not support parenthesized context expressions">(</warning>
foo() as baz,
foo() as bar
<warning descr="Python versions 2.7, 3.5, 3.6, 3.7, 3.8 do not support parenthesized context expressions">)</warning>:
pass
with (foo()) as baz:
pass
with (foo()):
pass
with <warning descr="Python versions 2.7, 3.5, 3.6, 3.7, 3.8 do not support parenthesized context expressions">(</warning>foo(),<warning descr="Python versions 2.7, 3.5, 3.6, 3.7, 3.8 do not support parenthesized context expressions">)</warning>:
pass
with <warning descr="Python versions 2.7, 3.5, 3.6, 3.7, 3.8 do not support parenthesized context expressions">(</warning>foo(), bar()<warning descr="Python versions 2.7, 3.5, 3.6, 3.7, 3.8 do not support parenthesized context expressions">)</warning>:
pass

View File

@@ -1,2 +0,0 @@
with open("") as :
pass

View File

@@ -1,23 +0,0 @@
PyFile:WithMissingID.py
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PyWithItem
PyCallExpression: open
PyReferenceExpression: open
PsiElement(Py:IDENTIFIER)('open')
PyArgumentList
PsiElement(Py:LPAR)('(')
PyStringLiteralExpression:
PsiElement(Py:SINGLE_QUOTED_STRING)('""')
PsiElement(Py:RPAR)(')')
PsiWhiteSpace(' ')
PsiElement(Py:AS_KEYWORD)('as')
PsiErrorElement:Identifier expected
<empty list>
PsiWhiteSpace(' ')
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')

View File

@@ -1,3 +0,0 @@
from __future__ import with_statement
with x as y:
pass

View File

@@ -1,29 +0,0 @@
PyFile:WithStatement.py
PyFromImportStatement
PsiElement(Py:FROM_KEYWORD)('from')
PsiWhiteSpace(' ')
PyReferenceExpression: __future__
PsiElement(Py:IDENTIFIER)('__future__')
PsiWhiteSpace(' ')
PsiElement(Py:IMPORT_KEYWORD)('import')
PsiWhiteSpace(' ')
PyImportElement:with_statement
PyReferenceExpression: with_statement
PsiElement(Py:IDENTIFIER)('with_statement')
PsiWhiteSpace('\n')
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PyWithItem
PyReferenceExpression: x
PsiElement(Py:IDENTIFIER)('x')
PsiWhiteSpace(' ')
PsiElement(Py:AS_KEYWORD)('as')
PsiWhiteSpace(' ')
PyTargetExpression: y
PsiElement(Py:IDENTIFIER)('y')
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')

View File

@@ -1,2 +0,0 @@
with x as y:
pass

View File

@@ -1,17 +0,0 @@
PyFile:WithStatement26.py
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PyWithItem
PyReferenceExpression: x
PsiElement(Py:IDENTIFIER)('x')
PsiWhiteSpace(' ')
PsiElement(Py:AS_KEYWORD)('as')
PsiWhiteSpace(' ')
PyTargetExpression: y
PsiElement(Py:IDENTIFIER)('y')
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')

View File

@@ -1 +0,0 @@
with x as a, y as b: pass

View File

@@ -1,27 +0,0 @@
PyFile:WithStatement31.py
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PyWithItem
PyReferenceExpression: x
PsiElement(Py:IDENTIFIER)('x')
PsiWhiteSpace(' ')
PsiElement(Py:AS_KEYWORD)('as')
PsiWhiteSpace(' ')
PyTargetExpression: a
PsiElement(Py:IDENTIFIER)('a')
PsiElement(Py:COMMA)(',')
PsiWhiteSpace(' ')
PyWithItem
PyReferenceExpression: y
PsiElement(Py:IDENTIFIER)('y')
PsiWhiteSpace(' ')
PsiElement(Py:AS_KEYWORD)('as')
PsiWhiteSpace(' ')
PyTargetExpression: b
PsiElement(Py:IDENTIFIER)('b')
PsiElement(Py:COLON)(':')
PsiWhiteSpace(' ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')

View File

@@ -0,0 +1,11 @@
with (foo).bar:
pass
with (foo)(bar):
pass
with (foo)[bar]:
pass
with (foo) | bar:
pass

View File

@@ -0,0 +1,80 @@
PyFile:WithStatementContextExpressionStartsWithParenthesis.py
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PyWithItem
PyReferenceExpression: bar
PyParenthesizedExpression
PsiElement(Py:LPAR)('(')
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PsiElement(Py:RPAR)(')')
PsiElement(Py:DOT)('.')
PsiElement(Py:IDENTIFIER)('bar')
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')
PsiWhiteSpace('\n\n')
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PyWithItem
PyCallExpression: foo
PyParenthesizedExpression
PsiElement(Py:LPAR)('(')
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PsiElement(Py:RPAR)(')')
PyArgumentList
PsiElement(Py:LPAR)('(')
PyReferenceExpression: bar
PsiElement(Py:IDENTIFIER)('bar')
PsiElement(Py:RPAR)(')')
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')
PsiWhiteSpace('\n\n')
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PyWithItem
PySubscriptionExpression
PyParenthesizedExpression
PsiElement(Py:LPAR)('(')
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PsiElement(Py:RPAR)(')')
PsiElement(Py:LBRACKET)('[')
PyReferenceExpression: bar
PsiElement(Py:IDENTIFIER)('bar')
PsiElement(Py:RBRACKET)(']')
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')
PsiWhiteSpace('\n\n')
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PyWithItem
PyBinaryExpression
PyParenthesizedExpression
PsiElement(Py:LPAR)('(')
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PsiElement(Py:RPAR)(')')
PsiWhiteSpace(' ')
PsiElement(Py:OR)('|')
PsiWhiteSpace(' ')
PyReferenceExpression: bar
PsiElement(Py:IDENTIFIER)('bar')
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')

View File

@@ -0,0 +1,11 @@
with foo(), foo():
pass
with foo(), \
foo():
pass
with foo() as bar, foo():
pass
with foo(), foo() as bar():
pass
with foo() as bar, foo() as bar:
pass

View File

@@ -0,0 +1,150 @@
PyFile:WithStatementMultipleWithItemsWithoutParentheses.py
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PyWithItem
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiElement(Py:COMMA)(',')
PsiWhiteSpace(' ')
PyWithItem
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')
PsiWhiteSpace('\n')
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PyWithItem
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiElement(Py:COMMA)(',')
PsiWhiteSpace(' \')
PsiWhiteSpace('\n ')
PyWithItem
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')
PsiWhiteSpace('\n')
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PyWithItem
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiWhiteSpace(' ')
PsiElement(Py:AS_KEYWORD)('as')
PsiWhiteSpace(' ')
PyTargetExpression: bar
PsiElement(Py:IDENTIFIER)('bar')
PsiElement(Py:COMMA)(',')
PsiWhiteSpace(' ')
PyWithItem
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')
PsiWhiteSpace('\n')
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PyWithItem
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiElement(Py:COMMA)(',')
PsiWhiteSpace(' ')
PyWithItem
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiWhiteSpace(' ')
PsiElement(Py:AS_KEYWORD)('as')
PsiWhiteSpace(' ')
PyCallExpression: bar
PyTargetExpression: bar
PsiElement(Py:IDENTIFIER)('bar')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')
PsiWhiteSpace('\n')
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PyWithItem
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiWhiteSpace(' ')
PsiElement(Py:AS_KEYWORD)('as')
PsiWhiteSpace(' ')
PyTargetExpression: bar
PsiElement(Py:IDENTIFIER)('bar')
PsiElement(Py:COMMA)(',')
PsiWhiteSpace(' ')
PyWithItem
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiWhiteSpace(' ')
PsiElement(Py:AS_KEYWORD)('as')
PsiWhiteSpace(' ')
PyTargetExpression: bar
PsiElement(Py:IDENTIFIER)('bar')
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')

View File

@@ -0,0 +1,16 @@
with (foo()):
pass
with (foo(),):
pass
with (foo() as bar):
pass
with (foo() as bar,):
pass
with (foo(), foo()):
pass
with (foo() as bar, foo()):
pass
with (foo(), foo() as bar):
pass
with (foo() as bar, foo() as baz):
pass

View File

@@ -0,0 +1,212 @@
PyFile:WithStatementParenthesizedWithItems.py
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PsiElement(Py:LPAR)('(')
PyWithItem
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiElement(Py:RPAR)(')')
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')
PsiWhiteSpace('\n')
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PsiElement(Py:LPAR)('(')
PyWithItem
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiElement(Py:COMMA)(',')
PsiElement(Py:RPAR)(')')
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')
PsiWhiteSpace('\n')
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PsiElement(Py:LPAR)('(')
PyWithItem
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiWhiteSpace(' ')
PsiElement(Py:AS_KEYWORD)('as')
PsiWhiteSpace(' ')
PyTargetExpression: bar
PsiElement(Py:IDENTIFIER)('bar')
PsiElement(Py:RPAR)(')')
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')
PsiWhiteSpace('\n')
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PsiElement(Py:LPAR)('(')
PyWithItem
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiWhiteSpace(' ')
PsiElement(Py:AS_KEYWORD)('as')
PsiWhiteSpace(' ')
PyTargetExpression: bar
PsiElement(Py:IDENTIFIER)('bar')
PsiElement(Py:COMMA)(',')
PsiElement(Py:RPAR)(')')
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')
PsiWhiteSpace('\n')
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PsiElement(Py:LPAR)('(')
PyWithItem
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiElement(Py:COMMA)(',')
PsiWhiteSpace(' ')
PyWithItem
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiElement(Py:RPAR)(')')
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')
PsiWhiteSpace('\n')
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PsiElement(Py:LPAR)('(')
PyWithItem
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiWhiteSpace(' ')
PsiElement(Py:AS_KEYWORD)('as')
PsiWhiteSpace(' ')
PyTargetExpression: bar
PsiElement(Py:IDENTIFIER)('bar')
PsiElement(Py:COMMA)(',')
PsiWhiteSpace(' ')
PyWithItem
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiElement(Py:RPAR)(')')
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')
PsiWhiteSpace('\n')
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PsiElement(Py:LPAR)('(')
PyWithItem
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiElement(Py:COMMA)(',')
PsiWhiteSpace(' ')
PyWithItem
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiWhiteSpace(' ')
PsiElement(Py:AS_KEYWORD)('as')
PsiWhiteSpace(' ')
PyTargetExpression: bar
PsiElement(Py:IDENTIFIER)('bar')
PsiElement(Py:RPAR)(')')
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')
PsiWhiteSpace('\n')
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PsiElement(Py:LPAR)('(')
PyWithItem
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiWhiteSpace(' ')
PsiElement(Py:AS_KEYWORD)('as')
PsiWhiteSpace(' ')
PyTargetExpression: bar
PsiElement(Py:IDENTIFIER)('bar')
PsiElement(Py:COMMA)(',')
PsiWhiteSpace(' ')
PyWithItem
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiWhiteSpace(' ')
PsiElement(Py:AS_KEYWORD)('as')
PsiWhiteSpace(' ')
PyTargetExpression: baz
PsiElement(Py:IDENTIFIER)('baz')
PsiElement(Py:RPAR)(')')
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')

View File

@@ -0,0 +1,5 @@
with foo(),:
pass
with foo() as bar,:
pass

View File

@@ -0,0 +1,43 @@
PyFile:WithStatementRecoveryDanglingComma.py
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PyWithItem
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiElement(Py:COMMA)(',')
PsiErrorElement:Expression expected
<empty list>
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')
PsiWhiteSpace('\n')
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PyWithItem
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiWhiteSpace(' ')
PsiElement(Py:AS_KEYWORD)('as')
PsiWhiteSpace(' ')
PyTargetExpression: bar
PsiElement(Py:IDENTIFIER)('bar')
PsiElement(Py:COMMA)(',')
PsiErrorElement:Expression expected
<empty list>
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')

View File

@@ -0,0 +1,2 @@
with ():
pass

View File

@@ -0,0 +1,13 @@
PyFile:WithStatementRecoveryEmptyParentheses.py
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PyWithItem
PyTupleExpression
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')

View File

@@ -0,0 +1,10 @@
with (:
pass
with (foo():
pass
with (foo() as:
pass
with (foo() as bar:
pass
with ((foo() as bar):
pass

View File

@@ -0,0 +1,101 @@
PyFile:WithStatementRecoveryIncompleteParentheses.py
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PyWithItem
PyParenthesizedExpression
PsiElement(Py:LPAR)('(')
PsiErrorElement:Unexpected expression syntax
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PsiElement(Py:PASS_KEYWORD)('pass')
PsiWhiteSpace('\n')
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PsiElement(Py:LPAR)('(')
PsiElement(Py:IDENTIFIER)('foo')
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')
PsiErrorElement:End of statement expected
<empty list>
PsiWhiteSpace('\n')
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PsiElement(Py:LPAR)('(')
PyWithItem
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiWhiteSpace(' ')
PsiElement(Py:AS_KEYWORD)('as')
PsiErrorElement:Identifier expected
<empty list>
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')
PsiErrorElement:End of statement expected
<empty list>
PsiWhiteSpace('\n')
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PsiElement(Py:LPAR)('(')
PyWithItem
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiWhiteSpace(' ')
PsiElement(Py:AS_KEYWORD)('as')
PsiWhiteSpace(' ')
PyTargetExpression: bar
PsiElement(Py:IDENTIFIER)('bar')
PsiErrorElement:')' expected
<empty list>
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')
PsiErrorElement:End of statement expected
<empty list>
PsiWhiteSpace('\n')
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PsiElement(Py:LPAR)('(')
PyWithItem
PyParenthesizedExpression
PsiElement(Py:LPAR)('(')
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiWhiteSpace(' ')
PsiErrorElement:Unexpected expression syntax
PsiElement(Py:AS_KEYWORD)('as')
PsiWhiteSpace(' ')
PsiElement(Py:IDENTIFIER)('bar')
PsiElement(Py:RPAR)(')')
PsiErrorElement:')' expected
<empty list>
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')

View File

@@ -0,0 +1,6 @@
with foo() as :
pass
with (foo() as ):
pass
with foo() as, foo():
pass

View File

@@ -0,0 +1,73 @@
PyFile:WithStatementRecoveryMissingAsName.py
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PyWithItem
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiWhiteSpace(' ')
PsiElement(Py:AS_KEYWORD)('as')
PsiErrorElement:Identifier expected
<empty list>
PsiWhiteSpace(' ')
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')
PsiWhiteSpace('\n')
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PsiElement(Py:LPAR)('(')
PyWithItem
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiWhiteSpace(' ')
PsiElement(Py:AS_KEYWORD)('as')
PsiErrorElement:Identifier expected
<empty list>
PsiWhiteSpace(' ')
PsiElement(Py:RPAR)(')')
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')
PsiWhiteSpace('\n')
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PyWithItem
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiWhiteSpace(' ')
PsiElement(Py:AS_KEYWORD)('as')
PsiErrorElement:Identifier expected
<empty list>
PsiElement(Py:COMMA)(',')
PsiWhiteSpace(' ')
PyWithItem
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')

View File

@@ -0,0 +1,10 @@
with foo()
pass
with (foo())
pass
with (foo()).bar
pass
with foo() as
pass
with foo() as bar
pass

View File

@@ -0,0 +1,100 @@
PyFile:WithStatementRecoveryMissingColon.py
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PyWithItem
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiErrorElement:':' expected
<empty list>
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')
PsiWhiteSpace('\n')
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PsiElement(Py:LPAR)('(')
PyWithItem
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiElement(Py:RPAR)(')')
PsiErrorElement:':' expected
<empty list>
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')
PsiWhiteSpace('\n')
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PyWithItem
PyReferenceExpression: bar
PyParenthesizedExpression
PsiElement(Py:LPAR)('(')
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiElement(Py:RPAR)(')')
PsiElement(Py:DOT)('.')
PsiElement(Py:IDENTIFIER)('bar')
PsiErrorElement:':' expected
<empty list>
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')
PsiWhiteSpace('\n')
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PyWithItem
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiWhiteSpace(' ')
PsiElement(Py:AS_KEYWORD)('as')
PsiErrorElement:Identifier expected
<empty list>
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')
PsiWhiteSpace('\n')
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PyWithItem
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiWhiteSpace(' ')
PsiElement(Py:AS_KEYWORD)('as')
PsiWhiteSpace(' ')
PyTargetExpression: bar
PsiElement(Py:IDENTIFIER)('bar')
PsiErrorElement:':' expected
<empty list>
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')

View File

@@ -0,0 +1,2 @@
with:
pass

View File

@@ -0,0 +1,10 @@
PyFile:WithStatementRecoveryNoWithItems.py
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiErrorElement:Expression expected
<empty list>
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')

View File

@@ -0,0 +1,14 @@
with (foo()):
pass
with ((foo())):
pass
with (foo()), (foo()):
pass
with (foo()) as bar:
pass
with ((foo()) as bar):
pass
with (bar := foo()):
pass
with (bar := foo()) as bar:
pass

View File

@@ -0,0 +1,175 @@
PyFile:WithStatementWithItemsOwnParentheses.py
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PsiElement(Py:LPAR)('(')
PyWithItem
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiElement(Py:RPAR)(')')
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')
PsiWhiteSpace('\n')
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PsiElement(Py:LPAR)('(')
PyWithItem
PyParenthesizedExpression
PsiElement(Py:LPAR)('(')
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiElement(Py:RPAR)(')')
PsiElement(Py:RPAR)(')')
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')
PsiWhiteSpace('\n')
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PyWithItem
PyParenthesizedExpression
PsiElement(Py:LPAR)('(')
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiElement(Py:RPAR)(')')
PsiElement(Py:COMMA)(',')
PsiWhiteSpace(' ')
PyWithItem
PyParenthesizedExpression
PsiElement(Py:LPAR)('(')
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiElement(Py:RPAR)(')')
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')
PsiWhiteSpace('\n')
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PyWithItem
PyParenthesizedExpression
PsiElement(Py:LPAR)('(')
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiElement(Py:RPAR)(')')
PsiWhiteSpace(' ')
PsiElement(Py:AS_KEYWORD)('as')
PsiWhiteSpace(' ')
PyTargetExpression: bar
PsiElement(Py:IDENTIFIER)('bar')
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')
PsiWhiteSpace('\n')
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PsiElement(Py:LPAR)('(')
PyWithItem
PyParenthesizedExpression
PsiElement(Py:LPAR)('(')
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiElement(Py:RPAR)(')')
PsiWhiteSpace(' ')
PsiElement(Py:AS_KEYWORD)('as')
PsiWhiteSpace(' ')
PyTargetExpression: bar
PsiElement(Py:IDENTIFIER)('bar')
PsiElement(Py:RPAR)(')')
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')
PsiWhiteSpace('\n')
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PyWithItem
PyParenthesizedExpression
PsiElement(Py:LPAR)('(')
PyAssignmentExpression
PyTargetExpression: bar
PsiElement(Py:IDENTIFIER)('bar')
PsiWhiteSpace(' ')
PsiElement(Py:COLONEQ)(':=')
PsiWhiteSpace(' ')
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiElement(Py:RPAR)(')')
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')
PsiWhiteSpace('\n')
PyWithStatement
PsiElement(Py:WITH_KEYWORD)('with')
PsiWhiteSpace(' ')
PyWithItem
PyParenthesizedExpression
PsiElement(Py:LPAR)('(')
PyAssignmentExpression
PyTargetExpression: bar
PsiElement(Py:IDENTIFIER)('bar')
PsiWhiteSpace(' ')
PsiElement(Py:COLONEQ)(':=')
PsiWhiteSpace(' ')
PyCallExpression: foo
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PyArgumentList
PsiElement(Py:LPAR)('(')
PsiElement(Py:RPAR)(')')
PsiElement(Py:RPAR)(')')
PsiWhiteSpace(' ')
PsiElement(Py:AS_KEYWORD)('as')
PsiWhiteSpace(' ')
PyTargetExpression: bar
PsiElement(Py:IDENTIFIER)('bar')
PsiElement(Py:COLON)(':')
PsiWhiteSpace('\n ')
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')

View File

@@ -897,6 +897,121 @@ public class PyEditingTest extends PyTestCase {
doTypingTest('\n'); doTypingTest('\n');
} }
// PY-42200
public void testParenthesizedWithItemsEnterBeforeExistingItem() {
doTestEnter("with (<caret>foo() as baz,\n" +
" foo() as bar\n" +
"):\n" +
" pass",
"with (\n" +
" foo() as baz,\n" +
" foo() as bar\n" +
"):\n" +
" pass");
doTestEnter("with (\n" +
" foo() as baz,<caret>foo() as bar\n" +
"):\n" +
" pass",
"with (\n" +
" foo() as baz,\n" +
" foo() as bar\n" +
"):\n" +
" pass");
doTestEnter("with (foo() as baz,<caret>foo() as bar):\n" +
" pass",
"with (foo() as baz,\n" +
" foo() as bar):\n" +
" pass");
}
// PY-42200
public void testParenthesizedWithItemsEnterBeforeClosingParenthesis() {
doTestEnter("with (foo(), \n" +
" foo()<caret>):\n" +
" pass",
"with (foo(), \n" +
" foo()\n" +
" <caret>):\n" +
" pass");
getPythonCodeStyleSettings().HANG_CLOSING_BRACKETS = false;
doTestEnter("with (\n" +
" foo() as baz,\n" +
" foo() as bar<caret>):\n" +
" pass",
"with (\n" +
" foo() as baz,\n" +
" foo() as bar\n" +
"):\n" +
" pass");
getPythonCodeStyleSettings().HANG_CLOSING_BRACKETS = true;
doTestEnter("with (\n" +
" foo() as baz,\n" +
" foo() as bar<caret>):\n" +
" pass",
"with (\n" +
" foo() as baz,\n" +
" foo() as bar\n" +
" ):\n" +
" pass");
}
// PY-42200
public void testParenthesizedWithItemsEnterBeforeNonExistingItem() {
doTestEnter("with (foo(),<caret>\n" +
" bar()):\n" +
" pass",
"with (foo(),\n" +
" <caret>\n" +
" bar()):\n" +
" pass");
doTestEnter("with (\n" +
" foo(),<caret>\n" +
" bar()\n" +
"):\n" +
" pass",
"with (\n" +
" foo(),\n" +
" <caret>\n" +
" bar()\n" +
"):\n" +
" pass");
}
// PY-42200
public void testParenthesizedWithItemsEnterBeforeComment() {
doTestEnter("with (\n" +
" foo(),<caret># comment\n" +
" bar()\n" +
"):\n" +
" pass",
"with (\n" +
" foo(),\n" +
" <caret># comment\n" +
" bar()\n" +
"):\n" +
" pass");
doTestEnter("with (foo(),<caret># comment\n" +
" bar()):\n" +
" pass",
"with (foo(),\n" +
" <caret># comment\n" +
" bar()):\n" +
" pass");
}
// PY-42200
public void testParenthesizedWithItemsEnterBeforeStatementList() {
doTestEnter("with (foo(), foo()):<caret>",
"with (foo(), foo()):\n" +
" <caret>");
}
@NotNull @NotNull
private PyCodeStyleSettings getPythonCodeStyleSettings() { private PyCodeStyleSettings getPythonCodeStyleSettings() {
return getCodeStyleSettings().getCustomSettings(PyCodeStyleSettings.class); return getCodeStyleSettings().getCustomSettings(PyCodeStyleSettings.class);

View File

@@ -1217,4 +1217,26 @@ public class PyFormatterTest extends PyTestCase {
getPythonCodeStyleSettings().SPACE_AROUND_EQ_IN_KEYWORD_ARGUMENT = true; getPythonCodeStyleSettings().SPACE_AROUND_EQ_IN_KEYWORD_ARGUMENT = true;
doTest(); doTest();
} }
// PY-42200
public void testParenthesizedWithItems() {
doTest();
}
// PY-42200
public void testHangingClosingBracketInParenthesizedWithItems() {
getPythonCodeStyleSettings().HANG_CLOSING_BRACKETS = true;
doTest();
}
// PY-42200
public void testParenthesizedWithItemsHangingIndentProcessedSimilarlyToCollectionsInStatementHeaders() {
doTest();
}
// PY-42200
public void testParenthesizedWithItemsWrapping() {
getCodeStyleSettings().setRightMargin(PythonLanguage.getInstance(), 20);
doTest();
}
} }

View File

@@ -328,11 +328,40 @@ public class PySmartEnterTest extends PyTestCase {
doTest(); doTest();
} }
public void testWithExpressionMissingNoSpaceAfterWithKeyword() {
doTest();
}
// PY-12877 // PY-12877
public void testWithOnlyColonMissing() { public void testWithOnlyColonMissing() {
doTest(); doTest();
} }
// PY-42200
public void testWithParenthesizedWithItemsOnlyColonMissing() {
doTest();
}
// PY-42200
public void testWithParenthesizedWithItemsColonMissingAndTargetIncomplete() {
doTest();
}
// PY-42200
public void testWithParenthesizedWithItemsFirstTargetIncomplete() {
doTest();
}
// PY-42200
public void testWithParenthesizedWithItemsLastTargetIncomplete() {
doTest();
}
// PY-42200
public void testWithParenthesizedWithItemsNothingToFix() {
doTest();
}
// PY-9209 // PY-9209
public void testSpaceInsertedAfterHashSignInComment() { public void testSpaceInsertedAfterHashSignInComment() {
doTest(); doTest();

View File

@@ -61,6 +61,11 @@ public class PyCompatibilityInspectionTest extends PyInspectionTestCase {
doTest(); doTest();
} }
// PY-42200
public void testParenthesizedWithItems() {
doTest(LanguageLevel.getLatest());
}
public void testPrintStatement() { public void testPrintStatement() {
doTest(); doTest();
} }

View File

@@ -105,10 +105,6 @@ public class PythonParsingTest extends ParsingTestCase {
doTest(); doTest();
} }
public void testWithStatement() {
doTest();
}
public void testDecoratedFunction() { public void testDecoratedFunction() {
doTest(); doTest();
} }
@@ -117,10 +113,6 @@ public class PythonParsingTest extends ParsingTestCase {
doTest(); doTest();
} }
public void testWithStatement26() {
doTest(LanguageLevel.PYTHON26);
}
public void testPrintAsFunction26() { public void testPrintAsFunction26() {
doTest(LanguageLevel.PYTHON26); doTest(LanguageLevel.PYTHON26);
} }
@@ -205,10 +197,6 @@ public class PythonParsingTest extends ParsingTestCase {
doTest(); doTest();
} }
public void testWithStatement31() {
doTest(LanguageLevel.PYTHON34);
}
public void testLongString() { public void testLongString() {
doTest(); doTest();
} }
@@ -421,10 +409,6 @@ public class PythonParsingTest extends ParsingTestCase {
doTest(); doTest();
} }
public void testWithMissingID() { // PY-9853
doTest(LanguageLevel.PYTHON27);
}
public void testOverIndentedComment() { // PY-1909 public void testOverIndentedComment() { // PY-1909
doTest(); doTest();
} }
@@ -1196,6 +1180,51 @@ public class PythonParsingTest extends ParsingTestCase {
doTest(LanguageLevel.getLatest()); doTest(LanguageLevel.getLatest());
} }
// PY-42200
public void testWithStatementParenthesizedWithItems() {
doTest(LanguageLevel.getLatest());
}
// PY-43505
public void testWithStatementMultipleWithItemsWithoutParentheses() {
doTest(LanguageLevel.getLatest());
}
// PY-42200
public void testWithStatementWithItemsOwnParentheses() {
doTest(LanguageLevel.getLatest());
}
// PY-42200
public void testWithStatementContextExpressionStartsWithParenthesis() {
doTest(LanguageLevel.getLatest());
}
public void testWithStatementRecoveryDanglingComma() {
doTest(LanguageLevel.getLatest());
}
public void testWithStatementRecoveryIncompleteParentheses() {
doTest(LanguageLevel.getLatest());
}
public void testWithStatementRecoveryMissingColon() {
doTest(LanguageLevel.getLatest());
}
public void testWithStatementRecoveryEmptyParentheses() {
doTest(LanguageLevel.getLatest());
}
// PY-9853
public void testWithStatementRecoveryMissingAsName() {
doTest(LanguageLevel.getLatest());
}
public void testWithStatementRecoveryNoWithItems() {
doTest(LanguageLevel.getLatest());
}
public void doTest() { public void doTest() {
doTest(LanguageLevel.PYTHON26); doTest(LanguageLevel.PYTHON26);
} }
@@ -1227,6 +1256,4 @@ public class PythonParsingTest extends ParsingTestCase {
functionToCheck.getStatementList(); //To make sure each function has statement list (does not throw exception) functionToCheck.getStatementList(); //To make sure each function has statement list (does not throw exception)
} }
} }
} }