diff --git a/python/src/com/jetbrains/python/sdk/poetry/PoetryConfigLoader.kt b/python/src/com/jetbrains/python/sdk/poetry/PoetryConfigLoader.kt index 94a0e787310e..be6f5bbe4be5 100644 --- a/python/src/com/jetbrains/python/sdk/poetry/PoetryConfigLoader.kt +++ b/python/src/com/jetbrains/python/sdk/poetry/PoetryConfigLoader.kt @@ -22,7 +22,7 @@ class PoetryConfigLoader : StartupActivity { try { project.sdks .filterNot { it.isPoetry } - .filter { isPoetryFromConfig(project, it) } + .filter { PoetryConfigService.getInstance(project).poetryVirtualenvPaths.contains(it.homePath)} .forEach { it.isPoetry = true } } catch (e: AlreadyDisposedException) { diff --git a/python/src/com/jetbrains/python/sdk/poetry/PyAddExistingPoetryEnvPanel.kt b/python/src/com/jetbrains/python/sdk/poetry/PyAddExistingPoetryEnvPanel.kt index e8fa1140a980..7d80731d8591 100644 --- a/python/src/com/jetbrains/python/sdk/poetry/PyAddExistingPoetryEnvPanel.kt +++ b/python/src/com/jetbrains/python/sdk/poetry/PyAddExistingPoetryEnvPanel.kt @@ -13,6 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +@file:Suppress("DialogTitleCapitalization") + package com.jetbrains.python.sdk.poetry import com.intellij.openapi.module.Module diff --git a/python/src/com/jetbrains/python/sdk/poetry/PyAddNewPoetryPanel.kt b/python/src/com/jetbrains/python/sdk/poetry/PyAddNewPoetryPanel.kt index 5459baca5dd2..cf3abc316a6e 100644 --- a/python/src/com/jetbrains/python/sdk/poetry/PyAddNewPoetryPanel.kt +++ b/python/src/com/jetbrains/python/sdk/poetry/PyAddNewPoetryPanel.kt @@ -5,9 +5,9 @@ import com.intellij.application.options.ModuleListCellRenderer import com.intellij.ide.util.PropertiesComponent import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory import com.intellij.openapi.module.Module -import com.intellij.openapi.module.ModuleUtil import com.intellij.openapi.project.Project import com.intellij.openapi.projectRoots.Sdk +import com.intellij.openapi.ui.ComboBox import com.intellij.openapi.ui.TextFieldWithBrowseButton import com.intellij.openapi.ui.ValidationInfo import com.intellij.openapi.util.UserDataHolder @@ -20,7 +20,6 @@ import com.intellij.util.text.nullize import com.intellij.util.ui.FormBuilder import com.jetbrains.python.PyBundle import com.jetbrains.python.PySdkBundle -import com.jetbrains.python.PythonModuleTypeBase import com.jetbrains.python.sdk.* import com.jetbrains.python.sdk.add.PyAddNewEnvPanel import com.jetbrains.python.sdk.add.PySdkPathChoosingComboBox @@ -92,7 +91,7 @@ class PyAddNewPoetryPanel(private val project: Project?, val modules = allModules(project) - moduleField = JComboBox(modules.toTypedArray()).apply { + moduleField = ComboBox(modules.toTypedArray()).apply { renderer = ModuleListCellRenderer() preferredSize = Dimension(Int.MAX_VALUE, preferredSize.height) addItemListener { @@ -199,7 +198,6 @@ class PyAddNewPoetryPanel(private val project: Project?, */ private fun validatePoetryIsNotAdded(): ValidationInfo? { val path = projectPath ?: return null - val project = project ?: return null val addedPoetry = isPoetry[path] ?: return null if (addedPoetry.homeDirectory == null) return null // TODO: check existing envs diff --git a/python/src/com/jetbrains/python/sdk/poetry/PyPoetryPackageManager.kt b/python/src/com/jetbrains/python/sdk/poetry/PyPoetryPackageManager.kt index 36e77eab2756..7a80e1989467 100644 --- a/python/src/com/jetbrains/python/sdk/poetry/PyPoetryPackageManager.kt +++ b/python/src/com/jetbrains/python/sdk/poetry/PyPoetryPackageManager.kt @@ -148,19 +148,10 @@ class PyPoetryPackageManager(val sdk: Sdk) : PyPackageManager() { return if (Regex("^[0-9]").containsMatchIn(version)) "==$version" else version } - private fun toRequirements(packages: List): List = - packages - .asSequence() - // .filterNot { (_, pkg) -> pkg.editable ?: false } - // TODO: Support requirements markers (PEP 496), currently any packages with markers are ignored due to PY-30803 - // .filter { (_, pkg) -> pkg.markers == null } - .flatMap { it -> this.parseRequirements("${it.name}${it.version?.let { getVersion(it) } ?: ""}").asSequence() } - .toList() - /** * Parses the output of `poetry install --dry-run ` into a list of packages. */ - fun parsePoetryInstallDryRun(input: String): Pair, List> { + private fun parsePoetryInstallDryRun(input: String): Pair, List> { fun getNameAndVersion(line: String): Triple { return line.split(" ").let { val installedVersion = it[5].replace(Regex("[():]"), "") diff --git a/python/src/com/jetbrains/python/sdk/poetry/poetry.kt b/python/src/com/jetbrains/python/sdk/poetry/poetry.kt index 831670663acf..9850c2b9b3f2 100644 --- a/python/src/com/jetbrains/python/sdk/poetry/poetry.kt +++ b/python/src/com/jetbrains/python/sdk/poetry/poetry.kt @@ -57,11 +57,7 @@ import com.jetbrains.python.sdk.flavors.PythonSdkFlavor import com.jetbrains.python.statistics.modules import icons.PythonIcons import org.apache.tuweni.toml.Toml -import org.apache.tuweni.toml.TomlInvalidTypeException -import org.apache.tuweni.toml.TomlParseResult -import org.apache.tuweni.toml.TomlTable import org.jetbrains.annotations.SystemDependent -import org.jetbrains.annotations.TestOnly import java.io.File import java.util.concurrent.TimeUnit import java.util.concurrent.TimeoutException @@ -235,12 +231,6 @@ fun setupPoetry(projectPath: @SystemDependent String, python: String?, installPa } -@Deprecated("This function is for backward compatibility") -fun isPoetryFromConfig(project: Project, sdk: Sdk): Boolean { - return PoetryConfigService.getInstance(project).poetryVirtualenvPaths.contains(sdk.homePath) -} - - var Sdk.isPoetry: Boolean get() = sdkAdditionalData is PyPoetrySdkAdditionalData set(value) { @@ -282,7 +272,7 @@ fun runPoetry(projectPath: @SystemDependent String?, vararg args: String): Strin emptyList(), ProcessOutput()) val command = listOf(executable) + args - val commandLine = GeneralCommandLine(command).withWorkDirectory(projectPath) + @Suppress("DialogTitleCapitalization") val commandLine = GeneralCommandLine(command).withWorkDirectory(projectPath) val handler = CapturingProcessHandler(commandLine) val indicator = ProgressManager.getInstance().progressIndicator val result = with(handler) { @@ -296,6 +286,7 @@ fun runPoetry(projectPath: @SystemDependent String?, vararg args: String): Strin } } return with(result) { + @Suppress("DialogTitleCapitalization") when { isCancelled -> throw RunCanceledByUserException() @@ -329,16 +320,6 @@ fun runCommand(projectPath: @SystemDependent String, command: String, vararg arg } } -/** - * Detects and sets up poetry SDK for a module with Pipfile. - */ -fun detectAndSetupPoetry(project: Project?, module: Module?, existingSdks: List): Sdk? { - if (module?.pyProjectToml == null || getPoetryExecutable() == null) { - return null - } - return setupPoetrySdkUnderProgress(project, module, existingSdks, null, null, false) -} - /** * The URLs of package sources configured in the Pipfile.lock of the module associated with this SDK. */ @@ -346,13 +327,6 @@ val Sdk.poetrySources: List // TODO parse pyproject.toml for tool.poetry.source.url get() = listOf(POETRY_DEFAULT_SOURCE_URL) -/** - * The list of requirements defined in the poetry.lock of the module associated with this SDK. - */ -//val Sdk.poetryLockRequirements: List? -// get() { -// return poetryLock?.let { PyPoetryPackageManager.getInstance(this).getRequirements() } -// } /** * A quick-fix for setting up the poetry for the module of the current PSI element. @@ -524,81 +498,9 @@ private fun VirtualFile.getModule(project: Project): Module? = private val LOCK_NOTIFICATION_GROUP = NotificationGroup(PyBundle.message("python.sdk.poetry.pip.file.watcher"), NotificationDisplayType.STICKY_BALLOON, false) -//private val Sdk.packageManager: PyPoetryPackageManager -// get() = PyPoetryPackageManager.getInstance(this) -// - -@TestOnly -fun getPoetryLockRequirements(virtualFile: VirtualFile, packageManager: PyPackageManager): List? { - fun getVersion(version: String): String { - return if (Regex("^[0-9]").containsMatchIn(version)) "==$version" else version - } - - fun toRequirements(packages: Map): List = - packages - .asSequence() - // .filterNot { (_, pkg) -> pkg.editable ?: false } - // TODO: Support requirements markers (PEP 496), currently any packages with markers are ignored due to PY-30803 - // .filter { (_, pkg) -> pkg.markers == null } - .flatMap { (name, pkg) -> packageManager.parseRequirements("$name${pkg.version?.let { getVersion(it) } ?: ""}").asSequence() } - .toList() - - //TODO: Support extras - val poetryLock = parsePoetryLock(virtualFile) ?: return null - return poetryLock.packages?.let { toRequirements(it) } ?: emptyList() -} - -private fun Sdk.parsePoetryLock(): PoetryLock? { - // TODO: Log errors if poetry.lock is not found - val file = poetryLock ?: return null - return parsePoetryLock(file) -} - -val Sdk.poetryLock: VirtualFile? - get() = - associatedModulePath?.let { StandardFileSystems.local().findFileByPath(it)?.findChild(POETRY_LOCK) } - private val Module.poetryLock: VirtualFile? get() = baseDir?.findChild(POETRY_LOCK) -private fun parsePoetryLock(pyProjectToml: VirtualFile): PoetryLock? { - val text = ReadAction.compute { FileDocumentManager.getInstance().getDocument(pyProjectToml)?.text } - return try { - val result: TomlParseResult = Toml.parse(text) - val packages = result.getArrayOrEmpty("package") - if (packages.isEmpty) return null - PoetryLock(packages = packages.toList().filterIsInstance(TomlTable::class.java).map { - Pair(it["name"] as String, - PoetryLockPackage( - version = it["version"] as? String - ) - ) - }.toMap()) - - // return try { - // Gson().fromJson(Toml.parse(text).toJson(), PoetryLock::class.java) - } - catch (e: Throwable) { - if (e is IllegalArgumentException || e is TomlInvalidTypeException || e is ClassCastException) return null - throw e - } -} - - -private data class PoetryLock( - @SerializedName("package") var packages: Map?) - -//private data class PoetryLockMeta(@SerializedName("sources") var sources: List?) - -private data class PoetryLockSource(@SerializedName("url") var url: String?) - -private data class PoetryLockPackage(@SerializedName("version") var version: String?, - // @SerializedName("category") var category: String?, - // @SerializedName("editable") var editable: Boolean?, - @SerializedName("hashes") var hashes: List? = null, - @SerializedName("markers") var markers: MutableList = mutableListOf(), - @SerializedName("extras") var extras: List>>? = null) - fun runPoetryInBackground(module: Module, args: List, description: String) { val task = object : Task.Backgroundable(module.project, StringUtil.toTitleCase(description), true) { override fun run(indicator: ProgressIndicator) { @@ -669,7 +571,7 @@ fun detectPoetryEnvs(module: Module?, existingSdkPaths: Set, projectPath fun getPoetryEnvs(projectPath: String): List = syncRunPoetry(projectPath, "env", "list", "--full-path", defaultResult = emptyList()) { result -> - result.lineSequence().mapNotNull { it.split(" ")[0] }.filterNot { it.isEmpty() }.toList() + result.lineSequence().map { it.split(" ")[0] }.filterNot { it.isEmpty() }.toList() } @@ -683,30 +585,6 @@ val poetryVersion: String? it.split(' ').lastOrNull() } -inline fun syncRunCommand(projectPath: @SystemDependent String, - command: String, - vararg args: String, - defaultResult: T, - crossinline callback: (String) -> T): T { - return try { - ApplicationManager.getApplication().executeOnPooledThread { - try { - val result = runCommand(projectPath, command, *args) - callback(result) - } - catch (e: PyExecutionException) { - defaultResult - } - catch (e: ProcessNotCreatedException) { - defaultResult - } - }.get(30, TimeUnit.SECONDS) - } - catch (e: TimeoutException) { - defaultResult - } -} - inline fun syncRunPoetry(projectPath: @SystemDependent String?, vararg args: String, defaultResult: T,