cleanup [python]: Stop using deprecated API basePath and rootManager

GitOrigin-RevId: 1687601dcc175ccf34e71de2bb0585ebc0fa2740
This commit is contained in:
Ilya.Kazakevich
2026-01-28 20:02:37 +01:00
committed by intellij-monorepo-bot
parent 98320dd3d0
commit da3979b491
29 changed files with 151 additions and 121 deletions

View File

@@ -33,7 +33,7 @@ import com.jetbrains.python.pathValidation.ValidationRequest
import com.jetbrains.python.pathValidation.validateExecutableFile
import com.jetbrains.python.run.PythonInterpreterTargetEnvironmentFactory
import com.jetbrains.python.sdk.PythonSdkUpdater
import com.jetbrains.python.sdk.basePath
import com.jetbrains.python.sdk.baseDir
import com.jetbrains.python.sdk.conda.PyCondaSdkCustomizer
import com.jetbrains.python.sdk.conda.createCondaSdkAlongWithNewEnv
import com.jetbrains.python.sdk.conda.createCondaSdkFromExistingEnv
@@ -63,9 +63,10 @@ internal class PyEnvironmentYmlSdkConfiguration : PyProjectSdkConfigurationExten
override val toolId: ToolId = CONDA_TOOL_ID
override suspend fun checkEnvironmentAndPrepareSdkCreator(module: Module, venvsInModule: List<PythonBinary>): CreateSdkInfo? = prepareSdkCreator(
{ checkManageableEnv(module, it) }
) { envExists -> { createAndAddSdk(module, envExists) } }
override suspend fun checkEnvironmentAndPrepareSdkCreator(module: Module, venvsInModule: List<PythonBinary>): CreateSdkInfo? =
prepareSdkCreator(
{ checkManageableEnv(module, it) }
) { envExists -> { createAndAddSdk(module, envExists) } }
override fun asPyProjectTomlSdkConfigurationExtension(): PyProjectTomlConfigurationExtension? = null
@@ -127,7 +128,7 @@ internal class PyEnvironmentYmlSdkConfiguration : PyProjectSdkConfigurationExten
}.getOr { return it }
val shared = PyCondaSdkCustomizer.instance.sharedEnvironmentsByDefault
val basePath = module.basePath
val basePath = module.baseDir?.path
withContext(Dispatchers.EDT) {
this@PyEnvironmentYmlSdkConfiguration.thisLogger()
@@ -165,7 +166,7 @@ internal class PyEnvironmentYmlSdkConfiguration : PyProjectSdkConfigurationExten
is PyCondaEnvIdentity.NamedEnv -> envIdentity.envName == envName
is PyCondaEnvIdentity.UnnamedEnv -> if (shouldGuessEnvPrefix) {
val envPath = Path.of(envIdentity.envPath)
val sameModule = module.basePath?.toNioPathOrNull() == envPath.parent
val sameModule = module.baseDir?.path?.toNioPathOrNull() == envPath.parent
!envIdentity.isBase && sameModule && module.findAmongRoots(FileName(Path.of(envIdentity.envPath).name)) != null
}
else envIdentity.envPath == envPrefix

View File

@@ -20,7 +20,7 @@ import com.jetbrains.python.PyBundle
import com.jetbrains.python.PythonBinary
import com.jetbrains.python.errorProcessing.PyResult
import com.jetbrains.python.sdk.PythonSdkType
import com.jetbrains.python.sdk.basePath
import com.jetbrains.python.sdk.baseDir
import com.jetbrains.python.sdk.configuration.*
import com.jetbrains.python.sdk.findAmongRoots
import com.jetbrains.python.sdk.impl.PySdkBundle
@@ -42,9 +42,10 @@ internal class PyPipfileSdkConfiguration : PyProjectSdkConfigurationExtension {
override val toolId: ToolId = PIPENV_TOOL_ID
override suspend fun checkEnvironmentAndPrepareSdkCreator(module: Module, venvsInModule: List<PythonBinary>): CreateSdkInfo? = prepareSdkCreator(
{ checkManageableEnv(module, it) }
) { { createAndAddSdk(module) } }
override suspend fun checkEnvironmentAndPrepareSdkCreator(module: Module, venvsInModule: List<PythonBinary>): CreateSdkInfo? =
prepareSdkCreator(
{ checkManageableEnv(module, it) }
) { { createAndAddSdk(module) } }
override fun asPyProjectTomlSdkConfigurationExtension(): PyProjectTomlConfigurationExtension? = null
@@ -61,7 +62,7 @@ internal class PyPipfileSdkConfiguration : PyProjectSdkConfigurationExtension {
canManage && checkExistence -> {
PropertiesComponent.getInstance().pipenvPath = pipEnvExecutable.pathString
val envPath = runPipEnv(
module.basePath?.toNioPathOrNull(),
module.baseDir?.path?.toNioPathOrNull(),
"--venv",
transformer = ZeroCodeStdoutParserTransformer { PyResult.success(Path.of(it)) }
).successOrNull
@@ -82,9 +83,9 @@ internal class PyPipfileSdkConfiguration : PyProjectSdkConfigurationExtension {
private suspend fun createAndAddSdk(module: Module): PyResult<Sdk> {
LOGGER.debug("Creating pipenv environment")
return withBackgroundProgress(module.project, PyBundle.message("python.sdk.using.pipenv.sentence")) {
val basePath = module.basePath
val basePath = module.baseDir?.path
?: return@withBackgroundProgress PyResult.localizedError(PyBundle.message("python.sdk.provided.path.is.invalid",
module.basePath))
module.baseDir?.path))
val pipEnv = setupPipEnv(Path.of(basePath), null, true).getOr {
PySdkConfigurationCollector.logPipEnv(module.project, PipEnvResult.CREATION_FAILURE)
return@withBackgroundProgress it

View File

@@ -21,7 +21,7 @@ import com.jetbrains.python.errorProcessing.PyResult
import com.jetbrains.python.poetry.findPoetryLock
import com.jetbrains.python.poetry.getPyProjectTomlForPoetry
import com.jetbrains.python.sdk.PythonSdkType
import com.jetbrains.python.sdk.basePath
import com.jetbrains.python.sdk.baseDir
import com.jetbrains.python.sdk.configuration.*
import com.jetbrains.python.sdk.impl.PySdkBundle
import com.jetbrains.python.sdk.impl.resolvePythonBinary
@@ -47,9 +47,10 @@ internal class PyPoetrySdkConfiguration : PyProjectTomlConfigurationExtension {
{ checkExistence -> checkManageableEnv(module, checkExistence, true) },
) { { createPoetry(module) } }
override suspend fun createSdkWithoutPyProjectTomlChecks(module: Module, venvsInModule: List<PythonBinary>): CreateSdkInfo? = prepareSdkCreator(
{ checkExistence -> checkManageableEnv(module, checkExistence, false) },
) { { createPoetry(module) } }
override suspend fun createSdkWithoutPyProjectTomlChecks(module: Module, venvsInModule: List<PythonBinary>): CreateSdkInfo? =
prepareSdkCreator(
{ checkExistence -> checkManageableEnv(module, checkExistence, false) },
) { { createPoetry(module) } }
override fun asPyProjectTomlSdkConfigurationExtension(): PyProjectTomlConfigurationExtension = this
@@ -71,7 +72,7 @@ internal class PyPoetrySdkConfiguration : PyProjectTomlConfigurationExtension {
when {
canManage && checkExistence -> {
val basePath = module.basePath?.toNioPathOrNull()
val basePath = module.baseDir?.path?.toNioPathOrNull()
runPoetry(basePath, "check", "--lock").getOr { return@reportRawProgress envNotFound }
val envPath = runPoetry(basePath, "env", "info", "-p")
.mapSuccess { it.toNioPathOrNull() }
@@ -87,9 +88,9 @@ internal class PyPoetrySdkConfiguration : PyProjectTomlConfigurationExtension {
withBackgroundProgress(module.project, PyCharmCommunityCustomizationBundle.message("sdk.progress.text.setting.up.poetry.environment")) {
LOGGER.debug("Creating poetry environment")
val basePath = module.basePath?.let { Path.of(it) }
val basePath = module.baseDir?.path?.let { Path.of(it) }
if (basePath == null) {
return@withBackgroundProgress PyResult.localizedError(PyBundle.message("python.sdk.provided.path.is.invalid", module.basePath))
return@withBackgroundProgress PyResult.localizedError(PyBundle.message("python.sdk.provided.path.is.invalid", module.baseDir?.path))
}
val tomlFile = PyProjectToml.findFile(module)
val poetry = setupPoetry(basePath, null, true, tomlFile == null).getOr { return@withBackgroundProgress it }
@@ -104,7 +105,7 @@ internal class PyPoetrySdkConfiguration : PyProjectTomlConfigurationExtension {
PythonSdkUtil.getAllSdks().toTypedArray(),
file,
PythonSdkType.getInstance(),
PyPoetrySdkAdditionalData(module.basePath?.let { Path.of(it) }),
PyPoetrySdkAdditionalData(module.baseDir?.path?.let { Path.of(it) }),
suggestedSdkName(basePath)
)

View File

@@ -14,7 +14,7 @@ import com.intellij.python.pyproject.model.api.suggestSdk
import com.jetbrains.python.PythonBinary
import com.jetbrains.python.errorProcessing.PyResult
import com.jetbrains.python.onSuccess
import com.jetbrains.python.sdk.basePath
import com.jetbrains.python.sdk.baseDir
import com.jetbrains.python.sdk.configuration.*
import com.jetbrains.python.sdk.persist
import com.jetbrains.python.sdk.pyvenvContains
@@ -81,7 +81,7 @@ internal class PyUvSdkConfiguration : PyProjectTomlConfigurationExtension {
private suspend fun createUv(module: Module, venvsInModule: List<PythonBinary>, envExists: Boolean): PyResult<Sdk> {
val sdkAssociatedModule = module.getSdkAssociatedModule()
val workingDir: Path? = tryResolvePath(sdkAssociatedModule.basePath)
val workingDir: Path? = tryResolvePath(sdkAssociatedModule.baseDir?.path)
if (workingDir == null) {
throw IllegalStateException("Can't determine working dir for the module")
}

View File

@@ -28,9 +28,10 @@ import kotlin.io.path.name
internal class PyVenvSdkConfiguration : PyProjectSdkConfigurationExtension {
override val toolId: ToolId = VENV_TOOL_ID
override suspend fun checkEnvironmentAndPrepareSdkCreator(module: Module, venvsInModule: List<PythonBinary>): CreateSdkInfo? = prepareSdkCreator(
{ checkManageableEnv(module, venvsInModule) }
) { envExists -> { setupVenv(module, venvsInModule, envExists) } }
override suspend fun checkEnvironmentAndPrepareSdkCreator(module: Module, venvsInModule: List<PythonBinary>): CreateSdkInfo? =
prepareSdkCreator(
{ checkManageableEnv(module, venvsInModule) }
) { envExists -> { setupVenv(module, venvsInModule, envExists) } }
override fun asPyProjectTomlSdkConfigurationExtension(): PyProjectTomlConfigurationExtension? = null
@@ -65,7 +66,7 @@ internal class PyVenvSdkConfiguration : PyProjectSdkConfigurationExtension {
val pyDetectedSdk = PyDetectedSdk(pythonBinary.toString())
val sdk = pyDetectedSdk.setupAssociated(
PythonSdkUtil.getAllSdks(),
module.basePath,
module.baseDir?.path,
true,
PyFlavorAndData(PyFlavorData.Empty, VirtualEnvSdkFlavor.getInstance())
).getOr { return it }

View File

@@ -13,7 +13,7 @@ import com.jetbrains.python.PythonInfo
import com.jetbrains.python.Result
import com.jetbrains.python.errorProcessing.MessageError
import com.jetbrains.python.errorProcessing.PyResult
import com.jetbrains.python.sdk.basePath
import com.jetbrains.python.sdk.baseDir
import java.nio.file.Path
const val HATCH_TOML: String = "hatch.toml"
@@ -93,7 +93,10 @@ interface HatchService {
* param[basePythonBinaryPath] base python for environment, the one on the PATH should be used if null.
* param[envName] environment name to create, 'default' should be used if null.
*/
suspend fun createVirtualEnvironment(basePythonBinaryPath: PythonBinary? = null, envName: String? = null): PyResult<PythonVirtualEnvironment.Existing>
suspend fun createVirtualEnvironment(
basePythonBinaryPath: PythonBinary? = null,
envName: String? = null,
): PyResult<PythonVirtualEnvironment.Existing>
suspend fun findVirtualEnvironments(): PyResult<List<HatchVirtualEnvironment>>
@@ -108,7 +111,9 @@ interface HatchService {
* Hatch Service for working directory (where hatch.toml / pyproject.toml is usually placed)
*/
suspend fun Path?.getHatchService(hatchExecutablePath: Path? = null, hatchEnvironmentName: String? = null): PyResult<HatchService> {
return CliBasedHatchService(hatchExecutablePath = hatchExecutablePath, workingDirectoryPath = this, hatchEnvironmentName = hatchEnvironmentName)
return CliBasedHatchService(hatchExecutablePath = hatchExecutablePath,
workingDirectoryPath = this,
hatchEnvironmentName = hatchEnvironmentName)
}
/**
@@ -126,7 +131,7 @@ suspend fun Module.getHatchService(hatchExecutablePath: Path? = null): PyResult<
fun PythonHomePath.getHatchEnvVirtualProjectPath(): Path = this.parent.parent
fun resolveHatchWorkingDirectory(project: Project, module: Module?): PyResult<Path> {
val pathString = module?.basePath ?: project.basePath
val pathString = module?.baseDir?.path ?: project.basePath
return when (val path = pathString?.let { Path.of(it) }) {
null -> Result.failure(WorkingDirectoryNotFoundHatchError(pathString))

View File

@@ -6,12 +6,12 @@ import com.intellij.openapi.module.Module
import com.intellij.openapi.util.io.NioFiles
import com.intellij.util.system.OS
import com.jetbrains.python.sdk.PySdkUtil
import com.jetbrains.python.sdk.basePath
import com.jetbrains.python.sdk.baseDir
import java.nio.file.Path
fun Module?.executeInModuleDir(executable: String, vararg arguments: String): ProcessOutput {
val pyProjectPath = this?.basePath
val pyProjectPath = this?.baseDir?.path
val commandLine = GeneralCommandLine(executable, *arguments)
return PySdkUtil.getProcessOutput(commandLine, pyProjectPath, emptyMap(), 5_000)
}

View File

@@ -12,19 +12,18 @@ import com.intellij.python.sdk.ui.evolution.ui.components.EvoTreeLeafElement
import com.intellij.python.sdk.ui.evolution.ui.components.EvoTreeSection
import com.intellij.python.sdk.ui.icons.PythonSdkUIIcons
import com.jetbrains.python.Result
import com.jetbrains.python.sdk.basePath
import com.jetbrains.python.sdk.baseDir
import com.jetbrains.python.venvReader.VirtualEnvReader
import java.nio.file.Path
import kotlin.collections.plus
internal class VenvSelectSdkProvider() : EvoSelectSdkProvider {
internal class VenvSelectSdkProvider : EvoSelectSdkProvider {
override fun getTreeElement(evoModuleSdk: EvoModuleSdk) = EvoTreeLazyNodeElement("pip", PythonSdkUIIcons.Tools.Pip) {
val environments = VenvEvoSdkManager.findEnvironments(evoModuleSdk.module).getOr {
return@EvoTreeLazyNodeElement it
}
val envByFolders = environments.groupBy { it.pythonBinaryPath?.parent?.parent?.parent }.toMutableMap()
envByFolders.putIfAbsent(
evoModuleSdk.module.basePath?.let { Path.of(it) },
evoModuleSdk.module.baseDir?.path?.let { Path.of(it) },
listOf(EvoSdk(icon = PythonSdkUIIcons.Tools.Pip, name = VirtualEnvReader.DEFAULT_VIRTUALENV_DIRNAME, pythonBinaryPath = null))
)

View File

@@ -14,7 +14,7 @@ import java.nio.file.Path
@get:Deprecated("Use root manager directly and obey its contract",
replaceWith = ReplaceWith(" ModuleRootManager.getInstance(this)"),
level = DeprecationLevel.WARNING)
level = DeprecationLevel.ERROR)
val Module.rootManager: ModuleRootManager
get() = ModuleRootManager.getInstance(this)
@@ -33,7 +33,7 @@ val Module.baseDir: VirtualFile?
}
@get:Deprecated("Representing path as string is discouraged", replaceWith = ReplaceWith("baseBase?.path"), level = DeprecationLevel.WARNING)
@get:Deprecated("Representing path as string is discouraged", replaceWith = ReplaceWith("baseBase?.path"), level = DeprecationLevel.ERROR)
val Module.basePath: String?
get() = baseDir?.path

View File

@@ -200,7 +200,7 @@ object SdksKeeper {
fun Sdk.setAssociationToModuleAsync(module: Module) {
requirePythonSdk()
val path = module.basePath
val path = module.baseDir?.path
assert(path != null) { "Module $module has not paths, and can't be associated" }
val data = getOrCreateAdditionalData()
@@ -222,7 +222,7 @@ fun Sdk.setAssociationToModuleAsync(module: Module) {
suspend fun Sdk.setAssociationToModule(module: Module) {
requirePythonSdk()
val path = module.basePath
val path = module.baseDir?.path
assert(path != null) { "Module $module has not paths, and can't be associated" }
setAssociationToPath(path)
}

View File

@@ -6,13 +6,13 @@ import com.intellij.openapi.project.Project
import com.intellij.openapi.projectRoots.SdkModificator
import com.intellij.util.concurrency.ThreadingAssertions
import com.jetbrains.python.sdk.PythonSdkAdditionalData
import com.jetbrains.python.sdk.basePath
import com.jetbrains.python.sdk.baseDir
import com.jetbrains.python.sdk.flavors.PythonSdkFlavor
import org.jetbrains.annotations.ApiStatus
@ApiStatus.Internal
fun SdkModificator.associateWithModule(module: Module) {
val basePath = module.basePath ?: throw IllegalArgumentException("Module $module has no roots and can't be associated")
val basePath = module.baseDir?.path ?: throw IllegalArgumentException("Module $module has no roots and can't be associated")
getOrCreateSdkAdditionalData().associatedModulePath = basePath
}

View File

@@ -16,6 +16,7 @@ import com.intellij.openapi.module.ModuleManager
import com.intellij.openapi.module.ModuleUtilCore
import com.intellij.openapi.project.Project
import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.roots.ModuleRootManager
import com.intellij.openapi.util.Pair
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiElement
@@ -274,7 +275,7 @@ fun getModuleToStartConsole(project: Project, moduleManager: ModuleManager): Mod
}
val projectLocalModule = moduleManager.modules.firstOrNull {
val roots = it.rootManager.contentRoots
val roots = ModuleRootManager.getInstance(it).contentRoots
roots.all { it.isInLocalFileSystem }
}
if (projectLocalModule != null) {

View File

@@ -9,6 +9,7 @@ import com.intellij.openapi.module.Module
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.modules
import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.roots.ModuleRootManager
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.openapi.vfs.findOrCreateFile
@@ -102,7 +103,7 @@ object PythonRequirementTxtSdkUtils {
*/
@JvmStatic
fun detectRequirementsTxtInModule(module: Module): VirtualFile? {
val requirementsPath = module.rootManager.contentRoots.firstNotNullOfOrNull {
val requirementsPath = ModuleRootManager.getInstance(module).contentRoots.firstNotNullOfOrNull {
it.findChild(PythonSdkAdditionalData.REQUIREMENT_TXT_DEFAULT)
}

View File

@@ -4,6 +4,7 @@ package com.jetbrains.python.packaging.setupPy
import com.intellij.openapi.application.runReadAction
import com.intellij.openapi.command.WriteCommandAction
import com.intellij.openapi.module.Module
import com.intellij.openapi.roots.ModuleRootManager
import com.intellij.openapi.util.Ref
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiManager
@@ -28,7 +29,7 @@ internal object SetupPyHelpers {
@JvmStatic
fun detectSetupPyInModule(module: Module): PyFile? {
val file = module.rootManager.contentRoots.firstNotNullOfOrNull {
val file = ModuleRootManager.getInstance(module).contentRoots.firstNotNullOfOrNull {
it.findChild(SETUP_PY)
} ?: return null

View File

@@ -85,7 +85,7 @@ suspend fun createVenvAndSdk(
}
logger.info("using venv python $venvPython")
val sdkBasePath = moduleOrProject.moduleIfExists?.basePath ?: project.basePath
val sdkBasePath = moduleOrProject.moduleIfExists?.baseDir?.path ?: project.basePath
val sdk = getSdk(venvPython, sdkBasePath?.let { Path.of(it) })
if (moduleOrProject.moduleIfExists == null && project.modules.isEmpty()) {
writeAction {

View File

@@ -101,7 +101,7 @@ fun filterSystemWideSdks(existingSdks: List<Sdk>): List<Sdk> {
@Internal
fun configurePythonSdk(project: Project, module: Module, sdk: Sdk) {
// in case module contains root of the project we consider it as a project wide interpreter
if (project.basePath == module.basePath) {
if (project.basePath == module.baseDir?.path) {
project.pythonSdk = sdk
}
@@ -275,7 +275,7 @@ internal fun showSdkExecutionException(sdk: Sdk?, e: ExecutionException, @NlsCon
@Internal
fun Sdk.isAssociatedWithModule(module: Module?): Boolean {
val basePath = module?.basePath
val basePath = module?.baseDir?.path
val associatedPath = associatedModulePath
if (basePath != null && associatedPath == basePath) return true
if (isAssociatedWithAnotherModule(module)) return false
@@ -284,7 +284,7 @@ fun Sdk.isAssociatedWithModule(module: Module?): Boolean {
@Internal
fun Sdk.isAssociatedWithAnotherModule(module: Module?): Boolean {
val basePath = module?.basePath ?: return false
val basePath = module?.baseDir?.path ?: return false
val associatedPath = associatedModulePath ?: return false
return basePath != associatedPath
}
@@ -334,7 +334,7 @@ suspend fun PyDetectedSdk.setupSdk(
existingSdks: List<Sdk>,
doAssociate: Boolean,
) {
val newSdk = setupAssociated(existingSdks, module.basePath, doAssociate).getOr {
val newSdk = setupAssociated(existingSdks, module.baseDir?.path, doAssociate).getOr {
ShowingMessageErrorSync.emit(it.error, module.project)
return
}
@@ -623,6 +623,7 @@ val Sdk.sdkSeemsValid: Boolean
fun setPythonSdk(module: Module, sdk: Sdk) {
module.pythonSdk = sdk
}
@Internal
@Deprecated("Use module.pythonSdk", replaceWith = ReplaceWith("module.pythonSdk"), level = DeprecationLevel.ERROR)
fun getPythonSdk(module: Module): Sdk? = module.pythonSdk
fun getPythonSdk(module: Module): Sdk? = module.pythonSdk

View File

@@ -69,7 +69,7 @@ internal abstract class CustomNewEnvironmentCreator<P : PathHolder>(
is ModuleOrProject.ModuleAndProject -> moduleOrProject.module
is ModuleOrProject.ProjectOnly -> null
}
val moduleBasePath = module?.basePath?.let { Path.of(it) }
val moduleBasePath = module?.baseDir?.path?.let { Path.of(it) }
?: model.projectPathFlows.projectPath.first()
?: error("module base path can't be recognized, both module and project are nulls")
@@ -133,9 +133,10 @@ internal abstract class CustomNewEnvironmentCreator<P : PathHolder>(
val installedSdk = when (baseInterpreter) {
is InstallableSelectableInterpreter -> installBaseSdk(baseInterpreter.sdk, model.existingSdks)
?.let {
val sdkWrapper = runWithModalProgressBlocking(ModalTaskOwner.guess(), message("sdk.create.custom.venv.progress.title.detect.executable")) {
model.fileSystem.wrapSdk(it)
}
val sdkWrapper =
runWithModalProgressBlocking(ModalTaskOwner.guess(), message("sdk.create.custom.venv.progress.title.detect.executable")) {
model.fileSystem.wrapSdk(it)
}
val installed = model.addInstalledInterpreter(sdkWrapper.homePath, baseInterpreter.pythonInfo)
model.state.baseInterpreter.set(installed)
installed

View File

@@ -2,6 +2,7 @@
package com.jetbrains.python.sdk.add.v2
import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.roots.ModuleRootManager
import com.intellij.openapi.util.io.toNioPathOrNull
import com.jetbrains.python.Result
import com.jetbrains.python.errorProcessing.ErrorSink
@@ -36,7 +37,7 @@ class PythonAddLocalInterpreterPresenter(
*/
val pathForVEnv: Path
get() = when (moduleOrProject) {
is ModuleOrProject.ModuleAndProject -> moduleOrProject.module.rootManager.contentRoots.firstOrNull()?.toNioPath()
is ModuleOrProject.ModuleAndProject -> ModuleRootManager.getInstance(moduleOrProject.module).contentRoots.firstOrNull()?.toNioPath()
?: moduleOrProject.project.basePath?.toNioPathOrNull()
is ModuleOrProject.ProjectOnly -> moduleOrProject.project.basePath?.toNioPathOrNull()
} ?: envReader.getVEnvRootDir()

View File

@@ -27,7 +27,7 @@ import com.jetbrains.python.sdk.add.v2.pipenv.PipenvViewModel
import com.jetbrains.python.sdk.add.v2.poetry.PoetryViewModel
import com.jetbrains.python.sdk.add.v2.uv.UvViewModel
import com.jetbrains.python.sdk.add.v2.venv.VenvViewModel
import com.jetbrains.python.sdk.basePath
import com.jetbrains.python.sdk.baseDir
import com.jetbrains.python.target.ui.TargetPanelExtension
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
@@ -282,7 +282,7 @@ internal val <P : PathHolder> PythonAddInterpreterModel<P>.existingSdks: List<Sd
internal suspend fun PythonAddInterpreterModel<*>.getBasePath(module: Module?): Path = withContext(Dispatchers.IO) {
val pyProjectTomlBased = module?.let { PyProjectToml.findFile(it)?.toNioPathOrNull()?.parent }
pyProjectTomlBased ?: module?.basePath?.let { Path.of(it) } ?: projectPathFlows.projectPathWithDefault.first()
pyProjectTomlBased ?: module?.baseDir?.path?.let { Path.of(it) } ?: projectPathFlows.projectPathWithDefault.first()
}
private fun <T : MaybeSystemPython> Flow<Iterable<T>>.sysPythonsOnly(): Flow<List<T>> = map { it.sysPythonsOnly() }

View File

@@ -25,7 +25,7 @@ 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
import com.jetbrains.python.sdk.add.v2.VenvExistenceValidationState.Invisible
import com.jetbrains.python.sdk.basePath
import com.jetbrains.python.sdk.baseDir
import com.jetbrains.python.sdk.poetry.configurePoetryEnvironment
import com.jetbrains.python.sdk.poetry.createNewPoetrySdk
import com.jetbrains.python.statistics.InterpreterType
@@ -141,7 +141,8 @@ internal class EnvironmentCreatorPoetry<P : PathHolder>(
@Service(Service.Level.APP)
@State(name = "PyPoetrySettings", storages = [Storage("pyPoetrySettings.xml")])
private class PoetryConfigService : SerializablePersistentStateComponent<PoetryConfigService.PyPoetrySettingsState>(PyPoetrySettingsState()) {
private class PoetryConfigService :
SerializablePersistentStateComponent<PoetryConfigService.PyPoetrySettingsState>(PyPoetrySettingsState()) {
class PyPoetrySettingsState : BaseState() {
var isInProjectEnv = false
}
@@ -150,7 +151,7 @@ private class PoetryConfigService : SerializablePersistentStateComponent<PoetryC
val hasPoetryToml = findPoetryToml(module) != null
if (state.isInProjectEnv || hasPoetryToml) {
val modulePath = withContext(Dispatchers.IO) {
PyProjectToml.findFile(module)?.parent?.toNioPath() ?: module.basePath?.let { Path.of(it) }
PyProjectToml.findFile(module)?.parent?.toNioPath() ?: module.baseDir?.path?.let { Path.of(it) }
}
configurePoetryEnvironment(modulePath, "virtualenvs.in-project", state.isInProjectEnv.toString(), "--local")
}

View File

@@ -13,6 +13,7 @@ import com.jetbrains.python.Result
import com.jetbrains.python.errorProcessing.PyResult
import com.jetbrains.python.sdk.ModuleOrProject
import com.jetbrains.python.sdk.add.v2.*
import com.jetbrains.python.sdk.baseDir
import com.jetbrains.python.sdk.basePath
import com.jetbrains.python.sdk.legacy.PythonSdkUtil
import com.jetbrains.python.sdk.moduleIfExists
@@ -43,7 +44,7 @@ internal class PoetryExistingEnvironmentSelector<P : PathHolder>(model: PythonMu
return Result.success(it)
}
val basePathString = moduleOrProject.moduleIfExists?.basePath ?: moduleOrProject.project.basePath
val basePathString = moduleOrProject.moduleIfExists?.baseDir?.path ?: moduleOrProject.project.basePath
val basePath = basePathString?.let { Path.of(it) } ?: error("module base path is not valid: $basePathString")
return createPoetrySdk(basePath, pythonBinaryPath)

View File

@@ -3,6 +3,7 @@ package com.jetbrains.python.sdk.add.v2
import com.intellij.openapi.diagnostic.fileLogger
import com.intellij.openapi.module.Module
import com.intellij.openapi.roots.ModuleRootManager
import com.jetbrains.python.sdk.*
import com.jetbrains.python.venvReader.VirtualEnvReader
import kotlinx.coroutines.Dispatchers
@@ -73,7 +74,7 @@ suspend fun <P : PathHolder> sortForExistingEnvironment(
if (module != null) {
when (it.homePath) {
is PathHolder.Eel -> {
if (module.rootManager.contentRoots.any { root -> it.homePath.path.startsWith(root.toNioPath()) }) {
if (ModuleRootManager.getInstance(module).contentRoots.any { root -> it.homePath.path.startsWith(root.toNioPath()) }) {
return@groupBy Group.ASSOC_WITH_PROJ_ROOT
}
}

View File

@@ -13,7 +13,7 @@ import com.jetbrains.python.getOrNull
import com.jetbrains.python.sdk.ModuleOrProject
import com.jetbrains.python.sdk.add.v2.*
import com.jetbrains.python.sdk.associatedModulePath
import com.jetbrains.python.sdk.basePath
import com.jetbrains.python.sdk.baseDir
import com.jetbrains.python.sdk.impl.resolvePythonBinary
import com.jetbrains.python.sdk.isAssociatedWithModule
import com.jetbrains.python.sdk.legacy.PythonSdkUtil
@@ -30,8 +30,8 @@ import kotlin.io.path.exists
import kotlin.io.path.pathString
internal class UvExistingEnvironmentSelector<P : PathHolder>(model: PythonMutableTargetAddInterpreterModel<P>, module: Module?)
: CustomExistingEnvironmentSelector<P>("uv", model, module) {
internal class UvExistingEnvironmentSelector<P : PathHolder>(model: PythonMutableTargetAddInterpreterModel<P>, module: Module?) :
CustomExistingEnvironmentSelector<P>("uv", model, module) {
override val interpreterType: InterpreterType = InterpreterType.UV
override val toolState: ToolValidator<P> = model.uvViewModel.toolValidator
override val toolExecutable: ObservableProperty<ValidatedPath.Executable<P>?> = model.uvViewModel.uvExecutable
@@ -46,7 +46,7 @@ internal class UvExistingEnvironmentSelector<P : PathHolder>(model: PythonMutabl
val allSdk = PythonSdkUtil.getAllSdks()
val existingSdk = allSdk.find { it.homePath == selectedInterpreterPath.path.pathString }
val associatedModule = extractModule(moduleOrProject)
val basePathString = associatedModule?.basePath ?: moduleOrProject.project.basePath
val basePathString = associatedModule?.baseDir?.path ?: moduleOrProject.project.basePath
val projectDir = tryResolvePath(basePathString)
?: return PyResult.localizedError(PyBundle.message("python.sdk.provided.path.is.invalid", basePathString))

View File

@@ -24,7 +24,6 @@ import com.intellij.platform.ide.progress.ModalTaskOwner
import com.intellij.platform.ide.progress.runWithModalProgressBlocking
import com.intellij.remote.RemoteSdkException
import com.intellij.util.concurrency.annotations.RequiresEdt
import com.jetbrains.python.sdk.impl.PySdkBundle
import com.jetbrains.python.Result
import com.jetbrains.python.packaging.PyPackageManagers
import com.jetbrains.python.packaging.PyTargetEnvCreationManager
@@ -33,6 +32,7 @@ import com.jetbrains.python.sdk.*
import com.jetbrains.python.sdk.flavors.PyFlavorAndData
import com.jetbrains.python.sdk.flavors.PyFlavorData
import com.jetbrains.python.sdk.flavors.VirtualEnvSdkFlavor
import com.jetbrains.python.sdk.impl.PySdkBundle
import com.jetbrains.python.target.PyTargetAwareAdditionalData
import com.jetbrains.python.target.getInterpreterVersion
import com.jetbrains.python.target.ui.TargetPanelExtension
@@ -68,7 +68,7 @@ fun createVirtualEnvAndSdkSynchronously(
baseSdk
}
val projectPath = projectBasePath ?: module?.basePath ?: project?.basePath
val projectPath = projectBasePath ?: module?.baseDir?.path ?: project?.basePath
val task = object : Task.WithResult<String, ExecutionException>(project, PySdkBundle.message("python.creating.venv.title"), false) {
override fun compute(indicator: ProgressIndicator): String {
indicator.isIndeterminate = true

View File

@@ -120,7 +120,7 @@ internal suspend fun detectPoetryEnvs(
existingSdkPaths: Set<String>?,
projectPath: @SystemIndependent @NonNls String?,
): List<PyDetectedSdk> {
val path = module?.basePath?.let { Path.of(it) } ?: projectPath?.let { Path.of(it) } ?: return emptyList()
val path = module?.baseDir?.path?.let { Path.of(it) } ?: projectPath?.let { Path.of(it) } ?: return emptyList()
return getPoetryEnvs(path).filter { existingSdkPaths?.contains(getPythonExecutable(it)) != false }
.map { PyDetectedSdk(getPythonExecutable(it)) }
}

View File

@@ -17,7 +17,7 @@ import com.jetbrains.python.psi.stubs.PyDecoratorStub
import com.jetbrains.python.psi.stubs.PyDecoratorStubIndex
import com.jetbrains.python.psi.stubs.PyTestFixtureDecoratorStub
import com.jetbrains.python.psi.types.TypeEvalContext
import com.jetbrains.python.sdk.basePath
import com.jetbrains.python.sdk.baseDir
import com.jetbrains.python.sdk.pythonSdk
import com.jetbrains.python.testing.PyTestFactory
import com.jetbrains.python.testing.TestRunnerService
@@ -52,23 +52,27 @@ internal fun getFixtureLink(element: PyElement, typeEvalContext: TypeEvalContext
/**
* If named parameter or reference expression has fixture (and import statement) -- return it
*/
private fun getFixtureAsExpressionLink(element: PyParameterOrPyReferenceExpression,
typeEvalContext: TypeEvalContext,
module: Module): NamedFixtureLink? {
private fun getFixtureAsExpressionLink(
element: PyParameterOrPyReferenceExpression,
typeEvalContext: TypeEvalContext,
module: Module,
): NamedFixtureLink? {
val pyExpression = element.expression
val func = PsiTreeUtil.getParentOfType(pyExpression, PyFunction::class.java) ?: return null
val fixtureCandidates = getFixtures(module, func, typeEvalContext).filter { o -> o.name == pyExpression.name }
return module.basePath?.let { return findRightFixture(fixtureCandidates, func, pyExpression, typeEvalContext, it) }
return module.baseDir?.path?.let { return findRightFixture(fixtureCandidates, func, pyExpression, typeEvalContext, it) }
}
/**
* If string literal has fixture (and import statement) -- return it
*/
private fun getFixtureAsStringLink(element: PyStringLiteralExpression,
typeEvalContext: TypeEvalContext,
module: Module): NamedFixtureLink? {
private fun getFixtureAsStringLink(
element: PyStringLiteralExpression,
typeEvalContext: TypeEvalContext,
module: Module,
): NamedFixtureLink? {
val fixtureCandidates = getModuleFixtures(module).filter { o -> o.name == element.stringValue }
return module.basePath?.let { return findRightFixture(fixtureCandidates, null, element, typeEvalContext, it) }
return module.baseDir?.path?.let { return findRightFixture(fixtureCandidates, null, element, typeEvalContext, it) }
}
data class NamedFixtureLink(val fixture: PyTestFixture, val importElement: PyElement?)
@@ -98,11 +102,13 @@ private fun PyTestFixture.isInConftestInDir(directory: PsiDirectory): Boolean {
*
* @return Fixture and import element if fixture was imported or null
*/
private fun findRightFixture(fixtureCandidates: List<PyTestFixture>,
func: PyFunction?,
pyFixtureElement: PyElement,
typeEvalContext: TypeEvalContext,
projectPath: String): NamedFixtureLink? {
private fun findRightFixture(
fixtureCandidates: List<PyTestFixture>,
func: PyFunction?,
pyFixtureElement: PyElement,
typeEvalContext: TypeEvalContext,
projectPath: String,
): NamedFixtureLink? {
val elementName = pyFixtureElement.getFixtureName() ?: return null
// request fixture
@@ -167,10 +173,12 @@ private fun findRightFixture(fixtureCandidates: List<PyTestFixture>,
/**
* Search fixture or imported fixture in 'constest.py' file
*/
private fun searchInConftest(fixtureCandidates: List<PyTestFixture>,
currentDirectory: PsiDirectory,
elementName: String,
func: PyFunction?): NamedFixtureLink? {
private fun searchInConftest(
fixtureCandidates: List<PyTestFixture>,
currentDirectory: PsiDirectory,
elementName: String,
func: PyFunction?,
): NamedFixtureLink? {
fixtureCandidates.find { it.isInConftestInDir(currentDirectory) }?.let { return NamedFixtureLink(it, null) }
// search in imports and 'pytest_plugins' in "conftest.py" file
@@ -184,10 +192,12 @@ private fun searchInConftest(fixtureCandidates: List<PyTestFixture>,
/**
* Return fixture from import statements
*/
private fun getFixtureFromImports(targetFile: PyFile,
elementName: String,
func: PyFunction?,
fixtureCandidates: List<PyTestFixture>): NamedFixtureLink? {
private fun getFixtureFromImports(
targetFile: PyFile,
elementName: String,
func: PyFunction?,
fixtureCandidates: List<PyTestFixture>,
): NamedFixtureLink? {
findImportedFixtureInFile(targetFile, elementName, func, fixtureCandidates)?.let { return it }
findImportedFixtureWithWildcard(targetFile, elementName, func, fixtureCandidates)?.let { return it }
return null
@@ -199,16 +209,18 @@ private fun getFixtureFromImports(targetFile: PyFile,
* `from module import some_fixture as sf` or
* `import module.some_fixture`
*/
private fun findImportedFixtureInFile(targetFile: PyFile,
elementName: String,
func: PyFunction?,
fixtureCandidates: List<PyTestFixture>): NamedFixtureLink? {
private fun findImportedFixtureInFile(
targetFile: PyFile,
elementName: String,
func: PyFunction?,
fixtureCandidates: List<PyTestFixture>,
): NamedFixtureLink? {
val importedFixture = targetFile.findExportedName(elementName) as? PyImportElement
val resolveImportElements = importedFixture?.multiResolve()?.map { it.element }
if (importedFixture != null) {
// if fixture is imported as `from module import some_fixture as sf`
resolveImportElements?.firstOrNull { (it as? PyFunction)?.isFixture() == true }?.let { fixture ->
return (fixture as? PyFunction)?.let { NamedFixtureLink(PyTestFixture(func, fixture, fixture.name ?: ""), importedFixture) }
return (fixture as? PyFunction)?.let { NamedFixtureLink(PyTestFixture(func, fixture, fixture.name ?: ""), importedFixture) }
}
resolveImportElements?.let { list ->
@@ -225,26 +237,30 @@ private fun findImportedFixtureInFile(targetFile: PyFile,
*
* `from module import *`
*/
private fun findImportedFixtureWithWildcard(targetFile: PyFile,
elementName: String,
func: PyFunction?,
fixtureCandidates: List<PyTestFixture>): NamedFixtureLink? {
private fun findImportedFixtureWithWildcard(
targetFile: PyFile,
elementName: String,
func: PyFunction?,
fixtureCandidates: List<PyTestFixture>,
): NamedFixtureLink? {
val starImportElements = targetFile.importBlock.filter { importStatement -> importStatement.children.any { it is PyStarImportElement } }
if (starImportElements.isNotEmpty()) {
// Map: containing file to fixture
val fileToFixture = fixtureCandidates.mapNotNull { candidate -> (candidate.getContainingFile() as? PyFile)?.let { it to candidate } }.toMap()
val fileToFixture =
fixtureCandidates.mapNotNull { candidate -> (candidate.getContainingFile() as? PyFile)?.let { it to candidate } }.toMap()
// Map: resolved source file to PyStarImportElement (needs for import reference)
val sourceToImport = starImportElements.mapNotNull { elem ->
val sourceFile = elem.children.firstOrNull { it is PyReferenceExpression }?.let { it.reference?.resolve() as? PyFile }
val starImportElement = elem.children.firstOrNull { it is PyStarImportElement } as? PyStarImportElement
if (sourceFile == null || starImportElement == null) {
null
} else {
}
else {
Pair(sourceFile, starImportElement)
}
}
sourceToImport.forEach {( sourceFile, importElement) ->
sourceToImport.forEach { (sourceFile, importElement) ->
// if a source file is a required file
fileToFixture[sourceFile]?.let { return NamedFixtureLink(it, importElement) }
@@ -258,6 +274,7 @@ private fun findImportedFixtureWithWildcard(targetFile: PyFile,
}
return null
}
/**
* Return fixture from pytest_plugins
*/
@@ -337,7 +354,7 @@ internal fun resolve(expr: PyExpression): PyExpression? {
when (expr) {
is PyStringLiteralExpression -> return expr
is PyQualifiedExpression -> return getFixtureNameFromQualifiedName(expr)
}
}
return null
}

View File

@@ -8,15 +8,14 @@ import com.jetbrains.python.packaging.PyPackageName
import com.jetbrains.python.packaging.common.PythonPackage
import com.jetbrains.python.packaging.packageRequirements.PythonPackageRequirementExtractor
import com.jetbrains.python.packaging.packageRequirements.PythonPackageRequiresExtractorProvider
import com.jetbrains.python.sdk.basePath
import com.jetbrains.python.sdk.baseDir
import com.jetbrains.python.sdk.uv.UvSdkAdditionalData
import com.jetbrains.python.sdk.uv.impl.createUvCli
import com.jetbrains.python.sdk.uv.impl.createUvLowLevel
import java.nio.file.Path
internal class UvPackageRequirementExtractor(private val uvWorkingDirectory: Path?) : PythonPackageRequirementExtractor {
override suspend fun extract(pkg: PythonPackage, module: Module): List<PyPackageName> {
val uvWorkingDirectory = uvWorkingDirectory ?: Path.of(module.basePath!!)
val uvWorkingDirectory = uvWorkingDirectory ?: Path.of(module.baseDir?.path!!)
val uv = createUvLowLevel(uvWorkingDirectory).getOr {
thisLogger().info("cannot run uv: ${it.error}")
return emptyList()
@@ -28,7 +27,7 @@ internal class UvPackageRequirementExtractor(private val uvWorkingDirectory: Pat
}
}
internal class UvPackageRequiresExtractorProvider: PythonPackageRequiresExtractorProvider {
internal class UvPackageRequiresExtractorProvider : PythonPackageRequiresExtractorProvider {
override fun createExtractor(sdk: Sdk): PythonPackageRequirementExtractor? {
val data = sdk.sdkAdditionalData as? UvSdkAdditionalData ?: return null
return UvPackageRequirementExtractor(data.uvWorkingDirectory)

View File

@@ -2,28 +2,25 @@ package com.jetbrains.python.uv.sdk.evolution
import com.intellij.openapi.ui.popup.ListSeparator
import com.intellij.python.community.impl.uv.common.icons.PythonCommunityImplUVCommonIcons
import com.jetbrains.python.Result
import com.jetbrains.python.errorProcessing.PyResult
import com.jetbrains.python.sdk.basePath
import com.intellij.python.sdk.ui.evolution.sdk.EvoModuleSdk
import com.intellij.python.sdk.ui.evolution.sdk.EvoSdk
import com.intellij.python.sdk.ui.evolution.AddNewEnvAction
import com.intellij.python.sdk.ui.evolution.SelectEnvAction
import com.intellij.python.sdk.ui.evolution.sdk.EvoModuleSdk
import com.intellij.python.sdk.ui.evolution.sdk.EvoSdk
import com.intellij.python.sdk.ui.evolution.tool.pip.sdk.VenvEvoSdkManager
import com.intellij.python.sdk.ui.evolution.ui.EvoSelectSdkProvider
import com.intellij.python.sdk.ui.evolution.ui.components.EvoTreeLazyNodeElement
import com.intellij.python.sdk.ui.evolution.ui.components.EvoTreeLeafElement
import com.intellij.python.sdk.ui.evolution.ui.components.EvoTreeSection
import com.jetbrains.python.PyBundle
import com.jetbrains.python.icons.PythonIcons
import com.jetbrains.python.Result
import com.jetbrains.python.errorProcessing.PyResult
import com.jetbrains.python.sdk.baseDir
import com.jetbrains.python.sdk.uv.impl.getUvExecutable
import com.jetbrains.python.venvReader.VirtualEnvReader
import java.nio.file.Path
import kotlin.collections.component1
import kotlin.collections.component2
internal class UvSelectSdkProvider() : EvoSelectSdkProvider {
internal class UvSelectSdkProvider : EvoSelectSdkProvider {
override fun getTreeElement(evoModuleSdk: EvoModuleSdk): EvoTreeLazyNodeElement {
val icon = PythonCommunityImplUVCommonIcons.UV
return EvoTreeLazyNodeElement("uv", icon) {
@@ -34,7 +31,7 @@ internal class UvSelectSdkProvider() : EvoSelectSdkProvider {
}.map { it.copy(icon = icon) }
val envByFolders = environments.groupBy { it.pythonBinaryPath?.parent?.parent?.parent }.toMutableMap()
envByFolders.putIfAbsent(
evoModuleSdk.module.basePath?.let { Path.of(it) },
evoModuleSdk.module.baseDir?.path?.let { Path.of(it) },
listOf(EvoSdk(icon = icon, name = VirtualEnvReader.DEFAULT_VIRTUALENV_DIRNAME, pythonBinaryPath = null))
)
val envSections = envByFolders.map { (basePath, sdks) ->

View File

@@ -285,7 +285,7 @@ class PySdkPathsTest {
val module = projectModel.createModule(name)
assertThat(PyUtil.getSourceRoots(module)).isEmpty()
module.rootManager.modifiableModel.apply {
ModuleRootManager.getInstance(module).modifiableModel.apply {
addContentEntry(moduleRoot)
runWriteActionAndWait { commit() }
}