diff --git a/python/ide/impl/src/com/intellij/pycharm/community/ide/impl/configuration/PyHatchSdkConfiguration.kt b/python/ide/impl/src/com/intellij/pycharm/community/ide/impl/configuration/PyHatchSdkConfiguration.kt index 09b85ee6d293..0933be5e8862 100644 --- a/python/ide/impl/src/com/intellij/pycharm/community/ide/impl/configuration/PyHatchSdkConfiguration.kt +++ b/python/ide/impl/src/com/intellij/pycharm/community/ide/impl/configuration/PyHatchSdkConfiguration.kt @@ -43,7 +43,7 @@ internal class PyHatchSdkConfiguration : PyProjectSdkConfigurationExtension { val createdEnvironment = hatchService.createVirtualEnvironment().getOr { return@runWithModalBlockingOrInBackground it } val hatchVenv = HatchVirtualEnvironment(HatchEnvironment.DEFAULT, createdEnvironment) - val sdk = hatchVenv.createSdk(hatchService.getWorkingDirectoryPath(), module) + val sdk = hatchVenv.createSdk(hatchService.getWorkingDirectoryPath()) sdk } override suspend fun createAndAddSdkForConfigurator(module: Module): PyResult = createSdk(module) diff --git a/python/ide/impl/src/com/intellij/pycharm/community/ide/impl/configuration/PyPoetrySdkConfiguration.kt b/python/ide/impl/src/com/intellij/pycharm/community/ide/impl/configuration/PyPoetrySdkConfiguration.kt index bafeaafd9b3d..dc2fb8993da2 100644 --- a/python/ide/impl/src/com/intellij/pycharm/community/ide/impl/configuration/PyPoetrySdkConfiguration.kt +++ b/python/ide/impl/src/com/intellij/pycharm/community/ide/impl/configuration/PyPoetrySdkConfiguration.kt @@ -16,13 +16,16 @@ import com.jetbrains.python.PyBundle import com.jetbrains.python.errorProcessing.PyResult import com.jetbrains.python.poetry.findPoetryLock import com.jetbrains.python.poetry.getPyProjectTomlForPoetry +import com.jetbrains.python.resolvePythonBinary import com.jetbrains.python.sdk.PythonSdkType import com.jetbrains.python.sdk.PythonSdkUtil import com.jetbrains.python.sdk.basePath import com.jetbrains.python.sdk.configuration.PyProjectSdkConfigurationExtension -import com.jetbrains.python.sdk.poetry.* +import com.jetbrains.python.sdk.poetry.PyPoetrySdkAdditionalData +import com.jetbrains.python.sdk.poetry.getPoetryExecutable +import com.jetbrains.python.sdk.poetry.setupPoetry +import com.jetbrains.python.sdk.poetry.suggestedSdkName import com.jetbrains.python.sdk.setAssociationToModule -import com.jetbrains.python.venvReader.VirtualEnvReader import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import java.nio.file.Path @@ -64,11 +67,8 @@ internal class PyPoetrySdkConfiguration : PyProjectSdkConfigurationExtension { } val tomlFile = PyProjectToml.findFile(module) val poetry = setupPoetry(basePath, null, true, tomlFile == null).getOr { return@withBackgroundProgress it } - - val path = withContext(Dispatchers.IO) { VirtualEnvReader.Instance.findPythonInPythonRoot(Path.of(poetry)) } - if (path == null) { - return@withBackgroundProgress PyResult.localizedError(PyBundle.message("cannot.find.executable", "python", poetry)) - } + val path = poetry.resolvePythonBinary() + ?: return@withBackgroundProgress PyResult.localizedError(PyBundle.message("cannot.find.executable", "python", poetry)) val file = LocalFileSystem.getInstance().refreshAndFindFileByPath(path.pathString) if (file == null) { diff --git a/python/pluginResources/messages/PyBundle.properties b/python/pluginResources/messages/PyBundle.properties index 77754b50837b..0a0162d3a84e 100644 --- a/python/pluginResources/messages/PyBundle.properties +++ b/python/pluginResources/messages/PyBundle.properties @@ -437,7 +437,7 @@ python.sdk.rendering.project.default.0=Project Default ({0}) python.sdk.installation.notification.group=Python interpreter installation python.sdk.installation.balloon.error.message=Python installation interrupted
Download Python manually from python.org, install it and configure the project interpreter. python.sdk.installation.balloon.error.action=See the documentation -python.sdk.directory.not.found=Directory {0} not found +python.sdk.python.executable.not.found=Python executable {0} is missing python.sdk.failed.to.create.interpreter.title=Failed to create interpreter python.sdk.can.t.obtain.python.version=Can't obtain python version python.sdk.empty.version.string=Python interpreter returned the empty output as a version string diff --git a/python/python-pyproject/src/com/intellij/python/pyproject/PyProjectToml.kt b/python/python-pyproject/src/com/intellij/python/pyproject/PyProjectToml.kt index 838c35ce6bb0..17e0fdd918cd 100644 --- a/python/python-pyproject/src/com/intellij/python/pyproject/PyProjectToml.kt +++ b/python/python-pyproject/src/com/intellij/python/pyproject/PyProjectToml.kt @@ -13,6 +13,8 @@ import org.apache.tuweni.toml.TomlParseError import org.apache.tuweni.toml.TomlTable import org.jetbrains.annotations.ApiStatus.Internal import java.io.InputStream +import java.nio.file.Path +import kotlin.io.path.isRegularFile /** * Stores the file name of `pyproject.toml`. @@ -240,6 +242,9 @@ data class PyProjectToml( findAmongRoots(module, PY_PROJECT_TOML) } + suspend fun findInRoot(moduleBasePath: Path): Path? = withContext(Dispatchers.IO) { + moduleBasePath.resolve(PY_PROJECT_TOML).takeIf { it.isRegularFile() } + } private fun TomlTable.parseContacts( key: String, diff --git a/python/src/com/jetbrains/python/hatch/sdk/HatchVirtualEnvironmentExt.kt b/python/src/com/jetbrains/python/hatch/sdk/HatchVirtualEnvironmentExt.kt index f4da87d4cad3..4fc46d4f35e9 100644 --- a/python/src/com/jetbrains/python/hatch/sdk/HatchVirtualEnvironmentExt.kt +++ b/python/src/com/jetbrains/python/hatch/sdk/HatchVirtualEnvironmentExt.kt @@ -2,10 +2,12 @@ package com.jetbrains.python.hatch.sdk import com.intellij.openapi.application.EDT -import com.intellij.openapi.module.Module import com.intellij.openapi.projectRoots.Sdk import com.intellij.openapi.util.NlsSafe -import com.intellij.python.hatch.* +import com.intellij.python.hatch.BasePythonExecutableNotFoundHatchError +import com.intellij.python.hatch.HatchVirtualEnvironment +import com.intellij.python.hatch.PythonVirtualEnvironment +import com.intellij.python.hatch.getHatchEnvVirtualProjectPath import com.jetbrains.python.Result import com.jetbrains.python.errorProcessing.PyResult import com.jetbrains.python.resolvePythonBinary @@ -19,7 +21,7 @@ import java.nio.file.Path import kotlin.io.path.name @ApiStatus.Internal -suspend fun HatchVirtualEnvironment.createSdk(workingDirectoryPath: Path, module: Module?): PyResult { +suspend fun HatchVirtualEnvironment.createSdk(workingDirectoryPath: Path): PyResult { val existingPythonEnvironment = pythonVirtualEnvironment as? PythonVirtualEnvironment.Existing ?: return Result.failure(BasePythonExecutableNotFoundHatchError(null as String?)) val pythonHomePath = pythonVirtualEnvironment?.pythonHomePath @@ -29,9 +31,9 @@ suspend fun HatchVirtualEnvironment.createSdk(workingDirectoryPath: Path, module val hatchSdkAdditionalData = HatchSdkAdditionalData(workingDirectoryPath, this.hatchEnvironment.name) val sdk = createSdk( - sdkHomePath = pythonBinary, + pythonBinaryPath = pythonBinary, existingSdks = PythonSdkUtil.getAllSdks(), - associatedProjectPath = module?.project?.basePath, + associatedProjectPath = workingDirectoryPath.toString(), suggestedSdkName = existingPythonEnvironment.suggestHatchSdkName(), sdkAdditionalData = hatchSdkAdditionalData ).getOr { return it } diff --git a/python/src/com/jetbrains/python/sdk/PySdkExt.kt b/python/src/com/jetbrains/python/sdk/PySdkExt.kt index 093d4d02b626..067a018bb84b 100644 --- a/python/src/com/jetbrains/python/sdk/PySdkExt.kt +++ b/python/src/com/jetbrains/python/sdk/PySdkExt.kt @@ -5,7 +5,10 @@ import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer import com.intellij.execution.ExecutionException import com.intellij.execution.target.* import com.intellij.ide.projectView.actions.MarkRootsManager -import com.intellij.openapi.application.* +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.application.EDT +import com.intellij.openapi.application.PathManager +import com.intellij.openapi.application.runInEdt import com.intellij.openapi.diagnostic.thisLogger import com.intellij.openapi.module.Module import com.intellij.openapi.module.ModuleUtil @@ -29,6 +32,7 @@ import com.intellij.platform.ide.progress.runWithModalProgressBlocking import com.intellij.util.PathUtil import com.intellij.webcore.packaging.PackagesNotificationPanel import com.jetbrains.python.PyBundle +import com.jetbrains.python.PythonBinary import com.jetbrains.python.errorProcessing.PyResult import com.jetbrains.python.isCondaVirtualEnv import com.jetbrains.python.isVirtualEnv @@ -188,7 +192,7 @@ fun createSdkByGenerateTask( val homeFile = try { val homePath = ProgressManager.getInstance().run(generateSdkHomePath) StandardFileSystems.local().refreshAndFindFileByPath(homePath) ?: throw ExecutionException( - PyBundle.message("python.sdk.directory.not.found", homePath) + PyBundle.message("python.sdk.python.executable.not.found", homePath) ) } catch (e: ExecutionException) { @@ -218,19 +222,20 @@ fun createSdkByGenerateTask( @Internal suspend fun createSdk( - sdkHomePath: Path, + pythonBinaryPath: PythonBinary, existingSdks: List, associatedProjectPath: String?, suggestedSdkName: String?, sdkAdditionalData: PythonSdkAdditionalData? = null, ): PyResult { - val homeFile = withContext(Dispatchers.IO) { StandardFileSystems.local().refreshAndFindFileByPath(sdkHomePath.pathString) } - ?: return PyResult.localizedError(PyBundle.message("python.sdk.directory.not.found", sdkHomePath.pathString)) + val pythonBinaryVirtualFile = withContext(Dispatchers.IO) { + StandardFileSystems.local().refreshAndFindFileByPath(pythonBinaryPath.pathString) + } ?: return PyResult.localizedError(PyBundle.message("python.sdk.python.executable.not.found", pythonBinaryPath.pathString)) - val sdkName = suggestedSdkName ?: suggestAssociatedSdkName(homeFile.path, associatedProjectPath) + val sdkName = suggestedSdkName ?: suggestAssociatedSdkName(pythonBinaryPath.pathString, associatedProjectPath) val sdk = SdkConfigurationUtil.setupSdk( existingSdks.toTypedArray(), - homeFile, + pythonBinaryVirtualFile, PythonSdkType.getInstance(), false, sdkAdditionalData, diff --git a/python/src/com/jetbrains/python/sdk/add/v2/CustomNewEnvironmentCreator.kt b/python/src/com/jetbrains/python/sdk/add/v2/CustomNewEnvironmentCreator.kt index 957f71b503e2..ac3c2512d2a3 100644 --- a/python/src/com/jetbrains/python/sdk/add/v2/CustomNewEnvironmentCreator.kt +++ b/python/src/com/jetbrains/python/sdk/add/v2/CustomNewEnvironmentCreator.kt @@ -1,9 +1,7 @@ // 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.add.v2 -import com.intellij.openapi.module.Module import com.intellij.openapi.observable.properties.ObservableMutableProperty -import com.intellij.openapi.project.Project import com.intellij.openapi.projectRoots.Sdk import com.intellij.openapi.ui.validation.DialogValidationRequestor import com.intellij.openapi.util.io.toNioPathOrNull @@ -13,6 +11,7 @@ import com.intellij.ui.components.ActionLink import com.intellij.ui.dsl.builder.Panel import com.intellij.util.concurrency.annotations.RequiresEdt import com.jetbrains.python.PyBundle.message +import com.jetbrains.python.PythonBinary import com.jetbrains.python.Result import com.jetbrains.python.errorProcessing.ErrorSink import com.jetbrains.python.errorProcessing.PyResult @@ -69,19 +68,20 @@ internal abstract class CustomNewEnvironmentCreator( // todo think about better error handling val selectedBasePython = model.state.baseInterpreter.get()!! - val homePath = model.installPythonIfNeeded(selectedBasePython) + val basePythonBinaryPath = model.installPythonIfNeeded(selectedBasePython) val module = when (moduleOrProject) { is ModuleOrProject.ModuleAndProject -> moduleOrProject.module is ModuleOrProject.ProjectOnly -> null } + val moduleBasePath = module?.basePath?.let { Path.of(it) } + ?: model.projectPathFlows.projectPath.first() + ?: error("module base path can't be recognized, both module and project are nulls") val newSdk = setupEnvSdk( - project = moduleOrProject.project, - module = module, + moduleBasePath = moduleBasePath, baseSdks = PythonSdkUtil.getAllSdks(), - projectPath = model.projectPathFlows.projectPathWithDefault.first().toString(), - homePath = homePath, + basePythonBinaryPath = basePythonBinaryPath, installPackages = false ).getOr { return it } @@ -184,7 +184,7 @@ internal abstract class CustomNewEnvironmentCreator( */ internal abstract fun savePathToExecutableToProperties(path: Path?) - protected abstract suspend fun setupEnvSdk(project: Project, module: Module?, baseSdks: List, projectPath: String, homePath: String?, installPackages: Boolean): PyResult + protected abstract suspend fun setupEnvSdk(moduleBasePath: Path, baseSdks: List, basePythonBinaryPath: PythonBinary?, installPackages: Boolean): PyResult internal abstract suspend fun detectExecutable() diff --git a/python/src/com/jetbrains/python/sdk/add/v2/EnvironmentCreatorPip.kt b/python/src/com/jetbrains/python/sdk/add/v2/EnvironmentCreatorPip.kt index 763ff8a55b17..c49ffdc755f4 100644 --- a/python/src/com/jetbrains/python/sdk/add/v2/EnvironmentCreatorPip.kt +++ b/python/src/com/jetbrains/python/sdk/add/v2/EnvironmentCreatorPip.kt @@ -2,11 +2,10 @@ package com.jetbrains.python.sdk.add.v2 import com.intellij.ide.util.PropertiesComponent -import com.intellij.openapi.module.Module import com.intellij.openapi.observable.properties.ObservableMutableProperty -import com.intellij.openapi.project.Project import com.intellij.openapi.projectRoots.Sdk import com.intellij.util.text.nullize +import com.jetbrains.python.PythonBinary import com.jetbrains.python.errorProcessing.ErrorSink import com.jetbrains.python.errorProcessing.PyResult import com.jetbrains.python.sdk.pipenv.pipEnvPath @@ -24,8 +23,9 @@ internal class EnvironmentCreatorPip(model: PythonMutableTargetAddInterpreterMod PropertiesComponent.getInstance().pipEnvPath = savingPath } - override suspend fun setupEnvSdk(project: Project, module: Module?, baseSdks: List, projectPath: String, homePath: String?, installPackages: Boolean): PyResult = - setupPipEnvSdkWithProgressReport(project, module, baseSdks, projectPath, homePath, installPackages) + override suspend fun setupEnvSdk(moduleBasePath: Path, baseSdks: List, basePythonBinaryPath: PythonBinary?, installPackages: Boolean): PyResult { + return setupPipEnvSdkWithProgressReport(moduleBasePath, baseSdks, basePythonBinaryPath, installPackages) + } override suspend fun detectExecutable() { model.detectPipEnvExecutable() diff --git a/python/src/com/jetbrains/python/sdk/add/v2/hatch/HatchExistingEnvironmentSelector.kt b/python/src/com/jetbrains/python/sdk/add/v2/hatch/HatchExistingEnvironmentSelector.kt index 67c611440e8c..539964ec67f3 100644 --- a/python/src/com/jetbrains/python/sdk/add/v2/hatch/HatchExistingEnvironmentSelector.kt +++ b/python/src/com/jetbrains/python/sdk/add/v2/hatch/HatchExistingEnvironmentSelector.kt @@ -72,7 +72,7 @@ internal class HatchExistingEnvironmentSelector( else -> { val (project, module) = moduleOrProject.destructured val workingDirectory = resolveHatchWorkingDirectory(project, module).getOr { return it } - environment.createSdk(workingDirectory, module).onSuccess { sdk -> + environment.createSdk(workingDirectory).onSuccess { sdk -> module?.let { module -> sdk.setAssociationToModule(module) } } } diff --git a/python/src/com/jetbrains/python/sdk/add/v2/hatch/HatchNewEnvironmentCreator.kt b/python/src/com/jetbrains/python/sdk/add/v2/hatch/HatchNewEnvironmentCreator.kt index cc04e5f017a1..9058f72a0318 100644 --- a/python/src/com/jetbrains/python/sdk/add/v2/hatch/HatchNewEnvironmentCreator.kt +++ b/python/src/com/jetbrains/python/sdk/add/v2/hatch/HatchNewEnvironmentCreator.kt @@ -3,7 +3,6 @@ package com.jetbrains.python.sdk.add.v2.hatch import com.intellij.openapi.module.Module import com.intellij.openapi.observable.properties.ObservableMutableProperty -import com.intellij.openapi.project.Project import com.intellij.openapi.projectRoots.Sdk import com.intellij.openapi.roots.ModuleRootModificationUtil import com.intellij.openapi.ui.validation.DialogValidationRequestor @@ -11,9 +10,9 @@ import com.intellij.openapi.vfs.VfsUtilCore import com.intellij.python.hatch.HatchConfiguration import com.intellij.python.hatch.HatchVirtualEnvironment import com.intellij.python.hatch.getHatchService -import com.intellij.python.hatch.resolveHatchWorkingDirectory import com.intellij.ui.dsl.builder.Panel import com.intellij.util.text.nullize +import com.jetbrains.python.PythonBinary import com.jetbrains.python.Result import com.jetbrains.python.errorProcessing.ErrorSink import com.jetbrains.python.errorProcessing.PyResult @@ -81,21 +80,20 @@ internal class HatchNewEnvironmentCreator( return Result.success(Unit) } - override suspend fun setupEnvSdk(project: Project, module: Module?, baseSdks: List, projectPath: String, homePath: String?, installPackages: Boolean): PyResult { + override suspend fun setupEnvSdk(moduleBasePath: Path, baseSdks: List, basePythonBinaryPath: PythonBinary?, installPackages: Boolean): PyResult { val hatchEnv = hatchEnvironmentProperty.get()?.hatchEnvironment ?: return Result.failure(HatchUIError.HatchEnvironmentIsNotSelected()) val hatchExecutablePath = executable.get().toPath().getOr { return it } - val hatchWorkingDirectory = resolveHatchWorkingDirectory(project, module).getOr { return it } - val hatchService = hatchWorkingDirectory.getHatchService(hatchExecutablePath = hatchExecutablePath).getOr { return it } + val hatchService = moduleBasePath.getHatchService(hatchExecutablePath = hatchExecutablePath).getOr { return it } val virtualEnvironment = hatchService.createVirtualEnvironment( - basePythonBinaryPath = homePath?.let { Path.of(it) }, + basePythonBinaryPath = basePythonBinaryPath, envName = hatchEnv.name ).getOr { return it } val hatchVirtualEnv = HatchVirtualEnvironment(hatchEnv, virtualEnvironment) - val createdSdk = hatchVirtualEnv.createSdk(hatchService.getWorkingDirectoryPath(), module).onSuccess { + val createdSdk = hatchVirtualEnv.createSdk(hatchService.getWorkingDirectoryPath()).onSuccess { HatchConfiguration.persistPathForTarget(hatchExecutablePath = hatchExecutablePath) } return createdSdk diff --git a/python/src/com/jetbrains/python/sdk/add/v2/poetry/EnvironmentCreatorPoetry.kt b/python/src/com/jetbrains/python/sdk/add/v2/poetry/EnvironmentCreatorPoetry.kt index 8ed159ba19d4..56bcbf202ffa 100644 --- a/python/src/com/jetbrains/python/sdk/add/v2/poetry/EnvironmentCreatorPoetry.kt +++ b/python/src/com/jetbrains/python/sdk/add/v2/poetry/EnvironmentCreatorPoetry.kt @@ -6,7 +6,6 @@ import com.intellij.openapi.application.EDT import com.intellij.openapi.components.* import com.intellij.openapi.module.Module import com.intellij.openapi.observable.properties.ObservableMutableProperty -import com.intellij.openapi.project.Project import com.intellij.openapi.projectRoots.Sdk import com.intellij.openapi.ui.validation.DialogValidationRequestor import com.intellij.openapi.vfs.VirtualFileManager @@ -16,9 +15,12 @@ import com.intellij.ui.dsl.builder.Panel import com.intellij.ui.dsl.builder.bindSelected import com.intellij.util.text.nullize import com.jetbrains.python.PyBundle +import com.jetbrains.python.PythonBinary import com.jetbrains.python.errorProcessing.ErrorSink import com.jetbrains.python.errorProcessing.PyResult import com.jetbrains.python.newProjectWizard.collector.PythonNewProjectWizardCollector +import com.jetbrains.python.poetry.PoetryPyProjectTomlPythonVersionsService +import com.jetbrains.python.poetry.findPoetryToml import com.jetbrains.python.sdk.add.v2.CustomNewEnvironmentCreator import com.jetbrains.python.sdk.add.v2.PythonInterpreterSelectionMethod.SELECT_EXISTING import com.jetbrains.python.sdk.add.v2.PythonMutableTargetAddInterpreterModel @@ -29,10 +31,8 @@ import com.jetbrains.python.sdk.add.v2.VenvExistenceValidationState.Error import com.jetbrains.python.sdk.add.v2.VenvExistenceValidationState.Invisible import com.jetbrains.python.sdk.add.v2.getBasePath import com.jetbrains.python.sdk.basePath -import com.jetbrains.python.poetry.PoetryPyProjectTomlPythonVersionsService import com.jetbrains.python.sdk.poetry.configurePoetryEnvironment -import com.jetbrains.python.poetry.findPoetryToml -import com.jetbrains.python.sdk.poetry.setupPoetrySdk +import com.jetbrains.python.sdk.poetry.createNewPoetrySdk import com.jetbrains.python.statistics.InterpreterType import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -113,9 +113,9 @@ internal class EnvironmentCreatorPoetry( PropertiesComponent.getInstance().poetryPath = savingPath } - override suspend fun setupEnvSdk(project: Project, module: Module?, baseSdks: List, projectPath: String, homePath: String?, installPackages: Boolean): PyResult { + override suspend fun setupEnvSdk(moduleBasePath: Path, baseSdks: List, basePythonBinaryPath: PythonBinary?, installPackages: Boolean): PyResult { module?.let { service().setInProjectEnv(it) } - return setupPoetrySdk(project, module, baseSdks, projectPath, homePath, installPackages) + return createNewPoetrySdk(moduleBasePath, baseSdks, basePythonBinaryPath, installPackages) } override suspend fun detectExecutable() { diff --git a/python/src/com/jetbrains/python/sdk/add/v2/poetry/PoetryExistingEnvironmentSelector.kt b/python/src/com/jetbrains/python/sdk/add/v2/poetry/PoetryExistingEnvironmentSelector.kt index deb65fb7d3a6..56a570b6237b 100644 --- a/python/src/com/jetbrains/python/sdk/add/v2/poetry/PoetryExistingEnvironmentSelector.kt +++ b/python/src/com/jetbrains/python/sdk/add/v2/poetry/PoetryExistingEnvironmentSelector.kt @@ -5,6 +5,7 @@ import com.intellij.openapi.module.Module import com.intellij.openapi.observable.properties.ObservableMutableProperty import com.intellij.openapi.projectRoots.ProjectJdkTable import com.intellij.openapi.projectRoots.Sdk +import com.jetbrains.python.PyBundle import com.jetbrains.python.Result import com.jetbrains.python.errorProcessing.PyResult import com.jetbrains.python.sdk.ModuleOrProject @@ -12,9 +13,10 @@ import com.jetbrains.python.sdk.PythonSdkUtil import com.jetbrains.python.sdk.add.v2.CustomExistingEnvironmentSelector import com.jetbrains.python.sdk.add.v2.DetectedSelectableInterpreter import com.jetbrains.python.sdk.add.v2.PythonMutableTargetAddInterpreterModel +import com.jetbrains.python.sdk.basePath +import com.jetbrains.python.sdk.poetry.createPoetrySdk import com.jetbrains.python.sdk.poetry.detectPoetryEnvs import com.jetbrains.python.sdk.poetry.isPoetry -import com.jetbrains.python.sdk.poetry.setupPoetrySdk import com.jetbrains.python.statistics.InterpreterType import com.jetbrains.python.statistics.version import java.nio.file.Path @@ -25,16 +27,24 @@ internal class PoetryExistingEnvironmentSelector(model: PythonMutableTargetAddIn override val interpreterType: InterpreterType = InterpreterType.POETRY override suspend fun getOrCreateSdk(moduleOrProject: ModuleOrProject): PyResult { - val selectedInterpreter = selectedEnv.get() - PythonSdkUtil.getAllSdks().find { sdk -> sdk.isPoetry && sdk.homePath == selectedInterpreter?.homePath }?.let { return Result.success(it) } + val pythonBinaryPath = selectedEnv.get()?.let { Path.of(it.homePath) } + ?: return PyResult.localizedError(PyBundle.message("python.sdk.provided.path.is.invalid", selectedEnv.get()?.homePath)) + + PythonSdkUtil.getAllSdks().find { sdk -> sdk.isPoetry && sdk.homePath == pythonBinaryPath.pathString }?.let { return Result.success(it) } + val module = when (moduleOrProject) { is ModuleOrProject.ModuleAndProject -> { moduleOrProject.module } else -> null } + val moduleBasePath = module?.basePath?.let { Path.of(it) } ?: error("module base path is not valid: ${module?.basePath}") - return setupPoetrySdk(moduleOrProject.project, module, ProjectJdkTable.getInstance().allJdks.toList(), null, selectedInterpreter?.homePath, true) + return createPoetrySdk( + moduleBasePath, + existingSdks = ProjectJdkTable.getInstance().allJdks.toList(), + pythonBinaryPath = pythonBinaryPath + ) } override suspend fun detectEnvironments(modulePath: Path): List { diff --git a/python/src/com/jetbrains/python/sdk/add/v2/presentersExt.kt b/python/src/com/jetbrains/python/sdk/add/v2/presentersExt.kt index ad034da5b0b1..f32dc5083841 100644 --- a/python/src/com/jetbrains/python/sdk/add/v2/presentersExt.kt +++ b/python/src/com/jetbrains/python/sdk/add/v2/presentersExt.kt @@ -95,10 +95,11 @@ suspend fun PythonAddInterpreterModel.selectCondaEnvironment(base: Boolean): PyR } -internal fun PythonAddInterpreterModel.installPythonIfNeeded(interpreter: PythonSelectableInterpreter): String? { +internal fun PythonAddInterpreterModel.installPythonIfNeeded(interpreter: PythonSelectableInterpreter): Path? { // todo use target config - return if (interpreter is InstallableSelectableInterpreter) { - installBaseSdk(interpreter.sdk, existingSdks)?.homePath ?: return null + val pathString = if (interpreter is InstallableSelectableInterpreter) { + installBaseSdk(interpreter.sdk, existingSdks)?.homePath } else interpreter.homePath + return pathString?.let { Path.of(it) } } \ No newline at end of file diff --git a/python/src/com/jetbrains/python/sdk/add/v2/uv/EnvironmentCreatorUv.kt b/python/src/com/jetbrains/python/sdk/add/v2/uv/EnvironmentCreatorUv.kt index 743879906727..cc6c27a71bf8 100644 --- a/python/src/com/jetbrains/python/sdk/add/v2/uv/EnvironmentCreatorUv.kt +++ b/python/src/com/jetbrains/python/sdk/add/v2/uv/EnvironmentCreatorUv.kt @@ -5,7 +5,6 @@ import com.intellij.openapi.module.Module import com.intellij.openapi.observable.properties.AtomicBooleanProperty import com.intellij.openapi.observable.properties.ObservableMutableProperty import com.intellij.openapi.observable.util.not -import com.intellij.openapi.project.Project import com.intellij.openapi.projectRoots.Sdk import com.intellij.openapi.ui.ComboBox import com.intellij.openapi.ui.validation.DialogValidationRequestor @@ -19,6 +18,7 @@ import com.intellij.ui.dsl.listCellRenderer.textListCellRenderer import com.intellij.util.text.nullize import com.intellij.util.ui.AsyncProcessIcon import com.jetbrains.python.PyBundle.message +import com.jetbrains.python.PythonBinary import com.jetbrains.python.errorProcessing.ErrorSink import com.jetbrains.python.errorProcessing.PyResult import com.jetbrains.python.getOrNull @@ -30,13 +30,11 @@ import com.jetbrains.python.sdk.add.v2.PythonSupportedEnvironmentManagers.PYTHON import com.jetbrains.python.sdk.add.v2.PythonSupportedEnvironmentManagers.UV import com.jetbrains.python.sdk.add.v2.VenvExistenceValidationState import com.jetbrains.python.sdk.add.v2.executableSelector -import com.jetbrains.python.sdk.basePath import com.jetbrains.python.sdk.uv.impl.createUvCli import com.jetbrains.python.sdk.uv.impl.createUvLowLevel import com.jetbrains.python.sdk.uv.impl.setUvExecutable import com.jetbrains.python.sdk.uv.setupNewUvSdkAndEnv import com.jetbrains.python.statistics.InterpreterType -import com.jetbrains.python.venvReader.tryResolvePath import io.github.z4kn4fein.semver.Version import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -173,19 +171,12 @@ internal class EnvironmentCreatorUv( } override suspend fun setupEnvSdk( - project: Project, - module: Module?, + moduleBasePath: Path, baseSdks: List, - projectPath: String, - homePath: String?, - installPackages: Boolean, + basePythonBinaryPath: PythonBinary?, + installPackages: Boolean ): PyResult { - val workingDir = module?.basePath?.let { tryResolvePath(it) } ?: project.basePath?.let { tryResolvePath(it) } - if (workingDir == null) { - return PyResult.localizedError(message("python.sdk.uv.working.dir.is.not.specified")) - } - - return setupNewUvSdkAndEnv(workingDir, baseSdks, pythonVersion.get()) + return setupNewUvSdkAndEnv(moduleBasePath, baseSdks, pythonVersion.get()) } override suspend fun detectExecutable() { diff --git a/python/src/com/jetbrains/python/sdk/pipenv/PipenvCommandExecutor.kt b/python/src/com/jetbrains/python/sdk/pipenv/PipenvCommandExecutor.kt index b32f47993e34..b6ca087659f9 100644 --- a/python/src/com/jetbrains/python/sdk/pipenv/PipenvCommandExecutor.kt +++ b/python/src/com/jetbrains/python/sdk/pipenv/PipenvCommandExecutor.kt @@ -2,18 +2,16 @@ package com.jetbrains.python.sdk.pipenv import com.intellij.ide.util.PropertiesComponent -import com.intellij.openapi.module.Module import com.intellij.openapi.progress.runBlockingCancellable -import com.intellij.openapi.project.Project import com.intellij.openapi.projectRoots.Sdk import com.intellij.openapi.util.SystemInfo import com.intellij.platform.eel.provider.asNioPath import com.intellij.platform.eel.provider.localEel import com.intellij.platform.eel.where import com.jetbrains.python.PyBundle +import com.jetbrains.python.PythonBinary import com.jetbrains.python.errorProcessing.PyResult import com.jetbrains.python.getOrNull -import com.jetbrains.python.sdk.basePath import com.jetbrains.python.sdk.createSdk import com.jetbrains.python.sdk.runExecutableWithProgress import com.jetbrains.python.venvReader.VirtualEnvReader @@ -22,6 +20,7 @@ import kotlinx.coroutines.withContext import org.jetbrains.annotations.ApiStatus.Internal import org.jetbrains.annotations.SystemDependent import java.nio.file.Path +import kotlin.io.path.pathString import kotlin.time.Duration.Companion.minutes @Internal @@ -81,24 +80,19 @@ suspend fun getPipEnvExecutable(): PyResult = */ @Internal suspend fun setupPipEnvSdkWithProgressReport( - project: Project?, - module: Module?, + moduleBasePath: Path, existingSdks: List, - newProjectPath: String?, - python: String?, + basePythonBinaryPath: PythonBinary?, installPackages: Boolean, ): PyResult { - val projectPath = newProjectPath ?: module?.basePath ?: project?.basePath - ?: return PyResult.localizedError(PyBundle.message("python.sdk.provided.path.is.invalid", null)) - val actualProject = project ?: module?.project - val pythonExecutablePath = if (actualProject != null) { - setUpPipEnv(projectPath, python, installPackages) - } - else { - setUpPipEnv(projectPath, python, installPackages) - }.getOr { return it } + val pythonExecutablePath = setUpPipEnv(moduleBasePath, basePythonBinaryPath, installPackages).getOr { return it } - return createSdk(pythonExecutablePath, existingSdks, projectPath, suggestedSdkName(projectPath), PyPipEnvSdkAdditionalData()) + return createSdk( + pythonExecutablePath, + existingSdks, moduleBasePath.pathString, + suggestedSdkName(moduleBasePath.pathString), + PyPipEnvSdkAdditionalData() + ) } /** @@ -107,23 +101,23 @@ suspend fun setupPipEnvSdkWithProgressReport( * @return the path to the pipenv environment. */ @Internal -suspend fun setupPipEnv(projectPath: Path, python: String?, installPackages: Boolean): PyResult<@SystemDependent String> { +suspend fun setupPipEnv(projectPath: Path, basePythonBinaryPath: PythonBinary?, installPackages: Boolean): PyResult<@SystemDependent String> { when { installPackages -> { - val pythonArgs = if (python != null) listOf("--python", python) else emptyList() + val pythonArgs = if (basePythonBinaryPath != null) listOf("--python", basePythonBinaryPath.pathString) else emptyList() val command = pythonArgs + listOf("install", "--dev") runPipEnv(projectPath, *command.toTypedArray()).getOr { return it } } - python != null -> - runPipEnv(projectPath, "--python", python).getOr { return it } + basePythonBinaryPath != null -> + runPipEnv(projectPath, "--python", basePythonBinaryPath.pathString).getOr { return it } else -> runPipEnv(projectPath, "run", "python", "-V").getOr { return it } } return runPipEnv(projectPath, "--venv") } -private suspend fun setUpPipEnv(projectPathString: String, python: String?, installPackages: Boolean): PyResult { - val pipEnv = setupPipEnv(Path.of(projectPathString), python, installPackages).getOr { return it } +private suspend fun setUpPipEnv(moduleBasePath: Path, basePythonBinaryPath: PythonBinary?, installPackages: Boolean): PyResult { + val pipEnv = setupPipEnv(moduleBasePath, basePythonBinaryPath, installPackages).getOr { return it } val pipEnvExecutablePathString = withContext(Dispatchers.IO) { VirtualEnvReader.Instance.findPythonInPythonRoot(Path.of(pipEnv))?.toString() } ?: return PyResult.localizedError(PyBundle.message("python.sdk.provided.path.is.invalid", pipEnv)) diff --git a/python/src/com/jetbrains/python/sdk/pipenv/ui/PyAddPipEnvPanel.kt b/python/src/com/jetbrains/python/sdk/pipenv/ui/PyAddPipEnvPanel.kt index 2643b05bd1a4..be2a03c74f1b 100644 --- a/python/src/com/jetbrains/python/sdk/pipenv/ui/PyAddPipEnvPanel.kt +++ b/python/src/com/jetbrains/python/sdk/pipenv/ui/PyAddPipEnvPanel.kt @@ -3,7 +3,6 @@ package com.jetbrains.python.sdk.pipenv.ui import com.intellij.application.options.ModuleListCellRenderer import com.intellij.ide.util.PropertiesComponent -import com.intellij.openapi.diagnostic.getOrLogException import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory import com.intellij.openapi.module.Module import com.intellij.openapi.module.ModuleUtil @@ -24,10 +23,13 @@ import com.intellij.util.ui.FormBuilder import com.jetbrains.python.* import com.jetbrains.python.newProject.collector.InterpreterStatisticsInfo import com.jetbrains.python.packaging.utils.PyPackageCoroutine -import com.jetbrains.python.sdk.* +import com.jetbrains.python.sdk.PySdkSettings import com.jetbrains.python.sdk.add.PyAddNewEnvPanel import com.jetbrains.python.sdk.add.PySdkPathChoosingComboBox import com.jetbrains.python.sdk.add.addBaseInterpretersAsync +import com.jetbrains.python.sdk.associatedModulePath +import com.jetbrains.python.sdk.basePath +import com.jetbrains.python.sdk.installSdkIfNeeded import com.jetbrains.python.sdk.pipenv.* import com.jetbrains.python.statistics.InterpreterTarget import com.jetbrains.python.statistics.InterpreterType @@ -36,6 +38,7 @@ import kotlinx.coroutines.withContext import java.awt.BorderLayout import java.awt.Dimension import java.awt.event.ItemEvent +import java.nio.file.Path import javax.swing.Icon import javax.swing.JComboBox import javax.swing.event.DocumentEvent @@ -128,12 +131,17 @@ class PyAddPipEnvPanel( @RequiresEdt override fun getOrCreateSdk(): Sdk? { PropertiesComponent.getInstance().pipEnvPath = pipEnvPathField.text.nullize() - val baseSdk = installSdkIfNeeded(baseSdkField.selectedSdk, selectedModule, existingSdks, context).getOrLogException(LOGGER)?.homePath + val baseSdk = installSdkIfNeeded(baseSdkField.selectedSdk, selectedModule, existingSdks, context).getOrThrow() + + val moduleBasePath = module?.basePath?.let { Path.of(it) } + ?: error("module base path is invalid: ${module?.basePath}") + + val basePythonBinaryPath = baseSdk.homePath?.let { Path.of(it) } + ?: error("base python binary path is invalid: ${baseSdk.homePath}") return runWithModalProgressBlocking(ModalTaskOwner.guess(), PyBundle.message("python.sdk.setting.up.pipenv.title")) { - setupPipEnvSdkWithProgressReport(project, selectedModule, existingSdks, newProjectPath, - baseSdk, installPackagesCheckBox.isSelected).onSuccess { - PySdkSettings.instance.preferredVirtualEnvBaseSdk = baseSdk + setupPipEnvSdkWithProgressReport(moduleBasePath, existingSdks, basePythonBinaryPath, installPackagesCheckBox.isSelected).onSuccess { + PySdkSettings.instance.preferredVirtualEnvBaseSdk = baseSdk.homePath } }.getOrNull() } diff --git a/python/src/com/jetbrains/python/sdk/poetry/PoetryCommandExecutor.kt b/python/src/com/jetbrains/python/sdk/poetry/PoetryCommandExecutor.kt index 1c4fb5cadf37..7e3c5c8a7ebc 100644 --- a/python/src/com/jetbrains/python/sdk/poetry/PoetryCommandExecutor.kt +++ b/python/src/com/jetbrains/python/sdk/poetry/PoetryCommandExecutor.kt @@ -16,11 +16,8 @@ import com.intellij.python.community.execService.execGetStdout import com.intellij.python.community.impl.poetry.poetryPath import com.intellij.python.pyproject.PY_PROJECT_TOML import com.intellij.util.SystemProperties -import com.jetbrains.python.PyBundle +import com.jetbrains.python.* import com.jetbrains.python.errorProcessing.PyResult -import com.jetbrains.python.getOrNull -import com.jetbrains.python.isSuccess -import com.jetbrains.python.onFailure import com.jetbrains.python.packaging.PyPackage import com.jetbrains.python.packaging.PyRequirement import com.jetbrains.python.packaging.PyRequirementParser @@ -41,7 +38,6 @@ import kotlinx.coroutines.withContext import org.jetbrains.annotations.ApiStatus.Internal import org.jetbrains.annotations.Nls import org.jetbrains.annotations.NonNls -import org.jetbrains.annotations.SystemDependent import org.jetbrains.annotations.SystemIndependent import java.nio.file.Path import kotlin.io.path.exists @@ -114,32 +110,30 @@ suspend fun runPoetryWithSdk(sdk: Sdk, vararg args: String): PyResult { * @return the path to the poetry environment. */ @Internal -suspend fun setupPoetry(projectPath: Path, python: String?, installPackages: Boolean, init: Boolean): PyResult<@SystemDependent String> { +suspend fun setupPoetry(projectPath: Path, basePythonBinaryPath: PythonBinary?, installPackages: Boolean, init: Boolean): PyResult { if (init) { - runPoetry(projectPath, *listOf("init", "-n").toTypedArray()) - .getOr { return it } + runPoetry(projectPath, *listOf("init", "-n").toTypedArray()).getOr { return it } - if (python != null) { // Replace a python version in toml - ExecService().execGetStdout(BinOnEel(Path.of(python), workDir = projectPath), Args("-c", REPLACE_PYTHON_VERSION)) - .getOr { return it } + if (basePythonBinaryPath != null) { // Replace a python version in toml + ExecService().execGetStdout( + binary = BinOnEel(path = basePythonBinaryPath, workDir = projectPath), + args = Args("-c", REPLACE_PYTHON_VERSION) + ).getOr { return it } } } - val env = if (python != null) { - runPoetry(projectPath, "env", "use", python) + if (basePythonBinaryPath != null) { + runPoetry(projectPath, "env", "use", basePythonBinaryPath.pathString).getOr { return it } } else { - runPoetry(projectPath, "run", "python", "-V") + runPoetry(projectPath, "run", "python", "-V").getOr { return it } } - env.onFailure { return PyResult.failure(it) } - if (installPackages) { - runPoetry(projectPath, "install") - .onFailure { return PyResult.failure(it) } + runPoetry(projectPath, "install").getOr { return it } } - return runPoetry(projectPath, "env", "info", "-p") + return runPoetry(projectPath, "env", "info", "-p").mapSuccess { Path.of(it) } } internal suspend fun detectPoetryEnvs(module: Module?, existingSdkPaths: Set?, projectPath: @SystemIndependent @NonNls String?): List { diff --git a/python/src/com/jetbrains/python/sdk/poetry/poetry.kt b/python/src/com/jetbrains/python/sdk/poetry/poetry.kt index 54c25a9b55db..c2bb3d122ab5 100644 --- a/python/src/com/jetbrains/python/sdk/poetry/poetry.kt +++ b/python/src/com/jetbrains/python/sdk/poetry/poetry.kt @@ -6,22 +6,18 @@ import com.intellij.openapi.module.ModuleUtil import com.intellij.openapi.project.Project import com.intellij.openapi.projectRoots.Sdk import com.intellij.openapi.util.NlsSafe -import com.intellij.openapi.vfs.StandardFileSystems -import com.intellij.python.pyproject.PY_PROJECT_TOML +import com.intellij.python.pyproject.PyProjectToml import com.intellij.util.PathUtil import com.jetbrains.python.PyBundle +import com.jetbrains.python.PythonBinary import com.jetbrains.python.PythonModuleTypeBase import com.jetbrains.python.errorProcessing.PyResult import com.jetbrains.python.icons.PythonIcons import com.jetbrains.python.packaging.common.PythonOutdatedPackage -import com.jetbrains.python.poetry.getPyProjectTomlForPoetry +import com.jetbrains.python.resolvePythonBinary import com.jetbrains.python.sdk.PythonSdkUtil -import com.jetbrains.python.sdk.basePath import com.jetbrains.python.sdk.createSdk import com.jetbrains.python.sdk.getOrCreateAdditionalData -import com.jetbrains.python.venvReader.tryResolvePath -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext import org.jetbrains.annotations.ApiStatus.Internal import java.nio.file.Path import java.util.regex.Pattern @@ -34,44 +30,32 @@ val POETRY_ICON: Icon = PythonIcons.Python.Origami @Internal fun suggestedSdkName(basePath: Path): @NlsSafe String = "Poetry (${PathUtil.getFileName(basePath.pathString)})" -/** - * Sets up the poetry environment under the modal progress window. - * - * The poetry is associated with the first valid object from this list: - * - * 1. New project specified by [newProjectPath] - * 2. Existing module specified by [module] - * 3. Existing project specified by [project] - * - * @return the SDK for poetry, not stored in the SDK table yet. - */ + @Internal -suspend fun setupPoetrySdk( - project: Project?, - module: Module?, +suspend fun createNewPoetrySdk( + moduleBasePath: Path, existingSdks: List, - newProjectPath: String?, - python: String?, + basePythonBinaryPath: PythonBinary?, installPackages: Boolean, - poetryPath: String? = null, ): PyResult { - val pathString = newProjectPath ?: module?.basePath ?: project?.basePath - val projectPath = pathString?.let { tryResolvePath(it) } - ?: return PyResult.localizedError(PyBundle.message("python.sdk.provided.path.is.invalid", pathString)) + val pythonBinaryPath = setUpPoetry(moduleBasePath, basePythonBinaryPath, installPackages).getOr { return it } - val pythonExecutablePath = setUpPoetry(projectPath, python, installPackages, poetryPath) - .getOr { return it } - - val result = createSdk( - sdkHomePath = pythonExecutablePath, - existingSdks = existingSdks, - associatedProjectPath = projectPath.toString(), - suggestedSdkName = suggestedSdkName(projectPath), - sdkAdditionalData = PyPoetrySdkAdditionalData(projectPath) - ) - return result + return createPoetrySdk(moduleBasePath, existingSdks, pythonBinaryPath) } +@Internal +suspend fun createPoetrySdk( + moduleBasePath: Path, + existingSdks: List, + pythonBinaryPath: PythonBinary, +): PyResult = createSdk( + pythonBinaryPath = pythonBinaryPath, + existingSdks = existingSdks, + associatedProjectPath = moduleBasePath.toString(), + suggestedSdkName = suggestedSdkName(moduleBasePath), + sdkAdditionalData = PyPoetrySdkAdditionalData(moduleBasePath) +) + internal val Sdk.isPoetry: Boolean get() { if (!PythonSdkUtil.isPythonSdk(this)) { @@ -91,21 +75,12 @@ internal fun allModules(project: Project?): List { }?.sortedBy { it.name } ?: emptyList() } -private suspend fun setUpPoetry(projectPath: Path, python: String?, installPackages: Boolean, poetryPath: String? = null): PyResult { - val poetryExecutablePathString = when (poetryPath) { - is String -> poetryPath - else -> { - val pyProjectToml = withContext(Dispatchers.IO) { - StandardFileSystems.local().findFileByPath(projectPath.toString())?.findChild(PY_PROJECT_TOML) - } - val init = pyProjectToml?.let { - getPyProjectTomlForPoetry(it) - } == null - setupPoetry(projectPath, python, installPackages, init).getOr { return it } - } - } - - return PyResult.success(Path.of(getPythonExecutable(poetryExecutablePathString))) +private suspend fun setUpPoetry(moduleBasePath: Path, basePythonBinaryPath: PythonBinary?, installPackages: Boolean): PyResult { + val init = PyProjectToml.findInRoot(moduleBasePath) == null + val pythonHomePath = setupPoetry(moduleBasePath, basePythonBinaryPath, installPackages, init).getOr { return it } + val pythonBinaryPath = pythonHomePath.resolvePythonBinary() + ?: return PyResult.localizedError(PyBundle.message("python.sdk.cannot.setup.sdk", pythonHomePath)) + return PyResult.success(pythonBinaryPath) } fun parsePoetryShowOutdated(input: String): Map { diff --git a/python/src/com/jetbrains/python/sdk/poetry/ui/PyAddExistingPoetryEnvPanel.kt b/python/src/com/jetbrains/python/sdk/poetry/ui/PyAddExistingPoetryEnvPanel.kt index 7b08cd6f86f4..e896107cc886 100644 --- a/python/src/com/jetbrains/python/sdk/poetry/ui/PyAddExistingPoetryEnvPanel.kt +++ b/python/src/com/jetbrains/python/sdk/poetry/ui/PyAddExistingPoetryEnvPanel.kt @@ -21,6 +21,7 @@ import com.jetbrains.python.sdk.poetry.* import com.jetbrains.python.ui.pyMayBeModalBlocking import com.jetbrains.python.util.runWithModalBlockingOrInBackground import java.awt.BorderLayout +import java.nio.file.Path import java.util.concurrent.ConcurrentHashMap import javax.swing.Icon @@ -75,9 +76,15 @@ class PyAddExistingPoetryEnvPanel( return when (val sdk = sdkComboBox.selectedSdk) { is PyDetectedSdk -> { val mappedModule = sdkToModule[sdk.name] ?: module + runWithModalBlockingOrInBackground(project, msg = PyBundle.message("python.sdk.dialog.title.setting.up.poetry.environment")) { - setupPoetrySdk(project, mappedModule, existingSdks, newProjectPath, - getPythonExecutable(sdk.name), false, sdk.name).onSuccess { + val moduleBasePath = mappedModule?.basePath?.let { Path.of(it) } + ?: error("module base path is invalid: ${mappedModule?.basePath}") + + val basePythonBinaryPath = getPythonExecutable(sdk.name).let { Path.of(it) } + ?: error("base python binary path is invalid, home path is ${sdk.name}") + + createPoetrySdk(moduleBasePath, existingSdks, basePythonBinaryPath).onSuccess { PySdkSettings.instance.preferredVirtualEnvBaseSdk = getPythonExecutable(sdk.name) } }.getOrNull() diff --git a/python/src/com/jetbrains/python/sdk/poetry/ui/PyAddNewPoetryPanel.kt b/python/src/com/jetbrains/python/sdk/poetry/ui/PyAddNewPoetryPanel.kt index 083db93518ba..3efc83bcb7e9 100644 --- a/python/src/com/jetbrains/python/sdk/poetry/ui/PyAddNewPoetryPanel.kt +++ b/python/src/com/jetbrains/python/sdk/poetry/ui/PyAddNewPoetryPanel.kt @@ -42,6 +42,7 @@ import kotlinx.coroutines.withContext import java.awt.BorderLayout import java.awt.Dimension import java.awt.event.ItemEvent +import java.nio.file.Path import javax.swing.Icon import javax.swing.JComboBox import javax.swing.event.DocumentEvent @@ -139,8 +140,11 @@ class PyAddNewPoetryPanel( override fun getOrCreateSdk(): Sdk? { PropertiesComponent.getInstance().poetryPath = poetryPathField.text.nullize() return pyModalBlocking { - setupPoetrySdk(project, selectedModule, existingSdks, newProjectPath, - baseSdkField.selectedSdk.homePath, installPackagesCheckBox.isSelected).onSuccess { + val moduleBasePath = selectedModule?.basePath?.let { Path.of(it) } + ?: error("select module base path is invalid: ${selectedModule?.basePath}") + val basePythonBinaryPath = baseSdkField.selectedSdk.homePath?.let { Path.of(it) } + + createNewPoetrySdk(moduleBasePath, existingSdks, basePythonBinaryPath, installPackagesCheckBox.isSelected).onSuccess { PySdkSettings.instance.preferredVirtualEnvBaseSdk = baseSdkField.selectedSdk.homePath } }.getOrNull()