From 58d8eddeb8969de95e876a124d34e97d6ab91724 Mon Sep 17 00:00:00 2001 From: "Egor.Eliseev" Date: Tue, 2 Jul 2024 11:43:46 +0000 Subject: [PATCH] PY-73525 Split HelpersLocator into Community/Pro versions Merge-request: IJ-MR-138058 Merged-by: Egor Eliseev GitOrigin-RevId: cd82bc44337e7fdd182262c44ea5ca29e1804ad2 --- .../python/PythonCommunityPluginModules.kt | 31 ++-- .../resources/META-INF/PythonPsiImpl.xml | 7 + .../python/PythonHelpersLocator.java | 148 ------------------ .../jetbrains/python/PythonHelpersLocator.kt | 143 +++++++++++++++++ .../codeInsight/stdlib/PyStdlibUtil.java | 2 +- .../python/codeInsight/typing/PyTypeShed.kt | 2 +- .../userSkeletons/PyUserSkeletonsUtil.java | 2 +- .../documentation/PyDocumentationBuilder.java | 2 +- .../validation/UnsupportedFeaturesUtil.java | 4 +- .../skeletons/PyLegacySkeletonGenerator.java | 2 +- .../com/jetbrains/python/PythonHelper.java | 15 +- .../console/PydevConsoleRunnerFactory.kt | 3 +- .../debugger/PyCythonExtensionWarning.java | 2 +- .../packaging/PyPackageManagerImplBase.java | 2 +- .../PyTargetEnvironmentPackageManager.java | 2 +- .../packaging/conda/CondaPackageCache.kt | 2 +- .../PyPackagingToolWindowService.kt | 4 +- .../PythonRemoteInterpreterManager.java | 2 +- .../python/run/PythonCommandLineState.java | 4 +- .../com/jetbrains/python/run/PythonScripts.kt | 7 +- .../python/run/TargetedPythonPaths.kt | 2 +- ...lpersAwareLocalTargetEnvironmentRequest.kt | 3 +- .../HelpersAwareTargetEnvironmentRequest.kt | 15 +- .../sdk/flavors/WinPythonSdkFlavor.java | 2 +- .../sdk/skeletons/PySkeletonRefresher.java | 2 +- .../PythonTestCommandLineStateBase.java | 6 +- 26 files changed, 205 insertions(+), 211 deletions(-) delete mode 100644 python/python-psi-impl/src/com/jetbrains/python/PythonHelpersLocator.java create mode 100644 python/python-psi-impl/src/com/jetbrains/python/PythonHelpersLocator.kt 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); }