diff --git a/python/ide/impl/resources/intellij.pycharm.community.ide.impl.xml b/python/ide/impl/resources/intellij.pycharm.community.ide.impl.xml
index cb9b9d8e4e3c..05b0e4c23ba4 100644
--- a/python/ide/impl/resources/intellij.pycharm.community.ide.impl.xml
+++ b/python/ide/impl/resources/intellij.pycharm.community.ide.impl.xml
@@ -104,7 +104,10 @@
id="environmentYml"/>
-
+
+
diff --git a/python/ide/impl/resources/messages/PyCharmCommunityCustomizationBundle.properties b/python/ide/impl/resources/messages/PyCharmCommunityCustomizationBundle.properties
index b21c733b5fe5..a3a5b64eca76 100644
--- a/python/ide/impl/resources/messages/PyCharmCommunityCustomizationBundle.properties
+++ b/python/ide/impl/resources/messages/PyCharmCommunityCustomizationBundle.properties
@@ -58,6 +58,8 @@ sdk.dialog.title.setting.up.poetry.environment=Setting Up Poetry Environment
sdk.notification.label.set.up.poetry.environment.from.pyproject.toml.dependencies=File pyproject.toml contains project dependencies. Would you like to set up a poetry environment?
notification.group.pro.advertiser=PyCharm Professional recommended
+sdk.set.up.uv.environment=Set up an uv environment using {0}
+
new.project.python.group.name=Python
new.project.other.group.name=Other
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 a79fb209cea6..cc9e2187625f 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
@@ -34,20 +34,29 @@ import javax.swing.JComponent
import javax.swing.JPanel
import kotlin.io.path.pathString
-/**
- * This source code is created by @koxudaxi Koudai Aono
- */
-
class PyPoetrySdkConfiguration : PyProjectSdkConfigurationExtension {
companion object {
private val LOGGER = Logger.getInstance(PyPoetrySdkConfiguration::class.java)
}
- @RequiresBackgroundThread
- override fun createAndAddSdkForConfigurator(module: Module): Sdk? = runBlockingCancellable { createAndAddSDk(module, false) }
+ override fun getIntention(module: Module): @IntentionName String? {
+ return runBlockingCancellable {
+ val toml = findAmongRoots(module, PY_PROJECT_TOML)
+ if (toml == null) {
+ return@runBlockingCancellable null
+ }
+
+ val isPoetry = getPyProjectTomlForPoetry(toml) != null
+ if (!isPoetry) {
+ return@runBlockingCancellable null
+ }
+
+ PyCharmCommunityCustomizationBundle.message("sdk.set.up.poetry.environment", toml.name)
+ }
+ }
@RequiresBackgroundThread
- override fun getIntention(module: Module): @IntentionName String? = findAmongRoots(module, PY_PROJECT_TOML)?.let { PyCharmCommunityCustomizationBundle.message("sdk.set.up.poetry.environment", it.name) }
+ override fun createAndAddSdkForConfigurator(module: Module): Sdk? = runBlockingCancellable { createAndAddSDk(module, false) }
@RequiresBackgroundThread
override fun createAndAddSdkForInspection(module: Module): Sdk? = runBlockingCancellable { createAndAddSDk(module, true) }
diff --git a/python/ide/impl/src/com/intellij/pycharm/community/ide/impl/configuration/PyUvSdkConfiguration.kt b/python/ide/impl/src/com/intellij/pycharm/community/ide/impl/configuration/PyUvSdkConfiguration.kt
new file mode 100644
index 000000000000..83dc69a1a691
--- /dev/null
+++ b/python/ide/impl/src/com/intellij/pycharm/community/ide/impl/configuration/PyUvSdkConfiguration.kt
@@ -0,0 +1,69 @@
+// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.pycharm.community.ide.impl.configuration
+
+import com.intellij.codeInspection.util.IntentionName
+import com.intellij.openapi.diagnostic.Logger
+import com.intellij.openapi.module.Module
+import com.intellij.openapi.progress.runBlockingCancellable
+import com.intellij.openapi.projectRoots.ProjectJdkTable
+import com.intellij.openapi.projectRoots.Sdk
+import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil
+import com.intellij.pycharm.community.ide.impl.PyCharmCommunityCustomizationBundle
+import com.intellij.util.concurrency.annotations.RequiresBackgroundThread
+import com.jetbrains.python.sdk.*
+import com.jetbrains.python.sdk.basePath
+import com.jetbrains.python.sdk.configuration.PyProjectSdkConfigurationExtension
+import com.jetbrains.python.sdk.uv.PY_PROJECT_TOML
+import com.jetbrains.python.sdk.uv.getUvExecutable
+import com.jetbrains.python.sdk.uv.setupUvSdkUnderProgress
+import java.io.FileNotFoundException
+import java.nio.file.Path
+
+class PyUvSdkConfiguration : PyProjectSdkConfigurationExtension {
+ companion object {
+ private val LOGGER = Logger.getInstance(PyUvSdkConfiguration::class.java)
+ }
+
+ @RequiresBackgroundThread
+ override fun getIntention(module: Module): @IntentionName String? {
+ return findAmongRoots(module, PY_PROJECT_TOML)?.let { toml ->
+ getUvExecutable()?.let { PyCharmCommunityCustomizationBundle.message("sdk.set.up.uv.environment", toml.name) }
+ }
+ }
+
+ @RequiresBackgroundThread
+ override fun createAndAddSdkForConfigurator(module: Module): Sdk? {
+ return runBlockingCancellable {
+ createUv(module).getOrElse {
+ LOGGER.warn(it)
+ null
+ }
+ }
+ }
+
+ @RequiresBackgroundThread
+ override fun createAndAddSdkForInspection(module: Module): Sdk? {
+ return runBlockingCancellable {
+ createUv(module).getOrElse {
+ LOGGER.warn(it)
+ null
+ }
+ }
+ }
+
+ override fun supportsHeadlessModel(): Boolean = true
+
+ private suspend fun createUv(module: Module): Result {
+ val basePath = module.basePath?.let { Path.of(it) }
+ if (basePath == null) {
+ return Result.failure(FileNotFoundException("Can't find module base path"))
+ }
+
+ val sdk = setupUvSdkUnderProgress(module, basePath, ProjectJdkTable.getInstance().allJdks.toList(), null)
+ sdk.onSuccess {
+ SdkConfigurationUtil.addSdk(it)
+ }
+
+ return sdk
+ }
+}
\ No newline at end of file
diff --git a/python/src/com/jetbrains/python/sdk/poetry/PoetryFilesUtils.kt b/python/src/com/jetbrains/python/sdk/poetry/PoetryFilesUtils.kt
index 900899e9d9ce..cdfaa1f870b1 100644
--- a/python/src/com/jetbrains/python/sdk/poetry/PoetryFilesUtils.kt
+++ b/python/src/com/jetbrains/python/sdk/poetry/PoetryFilesUtils.kt
@@ -61,7 +61,7 @@ const val POETRY_DEFAULT_SOURCE_URL: String = "https://pypi.org/simple"
val LOGGER = Logger.getInstance("#com.jetbrains.python.sdk.poetry")
-internal suspend fun getPyProjectTomlForPoetry(virtualFile: VirtualFile): VirtualFile? =
+suspend fun getPyProjectTomlForPoetry(virtualFile: VirtualFile): VirtualFile? =
withContext(Dispatchers.IO) {
readAction {
try {