diff --git a/platform/build-scripts/src/org/jetbrains/intellij/build/python/PythonCommunityPluginModules.kt b/platform/build-scripts/src/org/jetbrains/intellij/build/python/PythonCommunityPluginModules.kt
index e6ef526489b8..ce4f24db482d 100644
--- a/platform/build-scripts/src/org/jetbrains/intellij/build/python/PythonCommunityPluginModules.kt
+++ b/platform/build-scripts/src/org/jetbrains/intellij/build/python/PythonCommunityPluginModules.kt
@@ -64,21 +64,22 @@ object PythonCommunityPluginModules {
spec.directoryName = name
spec.mainJarName = "$name.jar"
spec.withModules(modules)
-
- spec.withGeneratedResources { targetDir, context ->
- val output = targetDir.resolve("helpers")
- Files.createDirectories(output)
- copyDir(
- sourceDir = context.paths.communityHomeDir.resolve("python/helpers"), targetDir = output,
- dirFilter = { path ->
- when {
- path.endsWith("tests") || path.endsWith(".idea") -> false
- path.parent?.fileName?.toString() == "pydev" -> !path.fileName.toString().startsWith("pydev_test")
- else -> true
- }
- },
- fileFilter = { path -> !path.endsWith("setup.py") && !path.endsWith("conftest.py") }
- )
+ if (mainModuleName == "intellij.python.community.plugin") {
+ spec.withGeneratedResources { targetDir, context ->
+ val output = targetDir.resolve("helpers")
+ Files.createDirectories(output)
+ copyDir(
+ sourceDir = context.paths.communityHomeDir.resolve("python/helpers"), targetDir = output,
+ dirFilter = { path ->
+ when {
+ path.endsWith("tests") || path.endsWith(".idea") -> false
+ path.parent?.fileName?.toString() == "pydev" -> !path.fileName.toString().startsWith("pydev_test")
+ else -> true
+ }
+ },
+ fileFilter = { path -> !path.endsWith("setup.py") && !path.endsWith("conftest.py") }
+ )
+ }
}
// required for "Python Console" in PythonCore plugin
diff --git a/python/python-psi-impl/resources/META-INF/PythonPsiImpl.xml b/python/python-psi-impl/resources/META-INF/PythonPsiImpl.xml
index deb379a27d74..a143d65e2373 100644
--- a/python/python-psi-impl/resources/META-INF/PythonPsiImpl.xml
+++ b/python/python-psi-impl/resources/META-INF/PythonPsiImpl.xml
@@ -502,6 +502,9 @@
+
@@ -577,4 +580,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/python/python-psi-impl/src/com/jetbrains/python/PythonHelpersLocator.java b/python/python-psi-impl/src/com/jetbrains/python/PythonHelpersLocator.java
deleted file mode 100644
index fd1c0a62ef0b..000000000000
--- a/python/python-psi-impl/src/com/jetbrains/python/PythonHelpersLocator.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright 2000-2015 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;
-
-import com.intellij.ide.plugins.PluginManagerCore;
-import com.intellij.openapi.application.PathManager;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.util.PathUtil;
-import org.jetbrains.annotations.ApiStatus;
-import org.jetbrains.annotations.NonNls;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.io.File;
-import java.nio.file.Path;
-import java.util.List;
-
-public final class PythonHelpersLocator {
- private static final Logger LOG = Logger.getInstance(PythonHelpersLocator.class);
- private static final String PROPERTY_HELPERS_LOCATION = "idea.python.helpers.path";
- private static final String EXPECTED_PRO_HELPER_PACKAGE = "jupyter_debug";
- private static final String PRO_HELPERS_DIR = "helpers-pro";
- private static final String PYTHON_PRO_PLUGIN_NAME = "python";
-
- private PythonHelpersLocator() { }
-
- /**
- * @return the base directory under which various scripts, etc. are stored.
- */
- public static @NotNull File getHelpersRoot() {
- String property = System.getProperty(PROPERTY_HELPERS_LOCATION);
- if (property != null) {
- return new File(property);
- }
- return assertHelpersLayout(getHelperRoot("intellij.python.helpers", "/python/helpers"));
- }
-
- public static @NotNull Path getHelpersProRoot() {
- return assertHelpersProLayout(getExpectedHelpersProRootLocation()).toPath().normalize();
- }
-
- @ApiStatus.Internal
- public static boolean hasHelpersPro() {
- return new File(getExpectedHelpersProRootLocation(), EXPECTED_PRO_HELPER_PACKAGE).exists();
- }
-
- private static @NotNull File getExpectedHelpersProRootLocation() {
- return getHelperRoot("intellij.python.helpers.pro", "/../python/helpers-pro");
- }
-
- private static @NotNull File getHelperRoot(@NotNull String moduleName, @NotNull String relativePath) {
- @NonNls String jarPath = PathUtil.getJarPathForClass(PythonHelpersLocator.class);
-
- if (PluginManagerCore.isRunningFromSources()) {
- return new File(PathManager.getCommunityHomePath() + relativePath);
- }
- else {
- final File pluginBaseDir = getPluginBaseDir(jarPath);
- if (pluginBaseDir != null) {
- return createWithPluginBaseDir(pluginBaseDir, relativePath);
- }
- else {
- return new File(new File(jarPath).getParentFile(), moduleName);
- }
- }
- }
-
- private static @NotNull File createWithPluginBaseDir(@NotNull File corePluginBaseDir, @NotNull String relativePath) {
- if (relativePath.contains(PRO_HELPERS_DIR)) {
- File proPluginBaseDir = new File(corePluginBaseDir.getParentFile(), PYTHON_PRO_PLUGIN_NAME);
- return new File(proPluginBaseDir, PathUtil.getFileName(relativePath));
- }
- return new File(corePluginBaseDir, PathUtil.getFileName(relativePath));
- }
-
- private static @Nullable File getPluginBaseDir(@NonNls String jarPath) {
- if (jarPath.endsWith(".jar")) {
- final File jarFile = new File(jarPath);
-
- LOG.assertTrue(jarFile.exists(), "jar file cannot be null");
- return jarFile.getParentFile().getParentFile();
- }
- return null;
- }
-
- private static @NotNull File assertHelpersLayout(@NotNull File root) {
- final String path = root.getAbsolutePath();
-
- LOG.assertTrue(root.exists(), "Helpers root does not exist " + path);
- for (String child : List.of("generator3", "pycharm", "pycodestyle.py", "pydev", "syspath.py", "typeshed")) {
- LOG.assertTrue(new File(root, child).exists(), "No '" + child + "' inside " + path);
- }
-
- return root;
- }
-
- private static @NotNull File assertHelpersProLayout(@NotNull File root) {
- final String path = root.getAbsolutePath();
-
- LOG.assertTrue(root.exists(), "Helpers pro root does not exist " + path);
- LOG.assertTrue(new File(root, EXPECTED_PRO_HELPER_PACKAGE).exists(),
- "No '" + EXPECTED_PRO_HELPER_PACKAGE + "' inside " + path);
-
- return root;
- }
-
- /**
- * Find a resource by name under helper root.
- *
- * @param resourceName a path relative to helper root
- * @return absolute path of the resource
- */
- public static String getHelperPath(@NonNls @NotNull String resourceName) {
- return getHelperFile(resourceName).getAbsolutePath();
- }
-
- /**
- * Finds a resource file by name under helper root.
- *
- * @param resourceName a path relative to helper root
- * @return a file object pointing to that path; existence is not checked.
- */
- public static @NotNull File getHelperFile(@NotNull String resourceName) {
- return new File(getHelpersRoot(), resourceName);
- }
-
-
- public static String getPythonCommunityPath() {
- File pathFromUltimate = new File(PathManager.getHomePath(), "community/python");
- if (pathFromUltimate.exists()) {
- return pathFromUltimate.getPath();
- }
- return new File(PathManager.getHomePath(), "python").getPath();
- }
-}
diff --git a/python/python-psi-impl/src/com/jetbrains/python/PythonHelpersLocator.kt b/python/python-psi-impl/src/com/jetbrains/python/PythonHelpersLocator.kt
new file mode 100644
index 000000000000..1ed610d27e2a
--- /dev/null
+++ b/python/python-psi-impl/src/com/jetbrains/python/PythonHelpersLocator.kt
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2000-2024 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
+
+import com.intellij.ide.plugins.PluginManagerCore
+import com.intellij.openapi.application.PathManager
+import com.intellij.openapi.diagnostic.Logger
+import com.intellij.openapi.extensions.ExtensionPointName
+import com.intellij.util.PathUtil
+import org.jetbrains.annotations.NonNls
+import java.io.File
+import java.nio.file.Path
+
+abstract class PythonHelpersLocator {
+ companion object {
+ val LOG = Logger.getInstance(PythonHelpersLocator::class.java)
+ private const val PROPERTY_HELPERS_LOCATION = "idea.python.helpers.path"
+ const val COMMUNITY_HELPERS_MODULE_NAME = "intellij.python.helpers"
+ private val EP_NAME: ExtensionPointName =
+ ExtensionPointName.create("com.jetbrains.python.pythonHelpersLocator")
+
+ /**
+ * @return A list of Path objects representing the roots of the Python Helpers.
+ */
+ @JvmStatic
+ fun getHelpersRoots(): List = EP_NAME.extensionList.first().getRoots()
+
+ /**
+ * Retrieves the root file of the Community Helpers extension.
+ * Community Helpers root always should be first in an extension list
+ *
+ * @return The root File of the Community Helpers extension.
+ */
+ @JvmStatic
+ fun getCommunityHelpersRoot(): File = EP_NAME.extensionList.first().getRoots().first().toFile()
+
+ /**
+ * Retrieves File of a helper file given its resource name.
+ *
+ * @param resourceName The name of the helper resource file.
+ * @return File of the helper file, or null if the file does not exist.
+ */
+ @JvmStatic
+ fun findFileInHelpers(resourceName: String): File? {
+ for (helperRoot in getHelpersRoots()) {
+ val file = File(helperRoot.toFile(), resourceName)
+ if (file.exists())
+ return file
+ }
+
+ LOG.warn("File $resourceName does not exist in helpers root")
+ return null
+ }
+
+ /**
+ * Retrieves the absolute path of a helper file given its resource name.
+ *
+ * @param resourceName The name of the helper resource file.
+ * @return The absolute path of the helper file, or null if the file does not exist.
+ */
+ @JvmStatic
+ fun findPathInHelpers(@NonNls resourceName: String): String = findFileInHelpers(resourceName)?.absolutePath ?: ""
+
+ @JvmStatic
+ fun getPythonCommunityPath(): String {
+ val pathFromUltimate = File(PathManager.getHomePath(), "community/python")
+ if (pathFromUltimate.exists()) {
+ return pathFromUltimate.path
+ }
+ return File(PathManager.getHomePath(), "python").path
+ }
+
+ @Deprecated("Use {@link PythonHelpersLocator#findPathInHelpers}.", ReplaceWith("findPathInHelpers(resourceName)"))
+ @JvmStatic
+ fun getHelperPath(@NonNls resourceName: String): String = findPathInHelpers(resourceName)
+ }
+
+ // Always add Community Helpers root on the first place of root's list
+ protected open fun getRoots(): List = listOf(getCommunityHelpersRootFile().toPath().normalize())
+
+ private fun getCommunityHelpersRootFile(): File {
+ val property = System.getProperty(PROPERTY_HELPERS_LOCATION)
+ return if (property != null) {
+ File(property)
+ }
+ else getHelpersRoot(COMMUNITY_HELPERS_MODULE_NAME, "/python/helpers").also {
+ assertHelpersLayout(it)
+ }
+ }
+
+ protected open fun getHelpersRoot(moduleName: String, relativePath: String): File =
+ findRootByJarPath(PathUtil.getJarPathForClass(PythonHelpersLocator::class.java), moduleName, relativePath)
+
+
+ protected fun findRootByJarPath(jarPath: String, moduleName: String, relativePath: String): File {
+ return if (PluginManagerCore.isRunningFromSources()) {
+ File(PathManager.getCommunityHomePath() + relativePath)
+ }
+ else {
+ getPluginBaseDir(jarPath)?.let {
+ File(it, PathUtil.getFileName(relativePath))
+ } ?: File(File(jarPath).parentFile, moduleName)
+ }
+ }
+
+ private fun getPluginBaseDir(jarPath: String): File? {
+ if (jarPath.endsWith(".jar")) {
+ val jarFile = File(jarPath)
+
+ LOG.assertTrue(jarFile.exists(), "jar file cannot be null")
+ return jarFile.parentFile.parentFile
+ }
+
+ return null
+ }
+
+ private fun assertHelpersLayout(root: File): File {
+ val path = root.absolutePath
+
+ LOG.assertTrue(root.exists(), "Helpers root does not exist $path")
+ listOf("generator3", "pycharm", "pycodestyle.py", "pydev", "syspath.py", "typeshed").forEach { child ->
+ LOG.assertTrue(File(root, child).exists(), "No '$child' inside $path")
+ }
+
+ return root
+ }
+}
+
+internal class PythonHelpersLocatorDefault : PythonHelpersLocator()
\ No newline at end of file
diff --git a/python/python-psi-impl/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibUtil.java b/python/python-psi-impl/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibUtil.java
index b8ed1efadcd8..54fe9512a9a1 100644
--- a/python/python-psi-impl/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibUtil.java
+++ b/python/python-psi-impl/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibUtil.java
@@ -30,7 +30,7 @@ public final class PyStdlibUtil {
@Nullable
private static Set loadStdlibPackagesList() {
final Logger log = Logger.getInstance(PyStdlibUtil.class.getName());
- final String helperPath = PythonHelpersLocator.getHelperPath("/tools/stdlib_packages.txt");
+ final String helperPath = PythonHelpersLocator.findPathInHelpers("/tools/stdlib_packages.txt");
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(helperPath), StandardCharsets.UTF_8))) {
return reader.lines().collect(Collectors.toSet());
}
diff --git a/python/python-psi-impl/src/com/jetbrains/python/codeInsight/typing/PyTypeShed.kt b/python/python-psi-impl/src/com/jetbrains/python/codeInsight/typing/PyTypeShed.kt
index d5c9060cec49..b3162646f9b6 100644
--- a/python/python-psi-impl/src/com/jetbrains/python/codeInsight/typing/PyTypeShed.kt
+++ b/python/python-psi-impl/src/com/jetbrains/python/codeInsight/typing/PyTypeShed.kt
@@ -158,7 +158,7 @@ object PyTypeShed {
get() {
val paths = listOf("${PathManager.getConfigPath()}/typeshed",
"${PathManager.getConfigPath()}/../typeshed",
- PythonHelpersLocator.getHelperPath("typeshed"))
+ PythonHelpersLocator.findPathInHelpers("typeshed"))
return paths.asSequence()
.filter { File(it).exists() }
.firstOrNull()
diff --git a/python/python-psi-impl/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsUtil.java b/python/python-psi-impl/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsUtil.java
index cfc556af7379..f77c0cd6c6b3 100644
--- a/python/python-psi-impl/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsUtil.java
+++ b/python/python-psi-impl/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsUtil.java
@@ -81,7 +81,7 @@ public final class PyUserSkeletonsUtil {
private static List getPossibleUserSkeletonsPaths() {
final List result = new ArrayList<>();
result.add(PathManager.getConfigPath() + File.separator + USER_SKELETONS_DIR);
- result.add(PythonHelpersLocator.getHelperPath(USER_SKELETONS_DIR));
+ result.add(PythonHelpersLocator.findPathInHelpers(USER_SKELETONS_DIR));
return result;
}
diff --git a/python/python-psi-impl/src/com/jetbrains/python/documentation/PyDocumentationBuilder.java b/python/python-psi-impl/src/com/jetbrains/python/documentation/PyDocumentationBuilder.java
index 1c366475ecb4..9977180ffd53 100644
--- a/python/python-psi-impl/src/com/jetbrains/python/documentation/PyDocumentationBuilder.java
+++ b/python/python-psi-impl/src/com/jetbrains/python/documentation/PyDocumentationBuilder.java
@@ -203,7 +203,7 @@ public class PyDocumentationBuilder {
private void buildForKeyword(@NotNull String name) {
try {
- try (FileReader reader = new FileReader(PythonHelpersLocator.getHelperPath("/tools/python_keywords/" + name),
+ try (FileReader reader = new FileReader(PythonHelpersLocator.findPathInHelpers("/tools/python_keywords/" + name),
StandardCharsets.UTF_8)) {
final String text = FileUtil.loadTextAndClose(reader);
final String converted = StringUtil.convertLineSeparators(text, "\n");
diff --git a/python/python-psi-impl/src/com/jetbrains/python/validation/UnsupportedFeaturesUtil.java b/python/python-psi-impl/src/com/jetbrains/python/validation/UnsupportedFeaturesUtil.java
index a75fb9c2b166..b18c9e924f4d 100644
--- a/python/python-psi-impl/src/com/jetbrains/python/validation/UnsupportedFeaturesUtil.java
+++ b/python/python-psi-impl/src/com/jetbrains/python/validation/UnsupportedFeaturesUtil.java
@@ -42,7 +42,7 @@ public final class UnsupportedFeaturesUtil {
private static void fillTestCaseMethods() throws IOException {
final Logger log = Logger.getInstance(UnsupportedFeaturesUtil.class.getName());
- try (FileReader reader = new FileReader(PythonHelpersLocator.getHelperPath("/tools/class_method_versions.xml"))) {
+ try (FileReader reader = new FileReader(PythonHelpersLocator.findPathInHelpers("/tools/class_method_versions.xml"))) {
final XMLReader xr = XMLReaderFactory.createXMLReader();
final ClassMethodsParser parser = new ClassMethodsParser();
xr.setContentHandler(parser);
@@ -55,7 +55,7 @@ public final class UnsupportedFeaturesUtil {
private static void fillMaps() throws IOException {
Logger log = Logger.getInstance(UnsupportedFeaturesUtil.class.getName());
- try (FileReader reader = new FileReader(PythonHelpersLocator.getHelperPath("/tools/versions.xml"))) {
+ try (FileReader reader = new FileReader(PythonHelpersLocator.findPathInHelpers("/tools/versions.xml"))) {
XMLReader xr = XMLReaderFactory.createXMLReader();
VersionsParser parser = new VersionsParser();
xr.setContentHandler(parser);
diff --git a/python/python-sdk/src/com/jetbrains/python/sdk/skeletons/PyLegacySkeletonGenerator.java b/python/python-sdk/src/com/jetbrains/python/sdk/skeletons/PyLegacySkeletonGenerator.java
index 36dee0d1c77b..d431e0d64149 100644
--- a/python/python-sdk/src/com/jetbrains/python/sdk/skeletons/PyLegacySkeletonGenerator.java
+++ b/python/python-sdk/src/com/jetbrains/python/sdk/skeletons/PyLegacySkeletonGenerator.java
@@ -97,7 +97,7 @@ public class PyLegacySkeletonGenerator extends PySkeletonGenerator {
public List getCommandLine() {
final List commandLine = new ArrayList<>();
commandLine.add(mySdk.getHomePath());
- commandLine.add(PythonHelpersLocator.getHelperPath(GENERATOR3));
+ commandLine.add(PythonHelpersLocator.findPathInHelpers(GENERATOR3));
commandLine.add("-d");
commandLine.add(mySkeletonsPath);
if (!ContainerUtil.isEmpty(myAssemblyRefs)) {
diff --git a/python/src/com/jetbrains/python/PythonHelper.java b/python/src/com/jetbrains/python/PythonHelper.java
index 552fb54e30b6..4cbec26ce837 100644
--- a/python/src/com/jetbrains/python/PythonHelper.java
+++ b/python/src/com/jetbrains/python/PythonHelper.java
@@ -18,8 +18,7 @@ import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
-import static com.jetbrains.python.PythonHelpersLocator.getHelperFile;
-import static com.jetbrains.python.PythonHelpersLocator.getHelpersRoot;
+import static com.jetbrains.python.PythonHelpersLocator.*;
public enum PythonHelper implements HelperPackage {
GENERATOR3("generator3/__main__.py"),
@@ -91,12 +90,12 @@ public enum PythonHelper implements HelperPackage {
private static @NotNull PathHelperPackage findModule(String moduleEntryPoint, String path, boolean asModule, String[] thirdPartyDependencies) {
List dependencies = HelperDependency.findThirdPartyDependencies(thirdPartyDependencies);
- if (getHelperFile(path + ".zip").isFile()) {
+ if (findFileInHelpers(path + ".zip") != null) {
return new ModuleHelperPackage(moduleEntryPoint, path + ".zip", dependencies);
}
- if (!asModule && new File(getHelperFile(path), moduleEntryPoint + ".py").isFile()) {
- return new ScriptPythonHelper(moduleEntryPoint + ".py", getHelperFile(path), dependencies);
+ if (!asModule && new File(findFileInHelpers(path), moduleEntryPoint + ".py").isFile()) {
+ return new ScriptPythonHelper(moduleEntryPoint + ".py", findFileInHelpers(path), dependencies);
}
return new ModuleHelperPackage(moduleEntryPoint, path, dependencies);
@@ -113,7 +112,7 @@ public enum PythonHelper implements HelperPackage {
}
PythonHelper(String helperScript) {
- myModule = new ScriptPythonHelper(helperScript, getHelpersRoot(), Collections.emptyList());
+ myModule = new ScriptPythonHelper(helperScript, getCommunityHelpersRoot(), Collections.emptyList());
}
public abstract static class PathHelperPackage implements HelperPackage {
@@ -187,7 +186,7 @@ public enum PythonHelper implements HelperPackage {
private final String myModuleName;
public ModuleHelperPackage(String moduleName, String relativePath, @NotNull List dependencies) {
- super(getHelperFile(relativePath).getAbsolutePath(), dependencies);
+ super(findPathInHelpers(relativePath), dependencies);
this.myModuleName = moduleName;
}
@@ -255,7 +254,7 @@ public enum PythonHelper implements HelperPackage {
}
private static @NotNull File getHelpersThirdPartyDir() {
- return getHelperFile("third_party");
+ return findFileInHelpers("third_party");
}
}
diff --git a/python/src/com/jetbrains/python/console/PydevConsoleRunnerFactory.kt b/python/src/com/jetbrains/python/console/PydevConsoleRunnerFactory.kt
index f2ffe0d54761..2b16a2064f77 100644
--- a/python/src/com/jetbrains/python/console/PydevConsoleRunnerFactory.kt
+++ b/python/src/com/jetbrains/python/console/PydevConsoleRunnerFactory.kt
@@ -215,7 +215,8 @@ open class PydevConsoleRunnerFactory : PythonConsoleRunnerFactory() {
paths.add(getTargetEnvironmentValueForLocalPath(Path.of(projectRoot)))
val targetEnvironmentRequest = findPythonTargetInterpreter(sdk, project)
- val (communityHelpers) = targetEnvironmentRequest.preparePyCharmHelpers()
+ // // Community Helpers root should be first in the list
+ val communityHelpers = targetEnvironmentRequest.preparePyCharmHelpers().helpers.first()
for (helper in listOf("pycharm", "pydev")) {
paths.add(communityHelpers.targetPathFun.getRelativeTargetPath(helper))
}
diff --git a/python/src/com/jetbrains/python/debugger/PyCythonExtensionWarning.java b/python/src/com/jetbrains/python/debugger/PyCythonExtensionWarning.java
index 756963f55589..cc21cb2a8dae 100644
--- a/python/src/com/jetbrains/python/debugger/PyCythonExtensionWarning.java
+++ b/python/src/com/jetbrains/python/debugger/PyCythonExtensionWarning.java
@@ -113,7 +113,7 @@ public final class PyCythonExtensionWarning {
throw new ExecutionException(PyBundle.message("debugger.cython.python.run.configuration.should.be.selected"));
}
final String interpreterPath = runConfiguration.getInterpreterPath();
- final String helpersPath = PythonHelpersLocator.getHelpersRoot().getPath();
+ final String helpersPath = PythonHelpersLocator.getCommunityHelpersRoot().getPath();
final String cythonExtensionsDir = PyDebugRunner.CYTHON_EXTENSIONS_DIR;
final String[] cythonArgs =
diff --git a/python/src/com/jetbrains/python/packaging/PyPackageManagerImplBase.java b/python/src/com/jetbrains/python/packaging/PyPackageManagerImplBase.java
index 49f1494a652b..db2d7ce49008 100644
--- a/python/src/com/jetbrains/python/packaging/PyPackageManagerImplBase.java
+++ b/python/src/com/jetbrains/python/packaging/PyPackageManagerImplBase.java
@@ -230,7 +230,7 @@ public abstract class PyPackageManagerImplBase extends PyPackageManager {
}
protected @Nullable String getHelperPath(final @NotNull String helper) throws ExecutionException {
- return PythonHelpersLocator.getHelperPath(helper);
+ return PythonHelpersLocator.findPathInHelpers(helper);
}
protected static @NotNull List makeSafeToDisplayCommand(@NotNull List cmdline) {
diff --git a/python/src/com/jetbrains/python/packaging/PyTargetEnvironmentPackageManager.java b/python/src/com/jetbrains/python/packaging/PyTargetEnvironmentPackageManager.java
index f97ad75ea6d2..5aceb7d8d78c 100644
--- a/python/src/com/jetbrains/python/packaging/PyTargetEnvironmentPackageManager.java
+++ b/python/src/com/jetbrains/python/packaging/PyTargetEnvironmentPackageManager.java
@@ -374,7 +374,7 @@ public class PyTargetEnvironmentPackageManager extends PyPackageManagerImplBase
private static @NotNull HelperPackage getPipHelperPackage() {
return new PythonHelper.ScriptPythonHelper(PIP_WHEEL_NAME + "/" + PyPackageUtil.PIP,
- PythonHelpersLocator.getHelpersRoot(),
+ PythonHelpersLocator.getCommunityHelpersRoot(),
Collections.emptyList());
}
diff --git a/python/src/com/jetbrains/python/packaging/conda/CondaPackageCache.kt b/python/src/com/jetbrains/python/packaging/conda/CondaPackageCache.kt
index df10428fd763..ca05a26ec140 100644
--- a/python/src/com/jetbrains/python/packaging/conda/CondaPackageCache.kt
+++ b/python/src/com/jetbrains/python/packaging/conda/CondaPackageCache.kt
@@ -46,7 +46,7 @@ class CondaPackageCache : PythonPackageCache {
.first { it.envIdentity is PyCondaEnvIdentity.UnnamedEnv && it.envIdentity.isBase }
val helpersAware = PythonInterpreterTargetEnvironmentFactory.findPythonTargetInterpreter(sdk, project)
- val (communityHelpers) = helpersAware.preparePyCharmHelpers()
+ val communityHelpers = helpersAware.preparePyCharmHelpers().helpers.first()
val targetReq = targetConfig?.createEnvironmentRequest(project) ?: LocalTargetEnvironmentRequest()
diff --git a/python/src/com/jetbrains/python/packaging/toolwindow/PyPackagingToolWindowService.kt b/python/src/com/jetbrains/python/packaging/toolwindow/PyPackagingToolWindowService.kt
index a23fe696b02d..b243750440e8 100644
--- a/python/src/com/jetbrains/python/packaging/toolwindow/PyPackagingToolWindowService.kt
+++ b/python/src/com/jetbrains/python/packaging/toolwindow/PyPackagingToolWindowService.kt
@@ -266,8 +266,8 @@ class PyPackagingToolWindowService(val project: Project, val serviceScope: Corou
// todo[akniazev]: this workaround should can be removed when PY-57134 is fixed
val helperLocation = if (localSdk.sdkFlavor.getLanguageLevel(localSdk).isPython2) "py2only" else "py3only"
- val path = PythonHelpersLocator.getHelpersRoot().toPath().resolve(helperLocation)
- pythonExecution.applyHelperPackageToPythonPath(listOf(path.toString()), helpersAwareTargetRequest)
+ val path = PythonHelpersLocator.findPathInHelpers(helperLocation)
+ pythonExecution.applyHelperPackageToPythonPath(listOf(path), helpersAwareTargetRequest)
pythonExecution.addParameter("rst2html_no_code")
val targetProgressIndicator = TargetProgressIndicator.EMPTY
diff --git a/python/src/com/jetbrains/python/remote/PythonRemoteInterpreterManager.java b/python/src/com/jetbrains/python/remote/PythonRemoteInterpreterManager.java
index a2036f6f9730..f084da1b07e5 100644
--- a/python/src/com/jetbrains/python/remote/PythonRemoteInterpreterManager.java
+++ b/python/src/com/jetbrains/python/remote/PythonRemoteInterpreterManager.java
@@ -62,7 +62,7 @@ public abstract class PythonRemoteInterpreterManager {
}
public static void addHelpersMapping(@NotNull RemoteSdkProperties data, @NotNull PyRemotePathMapper pathMapper) {
- pathMapper.addMapping(PythonHelpersLocator.getHelpersRoot().getPath(), data.getHelpersPath(), PyPathMappingType.HELPERS);
+ pathMapper.addMapping(PythonHelpersLocator.getCommunityHelpersRoot().getPath(), data.getHelpersPath(), PyPathMappingType.HELPERS);
}
public static @NotNull PyRemotePathMapper appendBasicMappings(@Nullable Project project,
diff --git a/python/src/com/jetbrains/python/run/PythonCommandLineState.java b/python/src/com/jetbrains/python/run/PythonCommandLineState.java
index 67a0af4ecfa7..e23b7a34346e 100644
--- a/python/src/com/jetbrains/python/run/PythonCommandLineState.java
+++ b/python/src/com/jetbrains/python/run/PythonCommandLineState.java
@@ -878,8 +878,8 @@ public abstract class PythonCommandLineState extends CommandLineState {
if (isDebug && PythonSdkFlavor.getFlavor(sdkHome) instanceof JythonSdkFlavor) {
//that fixes Jython problem changing sys.argv on execfile, see PY-8164
- pythonPath.add(PythonHelpersLocator.getHelperPath("pycharm"));
- pythonPath.add(PythonHelpersLocator.getHelperPath("pydev"));
+ pythonPath.add(PythonHelpersLocator.findPathInHelpers("pycharm"));
+ pythonPath.add(PythonHelpersLocator.findPathInHelpers("pydev"));
}
return pythonPath;
diff --git a/python/src/com/jetbrains/python/run/PythonScripts.kt b/python/src/com/jetbrains/python/run/PythonScripts.kt
index 73a3c262775d..c7fb4949dc2f 100644
--- a/python/src/com/jetbrains/python/run/PythonScripts.kt
+++ b/python/src/com/jetbrains/python/run/PythonScripts.kt
@@ -147,12 +147,7 @@ fun addHelperEntriesToPythonPath(envs: MutableMap {
val targetPlatform = helpersAwareTargetRequest.targetEnvironmentRequest.targetPlatform
val pythonHelpersMappings = helpersAwareTargetRequest.preparePyCharmHelpers()
- val pythonHelpersRoots =
- listOfNotNull(
- pythonHelpersMappings.communityHelpers,
- pythonHelpersMappings.proHelpers
- )
- .map(PathMapping::localPath)
+ val pythonHelpersRoots = pythonHelpersMappings.helpers.map(PathMapping::localPath)
val targetPathSeparator = targetPlatform.platform.pathSeparator
fun T?.onResolutionFailure(message: String): T? {
diff --git a/python/src/com/jetbrains/python/run/TargetedPythonPaths.kt b/python/src/com/jetbrains/python/run/TargetedPythonPaths.kt
index f06e977cd6f9..4501c17d8b75 100644
--- a/python/src/com/jetbrains/python/run/TargetedPythonPaths.kt
+++ b/python/src/com/jetbrains/python/run/TargetedPythonPaths.kt
@@ -95,7 +95,7 @@ private fun collectPythonPath(context: Context,
if (isDebug && context.sdk?.let { PythonSdkFlavor.getFlavor(it) } is JythonSdkFlavor) {
//that fixes Jython problem changing sys.argv on execfile, see PY-8164
for (helpersResource in listOf("pycharm", "pydev")) {
- val helperPath = PythonHelpersLocator.getHelperPath(helpersResource)
+ val helperPath = PythonHelpersLocator.findPathInHelpers(helpersResource)
val targetHelperPath = targetPath(Path.of(helperPath))
pythonPath.add(targetHelperPath)
}
diff --git a/python/src/com/jetbrains/python/run/target/HelpersAwareLocalTargetEnvironmentRequest.kt b/python/src/com/jetbrains/python/run/target/HelpersAwareLocalTargetEnvironmentRequest.kt
index ddaf3d646ac8..ad66a96227cd 100644
--- a/python/src/com/jetbrains/python/run/target/HelpersAwareLocalTargetEnvironmentRequest.kt
+++ b/python/src/com/jetbrains/python/run/target/HelpersAwareLocalTargetEnvironmentRequest.kt
@@ -12,8 +12,7 @@ class HelpersAwareLocalTargetEnvironmentRequest : HelpersAwareTargetEnvironmentR
override fun preparePyCharmHelpers(): PythonHelpersMappings =
PythonHelpersMappings(
- communityHelpers = getPythonHelpers().mapToSelf(),
- proHelpers = getPythonProHelpers()?.mapToSelf(),
+ getPythonHelpers().map { it.mapToSelf() }
)
}
diff --git a/python/src/com/jetbrains/python/run/target/HelpersAwareTargetEnvironmentRequest.kt b/python/src/com/jetbrains/python/run/target/HelpersAwareTargetEnvironmentRequest.kt
index cb2cf3af5f6d..8ca25c90328c 100644
--- a/python/src/com/jetbrains/python/run/target/HelpersAwareTargetEnvironmentRequest.kt
+++ b/python/src/com/jetbrains/python/run/target/HelpersAwareTargetEnvironmentRequest.kt
@@ -14,7 +14,7 @@ import kotlin.io.path.absolutePathString
data class PathMapping(val localPath: Path, val targetPathFun: TargetEnvironmentFunction)
-data class PythonHelpersMappings(val communityHelpers: PathMapping, val proHelpers: PathMapping?)
+data class PythonHelpersMappings(val helpers: List)
/**
* The target request for Python interpreter configured in PyCharm on a
@@ -31,27 +31,22 @@ interface HelpersAwareTargetEnvironmentRequest {
fun preparePyCharmHelpers(): PythonHelpersMappings
}
-fun getPythonHelpers(): Path = PythonHelpersLocator.getHelpersRoot().toPath()
-
-fun getPythonProHelpers(): Path? = if (PythonHelpersLocator.hasHelpersPro()) PythonHelpersLocator.getHelpersProRoot() else null
+fun getPythonHelpers(): List = PythonHelpersLocator.getHelpersRoots()
/**
* Returns the mappings where Python helpers of Community and Professional versions are mapped to a single directory.
* For example, when their contents are uploaded to the same directory on the SSH machine.
*/
fun singleDirectoryPythonHelpersMappings(targetPathFun: TargetEnvironmentFunction): PythonHelpersMappings =
- PythonHelpersMappings(
- communityHelpers = getPythonHelpers() to targetPathFun,
- proHelpers = getPythonProHelpers()?.let { pythonProHelpers -> pythonProHelpers to targetPathFun },
- )
+ PythonHelpersMappings(getPythonHelpers().map { it to targetPathFun })
+
infix fun Path.to(targetPathFun: TargetEnvironmentFunction): PathMapping =
PathMapping(localPath = this, targetPathFun)
fun String.tryResolveAsPythonHelperDir(mappings: PythonHelpersMappings): PathMapping? {
- val (communityHelpers, proHelpers) = mappings
val thisLocalPath = Path.of(this)
- val rootPaths = listOfNotNull(communityHelpers, proHelpers)
+ val rootPaths = mappings.helpers
.filter { (localPath) -> FileUtil.isAncestor(localPath.absolutePathString(), this, false) }
return rootPaths
.firstNotNullOfOrNull { (localPath, targetPathFun) ->
diff --git a/python/src/com/jetbrains/python/sdk/flavors/WinPythonSdkFlavor.java b/python/src/com/jetbrains/python/sdk/flavors/WinPythonSdkFlavor.java
index ab2c8495c2a8..d0b1da89e003 100644
--- a/python/src/com/jetbrains/python/sdk/flavors/WinPythonSdkFlavor.java
+++ b/python/src/com/jetbrains/python/sdk/flavors/WinPythonSdkFlavor.java
@@ -69,7 +69,7 @@ public class WinPythonSdkFlavor extends CPythonSdkFlavor {
public @NotNull Collection<@NotNull Path> suggestLocalHomePaths(final @Nullable Module module, final @Nullable UserDataHolder context) {
Set candidates = new TreeSet<>();
findInCandidatePaths(candidates, "python.exe", "jython.bat", "pypy.exe");
- findInstallations(candidates, "python.exe", PythonHelpersLocator.getHelpersRoot().getParent());
+ findInstallations(candidates, "python.exe", PythonHelpersLocator.getCommunityHelpersRoot().getParent());
return ContainerUtil.map(candidates, Path::of);
}
diff --git a/python/src/com/jetbrains/python/sdk/skeletons/PySkeletonRefresher.java b/python/src/com/jetbrains/python/sdk/skeletons/PySkeletonRefresher.java
index 37f850dcde90..0a4974dde662 100644
--- a/python/src/com/jetbrains/python/sdk/skeletons/PySkeletonRefresher.java
+++ b/python/src/com/jetbrains/python/sdk/skeletons/PySkeletonRefresher.java
@@ -187,7 +187,7 @@ public class PySkeletonRefresher {
}
private static int readGeneratorVersion() {
- File versionFile = PythonHelpersLocator.getHelperFile("generator3/version.txt");
+ File versionFile = PythonHelpersLocator.findFileInHelpers("generator3/version.txt");
try (Reader reader = new InputStreamReader(new FileInputStream(versionFile), StandardCharsets.UTF_8)) {
return PySkeletonHeader.fromVersionString(StreamUtil.readText(reader).trim());
}
diff --git a/python/src/com/jetbrains/python/testing/PythonTestCommandLineStateBase.java b/python/src/com/jetbrains/python/testing/PythonTestCommandLineStateBase.java
index 8a31bc9d661d..dcefac5c78d6 100644
--- a/python/src/com/jetbrains/python/testing/PythonTestCommandLineStateBase.java
+++ b/python/src/com/jetbrains/python/testing/PythonTestCommandLineStateBase.java
@@ -236,7 +236,7 @@ public abstract class PythonTestCommandLineStateBase envs, boolean passParentEnvs) {
super.customizeEnvironmentVars(envs, passParentEnvs);
- envs.put("PYCHARM_HELPERS_DIR", PythonHelpersLocator.getHelperPath("pycharm"));
+ envs.put("PYCHARM_HELPERS_DIR", PythonHelpersLocator.findPathInHelpers("pycharm"));
}
@Override
@@ -245,8 +245,10 @@ public abstract class PythonTestCommandLineStateBase targetPycharmHelpersPath =
- TargetEnvironmentFunctions.getRelativeTargetPath(helpersTargetPath.getCommunityHelpers().getTargetPathFun(), "pycharm");
+ TargetEnvironmentFunctions.getRelativeTargetPath(communityTargetPathFun, "pycharm");
envs.put("PYCHARM_HELPERS_DIR", targetPycharmHelpersPath);
}