mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Python: make python with language level independent from python binary to support conda and other python types.
GitOrigin-RevId: 2752eed732ab6d3e45da38714106700ba2014bd8
This commit is contained in:
committed by
intellij-monorepo-bot
parent
2e14347844
commit
cea3e7d9c0
+10
-8
@@ -5,9 +5,10 @@ import com.intellij.platform.eel.EelPlatform
|
||||
import com.intellij.platform.eel.provider.asNioPath
|
||||
import com.intellij.platform.eel.provider.getEelDescriptor
|
||||
import com.intellij.python.community.execService.python.validatePythonAndGetVersion
|
||||
import com.intellij.python.community.services.internal.impl.PythonWithLanguageLevelImpl.Companion.concurrentLimit
|
||||
import com.intellij.python.community.services.internal.impl.PythonWithLanguageLevelImpl.Companion.createByPythonBinary
|
||||
import com.intellij.python.community.services.internal.impl.VanillaPythonWithLanguageLevelImpl.Companion.concurrentLimit
|
||||
import com.intellij.python.community.services.internal.impl.VanillaPythonWithLanguageLevelImpl.Companion.createByPythonBinary
|
||||
import com.intellij.python.community.services.shared.PythonWithLanguageLevel
|
||||
import com.intellij.python.community.services.shared.VanillaPythonWithLanguageLevel
|
||||
import com.jetbrains.python.PythonBinary
|
||||
import com.jetbrains.python.Result
|
||||
import com.jetbrains.python.errorProcessing.PyResult
|
||||
@@ -23,10 +24,11 @@ import kotlin.io.path.pathString
|
||||
import kotlin.io.path.relativeTo
|
||||
|
||||
@Internal
|
||||
class PythonWithLanguageLevelImpl internal constructor(
|
||||
class VanillaPythonWithLanguageLevelImpl internal constructor(
|
||||
override val pythonBinary: PythonBinary,
|
||||
override val languageLevel: LanguageLevel,
|
||||
) : PythonWithLanguageLevel, Comparable<PythonWithLanguageLevel> {
|
||||
) : VanillaPythonWithLanguageLevel {
|
||||
|
||||
companion object {
|
||||
|
||||
private val concurrentLimit = Semaphore(permits = 4)
|
||||
@@ -35,7 +37,7 @@ class PythonWithLanguageLevelImpl internal constructor(
|
||||
* Like [createByPythonBinary] but runs in parallel up to [concurrentLimit]
|
||||
* @return python path -> python with language level sorted from highest to lowest.
|
||||
*/
|
||||
suspend fun createByPythonBinaries(pythonBinaries: Collection<PythonBinary>): Collection<Pair<PythonBinary, PyResult<PythonWithLanguageLevel>>> =
|
||||
suspend fun createByPythonBinaries(pythonBinaries: Collection<PythonBinary>): Collection<Pair<PythonBinary, PyResult<VanillaPythonWithLanguageLevel>>> =
|
||||
coroutineScope {
|
||||
pythonBinaries.map {
|
||||
async {
|
||||
@@ -46,9 +48,9 @@ class PythonWithLanguageLevelImpl internal constructor(
|
||||
}.awaitAll()
|
||||
}.sortedBy { it.first }
|
||||
|
||||
suspend fun createByPythonBinary(pythonBinary: PythonBinary): PyResult<PythonWithLanguageLevelImpl> {
|
||||
suspend fun createByPythonBinary(pythonBinary: PythonBinary): PyResult<VanillaPythonWithLanguageLevelImpl> {
|
||||
val languageLevel = pythonBinary.validatePythonAndGetVersion().getOr { return it }
|
||||
return Result.success(PythonWithLanguageLevelImpl(pythonBinary, languageLevel))
|
||||
return Result.success(VanillaPythonWithLanguageLevelImpl(pythonBinary, languageLevel))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +58,7 @@ class PythonWithLanguageLevelImpl internal constructor(
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as PythonWithLanguageLevelImpl
|
||||
other as VanillaPythonWithLanguageLevelImpl
|
||||
|
||||
return pythonBinary == other.pythonBinary
|
||||
}
|
||||
+4
-4
@@ -1,7 +1,7 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.python.junit5Tests.env.services.internal.impl
|
||||
|
||||
import com.intellij.python.community.services.internal.impl.PythonWithLanguageLevelImpl
|
||||
import com.intellij.python.community.services.internal.impl.VanillaPythonWithLanguageLevelImpl
|
||||
import com.intellij.python.junit5Tests.framework.env.PyEnvTestCase
|
||||
import com.intellij.python.junit5Tests.framework.env.PythonBinaryPath
|
||||
import com.intellij.python.junit5Tests.randomBinary
|
||||
@@ -15,7 +15,7 @@ import org.junit.jupiter.api.Test
|
||||
class PythonWithLanguageLevelImplTest {
|
||||
@Test
|
||||
fun testRainyDay(): Unit = runBlocking {
|
||||
when (val r = PythonWithLanguageLevelImpl.createByPythonBinary(randomBinary)) {
|
||||
when (val r = VanillaPythonWithLanguageLevelImpl.createByPythonBinary(randomBinary)) {
|
||||
is Result.Failure -> Unit
|
||||
is Result.Success -> fail("Unexpected success ${r.result}")
|
||||
}
|
||||
@@ -23,7 +23,7 @@ class PythonWithLanguageLevelImplTest {
|
||||
|
||||
@Test
|
||||
fun testSunnyDay(@PythonBinaryPath pythonBinary: PythonBinary): Unit = runBlocking {
|
||||
val python = PythonWithLanguageLevelImpl.createByPythonBinary(pythonBinary).orThrow()
|
||||
val python = VanillaPythonWithLanguageLevelImpl.createByPythonBinary(pythonBinary).orThrow()
|
||||
assertEquals(pythonBinary, python.pythonBinary, "Wrong python binary")
|
||||
assertTrue(python.languageLevel.isPy3K, "Wrong python version")
|
||||
}
|
||||
|
||||
+5
-5
@@ -1,7 +1,7 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.python.junit5Tests.unit
|
||||
|
||||
import com.intellij.python.community.services.internal.impl.PythonWithLanguageLevelImpl
|
||||
import com.intellij.python.community.services.internal.impl.VanillaPythonWithLanguageLevelImpl
|
||||
import com.intellij.testFramework.junit5.TestApplication
|
||||
import com.jetbrains.python.psi.LanguageLevel
|
||||
import org.junit.jupiter.api.Assertions.assertArrayEquals
|
||||
@@ -14,9 +14,9 @@ class CompareByLanguageLevelTest {
|
||||
@Test
|
||||
fun testCompareByLanguageLevel(@TempDir path: Path) {
|
||||
val list = listOf(
|
||||
PythonWithLanguageLevelImpl(path, LanguageLevel.PYTHON38),
|
||||
PythonWithLanguageLevelImpl(path, LanguageLevel.PYTHON312),
|
||||
PythonWithLanguageLevelImpl(path, LanguageLevel.PYTHON311),
|
||||
VanillaPythonWithLanguageLevelImpl(path, LanguageLevel.PYTHON38),
|
||||
VanillaPythonWithLanguageLevelImpl(path, LanguageLevel.PYTHON312),
|
||||
VanillaPythonWithLanguageLevelImpl(path, LanguageLevel.PYTHON311),
|
||||
)
|
||||
|
||||
val sortedLevels = list.sorted().map { it.languageLevel }.toTypedArray()
|
||||
|
||||
+5
-5
@@ -1,7 +1,7 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.python.junit5Tests.unit.alsoWin.services.internal.impl
|
||||
|
||||
import com.intellij.python.community.services.internal.impl.PythonWithLanguageLevelImpl
|
||||
import com.intellij.python.community.services.internal.impl.VanillaPythonWithLanguageLevelImpl
|
||||
import com.intellij.testFramework.junit5.TestApplication
|
||||
import com.jetbrains.python.psi.LanguageLevel
|
||||
import kotlinx.coroutines.runBlocking
|
||||
@@ -23,7 +23,7 @@ class ReadableNameTest {
|
||||
@Test
|
||||
fun testNoHomePath(@TempDir path: Path): Unit = runBlocking {
|
||||
val fakePython = path.resolve(PYTHON_FILE_NAME)
|
||||
val name = PythonWithLanguageLevelImpl(fakePython, LanguageLevel.PYTHON312).getReadableName()
|
||||
val name = VanillaPythonWithLanguageLevelImpl(fakePython, LanguageLevel.PYTHON312).getReadableName()
|
||||
assertThat("Wrong name generated", name, allOf(containsString("3.12"), containsString(fakePython.pathString)))
|
||||
}
|
||||
|
||||
@@ -33,11 +33,11 @@ class ReadableNameTest {
|
||||
|
||||
|
||||
var fakePython = home.resolve(PYTHON_FILE_NAME)
|
||||
var name = PythonWithLanguageLevelImpl(fakePython, LanguageLevel.PYTHON312).getReadableName()
|
||||
var name = VanillaPythonWithLanguageLevelImpl(fakePython, LanguageLevel.PYTHON312).getReadableName()
|
||||
assertThat("Wrong name generated", name, allOf(containsString("3.12"), matchesPattern(".*~[\\\\/]$PYTHON_FILE_NAME.*")))
|
||||
|
||||
fakePython = home.resolve("deep").resolve(PYTHON_FILE_NAME)
|
||||
name = PythonWithLanguageLevelImpl(fakePython, LanguageLevel.PYTHON312).getReadableName()
|
||||
name = VanillaPythonWithLanguageLevelImpl(fakePython, LanguageLevel.PYTHON312).getReadableName()
|
||||
assertThat("Wrong name generated", name, allOf(containsString("3.12"), matchesPattern(".*~[\\\\/]deep[\\\\/]$PYTHON_FILE_NAME.*")))
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ jvm_library(
|
||||
"//python/openapi:community",
|
||||
"@lib//:jetbrains-annotations",
|
||||
"//platform/eel-provider",
|
||||
"//python/python-exec-service/execService.python",
|
||||
],
|
||||
runtime_deps = [":shared_resources"]
|
||||
)
|
||||
|
||||
@@ -16,5 +16,6 @@
|
||||
<orderEntry type="library" scope="TEST" name="kotlinx-coroutines-core" level="project" />
|
||||
<orderEntry type="module" module-name="intellij.platform.testFramework.junit5" scope="TEST" />
|
||||
<orderEntry type="library" scope="TEST" name="hamcrest" level="project" />
|
||||
<orderEntry type="module" module-name="intellij.python.community.execService.python" />
|
||||
</component>
|
||||
</module>
|
||||
+11
-3
@@ -1,16 +1,24 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.python.community.services.shared
|
||||
|
||||
import com.jetbrains.python.PythonBinary
|
||||
import com.intellij.python.community.execService.python.advancedApi.ExecutablePython
|
||||
import com.jetbrains.python.psi.LanguageLevel
|
||||
import org.jetbrains.annotations.Nls
|
||||
|
||||
/**
|
||||
* Python (vanilla, conda, whatever) with known language level.
|
||||
*/
|
||||
interface PythonWithLanguageLevel : Comparable<PythonWithLanguageLevel> {
|
||||
val pythonBinary: PythonBinary
|
||||
val languageLevel: LanguageLevel
|
||||
|
||||
/**
|
||||
* Convert python to something that can be executed on [java.util.concurrent.ExecutorService]
|
||||
*/
|
||||
val asExecutablePython: ExecutablePython
|
||||
|
||||
/**
|
||||
* Name can be displayed to the end user
|
||||
*/
|
||||
suspend fun getReadableName(): @Nls String
|
||||
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.python.community.services.shared
|
||||
|
||||
import com.intellij.python.community.execService.python.advancedApi.ExecutablePython
|
||||
import com.jetbrains.python.PythonBinary
|
||||
|
||||
|
||||
/**
|
||||
* Vanilla (not conda) has [pythonBinary]
|
||||
*/
|
||||
interface VanillaPythonWithLanguageLevel : PythonWithLanguageLevel {
|
||||
val pythonBinary: PythonBinary
|
||||
override val asExecutablePython: ExecutablePython get() = ExecutablePython.Companion.VanillaExecutablePython(pythonBinary)
|
||||
|
||||
}
|
||||
@@ -32,6 +32,7 @@ jvm_library(
|
||||
"//python/services/internal-impl:python-community-services-internal-impl",
|
||||
"//platform/util",
|
||||
"//python/installer",
|
||||
"//python/python-venv:community-impl-venv",
|
||||
],
|
||||
exports = ["//python/services/shared"],
|
||||
runtime_deps = [":system-python_resources"]
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
<orderEntry type="module" module-name="intellij.platform.util" />
|
||||
<orderEntry type="module" module-name="intellij.python.community.junit5Tests.framework" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.python.community.impl.installer" />
|
||||
<orderEntry type="module" module-name="intellij.python.community.impl.venv" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.python.community.impl.venv" />
|
||||
<orderEntry type="module" module-name="intellij.python.community.testFramework.testEnv" scope="TEST" />
|
||||
<orderEntry type="library" scope="TEST" name="io.mockk" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="io.mockk.jvm" level="project" />
|
||||
|
||||
+2
@@ -3,5 +3,7 @@
|
||||
<module name="intellij.python.community"/>
|
||||
<module name="intellij.python.psi.impl"/>
|
||||
<module name="intellij.python.sdk"/>
|
||||
<module name="intellij.python.community.execService"/>
|
||||
<module name="intellij.python.community.impl.venv"/>
|
||||
</dependencies>
|
||||
</idea-plugin>
|
||||
+20
-3
@@ -5,11 +5,16 @@ import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.platform.eel.EelApi
|
||||
import com.intellij.platform.eel.provider.localEel
|
||||
import com.intellij.python.community.services.shared.PythonWithLanguageLevel
|
||||
import com.intellij.python.community.impl.venv.createVenv
|
||||
import com.intellij.python.community.services.shared.VanillaPythonWithLanguageLevel
|
||||
import com.jetbrains.python.PythonBinary
|
||||
import com.jetbrains.python.Result
|
||||
import com.jetbrains.python.errorProcessing.PyResult
|
||||
import com.jetbrains.python.venvReader.Directory
|
||||
import com.jetbrains.python.venvReader.VirtualEnvReader
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import org.jetbrains.annotations.ApiStatus.Internal
|
||||
import org.jetbrains.annotations.CheckReturnValue
|
||||
import org.jetbrains.annotations.Nls
|
||||
import javax.swing.Icon
|
||||
|
||||
@@ -50,7 +55,7 @@ fun SystemPythonService(): SystemPythonService = ApplicationManager.getApplicati
|
||||
*
|
||||
* Instances could be obtained with [SystemPythonService]
|
||||
*/
|
||||
class SystemPython internal constructor(private val impl: PythonWithLanguageLevel, val ui: UICustomization?) : PythonWithLanguageLevel by impl {
|
||||
class SystemPython internal constructor(private val impl: VanillaPythonWithLanguageLevel, val ui: UICustomization?) : VanillaPythonWithLanguageLevel by impl {
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
@@ -95,4 +100,16 @@ data class UICustomization(
|
||||
*/
|
||||
val title: @Nls String,
|
||||
val icon: Icon? = null,
|
||||
)
|
||||
)
|
||||
|
||||
/**
|
||||
* See [createVenv]
|
||||
*/
|
||||
@Internal
|
||||
@CheckReturnValue
|
||||
suspend fun createVenvFromSystemPython(
|
||||
python: SystemPython,
|
||||
venvDir: Directory,
|
||||
inheritSitePackages: Boolean = false,
|
||||
envReader: VirtualEnvReader = VirtualEnvReader.Instance,
|
||||
): PyResult<PythonBinary> = createVenv(python.pythonBinary, venvDir, inheritSitePackages, envReader)
|
||||
+3
-3
@@ -11,7 +11,7 @@ import com.intellij.platform.eel.EelDescriptor
|
||||
import com.intellij.platform.eel.provider.getEelDescriptor
|
||||
import com.intellij.platform.eel.provider.localEel
|
||||
import com.intellij.python.community.impl.installer.PySdkToInstallManager
|
||||
import com.intellij.python.community.services.internal.impl.PythonWithLanguageLevelImpl
|
||||
import com.intellij.python.community.services.internal.impl.VanillaPythonWithLanguageLevelImpl
|
||||
import com.intellij.python.community.services.systemPython.SystemPythonServiceImpl.MyServiceState
|
||||
import com.intellij.python.community.services.systemPython.impl.Cache
|
||||
import com.intellij.python.community.services.systemPython.impl.CoreSystemPythonProvider
|
||||
@@ -61,7 +61,7 @@ internal class SystemPythonServiceImpl(scope: CoroutineScope) : SystemPythonServ
|
||||
}
|
||||
|
||||
override suspend fun registerSystemPython(pythonPath: PythonBinary): PyResult<SystemPython> {
|
||||
val pythonWithLangLevel = PythonWithLanguageLevelImpl.createByPythonBinary(pythonPath).getOr { return it }
|
||||
val pythonWithLangLevel = VanillaPythonWithLanguageLevelImpl.createByPythonBinary(pythonPath).getOr { return it }
|
||||
val systemPython = SystemPython(pythonWithLangLevel, null)
|
||||
state.userProvidedPythons.add(pythonPath.pathString)
|
||||
cache()?.get(pythonPath.getEelDescriptor())?.add(systemPython)
|
||||
@@ -119,7 +119,7 @@ internal class SystemPythonServiceImpl(scope: CoroutineScope) : SystemPythonServ
|
||||
val badPythons = mutableSetOf<PythonBinary>()
|
||||
val pythons = pythonsFromExtensions + state.userProvidedPythonsAsPath.filter { it.getEelDescriptor() == eelApi.descriptor }
|
||||
|
||||
val result = PythonWithLanguageLevelImpl.createByPythonBinaries(pythons.toSet())
|
||||
val result = VanillaPythonWithLanguageLevelImpl.createByPythonBinaries(pythons.toSet())
|
||||
.mapNotNull { (python, r) ->
|
||||
when (r) {
|
||||
is Result.Success -> SystemPython(r.result, pythonsUi[r.result.pythonBinary])
|
||||
|
||||
Reference in New Issue
Block a user