summaryrefslogtreecommitdiff
path: root/python/src
diff options
context:
space:
mode:
Diffstat (limited to 'python/src')
-rw-r--r--python/src/META-INF/pycharm-core.xml3
-rw-r--r--python/src/META-INF/python-core.xml3
-rw-r--r--python/src/com/jetbrains/python/codeInsight/PyTypingTypeProvider.java375
-rw-r--r--python/src/com/jetbrains/python/codeInsight/highlighting/PyHighlightExitPointsHandlerFactory.java24
-rw-r--r--python/src/com/jetbrains/python/codeInsight/intentions/ImportToImportFromIntention.java122
-rw-r--r--python/src/com/jetbrains/python/codeInsight/intentions/PyGenerateDocstringIntention.java1
-rw-r--r--python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java8
-rw-r--r--python/src/com/jetbrains/python/console/PyConsoleOptions.java1
-rw-r--r--python/src/com/jetbrains/python/console/PyDebugConsoleBuilder.java2
-rw-r--r--python/src/com/jetbrains/python/console/PydevConsoleRunner.java45
-rw-r--r--python/src/com/jetbrains/python/debugger/PyDebugProcess.java22
-rw-r--r--python/src/com/jetbrains/python/debugger/PyExecutionStack.java2
-rw-r--r--python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java18
-rw-r--r--python/src/com/jetbrains/python/documentation/doctest/PyDocstringVisitorFilter.java2
-rw-r--r--python/src/com/jetbrains/python/formatter/PythonFormattingModelBuilder.java4
-rw-r--r--python/src/com/jetbrains/python/inspections/PyCompatibilityInspection.java4
-rw-r--r--python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java3
-rw-r--r--python/src/com/jetbrains/python/inspections/quickfix/PyDefaultArgumentQuickFix.java39
-rw-r--r--python/src/com/jetbrains/python/inspections/quickfix/StatementEffectFunctionCallQuickFix.java96
-rw-r--r--python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java3
-rw-r--r--python/src/com/jetbrains/python/module/PyContentEntriesEditor.java367
-rw-r--r--python/src/com/jetbrains/python/psi/impl/PyAnnotationImpl.java31
-rw-r--r--python/src/com/jetbrains/python/psi/impl/PyClassImpl.java28
-rw-r--r--python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java29
-rw-r--r--python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java10
-rw-r--r--python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java7
-rw-r--r--python/src/com/jetbrains/python/psi/resolve/PyResolveUtil.java8
-rw-r--r--python/src/com/jetbrains/python/psi/resolve/QualifiedNameFinder.java34
-rw-r--r--python/src/com/jetbrains/python/psi/stubs/PyClassNameIndex.java2
-rw-r--r--python/src/com/jetbrains/python/psi/types/PyFunctionType.java10
-rw-r--r--python/src/com/jetbrains/python/psi/types/PyTypeChecker.java90
-rw-r--r--python/src/com/jetbrains/python/refactoring/PyReplaceExpressionUtil.java13
-rw-r--r--python/src/com/jetbrains/python/refactoring/inline/PyInlineLocalHandler.java61
-rw-r--r--python/src/com/jetbrains/python/refactoring/surround/surrounders/statements/PyWithIfElseSurrounder.java1
-rw-r--r--python/src/com/jetbrains/python/refactoring/surround/surrounders/statements/PyWithIfSurrounder.java9
-rw-r--r--python/src/com/jetbrains/python/refactoring/surround/surrounders/statements/PyWithTryExceptSurrounder.java2
-rw-r--r--python/src/com/jetbrains/python/refactoring/surround/surrounders/statements/PyWithTryFinallySurrounder.java1
-rw-r--r--python/src/com/jetbrains/python/refactoring/surround/surrounders/statements/PyWithWhileSurrounder.java1
-rw-r--r--python/src/com/jetbrains/python/run/AbstractPythonRunConfiguration.java3
-rw-r--r--python/src/com/jetbrains/python/run/PythonCommandLineState.java6
-rw-r--r--python/src/com/jetbrains/python/run/PythonRunConfiguration.java13
-rw-r--r--python/src/com/jetbrains/python/run/PythonRunConfigurationForm.form13
-rw-r--r--python/src/com/jetbrains/python/run/PythonRunConfigurationForm.java12
-rw-r--r--python/src/com/jetbrains/python/run/PythonScriptCommandLineState.java118
-rw-r--r--python/src/com/jetbrains/python/sdk/PySdkListCellRenderer.java3
-rw-r--r--python/src/com/jetbrains/python/sdk/flavors/WinPythonSdkFlavor.java31
-rw-r--r--python/src/com/jetbrains/python/validation/CompatibilityVisitor.java2
47 files changed, 1395 insertions, 287 deletions
diff --git a/python/src/META-INF/pycharm-core.xml b/python/src/META-INF/pycharm-core.xml
index 4732ad084b32..a9f7824b5340 100644
--- a/python/src/META-INF/pycharm-core.xml
+++ b/python/src/META-INF/pycharm-core.xml
@@ -8,6 +8,9 @@
</xi:include>
<xi:include href="/META-INF/RegExpPlugin.xml" xpointer="xpointer(/idea-plugin/*)"/>
<xi:include href="/META-INF/SpellCheckerPlugin.xml" xpointer="xpointer(/idea-plugin/*)"/>
+ <xi:include href="/META-INF/RemoteServers.xml" xpointer="xpointer(/idea-plugin/*)">
+ <xi:fallback/>
+ </xi:include>
<application-components>
<component>
diff --git a/python/src/META-INF/python-core.xml b/python/src/META-INF/python-core.xml
index 292237aac6ac..7adbc46c189c 100644
--- a/python/src/META-INF/python-core.xml
+++ b/python/src/META-INF/python-core.xml
@@ -589,6 +589,9 @@
<pyClassMembersProvider implementation="com.jetbrains.python.codeInsight.userSkeletons.PyUserSkeletonsClassMembersProvider"/>
<typeProvider implementation="com.jetbrains.python.codeInsight.userSkeletons.PyUserSkeletonsTypeProvider"/>
+ <!-- typing -->
+ <typeProvider implementation="com.jetbrains.python.codeInsight.PyTypingTypeProvider"/>
+
<typeProvider implementation="com.jetbrains.python.debugger.PyCallSignatureTypeProvider"/>
<pyReferenceResolveProvider implementation="com.jetbrains.python.psi.resolve.PythonBuiltinReferenceResolveProvider"/>
diff --git a/python/src/com/jetbrains/python/codeInsight/PyTypingTypeProvider.java b/python/src/com/jetbrains/python/codeInsight/PyTypingTypeProvider.java
new file mode 100644
index 000000000000..f03befac6c14
--- /dev/null
+++ b/python/src/com/jetbrains/python/codeInsight/PyTypingTypeProvider.java
@@ -0,0 +1,375 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python.codeInsight;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiPolyVariantReference;
+import com.intellij.psi.util.QualifiedName;
+import com.jetbrains.python.PyNames;
+import com.jetbrains.python.psi.*;
+import com.jetbrains.python.psi.impl.PyExpressionCodeFragmentImpl;
+import com.jetbrains.python.psi.impl.PyPsiUtils;
+import com.jetbrains.python.psi.resolve.PyResolveContext;
+import com.jetbrains.python.psi.types.*;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * @author vlan
+ */
+public class PyTypingTypeProvider extends PyTypeProviderBase {
+ private static ImmutableMap<String, String> BUILTIN_COLLECTIONS = ImmutableMap.<String, String>builder()
+ .put("typing.List", "list")
+ .put("typing.Dict", "dict")
+ .put("typing.Set", PyNames.SET)
+ .put("typing.Tuple", PyNames.TUPLE)
+ .build();
+
+ private static ImmutableSet<String> GENERIC_CLASSES = ImmutableSet.<String>builder()
+ .add("typing.Generic")
+ .add("typing.AbstractGeneric")
+ .add("typing.Protocol")
+ .build();
+
+ public PyType getParameterType(@NotNull PyNamedParameter param, @NotNull PyFunction func, @NotNull TypeEvalContext context) {
+ final PyAnnotation annotation = param.getAnnotation();
+ if (annotation != null) {
+ // XXX: Requires switching from stub to AST
+ final PyExpression value = annotation.getValue();
+ if (value != null) {
+ return getTypingType(value, context);
+ }
+ }
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public PyType getReturnType(@NotNull Callable callable, @NotNull TypeEvalContext context) {
+ if (callable instanceof PyFunction) {
+ final PyFunction function = (PyFunction)callable;
+ final PyAnnotation annotation = function.getAnnotation();
+ if (annotation != null) {
+ // XXX: Requires switching from stub to AST
+ final PyExpression value = annotation.getValue();
+ if (value != null) {
+ return getTypingType(value, context);
+ }
+ }
+ final PyType constructorType = getGenericConstructorType(function, context);
+ if (constructorType != null) {
+ return constructorType;
+ }
+ }
+ return null;
+ }
+
+ @Nullable
+ private static PyType getGenericConstructorType(@NotNull PyFunction function, @NotNull TypeEvalContext context) {
+ if (PyUtil.isInit(function)) {
+ final PyClass cls = function.getContainingClass();
+ if (cls != null) {
+ final List<PyGenericType> genericTypes = collectGenericTypes(cls, context);
+
+ final PyType elementType;
+ if (genericTypes.size() == 1) {
+ elementType = genericTypes.get(0);
+ }
+ else if (genericTypes.size() > 1) {
+ elementType = PyTupleType.create(cls, genericTypes.toArray(new PyType[genericTypes.size()]));
+ }
+ else {
+ elementType = null;
+ }
+
+ if (elementType != null) {
+ return new PyCollectionTypeImpl(cls, false, elementType);
+ }
+ }
+ }
+ return null;
+ }
+
+ @NotNull
+ private static List<PyGenericType> collectGenericTypes(@NotNull PyClass cls, @NotNull TypeEvalContext context) {
+ boolean isGeneric = false;
+ for (PyClass ancestor : cls.getAncestorClasses(context)) {
+ if (GENERIC_CLASSES.contains(ancestor.getQualifiedName())) {
+ isGeneric = true;
+ break;
+ }
+ }
+ if (isGeneric) {
+ final ArrayList<PyGenericType> results = new ArrayList<PyGenericType>();
+ // XXX: Requires switching from stub to AST
+ for (PyExpression expr : cls.getSuperClassExpressions()) {
+ if (expr instanceof PySubscriptionExpression) {
+ final PyExpression indexExpr = ((PySubscriptionExpression)expr).getIndexExpression();
+ if (indexExpr != null) {
+ final PyGenericType genericType = getGenericType(indexExpr, context);
+ if (genericType != null) {
+ results.add(genericType);
+ }
+ }
+ }
+ }
+ return results;
+ }
+ return Collections.emptyList();
+ }
+
+ @Nullable
+ private static PyType getTypingType(@NotNull PyExpression expression, @NotNull TypeEvalContext context) {
+ final PyType unionType = getUnionType(expression, context);
+ if (unionType != null) {
+ return unionType;
+ }
+ final PyType parameterizedType = getParameterizedType(expression, context);
+ if (parameterizedType != null) {
+ return parameterizedType;
+ }
+ final PyType builtinCollection = getBuiltinCollection(expression, context);
+ if (builtinCollection != null) {
+ return builtinCollection;
+ }
+ final PyType genericType = getGenericType(expression, context);
+ if (genericType != null) {
+ return genericType;
+ }
+ final PyType functionType = getFunctionType(expression, context);
+ if (functionType != null) {
+ return functionType;
+ }
+ final PyType stringBasedType = getStringBasedType(expression, context);
+ if (stringBasedType != null) {
+ return stringBasedType;
+ }
+ return null;
+ }
+
+ @Nullable
+ private static PyType getStringBasedType(@NotNull PyExpression expression, @NotNull TypeEvalContext context) {
+ if (expression instanceof PyStringLiteralExpression) {
+ // XXX: Requires switching from stub to AST
+ final String contents = ((PyStringLiteralExpression)expression).getStringValue();
+ final Project project = expression.getProject();
+ final PyExpressionCodeFragmentImpl codeFragment = new PyExpressionCodeFragmentImpl(project, "dummy.py", contents, false);
+ codeFragment.setContext(expression.getContainingFile());
+ final PsiElement element = codeFragment.getFirstChild();
+ if (element instanceof PyExpressionStatement) {
+ final PyExpression dummyExpr = ((PyExpressionStatement)element).getExpression();
+ return getType(dummyExpr, context);
+ }
+ }
+ return null;
+ }
+
+ @Nullable
+ private static PyType getFunctionType(@NotNull PyExpression expression, @NotNull TypeEvalContext context) {
+ if (expression instanceof PySubscriptionExpression) {
+ final PySubscriptionExpression subscriptionExpr = (PySubscriptionExpression)expression;
+ final PyExpression operand = subscriptionExpr.getOperand();
+ final String operandName = resolveToQualifiedName(operand, context);
+ if ("typing.Function".equals(operandName)) {
+ final PyExpression indexExpr = subscriptionExpr.getIndexExpression();
+ if (indexExpr instanceof PyTupleExpression) {
+ final PyTupleExpression tupleExpr = (PyTupleExpression)indexExpr;
+ final PyExpression[] elements = tupleExpr.getElements();
+ if (elements.length == 2) {
+ final PyExpression parametersExpr = elements[0];
+ if (parametersExpr instanceof PyListLiteralExpression) {
+ final List<PyCallableParameter> parameters = new ArrayList<PyCallableParameter>();
+ final PyListLiteralExpression listExpr = (PyListLiteralExpression)parametersExpr;
+ for (PyExpression argExpr : listExpr.getElements()) {
+ parameters.add(new PyCallableParameterImpl(null, getType(argExpr, context)));
+ }
+ final PyExpression returnTypeExpr = elements[1];
+ final PyType returnType = getType(returnTypeExpr, context);
+ return new PyCallableTypeImpl(parameters, returnType);
+ }
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ @Nullable
+ private static PyType getUnionType(@NotNull PyExpression expression, @NotNull TypeEvalContext context) {
+ if (expression instanceof PySubscriptionExpression) {
+ final PySubscriptionExpression subscriptionExpr = (PySubscriptionExpression)expression;
+ final PyExpression operand = subscriptionExpr.getOperand();
+ final String operandName = resolveToQualifiedName(operand, context);
+ if ("typing.Union".equals(operandName)) {
+ return PyUnionType.union(getIndexTypes(subscriptionExpr, context));
+ }
+ }
+ return null;
+ }
+
+ @Nullable
+ private static PyGenericType getGenericType(@NotNull PyExpression expression, @NotNull TypeEvalContext context) {
+ final PsiElement resolved = resolve(expression, context);
+ if (resolved instanceof PyTargetExpression) {
+ final PyTargetExpression targetExpr = (PyTargetExpression)resolved;
+ final QualifiedName calleeName = targetExpr.getCalleeName();
+ if (calleeName != null && "typevar".equals(calleeName.toString())) {
+ // XXX: Requires switching from stub to AST
+ final PyExpression assigned = targetExpr.findAssignedValue();
+ if (assigned instanceof PyCallExpression) {
+ final PyCallExpression assignedCall = (PyCallExpression)assigned;
+ final PyExpression callee = assignedCall.getCallee();
+ if (callee != null) {
+ final String calleeQName = resolveToQualifiedName(callee, context);
+ if ("typing.typevar".equals(calleeQName)) {
+ final PyExpression[] arguments = assignedCall.getArguments();
+ if (arguments.length > 0) {
+ final PyExpression firstArgument = arguments[0];
+ if (firstArgument instanceof PyStringLiteralExpression) {
+ final String name = ((PyStringLiteralExpression)firstArgument).getStringValue();
+ if (name != null) {
+ return new PyGenericType(name, getGenericTypeBound(arguments, context));
+ }
+ }
+ }
+ }
+
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ @Nullable
+ private static PyType getGenericTypeBound(@NotNull PyExpression[] typeVarArguments, @NotNull TypeEvalContext context) {
+ final List<PyType> types = new ArrayList<PyType>();
+ if (typeVarArguments.length > 1) {
+ final PyExpression secondArgument = typeVarArguments[1];
+ if (secondArgument instanceof PyKeywordArgument) {
+ final PyKeywordArgument valuesArgument = (PyKeywordArgument)secondArgument;
+ final PyExpression valueExpr = PyPsiUtils.flattenParens(valuesArgument.getValueExpression());
+ if (valueExpr instanceof PyTupleExpression) {
+ final PyTupleExpression tupleExpr = (PyTupleExpression)valueExpr;
+ for (PyExpression expr : tupleExpr.getElements()) {
+ types.add(getType(expr, context));
+ }
+ }
+ }
+ }
+ return PyUnionType.union(types);
+ }
+
+ @NotNull
+ private static List<PyType> getIndexTypes(@NotNull PySubscriptionExpression expression, @NotNull TypeEvalContext context) {
+ final List<PyType> types = new ArrayList<PyType>();
+ final PyExpression indexExpr = expression.getIndexExpression();
+ if (indexExpr instanceof PyTupleExpression) {
+ final PyTupleExpression tupleExpr = (PyTupleExpression)indexExpr;
+ for (PyExpression expr : tupleExpr.getElements()) {
+ types.add(getType(expr, context));
+ }
+ }
+ return types;
+ }
+
+ @Nullable
+ private static PyType getParameterizedType(@NotNull PyExpression expression, @NotNull TypeEvalContext context) {
+ if (expression instanceof PySubscriptionExpression) {
+ final PySubscriptionExpression subscriptionExpr = (PySubscriptionExpression)expression;
+ final PyExpression operand = subscriptionExpr.getOperand();
+ final PyExpression indexExpr = subscriptionExpr.getIndexExpression();
+ final PyType operandType = getType(operand, context);
+ if (operandType instanceof PyClassType) {
+ final PyClass cls = ((PyClassType)operandType).getPyClass();
+ if (PyNames.TUPLE.equals(cls.getQualifiedName())) {
+ final List<PyType> indexTypes = getIndexTypes(subscriptionExpr, context);
+ return PyTupleType.create(expression, indexTypes.toArray(new PyType[indexTypes.size()]));
+ }
+ else if (indexExpr != null) {
+ final PyType indexType = context.getType(indexExpr);
+ return new PyCollectionTypeImpl(cls, false, indexType);
+ }
+ }
+ }
+ return null;
+ }
+
+ @Nullable
+ private static PyType getBuiltinCollection(@NotNull PyExpression expression, @NotNull TypeEvalContext context) {
+ final String collectionName = resolveToQualifiedName(expression, context);
+ final String builtinName = BUILTIN_COLLECTIONS.get(collectionName);
+ return builtinName != null ? PyTypeParser.getTypeByName(expression, builtinName) : null;
+ }
+
+ @Nullable
+ private static PyType getType(@NotNull PyExpression expression, @NotNull TypeEvalContext context) {
+ // It is possible to replace PyAnnotation.getType() with this implementation
+ final PyType typingType = getTypingType(expression, context);
+ if (typingType != null) {
+ return typingType;
+ }
+ final PyType type = context.getType(expression);
+ if (type instanceof PyClassLikeType) {
+ final PyClassLikeType classType = (PyClassLikeType)type;
+ if (classType.isDefinition()) {
+ return classType.toInstance();
+ }
+ }
+ else if (type instanceof PyNoneType) {
+ return type;
+ }
+ return null;
+ }
+
+ @Nullable
+ private static PsiElement resolve(@NotNull PyExpression expression, @NotNull TypeEvalContext context) {
+ if (expression instanceof PyReferenceOwner) {
+ final PyReferenceOwner referenceOwner = (PyReferenceOwner)expression;
+ final PyResolveContext resolveContext = PyResolveContext.noImplicits().withTypeEvalContext(context);
+ final PsiPolyVariantReference reference = referenceOwner.getReference(resolveContext);
+ final PsiElement element = reference.resolve();
+ if (element instanceof PyFunction) {
+ final PyFunction function = (PyFunction)element;
+ if (PyUtil.isInit(function)) {
+ final PyClass cls = function.getContainingClass();
+ if (cls != null) {
+ return cls;
+ }
+ }
+ }
+ return element;
+ }
+ return null;
+ }
+
+ @Nullable
+ private static String resolveToQualifiedName(@NotNull PyExpression expression, @NotNull TypeEvalContext context) {
+ final PsiElement element = resolve(expression, context);
+ if (element instanceof PyQualifiedNameOwner) {
+ final PyQualifiedNameOwner qualifiedNameOwner = (PyQualifiedNameOwner)element;
+ return qualifiedNameOwner.getQualifiedName();
+ }
+ return null;
+ }
+}
diff --git a/python/src/com/jetbrains/python/codeInsight/highlighting/PyHighlightExitPointsHandlerFactory.java b/python/src/com/jetbrains/python/codeInsight/highlighting/PyHighlightExitPointsHandlerFactory.java
index d0bc9dcbc7ca..27522d6e7f53 100644
--- a/python/src/com/jetbrains/python/codeInsight/highlighting/PyHighlightExitPointsHandlerFactory.java
+++ b/python/src/com/jetbrains/python/codeInsight/highlighting/PyHighlightExitPointsHandlerFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,30 +15,26 @@
*/
package com.jetbrains.python.codeInsight.highlighting;
-import com.intellij.codeInsight.TargetElementUtilBase;
import com.intellij.codeInsight.highlighting.HighlightUsagesHandlerBase;
-import com.intellij.codeInsight.highlighting.HighlightUsagesHandlerFactory;
+import com.intellij.codeInsight.highlighting.HighlightUsagesHandlerFactoryBase;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiTreeUtil;
import com.jetbrains.python.psi.PyExpression;
import com.jetbrains.python.psi.PyReturnStatement;
+import org.jetbrains.annotations.NotNull;
/**
* @author oleg
*/
-public class PyHighlightExitPointsHandlerFactory implements HighlightUsagesHandlerFactory {
- public HighlightUsagesHandlerBase createHighlightUsagesHandler(final Editor editor, final PsiFile file) {
- int offset = TargetElementUtilBase.adjustOffset(file, editor.getDocument(), editor.getCaretModel().getOffset());
- PsiElement target = file.findElementAt(offset);
- if (target != null) {
- final PyReturnStatement returnStatement = PsiTreeUtil.getParentOfType(target, PyReturnStatement.class);
- if (returnStatement != null) {
- final PyExpression returnExpr = returnStatement.getExpression();
- if (returnExpr == null || !PsiTreeUtil.isAncestor(returnExpr, target, false)) {
- return new PyHighlightExitPointsHandler(editor, file, target);
- }
+public class PyHighlightExitPointsHandlerFactory extends HighlightUsagesHandlerFactoryBase {
+ public HighlightUsagesHandlerBase createHighlightUsagesHandler(@NotNull Editor editor, @NotNull PsiFile file, @NotNull PsiElement target) {
+ final PyReturnStatement returnStatement = PsiTreeUtil.getParentOfType(target, PyReturnStatement.class);
+ if (returnStatement != null) {
+ final PyExpression returnExpr = returnStatement.getExpression();
+ if (returnExpr == null || !PsiTreeUtil.isAncestor(returnExpr, target, false)) {
+ return new PyHighlightExitPointsHandler(editor, file, target);
}
}
return null;
diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/ImportToImportFromIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/ImportToImportFromIntention.java
index fc35833473f8..e76240cefb1f 100644
--- a/python/src/com/jetbrains/python/codeInsight/intentions/ImportToImportFromIntention.java
+++ b/python/src/com/jetbrains/python/codeInsight/intentions/ImportToImportFromIntention.java
@@ -57,10 +57,11 @@ public class ImportToImportFromIntention implements IntentionAction {
private PsiElement myReferee = null;
private PyImportElement myImportElement = null;
private Collection<PsiReference> myReferences = null;
- private boolean myHasModuleReference = false; // is anything that resolves to our imported module is just an exact reference to that module
+ private boolean myHasModuleReference = false;
+ // is anything that resolves to our imported module is just an exact reference to that module
private int myRelativeLevel; // true if "from ... import"
- public IntentionState(Editor editor, PsiFile file) {
+ public IntentionState(@NotNull Editor editor, @NotNull PsiFile file) {
boolean available = false;
myImportElement = findImportElement(editor, file);
if (myImportElement != null) {
@@ -70,10 +71,10 @@ public class ImportToImportFromIntention implements IntentionAction {
available = true;
}
else if (parent instanceof PyFromImportStatement) {
- PyFromImportStatement from_import = (PyFromImportStatement)parent;
- final int relative_level = from_import.getRelativeLevel();
- if (from_import.isValid() && relative_level > 0 && from_import.getImportSource() == null) {
- myRelativeLevel = relative_level;
+ final PyFromImportStatement fromImport = (PyFromImportStatement)parent;
+ final int relativeLevel = fromImport.getRelativeLevel();
+ if (fromImport.isValid() && relativeLevel > 0 && fromImport.getImportSource() == null) {
+ myRelativeLevel = relativeLevel;
available = true;
}
}
@@ -92,25 +93,27 @@ public class ImportToImportFromIntention implements IntentionAction {
assert myImportElement != null : "isAvailable() must have returned true, but myImportElement is null";
// usages of imported name are qualifiers; what they refer to?
- PyReferenceExpression reference = myImportElement.getImportReferenceExpression();
- if (reference != null) {
- myModuleName = PyPsiUtils.toPath(reference);
+ final PyReferenceExpression importReference = myImportElement.getImportReferenceExpression();
+ if (importReference != null) {
+ myModuleName = PyPsiUtils.toPath(importReference);
myQualifierName = myImportElement.getVisibleName();
- myReferee = reference.getReference().resolve();
+ myReferee = importReference.getReference().resolve();
myHasModuleReference = false;
if (myReferee != null && myModuleName != null && myQualifierName != null) {
final Collection<PsiReference> references = new ArrayList<PsiReference>();
PsiTreeUtil.processElements(file, new PsiElementProcessor() {
public boolean execute(@NotNull PsiElement element) {
if (element instanceof PyReferenceExpression && PsiTreeUtil.getParentOfType(element, PyImportElement.class) == null) {
- PyReferenceExpression ref = (PyReferenceExpression)element;
+ final PyReferenceExpression ref = (PyReferenceExpression)element;
if (myQualifierName.equals(PyPsiUtils.toPath(ref))) { // filter out other names that might resolve to our target
- PsiElement parent_elt = ref.getParent();
- if (parent_elt instanceof PyQualifiedExpression) { // really qualified by us, not just referencing?
- PsiElement resolved = ref.getReference().resolve();
+ final PsiElement parentElt = ref.getParent();
+ if (parentElt instanceof PyQualifiedExpression) { // really qualified by us, not just referencing?
+ final PsiElement resolved = ref.getReference().resolve();
if (resolved == myReferee) references.add(ref.getReference());
}
- else myHasModuleReference = true;
+ else {
+ myHasModuleReference = true;
+ }
}
}
return true;
@@ -123,68 +126,70 @@ public class ImportToImportFromIntention implements IntentionAction {
public void invoke() {
assert myImportElement != null : "isAvailable() must have returned true, but myImportElement is null";
- PyUtil.sure(myImportElement.getImportReferenceExpression());
- Project project = myImportElement.getProject();
+ sure(myImportElement.getImportReferenceExpression());
+ final Project project = myImportElement.getProject();
+
+ final PyElementGenerator generator = PyElementGenerator.getInstance(project);
+ final LanguageLevel languageLevel = LanguageLevel.forElement(myImportElement);
// usages of imported name are qualifiers; what they refer to?
try {
// remember names and make them drop qualifiers
- Set<String> used_names = new HashSet<String>();
+ final Set<String> usedNames = new HashSet<String>();
for (PsiReference ref : myReferences) {
- PsiElement elt = ref.getElement();
- PsiElement parent_elt = elt.getParent();
- used_names.add(sure(PyUtil.sure(parent_elt).getLastChild()).getText()); // TODO: find ident node more properly
+ final PsiElement elt = ref.getElement();
+ final PsiElement parentElt = elt.getParent();
+ // TODO: find ident node more properly
+ final String nameUsed = sure(sure(parentElt).getLastChild()).getText();
+ usedNames.add(nameUsed);
if (!FileModificationService.getInstance().preparePsiElementForWrite(elt)) {
return;
}
- PsiElement next_elt = elt.getNextSibling();
- if (next_elt != null && ".".equals(next_elt.getText())) next_elt.delete();
- elt.delete();
+ assert parentElt instanceof PyReferenceExpression;
+ final PyElement newReference = generator.createExpressionFromText(languageLevel, nameUsed);
+ parentElt.replace(newReference);
}
// create a separate import stmt for the module
- PsiElement importer = myImportElement.getParent();
- PyStatement import_statement;
- PyImportElement[] import_elements;
+ final PsiElement importer = myImportElement.getParent();
+ final PyStatement importStatement;
+ final PyImportElement[] importElements;
if (importer instanceof PyImportStatement) {
- import_statement = (PyImportStatement)importer;
- import_elements = ((PyImportStatement)import_statement).getImportElements();
+ importStatement = (PyImportStatement)importer;
+ importElements = ((PyImportStatement)importStatement).getImportElements();
}
else if (importer instanceof PyFromImportStatement) {
- import_statement = (PyFromImportStatement)importer;
- import_elements = ((PyFromImportStatement)import_statement).getImportElements();
+ importStatement = (PyFromImportStatement)importer;
+ importElements = ((PyFromImportStatement)importStatement).getImportElements();
}
else {
throw new IncorrectOperationException("Not an import at all");
}
- PyElementGenerator generator = PyElementGenerator.getInstance(project);
- StringBuilder builder = new StringBuilder("from ").append(getDots()).append(myModuleName).append(" import ");
- builder.append(StringUtil.join(used_names, ", "));
- PyFromImportStatement from_import_stmt =
- generator.createFromText(LanguageLevel.getDefault(), PyFromImportStatement.class, builder.toString());
- PsiElement parent = import_statement.getParent();
+ final PyFromImportStatement newImportStatement =
+ generator.createFromImportStatement(languageLevel, getDots() + myModuleName, StringUtil.join(usedNames, ", "), null);
+ final PsiElement parent = importStatement.getParent();
sure(parent);
sure(parent.isValid());
- if (import_elements.length == 1) {
+ if (importElements.length == 1) {
if (myHasModuleReference) {
- parent.addAfter(from_import_stmt, import_statement); // add 'import from': we need the module imported as is
+ parent.addAfter(newImportStatement, importStatement); // add 'import from': we need the module imported as is
}
else { // replace entire existing import
- sure(parent.getNode()).replaceChild(sure(import_statement.getNode()), sure(from_import_stmt.getNode()));
+ sure(parent.getNode()).replaceChild(sure(importStatement.getNode()), sure(newImportStatement.getNode()));
// import_statement.replace(from_import_stmt);
}
}
else {
if (!myHasModuleReference) {
// cut the module out of import, add a from-import.
- for (PyImportElement pie : import_elements) {
+ for (PyImportElement pie : importElements) {
if (pie == myImportElement) {
PyUtil.removeListNode(pie);
break;
}
}
}
- parent.addAfter(from_import_stmt, import_statement);
+ parent.addAfter(newImportStatement, importStatement);
}
}
catch (IncorrectOperationException ignored) {
@@ -193,18 +198,24 @@ public class ImportToImportFromIntention implements IntentionAction {
}
+ @NotNull
public String getText() {
- String module_name = "?";
+ String moduleName = "?";
if (myImportElement != null) {
- PyReferenceExpression reference = myImportElement.getImportReferenceExpression();
- if (reference != null) module_name = PyPsiUtils.toPath(reference);
+ final PyReferenceExpression reference = myImportElement.getImportReferenceExpression();
+ if (reference != null) {
+ moduleName = PyPsiUtils.toPath(reference);
+ }
}
- return PyBundle.message("INTN.convert.to.from.$0.import.$1", getDots()+module_name, "...");
+ return PyBundle.message("INTN.convert.to.from.$0.import.$1", getDots() + moduleName, "...");
}
+ @NotNull
private String getDots() {
String dots = "";
- for (int i=0; i<myRelativeLevel; i+=1) dots += "."; // this generally runs 1-2 times, so it's cheaper than allocating a StringBuilder
+ for (int i = 0; i < myRelativeLevel; i += 1) {
+ dots += "."; // this generally runs 1-2 times, so it's cheaper than allocating a StringBuilder
+ }
return dots;
}
}
@@ -222,10 +233,15 @@ public class ImportToImportFromIntention implements IntentionAction {
}
@Nullable
- private static PyImportElement findImportElement(Editor editor, PsiFile file) {
- PyImportElement import_elt = PsiTreeUtil.getParentOfType(file.findElementAt(editor.getCaretModel().getOffset()), PyImportElement.class);
- if (import_elt != null && import_elt.isValid()) return import_elt;
- else return null;
+ private static PyImportElement findImportElement(@NotNull Editor editor, @NotNull PsiFile file) {
+ final PsiElement elementAtCaret = file.findElementAt(editor.getCaretModel().getOffset());
+ final PyImportElement importElement = PsiTreeUtil.getParentOfType(elementAtCaret, PyImportElement.class);
+ if (importElement != null && importElement.isValid()) {
+ return importElement;
+ }
+ else {
+ return null;
+ }
}
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
@@ -233,7 +249,7 @@ public class ImportToImportFromIntention implements IntentionAction {
return false;
}
- IntentionState state = new IntentionState(editor, file);
+ final IntentionState state = new IntentionState(editor, file);
if (state.isAvailable()) {
myText = state.getText();
return true;
@@ -242,7 +258,7 @@ public class ImportToImportFromIntention implements IntentionAction {
}
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
- IntentionState state = new IntentionState(editor, file);
+ final IntentionState state = new IntentionState(editor, file);
state.invoke();
}
diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/PyGenerateDocstringIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/PyGenerateDocstringIntention.java
index 7acfc9716fea..ca7ec65f9908 100644
--- a/python/src/com/jetbrains/python/codeInsight/intentions/PyGenerateDocstringIntention.java
+++ b/python/src/com/jetbrains/python/codeInsight/intentions/PyGenerateDocstringIntention.java
@@ -69,6 +69,7 @@ public class PyGenerateDocstringIntention extends BaseIntentionAction {
if (function == null || statementList != null) {
return false;
}
+ if (!elementAt.equals(function.getNameNode())) return false;
return isAvailableForFunction(project, function);
}
diff --git a/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java b/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java
index 48a42753ebe5..e11f3e01e916 100644
--- a/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java
+++ b/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java
@@ -143,7 +143,7 @@ public class PyOverrideImplementUtil {
return;
}
new WriteCommandAction(pyClass.getProject(), pyClass.getContainingFile()) {
- protected void run(final Result result) throws Throwable {
+ protected void run(@NotNull final Result result) throws Throwable {
write(pyClass, membersToOverride, editor, implement);
}
}.execute();
@@ -173,9 +173,7 @@ public class PyOverrideImplementUtil {
PyPsiUtils.removeRedundantPass(statementList);
if (element != null) {
final PyStatementList targetStatementList = element.getStatementList();
- final int start = targetStatementList != null
- ? targetStatementList.getTextRange().getStartOffset()
- : element.getTextRange().getStartOffset();
+ final int start = targetStatementList.getTextRange().getStartOffset();
editor.getCaretModel().moveToOffset(start);
editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
editor.getSelectionModel().setSelection(start, element.getTextRange().getEndOffset());
@@ -238,7 +236,7 @@ public class PyOverrideImplementUtil {
PsiElement outerClass = PsiTreeUtil.getParentOfType(pyClass, PyClass.class, true, PyFunction.class);
String className = pyClass.getName();
final List<String> nameResult = Lists.newArrayList(className);
- while(outerClass instanceof PyClass) {
+ while(outerClass != null) {
nameResult.add(0, ((PyClass)outerClass).getName());
outerClass = PsiTreeUtil.getParentOfType(outerClass, PyClass.class, true, PyFunction.class);
}
diff --git a/python/src/com/jetbrains/python/console/PyConsoleOptions.java b/python/src/com/jetbrains/python/console/PyConsoleOptions.java
index 59ae6875d1e9..2f8eb5ee3949 100644
--- a/python/src/com/jetbrains/python/console/PyConsoleOptions.java
+++ b/python/src/com/jetbrains/python/console/PyConsoleOptions.java
@@ -146,6 +146,7 @@ public class PyConsoleOptions implements PersistentStateComponent<PyConsoleOptio
form.setUseModuleSdk(myUseModuleSdk);
form.addContentRoots(myAddContentRoots);
form.addSourceRoots(myAddSourceRoots);
+
boolean moduleWasAutoselected = false;
if (form.isUseModuleSdk() != myUseModuleSdk) {
myUseModuleSdk = form.isUseModuleSdk();
diff --git a/python/src/com/jetbrains/python/console/PyDebugConsoleBuilder.java b/python/src/com/jetbrains/python/console/PyDebugConsoleBuilder.java
index a99b9332c00d..7fbd432ebf2c 100644
--- a/python/src/com/jetbrains/python/console/PyDebugConsoleBuilder.java
+++ b/python/src/com/jetbrains/python/console/PyDebugConsoleBuilder.java
@@ -37,7 +37,7 @@ public class PyDebugConsoleBuilder extends TextConsoleBuilder {
public PyDebugConsoleBuilder(final Project project, @Nullable Sdk sdk) {
myProject = project;
- this.mySdk = sdk;
+ mySdk = sdk;
}
public ConsoleView getConsole() {
diff --git a/python/src/com/jetbrains/python/console/PydevConsoleRunner.java b/python/src/com/jetbrains/python/console/PydevConsoleRunner.java
index b3ebacd83ae3..c710fd0abf4e 100644
--- a/python/src/com/jetbrains/python/console/PydevConsoleRunner.java
+++ b/python/src/com/jetbrains/python/console/PydevConsoleRunner.java
@@ -125,10 +125,10 @@ public class PydevConsoleRunner extends AbstractConsoleRunnerWithHistory<PythonC
private Sdk mySdk;
@NotNull private CommandLineArgumentsProvider myCommandLineArgumentsProvider;
- private int[] myPorts;
+ protected int[] myPorts;
private PydevConsoleCommunication myPydevConsoleCommunication;
private PyConsoleProcessHandler myProcessHandler;
- private PydevConsoleExecuteActionHandler myConsoleExecuteActionHandler;
+ protected PydevConsoleExecuteActionHandler myConsoleExecuteActionHandler;
private List<ConsoleListener> myConsoleListeners = ContainerUtil.createLockFreeCopyOnWriteList();
private final PyConsoleType myConsoleType;
private Map<String, String> myEnvironmentVariables;
@@ -146,9 +146,9 @@ public class PydevConsoleRunner extends AbstractConsoleRunnerWithHistory<PythonC
private String myConsoleTitle = null;
public PydevConsoleRunner(@NotNull final Project project,
- @NotNull Sdk sdk, @NotNull final PyConsoleType consoleType,
- @Nullable final String workingDir,
- Map<String, String> environmentVariables, String ... statementsToExecute) {
+ @NotNull Sdk sdk, @NotNull final PyConsoleType consoleType,
+ @Nullable final String workingDir,
+ Map<String, String> environmentVariables, String... statementsToExecute) {
super(project, consoleType.getTitle(), workingDir);
mySdk = sdk;
myConsoleType = consoleType;
@@ -281,6 +281,30 @@ public class PydevConsoleRunner extends AbstractConsoleRunnerWithHistory<PythonC
return actions;
}
+ public void runSync() {
+ myPorts = findAvailablePorts(getProject(), myConsoleType);
+
+ assert myPorts != null;
+
+ myCommandLineArgumentsProvider = createCommandLineArgumentsProvider(mySdk, myEnvironmentVariables, myPorts);
+
+ try {
+ super.initAndRun();
+ }
+ catch (ExecutionException e) {
+ LOG.warn("Error running console", e);
+ ExecutionHelper.showErrors(getProject(), Arrays.<Exception>asList(e), "Python Console", null);
+ }
+
+ ProgressManager.getInstance().run(new Task.Backgroundable(getProject(), "Connecting to console", false) {
+ @Override
+ public void run(@NotNull final ProgressIndicator indicator) {
+ indicator.setText("Connecting to console...");
+ connect(myStatementsToExecute);
+ }
+ });
+ }
+
public void run() {
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
@Override
@@ -337,9 +361,9 @@ public class PydevConsoleRunner extends AbstractConsoleRunnerWithHistory<PythonC
return ports;
}
- private static CommandLineArgumentsProvider createCommandLineArgumentsProvider(final Sdk sdk,
- final Map<String, String> environmentVariables,
- int[] ports) {
+ protected CommandLineArgumentsProvider createCommandLineArgumentsProvider(final Sdk sdk,
+ final Map<String, String> environmentVariables,
+ int[] ports) {
final ArrayList<String> args = new ArrayList<String>();
args.add(sdk.getHomePath());
final String versionString = sdk.getVersionString();
@@ -518,8 +542,11 @@ public class PydevConsoleRunner extends AbstractConsoleRunnerWithHistory<PythonC
public void initAndRun(final String... statements2execute) throws ExecutionException {
super.initAndRun();
- if (handshake()) {
+ connect(statements2execute);
+ }
+ public void connect(final String[] statements2execute) {
+ if (handshake()) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
diff --git a/python/src/com/jetbrains/python/debugger/PyDebugProcess.java b/python/src/com/jetbrains/python/debugger/PyDebugProcess.java
index cff49fb1f0d8..cdea41298a4e 100644
--- a/python/src/com/jetbrains/python/debugger/PyDebugProcess.java
+++ b/python/src/com/jetbrains/python/debugger/PyDebugProcess.java
@@ -17,6 +17,7 @@ package com.jetbrains.python.debugger;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
+import com.intellij.execution.console.DuplexConsoleView;
import com.intellij.execution.process.ProcessEvent;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.process.ProcessListener;
@@ -35,6 +36,7 @@ import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Pair;
import com.intellij.remote.RemoteProcessHandlerBase;
+import com.intellij.util.ui.UIUtil;
import com.intellij.xdebugger.*;
import com.intellij.xdebugger.breakpoints.XBreakpoint;
import com.intellij.xdebugger.breakpoints.XBreakpointHandler;
@@ -43,6 +45,7 @@ import com.intellij.xdebugger.breakpoints.XLineBreakpoint;
import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider;
import com.intellij.xdebugger.frame.XValueChildrenList;
import com.intellij.xdebugger.stepping.XSmartStepIntoHandler;
+import com.jetbrains.python.console.PythonDebugLanguageConsoleView;
import com.jetbrains.python.console.pydev.PydevCompletionVariant;
import com.jetbrains.python.debugger.pydev.*;
import com.jetbrains.python.run.PythonProcessHandler;
@@ -84,6 +87,7 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr
private final XSmartStepIntoHandler<?> mySmartStepIntoHandler;
private boolean myWaitingForConnection = false;
private PyStackFrame myStackFrameBeforeResume;
+ private PyStackFrame myConsoleContextFrame = null;
public PyDebugProcess(final @NotNull XDebugSession session,
@NotNull final ServerSocket serverSocket,
@@ -285,6 +289,19 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr
PySignatureCacheManager.getInstance(getSession().getProject()).recordSignature(myPositionConverter.convertSignature(signature));
}
+ @Override
+ public void showConsole(PyThreadInfo thread) {
+ myConsoleContextFrame = new PyExecutionStack(this, thread).getTopFrame();
+ if (myExecutionConsole instanceof PythonDebugLanguageConsoleView) {
+ UIUtil.invokeLaterIfNeeded(new Runnable() {
+ @Override
+ public void run() {
+ ((PythonDebugLanguageConsoleView)myExecutionConsole).enableConsole(false);
+ }
+ });
+ }
+ }
+
protected void afterConnect() {
}
@@ -545,6 +562,11 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr
}
final PyStackFrame frame = (PyStackFrame)getSession().getCurrentStackFrame();
+
+ if (frame == null && myConsoleContextFrame != null) {
+ return myConsoleContextFrame;
+ }
+
if (frame == null) {
throw new PyDebuggerException("Process is running");
}
diff --git a/python/src/com/jetbrains/python/debugger/PyExecutionStack.java b/python/src/com/jetbrains/python/debugger/PyExecutionStack.java
index ed48f09a99ca..7d9aba3608c2 100644
--- a/python/src/com/jetbrains/python/debugger/PyExecutionStack.java
+++ b/python/src/com/jetbrains/python/debugger/PyExecutionStack.java
@@ -37,7 +37,7 @@ public class PyExecutionStack extends XExecutionStack {
}
@Override
- public XStackFrame getTopFrame() {
+ public PyStackFrame getTopFrame() {
if (myTopFrame == null) {
final List<PyStackFrameInfo> frames = myThreadInfo.getFrames();
if (frames != null) {
diff --git a/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java b/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java
index 55bc1e4c5446..913ed65f1e53 100644
--- a/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java
+++ b/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java
@@ -34,6 +34,7 @@ import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.psi.util.QualifiedName;
import com.intellij.util.Function;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.codeInsight.PyCodeInsightSettings;
@@ -44,13 +45,16 @@ import com.jetbrains.python.debugger.PySignatureCacheManager;
import com.jetbrains.python.debugger.PySignatureUtil;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyBuiltinCache;
-import com.intellij.psi.util.QualifiedName;
import com.jetbrains.python.psi.resolve.QualifiedNameFinder;
-import com.jetbrains.python.psi.types.*;
+import com.jetbrains.python.psi.types.PyClassType;
+import com.jetbrains.python.psi.types.PyType;
+import com.jetbrains.python.psi.types.PyTypeParser;
+import com.jetbrains.python.psi.types.TypeEvalContext;
import com.jetbrains.python.toolbox.ChainIterable;
import com.jetbrains.python.toolbox.FP;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.HeadMethod;
+import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -414,8 +418,10 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i
return true;
}
HttpClient client = new HttpClient();
- client.setTimeout(5 * 1000);
- client.setConnectionTimeout(5 * 1000);
+ HttpConnectionManagerParams params = client.getHttpConnectionManager().getParams();
+ params.setSoTimeout(5 * 1000);
+ params.setConnectionTimeout(5 * 1000);
+
try {
HeadMethod method = new HeadMethod(url);
int rc = client.executeMethod(method);
@@ -618,9 +624,7 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i
if (checkReturn) {
RaiseVisitor visitor = new RaiseVisitor();
PyStatementList statementList = element.getStatementList();
- if (statementList != null) {
- statementList.accept(visitor);
- }
+ statementList.accept(visitor);
if (visitor.myHasReturn) {
builder.append(prefix).append("return:").append(offset);
if (PyCodeInsightSettings.getInstance().INSERT_TYPE_DOCSTUB) {
diff --git a/python/src/com/jetbrains/python/documentation/doctest/PyDocstringVisitorFilter.java b/python/src/com/jetbrains/python/documentation/doctest/PyDocstringVisitorFilter.java
index e79d52cb1685..71af6aa30fea 100644
--- a/python/src/com/jetbrains/python/documentation/doctest/PyDocstringVisitorFilter.java
+++ b/python/src/com/jetbrains/python/documentation/doctest/PyDocstringVisitorFilter.java
@@ -43,7 +43,7 @@ public class PyDocstringVisitorFilter implements PythonVisitorFilter {
visitorClass == PyByteLiteralInspection.class || visitorClass == PyNonAsciiCharInspection.class ||
visitorClass == PyPackageRequirementsInspection.class || visitorClass == PyMandatoryEncodingInspection.class ||
visitorClass == PyInterpreterInspection.class || visitorClass == PyDocstringTypesInspection.class ||
- visitorClass == PySingleQuotedDocstringInspection.class) {
+ visitorClass == PySingleQuotedDocstringInspection.class || visitorClass == PyClassHasNoInitInspection.class) {
return false;
}
//annotators
diff --git a/python/src/com/jetbrains/python/formatter/PythonFormattingModelBuilder.java b/python/src/com/jetbrains/python/formatter/PythonFormattingModelBuilder.java
index aee9e53adff6..4b71d6abec25 100644
--- a/python/src/com/jetbrains/python/formatter/PythonFormattingModelBuilder.java
+++ b/python/src/com/jetbrains/python/formatter/PythonFormattingModelBuilder.java
@@ -46,13 +46,13 @@ public class PythonFormattingModelBuilder implements FormattingModelBuilderEx, C
public FormattingModel createModel(@NotNull PsiElement element,
@NotNull CodeStyleSettings settings,
@NotNull FormattingMode mode) {
+ final ASTNode fileNode = element.getContainingFile().getNode();
if (DUMP_FORMATTING_AST) {
- ASTNode fileNode = element.getContainingFile().getNode();
System.out.println("AST tree for " + element.getContainingFile().getName() + ":");
printAST(fileNode, 0);
}
final PyBlockContext context = new PyBlockContext(settings, createSpacingBuilder(settings), mode);
- final PyBlock block = new PyBlock(null, element.getNode(), null, Indent.getNoneIndent(), null, context);
+ final PyBlock block = new PyBlock(null, fileNode, null, Indent.getNoneIndent(), null, context);
if (DUMP_FORMATTING_AST) {
FormattingModelDumper.dumpFormattingModel(block, 2, System.out);
}
diff --git a/python/src/com/jetbrains/python/inspections/PyCompatibilityInspection.java b/python/src/com/jetbrains/python/inspections/PyCompatibilityInspection.java
index c8a40a095134..0f69f4f72a56 100644
--- a/python/src/com/jetbrains/python/inspections/PyCompatibilityInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PyCompatibilityInspection.java
@@ -200,9 +200,7 @@ public class PyCompatibilityInspection extends PyInspection {
}
for (int i = 0; i != myVersionsToProcess.size(); ++i) {
LanguageLevel languageLevel = myVersionsToProcess.get(i);
- PsiFile file = resolved.getContainingFile();
- VirtualFile virtualFile = file.getVirtualFile();
- if (virtualFile != null && ind.isInLibraryClasses(virtualFile)) {
+ if (PyBuiltinCache.getInstance(resolved).isBuiltin(resolved)) {
if (!"print".equals(name) && !myUsedImports.contains(name) && UnsupportedFeaturesUtil.BUILTINS.get(languageLevel).contains(name)) {
len = appendLanguageLevel(message, len, languageLevel);
}
diff --git a/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java b/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java
index 0cc7a4abd140..a521ed76d92f 100644
--- a/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java
@@ -72,9 +72,6 @@ public class PyStatementEffectInspection extends PyInspection {
final PyTryPart tryPart = PsiTreeUtil.getParentOfType(node, PyTryPart.class);
if (tryPart != null) {
final PyStatementList statementList = tryPart.getStatementList();
- if (statementList == null) {
- return;
- }
if (statementList.getStatements().length == 1 && statementList.getStatements()[0] == node) {
return;
}
diff --git a/python/src/com/jetbrains/python/inspections/quickfix/PyDefaultArgumentQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/PyDefaultArgumentQuickFix.java
index 31723d3aab4e..db47f17f8ea8 100644
--- a/python/src/com/jetbrains/python/inspections/quickfix/PyDefaultArgumentQuickFix.java
+++ b/python/src/com/jetbrains/python/inspections/quickfix/PyDefaultArgumentQuickFix.java
@@ -61,29 +61,36 @@ public class PyDefaultArgumentQuickFix implements LocalQuickFix {
PyStatementList list = function.getStatementList();
PyParameterList paramList = function.getParameterList();
- StringBuilder str = new StringBuilder("def foo(");
+ final StringBuilder functionText = new StringBuilder("def foo(");
int size = paramList.getParameters().length;
for (int i = 0; i != size; ++i) {
PyParameter p = paramList.getParameters()[i];
if (p == param)
- str.append(defName).append("=None");
+ functionText.append(defName).append("=None");
else
- str.append(p.getText());
+ functionText.append(p.getText());
if (i != size-1)
- str.append(", ");
+ functionText.append(", ");
+ }
+ functionText.append("):\n\tif not ").append(defName).append(":\n\t\t").append(defName).append(" = ").append(defaultValue.getText());
+ final PyStatement[] statements = list.getStatements();
+ PyStatement firstStatement = statements.length > 0 ? statements[0] : null;
+ PyFunction newFunction = elementGenerator.createFromText(LanguageLevel.forElement(function), PyFunction.class,
+ functionText.toString());
+ if (firstStatement == null) {
+ function.replace(newFunction);
+ }
+ else {
+ final PyStatement ifStatement = newFunction.getStatementList().getStatements()[0];
+ PyStringLiteralExpression docString = function.getDocStringExpression();
+ if (docString != null)
+ list.addAfter(ifStatement, firstStatement);
+ else {
+ list.addBefore(ifStatement, firstStatement);
+ }
+ paramList.replace(elementGenerator.createFromText(LanguageLevel.forElement(defaultValue),
+ PyFunction.class, functionText.toString()).getParameterList());
}
- str.append("):\n\tpass");
- PyIfStatement ifStatement = elementGenerator.createFromText(LanguageLevel.forElement(function), PyIfStatement.class,
- "if not " + defName + ": " + defName + " = " + defaultValue.getText());
-
- PyStatement firstStatement = list.getStatements()[0];
- PyStringLiteralExpression docString = function.getDocStringExpression();
- if (docString != null)
- list.addAfter(ifStatement, firstStatement);
- else
- list.addBefore(ifStatement, firstStatement);
- paramList.replace(elementGenerator.createFromText(LanguageLevel.forElement(defaultValue),
- PyFunction.class, str.toString()).getParameterList());
}
}
}
diff --git a/python/src/com/jetbrains/python/inspections/quickfix/StatementEffectFunctionCallQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/StatementEffectFunctionCallQuickFix.java
index 95daf466172e..43f4f0394015 100644
--- a/python/src/com/jetbrains/python/inspections/quickfix/StatementEffectFunctionCallQuickFix.java
+++ b/python/src/com/jetbrains/python/inspections/quickfix/StatementEffectFunctionCallQuickFix.java
@@ -18,14 +18,14 @@ package com.jetbrains.python.inspections.quickfix;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiComment;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiWhiteSpace;
+import com.intellij.psi.impl.source.tree.LeafPsiElement;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.PyNames;
-import com.jetbrains.python.psi.LanguageLevel;
-import com.jetbrains.python.psi.PyElementGenerator;
-import com.jetbrains.python.psi.PyExpression;
-import com.jetbrains.python.psi.PyReferenceExpression;
+import com.jetbrains.python.PyTokenTypes;
+import com.jetbrains.python.psi.*;
import org.jetbrains.annotations.NotNull;
/**
@@ -48,15 +48,17 @@ public class StatementEffectFunctionCallQuickFix implements LocalQuickFix {
PsiElement expression = descriptor.getPsiElement();
if (expression != null && expression.isWritable() && expression instanceof PyReferenceExpression) {
final String expressionText = expression.getText();
- if (PyNames.PRINT.equals(expressionText) || PyNames.EXEC.equals(expressionText))
- replacePrintExec(expression);
+ if (PyNames.PRINT.equals(expressionText))
+ replacePrint(expression);
+ else if (PyNames.EXEC.equals(expressionText))
+ replaceExec(expression);
else
expression.replace(PyElementGenerator.getInstance(project).createCallExpression(LanguageLevel.forElement(expression),
expressionText));
}
}
- private static void replacePrintExec(@NotNull final PsiElement expression) {
+ private static void replaceExec(@NotNull final PsiElement expression) {
final PyElementGenerator elementGenerator = PyElementGenerator.getInstance(expression.getProject());
final String expressionText = expression.getText();
final StringBuilder stringBuilder = new StringBuilder(expressionText + " (");
@@ -77,14 +79,88 @@ public class StatementEffectFunctionCallQuickFix implements LocalQuickFix {
RemoveUnnecessaryBackslashQuickFix.removeBackSlash(next);
if (whiteSpace != null) whiteSpace.delete();
+ if (next == null) {
+ stringBuilder.append(")");
+ expression.replace(elementGenerator.createFromText(LanguageLevel.forElement(expression), PyExpression.class,
+ stringBuilder.toString()));
+ return;
+ }
+ if (next instanceof PyExpressionStatement) {
+ final PyExpression expr = ((PyExpressionStatement)next).getExpression();
+ if (expr instanceof PyBinaryExpression) {
+ addInArguments(stringBuilder, (PyBinaryExpression)expr);
+ }
+ else if (expr instanceof PyTupleExpression) {
+ final PyExpression[] elements = ((PyTupleExpression)expr).getElements();
+ if (elements.length > 1) {
+ if (elements[0] instanceof PyBinaryExpression) {
+ addInArguments(stringBuilder, (PyBinaryExpression)elements[0]);
+ }
+ stringBuilder.append(", ");
+ stringBuilder.append(elements[1].getText());
+ }
+ }
+ else {
+ stringBuilder.append(next.getText());
+ }
+ }
+ else {
+ stringBuilder.append(next.getText());
+ }
+ next.delete();
+ stringBuilder.append(")");
+ expression.replace(elementGenerator.createFromText(LanguageLevel.forElement(expression), PyExpression.class,
+ stringBuilder.toString()));
+ }
+
+ private static void addInArguments(@NotNull final StringBuilder stringBuilder, @NotNull final PyBinaryExpression binaryExpression) {
+ final PsiElement operator = binaryExpression.getPsiOperator();
+ if (operator instanceof LeafPsiElement && ((LeafPsiElement)operator).getElementType() == PyTokenTypes.IN_KEYWORD) {
+ stringBuilder.append(binaryExpression.getLeftExpression().getText());
+ stringBuilder.append(", ");
+ final PyExpression rightExpression = binaryExpression.getRightExpression();
+ if (rightExpression != null)
+ stringBuilder.append(rightExpression.getText());
+ }
+ }
+
+ private static void replacePrint(@NotNull final PsiElement expression) {
+ final PyElementGenerator elementGenerator = PyElementGenerator.getInstance(expression.getProject());
+ final String expressionText = expression.getText();
+ final StringBuilder stringBuilder = new StringBuilder(expressionText + " (");
+
+ final PsiElement whiteSpace = expression.getContainingFile().findElementAt(expression.getTextOffset() + expression.getTextLength());
+ PsiElement next = null;
+ if (whiteSpace instanceof PsiWhiteSpace) {
+ final String whiteSpaceText = whiteSpace.getText();
+ if (!whiteSpaceText.contains("\n")) {
+ next = whiteSpace.getNextSibling();
+ while (next instanceof PsiWhiteSpace && whiteSpaceText.contains("\\")) {
+ next = next.getNextSibling();
+ }
+ }
+ }
+ else
+ next = whiteSpace;
+
+ RemoveUnnecessaryBackslashQuickFix.removeBackSlash(next);
+ if (whiteSpace != null) whiteSpace.delete();
+ String commentText = null;
if (next != null) {
- final String text = next.getText();
+ final PsiElement lastChild = next.getLastChild();
+ if (lastChild instanceof PsiComment) {
+ commentText = lastChild.getText();
+ }
+ final String text = next instanceof PyExpressionStatement ? ((PyExpressionStatement)next).getExpression().getText() : next.getText();
+
stringBuilder.append(text);
- if (text.endsWith(",") && PyNames.PRINT.equals(expressionText))
- stringBuilder.append(" end=' '");
+ if (text.endsWith(",")) stringBuilder.append(" end=' '");
next.delete();
}
stringBuilder.append(")");
+ if (commentText != null) {
+ stringBuilder.append(commentText);
+ }
expression.replace(elementGenerator.createFromText(LanguageLevel.forElement(expression), PyExpression.class,
stringBuilder.toString()));
}
diff --git a/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java b/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java
index 4fd58629c516..b7523caf90e7 100644
--- a/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java
+++ b/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java
@@ -755,7 +755,7 @@ public class PyUnresolvedReferencesInspection extends PyInspection {
return false;
}
- private static void addCreateMemberFromUsageFixes(PyType type, PsiReference reference, String refText, List<LocalQuickFix> actions) {
+ private void addCreateMemberFromUsageFixes(PyType type, PsiReference reference, String refText, List<LocalQuickFix> actions) {
PsiElement element = reference.getElement();
if (type instanceof PyClassTypeImpl) {
PyClass cls = ((PyClassType)type).getPyClass();
@@ -771,6 +771,7 @@ public class PyUnresolvedReferencesInspection extends PyInspection {
else if (type instanceof PyModuleType) {
PyFile file = ((PyModuleType)type).getModule();
actions.add(new AddFunctionQuickFix(refText, file.getName()));
+ addCreateClassFix(refText, element, actions);
}
}
diff --git a/python/src/com/jetbrains/python/module/PyContentEntriesEditor.java b/python/src/com/jetbrains/python/module/PyContentEntriesEditor.java
new file mode 100644
index 000000000000..8ea8b26c0b5f
--- /dev/null
+++ b/python/src/com/jetbrains/python/module/PyContentEntriesEditor.java
@@ -0,0 +1,367 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python.module;
+
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.CustomShortcutSet;
+import com.intellij.openapi.actionSystem.Presentation;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.options.ConfigurationException;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.ContentEntry;
+import com.intellij.openapi.roots.ContentFolder;
+import com.intellij.openapi.roots.ModifiableRootModel;
+import com.intellij.openapi.roots.impl.ContentEntryImpl;
+import com.intellij.openapi.roots.impl.ContentFolderBaseImpl;
+import com.intellij.openapi.roots.ui.configuration.*;
+import com.intellij.openapi.roots.ui.configuration.actions.ContentEntryEditingAction;
+import com.intellij.openapi.util.Comparing;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.vfs.VfsUtilCore;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.openapi.vfs.pointers.VirtualFilePointer;
+import com.intellij.openapi.vfs.pointers.VirtualFilePointerListener;
+import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager;
+import com.intellij.ui.JBColor;
+import com.intellij.util.EventDispatcher;
+import com.intellij.util.containers.MultiMap;
+import com.jetbrains.python.templateLanguages.TemplatesService;
+import icons.PythonIcons;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.jps.model.module.JpsModuleSourceRootType;
+
+import javax.swing.*;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.tree.TreeCellRenderer;
+import java.awt.*;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+import java.util.ArrayList;
+import java.util.List;
+
+public class PyContentEntriesEditor extends CommonContentEntriesEditor {
+ private static final Color TEMPLATES_COLOR = JBColor.MAGENTA;
+ private final MultiMap<ContentEntry, VirtualFilePointer> myTemplateRoots = new MultiMap<ContentEntry, VirtualFilePointer>();
+ private final Module myModule;
+ private Disposable myFilePointersDisposable;
+
+ private final VirtualFilePointerListener DUMMY_LISTENER = new VirtualFilePointerListener() {
+ @Override
+ public void beforeValidityChanged(@NotNull VirtualFilePointer[] pointers) {
+ }
+
+ @Override
+ public void validityChanged(@NotNull VirtualFilePointer[] pointers) {
+ }
+ };
+
+ public PyContentEntriesEditor(Module module, ModuleConfigurationState moduleConfigurationState,
+ JpsModuleSourceRootType<?>... rootTypes) {
+ super(module.getName(), moduleConfigurationState, rootTypes);
+ myModule = module;
+ reset();
+ }
+
+ @Override
+ protected ContentEntryTreeEditor createContentEntryTreeEditor(Project project) {
+ return new MyContentEntryTreeEditor(project, getEditHandlers());
+ }
+
+ @Override
+ protected List<ContentEntry> addContentEntries(VirtualFile[] files) {
+ List<ContentEntry> entries = super.addContentEntries(files);
+ addContentEntryPanels(entries.toArray(new ContentEntry[entries.size()]));
+ return entries;
+ }
+
+ @Override
+ public void reset() {
+ if (myFilePointersDisposable != null) {
+ Disposer.dispose(myFilePointersDisposable);
+ }
+ myTemplateRoots.clear();
+
+ myFilePointersDisposable = Disposer.newDisposable();
+ final TemplatesService instance = TemplatesService.getInstance(myModule);
+ if (instance != null) {
+ final List<VirtualFile> folders = instance.getTemplateFolders();
+ for (VirtualFile folder : folders) {
+ ContentEntry contentEntry = findContentEntryForFile(folder);
+ if (contentEntry != null) {
+ myTemplateRoots.putValue(contentEntry, VirtualFilePointerManager.getInstance().create(folder, myFilePointersDisposable,
+ DUMMY_LISTENER));
+ }
+ }
+ }
+
+ if (myRootTreeEditor != null) {
+ ContentEntryEditor editor = myRootTreeEditor.getContentEntryEditor();
+ if(editor!=null) editor.update();
+ myRootTreeEditor.update();
+ }
+ }
+
+ @Nullable
+ private ContentEntry findContentEntryForFile(VirtualFile virtualFile) {
+ for (ContentEntry contentEntry : getModel().getContentEntries()) {
+ final VirtualFile file = contentEntry.getFile();
+ if (file != null && VfsUtilCore.isAncestor(file, virtualFile, false)) {
+ return contentEntry;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public void disposeUIResources() {
+ super.disposeUIResources();
+ if (myFilePointersDisposable != null) {
+ Disposer.dispose(myFilePointersDisposable);
+ }
+ }
+
+ @Override
+ public void apply() throws ConfigurationException {
+ super.apply();
+ List<VirtualFile> templateRoots = getCurrentState();
+ TemplatesService.getInstance(myModule).setTemplateFolders(templateRoots.toArray(new VirtualFile[templateRoots.size()]));
+ }
+
+ private List<VirtualFile> getCurrentState() {
+ List<VirtualFile> result = new ArrayList<VirtualFile>();
+ for (ContentEntry entry : myTemplateRoots.keySet()) {
+ for (VirtualFilePointer filePointer : myTemplateRoots.get(entry)) {
+ result.add(filePointer.getFile());
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public boolean isModified() {
+ if (super.isModified()) return true;
+ final TemplatesService templatesService = TemplatesService.getInstance(myModule);
+ if (templatesService != null) {
+ List<VirtualFile> original = templatesService.getTemplateFolders();
+ List<VirtualFile> current = getCurrentState();
+
+ if (!Comparing.haveEqualElements(original, current)) return true;
+
+ }
+ return false;
+ }
+
+ @Override
+ protected MyContentEntryEditor createContentEntryEditor(String contentEntryUrl) {
+ return new MyContentEntryEditor(contentEntryUrl, getEditHandlers());
+ }
+
+ protected class MyContentEntryEditor extends ContentEntryEditor {
+ private final EventDispatcher<ChangeListener> myEventDispatcher = EventDispatcher.create(ChangeListener.class);
+
+ public MyContentEntryEditor(String contentEntryUrl, List<ModuleSourceRootEditHandler<?>> handlers) {
+ super(contentEntryUrl, handlers);
+ }
+
+ @Override
+ protected ModifiableRootModel getModel() {
+ return PyContentEntriesEditor.this.getModel();
+ }
+
+ public void addListener(ChangeListener changeListener) {
+ myEventDispatcher.addListener(changeListener);
+ }
+
+ public void removeListener(ChangeListener changeListener) {
+ myEventDispatcher.removeListener(changeListener);
+ }
+
+ @Override
+ protected ContentRootPanel createContentRootPane() {
+ return new MyContentRootPanel();
+ }
+
+ @Override
+ public void deleteContentFolder(ContentEntry contentEntry, ContentFolder folder) {
+ if (folder instanceof TemplateRootFolder) {
+ final VirtualFile file = folder.getFile();
+ if (file != null) {
+ removeTemplateRoot(file);
+ }
+ }
+ else {
+ super.deleteContentFolder(contentEntry, folder);
+ }
+ }
+
+ public void addTemplateRoot(@NotNull final VirtualFile file) {
+ final VirtualFilePointer root = VirtualFilePointerManager.getInstance().create(file, myFilePointersDisposable, DUMMY_LISTENER);
+ myTemplateRoots.putValue(getContentEntry(), root);
+ myEventDispatcher.getMulticaster().stateChanged(new ChangeEvent(this));
+ update();
+ }
+
+ public void removeTemplateRoot(@NotNull final VirtualFile file) {
+ final VirtualFilePointer root = getTemplateRoot(file);
+ if (root != null) {
+ myTemplateRoots.remove(getContentEntry(), root);
+ myEventDispatcher.getMulticaster().stateChanged(new ChangeEvent(this));
+ update();
+ }
+ }
+
+ public boolean hasTemplateRoot(@NotNull final VirtualFile file) {
+ return getTemplateRoot(file) != null;
+ }
+
+ @Nullable
+ public VirtualFilePointer getTemplateRoot(@NotNull final VirtualFile file) {
+ for (VirtualFilePointer filePointer : myTemplateRoots.get(getContentEntry())) {
+ if (Comparing.equal(filePointer.getFile(), file)) {
+ return filePointer;
+ }
+ }
+ return null;
+ }
+
+ protected class MyContentRootPanel extends ContentRootPanel {
+ public MyContentRootPanel() {
+ super(MyContentEntryEditor.this, getEditHandlers());
+ }
+
+ @Override
+ @NotNull
+ protected ContentEntryImpl getContentEntry() {
+ //noinspection ConstantConditions
+ return (ContentEntryImpl)MyContentEntryEditor.this.getContentEntry();
+ }
+
+ @Override
+ protected void addFolderGroupComponents() {
+ super.addFolderGroupComponents();
+ if (!myTemplateRoots.get(getContentEntry()).isEmpty()) {
+ final List<TemplateRootFolder> folders = new ArrayList<TemplateRootFolder>(myTemplateRoots.size());
+ for (VirtualFilePointer root : myTemplateRoots.get(getContentEntry())) {
+ folders.add(new TemplateRootFolder(root, getContentEntry()));
+ }
+ final JComponent sourcesComponent = createFolderGroupComponent("Template Folders",
+ folders.toArray(new ContentFolder[folders.size()]),
+ TEMPLATES_COLOR, null);
+ this.add(sourcesComponent, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.NORTH,
+ GridBagConstraints.HORIZONTAL, new Insets(0, 0, 10, 0), 0, 0));
+ }
+ }
+ }
+ }
+
+ private static class MyContentEntryTreeEditor extends ContentEntryTreeEditor {
+
+ private final ChangeListener myListener = new ChangeListener() {
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ update();
+ }
+ };
+
+ public MyContentEntryTreeEditor(Project project, List<ModuleSourceRootEditHandler<?>> handlers) {
+ super(project, handlers);
+ }
+
+ @Override
+ public void setContentEntryEditor(ContentEntryEditor newEditor) {
+ PyContentEntriesEditor.MyContentEntryEditor existingEditor = getContentEntryEditor();
+ if (Comparing.equal(existingEditor, newEditor)) {
+ return;
+ }
+ if (existingEditor != null) {
+ existingEditor.removeListener(myListener);
+ }
+ if (newEditor != null) {
+ ((PyContentEntriesEditor.MyContentEntryEditor)newEditor).addListener(myListener);
+ }
+ super.setContentEntryEditor(newEditor);
+ }
+
+ @Override
+ public PyContentEntriesEditor.MyContentEntryEditor getContentEntryEditor() {
+ return (PyContentEntriesEditor.MyContentEntryEditor)super.getContentEntryEditor();
+ }
+
+ @Override
+ protected void createEditingActions() {
+ super.createEditingActions();
+
+ ContentEntryEditingAction a = new ContentEntryEditingAction(myTree) {
+ {
+ final Presentation templatePresentation = getTemplatePresentation();
+ templatePresentation.setText("Templates");
+ templatePresentation.setDescription("Template Folders");
+ templatePresentation.setIcon(PythonIcons.Python.TemplateRoot);
+ }
+
+ @Override
+ public boolean isSelected(AnActionEvent e) {
+ final VirtualFile[] selectedFiles = getSelectedFiles();
+ return selectedFiles.length != 0 && getContentEntryEditor().hasTemplateRoot(selectedFiles[0]);
+ }
+
+ @Override
+ public void setSelected(AnActionEvent e, boolean isSelected) {
+ final VirtualFile[] selectedFiles = getSelectedFiles();
+ assert selectedFiles.length != 0;
+
+ for (VirtualFile selectedFile : selectedFiles) {
+ boolean wasSelected = getContentEntryEditor().hasTemplateRoot(selectedFile);
+ if (isSelected) {
+ if (!wasSelected) {
+ getContentEntryEditor().addTemplateRoot(selectedFile);
+ }
+ }
+ else {
+ if (wasSelected) {
+ getContentEntryEditor().removeTemplateRoot(selectedFile);
+ }
+ }
+ }
+ }
+ };
+ myEditingActionsGroup.add(a);
+ a.registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_R, InputEvent.ALT_MASK)), myTree);
+ }
+
+ @Override
+ protected TreeCellRenderer getContentEntryCellRenderer() {
+ return new ContentEntryTreeCellRenderer(this, getEditHandlers()) {
+ @Override
+ protected Icon updateIcon(final ContentEntry entry, final VirtualFile file, final Icon originalIcon) {
+ if (getContentEntryEditor().hasTemplateRoot(file)) {
+ return PythonIcons.Python.TemplateRoot;
+ }
+ return super.updateIcon(entry, file, originalIcon);
+ }
+ };
+ }
+ }
+ private static class TemplateRootFolder extends ContentFolderBaseImpl {
+ protected TemplateRootFolder(@NotNull VirtualFilePointer filePointer, @NotNull ContentEntryImpl contentEntry) {
+ super(filePointer, contentEntry);
+ }
+ }
+
+}
diff --git a/python/src/com/jetbrains/python/psi/impl/PyAnnotationImpl.java b/python/src/com/jetbrains/python/psi/impl/PyAnnotationImpl.java
index f3c806dac7c5..f8a4d482c2f2 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyAnnotationImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyAnnotationImpl.java
@@ -16,14 +16,16 @@
package com.jetbrains.python.psi.impl;
import com.intellij.lang.ASTNode;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiPolyVariantReference;
import com.jetbrains.python.PyElementTypes;
import com.jetbrains.python.psi.PyAnnotation;
-import com.jetbrains.python.psi.PyClass;
import com.jetbrains.python.psi.PyExpression;
-import com.jetbrains.python.psi.PyReferenceExpression;
import com.jetbrains.python.psi.stubs.PyAnnotationStub;
+import com.jetbrains.python.psi.types.PyClassLikeType;
+import com.jetbrains.python.psi.types.PyNoneType;
+import com.jetbrains.python.psi.types.PyType;
+import com.jetbrains.python.psi.types.TypeEvalContext;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
/**
* @author yole
@@ -37,19 +39,26 @@ public class PyAnnotationImpl extends PyBaseElementImpl<PyAnnotationStub> implem
super(stub, PyElementTypes.ANNOTATION);
}
+ @Nullable
@Override
public PyExpression getValue() {
return findChildByClass(PyExpression.class);
}
+ @Nullable
@Override
- public PyClass resolveToClass() {
- PyExpression expr = getValue();
- if (expr instanceof PyReferenceExpression) {
- final PsiPolyVariantReference reference = ((PyReferenceExpression)expr).getReference();
- final PsiElement result = reference.resolve();
- if (result instanceof PyClass) {
- return (PyClass) result;
+ public PyType getType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) {
+ final PyExpression value = getValue();
+ if (value != null) {
+ final PyType type = context.getType(value);
+ if (type instanceof PyClassLikeType) {
+ final PyClassLikeType classType = (PyClassLikeType)type;
+ if (classType.isDefinition()) {
+ return classType.toInstance();
+ }
+ }
+ else if (type instanceof PyNoneType) {
+ return type;
}
}
return null;
diff --git a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java
index 7538fbae2fd2..bb2104fc0c77 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java
@@ -20,7 +20,6 @@ import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.NotNullLazyValue;
-import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.search.LocalSearchScope;
@@ -187,6 +186,11 @@ public class PyClassImpl extends PyPresentableElementImpl<PyClassStub> implement
}
}
}
+ // Heuristic: unfold Foo[Bar] to Foo for subscription expressions for superclasses
+ else if (expression instanceof PySubscriptionExpression) {
+ final PySubscriptionExpression subscriptionExpr = (PySubscriptionExpression)expression;
+ return subscriptionExpr.getOperand();
+ }
return expression;
}
@@ -237,27 +241,7 @@ public class PyClassImpl extends PyPresentableElementImpl<PyClassStub> implement
@Nullable
public String getQualifiedName() {
- String name = getName();
- final PyClassStub stub = getStub();
- PsiElement ancestor = stub != null ? stub.getParentStub().getPsi() : getParent();
- while (!(ancestor instanceof PsiFile)) {
- if (ancestor == null) return name; // can this happen?
- if (ancestor instanceof PyClass) {
- name = ((PyClass)ancestor).getName() + "." + name;
- }
- ancestor = stub != null ? ((StubBasedPsiElement)ancestor).getStub().getParentStub().getPsi() : ancestor.getParent();
- }
-
- PsiFile psiFile = ((PsiFile)ancestor).getOriginalFile();
- final PyFile builtins = PyBuiltinCache.getInstance(this).getBuiltinsFile();
- if (!psiFile.equals(builtins)) {
- VirtualFile vFile = psiFile.getVirtualFile();
- if (vFile != null) {
- final String packageName = QualifiedNameFinder.findShortestImportableName(this, vFile);
- return packageName + "." + name;
- }
- }
- return name;
+ return QualifiedNameFinder.getQualifiedName(this);
}
@Override
diff --git a/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java
index 2531b37bf8b2..86f84abb7fb6 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java
@@ -184,11 +184,11 @@ public class PyFunctionImpl extends PyPresentableElementImpl<PyFunctionStub> imp
}
}
if (context.maySwitchToAST(this) && LanguageLevel.forElement(this).isAtLeast(LanguageLevel.PYTHON30)) {
- PyAnnotation anno = getAnnotation();
- if (anno != null) {
- PyClass pyClass = anno.resolveToClass();
- if (pyClass != null) {
- return new PyClassTypeImpl(pyClass, false);
+ final PyAnnotation annotation = getAnnotation();
+ if (annotation != null) {
+ final PyType type = context.getType(annotation);
+ if (type != null) {
+ return type;
}
}
}
@@ -571,7 +571,7 @@ public class PyFunctionImpl extends PyPresentableElementImpl<PyFunctionStub> imp
@Override
public PyAnnotation getAnnotation() {
- return findChildByClass(PyAnnotation.class);
+ return getStubOrPsiChild(PyElementTypes.ANNOTATION);
}
@NotNull
@@ -699,21 +699,6 @@ public class PyFunctionImpl extends PyPresentableElementImpl<PyFunctionStub> imp
@Nullable
@Override
public String getQualifiedName() {
- String name = getName();
- if (name == null) {
- return null;
- }
- PyClass containingClass = getContainingClass();
- if (containingClass != null) {
- return containingClass.getQualifiedName() + "." + name;
- }
- if (PsiTreeUtil.getStubOrPsiParent(this) instanceof PyFile) {
- VirtualFile virtualFile = getContainingFile().getVirtualFile();
- if (virtualFile != null) {
- final String packageName = QualifiedNameFinder.findShortestImportableName(this, virtualFile);
- return packageName + "." + name;
- }
- }
- return null;
+ return QualifiedNameFinder.getQualifiedName(this);
}
}
diff --git a/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java b/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java
index bf792fef0dae..cc9178c07f9e 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java
@@ -181,11 +181,11 @@ public class PyNamedParameterImpl extends PyPresentableElementImpl<PyNamedParame
PyParameterList parameterList = (PyParameterList)parent;
PyFunction func = parameterList.getContainingFunction();
if (func != null) {
- PyAnnotation anno = getAnnotation();
- if (anno != null) {
- final PyClass pyClass = anno.resolveToClass();
- if (pyClass != null) {
- return new PyClassTypeImpl(pyClass, false);
+ final PyAnnotation annotation = getAnnotation();
+ if (annotation != null) {
+ final PyType type = context.getType(annotation);
+ if (type != null) {
+ return type;
}
}
StructuredDocString docString = func.getStructuredDocString();
diff --git a/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java
index 545e8e86cba1..3805c8df525e 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java
@@ -43,6 +43,7 @@ import com.jetbrains.python.psi.impl.references.PyQualifiedReference;
import com.jetbrains.python.psi.impl.references.PyTargetReference;
import com.jetbrains.python.psi.impl.stubs.CustomTargetExpressionStub;
import com.jetbrains.python.psi.resolve.PyResolveContext;
+import com.jetbrains.python.psi.resolve.QualifiedNameFinder;
import com.jetbrains.python.psi.resolve.RatedResolveResult;
import com.jetbrains.python.psi.stubs.PyClassStub;
import com.jetbrains.python.psi.stubs.PyFunctionStub;
@@ -707,4 +708,10 @@ public class PyTargetExpressionImpl extends PyPresentableElementImpl<PyTargetExp
super.subtreeChanged();
myQualifiedName = null;
}
+
+ @Nullable
+ @Override
+ public String getQualifiedName() {
+ return QualifiedNameFinder.getQualifiedName(this);
+ }
}
diff --git a/python/src/com/jetbrains/python/psi/resolve/PyResolveUtil.java b/python/src/com/jetbrains/python/psi/resolve/PyResolveUtil.java
index 838a4dbcc75a..f207169df77f 100644
--- a/python/src/com/jetbrains/python/psi/resolve/PyResolveUtil.java
+++ b/python/src/com/jetbrains/python/psi/resolve/PyResolveUtil.java
@@ -101,7 +101,13 @@ public class PyResolveUtil {
@Nullable PsiElement roof) {
// Use real context here to enable correct completion and resolve in case of PyExpressionCodeFragment!!!
final PsiElement realContext = PyPsiUtils.getRealContext(element);
- final ScopeOwner originalOwner = ScopeUtil.getScopeOwner(realContext);
+ final ScopeOwner originalOwner;
+ if (realContext != element && realContext instanceof PyFile) {
+ originalOwner = (PyFile)realContext;
+ }
+ else {
+ originalOwner = ScopeUtil.getScopeOwner(realContext);
+ }
final PsiElement parent = element.getParent();
final boolean isGlobalOrNonlocal = parent instanceof PyGlobalStatement || parent instanceof PyNonlocalStatement;
ScopeOwner owner = originalOwner;
diff --git a/python/src/com/jetbrains/python/psi/resolve/QualifiedNameFinder.java b/python/src/com/jetbrains/python/psi/resolve/QualifiedNameFinder.java
index 97a15da105c3..1c081eff9356 100644
--- a/python/src/com/jetbrains/python/psi/resolve/QualifiedNameFinder.java
+++ b/python/src/com/jetbrains/python/psi/resolve/QualifiedNameFinder.java
@@ -24,10 +24,14 @@ import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.jetbrains.python.PyNames;
+import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
+import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
import com.jetbrains.python.psi.PyClass;
+import com.jetbrains.python.psi.PyElement;
import com.jetbrains.python.psi.PyFile;
import com.jetbrains.python.psi.PyFunction;
import com.intellij.psi.util.QualifiedName;
+import com.jetbrains.python.psi.impl.PyBuiltinCache;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -156,6 +160,36 @@ public class QualifiedNameFinder {
return qname;
}
+ @Nullable
+ public static String getQualifiedName(@NotNull PyElement element) {
+ final String name = element.getName();
+ if (name != null) {
+ final ScopeOwner owner = ScopeUtil.getScopeOwner(element);
+ final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(element);
+ if (owner instanceof PyClass) {
+ final String classQName = ((PyClass)owner).getQualifiedName();
+ if (classQName != null) {
+ return classQName + "." + name;
+ }
+ }
+ else if (owner instanceof PyFile) {
+ if (builtinCache.isBuiltin(element)) {
+ return name;
+ }
+ else {
+ final VirtualFile virtualFile = ((PyFile)owner).getVirtualFile();
+ if (virtualFile != null) {
+ final String fileQName = findShortestImportableName(element, virtualFile);
+ if (fileQName != null) {
+ return fileQName + "." + name;
+ }
+ }
+ }
+ }
+ }
+ return null;
+ }
+
/**
* Tries to find roots that contain given vfile, and among them the root that contains at the smallest depth.
* For equal depth source root is in preference to library.
diff --git a/python/src/com/jetbrains/python/psi/stubs/PyClassNameIndex.java b/python/src/com/jetbrains/python/psi/stubs/PyClassNameIndex.java
index 814f450df8d2..14e1546c7e30 100644
--- a/python/src/com/jetbrains/python/psi/stubs/PyClassNameIndex.java
+++ b/python/src/com/jetbrains/python/psi/stubs/PyClassNameIndex.java
@@ -57,7 +57,7 @@ public class PyClassNameIndex extends StringStubIndexExtension<PyClass> {
int pos = qName.lastIndexOf(".");
String shortName = pos > 0 ? qName.substring(pos+1) : qName;
for (PyClass pyClass : find(shortName, project, scope)) {
- if (pyClass.getQualifiedName().equals(qName)) {
+ if (qName.equals(pyClass.getQualifiedName())) {
return pyClass;
}
}
diff --git a/python/src/com/jetbrains/python/psi/types/PyFunctionType.java b/python/src/com/jetbrains/python/psi/types/PyFunctionType.java
index 4bdbae69d83d..fe3633449b74 100644
--- a/python/src/com/jetbrains/python/psi/types/PyFunctionType.java
+++ b/python/src/com/jetbrains/python/psi/types/PyFunctionType.java
@@ -108,10 +108,14 @@ public class PyFunctionType implements PyCallableType {
*/
@Nullable
private PyClassTypeImpl selectFakeType(@Nullable PyExpression location, @NotNull TypeEvalContext context) {
- if (location instanceof PyReferenceExpression && isBoundMethodReference(((PyReferenceExpression)location), context)) {
- return PyBuiltinCache.getInstance(getCallable()).getObjectType(PyNames.FAKE_METHOD);
+ final String fakeClassName;
+ if (location instanceof PyReferenceExpression && isBoundMethodReference((PyReferenceExpression)location, context)) {
+ fakeClassName = PyNames.FAKE_METHOD;
}
- return PyBuiltinCache.getInstance(getCallable()).getObjectType(PyNames.FAKE_FUNCTION);
+ else {
+ fakeClassName = PyNames.FAKE_FUNCTION;
+ }
+ return PyBuiltinCache.getInstance(getCallable()).getObjectType(fakeClassName);
}
private boolean isBoundMethodReference(@NotNull PyReferenceExpression location, @NotNull TypeEvalContext context) {
diff --git a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java
index 9881d6cc106c..2e7c58c8201c 100644
--- a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java
+++ b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java
@@ -428,41 +428,39 @@ public class PyTypeChecker {
public static AnalyzeCallResults analyzeCall(@NotNull PyBinaryExpression expr, @NotNull TypeEvalContext context) {
final PsiPolyVariantReference ref = expr.getReference(PyResolveContext.noImplicits().withTypeEvalContext(context));
final ResolveResult[] resolveResult;
- if (ref != null) {
- resolveResult = ref.multiResolve(false);
- AnalyzeCallResults firstResults = null;
- for (ResolveResult result : resolveResult) {
- final PsiElement resolved = result.getElement();
- if (resolved instanceof PyTypedElement) {
- final PyTypedElement typedElement = (PyTypedElement)resolved;
- final PyType type = context.getType(typedElement);
- if (!(type instanceof PyFunctionType)) {
- return null;
- }
- final Callable callable = ((PyFunctionType)type).getCallable();
- final boolean isRight = PyNames.isRightOperatorName(typedElement.getName());
- final PyExpression arg = isRight ? expr.getLeftExpression() : expr.getRightExpression();
- final PyExpression receiver = isRight ? expr.getRightExpression() : expr.getLeftExpression();
- final PyParameter[] parameters = callable.getParameterList().getParameters();
- if (parameters.length >= 2) {
- final PyNamedParameter param = parameters[1].getAsNamed();
- if (arg != null && param != null) {
- final Map<PyExpression, PyNamedParameter> arguments = new LinkedHashMap<PyExpression, PyNamedParameter>();
- arguments.put(arg, param);
- final AnalyzeCallResults results = new AnalyzeCallResults(callable, receiver, arguments);
- if (firstResults == null) {
- firstResults = results;
- }
- if (match(context.getType(param), context.getType(arg), context)) {
- return results;
- }
+ resolveResult = ref.multiResolve(false);
+ AnalyzeCallResults firstResults = null;
+ for (ResolveResult result : resolveResult) {
+ final PsiElement resolved = result.getElement();
+ if (resolved instanceof PyTypedElement) {
+ final PyTypedElement typedElement = (PyTypedElement)resolved;
+ final PyType type = context.getType(typedElement);
+ if (!(type instanceof PyFunctionType)) {
+ return null;
+ }
+ final Callable callable = ((PyFunctionType)type).getCallable();
+ final boolean isRight = PyNames.isRightOperatorName(typedElement.getName());
+ final PyExpression arg = isRight ? expr.getLeftExpression() : expr.getRightExpression();
+ final PyExpression receiver = isRight ? expr.getRightExpression() : expr.getLeftExpression();
+ final PyParameter[] parameters = callable.getParameterList().getParameters();
+ if (parameters.length >= 2) {
+ final PyNamedParameter param = parameters[1].getAsNamed();
+ if (arg != null && param != null) {
+ final Map<PyExpression, PyNamedParameter> arguments = new LinkedHashMap<PyExpression, PyNamedParameter>();
+ arguments.put(arg, param);
+ final AnalyzeCallResults results = new AnalyzeCallResults(callable, receiver, arguments);
+ if (firstResults == null) {
+ firstResults = results;
+ }
+ if (match(context.getType(param), context.getType(arg), context)) {
+ return results;
}
}
}
}
- if (firstResults != null) {
- return firstResults;
- }
+ }
+ if (firstResults != null) {
+ return firstResults;
}
return null;
}
@@ -471,22 +469,20 @@ public class PyTypeChecker {
public static AnalyzeCallResults analyzeCall(@NotNull PySubscriptionExpression expr, @NotNull TypeEvalContext context) {
final PsiReference ref = expr.getReference(PyResolveContext.noImplicits().withTypeEvalContext(context));
final PsiElement resolved;
- if (ref != null) {
- resolved = ref.resolve();
- if (resolved instanceof PyTypedElement) {
- final PyType type = context.getType((PyTypedElement)resolved);
- if (type instanceof PyFunctionType) {
- final Callable callable = ((PyFunctionType)type).getCallable();
- final PyParameter[] parameters = callable.getParameterList().getParameters();
- if (parameters.length == 2) {
- final PyNamedParameter param = parameters[1].getAsNamed();
- if (param != null) {
- final Map<PyExpression, PyNamedParameter> arguments = new LinkedHashMap<PyExpression, PyNamedParameter>();
- final PyExpression arg = expr.getIndexExpression();
- if (arg != null) {
- arguments.put(arg, param);
- return new AnalyzeCallResults(callable, expr.getOperand(), arguments);
- }
+ resolved = ref.resolve();
+ if (resolved instanceof PyTypedElement) {
+ final PyType type = context.getType((PyTypedElement)resolved);
+ if (type instanceof PyFunctionType) {
+ final Callable callable = ((PyFunctionType)type).getCallable();
+ final PyParameter[] parameters = callable.getParameterList().getParameters();
+ if (parameters.length == 2) {
+ final PyNamedParameter param = parameters[1].getAsNamed();
+ if (param != null) {
+ final Map<PyExpression, PyNamedParameter> arguments = new LinkedHashMap<PyExpression, PyNamedParameter>();
+ final PyExpression arg = expr.getIndexExpression();
+ if (arg != null) {
+ arguments.put(arg, param);
+ return new AnalyzeCallResults(callable, expr.getOperand(), arguments);
}
}
}
diff --git a/python/src/com/jetbrains/python/refactoring/PyReplaceExpressionUtil.java b/python/src/com/jetbrains/python/refactoring/PyReplaceExpressionUtil.java
index 2cebb3ec2720..4a8d2b9d8551 100644
--- a/python/src/com/jetbrains/python/refactoring/PyReplaceExpressionUtil.java
+++ b/python/src/com/jetbrains/python/refactoring/PyReplaceExpressionUtil.java
@@ -61,21 +61,26 @@ public class PyReplaceExpressionUtil implements PyElementTypes {
private PyReplaceExpressionUtil() {}
+ /**
+ * @param oldExpr old expression that will be substituted
+ * @param newExpr new expression to substitute with
+ * @return whether new expression should be wrapped in parenthesis to preserve original semantics
+ */
public static boolean isNeedParenthesis(@NotNull final PyElement oldExpr, @NotNull final PyElement newExpr) {
final PyElement parentExpr = (PyElement)oldExpr.getParent();
if (parentExpr instanceof PyArgumentList) {
return newExpr instanceof PyTupleExpression;
}
- if (!(parentExpr instanceof PyExpression)) {
+ if (parentExpr instanceof PyParenthesizedExpression || !(parentExpr instanceof PyExpression)) {
return false;
}
- int newPriority = getExpressionPriority(newExpr);
- int parentPriority = getExpressionPriority(parentExpr);
+ final int newPriority = getExpressionPriority(newExpr);
+ final int parentPriority = getExpressionPriority(parentExpr);
if (parentPriority > newPriority) {
return true;
} else if (parentPriority == newPriority && parentPriority != 0) {
if (parentExpr instanceof PyBinaryExpression) {
- PyBinaryExpression binaryExpression = (PyBinaryExpression)parentExpr;
+ final PyBinaryExpression binaryExpression = (PyBinaryExpression)parentExpr;
if (isNotAssociative(binaryExpression) && oldExpr.equals(binaryExpression.getRightExpression())) {
return true;
}
diff --git a/python/src/com/jetbrains/python/refactoring/inline/PyInlineLocalHandler.java b/python/src/com/jetbrains/python/refactoring/inline/PyInlineLocalHandler.java
index 575399c61ceb..4f2dc65a22d3 100644
--- a/python/src/com/jetbrains/python/refactoring/inline/PyInlineLocalHandler.java
+++ b/python/src/com/jetbrains/python/refactoring/inline/PyInlineLocalHandler.java
@@ -29,18 +29,19 @@ import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.wm.WindowManager;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiFile;
-import com.intellij.psi.PsiReference;
-import com.intellij.psi.PsiWhiteSpace;
+import com.intellij.psi.*;
+import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.refactoring.RefactoringBundle;
import com.intellij.refactoring.util.CommonRefactoringUtil;
import com.intellij.refactoring.util.RefactoringMessageDialog;
+import com.intellij.util.Function;
import com.intellij.util.Query;
+import com.intellij.util.containers.ContainerUtil;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.PythonLanguage;
@@ -51,6 +52,7 @@ import com.jetbrains.python.psi.impl.PyAugAssignmentStatementImpl;
import com.jetbrains.python.psi.impl.PyPsiUtils;
import com.jetbrains.python.refactoring.PyDefUseUtil;
import com.jetbrains.python.refactoring.PyReplaceExpressionUtil;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
@@ -61,7 +63,7 @@ import java.util.List;
*/
public class PyInlineLocalHandler extends InlineActionHandler {
private static final Logger LOG = Logger.getInstance(PyInlineLocalHandler.class.getName());
-
+
private static final String REFACTORING_NAME = RefactoringBundle.message("inline.variable.title");
private static final Pair<PyStatement, Boolean> EMPTY_DEF_RESULT = Pair.create(null, false);
private static final String HELP_ID = "python.reference.inline";
@@ -111,21 +113,21 @@ public class PyInlineLocalHandler extends InlineActionHandler {
final PyStatement def = defPair.first;
if (def == null || getValue(def) == null){
final String key = defPair.second ? "variable.has.no.dominating.definition" : "variable.has.no.initializer";
- String message = RefactoringBundle.getCannotRefactorMessage(RefactoringBundle.message(key, localName));
+ final String message = RefactoringBundle.getCannotRefactorMessage(RefactoringBundle.message(key, localName));
CommonRefactoringUtil.showErrorHint(project, editor, message, REFACTORING_NAME, HELP_ID);
return;
}
if (def instanceof PyAssignmentStatement && ((PyAssignmentStatement)def).getTargets().length > 1){
highlightManager.addOccurrenceHighlights(editor, new PsiElement[] {def}, writeAttributes, true, null);
- String message = RefactoringBundle.getCannotRefactorMessage(PyBundle.message("refactoring.inline.local.multiassignment", localName));
+ final String message = RefactoringBundle.getCannotRefactorMessage(PyBundle.message("refactoring.inline.local.multiassignment", localName));
CommonRefactoringUtil.showErrorHint(project, editor, message, REFACTORING_NAME, HELP_ID);
return;
}
final PsiElement[] refsToInline = PyDefUseUtil.getPostRefs(containerBlock, local, getObject(def));
if (refsToInline.length == 0) {
- String message = RefactoringBundle.message("variable.is.never.used", localName);
+ final String message = RefactoringBundle.message("variable.is.never.used", localName);
CommonRefactoringUtil.showErrorHint(project, editor, message, REFACTORING_NAME, HELP_ID);
return;
}
@@ -133,11 +135,10 @@ public class PyInlineLocalHandler extends InlineActionHandler {
final TextAttributes attributes = EditorColorsManager.getInstance().getGlobalScheme().getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES);
if (editor != null && !ApplicationManager.getApplication().isUnitTestMode()) {
highlightManager.addOccurrenceHighlights(editor, refsToInline, attributes, true, null);
- int occurrencesCount = refsToInline.length;
- String occurencesString = RefactoringBundle.message("occurrences.string", occurrencesCount);
- final String promptKey = "inline.local.variable.prompt";
- final String question = RefactoringBundle.message(promptKey, localName) + " " + occurencesString;
- RefactoringMessageDialog dialog = new RefactoringMessageDialog(REFACTORING_NAME, question, HELP_ID, "OptionPane.questionIcon", true, project);
+ final int occurrencesCount = refsToInline.length;
+ final String occurrencesString = RefactoringBundle.message("occurrences.string", occurrencesCount);
+ final String question = RefactoringBundle.message("inline.local.variable.prompt", localName) + " " + occurrencesString;
+ final RefactoringMessageDialog dialog = new RefactoringMessageDialog(REFACTORING_NAME, question, HELP_ID, "OptionPane.questionIcon", true, project);
dialog.show();
if (!dialog.isOK()){
WindowManager.getInstance().getStatusBar(project).setInfo(RefactoringBundle.message("press.escape.to.remove.the.highlighting"));
@@ -145,11 +146,11 @@ public class PyInlineLocalHandler extends InlineActionHandler {
}
}
- PsiFile workingFile = local.getContainingFile();
+ final PsiFile workingFile = local.getContainingFile();
for (PsiElement ref : refsToInline) {
final PsiFile otherFile = ref.getContainingFile();
if (!otherFile.equals(workingFile)) {
- String message = RefactoringBundle.message("variable.is.referenced.in.multiple.files", localName);
+ final String message = RefactoringBundle.message("variable.is.referenced.in.multiple.files", localName);
CommonRefactoringUtil.showErrorHint(project, editor, message, REFACTORING_NAME, HELP_ID);
return;
}
@@ -170,9 +171,8 @@ public class PyInlineLocalHandler extends InlineActionHandler {
if (editor != null) {
highlightManager.addOccurrenceHighlights(editor, defs, writeAttributes, true, null);
highlightManager.addOccurrenceHighlights(editor, new PsiElement[]{ref}, attributes, true, null);
- String message =
- RefactoringBundle
- .getCannotRefactorMessage(RefactoringBundle.message("variable.is.accessed.for.writing.and.used.with.inlined", localName));
+ final String message = RefactoringBundle.getCannotRefactorMessage(
+ RefactoringBundle.message("variable.is.accessed.for.writing.and.used.with.inlined", localName));
CommonRefactoringUtil.showErrorHint(project, editor, message, REFACTORING_NAME, HELP_ID);
}
WindowManager.getInstance().getStatusBar(project).setInfo(RefactoringBundle.message("press.escape.to.remove.the.highlighting"));
@@ -185,7 +185,7 @@ public class PyInlineLocalHandler extends InlineActionHandler {
public void run() {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
- PsiElement[] exprs = new PsiElement[refsToInline.length];
+ final PsiElement[] exprs = new PsiElement[refsToInline.length];
final PyExpression value = prepareValue(def, localName, project);
final PyExpression withParent = PyElementGenerator.getInstance(project).createExpressionFromText("(" + value.getText() + ")");
final PsiElement lastChild = def.getLastChild();
@@ -195,7 +195,7 @@ public class PyInlineLocalHandler extends InlineActionHandler {
}
for (int i = 0, refsToInlineLength = refsToInline.length; i < refsToInlineLength; i++) {
- PsiElement element = refsToInline[i];
+ final PsiElement element = refsToInline[i];
if (PyReplaceExpressionUtil.isNeedParenthesis((PyExpression)element, value)) {
exprs[i] = element.replace(withParent);
} else {
@@ -207,6 +207,16 @@ public class PyInlineLocalHandler extends InlineActionHandler {
PyPsiUtils.removeElements(next);
}
PyPsiUtils.removeElements(def);
+
+ final List<TextRange> ranges = ContainerUtil.mapNotNull(exprs, new Function<PsiElement, TextRange>() {
+ @Override
+ public TextRange fun(PsiElement element) {
+ final PyStatement parentalStatement = PsiTreeUtil.getParentOfType(element, PyStatement.class, false);
+ return parentalStatement != null ? parentalStatement.getTextRange() : null;
+ }
+ });
+ CodeStyleManager.getInstance(project).reformatText(workingFile, ranges);
+
if (editor != null && !ApplicationManager.getApplication().isUnitTestMode()) {
highlightManager.addOccurrenceHighlights(editor, exprs, attributes, true, null);
WindowManager.getInstance().getStatusBar(project)
@@ -262,7 +272,7 @@ public class PyInlineLocalHandler extends InlineActionHandler {
}
@Nullable
- private static PyExpression getValue(PyStatement def) {
+ private static PyExpression getValue(@Nullable PyStatement def) {
if (def == null) return null;
if (def instanceof PyAssignmentStatement) {
return ((PyAssignmentStatement)def).getAssignedValue();
@@ -271,7 +281,7 @@ public class PyInlineLocalHandler extends InlineActionHandler {
}
@Nullable
- private static PyExpression getObject(PyStatement def) {
+ private static PyExpression getObject(@Nullable PyStatement def) {
if (def == null) return null;
if (def instanceof PyAssignmentStatement) {
return ((PyAssignmentStatement)def).getTargets()[0];
@@ -279,12 +289,15 @@ public class PyInlineLocalHandler extends InlineActionHandler {
return ((PyAugAssignmentStatement)def).getTarget();
}
- private static PyExpression prepareValue(PyStatement def, String localName, Project project) {
+ @NotNull
+ private static PyExpression prepareValue(@NotNull PyStatement def, @NotNull String localName, @NotNull Project project) {
final PyExpression value = getValue(def);
assert value != null;
if (def instanceof PyAugAssignmentStatementImpl) {
final PyAugAssignmentStatementImpl expression = (PyAugAssignmentStatementImpl)def;
- String op = expression.getOperation().getText().replace('=', ' ');
+ final PsiElement operation = expression.getOperation();
+ assert operation != null;
+ final String op = operation.getText().replace('=', ' ');
return PyElementGenerator.getInstance(project).createExpressionFromText(localName + " " + op + value.getText() + ")");
}
return value;
diff --git a/python/src/com/jetbrains/python/refactoring/surround/surrounders/statements/PyWithIfElseSurrounder.java b/python/src/com/jetbrains/python/refactoring/surround/surrounders/statements/PyWithIfElseSurrounder.java
index 76c4f4932038..1e1b6d0db815 100644
--- a/python/src/com/jetbrains/python/refactoring/surround/surrounders/statements/PyWithIfElseSurrounder.java
+++ b/python/src/com/jetbrains/python/refactoring/surround/surrounders/statements/PyWithIfElseSurrounder.java
@@ -44,7 +44,6 @@ public class PyWithIfElseSurrounder extends PyStatementSurrounder {
PyElementGenerator.getInstance(project).createFromText(LanguageLevel.getDefault(), PyIfStatement.class, "if True:\n pass\nelse: pass\n");
final PsiElement parent = elements[0].getParent();
final PyStatementList statementList = ifStatement.getIfPart().getStatementList();
- assert statementList != null;
statementList.addRange(elements[0], elements[elements.length - 1]);
statementList.deleteChildRange(statementList.getFirstChild(), statementList.getFirstChild());
diff --git a/python/src/com/jetbrains/python/refactoring/surround/surrounders/statements/PyWithIfSurrounder.java b/python/src/com/jetbrains/python/refactoring/surround/surrounders/statements/PyWithIfSurrounder.java
index 5ccca3de55e6..ac93e60af828 100644
--- a/python/src/com/jetbrains/python/refactoring/surround/surrounders/statements/PyWithIfSurrounder.java
+++ b/python/src/com/jetbrains/python/refactoring/surround/surrounders/statements/PyWithIfSurrounder.java
@@ -22,10 +22,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.util.IncorrectOperationException;
-import com.jetbrains.python.psi.LanguageLevel;
-import com.jetbrains.python.psi.PyElementGenerator;
-import com.jetbrains.python.psi.PyIfStatement;
-import com.jetbrains.python.psi.PyStatementList;
+import com.jetbrains.python.psi.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -40,7 +37,6 @@ public class PyWithIfSurrounder extends PyStatementSurrounder {
PyIfStatement ifStatement = PyElementGenerator.getInstance(project).createFromText(LanguageLevel.getDefault(), PyIfStatement.class, "if True:\n ");
final PsiElement parent = elements[0].getParent();
final PyStatementList statementList = ifStatement.getIfPart().getStatementList();
- assert statementList != null;
statementList.addRange(elements[0], elements[elements.length - 1]);
ifStatement = (PyIfStatement) parent.addBefore(ifStatement, elements[0]);
parent.deleteChildRange(elements[0], elements[elements.length - 1]);
@@ -49,7 +45,8 @@ public class PyWithIfSurrounder extends PyStatementSurrounder {
if (ifStatement == null) {
return null;
}
- return ifStatement.getIfPart().getCondition().getTextRange();
+ final PyExpression condition = ifStatement.getIfPart().getCondition();
+ return condition != null ? condition.getTextRange() : null;
}
public String getTemplateDescription() {
diff --git a/python/src/com/jetbrains/python/refactoring/surround/surrounders/statements/PyWithTryExceptSurrounder.java b/python/src/com/jetbrains/python/refactoring/surround/surrounders/statements/PyWithTryExceptSurrounder.java
index 25a9f26308d3..7466def257f4 100644
--- a/python/src/com/jetbrains/python/refactoring/surround/surrounders/statements/PyWithTryExceptSurrounder.java
+++ b/python/src/com/jetbrains/python/refactoring/surround/surrounders/statements/PyWithTryExceptSurrounder.java
@@ -44,7 +44,6 @@ public class PyWithTryExceptSurrounder extends PyStatementSurrounder {
createFromText(LanguageLevel.getDefault(), PyTryExceptStatement.class, getTemplate());
final PsiElement parent = elements[0].getParent();
final PyStatementList statementList = tryStatement.getTryPart().getStatementList();
- assert statementList != null;
statementList.addRange(elements[0], elements[elements.length - 1]);
statementList.getFirstChild().delete();
tryStatement = (PyTryExceptStatement)parent.addBefore(tryStatement, elements[0]);
@@ -71,7 +70,6 @@ public class PyWithTryExceptSurrounder extends PyStatementSurrounder {
protected TextRange getResultRange(PyTryExceptStatement tryStatement) {
final PyExceptPart part = tryStatement.getExceptParts()[0];
final PyStatementList list = part.getStatementList();
- assert list != null;
return list.getTextRange();
}
diff --git a/python/src/com/jetbrains/python/refactoring/surround/surrounders/statements/PyWithTryFinallySurrounder.java b/python/src/com/jetbrains/python/refactoring/surround/surrounders/statements/PyWithTryFinallySurrounder.java
index d457e32232c2..532fad5c5114 100644
--- a/python/src/com/jetbrains/python/refactoring/surround/surrounders/statements/PyWithTryFinallySurrounder.java
+++ b/python/src/com/jetbrains/python/refactoring/surround/surrounders/statements/PyWithTryFinallySurrounder.java
@@ -42,7 +42,6 @@ public class PyWithTryFinallySurrounder extends PyWithTryExceptSurrounder {
final PyFinallyPart finallyPart = tryStatement.getFinallyPart();
assert finallyPart != null;
final PyStatementList statementList = finallyPart.getStatementList();
- assert statementList != null;
return statementList.getTextRange();
}
}
diff --git a/python/src/com/jetbrains/python/refactoring/surround/surrounders/statements/PyWithWhileSurrounder.java b/python/src/com/jetbrains/python/refactoring/surround/surrounders/statements/PyWithWhileSurrounder.java
index 4ce663900065..a564d4ca3d3f 100644
--- a/python/src/com/jetbrains/python/refactoring/surround/surrounders/statements/PyWithWhileSurrounder.java
+++ b/python/src/com/jetbrains/python/refactoring/surround/surrounders/statements/PyWithWhileSurrounder.java
@@ -41,7 +41,6 @@ public class PyWithWhileSurrounder extends PyStatementSurrounder{
PyElementGenerator.getInstance(project).createFromText(LanguageLevel.getDefault(), PyWhileStatement.class, "while True:\n ");
final PsiElement parent = elements[0].getParent();
final PyStatementList statementList = whileStatement.getWhilePart().getStatementList();
- assert statementList != null;
statementList.addRange(elements[0], elements[elements.length - 1]);
whileStatement = (PyWhileStatement) parent.addBefore(whileStatement, elements[0]);
parent.deleteChildRange(elements[0], elements[elements.length - 1]);
diff --git a/python/src/com/jetbrains/python/run/AbstractPythonRunConfiguration.java b/python/src/com/jetbrains/python/run/AbstractPythonRunConfiguration.java
index 339f91ea7e3a..0927d2e37a3d 100644
--- a/python/src/com/jetbrains/python/run/AbstractPythonRunConfiguration.java
+++ b/python/src/com/jetbrains/python/run/AbstractPythonRunConfiguration.java
@@ -37,10 +37,10 @@ import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.util.PathMappingSettings;
import com.intellij.util.PlatformUtils;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.PythonModuleTypeBase;
-import com.intellij.util.PathMappingSettings;
import com.jetbrains.python.psi.PyClass;
import com.jetbrains.python.psi.PyFunction;
import com.jetbrains.python.sdk.PythonEnvUtil;
@@ -64,6 +64,7 @@ public abstract class AbstractPythonRunConfiguration<T extends AbstractRunConfig
private boolean myUseModuleSdk;
private boolean myAddContentRoots = true;
private boolean myAddSourceRoots = true;
+
protected PathMappingSettings myMappingSettings;
public AbstractPythonRunConfiguration(Project project, final ConfigurationFactory factory) {
diff --git a/python/src/com/jetbrains/python/run/PythonCommandLineState.java b/python/src/com/jetbrains/python/run/PythonCommandLineState.java
index 220939efc274..b1c768f0b012 100644
--- a/python/src/com/jetbrains/python/run/PythonCommandLineState.java
+++ b/python/src/com/jetbrains/python/run/PythonCommandLineState.java
@@ -141,7 +141,8 @@ public abstract class PythonCommandLineState extends CommandLineState {
protected void addTracebackFilter(Project project, ConsoleView consoleView, ProcessHandler processHandler) {
if (PySdkUtil.isRemote(myConfig.getSdk())) {
assert processHandler instanceof RemoteProcessHandlerBase;
- consoleView.addMessageFilter(new PyRemoteTracebackFilter(project, myConfig.getWorkingDirectory(), (RemoteProcessHandlerBase) processHandler));
+ consoleView
+ .addMessageFilter(new PyRemoteTracebackFilter(project, myConfig.getWorkingDirectory(), (RemoteProcessHandlerBase)processHandler));
}
else {
consoleView.addMessageFilter(new PythonTracebackFilter(project, myConfig.getWorkingDirectory()));
@@ -174,7 +175,8 @@ public abstract class PythonCommandLineState extends CommandLineState {
GeneralCommandLine commandLine = generateCommandLine(patchers);
// Extend command line
- PythonRunConfigurationExtensionsManager.getInstance().patchCommandLine(myConfig, getRunnerSettings(), commandLine, getEnvironment().getRunner().getRunnerId());
+ PythonRunConfigurationExtensionsManager.getInstance()
+ .patchCommandLine(myConfig, getRunnerSettings(), commandLine, getEnvironment().getRunner().getRunnerId());
Sdk sdk = PythonSdkType.findSdkByPath(myConfig.getInterpreterPath());
final ProcessHandler processHandler;
if (PySdkUtil.isRemote(sdk)) {
diff --git a/python/src/com/jetbrains/python/run/PythonRunConfiguration.java b/python/src/com/jetbrains/python/run/PythonRunConfiguration.java
index 118c27beb548..5efc8d465bc1 100644
--- a/python/src/com/jetbrains/python/run/PythonRunConfiguration.java
+++ b/python/src/com/jetbrains/python/run/PythonRunConfiguration.java
@@ -47,8 +47,10 @@ public class PythonRunConfiguration extends AbstractPythonRunConfiguration
public static final String SCRIPT_NAME = "SCRIPT_NAME";
public static final String PARAMETERS = "PARAMETERS";
public static final String MULTIPROCESS = "MULTIPROCESS";
+ public static final String SHOW_COMMAND_LINE = "SHOW_COMMAND_LINE";
private String myScriptName;
private String myScriptParameters;
+ private boolean myShowCommandLineAfterwards = false;
protected PythonRunConfiguration(Project project, ConfigurationFactory configurationFactory) {
super(project, configurationFactory);
@@ -98,17 +100,27 @@ public class PythonRunConfiguration extends AbstractPythonRunConfiguration
myScriptParameters = scriptParameters;
}
+ public boolean showCommandLineAfterwards() {
+ return myShowCommandLineAfterwards;
+ }
+
+ public void setShowCommandLineAfterwards(boolean showCommandLineAfterwards) {
+ myShowCommandLineAfterwards = showCommandLineAfterwards;
+ }
+
public void readExternal(Element element) throws InvalidDataException {
PathMacroManager.getInstance(getProject()).expandPaths(element);
super.readExternal(element);
myScriptName = JDOMExternalizerUtil.readField(element, SCRIPT_NAME);
myScriptParameters = JDOMExternalizerUtil.readField(element, PARAMETERS);
+ myShowCommandLineAfterwards = Boolean.parseBoolean(JDOMExternalizerUtil.readField(element, SHOW_COMMAND_LINE, "false"));
}
public void writeExternal(Element element) throws WriteExternalException {
super.writeExternal(element);
JDOMExternalizerUtil.writeField(element, SCRIPT_NAME, myScriptName);
JDOMExternalizerUtil.writeField(element, PARAMETERS, myScriptParameters);
+ JDOMExternalizerUtil.writeField(element, SHOW_COMMAND_LINE, Boolean.toString(myShowCommandLineAfterwards));
PathMacroManager.getInstance(getProject()).collapsePathsRecursively(element);
}
@@ -120,6 +132,7 @@ public class PythonRunConfiguration extends AbstractPythonRunConfiguration
AbstractPythonRunConfiguration.copyParams(source.getBaseParams(), target.getBaseParams());
target.setScriptName(source.getScriptName());
target.setScriptParameters(source.getScriptParameters());
+ target.setShowCommandLineAfterwards(source.showCommandLineAfterwards());
}
@Override
diff --git a/python/src/com/jetbrains/python/run/PythonRunConfigurationForm.form b/python/src/com/jetbrains/python/run/PythonRunConfigurationForm.form
index 1ba245143902..33e45b9c04ee 100644
--- a/python/src/com/jetbrains/python/run/PythonRunConfigurationForm.form
+++ b/python/src/com/jetbrains/python/run/PythonRunConfigurationForm.form
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.jetbrains.python.run.PythonRunConfigurationForm">
- <grid id="27dc6" binding="myRootPanel" layout-manager="GridLayoutManager" row-count="5" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+ <grid id="27dc6" binding="myRootPanel" layout-manager="GridLayoutManager" row-count="6" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<xy x="20" y="20" width="507" height="400"/>
@@ -44,7 +44,7 @@
</component>
<vspacer id="f8c96">
<constraints>
- <grid row="4" column="1" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
+ <grid row="5" column="1" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
</constraints>
</vspacer>
<grid id="9b4b8" binding="myCommonOptionsPlaceholder" layout-manager="BorderLayout" hgap="0" vgap="0">
@@ -63,6 +63,15 @@
<border type="none"/>
<children/>
</grid>
+ <component id="99b13" class="com.intellij.ui.components.JBCheckBox" binding="myShowCommandLineCheckbox">
+ <constraints>
+ <grid row="4" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties>
+ <selected value="true"/>
+ <text value="Show command line afterwards"/>
+ </properties>
+ </component>
</children>
</grid>
</form>
diff --git a/python/src/com/jetbrains/python/run/PythonRunConfigurationForm.java b/python/src/com/jetbrains/python/run/PythonRunConfigurationForm.java
index da041f961f80..cad905fd9618 100644
--- a/python/src/com/jetbrains/python/run/PythonRunConfigurationForm.java
+++ b/python/src/com/jetbrains/python/run/PythonRunConfigurationForm.java
@@ -25,6 +25,7 @@ import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.PanelWithAnchor;
import com.intellij.ui.RawCommandLineEditor;
+import com.intellij.ui.components.JBCheckBox;
import com.intellij.ui.components.JBLabel;
import com.jetbrains.python.debugger.PyDebuggerOptionsProvider;
import org.jetbrains.annotations.NotNull;
@@ -44,6 +45,7 @@ public class PythonRunConfigurationForm implements PythonRunConfigurationParams,
private final AbstractPyCommonOptionsForm myCommonOptionsForm;
private JComponent anchor;
private final Project myProject;
+ private JBCheckBox myShowCommandLineCheckbox;
public PythonRunConfigurationForm(PythonRunConfiguration configuration) {
myCommonOptionsForm = PyCommonOptionsFormFactory.getInstance().createForm(configuration.getCommonOptionsFormData());
@@ -105,6 +107,16 @@ public class PythonRunConfigurationForm implements PythonRunConfigurationParams,
}
@Override
+ public boolean showCommandLineAfterwards() {
+ return myShowCommandLineCheckbox.isSelected();
+ }
+
+ @Override
+ public void setShowCommandLineAfterwards(boolean showCommandLineAfterwards) {
+ myShowCommandLineCheckbox.setSelected(showCommandLineAfterwards);
+ }
+
+ @Override
public JComponent getAnchor() {
return anchor;
}
diff --git a/python/src/com/jetbrains/python/run/PythonScriptCommandLineState.java b/python/src/com/jetbrains/python/run/PythonScriptCommandLineState.java
index 81d2daaee3d0..cd92fdb34638 100644
--- a/python/src/com/jetbrains/python/run/PythonScriptCommandLineState.java
+++ b/python/src/com/jetbrains/python/run/PythonScriptCommandLineState.java
@@ -15,11 +15,37 @@
*/
package com.jetbrains.python.run;
+import com.google.common.collect.Lists;
+import com.intellij.execution.*;
import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.execution.configurations.ParametersList;
import com.intellij.execution.configurations.ParamsGroup;
+import com.intellij.execution.executors.DefaultDebugExecutor;
+import com.intellij.execution.process.CommandLineArgumentsProvider;
+import com.intellij.execution.process.OSProcessHandler;
+import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.runners.ExecutionEnvironment;
+import com.intellij.execution.ui.RunContentDescriptor;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.progress.ProgressIndicator;
+import com.intellij.openapi.progress.ProgressManager;
+import com.intellij.openapi.progress.Task;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.util.ArrayUtil;
+import com.intellij.util.ui.UIUtil;
+import com.jetbrains.python.PythonHelpersLocator;
+import com.jetbrains.python.console.PyConsoleType;
+import com.jetbrains.python.console.PydevConsoleRunner;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
/**
* @author yole
@@ -32,6 +58,34 @@ public class PythonScriptCommandLineState extends PythonCommandLineState {
myConfig = runConfiguration;
}
+ @NotNull
+ @Override
+ public ExecutionResult execute(Executor executor, final CommandLinePatcher... patchers) throws ExecutionException {
+ if (myConfig.showCommandLineAfterwards()) {
+ if (executor.getId() == DefaultDebugExecutor.EXECUTOR_ID) {
+ return super.execute(executor, ArrayUtil.append(patchers, new CommandLinePatcher() {
+ @Override
+ public void patchCommandLine(GeneralCommandLine commandLine) {
+ commandLine.getParametersList().getParamsGroup(PythonCommandLineState.GROUP_DEBUGGER).addParameterAt(1, "--cmd-line");
+ }
+ }));
+ }
+
+ PydevConsoleRunner runner =
+ new PythonScriptWithConsoleRunner(myConfig.getProject(), myConfig.getSdk(), PyConsoleType.PYTHON, myConfig.getWorkingDirectory(),
+ myConfig.getEnvs(), patchers);
+
+ runner.runSync();
+
+ List<AnAction> actions = Lists.newArrayList(createActions(runner.getConsoleView(), runner.getProcessHandler()));
+
+ return new DefaultExecutionResult(runner.getConsoleView(), runner.getProcessHandler(), actions.toArray(new AnAction[actions.size()]));
+ }
+ else {
+ return super.execute(executor, patchers);
+ }
+ }
+
@Override
protected void buildCommandLineParameters(GeneralCommandLine commandLine) {
ParametersList parametersList = commandLine.getParametersList();
@@ -53,4 +107,68 @@ public class PythonScriptCommandLineState extends PythonCommandLineState {
}
}
+ /**
+ * @author traff
+ */
+ public class PythonScriptWithConsoleRunner extends PydevConsoleRunner {
+
+ private CommandLinePatcher[] myPatchers;
+
+ public PythonScriptWithConsoleRunner(@NotNull Project project,
+ @NotNull Sdk sdk,
+ @NotNull PyConsoleType consoleType,
+ @Nullable String workingDir,
+ Map<String, String> environmentVariables,
+ CommandLinePatcher[] patchers,
+ String... statementsToExecute) {
+ super(project, sdk, consoleType, workingDir, environmentVariables, statementsToExecute);
+ myPatchers = patchers;
+ }
+
+ @Override
+ protected void createContentDescriptorAndActions() {
+ AnAction a = createConsoleExecAction(myConsoleExecuteActionHandler);
+ registerActionShortcuts(Lists.newArrayList(a), getConsoleView().getConsole().getConsoleEditor().getComponent());
+ }
+
+ @Override
+ protected CommandLineArgumentsProvider createCommandLineArgumentsProvider(final Sdk sdk,
+ final Map<String, String> environmentVariables,
+ int[] ports) {
+ final ArrayList<String> args = new ArrayList<String>();
+ args.add(sdk.getHomePath());
+ final String versionString = sdk.getVersionString();
+ if (versionString == null || !versionString.toLowerCase().contains("jython")) {
+ args.add("-u");
+ }
+ args.add(FileUtil.toSystemDependentName(PythonHelpersLocator.getHelperPath("pydev/pydev_run_in_console.py")));
+ for (int port : ports) {
+ args.add(String.valueOf(port));
+ }
+
+ try {
+ GeneralCommandLine cmd = generateCommandLine(myPatchers);
+ args.addAll(cmd.getParametersList().getList());
+ }
+ catch (Exception e) {
+ //pass
+ }
+ return new CommandLineArgumentsProvider() {
+ @Override
+ public String[] getArguments() {
+ return ArrayUtil.toStringArray(args);
+ }
+
+ @Override
+ public boolean passParentEnvs() {
+ return false;
+ }
+
+ @Override
+ public Map<String, String> getAdditionalEnvs() {
+ return addDefaultEnvironments(sdk, environmentVariables);
+ }
+ };
+ }
+ }
}
diff --git a/python/src/com/jetbrains/python/sdk/PySdkListCellRenderer.java b/python/src/com/jetbrains/python/sdk/PySdkListCellRenderer.java
index 1a42621dde3d..e165e59656f4 100644
--- a/python/src/com/jetbrains/python/sdk/PySdkListCellRenderer.java
+++ b/python/src/com/jetbrains/python/sdk/PySdkListCellRenderer.java
@@ -20,6 +20,7 @@ import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.projectRoots.SdkModificator;
import com.intellij.openapi.projectRoots.SdkType;
import com.intellij.openapi.util.IconLoader;
+import com.intellij.openapi.util.io.FileUtil;
import com.intellij.ui.LayeredIcon;
import com.intellij.ui.ListCellRendererWrapper;
import com.jetbrains.python.sdk.flavors.PythonSdkFlavor;
@@ -113,7 +114,7 @@ public class PySdkListCellRenderer extends ListCellRendererWrapper<Object> {
}
}
else if (new File(name).exists()) {
- name = "..." + File.separator + new File(name).getParentFile().getParentFile().getName();
+ name = FileUtil.getLocationRelativeToUserHome(name);
}
return name;
}
diff --git a/python/src/com/jetbrains/python/sdk/flavors/WinPythonSdkFlavor.java b/python/src/com/jetbrains/python/sdk/flavors/WinPythonSdkFlavor.java
index 8e75e634755b..9d22af8c03bf 100644
--- a/python/src/com/jetbrains/python/sdk/flavors/WinPythonSdkFlavor.java
+++ b/python/src/com/jetbrains/python/sdk/flavors/WinPythonSdkFlavor.java
@@ -15,7 +15,9 @@
*/
package com.jetbrains.python.sdk.flavors;
+import com.google.common.collect.ImmutableMap;
import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.io.WindowsRegistryUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
@@ -23,15 +25,17 @@ import com.intellij.openapi.vfs.newvfs.NewVirtualFile;
import com.jetbrains.python.PythonHelpersLocator;
import java.io.File;
-import java.util.Collection;
-import java.util.Set;
-import java.util.TreeSet;
+import java.util.*;
/**
* @author yole
*/
public class WinPythonSdkFlavor extends CPythonSdkFlavor {
public static WinPythonSdkFlavor INSTANCE = new WinPythonSdkFlavor();
+ private static Map<String, String> ourRegistryMap =
+ ImmutableMap.of("HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore", "python.exe",
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Python\\PythonCore", "python.exe",
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\IronPython", "ipy.exe");
private WinPythonSdkFlavor() {
}
@@ -48,6 +52,7 @@ public class WinPythonSdkFlavor extends CPythonSdkFlavor {
for (String name : exe_names) {
findInstallations(candidates, name, "C:\\", "C:\\Program Files\\");
findInPath(candidates, name);
+ findInRegistry(candidates);
}
}
@@ -59,6 +64,7 @@ public class WinPythonSdkFlavor extends CPythonSdkFlavor {
public static void findInPath(Collection<String> candidates, String exeName) {
final String path = System.getenv("PATH");
+ if (path == null) return;
for (String pathEntry : StringUtil.split(path, ";")) {
if (pathEntry.startsWith("\"") && pathEntry.endsWith("\"")) {
if (pathEntry.length() < 2) continue;
@@ -71,6 +77,25 @@ public class WinPythonSdkFlavor extends CPythonSdkFlavor {
}
}
+ public static void findInRegistry(Collection<String> candidates) {
+ for (Map.Entry<String, String> entry : ourRegistryMap.entrySet()) {
+ final String prefix = entry.getKey();
+ final String exePath = entry.getValue();
+ List<String> strings = WindowsRegistryUtil.readRegistryBranch(prefix);
+ for (String string : strings) {
+ final String path =
+ WindowsRegistryUtil.readRegistryDefault(prefix + "\\" + string +
+ "\\InstallPath");
+ if (path != null) {
+ File f = new File(path, exePath);
+ if (f.exists()) {
+ candidates.add(FileUtil.toSystemDependentName(f.getPath()));
+ }
+ }
+ }
+ }
+ }
+
private static void findSubdirInstallations(Collection<String> candidates, String rootDir, String dir_prefix, String exe_name) {
VirtualFile rootVDir = LocalFileSystem.getInstance().findFileByPath(rootDir);
if (rootVDir != null) {
diff --git a/python/src/com/jetbrains/python/validation/CompatibilityVisitor.java b/python/src/com/jetbrains/python/validation/CompatibilityVisitor.java
index f48af7ff0e73..9be15944f37e 100644
--- a/python/src/com/jetbrains/python/validation/CompatibilityVisitor.java
+++ b/python/src/com/jetbrains/python/validation/CompatibilityVisitor.java
@@ -295,7 +295,7 @@ public abstract class CompatibilityVisitor extends PyAnnotator {
}
}
commonRegisterProblem(message, " not support this syntax. Raise with no arguments can only be used in an except block",
- len, node, null);
+ len, node, null, false);
// raise 1, 2, 3
len = 0;
message = new StringBuilder(myCommonMessage);