Python: move VirtualEnvReader out of psi-impl module

GitOrigin-RevId: c4d7bd0bf0c5592b13a2ccffcd217c1bae819637
This commit is contained in:
Ilya.Kazakevich
2025-01-29 20:52:29 +01:00
committed by intellij-monorepo-bot
parent 504e1208ef
commit eab4466488
37 changed files with 77 additions and 62 deletions

View File

@@ -27,6 +27,7 @@ import com.intellij.util.concurrency.annotations.RequiresBackgroundThread
import com.jetbrains.python.sdk.configuration.PyProjectSdkConfigurationExtension
import com.jetbrains.python.sdk.pipenv.*
import com.jetbrains.python.sdk.pipenv.ui.PyAddNewPipEnvFromFilePanel
import com.jetbrains.python.venvReader.VirtualEnvReader
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.awt.BorderLayout

View File

@@ -26,6 +26,7 @@ import com.jetbrains.python.sdk.configuration.PyProjectSdkConfigurationExtension
import com.jetbrains.python.sdk.poetry.*
import com.jetbrains.python.sdk.poetry.ui.PyAddNewPoetryFromFilePanel
import com.jetbrains.python.util.runWithModalBlockingOrInBackground
import com.jetbrains.python.venvReader.VirtualEnvReader
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.awt.BorderLayout

View File

@@ -35,7 +35,7 @@ import com.intellij.python.community.services.systemPython.SystemPythonService
import com.intellij.util.SystemProperties
import com.intellij.util.concurrency.annotations.RequiresEdt
import com.jetbrains.python.*
import com.jetbrains.python.sdk.VirtualEnvReader
import com.jetbrains.python.venvReader.VirtualEnvReader
import com.jetbrains.python.sdk.createSdk
import com.jetbrains.python.createVirtualenv
import com.jetbrains.python.sdk.flavors.PythonSdkFlavor

View File

@@ -0,0 +1,31 @@
// Copyright 2000-2025 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 org.jetbrains.annotations.ApiStatus
import org.jetbrains.annotations.Contract
import java.util.regex.Pattern
@ApiStatus.Internal
object CustomSdkHomePattern {
/**
* Note that *\w+.** pattern is not sufficient because we need also the
* hyphen sign (*-*) for *docker-compose:* scheme.
* For WSL we use `\\wsl.local\` or `\\wsl$\`.
* As with a new workspace model paths changed on save, hence we need to support `//wsl` as well
*/
private val CUSTOM_PYTHON_SDK_HOME_PATH_PATTERN: Pattern = Pattern.compile("^([-a-zA-Z_0-9]{2,}:|\\\\\\\\|//wsl).+")
/**
* Returns whether provided Python interpreter path corresponds to custom
* Python SDK.
*
* @param homePath SDK home path
* @return whether provided Python interpreter path corresponds to custom Python SDK
*/
@JvmStatic
@Contract(pure = true)
@ApiStatus.Internal
fun isCustomPythonSdkHomePath(homePath: String): Boolean {
return CUSTOM_PYTHON_SDK_HOME_PATH_PATTERN.matcher(homePath).matches()
}
}

View File

@@ -1,5 +1,5 @@
// 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
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.jetbrains.python.venvReader
import com.intellij.openapi.util.SystemInfoRt
import com.intellij.openapi.util.io.toCanonicalPath
@@ -132,7 +132,7 @@ class VirtualEnvReader(
companion object {
@JvmStatic
val Instance = VirtualEnvReader()
val Instance: VirtualEnvReader = VirtualEnvReader()
/**
@@ -141,7 +141,7 @@ class VirtualEnvReader(
*
* @see com.jetbrains.python.sdk.flavors.VirtualEnvSdkFlavor.getDefaultLocation
*/
const val DEFAULT_VIRTUALENVS_DIR = ".virtualenvs"
const val DEFAULT_VIRTUALENV_DIRNAME = ".venv"
const val DEFAULT_VIRTUALENVS_DIR: String = ".virtualenvs"
const val DEFAULT_VIRTUALENV_DIRNAME: String = ".venv"
}
}

View File

