From 7a7d9e72e15598ae3b45e3176f134d1f659a8c13 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Thu, 16 Dec 2010 15:34:09 +0300 Subject: [PATCH 1/7] fixed PY-2514 False positive for augmented assignment --- .../inspections/PyAugmentAssignmentInspection.java | 13 ++++++++----- .../PyAugmentAssignmentInspection/test.py | 3 +++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/python/src/com/jetbrains/python/inspections/PyAugmentAssignmentInspection.java b/python/src/com/jetbrains/python/inspections/PyAugmentAssignmentInspection.java index abb92ff419a8..5a7383a1d72e 100644 --- a/python/src/com/jetbrains/python/inspections/PyAugmentAssignmentInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyAugmentAssignmentInspection.java @@ -2,6 +2,7 @@ package com.jetbrains.python.inspections; import com.intellij.codeInspection.ProblemsHolder; import com.intellij.psi.PsiElementVisitor; +import com.intellij.psi.tree.TokenSet; import com.jetbrains.python.PyBundle; import com.jetbrains.python.PyTokenTypes; import com.jetbrains.python.actions.AugmentedAssignmentQuickFix; @@ -43,17 +44,19 @@ public class PyAugmentAssignmentInspection extends PyInspection { PyExpression leftExpression = expression.getLeftExpression(); PyExpression rightExpression = expression.getRightExpression(); if (rightExpression != null) { + boolean changedParts = false; if (rightExpression.getText().equals(target.getText())) { PyExpression tmp = rightExpression; rightExpression = leftExpression; leftExpression = tmp; + changedParts = true; } PyElementType op = expression.getOperator(); - if (PyTokenTypes.ADDITIVE_OPERATIONS.contains(op) || - PyTokenTypes.MULTIPLICATIVE_OPERATIONS.contains(op) || - PyTokenTypes.SHIFT_OPERATIONS.contains(op) || - PyTokenTypes.BITWISE_OPERATIONS.contains(op) || - op == PyTokenTypes.EXP) { + final TokenSet operations = TokenSet.create(PyTokenTypes.PLUS, PyTokenTypes.MINUS, PyTokenTypes.MULT, + PyTokenTypes.FLOORDIV, PyTokenTypes.DIV, PyTokenTypes.PERC, PyTokenTypes.AND, PyTokenTypes.OR, + PyTokenTypes.XOR, PyTokenTypes.LTLT, PyTokenTypes.GTGT, PyTokenTypes.EXP); + final TokenSet commutativeOperations = TokenSet.create(PyTokenTypes.PLUS, PyTokenTypes.MULT); + if ((operations.contains(op) && !changedParts) || (changedParts && commutativeOperations.contains(op))) { if (leftExpression != null && (leftExpression instanceof PyReferenceExpression || leftExpression instanceof PySubscriptionExpression)) { if (leftExpression.getText().equals(target.getText())) { diff --git a/python/testData/inspections/PyAugmentAssignmentInspection/test.py b/python/testData/inspections/PyAugmentAssignmentInspection/test.py index 50601231ca12..fc807600fb9d 100644 --- a/python/testData/inspections/PyAugmentAssignmentInspection/test.py +++ b/python/testData/inspections/PyAugmentAssignmentInspection/test.py @@ -25,3 +25,6 @@ var_7 += 2 x = x | 3 x = x & 3 x = x ^ 3 + +#PY-2514 +dy = 1 - dy From e00afc8757c35a92315c3fd10d72220c176bfdf6 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Thu, 16 Dec 2010 15:55:46 +0300 Subject: [PATCH 2/7] fixed PY-2519 Join 2 ifs: disable intention if nested if contains also elif/else clause --- .../python/codeInsight/intentions/PyJoinIfIntention.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/PyJoinIfIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/PyJoinIfIntention.java index 545c84d98621..58187c43589b 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/PyJoinIfIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/PyJoinIfIntention.java @@ -37,10 +37,13 @@ public class PyJoinIfIntention extends BaseIntentionAction { PyIfStatement expression = PsiTreeUtil.getParentOfType(file.findElementAt(editor.getCaretModel().getOffset()), PyIfStatement.class); + PyIfStatement ifStatement = getIfStatement(expression); PyStatement firstStatement = getFirstStatement(ifStatement); if (firstStatement != null) { + if (((PyIfStatement)firstStatement).getElifParts().length != 0) return false; + if (((PyIfStatement)firstStatement).getElsePart() != null) return false; PyStatementList stList = ((PyIfStatement)firstStatement).getIfPart().getStatementList(); if (stList != null) if (stList.getStatements().length != 0) From 6fbcb1b804b0666c3f078010c210a18d2be047a2 Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Thu, 16 Dec 2010 16:56:12 +0300 Subject: [PATCH 3/7] fixed 'Unable to display children' in debugger (PY-2508) --- .../com/jetbrains/python/debugger/PyDebugValue.java | 6 +++++- .../com/jetbrains/python/debugger/pydev/ProtocolParser.java | 4 ---- .../src/com/jetbrains/python/debugger/PyDebugProcess.java | 1 + 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/python/pydevSrc/com/jetbrains/python/debugger/PyDebugValue.java b/python/pydevSrc/com/jetbrains/python/debugger/PyDebugValue.java index 1fa24d8bbf92..4cd70ae70e64 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/PyDebugValue.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/PyDebugValue.java @@ -133,7 +133,7 @@ public class PyDebugValue extends XValue { } catch (PyDebuggerException e) { if (!node.isObsolete()) { - node.setErrorMessage("Unable to display children"); + node.setErrorMessage("Unable to display children:" + e.getMessage()); } LOG.warn(e); } @@ -157,4 +157,8 @@ public class PyDebugValue extends XValue { return DebuggerIcons.VALUE_ICON; } } + + boolean isException() { + return myValue.startsWith("Traceback (most recent call last):"); + } } diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/ProtocolParser.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/ProtocolParser.java index b8b7a782af78..929a5893f281 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/ProtocolParser.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/ProtocolParser.java @@ -125,10 +125,6 @@ public class ProtocolParser { value = value.substring(type.length() + 2); } - if (value.startsWith("Traceback (most recent call last):")) { // convert traceback to exception - throw new PyDebuggerException(value); - } - return new PyDebugValue(name, type, value, "True".equals(isContainer)); } diff --git a/python/src/com/jetbrains/python/debugger/PyDebugProcess.java b/python/src/com/jetbrains/python/debugger/PyDebugProcess.java index ea24433cb15c..c11629eb4d35 100644 --- a/python/src/com/jetbrains/python/debugger/PyDebugProcess.java +++ b/python/src/com/jetbrains/python/debugger/PyDebugProcess.java @@ -124,6 +124,7 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr try { myDebugger.waitForConnect(); handshake(); + getSession().rebuildViews(); registerBreakpoints(); new RunCommand(myDebugger).execute(); } From 716f337c4f869e42b1d669e361e12cd604d30a43 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Thu, 16 Dec 2010 18:17:29 +0300 Subject: [PATCH 4/7] partly fixed PY-2518 Join 2 ifs: merge comments if both presented (Still have problem if comment is on the same level as Statement List) --- .../intentions/PyJoinIfIntention.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/PyJoinIfIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/PyJoinIfIntention.java index 58187c43589b..42636f1f993f 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/PyJoinIfIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/PyJoinIfIntention.java @@ -3,6 +3,8 @@ package com.jetbrains.python.codeInsight.intentions; import com.intellij.codeInsight.intention.impl.BaseIntentionAction; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiComment; +import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.IncorrectOperationException; @@ -11,6 +13,8 @@ import com.jetbrains.python.psi.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.List; + /** * User: catherine * Intention to merge the if clauses in the case of nested ifs where only the inner if contains code (the outer if only contains the inner one) @@ -62,11 +66,21 @@ public class PyJoinIfIntention extends BaseIntentionAction { if (firstStatement != null && firstStatement instanceof PyIfStatement) { PyExpression condition = ((PyIfStatement)firstStatement).getIfPart().getCondition(); PyElementGenerator elementGenerator = PyElementGenerator.getInstance(project); - PyExpression newCondition = elementGenerator.createExpressionFromText(ifStatement.getIfPart().getCondition().getText() + " and " + condition.getText()); + PyExpression newCondition = elementGenerator.createExpressionFromText( + ifStatement.getIfPart().getCondition().getText() + " and " + condition.getText()); ifStatement.getIfPart().getCondition().replace(newCondition); PyStatementList stList = ((PyIfStatement)firstStatement).getIfPart().getStatementList(); PyStatementList ifStatementList = ifStatement.getIfPart().getStatementList(); + + List comments = PsiTreeUtil.getChildrenOfTypeAsList(ifStatement.getIfPart(), PsiComment.class); + comments.addAll(PsiTreeUtil.getChildrenOfTypeAsList(((PyIfStatement)firstStatement).getIfPart(), PsiComment.class)); + + for (PsiElement comm : comments) { + ifStatement.getIfPart().addBefore(comm, ifStatementList); + comm.delete(); + } + ifStatementList.replace(stList); } } From 78595686fd03ba696555f040de630b4716fdde02 Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Thu, 16 Dec 2010 19:53:24 +0300 Subject: [PATCH 5/7] fixed sorting of children in variable view (PY-2471) --- python/helpers/pydev/pydevd_comm.py | 9 ++++- python/helpers/pydev/pydevd_utils.py | 58 ++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 python/helpers/pydev/pydevd_utils.py diff --git a/python/helpers/pydev/pydevd_comm.py b/python/helpers/pydev/pydevd_comm.py index f610025f0ed4..ad13efb961e8 100644 --- a/python/helpers/pydev/pydevd_comm.py +++ b/python/helpers/pydev/pydevd_comm.py @@ -77,6 +77,7 @@ import pydevd_tracing import pydevd_vm_type import pydevd_file_utils import traceback +from pydevd_utils import * from pydevd_tracing import GetExceptionTracebackStr @@ -615,9 +616,13 @@ class InternalGetVariable(InternalThreadCommand): valDict = pydevd_vars.resolveCompoundVariable(self.thread_id, self.frame_id, self.scope, self.attributes) keys = valDict.keys() if hasattr(keys, 'sort'): - keys.sort() #Python 3.0 does not have it + keys.sort(compare_object_attrs) #Python 3.0 does not have it else: - keys = sorted(keys, key=str) #Jython 2.1 does not have it (and all must be compared as strings). + if (IS_PY3K): + keys = sorted(keys, key=cmp_to_key(compare_object_attrs)) #Jython 2.1 does not have it (and all must be compared as strings). + else: + keys = sorted(keys, cmp=compare_object_attrs) #Jython 2.1 does not have it (and all must be compared as strings). + for k in keys: xml += pydevd_vars.varToXML(valDict[k], str(k)) diff --git a/python/helpers/pydev/pydevd_utils.py b/python/helpers/pydev/pydevd_utils.py new file mode 100644 index 000000000000..58d6ccb7f41b --- /dev/null +++ b/python/helpers/pydev/pydevd_utils.py @@ -0,0 +1,58 @@ +from numbers import * + +def to_number(x): + if isinstance(x, Number): + return x + if (isinstance(x, basestring)): + try: + n = float(x) + return n + except ValueError: + pass + + l = x.find('(') + if (l != -1): + y = x[0:l-1] + #print y + try: + n = float(y) + return n + except ValueError: + pass + return None + +def compare_object_attrs(x, y): + try: + x_num = to_number(x) + y_num = to_number(y) + if (x_num is not None and y_num is not None): + return int(x_num - y_num) + if ('__len__' == x): + return -1 + if ('__len__' == y): + return 1 + + return x.__cmp__(y) + except: + return cmp(str(x), str(y)) + + +def cmp_to_key(mycmp): + 'Convert a cmp= function into a key= function' + class K(object): + def __init__(self, obj, *args): + self.obj = obj + def __lt__(self, other): + return mycmp(self.obj, other.obj) < 0 + def __gt__(self, other): + return mycmp(self.obj, other.obj) > 0 + def __eq__(self, other): + return mycmp(self.obj, other.obj) == 0 + def __le__(self, other): + return mycmp(self.obj, other.obj) <= 0 + def __ge__(self, other): + return mycmp(self.obj, other.obj) >= 0 + def __ne__(self, other): + return mycmp(self.obj, other.obj) != 0 + return K + From f6236ffc9144ac388cbcc776a6fd0a45876a2576 Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Thu, 16 Dec 2010 22:21:53 +0300 Subject: [PATCH 6/7] added diagnostic of debugger version (PY-2526) --- python/build/pycharm_build.gant | 6 +++++- python/helpers/pydev/pydevd_comm.py | 2 +- python/helpers/pydev/pydevd_utils.py | 1 - .../python/debugger/PyDebugProcess.java | 20 ++++++++++++++----- 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/python/build/pycharm_build.gant b/python/build/pycharm_build.gant index 255179da8936..e77be8740432 100644 --- a/python/build/pycharm_build.gant +++ b/python/build/pycharm_build.gant @@ -130,7 +130,11 @@ def buildDebuggerEgg(paths, buildName) { fileset(dir: "$home/python/resources/debugger-egg/EGG-INFO") } - ant.replace(file: "$eggDir/EGG-INFO/PKG-INFO") { + ant.replace(file: "$eggDir/pydev/PKG-INFO") { + replacefilter(token: "@@BUILD_NUMBER@@", value: buildName) + } + + ant.replace(file: "$eggDir/pydev/pydevd_comm.py") { replacefilter(token: "@@BUILD_NUMBER@@", value: buildName) } ant.zip(destfile: egg) { diff --git a/python/helpers/pydev/pydevd_comm.py b/python/helpers/pydev/pydevd_comm.py index ad13efb961e8..ee0bd8ab796c 100644 --- a/python/helpers/pydev/pydevd_comm.py +++ b/python/helpers/pydev/pydevd_comm.py @@ -142,7 +142,7 @@ ID_TO_MEANING = { MAX_IO_MSG_SIZE = 1000 #if the io is too big, we'll not send all (could make the debugger too non-responsive) #this number can be changed if there's need to do so -VERSION_STRING = "PYCHARM-1.1" +VERSION_STRING = "@@BUILD_NUMBER@@" #--------------------------------------------------------------------------------------------------- UTILITIES diff --git a/python/helpers/pydev/pydevd_utils.py b/python/helpers/pydev/pydevd_utils.py index 58d6ccb7f41b..2993387a570b 100644 --- a/python/helpers/pydev/pydevd_utils.py +++ b/python/helpers/pydev/pydevd_utils.py @@ -36,7 +36,6 @@ def compare_object_attrs(x, y): except: return cmp(str(x), str(y)) - def cmp_to_key(mycmp): 'Convert a cmp= function into a key= function' class K(object): diff --git a/python/src/com/jetbrains/python/debugger/PyDebugProcess.java b/python/src/com/jetbrains/python/debugger/PyDebugProcess.java index c11629eb4d35..9fd96ae4d61e 100644 --- a/python/src/com/jetbrains/python/debugger/PyDebugProcess.java +++ b/python/src/com/jetbrains/python/debugger/PyDebugProcess.java @@ -8,6 +8,7 @@ import com.intellij.execution.process.ProcessListener; import com.intellij.execution.ui.ConsoleView; import com.intellij.execution.ui.ConsoleViewContentType; import com.intellij.execution.ui.ExecutionConsole; +import com.intellij.openapi.application.ApplicationInfo; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.Task; @@ -143,8 +144,16 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr } private void handshake() throws PyDebuggerException { - final String remoteVersion = myDebugger.handshake(); - printToConsole("Connected to pydevd (version " + remoteVersion + ")\n", ConsoleViewContentType.SYSTEM_OUTPUT); + String remoteVersion = myDebugger.handshake(); + String currentBuild = ApplicationInfo.getInstance().getBuild().asStringWithoutProductCode(); + if ("@@BUILD_NUMBER@@".equals(remoteVersion)) { + remoteVersion = currentBuild; + } + printToConsole("Connected to pydev debugger (build " + remoteVersion + ")\n", ConsoleViewContentType.SYSTEM_OUTPUT); + + if (!remoteVersion.equals(currentBuild)) { + printToConsole("Warning: wrong debugger version. Use pycharm-debugger.egg from PyCharm installation folder.", ConsoleViewContentType.ERROR_OUTPUT); + } } public void printToConsole(String text, ConsoleViewContentType contentType) { @@ -432,10 +441,11 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr public String getCurrentStateMessage() { if (getSession().isStopped()) { return XDebuggerBundle.message("debugger.state.message.disconnected"); - } else - if (myDebugger.isConnected()) { + } + else if (myDebugger.isConnected()) { return XDebuggerBundle.message("debugger.state.message.connected"); - } else { + } + else { return "Waiting for connection..."; } } From cd1889b6ba5f29de514b62ac6ad040fec6c33479 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Fri, 17 Dec 2010 11:39:29 +0300 Subject: [PATCH 7/7] fixed PY-2518 Join 2 ifs: merge comments if both presented --- .../intentions/PyConvertLambdaToFunctionIntention.java | 2 -- .../python/codeInsight/intentions/PyJoinIfIntention.java | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/PyConvertLambdaToFunctionIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/PyConvertLambdaToFunctionIntention.java index 921b09624481..2797a11f39fe 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/PyConvertLambdaToFunctionIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/PyConvertLambdaToFunctionIntention.java @@ -59,8 +59,6 @@ public class PyConvertLambdaToFunctionIntention extends BaseIntentionAction { functionBuilder.statement("return " + body.getText()); PyFunction function = functionBuilder.buildFunction(project); - - PyFunction parentFunction = PsiTreeUtil.getTopmostParentOfType(lambdaExpression, PyFunction.class); if (parentFunction != null ) { PyClass parentClass = PsiTreeUtil.getTopmostParentOfType(parentFunction, PyClass.class); diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/PyJoinIfIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/PyJoinIfIntention.java index 42636f1f993f..0bf11d123288 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/PyJoinIfIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/PyJoinIfIntention.java @@ -75,12 +75,13 @@ public class PyJoinIfIntention extends BaseIntentionAction { List comments = PsiTreeUtil.getChildrenOfTypeAsList(ifStatement.getIfPart(), PsiComment.class); comments.addAll(PsiTreeUtil.getChildrenOfTypeAsList(((PyIfStatement)firstStatement).getIfPart(), PsiComment.class)); + comments.addAll(PsiTreeUtil.getChildrenOfTypeAsList(ifStatementList, PsiComment.class)); + comments.addAll(PsiTreeUtil.getChildrenOfTypeAsList(stList, PsiComment.class)); for (PsiElement comm : comments) { ifStatement.getIfPart().addBefore(comm, ifStatementList); comm.delete(); } - ifStatementList.replace(stList); } }