diff --git a/python/interpreters/src/impl/InterpreterServiceImpl.kt b/python/interpreters/src/impl/InterpreterServiceImpl.kt index 749f75be31d9..ba3e817be404 100644 --- a/python/interpreters/src/impl/InterpreterServiceImpl.kt +++ b/python/interpreters/src/impl/InterpreterServiceImpl.kt @@ -41,7 +41,7 @@ internal object InterpreterServiceImpl : InterpreterService { } override suspend fun getForModule(module: Module): Interpreter? { - val pythonSdk = ModuleRootManager.getInstance(module).sdk?.takeIf { isPythonSdk(it) } ?: return null + val pythonSdk = PythonSdkUtil.findPythonSdk(module)?.takeIf { isPythonSdk(it) } ?: return null val data = pythonSdk.getOrCreateAdditionalData() return findInterpreter(data, pythonSdk) diff --git a/python/openapi/src/com/jetbrains/python/module/PyModuleService.java b/python/openapi/src/com/jetbrains/python/module/PyModuleService.java index 84130e26bf3d..0759c3aab711 100644 --- a/python/openapi/src/com/jetbrains/python/module/PyModuleService.java +++ b/python/openapi/src/com/jetbrains/python/module/PyModuleService.java @@ -4,14 +4,18 @@ package com.jetbrains.python.module; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Consumer; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public abstract class PyModuleService { - public abstract @Nullable Sdk findPythonSdk(@NotNull Module module); + public @Nullable Sdk findPythonSdk(@NotNull Module module) { + return ModuleRootManager.getInstance(module).getSdk(); + } public void forAllFacets(@NotNull Module module, @NotNull Consumer facetConsumer) { } @@ -24,4 +28,6 @@ public abstract class PyModuleService { public boolean isFileIgnored(@NotNull VirtualFile file) { return false; } + @ApiStatus.Internal + public abstract boolean isPythonModule(@NotNull Module module); } diff --git a/python/pluginCore/impl/src/com/intellij/python/community/plugin/impl/run/PyPluginSdkFragment.kt b/python/pluginCore/impl/src/com/intellij/python/community/plugin/impl/run/PyPluginSdkFragment.kt index 992945aea10f..5eccf6dde9d9 100644 --- a/python/pluginCore/impl/src/com/intellij/python/community/plugin/impl/run/PyPluginSdkFragment.kt +++ b/python/pluginCore/impl/src/com/intellij/python/community/plugin/impl/run/PyPluginSdkFragment.kt @@ -155,7 +155,7 @@ class PyPluginSdkFragment> : SettingsEdito private fun getSelectedSdk(): Sdk? { if (currentMode == SDK_OF_MODULE) { ((modulesCombo?.selectedItem) as? Module)?.let { - return ModuleRootManager.getInstance(it).sdk + return PythonSdkUtil.findPythonSdk(it) } } else if (currentMode == SDK_FROM_LIST) { diff --git a/python/pluginMinor/src/com/intellij/python/community/plugin/minor/facet/PyPluginSdkModuleConfigurable.kt b/python/pluginMinor/src/com/intellij/python/community/plugin/minor/facet/PyPluginSdkModuleConfigurable.kt index 312cdb80bb99..c9058b74980d 100644 --- a/python/pluginMinor/src/com/intellij/python/community/plugin/minor/facet/PyPluginSdkModuleConfigurable.kt +++ b/python/pluginMinor/src/com/intellij/python/community/plugin/minor/facet/PyPluginSdkModuleConfigurable.kt @@ -10,6 +10,7 @@ import com.intellij.openapi.projectRoots.Sdk import com.intellij.python.community.plugin.impl.facet.PythonFacetUtil import com.jetbrains.python.configuration.PyActiveSdkConfigurable import com.jetbrains.python.configuration.PyActiveSdkModuleConfigurable +import com.jetbrains.python.module.PyModuleService import com.jetbrains.python.sdk.removeTransferredRoots import com.jetbrains.python.sdk.transferRoots import org.jetbrains.annotations.ApiStatus @@ -22,7 +23,7 @@ internal class PyPluginSdkModuleConfigurable(project: Project?) : PyActiveSdkMod } override fun getSdk(): Sdk? { - return getSdkFromFacet(module) + return PyModuleService.getInstance().findPythonSdk(module) } } } @@ -42,13 +43,6 @@ fun setSdkToFacet(item: Sdk?, module: Module) { } } -@ApiStatus.Internal -fun getSdkFromFacet(module: Module): Sdk? { - val facetManager = FacetManager.getInstance(module) - val facet = facetManager.getFacetByType(MinorPythonFacet.ID) - return facet?.configuration?.sdk -} - private fun setFacetSdk(facet: MinorPythonFacet, item: Sdk?, module: Module) { diff --git a/python/python-core-impl/src/com/jetbrains/python/extensions/ModuleExt.kt b/python/python-core-impl/src/com/jetbrains/python/extensions/ModuleExt.kt index 0a89ce5ff4c7..d5ed3e3a3b42 100644 --- a/python/python-core-impl/src/com/jetbrains/python/extensions/ModuleExt.kt +++ b/python/python-core-impl/src/com/jetbrains/python/extensions/ModuleExt.kt @@ -17,7 +17,7 @@ package com.jetbrains.python.extensions import com.intellij.openapi.module.Module import com.intellij.openapi.projectRoots.Sdk -import com.intellij.openapi.roots.ModuleRootManager +import com.jetbrains.python.sdk.legacy.PythonSdkUtil -fun Module.getSdk(): Sdk? = ModuleRootManager.getInstance(this).sdk +fun Module.getSdk(): Sdk? = PythonSdkUtil.findPythonSdk(this) diff --git a/python/python-pyproject/src/com/intellij/python/pyproject/model/internal/workspaceTools.kt b/python/python-pyproject/src/com/intellij/python/pyproject/model/internal/workspaceTools.kt index 587af5562748..facaa315f340 100644 --- a/python/python-pyproject/src/com/intellij/python/pyproject/model/internal/workspaceTools.kt +++ b/python/python-pyproject/src/com/intellij/python/pyproject/model/internal/workspaceTools.kt @@ -6,7 +6,6 @@ import com.intellij.openapi.externalSystem.autoimport.ExternalSystemRefreshStatu import com.intellij.openapi.project.Project import com.intellij.openapi.project.modules import com.intellij.openapi.projectRoots.ProjectJdkTable -import com.intellij.openapi.roots.ModuleRootManager import com.intellij.openapi.roots.ModuleRootModificationUtil import com.intellij.openapi.util.Key import com.intellij.openapi.util.NlsSafe @@ -27,6 +26,10 @@ import com.intellij.python.pyproject.model.spi.PyProjectTomlProject import com.intellij.python.pyproject.model.spi.Tool import com.intellij.python.pyproject.model.spi.WorkspaceName import com.intellij.util.messages.Topic +import com.intellij.workspaceModel.ide.impl.legacyBridge.module.findModule +import com.jetbrains.python.PyNames +import com.jetbrains.python.module.PyModuleService +import com.jetbrains.python.sdk.legacy.PythonSdkUtil import com.jetbrains.python.venvReader.Directory import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.sync.Mutex @@ -70,7 +73,7 @@ internal suspend fun linkProject(project: Project, projectModelRoot: Path) { val entries = generatePyProjectTomlEntries(files, excludeDirs) if (entries.isNotEmpty()) { - val sdks = project.modules.associate { Pair(it.name, ModuleRootManager.getInstance(it).sdk?.name) } + val sdks = project.modules.associate { Pair(it.name, PythonSdkUtil.findPythonSdk(it)?.name) } project.workspaceModel.currentSnapshot.entities(ModuleEntity::class.java) unlinkProjectImpl(project, externalProjectPath) @@ -90,7 +93,7 @@ internal suspend fun linkProject(project: Project, projectModelRoot: Path) { // Restore SDK assoc for (module in project.modules) { - if (ModuleRootManager.getInstance(module).sdk == null) { + if (PythonSdkUtil.findPythonSdk(module) == null) { val sdkName = sdks[module.name] ?: continue ProjectJdkTable.getInstance().findJdk(sdkName)?.let { sdk -> ModuleRootModificationUtil.setModuleSdk(module, sdk) @@ -177,17 +180,8 @@ private suspend fun createEntityStorage( val fileUrlManager = project.workspaceModel.getVirtualFileUrlManager() val storage = MutableEntityStorage.create() for (pyProject in graph) { - val existingModuleEntity = project.workspaceModel.currentSnapshot - .entitiesBySource { it is PyProjectTomlEntitySource } - .filterIsInstance() - .find { it.name == pyProject.name.name } - val existingSdkEntity = existingModuleEntity - ?.dependencies - ?.find { it is SdkDependency } as? SdkDependency - val sdkDependency = existingSdkEntity ?: InheritedSdkDependency val entitySource = PyProjectTomlEntitySource(pyProject.tomlFile.toVirtualFileUrl(virtualFileUrlManager)) val moduleEntity = storage addEntity ModuleEntity(pyProject.name.name, emptyList(), entitySource) { - dependencies += sdkDependency dependencies += ModuleSourceDependency for (moduleName in pyProject.dependencies) { dependencies += ModuleDependency(ModuleId(moduleName.name), true, DependencyScope.COMPILE, false) @@ -210,6 +204,7 @@ private suspend fun createEntityStorage( } } + type = PYTHON_MODULE_ID_DATA_CLASS pyProjectTomlEntity = PyProjectTomlWorkspaceEntity(participatedTools = participatedTools, pyProject.tomlFile.parent.toVirtualFileUrl(fileUrlManager), entitySource) exModuleOptions = ExternalSystemModuleOptionsEntity(entitySource) { externalSystem = PYTHON_SOURCE_ROOT_TYPE.name @@ -220,6 +215,7 @@ private suspend fun createEntityStorage( return@withContext storage } + private class PyProjectTomlEntitySource(tomlFile: VirtualFileUrl) : EntitySource { override val virtualFileUrl: VirtualFileUrl = tomlFile } @@ -247,9 +243,14 @@ private data class PyProjectTomlBasedEntryImpl( * @see com.intellij.openapi.project.impl.getOrInitializeModule */ private fun removeFakeModuleEntity(storage: MutableEntityStorage, modulesToRemove: Set) { + val moduleService = PyModuleService.getInstance() val contentRoots = storage .entitiesBySource { it !is PyProjectTomlEntitySource } .filterIsInstance() + .filter { + val module = it.module.findModule(storage) ?: return@filter false + moduleService.isPythonModule(module) + } .toList() for (entity in contentRoots) { if (entity.module.name in modulesToRemove) { @@ -285,4 +286,6 @@ private suspend fun findSrc(root: Directory): Set = withContext(Dispatchers.IO) { val src = root.resolve("src") if (src.exists()) setOf(src) else emptySet() - } \ No newline at end of file + } + +private val PYTHON_MODULE_ID_DATA_CLASS: ModuleTypeId = ModuleTypeId(PyNames.PYTHON_MODULE_ID) diff --git a/python/python-sdk-configurator/backend/src/impl/ModulesSdkConfigurator.kt b/python/python-sdk-configurator/backend/src/impl/ModulesSdkConfigurator.kt index 7a17f7af3e2e..ebe0613c3d9b 100644 --- a/python/python-sdk-configurator/backend/src/impl/ModulesSdkConfigurator.kt +++ b/python/python-sdk-configurator/backend/src/impl/ModulesSdkConfigurator.kt @@ -25,6 +25,7 @@ import com.jetbrains.python.sdk.configuration.CreateSdkInfo import com.jetbrains.python.sdk.configuration.CreateSdkInfoWithTool import com.jetbrains.python.sdk.configuration.PyProjectSdkConfigurationExtension import com.jetbrains.python.sdk.getOrCreateAdditionalData +import com.jetbrains.python.sdk.legacy.PythonSdkUtil import com.jetbrains.python.sdk.setAssociationToPath import com.jetbrains.python.venvReader.Directory import kotlinx.collections.immutable.toPersistentList @@ -108,7 +109,7 @@ internal class ModulesSdkConfigurator private constructor( val tools = PyProjectSdkConfigurationExtension.createMap() val limit = Semaphore(permits = Registry.intValue("intellij.python.sdkConfigurator.backend.sdk.parallel")) val now = System.currentTimeMillis() - val resultDef = project.modules.filter { ModuleRootManager.getInstance(it).sdk == null }.map { module -> + val resultDef = project.modules.filter { PythonSdkUtil.findPythonSdk(it) == null }.map { module -> limit.withPermit { async { val moduleInfo = getModuleInfo(module, tools) ?: return@async null @@ -190,7 +191,7 @@ internal class ModulesSdkConfigurator private constructor( } // Link workspace members with their workspace val reportedBrokenModules = mutableSetOf() for ((module, parentModule) in modulesWithSameSdk) { - val parentSdk = ModuleRootManager.getInstance(parentModule).sdk + val parentSdk = PythonSdkUtil.findPythonSdk(module) if (parentSdk != null) { ModuleRootModificationUtil.setModuleSdk(module, parentSdk) // This SDK is shared, no need to associate it // TODO: Support association with multiple modules diff --git a/python/python-sdk/src/com/jetbrains/python/sdk/legacy/PythonSdkUtil.java b/python/python-sdk/src/com/jetbrains/python/sdk/legacy/PythonSdkUtil.java index 4c309526844e..51493fcaffa2 100644 --- a/python/python-sdk/src/com/jetbrains/python/sdk/legacy/PythonSdkUtil.java +++ b/python/python-sdk/src/com/jetbrains/python/sdk/legacy/PythonSdkUtil.java @@ -97,13 +97,7 @@ public final class PythonSdkUtil { if (module == null || module.isDisposed()) { return null; } - - Sdk sdk = ModuleRootManager.getInstance(module).getSdk(); - if (sdk != null && isPythonSdk(sdk)) { - return sdk; - } - - sdk = PyModuleService.getInstance().findPythonSdk(module); + var sdk = PyModuleService.getInstance().findPythonSdk(module); if (sdk != null && isPythonSdk(sdk)) { return sdk; } diff --git a/python/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java b/python/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java index 2573468ff920..a938a09bc3a2 100644 --- a/python/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java +++ b/python/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java @@ -282,7 +282,7 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { sdk = ProjectRootManager.getInstance(myProject).getProjectSdk(); } else { - sdk = ModuleRootManager.getInstance(myModule).getSdk(); + sdk = com.jetbrains.python.sdk.PythonSdkUtil.findPythonSdk(myModule); } if (sdk != null && PythonSdkUtil.isPythonSdk(sdk)) { diff --git a/python/src/com/jetbrains/python/configuration/PyActiveSdkModuleConfigurable.java b/python/src/com/jetbrains/python/configuration/PyActiveSdkModuleConfigurable.java index 0f1b8aa5d0f3..80eb4c742951 100644 --- a/python/src/com/jetbrains/python/configuration/PyActiveSdkModuleConfigurable.java +++ b/python/src/com/jetbrains/python/configuration/PyActiveSdkModuleConfigurable.java @@ -6,20 +6,29 @@ import com.intellij.openapi.module.Module; import com.intellij.openapi.options.UnnamedConfigurable; import com.intellij.openapi.project.Project; import com.jetbrains.python.PyBundle; +import com.jetbrains.python.module.PyModuleService; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; // Inherit in the module you are going to use it @ApiStatus.Internal -public abstract class PyActiveSdkModuleConfigurable extends ModuleAwareProjectConfigurable { +public abstract class PyActiveSdkModuleConfigurable extends ModuleAwareProjectConfigurable { private final Project myProject; protected PyActiveSdkModuleConfigurable(Project project) { - super(project, PyBundle.message("configurable.PyActiveSdkModuleConfigurable.python.interpreter.display.name"), "reference.settings.project.interpreter"); + super(project, PyBundle.message("configurable.PyActiveSdkModuleConfigurable.python.interpreter.display.name"), + "reference.settings.project.interpreter"); myProject = project; } + @Override + protected final boolean isSuitableForModule(@NotNull Module module) { + // One can't configure Python SDK for a random module as random module doesn't have a `baseDir` + // which is a requirement for various SDK types. + return PyModuleService.getInstance().isPythonModule(module); + } + @Override protected @NotNull UnnamedConfigurable createModuleConfigurable(Module module) { return new PyActiveSdkConfigurable(module); diff --git a/python/src/com/jetbrains/python/module/PyModuleServiceEx.java b/python/src/com/jetbrains/python/module/PyModuleServiceEx.java deleted file mode 100644 index ddc8fb453223..000000000000 --- a/python/src/com/jetbrains/python/module/PyModuleServiceEx.java +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -package com.jetbrains.python.module; - -public abstract class PyModuleServiceEx extends PyModuleService { -} diff --git a/python/src/com/jetbrains/python/module/PyModuleServiceImpl.java b/python/src/com/jetbrains/python/module/PyModuleServiceImpl.java index 2788610778a4..862cb1172a14 100644 --- a/python/src/com/jetbrains/python/module/PyModuleServiceImpl.java +++ b/python/src/com/jetbrains/python/module/PyModuleServiceImpl.java @@ -6,14 +6,18 @@ import com.intellij.facet.FacetConfiguration; import com.intellij.facet.FacetManager; import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleType; import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Consumer; +import com.jetbrains.python.PyNames; +import com.jetbrains.python.PythonModuleTypeBase; import com.jetbrains.python.facet.PythonFacetSettings; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -final class PyModuleServiceImpl extends PyModuleServiceEx { +final class PyModuleServiceImpl extends PyModuleService { @Override public boolean isFileIgnored(@NotNull VirtualFile file) { @@ -22,13 +26,17 @@ final class PyModuleServiceImpl extends PyModuleServiceEx { @Override public @Nullable Sdk findPythonSdk(@NotNull Module module) { + var sdk = super.findPythonSdk(module); + if (sdk != null) { + return sdk; + } for (Facet facet : FacetManager.getInstance(module).getAllFacets()) { final FacetConfiguration configuration = facet.getConfiguration(); if (configuration instanceof PythonFacetSettings) { return ((PythonFacetSettings)configuration).getSdk(); } } - return null; + return ModuleRootManager.getInstance(module).getSdk(); } @Override @@ -37,4 +45,19 @@ final class PyModuleServiceImpl extends PyModuleServiceEx { facetConsumer.consume(f); } } + + @Override + public boolean isPythonModule(@NotNull Module module) { + ModuleType type = ModuleType.get(module); + if (type instanceof PythonModuleTypeBase || type.getId().equals(PyNames.PYTHON_MODULE_ID)) { + return true; + } + final Facet[] allFacets = FacetManager.getInstance(module).getAllFacets(); + for (Facet facet : allFacets) { + if (facet.getConfiguration() instanceof PythonFacetSettings) { + return true; + } + } + return false; + } } diff --git a/python/src/com/jetbrains/python/run/configuration/PySdkComboBox.kt b/python/src/com/jetbrains/python/run/configuration/PySdkComboBox.kt index af4067920163..8ee05b60ad6c 100644 --- a/python/src/com/jetbrains/python/run/configuration/PySdkComboBox.kt +++ b/python/src/com/jetbrains/python/run/configuration/PySdkComboBox.kt @@ -3,13 +3,13 @@ package com.jetbrains.python.run.configuration import com.intellij.openapi.module.Module import com.intellij.openapi.projectRoots.Sdk -import com.intellij.openapi.roots.ModuleRootManager import com.intellij.openapi.ui.ComboBox import com.intellij.openapi.util.Computable import com.jetbrains.python.PyBundle import com.jetbrains.python.run.AbstractPythonRunConfigurationParams import com.jetbrains.python.sdk.PySdkListCellRenderer import com.jetbrains.python.sdk.legacy.PythonSdkUtil +import com.jetbrains.python.sdk.pythonSdk import java.util.function.Consumer class PySdkComboBox(private val addDefault: Boolean, @@ -48,7 +48,7 @@ class PySdkComboBox(private val addDefault: Boolean, } private fun updateDefaultInterpreter(module: Module?) { - val sdk = if (module == null) null else ModuleRootManager.getInstance(module).sdk + val sdk = module?.pythonSdk setRenderer( if (sdk == null) PySdkListCellRenderer() else PySdkListCellRenderer(PyBundle.message("python.sdk.rendering.project.default.0", sdk.name), sdk) diff --git a/python/src/com/jetbrains/python/testing/PythonTestLegacyConfigurationProducer.java b/python/src/com/jetbrains/python/testing/PythonTestLegacyConfigurationProducer.java index bd50dbaf31d7..7420ecb48942 100644 --- a/python/src/com/jetbrains/python/testing/PythonTestLegacyConfigurationProducer.java +++ b/python/src/com/jetbrains/python/testing/PythonTestLegacyConfigurationProducer.java @@ -3,11 +3,8 @@ package com.jetbrains.python.testing; import com.intellij.execution.Location; import com.intellij.execution.actions.ConfigurationContext; -import com.intellij.facet.Facet; -import com.intellij.facet.FacetManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; -import com.intellij.openapi.module.ModuleType; import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ProjectRootManager; @@ -17,8 +14,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.ThreeState; -import com.jetbrains.python.PythonModuleTypeBase; -import com.jetbrains.python.facet.PythonFacetSettings; +import com.jetbrains.python.module.PyModuleService; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.types.TypeEvalContext; import com.jetbrains.python.run.RunnableScriptFilter; @@ -108,6 +104,7 @@ public abstract class PythonTestLegacyConfigurationProducer getTestCaseClassesFromFile(final @NotNull PyFile pyFile) { diff --git a/python/src/com/jetbrains/python/testing/doctest/PythonDocTestConfigurationProducer.java b/python/src/com/jetbrains/python/testing/doctest/PythonDocTestConfigurationProducer.java index 30fb19155ea1..44d6c1a0ae5e 100644 --- a/python/src/com/jetbrains/python/testing/doctest/PythonDocTestConfigurationProducer.java +++ b/python/src/com/jetbrains/python/testing/doctest/PythonDocTestConfigurationProducer.java @@ -53,6 +53,7 @@ public final class PythonDocTestConfigurationProducer extends PythonTestLegacyCo @Override protected boolean isAvailable(final @NotNull Location location) { final Module module = location.getModule(); + if (module == null) return false; if (!isPythonModule(module)) return false; final PsiElement element = location.getPsiElement(); if (element instanceof PsiFile) {