@@ -1,17 +1,17 @@
package com.jetbrains.python.sdk
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.jetbrains.python.venvReader
import com.jetbrains.python.sdk.CustomSdkHomePattern
import org.jetbrains.annotations.ApiStatus
import java.nio.file.InvalidPathException
import java.nio.file.Path
// TODO: Move to PythonSdkUtil when rewritten in Kotlin
/**
* Converts [str] to [Path] of str is real nio path. Returns null otherwise
*/
@ApiStatus.Internal
fun tryResolvePath(str: String?): Path? {
if (str == null || PythonSdkUtil.isCustomPythonSdkHomePath(str)) {
if (str == null || CustomSdkHomePattern.isCustomPythonSdkHomePath(str)) {
return null
}

View File

@@ -32,6 +32,7 @@ import com.jetbrains.python.codeInsight.userSkeletons.PyUserSkeletonsUtil;
import com.jetbrains.python.module.PyModuleService;
import com.jetbrains.python.psi.search.PySearchUtilBase;
import com.jetbrains.python.sdk.skeleton.PySkeletonHeader;
import com.jetbrains.python.venvReader.VirtualEnvReader;
import org.jetbrains.annotations.*;
import java.io.File;
@@ -40,7 +41,6 @@ import java.nio.file.Path;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
/**
@@ -51,13 +51,6 @@ import java.util.stream.Collectors;
* @see PySdkUtil for run-time Python SDK utils
*/
public final class PythonSdkUtil {
/**
* Note that <i>\w+.*</i> pattern is not sufficient because we need also the
* hyphen sign (<i>-</i>) for <i>docker-compose:</i> scheme.
* For WSL we use <code>\\wsl.local\</code> or <code>\\wsl$\</code>.
* As with a new workspace model paths changed on save, hence we need to support <code>//wsl</code> as well
*/
private static final Pattern CUSTOM_PYTHON_SDK_HOME_PATH_PATTERN = Pattern.compile("^([-a-zA-Z_0-9]{2,}:|\\\\\\\\|//wsl).+");
public static final String REMOTE_SOURCES_DIR_NAME = "remote_sources";
/**
@@ -81,19 +74,6 @@ public final class PythonSdkUtil {
return ContainerUtil.filter(ProjectJdkTable.getInstance().getAllJdks(), PythonSdkUtil::isPythonSdk);
}
/**
* Returns whether provided Python interpreter path corresponds to custom
* Python SDK.
*
* @param homePath SDK home path
* @return whether provided Python interpreter path corresponds to custom Python SDK
*/
@Contract(pure = true)
@ApiStatus.Internal
public static boolean isCustomPythonSdkHomePath(@NotNull String homePath) {
return CUSTOM_PYTHON_SDK_HOME_PATH_PATTERN.matcher(homePath).matches();
}
private static @Nullable PySkeletonHeader readSkeletonHeader(@NotNull VirtualFile file, @NotNull Sdk pythonSdk) {
final VirtualFile skeletonsDir = findSkeletonsDir(pythonSdk);
if (skeletonsDir != null && VfsUtilCore.isAncestor(skeletonsDir, file, false)) {
@@ -530,7 +510,7 @@ public final class PythonSdkUtil {
}
public static @Nullable VirtualFile findCondaMeta(@Nullable String sdkPath) {
if (sdkPath == null || isCustomPythonSdkHomePath(sdkPath)) {
if (sdkPath == null || CustomSdkHomePattern.isCustomPythonSdkHomePath(sdkPath)) {
return null;
}
final VirtualFile homeDirectory = StandardFileSystems.local().findFileByPath(sdkPath);

View File

@@ -11,6 +11,7 @@ import com.intellij.openapi.util.io.FileUtil
import com.intellij.util.PathUtil
import com.intellij.util.SystemProperties
import com.intellij.util.xmlb.XmlSerializerUtil
import com.jetbrains.python.venvReader.VirtualEnvReader
import org.jetbrains.annotations.SystemIndependent
import org.jetbrains.jps.model.serialization.PathMacroUtil
import kotlin.io.path.absolutePathString

View File

@@ -22,6 +22,7 @@ import com.jetbrains.python.psi.LanguageLevel;
import com.jetbrains.python.psi.icons.PythonPsiApiIcons;
import com.jetbrains.python.run.CommandLinePatcher;
import com.jetbrains.python.sdk.*;
import com.jetbrains.python.sdk.CustomSdkHomePattern;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -33,7 +34,7 @@ import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
import static com.jetbrains.python.sdk.PythonSdkUtilKtKt.tryResolvePath;
import static com.jetbrains.python.venvReader.ResolveUtilKt.tryResolvePath;
import static com.jetbrains.python.sdk.flavors.PySdkFlavorUtilKt.getFileExecutionError;
import static com.jetbrains.python.sdk.flavors.PySdkFlavorUtilKt.getFileExecutionErrorOnEdt;
@@ -267,7 +268,7 @@ public abstract class PythonSdkFlavor<D extends PyFlavorData> {
@Deprecated(forRemoval = true)
@RequiresBackgroundThread(generateAssertion = false)
public static @Nullable PythonSdkFlavor<?> getFlavor(@Nullable String sdkPath) {
if (sdkPath == null || PythonSdkUtil.isCustomPythonSdkHomePath(sdkPath)) return null;
if (sdkPath == null || CustomSdkHomePattern.isCustomPythonSdkHomePath(sdkPath)) return null;
return tryDetectFlavorByLocalPath(sdkPath);
}

View File

@@ -15,7 +15,7 @@ import com.intellij.testFramework.common.timeoutRunBlocking
import com.intellij.testFramework.junit5.fixture.moduleFixture
import com.intellij.testFramework.junit5.fixture.projectFixture
import com.intellij.testFramework.junit5.fixture.tempPathFixture
import com.jetbrains.python.sdk.VirtualEnvReader
import com.jetbrains.python.venvReader.VirtualEnvReader
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import org.hamcrest.CoreMatchers.*

View File

@@ -14,8 +14,7 @@ import com.intellij.python.junit5Tests.framework.env.PythonBinaryPath
import com.intellij.python.junit5Tests.framework.winLockedFile.deleteCheckLocking
import com.intellij.python.junit5Tests.randomBinary
import com.intellij.testFramework.common.timeoutRunBlocking
import com.jetbrains.python.psi.LanguageLevel
import com.jetbrains.python.sdk.VirtualEnvReader
import com.jetbrains.python.venvReader.VirtualEnvReader
import com.jetbrains.python.createVirtualenv
import com.jetbrains.python.sdk.flavors.PythonSdkFlavor
import kotlinx.coroutines.async

View File

@@ -9,7 +9,7 @@ import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.jetbrains.python.PySdkBundle;
import com.jetbrains.python.sdk.PythonSdkUtil;
import com.jetbrains.python.sdk.VirtualEnvReader;
import com.jetbrains.python.venvReader.VirtualEnvReader;
import com.jetbrains.python.sdk.flavors.PyCondaRunKt;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

View File

@@ -126,7 +126,7 @@ fun getConfirmedPackages(packageNames: List<String>, project: Project): List<Str
return packageNames
}
val dialog = PyChooseRequirementsDialog(project, packageNames) { it }
val dialog = PyChooseRequirementsDialog(project, nonWellKnownPackages) { it }
val isOk = dialog.showAndGet()
if (!isOk) {

View File

@@ -20,6 +20,7 @@ import com.jetbrains.python.PySdkBundle;
import com.jetbrains.python.psi.LanguageLevel;
import com.jetbrains.python.sdk.*;
import com.jetbrains.python.sdk.flavors.PythonSdkFlavor;
import com.jetbrains.python.venvReader.VirtualEnvReader;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

View File

@@ -35,7 +35,7 @@ import com.jetbrains.python.run.PythonScripts;
import com.jetbrains.python.run.target.HelpersAwareTargetEnvironmentRequest;
import com.jetbrains.python.sdk.PyLazySdk;
import com.jetbrains.python.sdk.PySdkExtKt;
import com.jetbrains.python.sdk.VirtualEnvReader;
import com.jetbrains.python.venvReader.VirtualEnvReader;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

View File

@@ -316,7 +316,7 @@ public final class PythonSdkType extends SdkType {
*/
@Contract(pure = true)
static boolean isCustomPythonSdkHomePath(@NotNull String homePath) {
return PythonSdkUtil.isCustomPythonSdkHomePath(homePath);
return CustomSdkHomePattern.isCustomPythonSdkHomePath(homePath);
}
public static boolean isSkeletonsPath(String path) {

View File

@@ -31,7 +31,7 @@ import com.jetbrains.python.run.PythonInterpreterTargetEnvironmentFactory.Compan
import com.jetbrains.python.sdk.PyDetectedSdk
import com.jetbrains.python.sdk.PySdkSettings
import com.jetbrains.python.sdk.PythonSdkType
import com.jetbrains.python.sdk.VirtualEnvReader
import com.jetbrains.python.venvReader.VirtualEnvReader
import com.jetbrains.python.sdk.add.ExistingPySdkComboBoxItem
import com.jetbrains.python.sdk.add.PySdkPathChoosingComboBox
import com.jetbrains.python.sdk.add.addBaseInterpretersAsync

View File

@@ -22,7 +22,7 @@ import com.jetbrains.python.newProjectWizard.collector.PythonNewProjectWizardCol
import com.jetbrains.python.newProjectWizard.projectPath.ProjectPathFlows.Companion.validatePath
import com.jetbrains.python.sdk.ModuleOrProject
import com.jetbrains.python.sdk.PySdkSettings
import com.jetbrains.python.sdk.VirtualEnvReader
import com.jetbrains.python.venvReader.VirtualEnvReader
import com.jetbrains.python.sdk.add.v2.PythonInterpreterSelectionMethod.SELECT_EXISTING
import com.jetbrains.python.sdk.add.v2.PythonSupportedEnvironmentManagers.PYTHON
import com.jetbrains.python.statistics.InterpreterCreationMode

View File

@@ -5,7 +5,7 @@ import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.util.io.toNioPathOrNull
import com.jetbrains.python.Result
import com.jetbrains.python.sdk.ModuleOrProject
import com.jetbrains.python.sdk.VirtualEnvReader
import com.jetbrains.python.venvReader.VirtualEnvReader
import com.jetbrains.python.sdk.rootManager
import com.jetbrains.python.sdk.service.PySdkService.Companion.pySdkService
import com.jetbrains.python.errorProcessing.ErrorSink

View File

@@ -28,7 +28,7 @@ import com.jetbrains.python.getOrThrow
import com.jetbrains.python.newProject.collector.InterpreterStatisticsInfo
import com.jetbrains.python.newProjectWizard.projectPath.ProjectPathFlows
import com.jetbrains.python.sdk.ModuleOrProject
import com.jetbrains.python.sdk.VirtualEnvReader
import com.jetbrains.python.venvReader.VirtualEnvReader
import com.jetbrains.python.sdk.add.v2.PythonInterpreterSelectionMode.*
import com.jetbrains.python.statistics.InterpreterCreationMode
import com.jetbrains.python.statistics.InterpreterTarget

View File

@@ -25,6 +25,7 @@ import com.jetbrains.python.sdk.poetry.getPoetryExecutable
import com.jetbrains.python.sdk.uv.impl.getUvExecutable
import com.jetbrains.python.errorProcessing.ErrorSink
import com.jetbrains.python.errorProcessing.emit
import com.jetbrains.python.venvReader.tryResolvePath
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.*

View File

@@ -15,7 +15,7 @@ import com.jetbrains.python.PyBundle.message
import com.jetbrains.python.createVirtualenv
import com.jetbrains.python.packaging.PyExecutionException
import com.jetbrains.python.sdk.PythonSdkType
import com.jetbrains.python.sdk.VirtualEnvReader
import com.jetbrains.python.venvReader.VirtualEnvReader
import com.jetbrains.python.sdk.conda.createCondaSdkFromExistingEnv
import com.jetbrains.python.sdk.createSdk
import com.jetbrains.python.sdk.excludeInnerVirtualEnv

View File

@@ -6,7 +6,7 @@ import com.intellij.openapi.module.Module;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.UserDataHolder;
import com.intellij.util.containers.ContainerUtil;
import com.jetbrains.python.sdk.VirtualEnvReader;
import com.jetbrains.python.venvReader.VirtualEnvReader;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

View File

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

View File

@@ -26,7 +26,7 @@ import java.io.File;
import java.nio.file.Path;
import java.util.*;
import static com.jetbrains.python.sdk.PythonSdkUtilKtKt.tryResolvePath;
import static com.jetbrains.python.venvReader.ResolveUtilKt.tryResolvePath;
import static com.jetbrains.python.sdk.WinAppxToolsKt.getAppxFiles;
import static com.jetbrains.python.sdk.WinAppxToolsKt.getAppxProduct;

View File

@@ -10,7 +10,7 @@ import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.util.SystemInfo
import com.intellij.platform.ide.progress.withBackgroundProgress
import com.jetbrains.python.PyBundle
import com.jetbrains.python.sdk.VirtualEnvReader
import com.jetbrains.python.venvReader.VirtualEnvReader
import com.jetbrains.python.sdk.basePath
import com.jetbrains.python.sdk.createSdk
import com.jetbrains.python.sdk.runExecutable

View File

@@ -27,6 +27,7 @@ import com.jetbrains.python.pathValidation.PlatformAndRoot
import com.jetbrains.python.pathValidation.ValidationRequest
import com.jetbrains.python.pathValidation.validateExecutableFile
import com.jetbrains.python.sdk.*
import com.jetbrains.python.venvReader.VirtualEnvReader
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

View File

@@ -8,7 +8,7 @@ import com.intellij.util.io.delete
import com.jetbrains.python.packaging.common.PythonOutdatedPackage
import com.jetbrains.python.packaging.common.PythonPackage
import com.jetbrains.python.packaging.common.PythonPackageSpecification
import com.jetbrains.python.sdk.VirtualEnvReader
import com.jetbrains.python.venvReader.VirtualEnvReader
import com.jetbrains.python.sdk.uv.UvCli
import com.jetbrains.python.sdk.uv.UvLowLevel
import java.nio.file.Path

View File

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

View File

@@ -10,7 +10,7 @@ import com.intellij.util.concurrency.annotations.RequiresBackgroundThread
import com.jetbrains.python.PythonBinary
import com.jetbrains.python.failure
import com.jetbrains.python.packaging.findCondaExecutableRelativeToEnv
import com.jetbrains.python.sdk.VirtualEnvReader
import com.jetbrains.python.venvReader.VirtualEnvReader
import com.jetbrains.python.sdk.conda.TargetEnvironmentRequestCommandExecutor
import com.jetbrains.python.sdk.flavors.PythonSdkFlavor
import com.jetbrains.python.sdk.flavors.conda.PyCondaEnv

View File

@@ -16,8 +16,7 @@ import com.intellij.util.ui.UIUtil
import com.jetbrains.python.PyNames
import com.jetbrains.python.packaging.PyPackagingSettings
import com.jetbrains.python.sdk.PythonSdkUpdater
import com.jetbrains.python.sdk.PythonSdkUtil
import com.jetbrains.python.sdk.VirtualEnvReader
import com.jetbrains.python.venvReader.VirtualEnvReader
import com.jetbrains.python.tools.sdkTools.PySdkTools
import com.jetbrains.python.tools.sdkTools.SdkCreationType
import java.io.File

View File

@@ -2,7 +2,7 @@
package com.jetbrains.python.tools
import com.intellij.openapi.diagnostic.fileLogger
import com.jetbrains.python.sdk.Directory
import com.jetbrains.python.venvReader.Directory
import java.io.IOException
import java.nio.file.Path
import kotlin.io.path.isDirectory

View File

@@ -13,7 +13,7 @@ import com.intellij.util.containers.ContainerUtil;
import com.jetbrains.LoggingRule;
import com.jetbrains.python.psi.LanguageLevel;
import com.jetbrains.python.sdk.PySdkUtil;
import com.jetbrains.python.sdk.VirtualEnvReader;
import com.jetbrains.python.venvReader.VirtualEnvReader;
import com.jetbrains.python.sdk.flavors.PythonSdkFlavor;
import com.jetbrains.python.tools.sdkTools.PySdkTools;
import com.jetbrains.python.tools.sdkTools.SdkCreationType;

View File

@@ -1,5 +1,5 @@
import com.jetbrains.python.sdk.PySdkSettings
import com.jetbrains.python.sdk.VirtualEnvReader
import com.jetbrains.python.venvReader.VirtualEnvReader
import org.junit.Assert
import org.junit.Test
import kotlin.io.path.absolutePathString

View File

@@ -4,6 +4,7 @@ package com.jetbrains.python.sdk
import com.intellij.grazie.grammar.assertIsEmpty
import com.intellij.openapi.util.io.FileUtilRt
import com.intellij.testFramework.utils.io.deleteRecursively
import com.jetbrains.python.venvReader.VirtualEnvReader
import org.junit.Assert
import org.junit.Test
import java.nio.file.Files

View File

@@ -4,8 +4,7 @@ package com.jetbrains.python.tools
import com.intellij.openapi.vfs.VfsUtil
import com.intellij.testFramework.TestApplicationManager
import com.intellij.util.io.Compressor
import com.jetbrains.python.sdk.PythonSdkUtil
import com.jetbrains.python.sdk.VirtualEnvReader
import com.jetbrains.python.venvReader.VirtualEnvReader
import com.jetbrains.python.sdk.skeletons.DefaultPregeneratedSkeletonsProvider
import com.jetbrains.python.sdk.skeletons.PySkeletonRefresher
import com.jetbrains.python.tools.sdkTools.PySdkTools

View File

@@ -2,8 +2,7 @@
package com.jetbrains.python.tools
import com.jetbrains.python.PythonHelper
import com.jetbrains.python.sdk.PythonSdkUtil
import com.jetbrains.python.sdk.VirtualEnvReader
import com.jetbrains.python.venvReader.VirtualEnvReader
import java.io.BufferedReader
import java.io.File
import java.io.InputStreamReader