Skip to content
This repository has been archived by the owner on Feb 9, 2022. It is now read-only.

[#215] Suggest existing poetry venvs that are in existing modules #217

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
21 changes: 18 additions & 3 deletions src/com/koxudaxi/poetry/PyAddExistingPoetryEnvPanel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ import com.jetbrains.python.sdk.add.PyAddSdkView
import com.jetbrains.python.sdk.add.PySdkPathChoosingComboBox
import com.jetbrains.python.sdk.add.addInterpretersAsync
import java.awt.BorderLayout
import java.util.concurrent.ConcurrentHashMap
import javax.swing.Icon
import kotlin.streams.toList

/**
* @author vlan
Expand All @@ -44,6 +46,7 @@ class PyAddExistingPoetryEnvPanel(private val project: Project?,
private val existingSdks: List<Sdk>,
override var newProjectPath: String?,
context: UserDataHolder) : PyAddSdkPanel() {
private var sdkToModule = ConcurrentHashMap<String, Module>()
override val panelName: String get() = PyBundle.message("python.add.sdk.panel.name.existing.environment")
override val icon: Icon = POETRY_ICON
private val sdkComboBox = PySdkPathChoosingComboBox()
Expand All @@ -55,20 +58,32 @@ class PyAddExistingPoetryEnvPanel(private val project: Project?,
.panel
add(formPanel, BorderLayout.NORTH)
addInterpretersAsync(sdkComboBox) {
detectPoetryEnvs(module, existingSdks, context, project?.basePath ?: newProjectPath)
val existingSdkPaths = sdkHomes(existingSdks)
val moduleSdks = allModules(project).parallelStream().flatMap { module ->
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does not take a crazy long time to load if there are many modules (I have 45):
Add_Python_Interpreter_and_Project_Structure

val sdks = detectPoetryEnvs(module, existingSdkPaths, module.basePath)
.filterNot { it.isAssociatedWithAnotherModule(module) }
sdks.forEach { sdkToModule.putIfAbsent(it.name, module) }
sdks.stream()
}.toList()
val rootSdks = detectPoetryEnvs(module, existingSdkPaths, project?.basePath ?: newProjectPath)
.filterNot { it.isAssociatedWithAnotherModule(module) }
val moduleSdkPaths = moduleSdks.map { it.name }.toSet()
val sdks = rootSdks.filterNot { moduleSdkPaths.contains(it.name) } + moduleSdks
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure we only have one entry for the project if there's a module at the same level:
Add_Python_Interpreter_and_Project_Structure

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure that associated sdks are not in the dropdown:
Project_Structure_and_data-mesh
Add_Python_Interpreter_and_Project_Structure_and_data-mesh

sdks.sortedBy { it.name }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorted alphabetically, which is understandable and searchable (alternative was by module name):
Add_Python_Interpreter_and_Project_Structure

}
}

override fun validateAll(): List<ValidationInfo> = listOfNotNull(validateSdkComboBox(sdkComboBox, this))

override fun getOrCreateSdk(): Sdk? {
return when (val sdk = sdkComboBox.selectedSdk) {
is PyDetectedSdk ->
setupPoetrySdkUnderProgress(project, module, existingSdks, newProjectPath,
is PyDetectedSdk -> {
val mappedModule = sdkToModule[sdk.name] ?: module
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created sdk matches the corresponding module's folder's name:
Project_Structure_and_data-mesh

setupPoetrySdkUnderProgress(project, mappedModule, existingSdks, newProjectPath,
getPythonExecutable(sdk.name), false, sdk.name)?.apply {
PySdkSettings.instance.preferredVirtualEnvBaseSdk = getPythonExecutable(sdk.name)
}
}
else -> sdk
}
}
Expand Down
4 changes: 1 addition & 3 deletions src/com/koxudaxi/poetry/PyAddNewPoetryPanel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,7 @@ class PyAddNewPoetryPanel(private val project: Project?,
init {
layout = BorderLayout()

val modules = project?.let {
ModuleUtil.getModulesOfType(it, PythonModuleTypeBase.getInstance())
}?.sortedBy { it.name } ?: emptyList()
val modules = allModules(project)

moduleField = JComboBox(modules.toTypedArray()).apply {
renderer = ModuleListCellRenderer()
Expand Down
23 changes: 17 additions & 6 deletions src/com/koxudaxi/poetry/poetry.kt
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import com.intellij.openapi.vfs.VirtualFile
import com.intellij.serviceContainer.AlreadyDisposedException
import com.intellij.util.PathUtil
import com.intellij.util.PlatformUtils
import com.jetbrains.python.PythonModuleTypeBase
import com.jetbrains.python.inspections.PyPackageRequirementsInspection
import com.jetbrains.python.packaging.*
import com.jetbrains.python.sdk.*
Expand All @@ -60,6 +61,8 @@ 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.NonNls
import org.jetbrains.annotations.Nullable
import org.jetbrains.annotations.SystemDependent
import org.jetbrains.annotations.TestOnly
import org.toml.lang.psi.TomlKey
Expand Down Expand Up @@ -626,9 +629,10 @@ fun createPoetryPanel(project: Project?,
}
val existingPoetryPanel = PyAddExistingPoetryEnvPanel(project, module, existingSdks, null, context)
val panels = listOfNotNull(newPoetryPanel, existingPoetryPanel)
val existingSdkPaths = sdkHomes(existingSdks)
val defaultPanel = when {
detectPoetryEnvs(module, existingSdks, context, project?.basePath
?: newProjectPath).any { it.isAssociatedWithModule(module) } -> existingPoetryPanel
detectPoetryEnvs(module, existingSdkPaths, project?.basePath
?: newProjectPath).any { it.isAssociatedWithModule(module) } -> existingPoetryPanel
newPoetryPanel != null -> newPoetryPanel
else -> existingPoetryPanel
}
Expand All @@ -637,11 +641,18 @@ fun createPoetryPanel(project: Project?,
}


fun detectPoetryEnvs(module: Module?, existingSdks: List<Sdk>, context: UserDataHolder, projectPath: String?): List<PyDetectedSdk> {
if (projectPath == null) return emptyList()
val existingSdkPaths = existingSdks.mapNotNull { it.homePath }.toSet()
fun allModules(project: Project?): List<Module> {
return project?.let {
ModuleUtil.getModulesOfType(it, PythonModuleTypeBase.getInstance())
}?.sortedBy { it.name } ?: emptyList()
}

fun sdkHomes(sdks: List<Sdk>): Set<String> = sdks.mapNotNull { it.homePath }.toSet()

fun detectPoetryEnvs(module: Module?, existingSdkPaths: Set<String>, projectPath: String?): List<PyDetectedSdk> {
val path = module?.basePath ?: projectPath ?: return emptyList()
return try {
getPoetryEnvs(projectPath).filterNot { existingSdkPaths.contains(getPythonExecutable(it)) }.map { PyDetectedSdk(it) }
getPoetryEnvs(path).filterNot { existingSdkPaths.contains(getPythonExecutable(it)) }.map { PyDetectedSdk(it) }
} catch (e: Throwable) {
emptyList()
}
Expand Down