mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-15 02:59:33 +07:00
PY-52265 Poetry in-project environment
Add the new setting: create poetry env in the project. Merge-request: IJ-MR-149143 Merged-by: Egor Eliseev <Egor.Eliseev@jetbrains.com> (cherry picked from commit ed85efe339518cdf6949752be286172113931c22) IJ-MR-149143 GitOrigin-RevId: 3a682aac846e4a80e8310a3dcc0a5f1c988d28e2
This commit is contained in:
committed by
intellij-monorepo-bot
parent
b6fd54065e
commit
cf06be9b95
@@ -393,6 +393,7 @@ python.sdk.dialog.message.creating.virtual.environments.based.on.poetry.environm
|
||||
python.sdk.poetry.environment.panel.title=Poetry Environment
|
||||
python.sdk.poetry.install.packages.from.toml.checkbox.text=Install packages from pyproject.toml
|
||||
python.sdk.poetry.dialog.message.poetry.interpreter.has.been.already.added=Poetry interpreter has been already added, select ''{0}''
|
||||
python.sdk.poetry.dialog.add.new.environment.in.project.checkbox=Create an in-project environment
|
||||
|
||||
python.sdk.pipenv.has.been.selected=Pipenv interpreter has been already added, select ''{0}'' in your interpreters list
|
||||
python.sdk.there.is.no.interpreter=No interpreter
|
||||
|
||||
@@ -2,25 +2,48 @@
|
||||
package com.jetbrains.python.sdk.add.v2
|
||||
|
||||
import com.intellij.ide.util.PropertiesComponent
|
||||
import com.intellij.openapi.components.PersistentStateComponent
|
||||
import com.intellij.openapi.components.Service
|
||||
import com.intellij.openapi.components.State
|
||||
import com.intellij.openapi.components.Storage
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.observable.properties.ObservableMutableProperty
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.intellij.openapi.ui.validation.DialogValidationRequestor
|
||||
import com.intellij.ui.dsl.builder.Panel
|
||||
import com.intellij.ui.dsl.builder.bindSelected
|
||||
import com.intellij.util.text.nullize
|
||||
import com.intellij.util.xmlb.XmlSerializerUtil
|
||||
import com.jetbrains.python.PyBundle
|
||||
import com.jetbrains.python.sdk.ModuleOrProject
|
||||
import com.jetbrains.python.sdk.baseDir
|
||||
import com.jetbrains.python.sdk.poetry.PoetryPyProjectTomlPythonVersionsService
|
||||
import com.jetbrains.python.PythonHelpersLocator
|
||||
import com.jetbrains.python.sdk.basePath
|
||||
import com.jetbrains.python.sdk.poetry.configurePoetryEnvironment
|
||||
import com.jetbrains.python.sdk.poetry.poetryPath
|
||||
import com.jetbrains.python.sdk.poetry.poetryToml
|
||||
import com.jetbrains.python.sdk.poetry.pyProjectToml
|
||||
import com.jetbrains.python.sdk.poetry.setupPoetrySdkUnderProgress
|
||||
import com.jetbrains.python.statistics.InterpreterType
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.nio.file.Path
|
||||
|
||||
class PoetryNewEnvironmentCreator(model: PythonMutableTargetAddInterpreterModel, private val moduleOrProject: ModuleOrProject?) : CustomNewEnvironmentCreator("poetry", model) {
|
||||
override val interpreterType: InterpreterType = InterpreterType.POETRY
|
||||
override val executable: ObservableMutableProperty<String> = model.state.poetryExecutable
|
||||
override val installationScript = PythonHelpersLocator.findPathInHelpers("pycharm_poetry_installer.py")
|
||||
|
||||
override fun buildOptions(panel: Panel, validationRequestor: DialogValidationRequestor) {
|
||||
super.buildOptions(panel, validationRequestor)
|
||||
addInProjectCheckbox(panel)
|
||||
}
|
||||
|
||||
override fun onShown() {
|
||||
val moduleDir = when (moduleOrProject) {
|
||||
is ModuleOrProject.ModuleAndProject -> moduleOrProject.module.baseDir
|
||||
@@ -44,10 +67,42 @@ class PoetryNewEnvironmentCreator(model: PythonMutableTargetAddInterpreterModel,
|
||||
PropertiesComponent.getInstance().poetryPath = executable.get().nullize()
|
||||
}
|
||||
|
||||
override suspend fun setupEnvSdk(project: Project?, module: Module?, baseSdks: List<Sdk>, projectPath: String, homePath: String?, installPackages: Boolean): Result<Sdk> =
|
||||
setupPoetrySdkUnderProgress(project, module, baseSdks, projectPath, homePath, installPackages)
|
||||
override suspend fun setupEnvSdk(project: Project?, module: Module?, baseSdks: List<Sdk>, projectPath: String, homePath: String?, installPackages: Boolean): Result<Sdk> {
|
||||
module?.let { service<PoetryConfigService>().setInProjectEnv(it) }
|
||||
return setupPoetrySdkUnderProgress(project, module, baseSdks, projectPath, homePath, installPackages)
|
||||
}
|
||||
|
||||
override suspend fun detectExecutable() {
|
||||
model.detectPoetryExecutable()
|
||||
}
|
||||
|
||||
private fun addInProjectCheckbox(panel: Panel) {
|
||||
with(panel) {
|
||||
row {
|
||||
checkBox(PyBundle.message("python.sdk.poetry.dialog.add.new.environment.in.project.checkbox"))
|
||||
.bindSelected(service<PoetryConfigService>().state::isInProjectEnv)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Service(Service.Level.APP)
|
||||
@State(name = "PyPoetrySettings", storages = [Storage("pyPoetrySettings.xml")])
|
||||
internal class PoetryConfigService(private val cs: CoroutineScope) : PersistentStateComponent<PoetryConfigService> {
|
||||
var isInProjectEnv: Boolean = false
|
||||
|
||||
override fun getState(): PoetryConfigService = this
|
||||
|
||||
override fun loadState(state: PoetryConfigService) {
|
||||
XmlSerializerUtil.copyBean(state, this)
|
||||
}
|
||||
|
||||
suspend fun setInProjectEnv(module: Module) {
|
||||
val hasPoetryToml = poetryToml(module) != null
|
||||
|
||||
if (isInProjectEnv || hasPoetryToml) {
|
||||
val modulePath = withContext(Dispatchers.IO) { pyProjectToml(module)?.parent }?.toNioPath() ?: module.basePath?.let { Path.of(it) }
|
||||
configurePoetryEnvironment(modulePath, "virtualenvs.in-project", isInProjectEnv.toString(), "--local")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,7 +53,7 @@ class PythonAddLocalInterpreterDialog(private val dialogPresenter: PythonAddLoca
|
||||
// The whole idea of context passing is doubtful
|
||||
Dispatchers.EDT + ModalityState.any().asContextElement(), ProjectPathFlows.create(basePath)))
|
||||
model.navigator.selectionMode = AtomicProperty(PythonInterpreterSelectionMode.CUSTOM)
|
||||
mainPanel = PythonAddCustomInterpreter(model, errorSink = errorSink)
|
||||
mainPanel = PythonAddCustomInterpreter(model, moduleOrProject = dialogPresenter.moduleOrProject, errorSink = errorSink)
|
||||
mainPanel.buildPanel(this, WHEN_PROPERTY_CHANGED(AtomicProperty(basePath)))
|
||||
|
||||
}.apply {
|
||||
|
||||
@@ -190,6 +190,19 @@ suspend fun poetryReloadPackages(sdk: Sdk): Result<String> {
|
||||
return runPoetryWithSdk(sdk, "show")
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the Poetry environment for the specified module path with the given arguments.
|
||||
* Runs command: GeneralCommandLine("poetry config [args]").withWorkingDirectory([modulePath])
|
||||
*
|
||||
* @param [modulePath] The path to the module where the Poetry environment is to be configured.
|
||||
* Can be null, in which case the global Poetry environment will be configured.
|
||||
* @param [args] A vararg array of String arguments to pass to the Poetry configuration command.
|
||||
*/
|
||||
@Internal
|
||||
suspend fun configurePoetryEnvironment(modulePath: Path?, vararg args: String) {
|
||||
runPoetry(modulePath, "config", *args)
|
||||
}
|
||||
|
||||
private suspend fun getPoetryEnvs(projectPath: Path): List<String> {
|
||||
val executionResult = runPoetry(projectPath, "env", "list", "--full-path")
|
||||
return executionResult.getOrNull()?.lineSequence()?.map { it.split(" ")[0] }?.filterNot { it.isEmpty() }?.toList() ?: emptyList()
|
||||
|
||||
@@ -27,6 +27,7 @@ import com.intellij.openapi.components.Service
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.intellij.openapi.roots.ProjectFileIndex
|
||||
import com.intellij.openapi.startup.ProjectActivity
|
||||
import com.intellij.openapi.vfs.findDocument
|
||||
import com.intellij.openapi.vfs.findPsiFile
|
||||
@@ -55,6 +56,7 @@ import java.util.concurrent.ConcurrentMap
|
||||
|
||||
const val PY_PROJECT_TOML: String = "pyproject.toml"
|
||||
const val POETRY_LOCK: String = "poetry.lock"
|
||||
const val POETRY_TOML: String = "poetry.toml"
|
||||
const val POETRY_DEFAULT_SOURCE_URL: String = "https://pypi.org/simple"
|
||||
|
||||
val LOGGER = Logger.getInstance("#com.jetbrains.python.sdk.poetry")
|
||||
@@ -81,6 +83,9 @@ private suspend fun poetryLock(module: Module) = withContext(Dispatchers.IO) { f
|
||||
@Internal
|
||||
suspend fun pyProjectToml(module: Module): VirtualFile? = withContext(Dispatchers.IO) { findAmongRoots(module, PY_PROJECT_TOML) }
|
||||
|
||||
internal suspend fun poetryToml(module: Module): VirtualFile? = withContext(Dispatchers.IO) {
|
||||
findAmongRoots(module, POETRY_TOML)?.takeIf { readAction { ProjectFileIndex.getInstance(module.project).isInProject(it) } }
|
||||
}
|
||||
|
||||
/**
|
||||
* Watches for edits in PyProjectToml inside modules with a poetry SDK set.
|
||||
|
||||
Reference in New Issue
Block a user