mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
cleanup [python]: Move test to VirtualEnvReaderTest to run it on Windows as well.
GitOrigin-RevId: 65e3aed0ba560e5c00d8fe3852c830d853f0b4f5
This commit is contained in:
committed by
intellij-monorepo-bot
parent
672a9d9f8f
commit
fe66f186e7
@@ -1,6 +1,7 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.jetbrains.python.venvReader
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.progress.runBlockingMaybeCancellable
|
||||
import com.intellij.openapi.util.io.toCanonicalPath
|
||||
import com.intellij.platform.eel.EelApi
|
||||
@@ -47,7 +48,7 @@ class VirtualEnvReader private constructor(
|
||||
* Dir with virtual envs
|
||||
*/
|
||||
@RequiresBackgroundThread
|
||||
fun getVEnvRootDir(eel: EelApi = localEel): Directory {
|
||||
fun getVEnvRootDir(eel: EelApi? = getLocalEelIfApp()): Directory {
|
||||
return resolveDirFromEnvOrElseGetDirInHomePath(eel, "WORKON_HOME", DEFAULT_VIRTUALENVS_DIR)
|
||||
}
|
||||
|
||||
@@ -59,7 +60,7 @@ class VirtualEnvReader private constructor(
|
||||
findLocalInterpreters(getVEnvRootDir())
|
||||
|
||||
@RequiresBackgroundThread
|
||||
fun getPyenvRootDir(eel: EelApi = localEel): Directory {
|
||||
fun getPyenvRootDir(eel: EelApi? = getLocalEelIfApp()): Directory {
|
||||
return resolveDirFromEnvOrElseGetDirInHomePath(eel, "PYENV_ROOT", ".pyenv")
|
||||
}
|
||||
|
||||
@@ -176,10 +177,13 @@ class VirtualEnvReader private constructor(
|
||||
}
|
||||
|
||||
@RequiresBackgroundThread
|
||||
private fun resolveDirFromEnvOrElseGetDirInHomePath(eel: EelApi, env: String, dirName: String): Path {
|
||||
val envs = forcedVars ?: runBlockingMaybeCancellable { eel.exec.environmentVariables().eelIt().await() }
|
||||
return envs[env]?.let { tryResolvePath(it, eel.descriptor) }
|
||||
?: eel.userInfo.home.asNioPath().resolve(dirName)
|
||||
private fun resolveDirFromEnvOrElseGetDirInHomePath(eel: EelApi?, env: String, dirName: String): Path {
|
||||
val envs = forcedVars
|
||||
?: eel?.let { eel -> runBlockingMaybeCancellable { eel.exec.environmentVariables().eelIt().await() } }
|
||||
?: System.getenv()
|
||||
return envs[env]?.let { tryResolvePath(it, eel?.descriptor) }
|
||||
?: (eel?.userInfo?.home?.asNioPath()
|
||||
?: Path(System.getProperty("user.home"))).resolve(dirName)
|
||||
}
|
||||
|
||||
|
||||
@@ -197,5 +201,6 @@ class VirtualEnvReader private constructor(
|
||||
const val DEFAULT_VIRTUALENVS_DIR: String = ".virtualenvs"
|
||||
const val DEFAULT_VIRTUALENV_DIRNAME: String = ".venv"
|
||||
|
||||
private fun getLocalEelIfApp(): EelApi? = if (ApplicationManager.getApplication() != null) localEel else null
|
||||
}
|
||||
}
|
||||
@@ -1,247 +0,0 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.jetbrains.python.sdk
|
||||
|
||||
import com.intellij.grazie.grammar.assertIsEmpty
|
||||
import com.intellij.openapi.util.SystemInfoRt
|
||||
import com.intellij.openapi.util.io.FileUtilRt
|
||||
import com.intellij.testFramework.junit5.TestApplication
|
||||
import com.intellij.testFramework.utils.io.deleteRecursively
|
||||
import com.jetbrains.python.venvReader.VirtualEnvReader
|
||||
import com.jetbrains.python.venvReader.tryResolvePath
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
import org.junit.jupiter.params.provider.Arguments
|
||||
import org.junit.jupiter.params.provider.MethodSource
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.absolutePathString
|
||||
import kotlin.io.path.exists
|
||||
|
||||
@TestApplication
|
||||
class VirtualEnvReaderTest {
|
||||
inner class Bootstrap {
|
||||
val PYENV_ROOT = "PYENV_ROOT"
|
||||
|
||||
val cwd = FileUtilRt.createTempDirectory("venvreader", "").toPath()
|
||||
val pyenv = cwd.resolve(".pyenv")
|
||||
|
||||
val env = HashMap<String, String>()
|
||||
val virtualEnvReader = VirtualEnvReader(env)
|
||||
|
||||
fun setupPyenv(versions: List<String>, binary: String) {
|
||||
for (version in versions) {
|
||||
addVersion(pyenv, version, binary)
|
||||
}
|
||||
|
||||
env[PYENV_ROOT] = pyenv.absolutePathString()
|
||||
}
|
||||
|
||||
fun addVersion(root: Path, version: String, binary: String) {
|
||||
val vsdir = ensureVersions(root)
|
||||
|
||||
val vdir = vsdir.resolve(version)
|
||||
Files.createDirectory(vdir)
|
||||
|
||||
if (binary.isNotEmpty()) {
|
||||
Files.createFile(vdir.resolve(binary))
|
||||
}
|
||||
}
|
||||
|
||||
fun removeVersion(root: Path, version: String) {
|
||||
val vsdir = ensureVersions(root)
|
||||
val vdir = vsdir.resolve(version)
|
||||
|
||||
vdir.deleteRecursively()
|
||||
}
|
||||
|
||||
fun ensureVersions(root: Path): Path {
|
||||
if (!root.exists()) {
|
||||
Files.createDirectory(root);
|
||||
}
|
||||
|
||||
val versions = root.resolve("versions")
|
||||
if (!versions.exists()) {
|
||||
Files.createDirectory(versions)
|
||||
}
|
||||
|
||||
return versions
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testHandleEmptyDirs() {
|
||||
val bootstrap = Bootstrap()
|
||||
|
||||
// non existent dir
|
||||
var interpreters = bootstrap.virtualEnvReader.findLocalInterpreters(bootstrap.pyenv)
|
||||
assertIsEmpty(interpreters)
|
||||
|
||||
// invalid data
|
||||
bootstrap.env[bootstrap.PYENV_ROOT] = "aa\u0000bb"
|
||||
interpreters = bootstrap.virtualEnvReader.findPyenvInterpreters()
|
||||
assertIsEmpty(interpreters)
|
||||
|
||||
// empty dir
|
||||
interpreters = bootstrap.virtualEnvReader.findPyenvInterpreters()
|
||||
assertIsEmpty(interpreters)
|
||||
|
||||
// empty dir
|
||||
bootstrap.setupPyenv(listOf(), "")
|
||||
interpreters = bootstrap.virtualEnvReader.findPyenvInterpreters()
|
||||
assertIsEmpty(interpreters)
|
||||
|
||||
// .pyenv but no versions
|
||||
Files.createDirectory(bootstrap.pyenv)
|
||||
interpreters = bootstrap.virtualEnvReader.findPyenvInterpreters()
|
||||
assertIsEmpty(interpreters)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCollectPaths() {
|
||||
val bootstrap = Bootstrap()
|
||||
|
||||
// just version
|
||||
val binary = if (SystemInfoRt.isWindows) "python.exe" else "python"
|
||||
bootstrap.setupPyenv(listOf("3.1.1"), binary)
|
||||
var interpreters = bootstrap.virtualEnvReader.findPyenvInterpreters()
|
||||
Assertions.assertEquals(1, interpreters.size)
|
||||
assert(interpreters[0].absolutePathString().startsWith(bootstrap.pyenv.absolutePathString()))
|
||||
assert(interpreters[0].absolutePathString().endsWith(binary))
|
||||
|
||||
// another version w/o match
|
||||
bootstrap.setupPyenv(listOf("3.2.1"), "xxx")
|
||||
interpreters = bootstrap.virtualEnvReader.findPyenvInterpreters()
|
||||
Assertions.assertEquals(1, interpreters.size)
|
||||
|
||||
// both in names
|
||||
val pypyBinary = if (SystemInfoRt.isWindows) "pypy.exe" else "pypy"
|
||||
bootstrap.setupPyenv(listOf("3.2.2"), pypyBinary)
|
||||
interpreters = bootstrap.virtualEnvReader.findPyenvInterpreters()
|
||||
Assertions.assertEquals(2, interpreters.size)
|
||||
assert(interpreters[0] != interpreters[1])
|
||||
|
||||
bootstrap.removeVersion(bootstrap.pyenv, "3.2.2")
|
||||
interpreters = bootstrap.virtualEnvReader.findPyenvInterpreters()
|
||||
Assertions.assertEquals(1, interpreters.size)
|
||||
assert(interpreters[0].absolutePathString().endsWith(binary))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testIsPyenvSdk() {
|
||||
val bootstrap = Bootstrap()
|
||||
|
||||
Assertions.assertFalse(bootstrap.virtualEnvReader.isPyenvSdk(null as String?))
|
||||
Assertions.assertFalse(bootstrap.virtualEnvReader.isPyenvSdk(""))
|
||||
Assertions.assertFalse(bootstrap.virtualEnvReader.isPyenvSdk("aa\u0000bb"))
|
||||
Assertions.assertFalse(bootstrap.virtualEnvReader.isPyenvSdk("a/b/c/d"))
|
||||
Assertions.assertFalse(bootstrap.virtualEnvReader.isPyenvSdk(bootstrap.cwd))
|
||||
Assertions.assertFalse(bootstrap.virtualEnvReader.isPyenvSdk(bootstrap.cwd.resolve("smthg")))
|
||||
|
||||
bootstrap.setupPyenv(listOf("3.2.1"), "xxxx")
|
||||
|
||||
Assertions.assertFalse(bootstrap.virtualEnvReader.isPyenvSdk(null as String?))
|
||||
Assertions.assertFalse(bootstrap.virtualEnvReader.isPyenvSdk(""))
|
||||
Assertions.assertFalse(bootstrap.virtualEnvReader.isPyenvSdk("aa\u0000bb"))
|
||||
Assertions.assertFalse(bootstrap.virtualEnvReader.isPyenvSdk("a/b/c/d"))
|
||||
Assertions.assertFalse(bootstrap.virtualEnvReader.isPyenvSdk(bootstrap.cwd))
|
||||
Assertions.assertFalse(bootstrap.virtualEnvReader.isPyenvSdk(bootstrap.cwd.resolve("smthg")))
|
||||
|
||||
// particularly any path inside pyenv root will work
|
||||
Assertions.assertTrue(bootstrap.virtualEnvReader.isPyenvSdk(bootstrap.pyenv.resolve("xxx")))
|
||||
|
||||
// should resolve symlinks
|
||||
val link = bootstrap.cwd.resolve("smthg")
|
||||
val target = bootstrap.pyenv.resolve("xxx")
|
||||
|
||||
// hanging links, should not resolve it
|
||||
if (!SystemInfoRt.isWindows) {
|
||||
// links require UAC on Windows
|
||||
Files.createSymbolicLink(link, target)
|
||||
}
|
||||
Assertions.assertFalse(bootstrap.virtualEnvReader.isPyenvSdk(link))
|
||||
|
||||
if (!SystemInfoRt.isWindows) {
|
||||
Files.createFile(target)
|
||||
Assertions.assertTrue(bootstrap.virtualEnvReader.isPyenvSdk(link))
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "{0}")
|
||||
@MethodSource("getVenvRootPathTestCases")
|
||||
fun getVenvRootPathTests(name: String, isWindows: Boolean, path: Path, expectedReturnValue: Path?) {
|
||||
val result = VirtualEnvReader(isWindows = isWindows).getVenvRootPath(path)
|
||||
|
||||
Assertions.assertEquals(expectedReturnValue, result)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun getVenvRootPathTestCases(): List<Arguments> = listOf(
|
||||
GetVenvRootPathTestCase(
|
||||
"returns null when no parent is found",
|
||||
false,
|
||||
"python",
|
||||
null
|
||||
),
|
||||
|
||||
GetVenvRootPathTestCase(
|
||||
"returns null when bin dir is named Scripts on non-windows",
|
||||
false,
|
||||
"root/.venv/Scripts/python",
|
||||
null
|
||||
),
|
||||
|
||||
GetVenvRootPathTestCase(
|
||||
"returns null when bin dir is named bin on windows",
|
||||
true,
|
||||
"root/.venv/bin/python.exe",
|
||||
null
|
||||
),
|
||||
|
||||
GetVenvRootPathTestCase(
|
||||
"returns root when bin dir is named Scripts on windows",
|
||||
true,
|
||||
"root/.venv/Scripts/python.exe",
|
||||
"root"
|
||||
),
|
||||
|
||||
GetVenvRootPathTestCase(
|
||||
"returns root when bin dir is named bin on non-windows",
|
||||
false,
|
||||
"root/.venv/bin/python.exe",
|
||||
"root"
|
||||
),
|
||||
|
||||
GetVenvRootPathTestCase(
|
||||
"returns null when bin dir has no parent",
|
||||
false,
|
||||
"bin/python.exe",
|
||||
null
|
||||
),
|
||||
|
||||
GetVenvRootPathTestCase(
|
||||
"returns null when .venv dir has no parent",
|
||||
false,
|
||||
".venv/bin/python.exe",
|
||||
null
|
||||
),
|
||||
|
||||
GetVenvRootPathTestCase(
|
||||
"returns root with a custom .venv dir name",
|
||||
false,
|
||||
"root/.venv_custom/bin/python.exe",
|
||||
"root"
|
||||
),
|
||||
).map {
|
||||
Arguments.of(it.name, it.isWindows, Path.of(it.path), tryResolvePath(it.expectedReturnValue))
|
||||
}
|
||||
|
||||
data class GetVenvRootPathTestCase(
|
||||
val name: String,
|
||||
val isWindows: Boolean,
|
||||
val path: String,
|
||||
val expectedReturnValue: String?,
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user