Python: VirtualEnvReader refactoring: move the same module as PythonSdkUtil, and substitute a couple of methods.

`PythonSdkUtil` duplicates VER logic. One Jython-specific thing was also removed as we do not need Jython anymore

GitOrigin-RevId: 658fc42b485ac074a6d89fce3c7408e51cdc8f95
This commit is contained in:
Ilya.Kazakevich
2024-08-12 21:08:02 +02:00
committed by intellij-monorepo-bot
parent d8b8f63677
commit b1a4c55771
22 changed files with 89 additions and 121 deletions

View File

@@ -93,14 +93,14 @@ class PyPipfileSdkConfiguration : PyProjectSdkConfigurationExtension {
return null return null
} }
val path = PythonSdkUtil.getPythonExecutable(pipEnv).also { val path = VirtualEnvReader.Instance.findPythonInPythonRoot(Path.of(pipEnv)).also {
if (it == null) { if (it == null) {
PySdkConfigurationCollector.logPipEnv(module.project, PipEnvResult.NO_EXECUTABLE) PySdkConfigurationCollector.logPipEnv(module.project, PipEnvResult.NO_EXECUTABLE)
LOGGER.warn("Python executable is not found: $pipEnv") LOGGER.warn("Python executable is not found: $pipEnv")
} }
} ?: return null } ?: return null
val file = LocalFileSystem.getInstance().refreshAndFindFileByPath(path).also { val file = LocalFileSystem.getInstance().refreshAndFindFileByPath(path.toString()).also {
if (it == null) { if (it == null) {
PySdkConfigurationCollector.logPipEnv(module.project, PipEnvResult.NO_EXECUTABLE_FILE) PySdkConfigurationCollector.logPipEnv(module.project, PipEnvResult.NO_EXECUTABLE_FILE)
LOGGER.warn("Python executable file is not found: $path") LOGGER.warn("Python executable file is not found: $path")

View File

@@ -91,13 +91,13 @@ class PyPoetrySdkConfiguration : PyProjectSdkConfigurationExtension {
return null return null
} }
val path = PythonSdkUtil.getPythonExecutable(poetry).also { val path = VirtualEnvReader.Instance.findPythonInPythonRoot(Path.of(poetry)).also {
if (it == null) { if (it == null) {
LOGGER.warn("Python executable is not found: $poetry") LOGGER.warn("Python executable is not found: $poetry")
} }
} ?: return null } ?: return null
val file = LocalFileSystem.getInstance().refreshAndFindFileByPath(path).also { val file = LocalFileSystem.getInstance().refreshAndFindFileByPath(path.toString()).also {
if (it == null) { if (it == null) {
LOGGER.warn("Python executable file is not found: $path") LOGGER.warn("Python executable file is not found: $path")
} }

View File

@@ -15,12 +15,15 @@ import com.intellij.openapi.util.NlsSafe;
import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileSystemUtil; import com.intellij.openapi.util.io.FileSystemUtil;
import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.StandardFileSystems;
import com.intellij.openapi.vfs.*; import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFile;
import com.intellij.util.ObjectUtils; import com.intellij.util.ObjectUtils;
import com.intellij.util.SystemProperties; import com.intellij.util.SystemProperties;
import com.intellij.util.concurrency.annotations.RequiresBackgroundThread;
import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.ContainerUtil;
import com.jetbrains.python.PyNames; import com.jetbrains.python.PyNames;
import com.jetbrains.python.PythonRuntimeService; import com.jetbrains.python.PythonRuntimeService;
@@ -66,9 +69,6 @@ public final class PythonSdkUtil {
*/ */
public static final OrderRootType BUILTIN_ROOT_TYPE = OrderRootType.CLASSES; public static final OrderRootType BUILTIN_ROOT_TYPE = OrderRootType.CLASSES;
static final String[] WINDOWS_EXECUTABLE_SUFFIXES = {"cmd", "exe", "bat", "com"}; static final String[] WINDOWS_EXECUTABLE_SUFFIXES = {"cmd", "exe", "bat", "com"};
private static final String[] DIRS_WITH_BINARY = {"", "bin", "Scripts", "net45"};
private static final String[] UNIX_BINARY_NAMES = {"jython", "pypy", "python", "python3"};
private static final String[] WIN_BINARY_NAMES = {"jython.bat", "ipy.exe", "pypy.exe", "python.exe", "python3.exe"};
private static final Predicate<Sdk> REMOTE_SDK_PREDICATE = PythonSdkUtil::isRemote; private static final Predicate<Sdk> REMOTE_SDK_PREDICATE = PythonSdkUtil::isRemote;
private static final Key<PySkeletonHeader> CACHED_SKELETON_HEADER = Key.create("CACHED_SKELETON_HEADER"); private static final Key<PySkeletonHeader> CACHED_SKELETON_HEADER = Key.create("CACHED_SKELETON_HEADER");
@@ -316,66 +316,27 @@ public final class PythonSdkUtil {
return getAllSdks().stream().filter(REMOTE_SDK_PREDICATE.negate()).collect(Collectors.toList()); return getAllSdks().stream().filter(REMOTE_SDK_PREDICATE.negate()).collect(Collectors.toList());
} }
// It is only here for external plugins
@Nullable @Nullable
@RequiresBackgroundThread(generateAssertion = false)
public static String getPythonExecutable(@NotNull String rootPath) { public static String getPythonExecutable(@NotNull String rootPath) {
final File rootFile = new File(rootPath); var python = VirtualEnvReader.getInstance().findPythonInPythonRoot(Path.of(rootPath));
if (rootFile.isFile()) { return (python != null) ? python.toString() : null;
return rootFile.getAbsolutePath();
}
for (String dir : DIRS_WITH_BINARY) {
final File subDir;
if (StringUtil.isEmpty(dir)) {
subDir = rootFile;
}
else {
subDir = new File(rootFile, dir);
}
if (!subDir.isDirectory()) {
continue;
}
for (String binaryName : getBinaryNames()) {
final File executable = new File(subDir, binaryName);
if (executable.isFile()) {
return executable.getAbsolutePath();
}
}
}
return null;
} }
/**
* @deprecated use {@link #getExecutablePath(Path, String)}
*/
@Deprecated
@Nullable @Nullable
@RequiresBackgroundThread(generateAssertion = false)
public static String getExecutablePath(@NotNull final String homeDirectory, @NotNull String name) { public static String getExecutablePath(@NotNull final String homeDirectory, @NotNull String name) {
File binPath = new File(homeDirectory); Path path = getExecutablePath(Path.of(homeDirectory), name);
File binDir = binPath.getParentFile(); return (path != null) ? path.toString() : null;
if (binDir == null) return null;
VirtualFileSystem localVfs = StandardFileSystems.local();
File runner = new File(binDir, name);
if (runner.exists()) return localVfs.extractPresentableUrl(runner.getPath());
runner = new File(new File(binDir, "Scripts"), name);
if (runner.exists()) return localVfs.extractPresentableUrl(runner.getPath());
runner = new File(new File(binDir.getParentFile(), "Scripts"), name);
if (runner.exists()) return localVfs.extractPresentableUrl(runner.getPath());
runner = new File(new File(binDir.getParentFile(), "local"), name);
if (runner.exists()) return localVfs.extractPresentableUrl(runner.getPath());
runner = new File(new File(new File(binDir.getParentFile(), "local"), "bin"), name);
if (runner.exists()) return localVfs.extractPresentableUrl(runner.getPath());
// if interpreter is a symlink
if (FileSystemUtil.isSymLink(homeDirectory)) {
String resolvedPath = FileSystemUtil.resolveSymLink(homeDirectory);
if (resolvedPath != null) {
return getExecutablePath(resolvedPath, name);
}
}
// Search in standard unix path
runner = new File(new File("/usr", "bin"), name);
if (runner.exists()) return localVfs.extractPresentableUrl(runner.getPath());
runner = new File(new File(new File("/usr", "local"), "bin"), name);
if (runner.exists()) return localVfs.extractPresentableUrl(runner.getPath());
return null;
} }
@Nullable @Nullable
@RequiresBackgroundThread(generateAssertion = false)
public static Path getExecutablePath(@NotNull Path homeDirectory, @NotNull String name) { public static Path getExecutablePath(@NotNull Path homeDirectory, @NotNull String name) {
Path binDir = homeDirectory.getParent(); Path binDir = homeDirectory.getParent();
if (binDir == null) return null; if (binDir == null) return null;
@@ -459,14 +420,6 @@ public final class PythonSdkUtil {
return null; return null;
} }
private static String[] getBinaryNames() {
if (SystemInfo.isUnix) {
return UNIX_BINARY_NAMES;
}
else {
return WIN_BINARY_NAMES;
}
}
@Nullable @Nullable
public static Sdk findSdkByKey(@NotNull String key) { public static Sdk findSdkByKey(@NotNull String key) {

View File

@@ -1,12 +1,10 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. // Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.jetbrains.python.sdk.flavors package com.jetbrains.python.sdk
import com.intellij.openapi.util.IntellijInternalApi
import com.intellij.openapi.util.SystemInfoRt import com.intellij.openapi.util.SystemInfoRt
import com.intellij.openapi.util.io.toCanonicalPath import com.intellij.openapi.util.io.toCanonicalPath
import com.intellij.util.SystemProperties import com.intellij.util.SystemProperties
import com.intellij.util.concurrency.annotations.RequiresBackgroundThread import com.intellij.util.concurrency.annotations.RequiresBackgroundThread
import com.jetbrains.python.sdk.tryResolvePath
import org.jetbrains.annotations.ApiStatus import org.jetbrains.annotations.ApiStatus
import org.jetbrains.annotations.NonNls import org.jetbrains.annotations.NonNls
import java.io.IOException import java.io.IOException
@@ -19,7 +17,6 @@ import kotlin.io.path.*
typealias PythonBinary = Path typealias PythonBinary = Path
typealias Directory = Path typealias Directory = Path
@IntellijInternalApi
@ApiStatus.Internal @ApiStatus.Internal
class VirtualEnvReader( class VirtualEnvReader(
private val envs: Map<@NonNls String, @NonNls String> = System.getenv(), private val envs: Map<@NonNls String, @NonNls String> = System.getenv(),
@@ -105,7 +102,7 @@ class VirtualEnvReader(
* [dir] is root directory of python installation or virtualenv * [dir] is root directory of python installation or virtualenv
*/ */
@RequiresBackgroundThread @RequiresBackgroundThread
private fun findPythonInPythonRoot(dir: Directory): PythonBinary? { fun findPythonInPythonRoot(dir: Directory): PythonBinary? {
if (!dir.isDirectory()) { if (!dir.isDirectory()) {
return null return null
} }

View File

@@ -33,6 +33,7 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*; import javax.swing.*;
import java.awt.*; import java.awt.*;
import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@@ -67,8 +68,8 @@ public class SphinxBaseCommand {
setTitle(RestBundle.message("sphinx.set.working.directory.dialog.title")); setTitle(RestBundle.message("sphinx.set.working.directory.dialog.title"));
init(); init();
VirtualFile baseDir = project.getBaseDir(); VirtualFile baseDir = project.getBaseDir();
String path = baseDir != null? baseDir.getPath() : ""; String path = baseDir != null ? baseDir.getPath() : "";
myInputFile.setText(path); myInputFile.setText(path);
myInputFile.setEditable(false); myInputFile.setEditable(false);
myInputFile.addBrowseFolderListener(RestBundle.message("sphinx.choose.working.directory.browse.folder.title"), null, project, myInputFile.addBrowseFolderListener(RestBundle.message("sphinx.choose.working.directory.browse.folder.title"), null, project,
@@ -134,7 +135,8 @@ public class SphinxBaseCommand {
GeneralCommandLine cmd = new GeneralCommandLine(); GeneralCommandLine cmd = new GeneralCommandLine();
if (sdkHomePath != null) { if (sdkHomePath != null) {
final String runnerName = "sphinx-quickstart" + (SystemInfo.isWindows ? ".exe" : ""); final String runnerName = "sphinx-quickstart" + (SystemInfo.isWindows ? ".exe" : "");
String executablePath = PythonSdkUtil.getExecutablePath(sdkHomePath, runnerName); var executablePathNio = PythonSdkUtil.getExecutablePath(Path.of(sdkHomePath), runnerName);
String executablePath = executablePathNio != null ? executablePathNio.toString() : null;
if (executablePath != null) { if (executablePath != null) {
cmd.setExePath(executablePath); cmd.setExePath(executablePath);
} }
@@ -143,7 +145,7 @@ public class SphinxBaseCommand {
} }
} }
cmd.setWorkDirectory(service.getWorkdir().isEmpty()? module.getProject().getBasePath(): service.getWorkdir()); cmd.setWorkDirectory(service.getWorkdir().isEmpty() ? module.getProject().getBasePath() : service.getWorkdir());
PythonCommandLineState.createStandardGroups(cmd); PythonCommandLineState.createStandardGroups(cmd);
ParamsGroup scriptParams = cmd.getParametersList().getParamsGroup(PythonCommandLineState.GROUP_SCRIPT); ParamsGroup scriptParams = cmd.getParametersList().getParamsGroup(PythonCommandLineState.GROUP_SCRIPT);
assert scriptParams != null; assert scriptParams != null;
@@ -172,5 +174,4 @@ public class SphinxBaseCommand {
return cmd; return cmd;
} }
} }

View File

@@ -9,11 +9,13 @@ import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFile;
import com.jetbrains.python.PySdkBundle; import com.jetbrains.python.PySdkBundle;
import com.jetbrains.python.sdk.PythonSdkUtil; import com.jetbrains.python.sdk.PythonSdkUtil;
import com.jetbrains.python.sdk.VirtualEnvReader;
import com.jetbrains.python.sdk.flavors.PyCondaRunKt; import com.jetbrains.python.sdk.flavors.PyCondaRunKt;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.io.File; import java.io.File;
import java.nio.file.Path;
import java.util.*; import java.util.*;
public class PyCondaPackageManagerImpl extends PyPackageManagerImpl { public class PyCondaPackageManagerImpl extends PyPackageManagerImpl {
@@ -148,9 +150,9 @@ public class PyCondaPackageManagerImpl extends PyPackageManagerImpl {
final ArrayList<String> parameters = Lists.newArrayList("create", "-p", destinationDir, "-y", "python=" + version); final ArrayList<String> parameters = Lists.newArrayList("create", "-p", destinationDir, "-y", "python=" + version);
PyCondaRunKt.runConda(condaExecutable, parameters); PyCondaRunKt.runConda(condaExecutable, parameters);
final String binary = PythonSdkUtil.getPythonExecutable(destinationDir); final Path binary = VirtualEnvReader.getInstance().findPythonInPythonRoot(Path.of(destinationDir));
final String binaryFallback = destinationDir + File.separator + "bin" + File.separator + "python"; final String binaryFallback = destinationDir + File.separator + "bin" + File.separator + "python";
return (binary != null) ? binary : binaryFallback; return (binary != null) ? binary.toString() : binaryFallback;
} }
@Override @Override

View File

@@ -26,6 +26,7 @@ import org.jetbrains.annotations.Nullable;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.*; import java.util.*;
@@ -193,10 +194,10 @@ public class PyPackageManagerImpl extends PyPackageManagerImplBase {
showSdkExecutionException(sdk, e, PySdkBundle.message("python.creating.venv.failed.title")); showSdkExecutionException(sdk, e, PySdkBundle.message("python.creating.venv.failed.title"));
} }
final String binary = PythonSdkUtil.getPythonExecutable(destinationDir); final Path binary = VirtualEnvReader.getInstance().findPythonInPythonRoot(Paths.get(destinationDir));
final String binaryFallback = destinationDir + mySeparator + "bin" + mySeparator + "python"; final String binaryFallback = destinationDir + mySeparator + "bin" + mySeparator + "python";
return (binary != null) ? binary : binaryFallback; return (binary != null) ? binary.toString() : binaryFallback;
} }
/** /**

View File

@@ -37,11 +37,13 @@ import com.jetbrains.python.run.target.HelpersAwareTargetEnvironmentRequest;
import com.jetbrains.python.sdk.PyLazySdk; import com.jetbrains.python.sdk.PyLazySdk;
import com.jetbrains.python.sdk.PySdkExtKt; import com.jetbrains.python.sdk.PySdkExtKt;
import com.jetbrains.python.sdk.PythonSdkUtil; import com.jetbrains.python.sdk.PythonSdkUtil;
import com.jetbrains.python.sdk.VirtualEnvReader;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.*; import java.util.*;
@@ -237,11 +239,11 @@ public class PyTargetEnvironmentPackageManager extends PyPackageManagerImplBase
// TODO [targets] Pass `parentDir = null` // TODO [targets] Pass `parentDir = null`
getPythonProcessResult(pythonExecution, false, true, targetEnvironmentRequest); getPythonProcessResult(pythonExecution, false, true, targetEnvironmentRequest);
final String binary = PythonSdkUtil.getPythonExecutable(destinationDir); final Path binary = VirtualEnvReader.getInstance().findPythonInPythonRoot(Path.of(destinationDir));
final char separator = targetEnvironmentRequest.getTargetPlatform().getPlatform().fileSeparator; final char separator = targetEnvironmentRequest.getTargetPlatform().getPlatform().fileSeparator;
final String binaryFallback = destinationDir + separator + "bin" + separator + "python"; final String binaryFallback = destinationDir + separator + "bin" + separator + "python";
return (binary != null) ? binary : binaryFallback; return (binary != null) ? binary.toString() : binaryFallback;
} }
/** /**

View File

@@ -5,7 +5,6 @@ import com.intellij.execution.target.TargetEnvironmentConfiguration
import com.intellij.execution.target.joinTargetPaths import com.intellij.execution.target.joinTargetPaths
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory
import com.intellij.openapi.module.Module import com.intellij.openapi.module.Module
import com.intellij.openapi.observable.properties.PropertyGraph
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.projectRoots.Sdk import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil
@@ -33,7 +32,7 @@ import com.jetbrains.python.sdk.configuration.createSdkForTarget
import com.jetbrains.python.sdk.configuration.createVirtualEnvSynchronously import com.jetbrains.python.sdk.configuration.createVirtualEnvSynchronously
import com.jetbrains.python.sdk.flavors.PyFlavorAndData import com.jetbrains.python.sdk.flavors.PyFlavorAndData
import com.jetbrains.python.sdk.flavors.PyFlavorData import com.jetbrains.python.sdk.flavors.PyFlavorData
import com.jetbrains.python.sdk.flavors.VirtualEnvReader.Companion.DEFAULT_VIRTUALENVS_DIR import com.jetbrains.python.sdk.VirtualEnvReader.Companion.DEFAULT_VIRTUALENVS_DIR
import com.jetbrains.python.target.PyTargetAwareAdditionalData import com.jetbrains.python.target.PyTargetAwareAdditionalData
import com.jetbrains.python.target.PythonLanguageRuntimeConfiguration import com.jetbrains.python.target.PythonLanguageRuntimeConfiguration
import java.awt.BorderLayout import java.awt.BorderLayout

View File

@@ -5,7 +5,7 @@ import com.intellij.openapi.application.EDT
import com.intellij.openapi.projectRoots.Sdk import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.util.io.toNioPathOrNull import com.intellij.openapi.util.io.toNioPathOrNull
import com.jetbrains.python.sdk.ModuleOrProject import com.jetbrains.python.sdk.ModuleOrProject
import com.jetbrains.python.sdk.flavors.VirtualEnvReader import com.jetbrains.python.sdk.VirtualEnvReader
import com.jetbrains.python.sdk.rootManager import com.jetbrains.python.sdk.rootManager
import com.jetbrains.python.sdk.service.PySdkService.Companion.pySdkService import com.jetbrains.python.sdk.service.PySdkService.Companion.pySdkService
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers

View File

@@ -14,6 +14,7 @@ import com.intellij.platform.ide.progress.runWithModalProgressBlocking
import com.jetbrains.python.PyBundle import com.jetbrains.python.PyBundle
import com.jetbrains.python.sdk.PythonSdkType import com.jetbrains.python.sdk.PythonSdkType
import com.jetbrains.python.sdk.PythonSdkUtil import com.jetbrains.python.sdk.PythonSdkUtil
import com.jetbrains.python.sdk.VirtualEnvReader
import com.jetbrains.python.sdk.add.target.conda.createCondaSdkFromExistingEnv import com.jetbrains.python.sdk.add.target.conda.createCondaSdkFromExistingEnv
import com.jetbrains.python.sdk.excludeInnerVirtualEnv import com.jetbrains.python.sdk.excludeInnerVirtualEnv
import com.jetbrains.python.sdk.flavors.conda.PyCondaCommand import com.jetbrains.python.sdk.flavors.conda.PyCondaCommand
@@ -41,7 +42,7 @@ internal fun PythonMutableTargetAddInterpreterModel.setupVirtualenv(venvPath: Pa
inheritSitePackages = state.inheritSitePackages.get()) inheritSitePackages = state.inheritSitePackages.get())
if (targetEnvironmentConfiguration != null) error("Remote targets aren't supported") if (targetEnvironmentConfiguration != null) error("Remote targets aren't supported")
val venvPython = PythonSdkUtil.getPythonExecutable(venvPathOnTarget) val venvPython = VirtualEnvReader.Instance.findPythonInPythonRoot(Path.of(venvPathOnTarget))?.toString()
val homeFile = try { val homeFile = try {
StandardFileSystems.local().refreshAndFindFileByPath(venvPython!!)!! StandardFileSystems.local().refreshAndFindFileByPath(venvPython!!)!!

View File

@@ -5,6 +5,7 @@ import com.google.common.collect.Sets;
import com.intellij.openapi.module.Module; import com.intellij.openapi.module.Module;
import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.UserDataHolder; import com.intellij.openapi.util.UserDataHolder;
import com.jetbrains.python.sdk.VirtualEnvReader;
import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;

View File

@@ -11,6 +11,7 @@ import com.jetbrains.python.icons.PythonIcons;
import com.jetbrains.python.sdk.BasePySdkExtKt; import com.jetbrains.python.sdk.BasePySdkExtKt;
import com.jetbrains.python.sdk.PySdkExtKt; import com.jetbrains.python.sdk.PySdkExtKt;
import com.jetbrains.python.sdk.PythonSdkUtil; import com.jetbrains.python.sdk.PythonSdkUtil;
import com.jetbrains.python.sdk.VirtualEnvReader;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;

View File

@@ -122,7 +122,7 @@ fun setupPipEnvSdkUnderProgress(project: Project?,
override fun compute(indicator: ProgressIndicator): String { override fun compute(indicator: ProgressIndicator): String {
indicator.isIndeterminate = true indicator.isIndeterminate = true
val pipEnv = setupPipEnv(FileUtil.toSystemDependentName(projectPath), python, installPackages) val pipEnv = setupPipEnv(FileUtil.toSystemDependentName(projectPath), python, installPackages)
return PythonSdkUtil.getPythonExecutable(pipEnv) ?: FileUtil.join(pipEnv, "bin", "python") return VirtualEnvReader.Instance.findPythonInPythonRoot(Path.of(pipEnv))?.toString() ?: FileUtil.join(pipEnv, "bin", "python")
} }
} }
return createSdkByGenerateTask(task, existingSdks, null, projectPath, suggestedSdkName(projectPath))?.apply { return createSdkByGenerateTask(task, existingSdks, null, projectPath, suggestedSdkName(projectPath))?.apply {

View File

@@ -210,4 +210,4 @@ inline fun <reified T> syncRunPoetry(
} }
} }
fun getPythonExecutable(homePath: String): String = PythonSdkUtil.getPythonExecutable(homePath) ?: FileUtil.join(homePath, "bin", "python") fun getPythonExecutable(homePath: String): String = VirtualEnvReader.Instance.findPythonInPythonRoot(Path.of(homePath))?.toString() ?: FileUtil.join(homePath, "bin", "python")

View File

@@ -20,7 +20,7 @@ import com.jetbrains.python.sdk.PythonSdkAdditionalData
import com.jetbrains.python.sdk.PythonSdkType import com.jetbrains.python.sdk.PythonSdkType
import com.jetbrains.python.sdk.PythonSdkUtil import com.jetbrains.python.sdk.PythonSdkUtil
import com.jetbrains.python.sdk.flavors.PythonSdkFlavor import com.jetbrains.python.sdk.flavors.PythonSdkFlavor
import com.jetbrains.python.sdk.flavors.VirtualEnvReader import com.jetbrains.python.sdk.VirtualEnvReader
import com.jetbrains.python.sdk.flavors.conda.CondaEnvSdkFlavor import com.jetbrains.python.sdk.flavors.conda.CondaEnvSdkFlavor
import com.jetbrains.python.sdk.pipenv.isPipEnv import com.jetbrains.python.sdk.pipenv.isPipEnv
import com.jetbrains.python.sdk.poetry.isPoetry import com.jetbrains.python.sdk.poetry.isPoetry

View File

@@ -17,10 +17,12 @@ import com.jetbrains.python.PyNames
import com.jetbrains.python.packaging.PyPackagingSettings import com.jetbrains.python.packaging.PyPackagingSettings
import com.jetbrains.python.sdk.PythonSdkUpdater import com.jetbrains.python.sdk.PythonSdkUpdater
import com.jetbrains.python.sdk.PythonSdkUtil import com.jetbrains.python.sdk.PythonSdkUtil
import com.jetbrains.python.sdk.VirtualEnvReader
import com.jetbrains.python.tools.sdkTools.PySdkTools import com.jetbrains.python.tools.sdkTools.PySdkTools
import com.jetbrains.python.tools.sdkTools.SdkCreationType import com.jetbrains.python.tools.sdkTools.SdkCreationType
import java.io.File import java.io.File
import java.nio.file.Paths import java.nio.file.Paths
import kotlin.io.path.Path
internal val TestPath = System.getenv("PYCHARM_PERF_ENVS") internal val TestPath = System.getenv("PYCHARM_PERF_ENVS")
@@ -30,7 +32,7 @@ fun createSdkForPerformance(module: Module,
sdkHome: String = File(TestPath, "envs/py36_64").absolutePath): Sdk { sdkHome: String = File(TestPath, "envs/py36_64").absolutePath): Sdk {
ApplicationManagerEx.setInStressTest(true) ApplicationManagerEx.setInStressTest(true)
// To disable slow debugging // To disable slow debugging
val executable = File(PythonSdkUtil.getPythonExecutable(sdkHome) ?: throw AssertionError("No python on $sdkHome")) val executable = VirtualEnvReader.Instance.findPythonInPythonRoot(Path(sdkHome))?.toFile() ?: throw AssertionError("No python on $sdkHome")
println("Creating Python SDK $sdkHome") println("Creating Python SDK $sdkHome")
return PySdkTools.createTempSdk(VfsUtil.findFileByIoFile(executable, true)!!, sdkCreationType, module, return PySdkTools.createTempSdk(VfsUtil.findFileByIoFile(executable, true)!!, sdkCreationType, module,
PyPackagingSettings.getInstance(module.project)) PyPackagingSettings.getInstance(module.project))

View File

@@ -14,6 +14,7 @@ import com.jetbrains.LoggingRule;
import com.jetbrains.python.psi.LanguageLevel; import com.jetbrains.python.psi.LanguageLevel;
import com.jetbrains.python.sdk.PySdkUtil; import com.jetbrains.python.sdk.PySdkUtil;
import com.jetbrains.python.sdk.PythonSdkUtil; import com.jetbrains.python.sdk.PythonSdkUtil;
import com.jetbrains.python.sdk.VirtualEnvReader;
import com.jetbrains.python.sdk.flavors.PythonSdkFlavor; import com.jetbrains.python.sdk.flavors.PythonSdkFlavor;
import com.jetbrains.python.tools.sdkTools.PySdkTools; import com.jetbrains.python.tools.sdkTools.PySdkTools;
import com.jetbrains.python.tools.sdkTools.SdkCreationType; import com.jetbrains.python.tools.sdkTools.SdkCreationType;
@@ -21,6 +22,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.io.File; import java.io.File;
import java.nio.file.Path;
import java.util.*; import java.util.*;
public class PyEnvTaskRunner { public class PyEnvTaskRunner {
@@ -74,10 +76,10 @@ public class PyEnvTaskRunner {
else { else {
testTask.useNormalTimeout(); testTask.useNormalTimeout();
} }
final String executable = PythonSdkUtil.getPythonExecutable(root); final Path executable = VirtualEnvReader.getInstance().findPythonInPythonRoot(Path.of(root));
assert executable != null : "No executable in " + root; assert executable != null : "No executable in " + root;
final Sdk sdk = getSdk(executable, testTask); final Sdk sdk = getSdk(executable.toString(), testTask);
if (skipOnFlavors != null) { if (skipOnFlavors != null) {
final PythonSdkFlavor flavor = PythonSdkFlavor.getFlavor(sdk); final PythonSdkFlavor flavor = PythonSdkFlavor.getFlavor(sdk);
if (ContainerUtil.exists(skipOnFlavors, o -> o.isInstance(flavor))) { if (ContainerUtil.exists(skipOnFlavors, o -> o.isInstance(flavor))) {
@@ -101,7 +103,7 @@ public class PyEnvTaskRunner {
} }
testTask.runTestOn(executable, sdk); testTask.runTestOn(executable.toString(), sdk);
passedRoots.add(root); passedRoots.add(root);
} }

View File

@@ -9,6 +9,7 @@ import com.jetbrains.env.PyEnvTestCase
import com.jetbrains.env.PyEnvTestSettings import com.jetbrains.env.PyEnvTestSettings
import com.jetbrains.python.packaging.findCondaExecutableRelativeToEnv import com.jetbrains.python.packaging.findCondaExecutableRelativeToEnv
import com.jetbrains.python.sdk.PythonSdkUtil import com.jetbrains.python.sdk.PythonSdkUtil
import com.jetbrains.python.sdk.VirtualEnvReader
import com.jetbrains.python.sdk.add.target.conda.TargetEnvironmentRequestCommandExecutor import com.jetbrains.python.sdk.add.target.conda.TargetEnvironmentRequestCommandExecutor
import com.jetbrains.python.sdk.flavors.conda.PyCondaEnv import com.jetbrains.python.sdk.flavors.conda.PyCondaEnv
import com.jetbrains.python.sdk.flavors.conda.PyCondaEnvIdentity import com.jetbrains.python.sdk.flavors.conda.PyCondaEnvIdentity
@@ -37,9 +38,9 @@ sealed class PythonType<T : Any>(private val tag: @NonNls String) {
.map { it.toPath() } .map { it.toPath() }
.firstOrNull { typeMatchesEnv(it, *additionalTags) } .firstOrNull { typeMatchesEnv(it, *additionalTags) }
?.let { envDir -> ?.let { envDir ->
Result.success(pythonPathToEnvironment(Path.of( Result.success(pythonPathToEnvironment(
PythonSdkUtil.getPythonExecutable(envDir.toString()) VirtualEnvReader.Instance.findPythonInPythonRoot(envDir)
?: error("Can't find python binary in $envDir")), envDir)) // This is a misconfiguration, hence an error ?: error("Can't find python binary in $envDir"), envDir)) // This is a misconfiguration, hence an error
} }
?: Result.failure(Throwable("No python found. See ${PyEnvTestSettings::class} class for more info")) ?: Result.failure(Throwable("No python found. See ${PyEnvTestSettings::class} class for more info"))

View File

@@ -1,9 +1,10 @@
package com.jetbrains.python.sdk.flavors // Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.jetbrains.python.sdk
import com.intellij.grazie.grammar.assertIsEmpty import com.intellij.grazie.grammar.assertIsEmpty
import com.intellij.openapi.util.io.FileUtilRt import com.intellij.openapi.util.io.FileUtilRt
import com.intellij.testFramework.utils.io.deleteRecursively import com.intellij.testFramework.utils.io.deleteRecursively
import org.junit.Assert.* import org.junit.Assert
import org.junit.Test import org.junit.Test
import java.nio.file.Files import java.nio.file.Files
import java.nio.file.Path import java.nio.file.Path
@@ -95,24 +96,24 @@ class VirtualEnvReaderTest {
// just version // just version
bootstrap.setupPyenv(listOf("3.1.1"), "python") bootstrap.setupPyenv(listOf("3.1.1"), "python")
var interpreters = bootstrap.virtualEnvReader.findPyenvInterpreters() var interpreters = bootstrap.virtualEnvReader.findPyenvInterpreters()
assertEquals(1, interpreters.size) Assert.assertEquals(1, interpreters.size)
assert(interpreters[0].absolutePathString().startsWith(bootstrap.pyenv.absolutePathString())) assert(interpreters[0].absolutePathString().startsWith(bootstrap.pyenv.absolutePathString()))
assert(interpreters[0].absolutePathString().endsWith("python")) assert(interpreters[0].absolutePathString().endsWith("python"))
// another version w/o match // another version w/o match
bootstrap.setupPyenv(listOf("3.2.1"), "xxx") bootstrap.setupPyenv(listOf("3.2.1"), "xxx")
interpreters = bootstrap.virtualEnvReader.findPyenvInterpreters() interpreters = bootstrap.virtualEnvReader.findPyenvInterpreters()
assertEquals(1, interpreters.size) Assert.assertEquals(1, interpreters.size)
// both in names // both in names
bootstrap.setupPyenv(listOf("3.2.2"), "pypy") bootstrap.setupPyenv(listOf("3.2.2"), "pypy")
interpreters = bootstrap.virtualEnvReader.findPyenvInterpreters() interpreters = bootstrap.virtualEnvReader.findPyenvInterpreters()
assertEquals(2, interpreters.size) Assert.assertEquals(2, interpreters.size)
assert(interpreters[0] != interpreters[1]) assert(interpreters[0] != interpreters[1])
bootstrap.removeVersion(bootstrap.pyenv, "3.2.2") bootstrap.removeVersion(bootstrap.pyenv, "3.2.2")
interpreters = bootstrap.virtualEnvReader.findPyenvInterpreters() interpreters = bootstrap.virtualEnvReader.findPyenvInterpreters()
assertEquals(1, interpreters.size) Assert.assertEquals(1, interpreters.size)
assert(interpreters[0].absolutePathString().endsWith("python")) assert(interpreters[0].absolutePathString().endsWith("python"))
} }
@@ -120,24 +121,24 @@ class VirtualEnvReaderTest {
fun testIsPyenvSdk() { fun testIsPyenvSdk() {
val bootstrap = Bootstrap() val bootstrap = Bootstrap()
assertFalse(bootstrap.virtualEnvReader.isPyenvSdk(null as String?)) Assert.assertFalse(bootstrap.virtualEnvReader.isPyenvSdk(null as String?))
assertFalse(bootstrap.virtualEnvReader.isPyenvSdk("")) Assert.assertFalse(bootstrap.virtualEnvReader.isPyenvSdk(""))
assertFalse(bootstrap.virtualEnvReader.isPyenvSdk("aa\u0000bb")) Assert.assertFalse(bootstrap.virtualEnvReader.isPyenvSdk("aa\u0000bb"))
assertFalse(bootstrap.virtualEnvReader.isPyenvSdk("a/b/c/d")) Assert.assertFalse(bootstrap.virtualEnvReader.isPyenvSdk("a/b/c/d"))
assertFalse(bootstrap.virtualEnvReader.isPyenvSdk(bootstrap.cwd)) Assert.assertFalse(bootstrap.virtualEnvReader.isPyenvSdk(bootstrap.cwd))
assertFalse(bootstrap.virtualEnvReader.isPyenvSdk(bootstrap.cwd.resolve("smthg"))) Assert.assertFalse(bootstrap.virtualEnvReader.isPyenvSdk(bootstrap.cwd.resolve("smthg")))
bootstrap.setupPyenv(listOf("3.2.1"), "xxxx") bootstrap.setupPyenv(listOf("3.2.1"), "xxxx")
assertFalse(bootstrap.virtualEnvReader.isPyenvSdk(null as String?)) Assert.assertFalse(bootstrap.virtualEnvReader.isPyenvSdk(null as String?))
assertFalse(bootstrap.virtualEnvReader.isPyenvSdk("")) Assert.assertFalse(bootstrap.virtualEnvReader.isPyenvSdk(""))
assertFalse(bootstrap.virtualEnvReader.isPyenvSdk("aa\u0000bb")) Assert.assertFalse(bootstrap.virtualEnvReader.isPyenvSdk("aa\u0000bb"))
assertFalse(bootstrap.virtualEnvReader.isPyenvSdk("a/b/c/d")) Assert.assertFalse(bootstrap.virtualEnvReader.isPyenvSdk("a/b/c/d"))
assertFalse(bootstrap.virtualEnvReader.isPyenvSdk(bootstrap.cwd)) Assert.assertFalse(bootstrap.virtualEnvReader.isPyenvSdk(bootstrap.cwd))
assertFalse(bootstrap.virtualEnvReader.isPyenvSdk(bootstrap.cwd.resolve("smthg"))) Assert.assertFalse(bootstrap.virtualEnvReader.isPyenvSdk(bootstrap.cwd.resolve("smthg")))
// particularly any path inside pyenv root will work // particularly any path inside pyenv root will work
assertTrue(bootstrap.virtualEnvReader.isPyenvSdk(bootstrap.pyenv.resolve("xxx"))) Assert.assertTrue(bootstrap.virtualEnvReader.isPyenvSdk(bootstrap.pyenv.resolve("xxx")))
// should resolve symlinks // should resolve symlinks
val link = bootstrap.cwd.resolve("smthg") val link = bootstrap.cwd.resolve("smthg")
@@ -145,9 +146,9 @@ class VirtualEnvReaderTest {
// hanging links, should not resolve it // hanging links, should not resolve it
Files.createSymbolicLink(link, target) Files.createSymbolicLink(link, target)
assertFalse(bootstrap.virtualEnvReader.isPyenvSdk(link)) Assert.assertFalse(bootstrap.virtualEnvReader.isPyenvSdk(link))
Files.createFile(target) Files.createFile(target)
assertTrue(bootstrap.virtualEnvReader.isPyenvSdk(link)) Assert.assertTrue(bootstrap.virtualEnvReader.isPyenvSdk(link))
} }
} }

View File

@@ -5,11 +5,13 @@ import com.intellij.openapi.vfs.VfsUtil
import com.intellij.testFramework.TestApplicationManager import com.intellij.testFramework.TestApplicationManager
import com.intellij.util.io.Compressor import com.intellij.util.io.Compressor
import com.jetbrains.python.sdk.PythonSdkUtil import com.jetbrains.python.sdk.PythonSdkUtil
import com.jetbrains.python.sdk.VirtualEnvReader
import com.jetbrains.python.sdk.skeletons.DefaultPregeneratedSkeletonsProvider import com.jetbrains.python.sdk.skeletons.DefaultPregeneratedSkeletonsProvider
import com.jetbrains.python.sdk.skeletons.PySkeletonRefresher import com.jetbrains.python.sdk.skeletons.PySkeletonRefresher
import com.jetbrains.python.tools.sdkTools.PySdkTools import com.jetbrains.python.tools.sdkTools.PySdkTools
import com.jetbrains.python.tools.sdkTools.SdkCreationType import com.jetbrains.python.tools.sdkTools.SdkCreationType
import java.io.File import java.io.File
import kotlin.io.path.Path
import kotlin.math.abs import kotlin.math.abs
import kotlin.system.exitProcess import kotlin.system.exitProcess
@@ -29,7 +31,7 @@ fun main() {
for (python in File(root).listFiles()!!) { for (python in File(root).listFiles()!!) {
println("Running on $python") println("Running on $python")
val executable = PythonSdkUtil.getPythonExecutable(python.absolutePath)!! val executable = VirtualEnvReader.Instance.findPythonInPythonRoot(Path(python.absolutePath))!!.toString()
val sdk = PySdkTools.createTempSdk(VfsUtil.findFileByIoFile(File(executable), true)!!, SdkCreationType.SDK_PACKAGES_ONLY, null, null) val sdk = PySdkTools.createTempSdk(VfsUtil.findFileByIoFile(File(executable), true)!!, SdkCreationType.SDK_PACKAGES_ONLY, null, null)
val skeletonsDir = File(workingDir, "skeletons-${sdk.versionString!!.replace(" ", "_")}_" + abs(sdk.homePath!!.hashCode())) val skeletonsDir = File(workingDir, "skeletons-${sdk.versionString!!.replace(" ", "_")}_" + abs(sdk.homePath!!.hashCode()))

View File

@@ -3,9 +3,11 @@ package com.jetbrains.python.tools
import com.jetbrains.python.PythonHelper import com.jetbrains.python.PythonHelper
import com.jetbrains.python.sdk.PythonSdkUtil import com.jetbrains.python.sdk.PythonSdkUtil
import com.jetbrains.python.sdk.VirtualEnvReader
import java.io.BufferedReader import java.io.BufferedReader
import java.io.File import java.io.File
import java.io.InputStreamReader import java.io.InputStreamReader
import kotlin.io.path.Path
fun main() { fun main() {
@@ -21,7 +23,7 @@ fun main() {
} }
val sdkHome = python.absolutePath val sdkHome = python.absolutePath
val executable = PythonSdkUtil.getPythonExecutable(sdkHome)?.let { File(it) } val executable = VirtualEnvReader.Instance.findPythonInPythonRoot(Path(sdkHome))?.toFile()
if (executable == null) { if (executable == null) {
println("No python on $sdkHome") println("No python on $sdkHome")