diff --git a/python/pluginResources/intellij.python.community.impl.xml b/python/pluginResources/intellij.python.community.impl.xml
index be253d183174..0615596c2e45 100644
--- a/python/pluginResources/intellij.python.community.impl.xml
+++ b/python/pluginResources/intellij.python.community.impl.xml
@@ -138,8 +138,8 @@
-
+
@@ -461,6 +461,9 @@
+
+
@@ -895,6 +898,12 @@
+
+
+
+
+
+
@@ -1119,4 +1128,4 @@
dynamic="true"
interface="com.intellij.python.community.services.systemPython.SystemPythonProvider"/>
-
\ No newline at end of file
+
diff --git a/python/src/com/jetbrains/python/sdk/flavors/WinRegistryService.kt b/python/python-sdk/src/com/jetbrains/python/sdk/WinRegistryService.kt
similarity index 95%
rename from python/src/com/jetbrains/python/sdk/flavors/WinRegistryService.kt
rename to python/python-sdk/src/com/jetbrains/python/sdk/WinRegistryService.kt
index a5d70ae158f1..0926ba87cbc4 100644
--- a/python/src/com/jetbrains/python/sdk/flavors/WinRegistryService.kt
+++ b/python/python-sdk/src/com/jetbrains/python/sdk/WinRegistryService.kt
@@ -1,5 +1,5 @@
// 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.flavors
+package com.jetbrains.python.sdk
import com.intellij.openapi.util.io.WindowsRegistryUtil
import org.jetbrains.annotations.ApiStatus
@@ -10,7 +10,6 @@ import org.jetbrains.annotations.ApiStatus
* @author Ilya.Kazakevich
*/
@ApiStatus.Internal
-
interface WinRegistryService {
/**
* @param basePath path like "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node"
diff --git a/python/services/system-python/BUILD.bazel b/python/services/system-python/BUILD.bazel
index ca81b66e771c..32467f8e4092 100644
--- a/python/services/system-python/BUILD.bazel
+++ b/python/services/system-python/BUILD.bazel
@@ -18,7 +18,7 @@ jvm_library(
name = "system-python",
module_name = "intellij.python.community.services.systemPython",
visibility = ["//visibility:public"],
- srcs = glob(["src/**/*.kt", "src/**/*.java"], allow_empty = True),
+ srcs = glob(["gen/**/*.kt", "gen/**/*.java", "src/**/*.kt", "src/**/*.java"], allow_empty = True),
deps = [
"@lib//:kotlin-stdlib",
"//python/python-sdk:sdk",
@@ -34,6 +34,7 @@ jvm_library(
"//platform/util",
"//python/installer",
"//python/python-venv:community-impl-venv",
+ "//python/python-psi-impl:psi-impl",
],
exports = ["//python/services/shared"],
runtime_deps = [":system-python_resources"]
@@ -75,6 +76,7 @@ jvm_library(
"@lib//:io-mockk-jvm",
"//platform/testFramework",
"//platform/testFramework:testFramework_test_lib",
+ "//python/python-psi-impl:psi-impl",
],
runtime_deps = [
":system-python_resources",
diff --git a/python/services/system-python/gen/com/intellij/python/community/services/systemPython/PythonCommunityServicesSystemPythonIcons.java b/python/services/system-python/gen/com/intellij/python/community/services/systemPython/PythonCommunityServicesSystemPythonIcons.java
new file mode 100644
index 000000000000..1a842014212c
--- /dev/null
+++ b/python/services/system-python/gen/com/intellij/python/community/services/systemPython/PythonCommunityServicesSystemPythonIcons.java
@@ -0,0 +1,19 @@
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.python.community.services.systemPython;
+
+import com.intellij.ui.IconManager;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+
+/**
+ * NOTE THIS FILE IS AUTO-GENERATED
+ * DO NOT EDIT IT BY HAND, run "Generate icon classes" configuration instead
+ */
+public final class PythonCommunityServicesSystemPythonIcons {
+ private static @NotNull Icon load(@NotNull String path, int cacheKey, int flags) {
+ return IconManager.getInstance().loadRasterizedIcon(path, PythonCommunityServicesSystemPythonIcons.class.getClassLoader(), cacheKey, flags);
+ }
+ /** 16x16 */ public static final @NotNull Icon Homebrew = load("icons/com/intellij/python/community/system/providers/expui/homebrew.svg", -2104807435, 0);
+ /** 16x16 */ public static final @NotNull Icon Pyenv = load("icons/com/intellij/python/community/system/providers/expui/pyenv.svg", -770384196, 0);
+}
diff --git a/python/services/system-python/intellij.python.community.services.systemPython.iml b/python/services/system-python/intellij.python.community.services.systemPython.iml
index 3a0cef502ca5..a665ee86be8d 100644
--- a/python/services/system-python/intellij.python.community.services.systemPython.iml
+++ b/python/services/system-python/intellij.python.community.services.systemPython.iml
@@ -3,6 +3,7 @@
+
@@ -33,5 +34,6 @@
+
\ No newline at end of file
diff --git a/python/services/system-python/resources/icons/com/intellij/python/community/system/providers/expui/homebrew.svg b/python/services/system-python/resources/icons/com/intellij/python/community/system/providers/expui/homebrew.svg
new file mode 100644
index 000000000000..a977351328b4
--- /dev/null
+++ b/python/services/system-python/resources/icons/com/intellij/python/community/system/providers/expui/homebrew.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/python/services/system-python/resources/icons/com/intellij/python/community/system/providers/expui/pyenv.svg b/python/services/system-python/resources/icons/com/intellij/python/community/system/providers/expui/pyenv.svg
new file mode 100644
index 000000000000..003e39edf1c2
--- /dev/null
+++ b/python/services/system-python/resources/icons/com/intellij/python/community/system/providers/expui/pyenv.svg
@@ -0,0 +1,6 @@
+
+
diff --git a/python/services/system-python/src/com/intellij/python/community/services/systemPython/impl/providers/BrewSystemPythonProvider.kt b/python/services/system-python/src/com/intellij/python/community/services/systemPython/impl/providers/BrewSystemPythonProvider.kt
new file mode 100644
index 000000000000..d9cdb216b1d8
--- /dev/null
+++ b/python/services/system-python/src/com/intellij/python/community/services/systemPython/impl/providers/BrewSystemPythonProvider.kt
@@ -0,0 +1,45 @@
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.python.community.services.systemPython.impl.providers
+
+import com.intellij.openapi.diagnostic.Logger
+import com.intellij.platform.eel.EelApi
+import com.intellij.platform.eel.isMac
+import com.intellij.python.community.services.shared.UICustomization
+import com.intellij.python.community.services.systemPython.PythonCommunityServicesSystemPythonIcons
+import com.intellij.python.community.services.systemPython.SystemPythonProvider
+import com.jetbrains.python.PythonBinary
+import com.jetbrains.python.errorProcessing.PyResult
+import java.nio.file.Path
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+
+
+private class BrewSystemPythonProvider : SystemPythonProvider {
+ private val LOGGER: Logger = Logger.getInstance(BrewSystemPythonProvider::class.java)
+ private val binDirectory = Path.of("/opt/homebrew/bin")
+
+ override suspend fun findSystemPythons(eelApi: EelApi): PyResult> {
+ if (!eelApi.platform.isMac) {
+ return PyResult.success(emptySet())
+ }
+
+ val pythons = withContext(Dispatchers.IO) {
+ try {
+ return@withContext collectPythonsInPaths(eelApi, listOf(binDirectory), listOf(python3XNamePattern))
+ }
+ catch (e: RuntimeException) {
+ LOGGER.error("failed to discover brew pythons", e)
+ }
+
+ return@withContext emptySet()
+ }
+
+ return PyResult.success(pythons)
+ }
+
+ override val uiCustomization: UICustomization?
+ get() {
+ // TODO: proper icon
+ return UICustomization(title = "homebrew", icon = PythonCommunityServicesSystemPythonIcons.Homebrew)
+ }
+}
diff --git a/python/services/system-python/src/com/intellij/python/community/services/systemPython/impl/CoreSystemPythonProvider.kt b/python/services/system-python/src/com/intellij/python/community/services/systemPython/impl/providers/LegacyPythonProvider.kt
similarity index 67%
rename from python/services/system-python/src/com/intellij/python/community/services/systemPython/impl/CoreSystemPythonProvider.kt
rename to python/services/system-python/src/com/intellij/python/community/services/systemPython/impl/providers/LegacyPythonProvider.kt
index b8fa47f11cf7..6f4911f5a8a9 100644
--- a/python/services/system-python/src/com/intellij/python/community/services/systemPython/impl/CoreSystemPythonProvider.kt
+++ b/python/services/system-python/src/com/intellij/python/community/services/systemPython/impl/providers/LegacyPythonProvider.kt
@@ -1,28 +1,33 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-package com.intellij.python.community.services.systemPython.impl
+package com.intellij.python.community.services.systemPython.impl.providers
import com.intellij.platform.eel.EelApi
import com.intellij.platform.eel.provider.localEel
import com.intellij.python.community.services.systemPython.SystemPythonProvider
import com.jetbrains.python.PythonBinary
-import com.jetbrains.python.Result
import com.jetbrains.python.errorProcessing.PyResult
import com.jetbrains.python.sdk.flavors.PythonSdkFlavor
import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
/**
- * [SystemPythonProvider] based ob [PythonSdkFlavor] (kind of bridge)
+ * [SystemPythonProvider] based of [PythonSdkFlavor]
*/
-internal object CoreSystemPythonProvider : SystemPythonProvider {
+internal class LegacySystemPythonProvider : SystemPythonProvider {
override suspend fun findSystemPythons(eelApi: EelApi): PyResult> {
- if (eelApi != localEel) return Result.success(emptySet())
- with(Dispatchers.IO) {
+ if (eelApi != localEel || !useLegacyPythonProvider()) {
+ return PyResult.success(emptySet())
+ }
+
+ val pythons = withContext(Dispatchers.IO) {
val paths = PythonSdkFlavor.getApplicableFlavors(false)
.flatMap {
it.dropCaches()
it.suggestLocalHomePaths(null, null)
}
- return Result.success(paths.toSet())
+ return@withContext PyResult.success(paths.toSet())
}
+
+ return pythons
}
}
\ No newline at end of file
diff --git a/python/services/system-python/src/com/intellij/python/community/services/systemPython/impl/providers/MacSystemPythonProvider.kt b/python/services/system-python/src/com/intellij/python/community/services/systemPython/impl/providers/MacSystemPythonProvider.kt
new file mode 100644
index 000000000000..3e5ba4f4c4d0
--- /dev/null
+++ b/python/services/system-python/src/com/intellij/python/community/services/systemPython/impl/providers/MacSystemPythonProvider.kt
@@ -0,0 +1,59 @@
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.python.community.services.systemPython.impl.providers
+
+import com.intellij.openapi.diagnostic.Logger
+import com.intellij.platform.eel.EelApi
+import com.intellij.platform.eel.isMac
+import com.intellij.python.community.services.shared.UICustomization
+import com.intellij.python.community.services.systemPython.SystemPythonProvider
+import com.jetbrains.python.PythonBinary
+import com.jetbrains.python.errorProcessing.PyResult
+import java.nio.file.Path
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+
+
+private class MacSystemPythonProvider : SystemPythonProvider {
+ private val LOGGER: Logger = Logger.getInstance(MacSystemPythonProvider::class.java)
+
+ private val directories = listOf(
+ Path.of("/usr/bin"),
+ Path.of("/usr/local/bin"),
+ Path.of("/usr/local/Cellar/python"),
+ Path.of("/Library/Frameworks/Python.framework/Versions"),
+ Path.of("/System/Library/Frameworks/Python.framework/Versions"),
+ )
+
+ // Patterns to match Python executable filenames
+ private val names = listOf(
+ python3NamePattern,
+ python3XNamePattern,
+ pypyNamePattern,
+ )
+
+ override suspend fun findSystemPythons(eelApi: EelApi): PyResult> {
+ // Check if we're on a Unix system that's not Mac
+ if (!eelApi.platform.isMac || useLegacyPythonProvider()) {
+ return PyResult.success(emptySet())
+ }
+
+ val pythons = withContext(Dispatchers.IO) {
+ try {
+ return@withContext collectPythonsInPaths(eelApi, directories, names)
+ }
+ catch (e: RuntimeException) {
+ LOGGER.error("Failed to discover mac system pythons", e)
+ }
+
+ return@withContext emptySet()
+ }
+
+ return PyResult.success(pythons)
+ }
+
+ override val uiCustomization: UICustomization?
+ get() {
+ // TODO:
+ return null
+ }
+}
\ No newline at end of file
diff --git a/python/services/system-python/src/com/intellij/python/community/services/systemPython/impl/providers/PyenvSystemPythonProvider.kt b/python/services/system-python/src/com/intellij/python/community/services/systemPython/impl/providers/PyenvSystemPythonProvider.kt
new file mode 100644
index 000000000000..1f785118c841
--- /dev/null
+++ b/python/services/system-python/src/com/intellij/python/community/services/systemPython/impl/providers/PyenvSystemPythonProvider.kt
@@ -0,0 +1,64 @@
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.python.community.services.systemPython.impl.providers
+
+import com.intellij.openapi.diagnostic.Logger
+import com.intellij.platform.eel.EelApi
+import com.intellij.platform.eel.getOrNull
+import com.intellij.platform.eel.path.EelPath
+import com.intellij.platform.eel.provider.asNioPath
+import com.intellij.python.community.services.shared.UICustomization
+import com.intellij.python.community.services.systemPython.PythonCommunityServicesSystemPythonIcons
+import com.intellij.python.community.services.systemPython.SystemPythonProvider
+import com.jetbrains.python.PythonBinary
+import com.jetbrains.python.errorProcessing.PyResult
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+
+
+private class PyenvSystemPythonProvider : SystemPythonProvider {
+ private val LOGGER: Logger = Logger.getInstance(PyenvSystemPythonProvider::class.java)
+
+ override suspend fun findSystemPythons(eelApi: EelApi): PyResult> {
+ if (useLegacyPythonProvider()) {
+ return PyResult.success(emptySet())
+ }
+
+ val pythons = withContext(Dispatchers.IO) {
+ try {
+ val env = eelApi.exec.fetchLoginShellEnvVariables()
+ val pyenvRoot = if ("PYENV_ROOT" in env) {
+ EelPath.parse(env["PYENV_ROOT"]!!, eelApi.descriptor)
+ }
+ else {
+ eelApi.userInfo.home.resolve(".pyenv")
+ }
+
+ val versionsDir = pyenvRoot.resolve("versions")
+ val entries = eelApi.fs.listDirectory(versionsDir)
+ .getOrNull()
+
+ if (entries == null) {
+ return@withContext emptySet()
+ }
+
+ val paths = entries
+ .map { versionsDir.resolve(it).resolve("bin").asNioPath() }
+
+ return@withContext collectPythonsInPaths(eelApi, paths, listOf(python3NamePattern))
+ }
+ catch (e: RuntimeException) {
+ LOGGER.error("failed to discover pyenv pythons", e)
+ }
+
+ return@withContext emptySet()
+ }
+
+ return PyResult.success(pythons)
+ }
+
+ override val uiCustomization: UICustomization?
+ get() {
+ // TODO: proper icon
+ return UICustomization(title = "pyenv", icon = PythonCommunityServicesSystemPythonIcons.Pyenv)
+ }
+}
diff --git a/python/services/system-python/src/com/intellij/python/community/services/systemPython/impl/providers/UnixSystemPythonProvider.kt b/python/services/system-python/src/com/intellij/python/community/services/systemPython/impl/providers/UnixSystemPythonProvider.kt
new file mode 100644
index 000000000000..79de99b2d68a
--- /dev/null
+++ b/python/services/system-python/src/com/intellij/python/community/services/systemPython/impl/providers/UnixSystemPythonProvider.kt
@@ -0,0 +1,56 @@
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.python.community.services.systemPython.impl.providers
+
+import com.intellij.openapi.diagnostic.Logger
+import com.intellij.platform.eel.EelApi
+import com.intellij.platform.eel.EelPlatform
+import com.intellij.platform.eel.isMac
+import com.intellij.python.community.services.systemPython.SystemPythonProvider
+import com.intellij.python.community.services.shared.UICustomization
+import com.jetbrains.python.PythonBinary
+import com.jetbrains.python.errorProcessing.PyResult
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+import java.nio.file.Path
+
+
+private class UnixSystemPythonProvider : SystemPythonProvider {
+ private val LOGGER: Logger = Logger.getInstance(UnixSystemPythonProvider::class.java)
+
+ private val directories = listOf(
+ Path.of("/usr/bin"),
+ Path.of("/usr/local/bin"))
+
+ // Patterns to match Python executable filenames
+ private val names = listOf(
+ python3NamePattern,
+ python3XNamePattern,
+ pypyNamePattern,
+ )
+
+ override suspend fun findSystemPythons(eelApi: EelApi): PyResult> {
+ // Check if we're on a Unix system that's not Mac
+ if (eelApi.platform !is EelPlatform.Posix || eelApi.platform.isMac || useLegacyPythonProvider()) {
+ return PyResult.success(emptySet())
+ }
+
+ val pythons = withContext(Dispatchers.IO) {
+ try {
+ return@withContext collectPythonsInPaths(eelApi, directories, names)
+ }
+ catch (e: RuntimeException) {
+ LOGGER.error("Failed to discover unix system pythons", e)
+ }
+
+ return@withContext emptySet()
+ }
+
+ return PyResult.success(pythons)
+ }
+
+ override val uiCustomization: UICustomization?
+ get() {
+ // TODO:
+ return null
+ }
+}
\ No newline at end of file
diff --git a/python/services/system-python/src/com/intellij/python/community/services/systemPython/impl/providers/Utils.kt b/python/services/system-python/src/com/intellij/python/community/services/systemPython/impl/providers/Utils.kt
new file mode 100644
index 000000000000..b3bc7b1d83e9
--- /dev/null
+++ b/python/services/system-python/src/com/intellij/python/community/services/systemPython/impl/providers/Utils.kt
@@ -0,0 +1,44 @@
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.python.community.services.systemPython.impl.providers
+
+import com.intellij.openapi.util.registry.Registry
+import com.intellij.platform.eel.EelApi
+import com.intellij.platform.eel.fs.EelFileSystemApi.StatError
+import com.intellij.platform.eel.fs.stat
+import com.intellij.platform.eel.getOrNull
+import com.intellij.platform.eel.path.EelPath
+import com.intellij.platform.eel.provider.asNioPath
+import java.nio.file.Path
+import java.util.regex.Pattern
+import kotlin.collections.map
+import kotlin.io.path.pathString
+
+
+internal val pypyNamePattern: Pattern = Pattern.compile("pypy$")
+internal val python3NamePattern: Pattern = Pattern.compile("python3$")
+internal val python3XNamePattern: Pattern = Pattern.compile("python3\\.[0-9]+$")
+
+internal fun useLegacyPythonProvider(): Boolean {
+ return Registry.`is`("python.use.system.legacy.provider")
+}
+
+internal suspend fun collectPythonsInPaths(eelApi: EelApi, paths: List, names: List): Set {
+ val pythons = mutableSetOf()
+
+ for (path in paths) {
+ val directory = EelPath.parse(path.pathString, eelApi.descriptor)
+ if (eelApi.fs.stat(directory).eelIt() is StatError) {
+ continue
+ }
+
+ val entries = eelApi.fs.listDirectory(directory)
+ .getOrNull()
+
+ entries
+ ?.map { directory.resolve(it).asNioPath() }
+ ?.filter { names.firstOrNull { name -> name.matcher(it.fileName.toString()).matches() } != null }
+ ?.let { pythons.addAll(it) }
+ }
+
+ return pythons
+}
\ No newline at end of file
diff --git a/python/services/system-python/src/com/intellij/python/community/services/systemPython/impl/providers/WindowsSystemPythonProvider.kt b/python/services/system-python/src/com/intellij/python/community/services/systemPython/impl/providers/WindowsSystemPythonProvider.kt
new file mode 100644
index 000000000000..34451485bed9
--- /dev/null
+++ b/python/services/system-python/src/com/intellij/python/community/services/systemPython/impl/providers/WindowsSystemPythonProvider.kt
@@ -0,0 +1,119 @@
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.python.community.services.systemPython.impl.providers
+
+import com.intellij.execution.configurations.PathEnvironmentVariableUtil
+import com.intellij.openapi.application.ApplicationManager
+import com.intellij.openapi.diagnostic.Logger
+import com.intellij.platform.eel.EelApi
+import com.intellij.platform.eel.isWindows
+import com.intellij.platform.eel.provider.localEel
+import com.intellij.python.community.services.systemPython.SystemPythonProvider
+import com.jetbrains.python.PythonBinary
+import com.jetbrains.python.errorProcessing.PyResult
+import com.jetbrains.python.sdk.PythonSdkUtil
+import com.jetbrains.python.sdk.WinRegistryService
+import com.jetbrains.python.sdk.getAppxFiles
+import com.jetbrains.python.venvReader.tryResolvePath
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+import java.nio.file.Path
+import java.util.regex.Pattern
+import kotlin.collections.iterator
+import kotlin.io.path.exists
+import kotlin.io.path.pathString
+
+
+class WindowsSystemPythonProvider(val winRegistryBase: WinRegistryService? = null) : SystemPythonProvider {
+ private val LOGGER: Logger = Logger.getInstance(WindowsSystemPythonProvider::class.java)
+
+ private val names = listOf(
+ "pypy.exe",
+ "python.exe")
+
+ // Registry roots and product mappings from WinPythonSdkFlavor
+ private val REG_ROOTS = arrayOf("HKEY_LOCAL_MACHINE", "HKEY_CURRENT_USER")
+ private val REGISTRY_MAP = mapOf(
+ "Python" to "python.exe",
+ "IronPython" to "ipy.exe"
+ )
+ val winRegistry: Lazy = lazy {
+ winRegistryBase ?: ApplicationManager.getApplication().getService(WinRegistryService::class.java)
+ }
+
+ // Windows Store Python product name
+ private val APPX_PRODUCT = "Python"
+ private val pythonVersionedExePattern = Pattern.compile("python[0-9.]*?\\.exe$")
+
+ override suspend fun findSystemPythons(eelApi: EelApi): PyResult> {
+ if (eelApi != localEel || !eelApi.platform.isWindows || useLegacyPythonProvider()) {
+ return PyResult.success(emptySet())
+ }
+
+ val pythons = withContext(Dispatchers.IO) {
+ try {
+ val candidates = mutableSetOf()
+
+ for (name in names) {
+ val binaries = PathEnvironmentVariableUtil.findAllExeFilesInPath(name)
+ .mapNotNull { it.toPath() }
+ .filter { !PythonSdkUtil.isConda(it.pathString) }
+ .toSet()
+
+ candidates.addAll(binaries)
+ }
+
+ candidates.addAll(getPythonsFromStore())
+ candidates.addAll(getPythonsFromRegistry())
+
+ return@withContext candidates
+ }
+ catch (e: RuntimeException) {
+ LOGGER.error("Failed to discover Windows system pythons", e)
+ }
+
+ return@withContext emptySet()
+ }
+
+ return PyResult.success(pythons)
+ }
+
+ // Check https://www.python.org/dev/peps/pep-0514/ for windows registry layout to understand
+ private fun getPythonsFromRegistry(): Set {
+ val candidates = mutableSetOf()
+
+ for (regRoot in REG_ROOTS) {
+ for ((productId, exe) in REGISTRY_MAP) {
+ val companiesPath = "$regRoot\\SOFTWARE\\$productId"
+ val companiesPathWow = "$regRoot\\SOFTWARE\\Wow6432Node\\$productId"
+
+ for (path in arrayOf(companiesPath, companiesPathWow)) {
+ for (company in winRegistry.value.listBranches(path)) {
+ val pathToCompany = "$path\\$company"
+
+ for (version in winRegistry.value.listBranches(pathToCompany)) {
+ val folder = winRegistry.value.getDefaultKey("$pathToCompany\\$version\\InstallPath")
+ tryResolvePath(folder)
+ ?.resolve(exe)
+ ?.takeIf(Path::exists)
+ ?.let { candidates.add(it) }
+ }
+ }
+ }
+ }
+ }
+
+ return candidates
+ }
+
+ private fun getPythonsFromStore(): Set {
+ return try {
+ getAppxFiles(APPX_PRODUCT, pythonVersionedExePattern.toRegex())
+ .map { it.toAbsolutePath() }
+ .toSet()
+ }
+ catch (e: Exception) {
+ LOGGER.debug("Error getting Python from Windows Store", e)
+ emptySet()
+ }
+ }
+}
diff --git a/python/services/system-python/src/com/intellij/python/community/services/systemPython/systemPythonServiceImpl.kt b/python/services/system-python/src/com/intellij/python/community/services/systemPython/systemPythonServiceImpl.kt
index b6262a4fb0ae..74ae45611d3f 100644
--- a/python/services/system-python/src/com/intellij/python/community/services/systemPython/systemPythonServiceImpl.kt
+++ b/python/services/system-python/src/com/intellij/python/community/services/systemPython/systemPythonServiceImpl.kt
@@ -15,7 +15,6 @@ import com.intellij.python.community.services.internal.impl.VanillaPythonWithLan
import com.intellij.python.community.services.shared.UICustomization
import com.intellij.python.community.services.systemPython.SystemPythonServiceImpl.MyServiceState
import com.intellij.python.community.services.systemPython.impl.Cache
-import com.intellij.python.community.services.systemPython.impl.CoreSystemPythonProvider
import com.intellij.python.community.services.systemPython.impl.PySystemPythonBundle
import com.jetbrains.python.PythonBinary
import com.jetbrains.python.Result
@@ -93,7 +92,7 @@ internal class SystemPythonServiceImpl(scope: CoroutineScope) : SystemPythonServ
// Only strings are supported by serializer
var userProvidedPythons by list()
val userProvidedPythonsAsPath: Collection
- get() = userProvidedPythons.filterNotNull().mapNotNull {
+ get() = userProvidedPythons.mapNotNull {
try {
Path.of(it)
}
@@ -109,8 +108,7 @@ internal class SystemPythonServiceImpl(scope: CoroutineScope) : SystemPythonServ
findPythonsMutex.withLock {
val pythonsUi = mutableMapOf()
- val pythonsFromExtensions = (SystemPythonProvider.EP
- .extensionList + listOf(CoreSystemPythonProvider))
+ val pythonsFromExtensions = SystemPythonProvider.EP.extensionList
.flatMap { provider ->
val pythons = provider.findSystemPythons(eelApi).getOrNull() ?: emptyList()
val ui = provider.uiCustomization
diff --git a/python/src/com/jetbrains/python/sdk/flavors/WinPythonSdkFlavor.java b/python/src/com/jetbrains/python/sdk/flavors/WinPythonSdkFlavor.java
index aa12207ee181..d8b334874f2d 100644
--- a/python/src/com/jetbrains/python/sdk/flavors/WinPythonSdkFlavor.java
+++ b/python/src/com/jetbrains/python/sdk/flavors/WinPythonSdkFlavor.java
@@ -16,6 +16,7 @@ import com.intellij.python.community.helpersLocator.PythonHelpersLocator;
import com.intellij.util.concurrency.SynchronizedClearableLazy;
import com.intellij.util.concurrency.annotations.RequiresBackgroundThread;
import com.intellij.util.containers.ContainerUtil;
+import com.jetbrains.python.sdk.WinRegistryService;
import kotlin.text.Regex;
import org.jetbrains.annotations.*;
diff --git a/python/src/com/jetbrains/python/sdk/poetry/PoetryCommandExecutor.kt b/python/src/com/jetbrains/python/sdk/poetry/PoetryCommandExecutor.kt
index 598cd862e7da..a22cb65d47ca 100644
--- a/python/src/com/jetbrains/python/sdk/poetry/PoetryCommandExecutor.kt
+++ b/python/src/com/jetbrains/python/sdk/poetry/PoetryCommandExecutor.kt
@@ -117,6 +117,7 @@ suspend fun setupPoetry(projectPath: Path, python: String?, installPackages: Boo
if (init) {
runPoetry(projectPath, *listOf("init", "-n").toTypedArray())
.getOr { return it }
+
if (python != null) { // Replace a python version in toml
ExecService().execGetStdout(Path.of(python), listOf("-c", REPLACE_PYTHON_VERSION), ExecOptions(workingDirectory = projectPath))
.getOr { return it }
diff --git a/python/testSrc/com/jetbrains/python/sdk/flavors/WinPythonSdkFlavorTest.java b/python/testSrc/com/jetbrains/python/sdk/flavors/WinPythonSdkFlavorTest.java
index 502a53ef80ce..ad9790d579f3 100644
--- a/python/testSrc/com/jetbrains/python/sdk/flavors/WinPythonSdkFlavorTest.java
+++ b/python/testSrc/com/jetbrains/python/sdk/flavors/WinPythonSdkFlavorTest.java
@@ -2,6 +2,7 @@
package com.jetbrains.python.sdk.flavors;
import com.intellij.openapi.util.io.FileUtil;
+import com.jetbrains.python.sdk.WinRegistryService;
import org.easymock.EasyMock;
import org.easymock.IMocksControl;
import org.easymock.MockType;