diff --git a/python/src/META-INF/python-plugin-common.xml b/python/src/META-INF/python-plugin-common.xml
index c9dd720108fe..801590de42f6 100644
--- a/python/src/META-INF/python-plugin-common.xml
+++ b/python/src/META-INF/python-plugin-common.xml
@@ -24,6 +24,7 @@
+
diff --git a/python/src/com/jetbrains/python/editor/PyEnterBetweenBracketsHandler.java b/python/src/com/jetbrains/python/editor/PyEnterBetweenBracketsHandler.java
new file mode 100644
index 000000000000..0ceb1e79eb2e
--- /dev/null
+++ b/python/src/com/jetbrains/python/editor/PyEnterBetweenBracketsHandler.java
@@ -0,0 +1,13 @@
+package com.jetbrains.python.editor;
+
+import com.intellij.codeInsight.editorActions.enter.EnterBetweenBracesHandler;
+
+/**
+ * @author yole
+ */
+public class PyEnterBetweenBracketsHandler extends EnterBetweenBracesHandler {
+ @Override
+ protected boolean isBracePair(char c1, char c2) {
+ return c1 == '[' && c2 == ']';
+ }
+}
diff --git a/python/src/com/jetbrains/python/editor/PythonEnterHandler.java b/python/src/com/jetbrains/python/editor/PythonEnterHandler.java
index 079e0f40a707..e13480e7cfbe 100644
--- a/python/src/com/jetbrains/python/editor/PythonEnterHandler.java
+++ b/python/src/com/jetbrains/python/editor/PythonEnterHandler.java
@@ -7,6 +7,7 @@ import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.actionSystem.EditorActionHandler;
+import com.intellij.openapi.editor.actions.SplitLineAction;
import com.intellij.openapi.util.Ref;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
@@ -46,6 +47,10 @@ public class PythonEnterHandler implements EnterHandlerDelegate {
if (!(file instanceof PyFile)) {
return Result.Continue;
}
+ final Boolean isSplitLine = DataManager.getInstance().loadFromDataContext(dataContext, SplitLineAction.SPLIT_LINE_KEY);
+ if (isSplitLine != null) {
+ return Result.Continue;
+ }
Document doc = editor.getDocument();
PsiDocumentManager.getInstance(file.getProject()).commitDocument(doc);
final int offset = caretOffset.get();
diff --git a/python/src/com/jetbrains/python/formatter/PyBlock.java b/python/src/com/jetbrains/python/formatter/PyBlock.java
index 1bc4435d1a48..10e355f9abb4 100644
--- a/python/src/com/jetbrains/python/formatter/PyBlock.java
+++ b/python/src/com/jetbrains/python/formatter/PyBlock.java
@@ -129,7 +129,7 @@ public class PyBlock implements ASTBlock {
!ourBrackets.contains(childType)) {
wrap = Wrap.createWrap(WrapType.NORMAL, true);
}
- if (needListAlignment(child)) {
+ if (needListAlignment(child) && !isEmptyList(_node.getPsi())) {
childAlignment = getAlignmentForChildren();
}
}
@@ -149,7 +149,7 @@ public class PyBlock implements ASTBlock {
childIndent = Indent.getNoneIndent();
}
else {
- childIndent = Indent.getContinuationIndent();
+ childIndent = Indent.getNormalIndent();
}
}
else if (parentType == PyElementTypes.DICT_LITERAL_EXPRESSION) {
@@ -171,6 +171,12 @@ public class PyBlock implements ASTBlock {
childAlignment = getAlignmentForChildren();
}
}
+ else if (parentType == PyElementTypes.KEY_VALUE_EXPRESSION) {
+ PyKeyValueExpression keyValue = (PyKeyValueExpression) _node.getPsi();
+ if (keyValue != null && child.getPsi() == keyValue.getValue()) {
+ childIndent = Indent.getNormalIndent();
+ }
+ }
if (isAfterStatementList(child) && !hasLineBreaksBefore(child, 2)) { // maybe enter was pressed and cut us from a previous (nested) statement list
childIndent = Indent.getNormalIndent();
@@ -179,6 +185,16 @@ public class PyBlock implements ASTBlock {
return new PyBlock(child, childAlignment, childIndent, wrap, mySettings);
}
+ private static boolean isEmptyList(PsiElement psi) {
+ if (psi instanceof PyDictLiteralExpression) {
+ return ((PyDictLiteralExpression) psi).getElements().length == 0;
+ }
+ if (psi instanceof PySequenceExpression) {
+ return ((PySequenceExpression) psi).getElements().length == 0;
+ }
+ return false;
+ }
+
private static boolean isAfterStatementList(ASTNode child) {
try {
PsiElement prev = sure(child.getPsi().getPrevSibling());
@@ -193,17 +209,33 @@ public class PyBlock implements ASTBlock {
}
}
- private static boolean needListAlignment(ASTNode child) {
+ private boolean needListAlignment(ASTNode child) {
IElementType childType = child.getElementType();
if (PyTokenTypes.OPEN_BRACES.contains(childType)) {
return false;
}
if (PyTokenTypes.CLOSE_BRACES.contains(childType)) {
- return PsiTreeUtil.getParentOfType(child.getPsi(), PyArgumentList.class) != null;
+ ASTNode prevNonSpace = findPrevNonSpaceNode(child);
+ if (prevNonSpace != null && prevNonSpace.getElementType() == PyTokenTypes.COMMA) {
+ return true;
+ }
+ return false;
+ }
+ if (_node.getElementType() == PyElementTypes.ARGUMENT_LIST) {
+ PyArgumentList argList = (PyArgumentList) _node.getPsi();
+ return argList != null && argList.getArguments().length > 1;
}
return true;
}
+ @Nullable
+ private static ASTNode findPrevNonSpaceNode(ASTNode node) {
+ do {
+ node = node.getTreePrev();
+ } while(node != null && (node.getElementType() == TokenType.WHITE_SPACE || PyTokenTypes.WHITESPACE.contains(node.getElementType())));
+ return node;
+ }
+
private static boolean hasLineBreaksBefore(ASTNode child, int minCount) {
return isWhitespaceWithLineBreaks(TreeUtil.findLastLeaf(child.getTreePrev()), minCount) ||
isWhitespaceWithLineBreaks(child.getFirstChildNode(), minCount);
@@ -263,8 +295,17 @@ public class PyBlock implements ASTBlock {
IElementType type2 = childNode2.getElementType();
if (type1 == PyElementTypes.CLASS_DECLARATION) {
+ if ((type2 == PyElementTypes.CLASS_DECLARATION || type2 == PyElementTypes.FUNCTION_DECLARATION) &&
+ parentType instanceof PyFileElementType) {
+ return getBlankLinesForOption(getPySettings().BLANK_LINES_BETWEEN_TOP_LEVEL_CLASSES_FUNCTIONS);
+ }
return getBlankLinesForOption(mySettings.BLANK_LINES_AROUND_CLASS);
}
+ if (type1 == PyElementTypes.FUNCTION_DECLARATION &&
+ (type2 == PyElementTypes.CLASS_DECLARATION || type2 == PyElementTypes.FUNCTION_DECLARATION) &&
+ parentType instanceof PyFileElementType) {
+ return getBlankLinesForOption(getPySettings().BLANK_LINES_BETWEEN_TOP_LEVEL_CLASSES_FUNCTIONS);
+ }
if (type1 == PyElementTypes.FUNCTION_DECLARATION ||
(type2 == PyElementTypes.FUNCTION_DECLARATION && isStatementOrDeclaration(type1))) {
return getBlankLinesForOption(mySettings.BLANK_LINES_AROUND_METHOD);
@@ -386,7 +427,7 @@ public class PyBlock implements ASTBlock {
return null;
}
- private boolean isImportStatement(IElementType type1) {
+ private static boolean isImportStatement(IElementType type1) {
return (type1 == PyElementTypes.IMPORT_STATEMENT || type1 == PyElementTypes.FROM_IMPORT_STATEMENT);
}
@@ -486,7 +527,9 @@ public class PyBlock implements ASTBlock {
*/
- return new ChildAttributes(getChildIndent(newChildIndex), getChildAlignment());
+ Indent childIndent = getChildIndent(newChildIndex);
+ Alignment childAlignment = getChildAlignment();
+ return new ChildAttributes(childIndent, childAlignment);
}
private static boolean dedentAfterLastStatement(PyStatementList statementList) {
@@ -498,25 +541,31 @@ public class PyBlock implements ASTBlock {
return last instanceof PyReturnStatement || last instanceof PyRaiseStatement || last instanceof PyPassStatement;
}
+ @Nullable
private Alignment getChildAlignment() {
if (ourListElementTypes.contains(_node.getElementType())) {
+ if (_node.getPsi() instanceof PyDictLiteralExpression) {
+ PyKeyValueExpression[] elements = ((PyDictLiteralExpression)_node.getPsi()).getElements();
+ if (elements.length == 0) {
+ return null;
+ }
+ PyKeyValueExpression last = elements[elements.length-1];
+ if (last.getValue() == null) { // incomplete
+ return null;
+ }
+ }
return getAlignmentForChildren();
}
return null;
}
private Indent getChildIndent(int newChildIndex) {
+ ASTNode afterNode = getAfterNode(newChildIndex);
ASTNode lastChild = getLastNonSpaceChild(_node, false);
if (lastChild != null && lastChild.getElementType() == PyElementTypes.STATEMENT_LIST && _subBlocks.size() >= newChildIndex) {
- if (newChildIndex == 0) { // block text contains backslash line wrappings, child block list not built
+ if (afterNode == null) {
return Indent.getNoneIndent();
}
- int prevIndex = newChildIndex - 1;
- while (prevIndex > 0 && _subBlocks.get(prevIndex).getNode().getElementType() == PyTokenTypes.END_OF_LINE_COMMENT) {
- prevIndex--;
- }
- PyBlock insertAfterBlock = _subBlocks.get(prevIndex);
- ASTNode afterNode = insertAfterBlock.getNode();
// handle pressing Enter after colon and before first statement in
// existing statement list
@@ -570,6 +619,13 @@ public class PyBlock implements ASTBlock {
}
}
+ if (afterNode != null && afterNode.getElementType() == PyElementTypes.KEY_VALUE_EXPRESSION) {
+ PyKeyValueExpression keyValue = (PyKeyValueExpression) afterNode.getPsi();
+ if (keyValue != null && keyValue.getValue() == null) { // incomplete
+ return Indent.getContinuationIndent(true);
+ }
+ }
+
// constructs that imply indent for their children
if (ourListElementTypes.contains(_node.getElementType()) || _node.getPsi() instanceof PyStatementPart) {
return Indent.getNormalIndent();
@@ -589,6 +645,19 @@ public class PyBlock implements ASTBlock {
*/
}
+ @Nullable
+ private ASTNode getAfterNode(int newChildIndex) {
+ if (newChildIndex == 0) { // block text contains backslash line wrappings, child block list not built
+ return null;
+ }
+ int prevIndex = newChildIndex - 1;
+ while (prevIndex > 0 && _subBlocks.get(prevIndex).getNode().getElementType() == PyTokenTypes.END_OF_LINE_COMMENT) {
+ prevIndex--;
+ }
+ PyBlock insertAfterBlock = _subBlocks.get(prevIndex);
+ return insertAfterBlock.getNode();
+ }
+
private static ASTNode getLastNonSpaceChild(ASTNode node, boolean acceptError) {
ASTNode lastChild = node.getLastChildNode();
while (lastChild != null &&
diff --git a/python/src/com/jetbrains/python/formatter/PyCodeStyleSettings.java b/python/src/com/jetbrains/python/formatter/PyCodeStyleSettings.java
index 22a67e7053b8..f7232ade3245 100644
--- a/python/src/com/jetbrains/python/formatter/PyCodeStyleSettings.java
+++ b/python/src/com/jetbrains/python/formatter/PyCodeStyleSettings.java
@@ -14,6 +14,8 @@ public class PyCodeStyleSettings extends CustomCodeStyleSettings {
public boolean SPACE_AROUND_EQ_IN_NAMED_PARAMETER = false;
public boolean SPACE_AROUND_EQ_IN_KEYWORD_ARGUMENT = false;
+ public int BLANK_LINES_BETWEEN_TOP_LEVEL_CLASSES_FUNCTIONS = 2;
+
public PyCodeStyleSettings(CodeStyleSettings container) {
super("Python", container);
}
diff --git a/python/src/com/jetbrains/python/formatter/PyLanguageCodeStyleSettingsProvider.java b/python/src/com/jetbrains/python/formatter/PyLanguageCodeStyleSettingsProvider.java
index 7474cb6197f8..472d6eb224b8 100644
--- a/python/src/com/jetbrains/python/formatter/PyLanguageCodeStyleSettingsProvider.java
+++ b/python/src/com/jetbrains/python/formatter/PyLanguageCodeStyleSettingsProvider.java
@@ -57,6 +57,8 @@ public class PyLanguageCodeStyleSettingsProvider extends LanguageCodeStyleSettin
"BLANK_LINES_AFTER_IMPORTS",
"KEEP_BLANK_LINES_IN_DECLARATIONS",
"KEEP_BLANK_LINES_IN_CODE");
+ consumer.showCustomOption(PyCodeStyleSettings.class, "BLANK_LINES_BETWEEN_TOP_LEVEL_CLASSES_FUNCTIONS", "Between top-level classes and functions",
+ BLANK_LINES);
}
else if (settingsType == SettingsType.WRAPPING_AND_BRACES_SETTINGS) {
consumer.showAllStandardOptions();
diff --git a/python/src/com/jetbrains/python/parsing/ExpressionParsing.java b/python/src/com/jetbrains/python/parsing/ExpressionParsing.java
index 3c4073bba423..8047264147be 100644
--- a/python/src/com/jetbrains/python/parsing/ExpressionParsing.java
+++ b/python/src/com/jetbrains/python/parsing/ExpressionParsing.java
@@ -188,7 +188,10 @@ public class ExpressionParsing extends Parsing {
private void parseDictLiteralTail(PsiBuilder.Marker startMarker, PsiBuilder.Marker firstKeyValueMarker) {
if (!parseSingleExpression(false)) {
myBuilder.error("expression expected");
- firstKeyValueMarker.drop();
+ firstKeyValueMarker.done(PyElementTypes.KEY_VALUE_EXPRESSION);
+ if (atToken(PyTokenTypes.RBRACE)) {
+ myBuilder.advanceLexer();
+ }
startMarker.done(PyElementTypes.DICT_LITERAL_EXPRESSION);
return;
}
@@ -308,10 +311,14 @@ public class ExpressionParsing extends Parsing {
parseSliceEnd(expr, sliceItemStart);
}
else {
- parseExpressionOptional();
- if (myBuilder.getTokenType() == PyTokenTypes.COLON) {
+ parseSingleExpression(false);
+ if (atToken(PyTokenTypes.COLON)) {
parseSliceEnd(expr, sliceItemStart);
}
+ else if (atToken(PyTokenTypes.COMMA)) {
+ sliceItemStart.done(PyElementTypes.SLICE_ITEM);
+ parseSliceListTail(expr);
+ }
else {
sliceItemStart.drop();
checkMatches(PyTokenTypes.RBRACKET, message("PARSE.expected.rbracket"));
@@ -373,9 +380,13 @@ public class ExpressionParsing extends Parsing {
}
}
+ parseSliceListTail(exprStart);
+ }
+
+ private void parseSliceListTail(PsiBuilder.Marker exprStart) {
while (atToken(PyTokenTypes.COMMA)) {
nextToken();
- sliceItemStart = myBuilder.mark();
+ PsiBuilder.Marker sliceItemStart = myBuilder.mark();
parseTestExpression(false, false);
if (matchToken(PyTokenTypes.COLON)) {
parseTestExpression(false, false);
diff --git a/python/testData/formatter/blankLineBetweenMethods.py b/python/testData/formatter/blankLineBetweenMethods.py
index 2f18aaa72111..1c072f1a451e 100644
--- a/python/testData/formatter/blankLineBetweenMethods.py
+++ b/python/testData/formatter/blankLineBetweenMethods.py
@@ -1,6 +1,5 @@
class C:
- pass
-def foo():
- pass
-def bar():
- pass
\ No newline at end of file
+ def foo(self):
+ pass
+ def bar(self):
+ pass
\ No newline at end of file
diff --git a/python/testData/formatter/blankLineBetweenMethods_after.py b/python/testData/formatter/blankLineBetweenMethods_after.py
index 89a633f6165e..a6b9280d7dbf 100644
--- a/python/testData/formatter/blankLineBetweenMethods_after.py
+++ b/python/testData/formatter/blankLineBetweenMethods_after.py
@@ -1,8 +1,6 @@
class C:
- pass
+ def foo(self):
+ pass
-def foo():
- pass
-
-def bar():
- pass
\ No newline at end of file
+ def bar(self):
+ pass
\ No newline at end of file
diff --git a/python/testData/formatter/specialSlice.py b/python/testData/formatter/specialSlice.py
new file mode 100644
index 000000000000..ba8e7fad0df1
--- /dev/null
+++ b/python/testData/formatter/specialSlice.py
@@ -0,0 +1 @@
+a[b1,:]
\ No newline at end of file
diff --git a/python/testData/formatter/specialSlice_after.py b/python/testData/formatter/specialSlice_after.py
new file mode 100644
index 000000000000..98b951a3c1f9
--- /dev/null
+++ b/python/testData/formatter/specialSlice_after.py
@@ -0,0 +1 @@
+a[b1, :]
\ No newline at end of file
diff --git a/python/testData/formatter/twoLinesBetweenTopLevelClasses.py b/python/testData/formatter/twoLinesBetweenTopLevelClasses.py
new file mode 100644
index 000000000000..c2e1ee19ffd3
--- /dev/null
+++ b/python/testData/formatter/twoLinesBetweenTopLevelClasses.py
@@ -0,0 +1,5 @@
+class C:
+ pass
+
+class D:
+ pass
\ No newline at end of file
diff --git a/python/testData/formatter/twoLinesBetweenTopLevelClasses_after.py b/python/testData/formatter/twoLinesBetweenTopLevelClasses_after.py
new file mode 100644
index 000000000000..55ec52a5afaf
--- /dev/null
+++ b/python/testData/formatter/twoLinesBetweenTopLevelClasses_after.py
@@ -0,0 +1,6 @@
+class C:
+ pass
+
+
+class D:
+ pass
\ No newline at end of file
diff --git a/python/testData/formatter/twoLinesBetweenTopLevelFunctions.py b/python/testData/formatter/twoLinesBetweenTopLevelFunctions.py
new file mode 100644
index 000000000000..3a6fd143c7fb
--- /dev/null
+++ b/python/testData/formatter/twoLinesBetweenTopLevelFunctions.py
@@ -0,0 +1,11 @@
+class D:
+ pass
+
+def foo():
+ pass
+
+def bar():
+ pass
+
+class C:
+ pass
diff --git a/python/testData/formatter/twoLinesBetweenTopLevelFunctions_after.py b/python/testData/formatter/twoLinesBetweenTopLevelFunctions_after.py
new file mode 100644
index 000000000000..99227dec7391
--- /dev/null
+++ b/python/testData/formatter/twoLinesBetweenTopLevelFunctions_after.py
@@ -0,0 +1,14 @@
+class D:
+ pass
+
+
+def foo():
+ pass
+
+
+def bar():
+ pass
+
+
+class C:
+ pass
diff --git a/python/testData/inspections/AddClass_after.py b/python/testData/inspections/AddClass_after.py
index 2e177c5b5b46..cecadfbd15f2 100644
--- a/python/testData/inspections/AddClass_after.py
+++ b/python/testData/inspections/AddClass_after.py
@@ -1,6 +1,7 @@
class Xyzzy(object):
pass
+
class XyzzyTest:
def testSimple(self):
c = Xyzzy()
diff --git a/python/testData/psi/IncompleteDict.py b/python/testData/psi/IncompleteDict.py
new file mode 100644
index 000000000000..f047ba139c62
--- /dev/null
+++ b/python/testData/psi/IncompleteDict.py
@@ -0,0 +1 @@
+some_dict = { 'key': }
\ No newline at end of file
diff --git a/python/testData/psi/IncompleteDict.txt b/python/testData/psi/IncompleteDict.txt
new file mode 100644
index 000000000000..e493cb0219c5
--- /dev/null
+++ b/python/testData/psi/IncompleteDict.txt
@@ -0,0 +1,18 @@
+PyFile:IncompleteDict.py
+ PyAssignmentStatement
+ PyTargetExpression: some_dict
+ PsiElement(Py:IDENTIFIER)('some_dict')
+ PsiWhiteSpace(' ')
+ PsiElement(Py:EQ)('=')
+ PsiWhiteSpace(' ')
+ PyDictLiteralExpression
+ PsiElement(Py:LBRACE)('{')
+ PsiWhiteSpace(' ')
+ PyKeyValueExpression
+ PyStringLiteralExpression: key
+ PsiElement(Py:STRING_LITERAL)(''key'')
+ PsiElement(Py:COLON)(':')
+ PsiErrorElement:expression expected
+
+ PsiWhiteSpace(' ')
+ PsiElement(Py:RBRACE)('}')
\ No newline at end of file
diff --git a/python/testData/psi/SliceList.py b/python/testData/psi/SliceList.py
new file mode 100644
index 000000000000..ba8e7fad0df1
--- /dev/null
+++ b/python/testData/psi/SliceList.py
@@ -0,0 +1 @@
+a[b1,:]
\ No newline at end of file
diff --git a/python/testData/psi/SliceList.txt b/python/testData/psi/SliceList.txt
new file mode 100644
index 000000000000..c0c01a09a89c
--- /dev/null
+++ b/python/testData/psi/SliceList.txt
@@ -0,0 +1,13 @@
+PyFile:SliceList.py
+ PyExpressionStatement
+ PySliceExpression
+ PyReferenceExpression: a
+ PsiElement(Py:IDENTIFIER)('a')
+ PsiElement(Py:LBRACKET)('[')
+ PySliceItem
+ PyReferenceExpression: b1
+ PsiElement(Py:IDENTIFIER)('b1')
+ PsiElement(Py:COMMA)(',')
+ PySliceItem
+ PsiElement(Py:COLON)(':')
+ PsiElement(Py:RBRACKET)(']')
\ No newline at end of file
diff --git a/python/testData/refactoring/extractmethod/comment.after.py b/python/testData/refactoring/extractmethod/comment.after.py
index 534163362db3..f4760c22c752 100644
--- a/python/testData/refactoring/extractmethod/comment.after.py
+++ b/python/testData/refactoring/extractmethod/comment.after.py
@@ -2,5 +2,6 @@
def bar():
print("Hello")
+
def foo():
bar()
diff --git a/python/testData/refactoring/extractmethod/file.after.py b/python/testData/refactoring/extractmethod/file.after.py
index 74d8ca43a208..5a313ba35fef 100644
--- a/python/testData/refactoring/extractmethod/file.after.py
+++ b/python/testData/refactoring/extractmethod/file.after.py
@@ -2,6 +2,7 @@ def bar(base_new, self_new):
try: base_new.__init__(self_new)
except AttributeError: pass
+
def __init__(self):
for base in self__class__.__bases__:
bar(base, self)
diff --git a/python/testData/refactoring/extractmethod/return_tuple.after.py b/python/testData/refactoring/extractmethod/return_tuple.after.py
index dc924a7a7074..f4ff8f774e74 100644
--- a/python/testData/refactoring/extractmethod/return_tuple.after.py
+++ b/python/testData/refactoring/extractmethod/return_tuple.after.py
@@ -1,5 +1,6 @@
def bar(p_name_new, params_new):
return p_name_new + '(' + ', '.join(params_new) + ')'
+
def x(p_name, params):
return bar(p_name, params), None
\ No newline at end of file
diff --git a/python/testData/refactoring/extractsuperclass/simple.after.py b/python/testData/refactoring/extractsuperclass/simple.after.py
index 937128f2bd30..38248501dc4a 100644
--- a/python/testData/refactoring/extractsuperclass/simple.after.py
+++ b/python/testData/refactoring/extractsuperclass/simple.after.py
@@ -2,6 +2,7 @@ class Suppa:
def foo(self):
print "bar"
+
class Foo(Suppa):
def bar(self):
print "foo"
diff --git a/python/testData/refactoring/extractsuperclass/withSuper.after.py b/python/testData/refactoring/extractsuperclass/withSuper.after.py
index 76488d3f4b0f..5f346b590cad 100644
--- a/python/testData/refactoring/extractsuperclass/withSuper.after.py
+++ b/python/testData/refactoring/extractsuperclass/withSuper.after.py
@@ -2,6 +2,7 @@ class Suppa(object):
def foo(self):
print "bar"
+
class Foo(Suppa):
def bar(self):
print "foo"
diff --git a/python/testData/refactoring/pullup/simple.after.py b/python/testData/refactoring/pullup/simple.after.py
index 20c544899de8..d8c6cb7a0c2e 100644
--- a/python/testData/refactoring/pullup/simple.after.py
+++ b/python/testData/refactoring/pullup/simple.after.py
@@ -5,5 +5,6 @@ class Foo:
def boo(self):
print "rrrrr"
+
class Boo(Foo):
pass
\ No newline at end of file
diff --git a/python/testData/refactoring/pullup/withComments.after.py b/python/testData/refactoring/pullup/withComments.after.py
index 5ddd8d4241f3..ce91117e5413 100644
--- a/python/testData/refactoring/pullup/withComments.after.py
+++ b/python/testData/refactoring/pullup/withComments.after.py
@@ -6,5 +6,6 @@ class Foo:
def boo(self):
print "rrrrr"
+
class Boo(Foo):
pass
\ No newline at end of file
diff --git a/python/testData/refactoring/pullup/withMultilineComments.after.py b/python/testData/refactoring/pullup/withMultilineComments.after.py
index 3780dec0eb33..b7c0179871d9 100644
--- a/python/testData/refactoring/pullup/withMultilineComments.after.py
+++ b/python/testData/refactoring/pullup/withMultilineComments.after.py
@@ -5,6 +5,7 @@ class Foo:
def boo(self):
print "rrrrr"
+
class Boo(Foo):
'''
this is boo
diff --git a/python/testData/refactoring/pushdown/multiple.after.py b/python/testData/refactoring/pushdown/multiple.after.py
index 1cdbbe7d84f7..fc67b30f16de 100644
--- a/python/testData/refactoring/pushdown/multiple.after.py
+++ b/python/testData/refactoring/pushdown/multiple.after.py
@@ -1,6 +1,7 @@
class Foo:
pass
+
class Zope(Foo):
def _mine(self):
print "zope"
@@ -8,6 +9,7 @@ class Zope(Foo):
def foo(self):
print("a")
+
class Boo(Foo):
def boo(self):
print "rrrrr"
diff --git a/python/testData/refactoring/pushdown/py346.after.py b/python/testData/refactoring/pushdown/py346.after.py
index b60d169e4c9e..278ab4607823 100644
--- a/python/testData/refactoring/pushdown/py346.after.py
+++ b/python/testData/refactoring/pushdown/py346.after.py
@@ -1,6 +1,7 @@
class A:
pass
+
class B(A):
def meth_b1(self):
pass
@@ -13,6 +14,7 @@ class B(A):
def meth_a2(self):
pass
+
class D(A):
def meth_d1(self):
pass
diff --git a/python/testData/refactoring/pushdown/simple.after.py b/python/testData/refactoring/pushdown/simple.after.py
index 926f8cf64c19..3d36fa53d6a6 100644
--- a/python/testData/refactoring/pushdown/simple.after.py
+++ b/python/testData/refactoring/pushdown/simple.after.py
@@ -1,6 +1,7 @@
class Foo:
pass
+
class Boo(Foo):
def boo(self):
print "rrrrr"
diff --git a/python/testSrc/com/jetbrains/python/PyFormatterTest.java b/python/testSrc/com/jetbrains/python/PyFormatterTest.java
index 8ed532b07ff1..ecb58ad554ae 100644
--- a/python/testSrc/com/jetbrains/python/PyFormatterTest.java
+++ b/python/testSrc/com/jetbrains/python/PyFormatterTest.java
@@ -92,6 +92,18 @@ public class PyFormatterTest extends PyLightFixtureTestCase {
doTest();
}
+ public void testTwoLinesBetweenTopLevelClasses() { // PY-2765
+ doTest();
+ }
+
+ public void testTwoLinesBetweenTopLevelFunctions() { // PY-2765
+ doTest();
+ }
+
+ public void testSpecialSlice() { // PY-1928
+ doTest();
+ }
+
private void doTest() {
myFixture.configureByFile("formatter/" + getTestName(true) + ".py");
ApplicationManager.getApplication().runWriteAction(new Runnable() {
diff --git a/python/testSrc/com/jetbrains/python/PyIndentTest.java b/python/testSrc/com/jetbrains/python/PyIndentTest.java
index 31a195891490..5cd39c0783d6 100644
--- a/python/testSrc/com/jetbrains/python/PyIndentTest.java
+++ b/python/testSrc/com/jetbrains/python/PyIndentTest.java
@@ -71,12 +71,49 @@ public class PyIndentTest extends PyLightFixtureTestCase {
doTest("__all__ = [a for", "__all__ = [a for\n" + " ");
}
+ public void testAlignInListOnceMore() { // PY-2407
+ doTest("for id in [\"SEARCH_RESULT_ATTRIBUTES\", \n" +
+ " \"WRITE_SEARCH_RESULT_ATTRIBUTES\", \n" +
+ " \"IDENTIFIER_UNDER_CARET_ATTRIBUTES\",]:",
+ "for id in [\"SEARCH_RESULT_ATTRIBUTES\", \n" +
+ " \"WRITE_SEARCH_RESULT_ATTRIBUTES\", \n" +
+ " \"IDENTIFIER_UNDER_CARET_ATTRIBUTES\",\n" +
+ " ]:");
+ }
+
public void testAlignInDict() {
doTest("some_call({'aaa': 'v1',})",
"some_call({'aaa': 'v1',\n" +
" })");
}
+ public void testAlignInDictInParams() { // PY-1947
+ doTest("foobar({})",
+ "foobar({\n" +
+ " \n" +
+ "})");
+ }
+
+ public void testIndentDictMissingValue() { // PY-1469
+ doTest("some_dict = {\n" +
+ " 'key': \n" +
+ "}",
+ "some_dict = {\n" +
+ " 'key': \n" +
+ " \n" +
+ "}");
+ }
+
+ public void testIndentDictStringValue() { // PY-1469
+ doTest("some_dict = {\n" +
+ " 'key': ''\n" +
+ "}",
+ "some_dict = {\n" +
+ " 'key': \n" +
+ " ''\n" +
+ "}");
+ }
+
public void testClass() {
doTest("class A:\n" + " print a", "class A:\n" + " print a\n" + " ");
}
@@ -128,7 +165,7 @@ public class PyIndentTest extends PyLightFixtureTestCase {
}
public void testEnterInEmptyList() {
- doTest("[]", "[\n]");
+ doTest("[]", "[\n \n]");
}
public void testEnterInEmptyDict() {
@@ -149,6 +186,12 @@ public class PyIndentTest extends PyLightFixtureTestCase {
")");
}
+ public void testEnterInNonEmptyArgList() { // PY-1947
+ doTest("Task(params=1)",
+ "Task(\n" +
+ " params=1)");
+ }
+
public void testIndentAfterComment() { // PY-641
doTest("def foo():\n #some_call()\n another_call()", "def foo():\n #some_call()\n \n another_call()");
}
diff --git a/python/testSrc/com/jetbrains/python/PythonParsingTest.java b/python/testSrc/com/jetbrains/python/PythonParsingTest.java
index b3d8485f9995..3cd473572f7e 100644
--- a/python/testSrc/com/jetbrains/python/PythonParsingTest.java
+++ b/python/testSrc/com/jetbrains/python/PythonParsingTest.java
@@ -239,6 +239,14 @@ public class PythonParsingTest extends ParsingTestCase {
doTest();
}
+ public void testIncompleteDict() {
+ doTest();
+ }
+
+ public void testSliceList() { // PY-1928
+ doTest();
+ }
+
public void doTest() {
doTest(LanguageLevel.PYTHON25);
}