diff --git a/python/helpers/StdlibTypes2.properties b/python/helpers/StdlibTypes2.properties index c24e569c1e86..45274f025196 100644 --- a/python/helpers/StdlibTypes2.properties +++ b/python/helpers/StdlibTypes2.properties @@ -66,7 +66,7 @@ __builtin__.getattr = \ :rtype: object or unknown \n\ __builtin__.globals = \ - :rtype: dict of (bytes, object) + :rtype: dict of (string, unknown) __builtin__.hasattr = \ :type name: string \n\ @@ -84,7 +84,7 @@ __builtin__.len = \ :rtype: int \n\ __builtin__.locals = \ - :rtype: dict of (bytes, object) + :rtype: dict of (string, unknown) __builtin__.map = \ :type function: collections.Callable or None \n\ @@ -138,7 +138,7 @@ __builtin__.round = \ :rtype: float \n\ __builtin__.vars = \ - :rtype: dict of (bytes, object) + :rtype: dict of (string, unknown) __builtin__.xrange.__init__ = \ :type start: int \n\ diff --git a/python/helpers/pydev/pydevd.py b/python/helpers/pydev/pydevd.py index 28880d1a2b5b..70c63569b1dc 100644 --- a/python/helpers/pydev/pydevd.py +++ b/python/helpers/pydev/pydevd.py @@ -103,7 +103,8 @@ DONT_TRACE = { 'pydevd_vm_type.py':1, 'pydevd.py':1 , 'pydevd_psyco_stub.py':1, - '_pydev_execfile.py':1 + '_pydev_execfile.py':1, + '_pydev_jython_execfile.py':1 } if IS_PY3K: @@ -135,11 +136,7 @@ class PyDBCommandThread(PyDBDaemonThread): if self.killReceived: return - run_traced = True - - import pydevd_tracing - if run_traced: - pydevd_tracing.SetTrace(None) # no debugging on this thread + threading.settrace(None) # no debugging on this thread try: while not self.killReceived: diff --git a/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.form b/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.form index dfd2644e406a..5aacd414fb03 100644 --- a/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.form +++ b/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.form @@ -22,60 +22,11 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -98,23 +49,74 @@ - + + - + - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.java b/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.java index 8f176853fbf8..3bf58506046b 100644 --- a/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.java +++ b/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.java @@ -17,6 +17,7 @@ import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.ui.TextFieldWithBrowseButton; import com.intellij.openapi.util.Comparing; import com.intellij.ui.CollectionComboBoxModel; +import com.intellij.ui.IdeBorderFactory; import com.jetbrains.python.PyBundle; import com.jetbrains.python.PyNames; import com.jetbrains.python.ReSTService; @@ -51,6 +52,8 @@ public class PyIntegratedToolsConfigurable implements SearchableConfigurable, No private JPanel myErrorPanel; private TextFieldWithBrowseButton myRequirementsPathField; private JCheckBox analyzeDoctest; + private JPanel myDocStringsPanel; + private JPanel myRestPanel; public PyIntegratedToolsConfigurable(@NotNull Module module) { myModule = module; @@ -67,6 +70,9 @@ public class PyIntegratedToolsConfigurable implements SearchableConfigurable, No myRequirementsPathField.addBrowseFolderListener("Choose path to the package requirements file:", null, myProject, FileChooserDescriptorFactory.createSingleLocalFileDescriptor()); myRequirementsPathField.setText(getRequirementsPath()); + + myDocStringsPanel.setBorder(IdeBorderFactory.createTitledBorder("Docstrings")); + myRestPanel.setBorder(IdeBorderFactory.createTitledBorder("reStructuredText")); } @NotNull diff --git a/python/src/com/jetbrains/python/debugger/PySignatureUtil.java b/python/src/com/jetbrains/python/debugger/PySignatureUtil.java index 1d70341508c8..be827d965fbb 100644 --- a/python/src/com/jetbrains/python/debugger/PySignatureUtil.java +++ b/python/src/com/jetbrains/python/debugger/PySignatureUtil.java @@ -1,11 +1,16 @@ package com.jetbrains.python.debugger; +import com.google.common.base.Function; +import com.google.common.collect.Collections2; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; +import com.jetbrains.appengine.util.StringUtils; import com.jetbrains.python.psi.PyClass; import com.jetbrains.python.psi.PyFunction; 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.PyUnionType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -25,13 +30,27 @@ public class PySignatureUtil { } if (pyType != null) { - return pyType.getName(); + return getPrintableName(pyType); } else { return type; } } + private static String getPrintableName(PyType type) { + if (type instanceof PyUnionType) { + return StringUtil.join(Collections2.transform(((PyUnionType)type).getMembers(), new Function() { + @Override + public String apply(@Nullable PyType input) { + return getPrintableName(input); + } + }), " or "); + } + else { + return type.getName(); + } + } + @Nullable public static String getArgumentType(@NotNull PyFunction function, @NotNull String name) { PySignatureCacheManager cacheManager = PySignatureCacheManager.getInstance(function.getProject()); diff --git a/python/src/com/jetbrains/python/inspections/PyShadowingBuiltinsInspection.java b/python/src/com/jetbrains/python/inspections/PyShadowingBuiltinsInspection.java index 3c81974adacf..64c3ff48a5c3 100644 --- a/python/src/com/jetbrains/python/inspections/PyShadowingBuiltinsInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyShadowingBuiltinsInspection.java @@ -1,10 +1,24 @@ package com.jetbrains.python.inspections; import com.intellij.codeInspection.LocalInspectionToolSession; +import com.intellij.codeInspection.LocalQuickFix; +import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.codeInspection.ProblemsHolder; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.fileEditor.OpenFileDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElementVisitor; import com.intellij.psi.PsiNameIdentifierOwner; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.refactoring.rename.PsiElementRenameHandler; +import com.intellij.refactoring.rename.RenameProcessor; +import com.intellij.refactoring.rename.RenamePsiElementProcessor; +import com.intellij.refactoring.rename.inplace.VariableInplaceRenamer; +import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyBuiltinCache; import org.jetbrains.annotations.NotNull; @@ -62,7 +76,55 @@ public class PyShadowingBuiltinsInspection extends PyInspection { final PsiElement builtin = builtinCache.getByName(name); if (builtin != null && !PyUtil.inSameFile(builtin, element)) { final PsiElement identifier = element.getNameIdentifier(); - registerProblem(identifier != null ? identifier : element, "Shadows a built-in with the same name"); + registerProblem(identifier != null ? identifier : element, "Shadows a built-in with the same name", + new PyRenameElementQuickFix()); + } + } + } + + private static class PyRenameElementQuickFix implements LocalQuickFix { + @NotNull + @Override + public String getName() { + return "Rename element"; + } + + @NotNull + @Override + public String getFamilyName() { + return "Rename element"; + } + + @Override + public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { + final PsiElement element = descriptor.getPsiElement(); + final PsiNameIdentifierOwner nameOwner = element instanceof PsiNameIdentifierOwner ? + (PsiNameIdentifierOwner)element : + PsiTreeUtil.getParentOfType(element, PsiNameIdentifierOwner.class, true); + if (nameOwner != null) { + final VirtualFile virtualFile = nameOwner.getContainingFile().getVirtualFile(); + if (virtualFile != null) { + final Editor editor = FileEditorManager.getInstance(project).openTextEditor(new OpenFileDescriptor(project, virtualFile), true); + if (ApplicationManager.getApplication().isUnitTestMode()) { + renameInUnitTestMode(project, nameOwner, editor); + } + else { + if (nameOwner instanceof PyNamedParameter || nameOwner instanceof PyTargetExpression) { + new VariableInplaceRenamer(nameOwner, editor).performInplaceRename(); + } + else { + PsiElementRenameHandler.invoke(nameOwner, project, ScopeUtil.getScopeOwner(nameOwner), editor); + } + } + } + } + } + + private static void renameInUnitTestMode(@NotNull Project project, @NotNull PsiNameIdentifierOwner nameOwner, + @Nullable Editor editor) { + final PsiElement substitution = RenamePsiElementProcessor.forElement(nameOwner).substituteElementToRename(nameOwner, editor); + if (substitution != null) { + new RenameProcessor(project, substitution, "a", false, false).run(); } } } diff --git a/python/src/com/jetbrains/python/run/PythonCommandLineState.java b/python/src/com/jetbrains/python/run/PythonCommandLineState.java index 20e807ae8090..ee17f05041f7 100644 --- a/python/src/com/jetbrains/python/run/PythonCommandLineState.java +++ b/python/src/com/jetbrains/python/run/PythonCommandLineState.java @@ -171,7 +171,6 @@ public abstract class PythonCommandLineState extends CommandLineState { private ProcessHandler startRemoteProcess(Sdk sdk, GeneralCommandLine commandLine) throws ExecutionException { PythonRemoteInterpreterManager manager = PythonRemoteInterpreterManager.getInstance(); if (manager != null) { - ProcessHandler processHandler = null; @@ -288,12 +287,13 @@ public abstract class PythonCommandLineState extends CommandLineState { boolean passParentEnvs, List pathList, final String interpreterPath) { + Map envs = commandLine.getEnvParams(); final PythonSdkFlavor flavor = PythonSdkFlavor.getFlavor(interpreterPath); if (flavor != null) { flavor.initPythonPath(commandLine, pathList); } else { - PythonSdkFlavor.initPythonPath(commandLine.getEnvParams(), passParentEnvs, pathList); + PythonSdkFlavor.initPythonPath(envs, passParentEnvs, pathList); } } @@ -339,8 +339,6 @@ public abstract class PythonCommandLineState extends CommandLineState { } return pythonPath; - - } @NotNull diff --git a/python/src/com/jetbrains/python/sdk/PythonEnvUtil.java b/python/src/com/jetbrains/python/sdk/PythonEnvUtil.java index 2bc2031eeb94..015c04759b02 100644 --- a/python/src/com/jetbrains/python/sdk/PythonEnvUtil.java +++ b/python/src/com/jetbrains/python/sdk/PythonEnvUtil.java @@ -78,11 +78,13 @@ public class PythonEnvUtil { } public static void addToEnv(Map envs, String key, String value) { - if (envs.containsKey(key)) { - envs.put(key, appendToPathEnvVar(envs.get(key), value)); - } - else { - envs.put(key, value); + if (!StringUtil.isEmpty(value)) { + if (envs.containsKey(key)) { + envs.put(key, appendToPathEnvVar(envs.get(key), value)); + } + else { + envs.put(key, value); + } } } diff --git a/python/src/com/jetbrains/python/sdk/flavors/IronPythonSdkFlavor.java b/python/src/com/jetbrains/python/sdk/flavors/IronPythonSdkFlavor.java index 7b3b32d1ba6d..07d5fa82ec4f 100644 --- a/python/src/com/jetbrains/python/sdk/flavors/IronPythonSdkFlavor.java +++ b/python/src/com/jetbrains/python/sdk/flavors/IronPythonSdkFlavor.java @@ -7,10 +7,7 @@ import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.io.File; -import java.util.Collection; -import java.util.Collections; -import java.util.Set; -import java.util.TreeSet; +import java.util.*; /** * @author yole @@ -73,7 +70,13 @@ public class IronPythonSdkFlavor extends PythonSdkFlavor { @Override public void initPythonPath(GeneralCommandLine cmd, Collection path) { - addToEnv(cmd, "IRONPYTHONPATH", StringUtil.join(path, File.pathSeparator)); + Map env = getEnv(cmd); + initPythonPath(path, env); + } + + @Override + public void initPythonPath(Collection path, Map env) { + addToEnv("IRONPYTHONPATH", StringUtil.join(path, File.pathSeparator), env); } @NotNull diff --git a/python/src/com/jetbrains/python/sdk/flavors/JythonSdkFlavor.java b/python/src/com/jetbrains/python/sdk/flavors/JythonSdkFlavor.java index 8a8640481041..cce2d4bce95d 100644 --- a/python/src/com/jetbrains/python/sdk/flavors/JythonSdkFlavor.java +++ b/python/src/com/jetbrains/python/sdk/flavors/JythonSdkFlavor.java @@ -5,12 +5,14 @@ import com.intellij.execution.configurations.ParamsGroup; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.jetbrains.python.run.PythonCommandLineState; +import com.jetbrains.python.sdk.PythonEnvUtil; import icons.PythonIcons; import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.io.File; import java.util.Collection; +import java.util.Map; /** * @author yole @@ -23,14 +25,6 @@ public class JythonSdkFlavor extends PythonSdkFlavor { public static JythonSdkFlavor INSTANCE = new JythonSdkFlavor(); - public static String appendSystemJythonPath(String pythonPath) { - String syspath = System.getenv(JYTHONPATH); - if (syspath != null) { - pythonPath += File.pathSeparator + syspath; - } - return pythonPath; - } - public boolean isValidSdkPath(@NotNull File file) { return FileUtil.getNameWithoutExtension(file).toLowerCase().startsWith("jython"); } @@ -47,13 +41,19 @@ public class JythonSdkFlavor extends PythonSdkFlavor { @Override public void initPythonPath(GeneralCommandLine cmd, Collection path) { - final String jythonPath = StringUtil.join(path, File.pathSeparator); - addToEnv(cmd, JYTHONPATH, appendSystemJythonPath(jythonPath)); + initPythonPath(path, getEnv(cmd)); ParamsGroup param_group = cmd.getParametersList().getParamsGroup(PythonCommandLineState.GROUP_EXE_OPTIONS); assert param_group != null; param_group.addParameter(getPythonPathCmdLineArgument(path)); } + @Override + public void initPythonPath(Collection path, Map env) { + path = appendSystemEnvPaths(path, JYTHONPATH); + final String jythonPath = StringUtil.join(path, File.pathSeparator); + addToEnv(JYTHONPATH, jythonPath, env); + } + @NotNull @Override public String getName() { @@ -61,7 +61,7 @@ public class JythonSdkFlavor extends PythonSdkFlavor { } public static String getPythonPathCmdLineArgument(Collection path) { - return "-Dpython.path=" + appendSystemJythonPath(StringUtil.join(path, File.pathSeparator)); + return "-Dpython.path=" + StringUtil.join(appendSystemEnvPaths(path, JYTHONPATH), File.pathSeparator); } @Override diff --git a/python/src/com/jetbrains/python/sdk/flavors/PythonSdkFlavor.java b/python/src/com/jetbrains/python/sdk/flavors/PythonSdkFlavor.java index 09debcfe2889..cf77e38d3f33 100644 --- a/python/src/com/jetbrains/python/sdk/flavors/PythonSdkFlavor.java +++ b/python/src/com/jetbrains/python/sdk/flavors/PythonSdkFlavor.java @@ -32,7 +32,11 @@ public abstract class PythonSdkFlavor { private static final Logger LOG = Logger.getInstance(PythonSdkFlavor.class); public static Collection appendSystemPythonPath(Collection pythonPath) { - String syspath = System.getenv(PythonEnvUtil.PYTHONPATH); + return appendSystemEnvPaths(pythonPath, PythonEnvUtil.PYTHONPATH); + } + + protected static Collection appendSystemEnvPaths(Collection pythonPath, String envname) { + String syspath = System.getenv(envname); if (syspath != null) { pythonPath.addAll(Lists.newArrayList(syspath.split(File.pathSeparator))); } @@ -186,20 +190,14 @@ public abstract class PythonSdkFlavor { } public void initPythonPath(GeneralCommandLine cmd, Collection path) { - addToEnv(cmd, PythonEnvUtil.PYTHONPATH, appendSystemPythonPath(path)); + initPythonPath(path, getEnv(cmd)); } - public static void addToEnv(GeneralCommandLine cmd, final String key, Collection values) { - Map envs = getEnv(cmd); - PythonEnvUtil.addToEnv(envs, key, values); - } - - public static void addToEnv(GeneralCommandLine cmd, final String key, String value) { - Map envs = getEnv(cmd); + public static void addToEnv(final String key, String value, Map envs) { PythonEnvUtil.addToEnv(envs, key, value); } - private static Map getEnv(GeneralCommandLine cmd) { + static Map getEnv(GeneralCommandLine cmd) { Map envs = cmd.getEnvParams(); if (envs == null) { envs = new HashMap(); @@ -232,4 +230,9 @@ public abstract class PythonSdkFlavor { public Icon getIcon() { return PythonIcons.Python.Python; } + + public void initPythonPath(Collection path, Map env) { + path = appendSystemPythonPath(path); + addToEnv(PythonEnvUtil.PYTHONPATH, StringUtil.join(path, File.pathSeparator), env); + } } diff --git a/python/testData/inspections/RenameFunctionShadowingBuiltins.py b/python/testData/inspections/RenameFunctionShadowingBuiltins.py new file mode 100644 index 000000000000..ed54b1c887d9 --- /dev/null +++ b/python/testData/inspections/RenameFunctionShadowingBuiltins.py @@ -0,0 +1,6 @@ +def id(x): + return x + + +def f(): + return id('foo') diff --git a/python/testData/inspections/RenameFunctionShadowingBuiltins_after.py b/python/testData/inspections/RenameFunctionShadowingBuiltins_after.py new file mode 100644 index 000000000000..57ac3e896508 --- /dev/null +++ b/python/testData/inspections/RenameFunctionShadowingBuiltins_after.py @@ -0,0 +1,6 @@ +def a(x): + return x + + +def f(): + return a('foo') diff --git a/python/testData/inspections/RenameShadowingBuiltins.py b/python/testData/inspections/RenameShadowingBuiltins.py new file mode 100644 index 000000000000..f22217991759 --- /dev/null +++ b/python/testData/inspections/RenameShadowingBuiltins.py @@ -0,0 +1,3 @@ +def f(name): + file = open(name, 'rb') + return file.read() diff --git a/python/testData/inspections/RenameShadowingBuiltins_after.py b/python/testData/inspections/RenameShadowingBuiltins_after.py new file mode 100644 index 000000000000..4f8354971055 --- /dev/null +++ b/python/testData/inspections/RenameShadowingBuiltins_after.py @@ -0,0 +1,3 @@ +def f(name): + a = open(name, 'rb') + return a.read() diff --git a/python/testSrc/com/jetbrains/python/PyQuickFixTest.java b/python/testSrc/com/jetbrains/python/PyQuickFixTest.java index 84b60a170548..4a7aba094c2b 100644 --- a/python/testSrc/com/jetbrains/python/PyQuickFixTest.java +++ b/python/testSrc/com/jetbrains/python/PyQuickFixTest.java @@ -424,6 +424,19 @@ public class PyQuickFixTest extends PyTestCase { myFixture.checkResultByFile(graftBeforeExt(testFiles[0], "_after")); } + // PY-8788 + public void testRenameShadowingBuiltins() { + doInspectionTest("RenameShadowingBuiltins.py", PyShadowingBuiltinsInspection.class, + "Rename element", true, true); + } + + // PY-8788 + public void testRenameFunctionShadowingBuiltins() { + doInspectionTest("RenameFunctionShadowingBuiltins.py", PyShadowingBuiltinsInspection.class, + "Rename element", true, true); + + } + @Override @NonNls protected String getTestDataPath() {