diff --git a/python/helpers/pycharm/tcunittest.py b/python/helpers/pycharm/tcunittest.py
index 5b78c7f4205d..d8b37caad90f 100644
--- a/python/helpers/pycharm/tcunittest.py
+++ b/python/helpers/pycharm/tcunittest.py
@@ -40,6 +40,9 @@ class TeamcityTestResult(TestResult):
self.messages.testFailed(self.getTestName(test),
message='Failure', details=err)
+ def addSkip(self, test, reason):
+ self.messages.testIgnored(self.getTestName(test), message=reason)
+
def startTest(self, test):
setattr(test, "startTime", datetime.datetime.now())
self.messages.testStarted(self.getTestName(test), location="python_uttestid://" + str(test.id()))
diff --git a/python/src/META-INF/python-plugin-common.xml b/python/src/META-INF/python-plugin-common.xml
index 6c53e1d844d7..e19d92a37b7f 100644
--- a/python/src/META-INF/python-plugin-common.xml
+++ b/python/src/META-INF/python-plugin-common.xml
@@ -33,9 +33,6 @@
-
@@ -64,9 +61,6 @@
-
-
@@ -74,59 +68,50 @@
-
- PyDemorganIntention
- Python
- PyDemorganIntention
-
com.jetbrains.python.codeInsight.intentions.ImportToImportFromIntention
Python
- ImportToImportFromIntention
com.jetbrains.python.codeInsight.intentions.ImportFromToImportIntention
Python
- ImportFromToImportIntention
com.jetbrains.python.codeInsight.intentions.ImportToggleAliasIntention
Python
- ImportToggleAliasIntention
com.jetbrains.python.codeInsight.intentions.PySplitIfIntention
Python
- PySplitIfIntention
com.jetbrains.python.codeInsight.intentions.PyNegateComparisonIntention
Python
- PyNegateComparisonIntention
com.jetbrains.python.codeInsight.intentions.PyStringConcatenationToFormatIntention
Python
- PyStringConcatenationToFormatIntention
com.jetbrains.python.codeInsight.intentions.ConvertFormatOperatorToMethodIntention
Python
- ConvertFormatOperatorToMethodIntention
com.jetbrains.python.codeInsight.intentions.PyFlipComparisonIntention
Python
- PyFlipComparisonIntention
+
+
+
+ com.jetbrains.python.codeInsight.intentions.PyDemorganIntention
+ Python
diff --git a/python/src/com/jetbrains/python/JythonManager.java b/python/src/com/jetbrains/python/JythonManager.java
deleted file mode 100644
index a9da91a3817e..000000000000
--- a/python/src/com/jetbrains/python/JythonManager.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package com.jetbrains.python;
-
-import com.intellij.openapi.components.ServiceManager;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.util.PathUtil;
-import org.jetbrains.annotations.NonNls;
-import org.python.core.*;
-import org.python.util.PythonInterpreter;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Properties;
-
-/**
- * @author yole
- */
-public class JythonManager {
- private static final Logger LOG = Logger.getInstance("#com.jetbrains.python.JythonManager");
-
- public static JythonManager getInstance() {
- return ServiceManager.getService(JythonManager.class);
- }
-
- private final PythonInterpreter myInterpreter;
-
- public JythonManager() {
- @NonNls Properties postProperties = new Properties();
- postProperties.put("python.cachedir.skip", "true");
- String pythonScriptPath = findPythonScriptPath();
- postProperties.put("python.path", pythonScriptPath);
- LOG.info("Loading Python scripts from " + pythonScriptPath);
- PySystemState.initialize(PySystemState.getBaseProperties(), postProperties, new String[] { "" });
- myInterpreter = new PythonInterpreter();
- }
-
- private String findPythonScriptPath() {
- @NonNls String classRoot = PathUtil.getJarPathForClass(getClass());
- if (classRoot.endsWith(".jar")) {
- return classRoot;
- }
- // compiled classes
- File f = new File(new File(classRoot).getParent(), "python-py");
- if (f.exists()) {
- return f.getPath();
- }
- throw new RuntimeException("Can't figure out Python script path: " + classRoot);
- }
-
- public void execScriptFromResource(@NonNls String resourcePath) {
- final InputStream stream = getClass().getClassLoader().getResourceAsStream(resourcePath);
- try {
- myInterpreter.execfile(stream);
- }
- finally {
- try {
- stream.close();
- }
- catch (IOException e) {
- LOG.error(e);
- }
- }
- }
-
- public PyObject eval(@NonNls final String code) {
- return myInterpreter.eval(code);
- }
-}
diff --git a/python/src/com/jetbrains/python/PyExtensionFactory.java b/python/src/com/jetbrains/python/PyExtensionFactory.java
deleted file mode 100644
index 188b1f40cd25..000000000000
--- a/python/src/com/jetbrains/python/PyExtensionFactory.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.jetbrains.python;
-
-import com.intellij.openapi.extensions.ExtensionFactory;
-import com.intellij.openapi.diagnostic.Logger;
-import org.python.core.PyObject;
-
-/**
- * @author yole
- */
-public class PyExtensionFactory implements ExtensionFactory {
- private static final Logger LOG = Logger.getInstance("#com.jetbrains.python.PyExtensionFactory");
-
- public Object createInstance(final String factoryArgument, final String implementationClass) {
- LOG.info("Instantiating Jython class " + implementationClass + " from script " + factoryArgument);
- JythonManager jythonManager = JythonManager.getInstance();
- jythonManager.execScriptFromResource(factoryArgument);
- final PyObject object = jythonManager.eval(implementationClass + "()");
- return object.__tojava__(Object.class);
- }
-}
diff --git a/python/src/com/jetbrains/python/codeInsight/codeFragment/PyCodeFragmentUtil.java b/python/src/com/jetbrains/python/codeInsight/codeFragment/PyCodeFragmentUtil.java
index ca1c502f430b..241703071895 100644
--- a/python/src/com/jetbrains/python/codeInsight/codeFragment/PyCodeFragmentUtil.java
+++ b/python/src/com/jetbrains/python/codeInsight/codeFragment/PyCodeFragmentUtil.java
@@ -92,9 +92,26 @@ public class PyCodeFragmentUtil {
}
// If we see more than 1 outer instruction, controlflow is interrupted
- if (outerInstructions.size() > 1){
+ if (outerInstructions.size() > 2){
throw new CannotCreateCodeFragmentException(PyBundle.message("refactoring.extract.method.error.cannot.perform.refactoring.when.execution.flow.is.interrupted"));
}
+ if (outerInstructions.size() == 2){
+ boolean errorFound = true;
+ for (Instruction outerInstruction : outerInstructions) {
+ // Here we check control flow when for statement content is beeing extracted
+ if (outerInstruction instanceof ReadWriteInstruction &&
+ PyForStatementNavigator.getPyForStatementByIterable(outerInstruction.getElement())!=null) {
+ // In case when return instruction is inside
+ if (!returnInstructionInside){
+ errorFound = false;
+ break;
+ }
+ }
+ }
+ if (errorFound){
+ throw new CannotCreateCodeFragmentException(PyBundle.message("refactoring.extract.method.error.cannot.perform.refactoring.when.execution.flow.is.interrupted"));
+ }
+ }
// Building code fragment
final PyCodeFragmentBuilder builder = new PyCodeFragmentBuilder(owner, start, end);
diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/PyDemorganIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/PyDemorganIntention.java
new file mode 100644
index 000000000000..da1eb8cc58dd
--- /dev/null
+++ b/python/src/com/jetbrains/python/codeInsight/intentions/PyDemorganIntention.java
@@ -0,0 +1,123 @@
+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.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.util.IncorrectOperationException;
+import com.jetbrains.python.PyTokenTypes;
+import com.jetbrains.python.psi.*;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author yole
+ */
+public class PyDemorganIntention extends BaseIntentionAction {
+ @NotNull
+ @Override
+ public String getText() {
+ return "DeMorgan Law";
+ }
+
+ @NotNull
+ @Override
+ public String getFamilyName() {
+ return "DeMorgan Law";
+ }
+
+ @Override
+ public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
+ PyBinaryExpression expression = PsiTreeUtil.getParentOfType(file.findElementAt(editor.getCaretModel().getOffset()), PyBinaryExpression.class);
+ if (expression != null) {
+ PyElementType op = expression.getOperator();
+ if (op == PyTokenTypes.AND_KEYWORD || op == PyTokenTypes.OR_KEYWORD) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
+ PyBinaryExpression expression = PsiTreeUtil.getParentOfType(file.findElementAt(editor.getCaretModel().getOffset()),
+ PyBinaryExpression.class);
+ PyElementType op = expression.getOperator();
+ String converted = convertConjunctionExpression(expression, op);
+ replaceExpression(converted, expression);
+ }
+
+ private static void replaceExpression(String newExpression, PyBinaryExpression expression) {
+ PsiElement expressionToReplace = expression;
+ String expString = "not(" + newExpression + ')';
+ PsiElement parent = expression.getParent().getParent();
+ if (isNegation(parent)) {
+ expressionToReplace = parent;
+ expString = newExpression;
+ }
+ PyElementGenerator generator = PyElementGenerator.getInstance(expression.getProject());
+ PyExpression newCall = generator.createExpressionFromText(expString);
+ PsiElement insertedElement = expressionToReplace.replace(newCall);
+ // codeStyleManager = expression.getManager().getCodeStyleManager()
+ // TODO codeStyleManager.reformat(insertedElement)
+ }
+
+ private static String convertConjunctionExpression(PyBinaryExpression exp, PyElementType tokenType) {
+ PyExpression lhs = exp.getLeftExpression();
+ String lhsText, rhsText;
+ if (isConjunctionExpression(lhs, tokenType)) {
+ lhsText = convertConjunctionExpression((PyBinaryExpression)lhs, tokenType);
+ }
+ else {
+ lhsText = convertLeafExpression(lhs);
+ }
+
+ PyExpression rhs = exp.getRightExpression();
+ if (isConjunctionExpression(rhs, tokenType)) {
+ rhsText = convertConjunctionExpression((PyBinaryExpression)rhs, tokenType);
+ }
+ else {
+ rhsText = convertLeafExpression(rhs);
+ }
+
+ String flippedConjunction = (tokenType == PyTokenTypes.AND_KEYWORD) ? " or " : " and ";
+ return lhsText + flippedConjunction + rhsText;
+ }
+
+ private static String convertLeafExpression(PyExpression condition) {
+ if (isNegation(condition)) {
+ PyExpression negated = getNegated(condition);
+ if (negated == null) {
+ return "";
+ }
+ return negated.getText();
+ }
+ else {
+ return "not " + condition.getText();
+ }
+ }
+
+ private static PyExpression getNegated(PyExpression expression) {
+ PyExpression operand = ((PyPrefixExpression)expression).getOperand();
+ return operand; // TODO strip ()
+ }
+
+ private static boolean isConjunctionExpression(PyExpression expression, PyElementType tokenType) {
+ if (expression instanceof PyBinaryExpression) {
+ PyElementType operator = ((PyBinaryExpression) expression).getOperator();
+ return operator == tokenType;
+ }
+ return false;
+ }
+
+ private static boolean isNegation(PsiElement expression) {
+ if (!(expression instanceof PyPrefixExpression)) {
+ return false;
+ }
+ PyElementType op = ((PyPrefixExpression)expression).getOperationSign();
+ return op == PyTokenTypes.NOT_KEYWORD;
+ }
+
+
+}
diff --git a/python/src/com/jetbrains/python/debugger/PyDebugValue.java b/python/src/com/jetbrains/python/debugger/PyDebugValue.java
index 63a1c590a426..47aec3a7fec5 100644
--- a/python/src/com/jetbrains/python/debugger/PyDebugValue.java
+++ b/python/src/com/jetbrains/python/debugger/PyDebugValue.java
@@ -74,18 +74,18 @@ public class PyDebugValue extends XValue {
}
// todo: pass StringBuilder to recursive calls
- public String getQualifiedExpression() {
+ public String getEvaluationExpression() {
if (myParent == null) {
return getTempName();
}
else if ("list".equals(myParent.getType()) || "tuple".equals(myParent.getType())) {
- return new StringBuilder().append(myParent.getQualifiedExpression()).append('[').append(myName).append(']').toString();
+ return new StringBuilder().append(myParent.getEvaluationExpression()).append('[').append(myName).append(']').toString();
}
else if ("dict".equals(myParent.getType())) {
- return new StringBuilder().append(myParent.getQualifiedExpression()).append("['").append(myName).append("']").toString();
+ return new StringBuilder().append(myParent.getEvaluationExpression()).append("['").append(myName).append("']").toString();
}
else {
- return new StringBuilder().append(myParent.getQualifiedExpression()).append('.').append(myName).toString();
+ return new StringBuilder().append(myParent.getEvaluationExpression()).append('.').append(myName).toString();
}
}
diff --git a/python/src/com/jetbrains/python/inspections/PythonPyInspectionToolProvider.java b/python/src/com/jetbrains/python/inspections/PythonPyInspectionToolProvider.java
deleted file mode 100644
index e04ce9d71647..000000000000
--- a/python/src/com/jetbrains/python/inspections/PythonPyInspectionToolProvider.java
+++ /dev/null
@@ -1,71 +0,0 @@
-package com.jetbrains.python.inspections;
-
-import com.intellij.codeInspection.InspectionProfileEntry;
-import com.intellij.codeInspection.InspectionToolsFactory;
-import com.intellij.codeInspection.LocalInspectionTool;
-import com.intellij.codeInspection.ex.InspectionTool;
-import com.intellij.codeInspection.ex.InspectionToolRegistrar;
-import com.intellij.codeInspection.ex.LocalInspectionToolWrapper;
-import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.util.Function;
-import com.jetbrains.python.JythonManager;
-import org.jetbrains.annotations.Nullable;
-import org.python.core.PyList;
-import org.python.core.PyObject;
-
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * @author yole
- */
-public class PythonPyInspectionToolProvider implements InspectionToolsFactory {
- private final JythonManager myManager;
-
- public static PythonPyInspectionToolProvider getInstance() {
- return ApplicationManager.getApplication().getComponent(PythonPyInspectionToolProvider.class);
- }
-
- private final InspectionToolRegistrar myRegistrar;
-
- private final Set myShortNames = new HashSet();
-
- public PythonPyInspectionToolProvider(final InspectionToolRegistrar registrar, final JythonManager jythonManager) {
- myRegistrar = registrar;
- myManager = jythonManager;
- }
-
- @Nullable
- public LocalInspectionTool createLocalInspectionTool(final String inspectionToolName) {
- try {
- final PyObject object = myManager.eval(inspectionToolName + "()");
- final Object o = object.__tojava__(LocalInspectionTool.class);
- return (LocalInspectionTool)o;
- }
- catch (Exception e) {
- return null;
- }
- }
-
- public InspectionProfileEntry[] createTools() {
- myRegistrar.registerInspectionToolProvider(new Function() {
- @Nullable
- public InspectionTool fun(String shortName) {
- final LocalInspectionTool tool = myShortNames.contains(shortName) ? createLocalInspectionTool(shortName) : null;
- return tool != null ? new LocalInspectionToolWrapper(tool) : null;
- }
- });
-
- myManager.execScriptFromResource("inspections/inspections.py");
-
- final PyList pyList = (PyList) myManager.eval("getAllInspections()");
- int len = pyList.__len__();
- final InspectionProfileEntry[] profileEntries = new InspectionProfileEntry[len];
- for(int i=0; iif hour >= start and hour < end: return name
\ No newline at end of file
diff --git a/python/testSrc/com/jetbrains/python/refactoring/PyCodeFragmentTest.java b/python/testSrc/com/jetbrains/python/refactoring/PyCodeFragmentTest.java
index 03fdb9bae802..db7a65fa4a33 100644
--- a/python/testSrc/com/jetbrains/python/refactoring/PyCodeFragmentTest.java
+++ b/python/testSrc/com/jetbrains/python/refactoring/PyCodeFragmentTest.java
@@ -70,7 +70,7 @@ public class PyCodeFragmentTest extends LightMarkedTestCase {
final StringBuffer buffer = new StringBuffer();
try {
final CodeFragment fragment = PyCodeFragmentUtil.createCodeFragment((ScopeOwner)context, startElement, endElement);
- if (fragment.isReturnInstructonInside()) {
+ if (fragment.isReturnInstructionInside()) {
buffer.append("Return instruction inside found").append("\n");
}
buffer.append("In:\n");
diff --git a/python/testSrc/com/jetbrains/python/refactoring/PyExtractMethodTest.java b/python/testSrc/com/jetbrains/python/refactoring/PyExtractMethodTest.java
index c04760dd7c97..6a0334228c5a 100644
--- a/python/testSrc/com/jetbrains/python/refactoring/PyExtractMethodTest.java
+++ b/python/testSrc/com/jetbrains/python/refactoring/PyExtractMethodTest.java
@@ -126,4 +126,9 @@ public class PyExtractMethodTest extends LightMarkedTestCase {
public void testClass() throws Throwable {
doTest("context/class.before.py", "bar", "context/class.after.py");
}
+
+ public void testConditionalReturn() throws Throwable {
+ doTest("conditionalreturn.before.py", "bar", "Cannot perform refactoring when execution flow is interrupted");
+ }
+
}