diff --git a/python/helpers/pydev/pydevd.py b/python/helpers/pydev/pydevd.py index 4385a4db9248..af4272e6444c 100644 --- a/python/helpers/pydev/pydevd.py +++ b/python/helpers/pydev/pydevd.py @@ -346,6 +346,7 @@ class PyDB: self.processThreadNotAlive(tId) except: sys.stderr.write('Error iterating through %s (%s) - %s\n' % (foundThreads, foundThreads.__class__, dir(foundThreads))) + sys.stderr.flush() raise finally: @@ -457,9 +458,11 @@ class PyDB: if not DictContains(sys.modules, module_name): sys.stderr.write('pydev debugger: Unable to find module to reload: "'+module_name+'".\n') sys.stderr.write('pydev debugger: This usually means you are trying to reload the __main__ module (which cannot be reloaded).\n') + sys.stderr.flush() else: sys.stderr.write('pydev debugger: Reloading: '+module_name+'\n') + sys.stderr.flush() xreload(sys.modules[module_name]) @@ -536,11 +539,13 @@ class PyDB: if not os.path.exists(file): sys.stderr.write('pydev debugger: warning: trying to add breakpoint'\ ' to file that does not exist: %s (will have no effect)\n' % (file,)) + sys.stderr.flush() line = int(line) if DEBUG_TRACE_BREAKPOINTS > 0: sys.stderr.write('Added breakpoint:%s - line:%s - func_name:%s\n' % (file, line, func_name)) + sys.stderr.flush() if DictContains(self.breakpoints, file): breakDict = self.breakpoints[file] @@ -575,11 +580,13 @@ class PyDB: del self.breakpoints[file][line] #remove the breakpoint in that line if DEBUG_TRACE_BREAKPOINTS > 0: sys.stderr.write('Removed breakpoint:%s\n' % (file,)) + sys.stderr.flush() except KeyError: #ok, it's not there... if DEBUG_TRACE_BREAKPOINTS > 0: #Sometimes, when adding a breakpoint, it adds a remove command before (don't really know why) sys.stderr.write("breakpoint not found: %s - %s\n" % (file, line)) + sys.stderr.flush() elif cmd_id == CMD_EVALUATE_EXPRESSION or cmd_id == CMD_EXEC_EXPRESSION: #command to evaluate the given expression @@ -823,8 +830,9 @@ class PyDB: if hasattr(sys, 'exc_clear'): #jython does not have it sys.exc_clear() #don't keep the traceback (let's keep it clear for when we go to the point of executing client code) - if not sys.platform.startswith("java") and not sys.platform.startswith("cli"): + if not IS_PY3K and not sys.platform.startswith("java") and not sys.platform.startswith("cli"): sys.stderr.write("pydev debugger: warning: psyco not available for speedups (the debugger will still work correctly, but a bit slower)\n") + sys.stderr.flush() def run(self, file, globals=None, locals=None): @@ -1087,6 +1095,7 @@ def settrace(host='localhost', stdoutToServer=False, stderrToServer=False, port= if __name__ == '__main__': sys.stderr.write("pydev debugger: starting\n") + sys.stderr.flush() # parse the command line. --file is our last argument that is required try: setup = processCommandLine(sys.argv) diff --git a/python/helpers/pydev/pydevd_breakpoints.py b/python/helpers/pydev/pydevd_breakpoints.py index 2dbc3c187340..8d53edfa7155 100644 --- a/python/helpers/pydev/pydevd_breakpoints.py +++ b/python/helpers/pydev/pydevd_breakpoints.py @@ -1,3 +1,4 @@ +from pydevd_constants import * import sys _original_excepthook = None @@ -110,7 +111,10 @@ def get_class( kls ): parts = kls.split('.') module = ".".join(parts[:-1]) if (module == ""): - module = "__builtin__" + if IS_PY3K: + module = "builtins" + else: + module = "__builtin__" m = __import__( module ) for comp in parts[-1:]: m = getattr(m, comp) diff --git a/python/helpers/pydev/pydevd_comm.py b/python/helpers/pydev/pydevd_comm.py index 2a4ced0e657d..2ed09dd022c4 100644 --- a/python/helpers/pydev/pydevd_comm.py +++ b/python/helpers/pydev/pydevd_comm.py @@ -349,6 +349,7 @@ def StartClient(host, port): return s except: sys.stderr.write("Could not connect to %s: %s\n" % (host, port)) + sys.stderr.flush() traceback.print_exc() sys.exit(1) @@ -408,7 +409,7 @@ class NetCommandFactory: cmd = NetCommand(CMD_ERROR, seq, text) if DEBUG_TRACE_LEVEL > 2: sys.stderr.write("Error: %s" % (text,)) - return cmd; + return cmd def makeThreadCreatedMessage(self, thread): cmdText = "" + self.threadToXML(thread) + "" @@ -728,6 +729,9 @@ class InternalConsoleExec(InternalThreadCommand): sys.stderr.write('%s\n' % (exc,)) cmd = dbg.cmdFactory.makeErrorMessage(self.sequence, "Error evaluating console expression " + exc) dbg.writer.addCommand(cmd) + finally: + sys.stderr.flush() + sys.stdout.flush() #======================================================================================================================= # InternalGetCompletions @@ -806,6 +810,7 @@ def PydevdFindThreadById(thread_id): sys.stderr.write("Could not find thread %s\n" % thread_id) sys.stderr.write("Available: %s\n" % [GetThreadId(t) for t in threads]) + sys.stderr.flush() except: traceback.print_exc() diff --git a/python/helpers/pydev/pydevd_file_utils.py b/python/helpers/pydev/pydevd_file_utils.py index bee4c18b7b7f..ab5357ce38a9 100644 --- a/python/helpers/pydev/pydevd_file_utils.py +++ b/python/helpers/pydev/pydevd_file_utils.py @@ -100,6 +100,7 @@ try: sys.stderr.write('pydev debugger: The debugger may still function, but it will work slower and may miss breakpoints.\n') sys.stderr.write('pydev debugger: Related bug: http://bugs.python.org/issue1666807\n') sys.stderr.write('-------------------------------------------------------------------------------\n') + sys.stderr.flush() NORM_SEARCH_CACHE = {} diff --git a/python/helpers/pydev/pydevd_frame.py b/python/helpers/pydev/pydevd_frame.py index e258499e59e6..71545f965c3d 100644 --- a/python/helpers/pydev/pydevd_frame.py +++ b/python/helpers/pydev/pydevd_frame.py @@ -109,6 +109,7 @@ class PyDBFrame: except: sys.stderr.write('Error while evaluating expression\n') traceback.print_exc() + sys.stderr.flush() return self.trace_dispatch expression = breakpoint[line][3] diff --git a/python/helpers/pydev/pydevd_tracing.py b/python/helpers/pydev/pydevd_tracing.py index 202854a599f4..c49c17ee298a 100644 --- a/python/helpers/pydev/pydevd_tracing.py +++ b/python/helpers/pydev/pydevd_tracing.py @@ -58,6 +58,7 @@ def _InternalSetTrace(tracing_func): #only warn about each message once... TracingFunctionHolder._warnings_shown[message] = 1 sys.stderr.write('%s\n' % (message,)) + sys.stderr.flush() TracingFunctionHolder._original_tracing(tracing_func) diff --git a/python/helpers/pydev/pydevd_vars.py b/python/helpers/pydev/pydevd_vars.py index f415372c8ff8..b454fe610607 100644 --- a/python/helpers/pydev/pydevd_vars.py +++ b/python/helpers/pydev/pydevd_vars.py @@ -227,6 +227,7 @@ def frameVarsToXML(frame): except Exception: traceback.print_exc() sys.stderr.write("Unexpected error, recovered safely.\n") + sys.stderr.flush() return xml def iterFrames(initialFrame): diff --git a/python/pydevSrc/com/jetbrains/python/debugger/PyDebugValue.java b/python/pydevSrc/com/jetbrains/python/debugger/PyDebugValue.java index ff5bdc1bc39e..1fa24d8bbf92 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/PyDebugValue.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/PyDebugValue.java @@ -86,7 +86,7 @@ public class PyDebugValue extends XValue { result.append('[').append(removeId(myName)).append(']'); } else if (("set".equals(myParent.getType())) && !isLen(myName)) { - result.append("[").append(myName).append("]"); + //set doesn't support indexing } else if (isLen(myName)) { result.append('.').append(myName).append("()"); diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractFrameCommand.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractFrameCommand.java index dc8695618fc1..28563a60d0fc 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractFrameCommand.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractFrameCommand.java @@ -3,7 +3,7 @@ package com.jetbrains.python.debugger.pydev; public abstract class AbstractFrameCommand extends AbstractThreadCommand { - protected final String myFrameId; + private final String myFrameId; protected AbstractFrameCommand(final RemoteDebugger debugger, final int commandCode, final String threadId, final String frameId) { super(debugger, commandCode, threadId); diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractThreadCommand.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractThreadCommand.java index 5c85b07be8ef..5598941a69cf 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractThreadCommand.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractThreadCommand.java @@ -2,7 +2,7 @@ package com.jetbrains.python.debugger.pydev; public abstract class AbstractThreadCommand extends AbstractCommand { - protected final String myThreadId; + private final String myThreadId; protected AbstractThreadCommand(final RemoteDebugger debugger, final int commandCode, final String threadId) { super(debugger, commandCode); @@ -21,4 +21,8 @@ public abstract class AbstractThreadCommand extends AbstractCommand { command == SUSPEND_THREAD; } + public String getThreadId() { + return myThreadId; + } + } diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/ConsoleExecCommand.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/ConsoleExecCommand.java index a3f599f65983..bbd0540d5c1a 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/ConsoleExecCommand.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/ConsoleExecCommand.java @@ -16,7 +16,7 @@ public class ConsoleExecCommand extends AbstractFrameCommand { @Override protected void buildPayload(Payload payload) { super.buildPayload(payload); - payload.add(myThreadId).add(myFrameId).add("FRAME").add(myExpression); + payload.add("FRAME").add(myExpression); } @Override diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/ResumeCommand.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/ResumeCommand.java index a3e407128da8..8712d676b5d7 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/ResumeCommand.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/ResumeCommand.java @@ -16,8 +16,4 @@ public class ResumeCommand extends AbstractThreadCommand { public ResumeCommand(final RemoteDebugger debugger, final String threadId, final Mode mode) { super(debugger, mode.code, threadId); } - - public String getThreadId() { - return myThreadId; - } } diff --git a/python/src/META-INF/python-plugin-common.xml b/python/src/META-INF/python-plugin-common.xml index 1b02cfd7d813..ff3dc3ae8d56 100644 --- a/python/src/META-INF/python-plugin-common.xml +++ b/python/src/META-INF/python-plugin-common.xml @@ -148,6 +148,11 @@ Python + + com.jetbrains.python.codeInsight.intentions.PyConvertLambdaToFunctionIntention + Python + + @@ -306,7 +311,7 @@ - + diff --git a/python/src/com/jetbrains/python/PyBundle.properties b/python/src/com/jetbrains/python/PyBundle.properties index f7d2a8834a2f..726f495e2c08 100644 --- a/python/src/com/jetbrains/python/PyBundle.properties +++ b/python/src/com/jetbrains/python/PyBundle.properties @@ -59,6 +59,12 @@ QFIX.statement.effect.introduce.variable=Introduce variable QFIX.unresolved.reference=Reference can be resolved added self +QFIX.unresolved.reference.create.function=Create function for reference + +QFIX.introduce.variable=Introduce variable for statement + +QFIX.unresolved.reference.add.future=Add 'from __future__ import with_statement'' + # Intentions: INTN INTN.Family.convert.import.unqualify=Convert 'import module' to 'from module import' INTN.Family.convert.import.qualify=Convert 'from module import' to 'import module' @@ -130,7 +136,9 @@ INTN.convert.dict.literal.to.dict.constructor=Convert dict literal to dict const INTN.quoted.string=Convert between single-quoted and double-quoted strings INTN.quoted.string.single.to.double=Convert single-quoted string to double-quoted string -INTN.quoted.string.double.to.single=Convert double-quoted string to sungle-quoted string +INTN.quoted.string.double.to.single=Convert double-quoted string to single-quoted string + +INTN.convert.lambda.to.function=Convert lambda to function # Conflict checker CONFLICT.name.$0.obscured=Name ''{0}'' obscured by local definitions diff --git a/python/src/com/jetbrains/python/actions/StatementEffectQuickFix.java b/python/src/com/jetbrains/python/actions/StatementEffectFunctionCallQuickFix.java similarity index 91% rename from python/src/com/jetbrains/python/actions/StatementEffectQuickFix.java rename to python/src/com/jetbrains/python/actions/StatementEffectFunctionCallQuickFix.java index 805c89d9d26a..094a22551ff8 100644 --- a/python/src/com/jetbrains/python/actions/StatementEffectQuickFix.java +++ b/python/src/com/jetbrains/python/actions/StatementEffectFunctionCallQuickFix.java @@ -17,9 +17,9 @@ import org.jetbrains.annotations.NotNull; * * QuickFix to replace statement that has no effect with function call */ -public class StatementEffectQuickFix implements LocalQuickFix { +public class StatementEffectFunctionCallQuickFix implements LocalQuickFix { - public StatementEffectQuickFix() { + public StatementEffectFunctionCallQuickFix() { } @NotNull diff --git a/python/src/com/jetbrains/python/actions/StatementEffectIntroduceVariableQuickFix.java b/python/src/com/jetbrains/python/actions/StatementEffectIntroduceVariableQuickFix.java new file mode 100644 index 000000000000..dd1a215ecab7 --- /dev/null +++ b/python/src/com/jetbrains/python/actions/StatementEffectIntroduceVariableQuickFix.java @@ -0,0 +1,52 @@ +package com.jetbrains.python.actions; + +import com.intellij.codeInspection.LocalQuickFix; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.application.Application; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.Messages; +import com.intellij.psi.PsiElement; +import com.jetbrains.python.PyBundle; +import com.jetbrains.python.psi.*; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +/** + * User: catherine + * + * Quickfix to introduce variable if statement seems to have no effect + */ +public class StatementEffectIntroduceVariableQuickFix implements LocalQuickFix { + PyExpression myExpression; + public StatementEffectIntroduceVariableQuickFix(PyExpression expression) { + myExpression = expression; + } + + @NotNull + public String getName() { + return PyBundle.message("QFIX.introduce.variable"); + } + + @NonNls + @NotNull + public String getFamilyName() { + return PyBundle.message("INSP.GROUP.python"); + } + + public void applyFix(@NotNull final Project project, @NotNull final ProblemDescriptor descriptor) { + String name = "var"; + if (myExpression != null) { + Application application = ApplicationManager.getApplication(); + if (application != null && !application.isUnitTestMode()) { + name = Messages.showInputDialog(project, "Enter new variable name", + "New variable name", Messages.getQuestionIcon()); + if (name == null) return; + } + if (name.isEmpty()) return; + PyElementGenerator elementGenerator = PyElementGenerator.getInstance(project); + myExpression.replace(elementGenerator.createFromText(LanguageLevel.forElement(myExpression), PyAssignmentStatement.class, + name + " = " + myExpression.getText())); + } + } +} diff --git a/python/src/com/jetbrains/python/actions/UnresolvedRefAddFutureImportQuickFix.java b/python/src/com/jetbrains/python/actions/UnresolvedRefAddFutureImportQuickFix.java new file mode 100644 index 000000000000..0c2a3f4752b2 --- /dev/null +++ b/python/src/com/jetbrains/python/actions/UnresolvedRefAddFutureImportQuickFix.java @@ -0,0 +1,40 @@ +package com.jetbrains.python.actions; + +import com.intellij.codeInsight.CodeInsightUtilBase; +import com.intellij.codeInspection.LocalQuickFix; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.jetbrains.python.PyBundle; +import com.jetbrains.python.psi.*; +import org.jetbrains.annotations.NotNull; + +/** + * User: catherine + * + * QuickFix to add 'from __future__ import with_statement'' if python version is less than 2.6 + */ +public class UnresolvedRefAddFutureImportQuickFix implements LocalQuickFix { + private PyReferenceExpression myElement; + public UnresolvedRefAddFutureImportQuickFix(PyReferenceExpression element) { + myElement = element; + } + + @NotNull + public String getName() { + return PyBundle.message("QFIX.unresolved.reference.add.future"); + } + + @NotNull + public String getFamilyName() { + return PyBundle.message("INSP.GROUP.python"); + } + + public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { + PyFile file = (PyFile)myElement.getContainingFile(); + if (!CodeInsightUtilBase.prepareFileForWrite(file)) return; + PyElementGenerator elementGenerator = PyElementGenerator.getInstance(project); + PyFromImportStatement statement = elementGenerator.createFromText(LanguageLevel.forElement(myElement), PyFromImportStatement.class, + "from __future__ import with_statement"); + file.addBefore(statement, file.getStatements().get(0)); + } +} diff --git a/python/src/com/jetbrains/python/actions/UnresolvedRefCreateFunctionQuickFix.java b/python/src/com/jetbrains/python/actions/UnresolvedRefCreateFunctionQuickFix.java new file mode 100644 index 000000000000..abadc1945150 --- /dev/null +++ b/python/src/com/jetbrains/python/actions/UnresolvedRefCreateFunctionQuickFix.java @@ -0,0 +1,48 @@ +package com.jetbrains.python.actions; + +import com.intellij.codeInsight.CodeInsightUtilBase; +import com.intellij.codeInspection.LocalQuickFix; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import com.intellij.psi.util.PsiTreeUtil; +import com.jetbrains.python.PyBundle; +import com.jetbrains.python.psi.*; +import org.jetbrains.annotations.NotNull; + +/** + * User: catherine + * + * QuickFix to create function to unresolved unqualified reference + */ +public class UnresolvedRefCreateFunctionQuickFix implements LocalQuickFix { + private PyReferenceExpression myElement; + + public UnresolvedRefCreateFunctionQuickFix(PyReferenceExpression element) { + myElement = element; + } + + @NotNull + public String getName() { + return PyBundle.message("QFIX.unresolved.reference.create.function"); + } + + @NotNull + public String getFamilyName() { + return PyBundle.message("INSP.GROUP.python"); + } + + public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { + if (!CodeInsightUtilBase.preparePsiElementForWrite(myElement)) return; + PyElementGenerator elementGenerator = PyElementGenerator.getInstance(project); + PyFunction function = elementGenerator.createFromText(LanguageLevel.forElement(myElement), PyFunction.class, + "def " + myElement.getText() + "():\n pass"); + + PyStatement statement = PsiTreeUtil.getParentOfType(myElement, PyStatement.class); + if (statement != null) { + PsiElement parent = statement.getParent(); + if (parent != null) + parent.addBefore(function, statement); + } + } +} diff --git a/python/src/com/jetbrains/python/actions/UnresolvedReferenceAddSelfQuickFix.java b/python/src/com/jetbrains/python/actions/UnresolvedReferenceAddSelfQuickFix.java index daa91a227bc1..521bd804688e 100644 --- a/python/src/com/jetbrains/python/actions/UnresolvedReferenceAddSelfQuickFix.java +++ b/python/src/com/jetbrains/python/actions/UnresolvedReferenceAddSelfQuickFix.java @@ -12,7 +12,7 @@ import org.jetbrains.annotations.NotNull; /** * User: catherine * - * QuickFix to remove redundant parentheses from if/while/except statement + * QuickFix to add self to unresolved reference */ public class UnresolvedReferenceAddSelfQuickFix implements LocalQuickFix { private PyReferenceExpression myElement; @@ -33,9 +33,8 @@ public class UnresolvedReferenceAddSelfQuickFix implements LocalQuickFix { public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { if (!CodeInsightUtilBase.preparePsiElementForWrite(myElement)) return; - PyReferenceExpression ref = myElement; PyElementGenerator elementGenerator = PyElementGenerator.getInstance(project); - PyExpression expression = elementGenerator.createExpressionFromText("self." + ref.getText()); + PyExpression expression = elementGenerator.createExpressionFromText("self." + myElement.getText()); myElement.replace(expression); } } diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/PyConvertLambdaToFunctionIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/PyConvertLambdaToFunctionIntention.java new file mode 100644 index 000000000000..0a47186f99d5 --- /dev/null +++ b/python/src/com/jetbrains/python/codeInsight/intentions/PyConvertLambdaToFunctionIntention.java @@ -0,0 +1,95 @@ +package com.jetbrains.python.codeInsight.intentions; + +import com.intellij.codeInsight.intention.impl.BaseIntentionAction; +import com.intellij.ide.IdeBundle; +import com.intellij.openapi.application.Application; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.Messages; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.IncorrectOperationException; +import com.jetbrains.python.PyBundle; +import com.jetbrains.python.psi.*; +import org.jetbrains.annotations.NotNull; + +/** + * User: catherine + * Intention to convert lambda to function + */ +public class PyConvertLambdaToFunctionIntention extends BaseIntentionAction { + + @NotNull + public String getFamilyName() { + return PyBundle.message("INTN.convert.lambda.to.function"); + } + + @NotNull + public String getText() { + return PyBundle.message("INTN.convert.lambda.to.function"); + } + + public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { + PyLambdaExpression lambdaExpression = PsiTreeUtil.getParentOfType(file.findElementAt(editor.getCaretModel().getOffset()), PyLambdaExpression.class); + if (lambdaExpression != null) { + if (lambdaExpression.getBody() != null) + return true; + } + return false; + } + + public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { + PyLambdaExpression lambdaExpression = PsiTreeUtil.getParentOfType(file.findElementAt(editor.getCaretModel().getOffset()), PyLambdaExpression.class); + PyElementGenerator elementGenerator = PyElementGenerator.getInstance(project); + if (lambdaExpression != null) { + String name = "function"; + PsiElement parent = lambdaExpression.getParent(); + if (parent instanceof PyAssignmentStatement) { + name = ((PyAssignmentStatement)parent).getLeftHandSideExpression().getText(); + } + else { + Application application = ApplicationManager.getApplication(); + if (application != null && !application.isUnitTestMode()) { + name = Messages.showInputDialog(project, "Enter new function name", + "New function name", Messages.getQuestionIcon()); + if (name == null) return; + } + } + if (name.isEmpty()) return; + PyExpression body = lambdaExpression.getBody(); + PyParameter[] parameters = lambdaExpression.getParameterList().getParameters(); + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("def "); + stringBuilder.append(name); + stringBuilder.append("("); + int size = parameters.length; + for (int i = 0; i != size; ++i) { + PyParameter parameter = parameters[i]; + stringBuilder.append(parameter.getName()); + if ( i != size - 1) + stringBuilder.append(","); + } + stringBuilder.append("):\n return "); + stringBuilder.append(body.getText()); + + PyFunction function = elementGenerator.createFromText(LanguageLevel.forElement(lambdaExpression), + PyFunction.class, stringBuilder.toString()); + + PyStatement statement = PsiTreeUtil.getParentOfType(lambdaExpression, PyStatement.class); + if (statement != null) { + PsiElement parentOfStatement = statement.getParent(); + if (parentOfStatement != null) + parentOfStatement.addBefore(function, statement); + } + if (parent instanceof PyAssignmentStatement) { + parent.delete(); + } + else { + lambdaExpression.replace(elementGenerator.createFromText(LanguageLevel.forElement(lambdaExpression), PyExpression.class, + name)); + } + } + } +} diff --git a/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java b/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java index 6c4f634185fe..c6bc44206920 100644 --- a/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java @@ -2,12 +2,12 @@ package com.jetbrains.python.inspections; import com.intellij.codeInspection.LocalInspectionToolSession; import com.intellij.codeInspection.ProblemsHolder; -import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElementVisitor; import com.intellij.psi.ResolveResult; import com.intellij.psi.util.PsiTreeUtil; import com.jetbrains.python.PyBundle; -import com.jetbrains.python.actions.StatementEffectQuickFix; +import com.jetbrains.python.actions.StatementEffectFunctionCallQuickFix; +import com.jetbrains.python.actions.StatementEffectIntroduceVariableQuickFix; import com.jetbrains.python.console.PydevConsoleRunner; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.resolve.PyResolveContext; @@ -16,8 +16,6 @@ import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.sql.Statement; - /** * @author Alexey.Ivanov */ @@ -64,7 +62,7 @@ public class PyStatementEffectInspection extends PyInspection { return; } } - registerProblem(expression, "Statement seems to have no effect"); + registerProblem(expression, "Statement seems to have no effect", new StatementEffectIntroduceVariableQuickFix(expression)); } private boolean hasEffect(@Nullable PyExpression expression) { @@ -125,7 +123,7 @@ public class PyStatementEffectInspection extends PyInspection { ResolveResult[] results = referenceExpression.getReference().multiResolve(true); for (ResolveResult res : results) { if (res.getElement() instanceof PyFunction) { - registerProblem(expression, "Statement seems to have no effect and can be replaced with function call to have effect", new StatementEffectQuickFix()); + registerProblem(expression, "Statement seems to have no effect and can be replaced with function call to have effect", new StatementEffectFunctionCallQuickFix()); return true; } } diff --git a/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java b/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java index c8bba4b57b14..ae8a6a7ef657 100644 --- a/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java @@ -133,7 +133,7 @@ public class PyUnresolvedReferencesInspection extends PyInspection { super.visitPyStarImportElement(node); myAllImports.add(node); } - + @Override public void visitPyElement(final PyElement node) { super.visitPyElement(node); @@ -191,6 +191,11 @@ public class PyUnresolvedReferencesInspection extends PyInspection { } else { + if (LanguageLevel.forElement(node).isOlderThan(LanguageLevel.PYTHON26)) { + if (refname.equals("with")) { + actions.add(new UnresolvedRefAddFutureImportQuickFix(refex)); + } + } PyClass containedClass = PsiTreeUtil.getParentOfType(node, PyClass.class); if (containedClass != null) { for (PyTargetExpression target : containedClass.getInstanceAttributes()) { @@ -199,6 +204,7 @@ public class PyUnresolvedReferencesInspection extends PyInspection { } } } + actions.add(new UnresolvedRefCreateFunctionQuickFix(refex)); } // unqualified: // may be module's diff --git a/python/src/com/jetbrains/python/sdk/PythonSdkType.java b/python/src/com/jetbrains/python/sdk/PythonSdkType.java index d1374fe7fc25..25d558abab00 100644 --- a/python/src/com/jetbrains/python/sdk/PythonSdkType.java +++ b/python/src/com/jetbrains/python/sdk/PythonSdkType.java @@ -373,7 +373,7 @@ public class PythonSdkType extends SdkType { public static VirtualFile findSkeletonsDir(Sdk sdk) { final VirtualFile[] virtualFiles = sdk.getRootProvider().getFiles(BUILTIN_ROOT_TYPE); for (VirtualFile virtualFile : virtualFiles) { - if (virtualFile.getPath().contains(SKELETON_DIR_NAME)) { + if (virtualFile.isValid() && virtualFile.getPath().contains(SKELETON_DIR_NAME)) { return virtualFile; } } diff --git a/python/src/com/jetbrains/python/testing/doctest/PythonDocTestConfigurationProducer.java b/python/src/com/jetbrains/python/testing/doctest/PythonDocTestConfigurationProducer.java index 7f46db5bb7c9..5e92e29df616 100644 --- a/python/src/com/jetbrains/python/testing/doctest/PythonDocTestConfigurationProducer.java +++ b/python/src/com/jetbrains/python/testing/doctest/PythonDocTestConfigurationProducer.java @@ -156,13 +156,11 @@ public class PythonDocTestConfigurationProducer extends RuntimeConfigurationProd @Nullable private RunnerAndConfigurationSettings createConfigurationFromFile(Location location, PsiElement element) { PsiElement file = element.getContainingFile(); - if (file == null) return null; + if (file == null || !(file instanceof PyFile)) return null; - if (file instanceof PyFile) { - final PyFile pyFile = (PyFile)file; - final List testCases = PythonDocTestUtil.getDocTestCasesFromFile(pyFile); - if (testCases.isEmpty()) return null; - } + final PyFile pyFile = (PyFile)file; + final List testCases = PythonDocTestUtil.getDocTestCasesFromFile(pyFile); + if (testCases.isEmpty()) return null; final RunnerAndConfigurationSettings settings = makeConfigurationSettings(location, "doc tests from file"); final PythonDocTestRunConfiguration configuration = (PythonDocTestRunConfiguration)settings.getConfiguration(); diff --git a/python/testData/inspections/StatementEffectIntroduceVariable.py b/python/testData/inspections/StatementEffectIntroduceVariable.py new file mode 100644 index 000000000000..107d3e6a49ce --- /dev/null +++ b/python/testData/inspections/StatementEffectIntroduceVariable.py @@ -0,0 +1 @@ +a+ b \ No newline at end of file diff --git a/python/testData/inspections/StatementEffectIntroduceVariable_after.py b/python/testData/inspections/StatementEffectIntroduceVariable_after.py new file mode 100644 index 000000000000..0db79b1d5e6f --- /dev/null +++ b/python/testData/inspections/StatementEffectIntroduceVariable_after.py @@ -0,0 +1 @@ +var = a + b \ No newline at end of file diff --git a/python/testData/inspections/UnresolvedRefCreateFunction.py b/python/testData/inspections/UnresolvedRefCreateFunction.py new file mode 100644 index 000000000000..aea8443bca14 --- /dev/null +++ b/python/testData/inspections/UnresolvedRefCreateFunction.py @@ -0,0 +1 @@ +ref \ No newline at end of file diff --git a/python/testData/inspections/UnresolvedRefCreateFunction_after.py b/python/testData/inspections/UnresolvedRefCreateFunction_after.py new file mode 100644 index 000000000000..220da55cc19c --- /dev/null +++ b/python/testData/inspections/UnresolvedRefCreateFunction_after.py @@ -0,0 +1,4 @@ +def ref(): + pass + +ref \ No newline at end of file diff --git a/python/testData/inspections/UnresolvedWith.py b/python/testData/inspections/UnresolvedWith.py new file mode 100644 index 000000000000..135ac77300fa --- /dev/null +++ b/python/testData/inspections/UnresolvedWith.py @@ -0,0 +1,2 @@ +with open("x.txt") as f: + data = f.read() \ No newline at end of file diff --git a/python/testData/inspections/UnresolvedWith_after.py b/python/testData/inspections/UnresolvedWith_after.py new file mode 100644 index 000000000000..66b1d3d0445a --- /dev/null +++ b/python/testData/inspections/UnresolvedWith_after.py @@ -0,0 +1,4 @@ +from __future__ import with_statement + +with open("x.txt") as f: + data = f.read() \ No newline at end of file diff --git a/python/testData/intentions/afterConvertLambdaToFunction.py b/python/testData/intentions/afterConvertLambdaToFunction.py new file mode 100644 index 000000000000..619b1e392e9c --- /dev/null +++ b/python/testData/intentions/afterConvertLambdaToFunction.py @@ -0,0 +1,6 @@ +def func(seq): + def function(x, y): + return (x + y) / y + + newlist = reduce(function + , seq) \ No newline at end of file diff --git a/python/testData/intentions/beforeConvertLambdaToFunction.py b/python/testData/intentions/beforeConvertLambdaToFunction.py new file mode 100644 index 000000000000..eaa151a875ac --- /dev/null +++ b/python/testData/intentions/beforeConvertLambdaToFunction.py @@ -0,0 +1,2 @@ +def func(seq): + newlist = reduce(lambda x, y: (x+y)/y, seq) \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/PyIntentionTest.java b/python/testSrc/com/jetbrains/python/PyIntentionTest.java index c5a4a0112bc3..5799c1ffb6f1 100644 --- a/python/testSrc/com/jetbrains/python/PyIntentionTest.java +++ b/python/testSrc/com/jetbrains/python/PyIntentionTest.java @@ -124,4 +124,8 @@ public class PyIntentionTest extends PyLightFixtureTestCase { public void testQuotedString() { doTest(PyBundle.message("INTN.quoted.string.double.to.single")); } + + public void testConvertLambdaToFunction() { + doTest(PyBundle.message("INTN.convert.lambda.to.function")); + } } diff --git a/python/testSrc/com/jetbrains/python/PyQuickFixTest.java b/python/testSrc/com/jetbrains/python/PyQuickFixTest.java index 0d8d046ffeb5..bc9f47b6e55c 100644 --- a/python/testSrc/com/jetbrains/python/PyQuickFixTest.java +++ b/python/testSrc/com/jetbrains/python/PyQuickFixTest.java @@ -6,6 +6,7 @@ import com.intellij.testFramework.TestDataPath; import com.jetbrains.python.codeInsight.PyCodeInsightSettings; import com.jetbrains.python.fixtures.PyLightFixtureTestCase; import com.jetbrains.python.inspections.*; +import com.jetbrains.python.psi.LanguageLevel; import org.jetbrains.annotations.NonNls; /** @@ -188,6 +189,21 @@ public class PyQuickFixTest extends PyLightFixtureTestCase { PyBundle.message("QFIX.statement.effect"), true, true); } + public void testStatementEffectIntroduceVariable() { // PY-1265 + doInspectionTest("StatementEffectIntroduceVariable.py", PyStatementEffectInspection.class, + PyBundle.message("QFIX.statement.effect.introduce.variable"), true, true); + } + + public void testUnresolvedWith() { // PY-2083 + setLanguageLevel(LanguageLevel.PYTHON25); + doInspectionTest("UnresolvedWith.py", PyUnresolvedReferencesInspection.class, + PyBundle.message("QFIX.unresolved.reference.add.future"), true, true); + } + + public void testUnresolvedRefCreateFunction() { // PY-2092 + doInspectionTest("UnresolvedRefCreateFunction.py", PyUnresolvedReferencesInspection.class, + PyBundle.message("QFIX.unresolved.reference.create.function"), true, true); + } @Override @NonNls protected String getTestDataPath() {