mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-20 13:31:28 +07:00
[python][sdk] fix lazy loading interpreter lists (PY-82913)
+ make all interpreter flow states nullable to distinguish the loading state from an empty value. + remove interpreterLoading flow/flag because it is non-consistent with other interpreter flow states. + remove PythonInterpreterComboBox dependency on the model Merge-request: IJ-MR-174441 Merged-by: Vitaly Legchilkin <Vitaly.Legchilkin@jetbrains.com> (cherry picked from commit 50832570f4618ba3af40c1216e37eb3431effd80) # Conflicts: # community/python/src/com/jetbrains/python/sdk/add/v2/models.kt # python/junit5Tests/tests/com/intellij/python/junit5Tests/env/tests/sdk/addSdk/PythonAddInterpreterModelTest.kt # python/junit5Tests/tests/com/intellij/python/junit5Tests/env/tests/sdk/addSdk/PythonLocalAddInterpreterModelTest.kt GitOrigin-RevId: 467815b09864a9e679f37ac4cea77dc1448c6fa1
This commit is contained in:
committed by
intellij-monorepo-bot
parent
1389b1dc24
commit
5e3a8e9bed
@@ -31,7 +31,7 @@ internal abstract class CustomExistingEnvironmentSelector(
|
||||
) : PythonExistingEnvironmentConfigurator(model) {
|
||||
|
||||
private lateinit var comboBox: PythonInterpreterComboBox
|
||||
private val existingEnvironments: MutableStateFlow<List<PythonSelectableInterpreter>> = MutableStateFlow(emptyList())
|
||||
private val existingEnvironments: MutableStateFlow<List<PythonSelectableInterpreter>?> = MutableStateFlow(null)
|
||||
protected val selectedEnv: ObservableMutableProperty<PythonSelectableInterpreter?> = propertyGraph.property(null)
|
||||
|
||||
override fun setupUI(panel: Panel, validationRequestor: DialogValidationRequestor) {
|
||||
@@ -47,7 +47,6 @@ internal abstract class CustomExistingEnvironmentSelector(
|
||||
comboBox = pythonInterpreterComboBox(
|
||||
title = message("sdk.create.custom.existing.env.title", nameTitle),
|
||||
selectedSdkProperty = selectedEnv,
|
||||
model = model,
|
||||
validationRequestor = validationRequestor,
|
||||
onPathSelected = { path -> addEnvByPath(path) }
|
||||
) {
|
||||
@@ -69,6 +68,7 @@ internal abstract class CustomExistingEnvironmentSelector(
|
||||
comboBox.initialize(
|
||||
scope = scope,
|
||||
flow = existingEnvironments.map { existing ->
|
||||
existing ?: return@map null
|
||||
val withUniquePath = existing.distinctBy { interpreter -> interpreter.homePath }
|
||||
sortForExistingEnvironment(withUniquePath, module)
|
||||
}
|
||||
@@ -89,7 +89,7 @@ internal abstract class CustomExistingEnvironmentSelector(
|
||||
|
||||
private fun addEnvByPath(python: VanillaPythonWithLanguageLevel): PythonSelectableInterpreter {
|
||||
val interpreter = ManuallyAddedSelectableInterpreter(python)
|
||||
existingEnvironments.value += interpreter
|
||||
existingEnvironments.value = (existingEnvironments.value ?: emptyList()) + interpreter
|
||||
return interpreter
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,6 @@ internal abstract class CustomNewEnvironmentCreator(
|
||||
basePythonComboBox = pythonInterpreterComboBox(
|
||||
title = message("sdk.create.custom.base.python"),
|
||||
selectedSdkProperty = model.state.baseInterpreter,
|
||||
model = model,
|
||||
validationRequestor = validationRequestor,
|
||||
onPathSelected = model::addInterpreter,
|
||||
)
|
||||
|
||||
@@ -74,7 +74,6 @@ class EnvironmentCreatorVenv(model: PythonMutableTargetAddInterpreterModel) : Py
|
||||
versionComboBox = pythonInterpreterComboBox(
|
||||
title = message("sdk.create.custom.base.python"),
|
||||
selectedSdkProperty = model.state.baseInterpreter,
|
||||
model = model,
|
||||
validationRequestor = validationRequestor,
|
||||
onPathSelected = model::addInterpreter,
|
||||
)
|
||||
|
||||
@@ -24,7 +24,6 @@ class PythonExistingEnvironmentSelector(model: PythonAddInterpreterModel, privat
|
||||
comboBox = pythonInterpreterComboBox(
|
||||
title = message("sdk.create.custom.python.path"),
|
||||
selectedSdkProperty = model.state.selectedInterpreter,
|
||||
model = model,
|
||||
validationRequestor = validationRequestor,
|
||||
onPathSelected = model::addInterpreter,
|
||||
)
|
||||
@@ -32,7 +31,7 @@ class PythonExistingEnvironmentSelector(model: PythonAddInterpreterModel, privat
|
||||
}
|
||||
|
||||
override fun onShown(scope: CoroutineScope) {
|
||||
val interpretersFlow = model.allInterpreters.map { sortForExistingEnvironment(it, module) }
|
||||
val interpretersFlow = model.allInterpreters.map { it?.let { sortForExistingEnvironment(it, module) } }
|
||||
comboBox.initialize(scope, interpretersFlow)
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@ import javax.swing.JLabel
|
||||
|
||||
internal class PythonSdkComboBoxWithBrowseButtonEditor(
|
||||
val comboBox: ComboBox<PythonSelectableInterpreter?>,
|
||||
val controller: PythonAddInterpreterModel,
|
||||
onPathSelected: (String) -> Unit,
|
||||
) : ComboBoxEditor {
|
||||
private val component = SimpleColoredComponent()
|
||||
@@ -104,7 +103,7 @@ internal class PythonSdkComboBoxWithBrowseButtonEditor(
|
||||
if (_item == anObject) return
|
||||
_item = anObject
|
||||
component.clear()
|
||||
component.customizeForPythonInterpreter(controller.interpreterLoading.value, anObject as? PythonSelectableInterpreter)
|
||||
component.customizeForPythonInterpreter(isBusy, anObject as? PythonSelectableInterpreter)
|
||||
}
|
||||
|
||||
fun setBusy(busy: Boolean) {
|
||||
@@ -114,7 +113,7 @@ internal class PythonSdkComboBoxWithBrowseButtonEditor(
|
||||
comboBox.isEnabled = !isBusy
|
||||
component.clear()
|
||||
(item as? PythonSelectableInterpreter).takeIf { !busy }.let {
|
||||
component.customizeForPythonInterpreter(controller.interpreterLoading.value, it)
|
||||
component.customizeForPythonInterpreter(busy, it)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -112,7 +112,6 @@ internal class PythonSdkPanelBuilderAndSdkCreator(
|
||||
pythonBaseVersionComboBox = pythonInterpreterComboBox(
|
||||
title = message("sdk.create.python.version"),
|
||||
selectedSdkProperty = model.state.baseInterpreter,
|
||||
model = model,
|
||||
validationRequestor = validationRequestor,
|
||||
onPathSelected = model::addInterpreter
|
||||
) {
|
||||
|
||||
@@ -195,10 +195,6 @@ internal data class HatchFormFields(
|
||||
val hatchError: ObservableMutableProperty<PyError?>,
|
||||
) {
|
||||
fun onShown(scope: CoroutineScope, model: PythonMutableTargetAddInterpreterModel, state: AddInterpreterState, isFilterOnlyExisting: Boolean) {
|
||||
basePythonComboBox?.let { comboBox ->
|
||||
model.interpreterLoading.onEach { comboBox.setBusy(it) }.launchIn(scope + Dispatchers.EDT)
|
||||
}
|
||||
|
||||
model.hatchEnvironmentsResult.onEach { environmentsResult ->
|
||||
hatchError.set((environmentsResult as? Result.Failure)?.error)
|
||||
|
||||
@@ -238,7 +234,6 @@ internal fun Panel.buildHatchFormFields(
|
||||
basePythonComboBox = pythonInterpreterComboBox(
|
||||
title = message("sdk.create.custom.base.python"),
|
||||
selectedSdkProperty = model.state.baseInterpreter,
|
||||
model = model,
|
||||
validationRequestor = validationRequestor,
|
||||
onPathSelected = model::addInterpreter,
|
||||
)
|
||||
|
||||
@@ -69,24 +69,25 @@ abstract class PythonAddInterpreterModel(
|
||||
open val state: AddInterpreterState = AddInterpreterState(propertyGraph)
|
||||
val targetEnvironmentConfiguration: TargetEnvironmentConfiguration? = null
|
||||
|
||||
internal val knownInterpreters: MutableStateFlow<List<PythonSelectableInterpreter>> = MutableStateFlow(emptyList())
|
||||
private val _detectedInterpreters: MutableStateFlow<List<PythonSelectableInterpreter>> = MutableStateFlow(emptyList())
|
||||
val detectedInterpreters: StateFlow<List<PythonSelectableInterpreter>> = _detectedInterpreters
|
||||
internal val knownInterpreters: MutableStateFlow<List<PythonSelectableInterpreter>?> = MutableStateFlow(null)
|
||||
private val _detectedInterpreters: MutableStateFlow<List<PythonSelectableInterpreter>?> = MutableStateFlow(null)
|
||||
val detectedInterpreters: StateFlow<List<PythonSelectableInterpreter>?> = _detectedInterpreters
|
||||
val manuallyAddedInterpreters: MutableStateFlow<List<PythonSelectableInterpreter>> = MutableStateFlow(emptyList())
|
||||
private var installable: List<PythonSelectableInterpreter> = emptyList()
|
||||
val condaEnvironments: MutableStateFlow<List<PyCondaEnv>> = MutableStateFlow(emptyList())
|
||||
val hatchEnvironmentsResult: MutableStateFlow<PyResult<List<HatchVirtualEnvironment>>?> = MutableStateFlow(null)
|
||||
|
||||
lateinit var allInterpreters: StateFlow<List<PythonSelectableInterpreter>>
|
||||
lateinit var baseInterpreters: StateFlow<List<PythonSelectableInterpreter>>
|
||||
lateinit var allInterpreters: StateFlow<List<PythonSelectableInterpreter>?>
|
||||
lateinit var baseInterpreters: StateFlow<List<PythonSelectableInterpreter>?>
|
||||
|
||||
val interpreterLoading: MutableStateFlow<Boolean> = MutableStateFlow(true)
|
||||
val condaEnvironmentsLoading: MutableStateFlow<Boolean> = MutableStateFlow(true)
|
||||
|
||||
@TestOnly
|
||||
@ApiStatus.Internal
|
||||
fun addDetected(detected: DetectedSelectableInterpreter) {
|
||||
_detectedInterpreters.value += detected
|
||||
_detectedInterpreters.value?.let { existing ->
|
||||
_detectedInterpreters.value = existing + detected
|
||||
}
|
||||
}
|
||||
|
||||
// If the project is provided, sdks associated with it will be kept in the list of interpreters. If not, then they will be filtered out.
|
||||
@@ -107,8 +108,6 @@ abstract class PythonAddInterpreterModel(
|
||||
val existingSelectableInterpreters = getExistingSelectableInterpreters()
|
||||
knownInterpreters.value = existingSelectableInterpreters
|
||||
_detectedInterpreters.value = getDetectedSelectableInterpreters(existingSelectableInterpreters)
|
||||
}.invokeOnCompletion {
|
||||
this.interpreterLoading.value = false
|
||||
}
|
||||
|
||||
this.allInterpreters = combine(
|
||||
@@ -116,16 +115,20 @@ abstract class PythonAddInterpreterModel(
|
||||
detectedInterpreters,
|
||||
manuallyAddedInterpreters,
|
||||
) { known, detected, added ->
|
||||
if (known == null || detected == null) return@combine null
|
||||
added + known + detected
|
||||
}.map { it.distinctBy { int -> int.homePath }.sorted() }.stateIn(scope, started = SharingStarted.Eagerly, initialValue = emptyList())
|
||||
}.map { all ->
|
||||
all?.distinctBy { int -> int.homePath }?.sorted()
|
||||
}.stateIn(scope, started = SharingStarted.Eagerly, initialValue = null)
|
||||
|
||||
this.baseInterpreters = allInterpreters.map { all ->
|
||||
all.filter { it.isBasePython() }
|
||||
all?.filter { it.isBasePython() }
|
||||
}.mapLatest { allExisting ->
|
||||
allExisting ?: return@mapLatest null
|
||||
val existingLanguageLevels = allExisting.map { it.languageLevel }.toSet()
|
||||
val nonExistingInstallable = installable.filter { it.languageLevel !in existingLanguageLevels }
|
||||
allExisting + nonExistingInstallable
|
||||
}.stateIn(scope, started = SharingStarted.Eagerly, initialValue = emptyList())
|
||||
}.stateIn(scope, started = SharingStarted.Eagerly, initialValue = null)
|
||||
|
||||
|
||||
scope.launch(CoroutineName("Detecting Conda Executable and environments") + Dispatchers.IO) {
|
||||
@@ -266,32 +269,9 @@ abstract class PythonAddInterpreterModel(
|
||||
@RequiresEdt
|
||||
internal fun addInstalledInterpreter(homePath: Path, languageLevel: LanguageLevel): DetectedSelectableInterpreter {
|
||||
val installedInterpreter = DetectedSelectableInterpreter(homePath.pathString, languageLevel, true)
|
||||
_detectedInterpreters.value += installedInterpreter
|
||||
_detectedInterpreters.value = (_detectedInterpreters.value ?: emptyList()) + installedInterpreter
|
||||
return installedInterpreter
|
||||
}
|
||||
|
||||
/**
|
||||
* Given [pathToPython] returns either cleaned path (if valid) or null and reports error to [errorSink]
|
||||
*/
|
||||
suspend fun getSystemPythonFromSelection(pathToPython: String, errorSink: ErrorSink): SystemPython? {
|
||||
val result = try {
|
||||
when (val r = systemPythonService.registerSystemPython(Path(pathToPython))) {
|
||||
is Result.Failure -> PyResult.failure(r.error)
|
||||
is Result.Success -> PyResult.success(r.result)
|
||||
}
|
||||
}
|
||||
catch (e: InvalidPathException) {
|
||||
PyResult.localizedError(e.localizedMessage)
|
||||
}
|
||||
|
||||
return when (result) {
|
||||
is Result.Success -> result.result
|
||||
is Result.Failure -> {
|
||||
errorSink.emit(result.error)
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract class PythonMutableTargetAddInterpreterModel(projectPathFlows: ProjectPathFlows) : PythonAddInterpreterModel(projectPathFlows) {
|
||||
@@ -361,8 +341,8 @@ class PythonLocalAddInterpreterModel(projectPathFlows: ProjectPathFlows) : Pytho
|
||||
super.initialize(scope)
|
||||
|
||||
val mostRecentlyUsedBasePath = PySdkSettings.instance.preferredVirtualEnvBaseSdk
|
||||
val interpreterToSelect = detectedInterpreters.value.find { it.homePath == mostRecentlyUsedBasePath }
|
||||
?: baseInterpreters.value.filterIsInstance<ExistingSelectableInterpreter>().maxByOrNull { it.languageLevel }
|
||||
val interpreterToSelect = detectedInterpreters.value?.find { it.homePath == mostRecentlyUsedBasePath }
|
||||
?: baseInterpreters.value?.filterIsInstance<ExistingSelectableInterpreter>()?.maxByOrNull { it.languageLevel }
|
||||
|
||||
if (interpreterToSelect != null) {
|
||||
state.baseInterpreter.set(interpreterToSelect)
|
||||
@@ -481,10 +461,10 @@ class MutableTargetState(propertyGraph: PropertyGraph) : AddInterpreterState(pro
|
||||
|
||||
|
||||
internal val PythonAddInterpreterModel.existingSdks
|
||||
get() = allInterpreters.value.filterIsInstance<ExistingSelectableInterpreter>().map { it.sdk }
|
||||
get() = allInterpreters.value?.filterIsInstance<ExistingSelectableInterpreter>()?.map { it.sdk } ?: emptyList()
|
||||
|
||||
internal fun PythonAddInterpreterModel.findInterpreter(path: String): PythonSelectableInterpreter? {
|
||||
return allInterpreters.value.find { it.homePath == path }
|
||||
return allInterpreters.value?.find { it.homePath == path }
|
||||
}
|
||||
|
||||
internal suspend fun PythonAddInterpreterModel.detectCondaEnvironmentsOrError(errorSink: ErrorSink) {
|
||||
@@ -508,3 +488,27 @@ internal suspend fun PythonAddInterpreterModel.getBasePath(module: Module?): Pat
|
||||
?: module?.basePath?.let { Path.of(it) }
|
||||
?: projectPathFlows.projectPathWithDefault.first()
|
||||
}
|
||||
|
||||
/**
|
||||
* Given [pathToPython] returns either cleaned path (if valid) or null and reports error to [errorSink]
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
suspend fun getSystemPythonFromSelection(pathToPython: String, errorSink: ErrorSink): SystemPython? {
|
||||
val result = try {
|
||||
when (val r = SystemPythonService().registerSystemPython(Path(pathToPython))) {
|
||||
is Result.Failure -> PyResult.failure(r.error)
|
||||
is Result.Success -> PyResult.success(r.result)
|
||||
}
|
||||
}
|
||||
catch (e: InvalidPathException) {
|
||||
PyResult.localizedError(e.localizedMessage)
|
||||
}
|
||||
|
||||
return when (result) {
|
||||
is Result.Success -> result.result
|
||||
is Result.Failure -> {
|
||||
errorSink.emit(result.error)
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,6 @@ import com.jetbrains.python.newProjectWizard.collector.PythonNewProjectWizardCol
|
||||
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
|
||||
import com.jetbrains.python.sdk.add.v2.PythonSelectableInterpreter
|
||||
import com.jetbrains.python.sdk.add.v2.PythonSupportedEnvironmentManagers.POETRY
|
||||
import com.jetbrains.python.sdk.add.v2.PythonSupportedEnvironmentManagers.PYTHON
|
||||
import com.jetbrains.python.sdk.add.v2.VenvExistenceValidationState.Error
|
||||
@@ -34,7 +33,6 @@ import com.jetbrains.python.statistics.InterpreterType
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
@@ -71,13 +69,9 @@ internal class EnvironmentCreatorPoetry(
|
||||
scope.launch(Dispatchers.IO) {
|
||||
val moduleDir = model.getBasePath(module).let { VirtualFileManager.getInstance().findFileByNioPath(it) }
|
||||
|
||||
val validatedInterpreters = if (moduleDir != null) {
|
||||
val validatedInterpreters = moduleDir?.let {
|
||||
PoetryPyProjectTomlPythonVersionsService.instance.validateInterpretersVersions(moduleDir, model.baseInterpreters)
|
||||
as? StateFlow<List<PythonSelectableInterpreter>> ?: model.baseInterpreters
|
||||
}
|
||||
else {
|
||||
model.baseInterpreters
|
||||
}
|
||||
} ?: model.baseInterpreters
|
||||
|
||||
withContext(Dispatchers.EDT) {
|
||||
basePythonComboBox.initialize(scope, validatedInterpreters)
|
||||
|
||||
@@ -208,14 +208,14 @@ fun replaceHomePathToTilde(sdkHomePath: @NonNls String): @NlsSafe String {
|
||||
}
|
||||
|
||||
|
||||
class PythonSdkComboBoxListCellRenderer(val loadingFlow: StateFlow<Boolean>) : ColoredListCellRenderer<PythonSelectableInterpreter?>() {
|
||||
class PythonSdkComboBoxListCellRenderer(val isLoading: () -> Boolean) : ColoredListCellRenderer<PythonSelectableInterpreter?>() {
|
||||
|
||||
override fun getListCellRendererComponent(list: JList<out PythonSelectableInterpreter?>?, value: PythonSelectableInterpreter?, index: Int, selected: Boolean, hasFocus: Boolean): Component {
|
||||
return super.getListCellRendererComponent(list, value, index, selected, hasFocus)
|
||||
}
|
||||
|
||||
override fun customizeCellRenderer(list: JList<out PythonSelectableInterpreter?>, value: PythonSelectableInterpreter?, index: Int, selected: Boolean, hasFocus: Boolean) {
|
||||
customizeForPythonInterpreter(loadingFlow.value, value)
|
||||
customizeForPythonInterpreter(isLoading.invoke(), value)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,12 +250,11 @@ class PythonEnvironmentComboBoxRenderer : ColoredListCellRenderer<Any>() {
|
||||
internal fun Panel.pythonInterpreterComboBox(
|
||||
title: @Nls String,
|
||||
selectedSdkProperty: ObservableMutableProperty<PythonSelectableInterpreter?>, // todo not sdk
|
||||
model: PythonAddInterpreterModel,
|
||||
validationRequestor: DialogValidationRequestor,
|
||||
onPathSelected: (VanillaPythonWithLanguageLevel) -> PythonSelectableInterpreter,
|
||||
customizer: RowsRange.() -> Unit = {},
|
||||
): PythonInterpreterComboBox {
|
||||
val comboBox = PythonInterpreterComboBox(model, onPathSelected, ShowingMessageErrorSync)
|
||||
val comboBox = PythonInterpreterComboBox(onPathSelected, ShowingMessageErrorSync)
|
||||
.apply {
|
||||
setBusy(true)
|
||||
}
|
||||
@@ -291,16 +290,15 @@ internal fun Panel.pythonInterpreterComboBox(
|
||||
}
|
||||
|
||||
internal class PythonInterpreterComboBox(
|
||||
val controller: PythonAddInterpreterModel,
|
||||
val onPathSelected: (VanillaPythonWithLanguageLevel) -> PythonSelectableInterpreter,
|
||||
private val errorSink: ErrorSink,
|
||||
) : ComboBox<PythonSelectableInterpreter?>() {
|
||||
|
||||
init {
|
||||
renderer = PythonSdkComboBoxListCellRenderer(controller.interpreterLoading)
|
||||
renderer = PythonSdkComboBoxListCellRenderer { isBusy }
|
||||
val newOnPathSelected: (String) -> Unit = {
|
||||
runWithModalProgressBlocking(ModalTaskOwner.guess(), message("python.sdk.validating.environment")) {
|
||||
controller.getSystemPythonFromSelection(it, errorSink)?.let { python ->
|
||||
getSystemPythonFromSelection(it, errorSink)?.let { python ->
|
||||
onPathSelected(python).also { interpreter ->
|
||||
require(isEditable) {
|
||||
"works only with editable combobox because it doesn't reject non-listed items (the list will be updated later via coroutine)"
|
||||
@@ -310,20 +308,22 @@ internal class PythonInterpreterComboBox(
|
||||
}
|
||||
}
|
||||
}
|
||||
editor = PythonSdkComboBoxWithBrowseButtonEditor(this, controller, newOnPathSelected)
|
||||
editor = PythonSdkComboBoxWithBrowseButtonEditor(this, newOnPathSelected)
|
||||
}
|
||||
|
||||
fun initialize(scope: CoroutineScope, flow: Flow<List<PythonSelectableInterpreter>>) {
|
||||
controller.interpreterLoading.onEach {
|
||||
setBusy(it)
|
||||
}.launchIn(scope + Dispatchers.EDT)
|
||||
|
||||
|
||||
fun initialize(scope: CoroutineScope, flow: Flow<List<PythonSelectableInterpreter>?>) {
|
||||
flow.onEach { interpreters ->
|
||||
if (interpreters == null) {
|
||||
setBusy(true)
|
||||
return@onEach
|
||||
}
|
||||
|
||||
val selectedItemReminder = selectedItem
|
||||
removeAllItems()
|
||||
interpreters.forEach(this::addItem)
|
||||
selectedItemReminder?.let { selectedItem = it }
|
||||
|
||||
setBusy(false)
|
||||
}.launchIn(scope + Dispatchers.EDT)
|
||||
}
|
||||
|
||||
|
||||
@@ -156,9 +156,9 @@ class PoetryPyProjectTomlPythonVersionsService : Disposable {
|
||||
fun validateSdkVersions(moduleFile: VirtualFile, sdks: List<Sdk>): List<Sdk> =
|
||||
sdks.filter { getVersion(moduleFile).isValid(it.versionString) }
|
||||
|
||||
fun validateInterpretersVersions(moduleFile: VirtualFile, interpreters: Flow<List<PythonSelectableInterpreter>>): Flow<List<PythonSelectableInterpreter>> {
|
||||
fun validateInterpretersVersions(moduleFile: VirtualFile, interpreters: Flow<List<PythonSelectableInterpreter>?>): Flow<List<PythonSelectableInterpreter>?> {
|
||||
val version = getVersion(moduleFile)
|
||||
return interpreters.map { list -> list.filter { version.isValid(it.languageLevel) } }
|
||||
return interpreters.map { list -> list?.filter { version.isValid(it.languageLevel) } }
|
||||
}
|
||||
|
||||
private fun getVersion(moduleFile: VirtualFile): PoetryPythonVersion =
|
||||
|
||||
Reference in New Issue
Block a user