Python: hide symbols

GitOrigin-RevId: 2653974b9d8ba190fb9a1aea8c36759e8ddc42d3
This commit is contained in:
Ilya.Kazakevich
2025-05-14 18:43:34 +02:00
committed by intellij-monorepo-bot
parent 531e3b1667
commit c16d6840e8
56 changed files with 310 additions and 124 deletions

View File

@@ -1,10 +1,8 @@
package com.jetbrains.python
import com.intellij.openapi.util.NlsSafe
import com.intellij.platform.eel.EelExecApi
import com.intellij.platform.eel.EelPlatform
import com.intellij.platform.eel.ExecuteProcessException
import com.intellij.platform.eel.getOr
import com.intellij.platform.eel.provider.getEelDescriptor
import com.intellij.platform.eel.provider.utils.EelProcessExecutionResult
import com.intellij.platform.eel.provider.utils.exec
@@ -66,12 +64,14 @@ private suspend fun PythonBinary.executeWithResult(vararg args: String): Result<
}
@RequiresBackgroundThread
@ApiStatus.Internal
fun PythonBinary.resolvePythonHome(): PythonHomePath = when (getEelDescriptor().platform) {
is EelPlatform.Windows -> parent.takeIf { it.name.lowercase() != "scripts" } ?: parent.parent
is EelPlatform.Posix -> parent.takeIf { it.name != "bin" } ?: parent.parent
}
@RequiresBackgroundThread
@ApiStatus.Internal
fun PythonHomePath.resolvePythonBinary(): PythonBinary? {
return VirtualEnvReader(isWindows = getEelDescriptor().platform is EelPlatform.Windows).findPythonInPythonRoot(this)
}

View File

@@ -8,6 +8,7 @@ import com.intellij.openapi.util.SystemInfo
import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.util.SystemProperties
import com.jetbrains.python.sdk.PythonSdkUtil
import org.jetbrains.annotations.ApiStatus
import java.nio.file.Files
import java.nio.file.Path
import kotlin.io.path.div
@@ -28,6 +29,8 @@ private const val UNIX_OPT_PATH = "/opt/"
private val LOG = Logger.getInstance("#com.jetbrains.python.packaging")
@ApiStatus.Internal
fun getCondaBasePython(systemCondaExecutable: String): String? {
val condaFile = LocalFileSystem.getInstance().findFileByPath(systemCondaExecutable)
if (condaFile != null) {
@@ -42,6 +45,8 @@ fun getCondaBasePython(systemCondaExecutable: String): String? {
private fun getPythonName(): String = if (SystemInfo.isWindows) PYTHON_EXE_NAME else PYTHON_UNIX_BINARY_NAME
@ApiStatus.Internal
fun findCondaExecutableRelativeToEnv(pyExecutable: Path): Path? {
if (!Files.exists(pyExecutable)) {
return null
@@ -112,8 +117,7 @@ private fun findExecutable(condaName: String, condaFolder: Path): Path? {
if (!Files.exists(bin)) return null
return PythonSdkUtil.getExecutablePath(bin, condaName)
}
fun getSystemCondaExecutable(): Path? {
internal fun getSystemCondaExecutable(): Path? {
val condaName = if (SystemInfo.isWindows) CONDA_BAT_NAME else CONDA_BINARY_NAME
// TODO we need another findInPath() that works with Path-s

View File

@@ -9,7 +9,7 @@ import com.intellij.openapi.util.NlsSafe;
import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.annotations.NotNull;
public class IndicatedProcessOutputListener extends ProcessAdapter {
public final class IndicatedProcessOutputListener extends ProcessAdapter {
private final @NotNull ProgressIndicator myIndicator;
public IndicatedProcessOutputListener(@NotNull ProgressIndicator indicator) {

View File

@@ -17,8 +17,11 @@ package com.jetbrains.python.sdk;
import com.intellij.openapi.util.NlsContexts.DialogMessage;
import org.jetbrains.annotations.ApiStatus;
public class InvalidSdkException extends Exception {
@ApiStatus.Internal
public final class InvalidSdkException extends Exception {
public InvalidSdkException(@DialogMessage String s) {
super(s);
}

View File

@@ -13,6 +13,8 @@ import org.jetbrains.annotations.ApiStatus.Internal
*
* This method creates new in this case, but only if an SDK flavor doesn't require special additional data.
*/
@Internal
fun Sdk.getOrCreateAdditionalData(): PythonSdkAdditionalData {
val existingData = sdkAdditionalData as? PythonSdkAdditionalData
if (existingData != null) {

View File

@@ -68,10 +68,14 @@ public final class PySdkUtil {
* @param timeout how many milliseconds to wait until the process terminates; non-positive means inifinity.
* @return a tuple of (stdout lines, stderr lines, exit_code), lines in them have line terminators stripped, or may be null.
*/
@ApiStatus.Internal
public static @NotNull ProcessOutput getProcessOutput(String homePath, @NonNls String[] command, final int timeout) {
return getProcessOutput(homePath, command, null, timeout);
}
@ApiStatus.Internal
public static @NotNull ProcessOutput getProcessOutput(String homePath,
@NonNls String[] command,
@Nullable @NonNls Map<String, String> extraEnv,
@@ -79,6 +83,8 @@ public final class PySdkUtil {
return getProcessOutput(homePath, command, extraEnv, timeout, null, true);
}
@ApiStatus.Internal
public static @NotNull ProcessOutput getProcessOutput(String homePath,
@NonNls String[] command,
@Nullable @NonNls Map<String, String> extraEnv,
@@ -88,6 +94,8 @@ public final class PySdkUtil {
return getProcessOutput(new GeneralCommandLine(command), homePath, extraEnv, timeout, stdin, needEOFMarker);
}
@ApiStatus.Internal
public static ProcessOutput getProcessOutput(@NotNull GeneralCommandLine cmd, @Nullable String homePath,
@Nullable @NonNls Map<String, String> extraEnv,
int timeout) {
@@ -101,6 +109,8 @@ public final class PySdkUtil {
return getProcessOutput(cmd, homePath, extraEnv, timeout, stdin, needEOFMarker, null);
}
@ApiStatus.Internal
public static ProcessOutput getProcessOutput(@NotNull GeneralCommandLine cmd, @Nullable String homePath,
@Nullable @NonNls Map<String, String> extraEnv,
int timeout,
@@ -244,6 +254,9 @@ public final class PySdkUtil {
/**
* @return name of builtins skeleton file; for Python 2.x it is '{@code __builtins__.py}'.
*/
@ApiStatus.Internal
public static @NotNull @NonNls String getBuiltinsFileName(@NotNull Sdk sdk) {
return PyBuiltinCache.getBuiltinsFileName(getLanguageLevelForSdk(sdk));
}
@@ -253,6 +266,7 @@ public final class PySdkUtil {
*
* @param allowRemote - indicates whether remote interpreter is acceptable
*/
@ApiStatus.Internal
public static @Nullable Sdk findSdkForDirectory(@NotNull Project project, @NotNull Path workingDirectory, boolean allowRemote) {
VirtualFile workingDirectoryVirtualFile = LocalFileSystem.getInstance().findFileByNioFile(workingDirectory);
if (workingDirectoryVirtualFile != null) {

View File

@@ -133,6 +133,7 @@ public class PythonSdkAdditionalData implements SdkAdditionalData {
}
}
@ApiStatus.Internal
public final String getAssociatedModulePath() {
return myAssociatedModulePath;
}
@@ -171,10 +172,14 @@ public class PythonSdkAdditionalData implements SdkAdditionalData {
return myFlavorAndData.getFlavor();
}
@ApiStatus.Internal
public final @NotNull PyFlavorAndData<?, ?> getFlavorAndData() {
return myFlavorAndData;
}
@ApiStatus.Internal
public static @NotNull PythonSdkAdditionalData loadFromElement(@Nullable Element element) {
final PythonSdkAdditionalData data = new PythonSdkAdditionalData();
data.load(element);
@@ -219,11 +224,14 @@ public class PythonSdkAdditionalData implements SdkAdditionalData {
}
}
@ApiStatus.Internal
public final Set<VirtualFile> getAddedPathFiles() {
return getPathsAsVirtualFiles(myAddedPaths);
}
@ApiStatus.Internal
public final Set<VirtualFile> getExcludedPathFiles() {
return getPathsAsVirtualFiles(myExcludedPaths);
}
@@ -231,6 +239,8 @@ public class PythonSdkAdditionalData implements SdkAdditionalData {
/**
* @see com.jetbrains.python.sdk.PyTransferredSdkRootsKt#getPathsToTransfer(Sdk)
*/
@ApiStatus.Internal
public final @NotNull Set<VirtualFile> getPathsToTransfer() {
return getPathsAsVirtualFiles(myPathsToTransfer);
}

View File

@@ -28,12 +28,13 @@ import java.net.URL
import java.nio.charset.StandardCharsets
val LOG: Logger = logger<Sdks>()
private val LOG: Logger = logger<Sdks>()
/**
* Currently only CPython is supported
*/
@ApiStatus.Internal
enum class Product(val title: String) {
CPython("Python"),
Miniconda("Miniconda"),
@@ -43,6 +44,7 @@ enum class Product(val title: String) {
/**
* Resource Type enum with autodetection via file extensions.
*/
@ApiStatus.Internal
enum class ResourceType(vararg val extensions: String) {
MICROSOFT_WINDOWS_EXECUTABLE("exe"),
MICROSOFT_SOFTWARE_INSTALLER("msi"),
@@ -62,6 +64,8 @@ enum class ResourceType(vararg val extensions: String) {
* Url-specified file resource. FileName and ResourceType values are calculated by the Url provided (might be declared explicitly).
* Downloaded size / sha256 should be verified to prevent consistency leaks.
*/
@ApiStatus.Internal
data class Resource(
val url: Url,
val size: Long,
@@ -75,6 +79,7 @@ data class Resource(
* Custom prepared installation packages per OS and ArchType.
* Could contain multiple resources (in case of MSI for example)
*/
@ApiStatus.Internal
data class Binary(
val os: OS,
val cpuArch: CpuArch?,
@@ -89,12 +94,13 @@ data class Binary(
* Bundle with release version of vendor. Might contain sources or any binary packages.
* Vendor + Version is a primary key.
*/
@ApiStatus.Internal
data class Release(
val version: String,
val product: Product,
val sources: List<Resource>?,
val binaries: List<Binary>?,
val title: String = "${product.title} ${version}"
val title: String = "${product.title} ${version}",
) : Comparable<Release> {
override fun compareTo(other: Release) = compareValuesBy(this, other, { it.product }, { it.version })
override fun toString(): String {
@@ -107,12 +113,14 @@ data class Release(
* Class represents /sdks.json structure with all available SDK release mappings.
* It has only python section currently.
*/
@ApiStatus.Internal
data class Sdks(
val python: List<Release> = listOf(),
val conda: List<Release> = listOf(),
)
@ApiStatus.Internal
fun Version?.toLanguageLevel(): LanguageLevel? = this?.let { LanguageLevel.fromPythonVersion("$major.$minor") }
@@ -121,12 +129,14 @@ fun Version?.toLanguageLevel(): LanguageLevel? = this?.let { LanguageLevel.fromP
*
* @see com.intellij.util.Url
*/
@ApiStatus.Internal
class UrlDeserializer : JsonDeserializer<Url>() {
override fun deserialize(p: JsonParser?, ctxt: DeserializationContext?): Url {
return Urls.parseEncoded(p!!.valueAsString)!!
}
}
@ApiStatus.Internal
class UrlSerializer : JsonSerializer<Url>() {
override fun serialize(value: Url?, gen: JsonGenerator?, serializers: SerializerProvider?) {
value?.let {
@@ -135,6 +145,8 @@ class UrlSerializer : JsonSerializer<Url>() {
}
}
@ApiStatus.Internal
object SdksKeeper {
private val configUrl: URL? = Sdks::class.java.getResource("/sdks.json")

View File

@@ -8,6 +8,7 @@ import com.sun.jna.platform.win32.Kernel32.*
import com.sun.jna.platform.win32.Ntifs
import com.sun.jna.platform.win32.WinioctlUtil
import com.sun.jna.ptr.IntByReference
import org.jetbrains.annotations.ApiStatus
import java.nio.ByteBuffer
import java.nio.file.Path
import kotlin.io.path.*
@@ -41,6 +42,8 @@ private const val storeMarker = "DesktopAppInstaller"
* There may be several files linked to this product, we need only first.
* And for 3.7 there could be ``PythonSoftwareFoundation.Python.3.7_(SOME_OTHER_UID)``.
*/
@ApiStatus.Internal
fun getAppxFiles(expectedProduct: String?, filePattern: Regex): Collection<Path> =
userAppxFolder?.listDirectoryEntries()
?.filter { filePattern.matches(it.name) }

View File

@@ -14,8 +14,14 @@ import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.util.text.StringUtil
import com.jetbrains.python.PySdkBundle
import com.jetbrains.python.packaging.*
import com.jetbrains.python.packaging.IndicatedProcessOutputListener
import com.jetbrains.python.packaging.PyCondaPackageService
import com.jetbrains.python.packaging.PyExecutionException
import com.jetbrains.python.packaging.getCondaBasePython
import com.jetbrains.python.sdk.PySdkUtil
import org.jetbrains.annotations.ApiStatus
@ApiStatus.Internal
@Deprecated("Use Sdk.configureBuilderToRunPythonOnTarget")
@Throws(ExecutionException::class)
@@ -23,6 +29,8 @@ fun runConda(condaExecutable: String, arguments: List<String>): ProcessOutput {
return run(condaExecutable, arguments, readCondaEnv(condaExecutable))
}
@ApiStatus.Internal
@Deprecated("Use Sdk.configureBuilderToRunPythonOnTarget")
@Throws(ExecutionException::class)
fun runConda(sdk: Sdk?, arguments: List<String>): ProcessOutput {
@@ -69,6 +77,8 @@ private fun ProcessOutput.checkExitCode(executable: String, arguments: List<Stri
}
}
@ApiStatus.Internal
@Deprecated("Use PyCondaEnv")
@Throws(ExecutionException::class, JsonSyntaxException::class)
fun listCondaEnvironments(condaExecutable: String): List<String> {

View File

@@ -28,12 +28,16 @@ import kotlinx.coroutines.launch
import org.jetbrains.annotations.ApiStatus
import java.net.URI
@ApiStatus.Internal
sealed class PythonPackageInstallRequest(val title: String) {
data object AllRequirements : PythonPackageInstallRequest("All Requirements")
data class ByLocation(val location: URI) : PythonPackageInstallRequest(location.toString())
data class ByRepositoryPythonPackageSpecification(val specification: PythonRepositoryPackageSpecification) : PythonPackageInstallRequest(specification.nameWithVersionSpec)
}
@ApiStatus.Internal
fun PythonRepositoryPackageSpecification.toInstallRequest(): PythonPackageInstallRequest.ByRepositoryPythonPackageSpecification {
return PythonPackageInstallRequest.ByRepositoryPythonPackageSpecification(this)
}

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
@file:JvmName("AddInterpreterActions")
package com.jetbrains.python.sdk
@@ -25,8 +25,10 @@ import com.jetbrains.python.sdk.add.v2.PythonAddLocalInterpreterDialog
import com.jetbrains.python.sdk.add.v2.PythonAddLocalInterpreterPresenter
import com.jetbrains.python.target.PythonLanguageRuntimeType
import com.jetbrains.python.util.ShowingMessageErrorSync
import org.jetbrains.annotations.ApiStatus
import java.util.function.Consumer
@ApiStatus.Internal
fun collectAddInterpreterActions(moduleOrProject: ModuleOrProject, onSdkCreated: Consumer<Sdk>): List<AnAction> {
// If module resides on this target, we can't use any target except same target and target types that explicitly allow that
// example: on ``\\wsl$`` you can only use wsl target and dockers
@@ -91,6 +93,8 @@ private class AddInterpreterOnTargetAction(
}
}
@ApiStatus.Internal
fun switchToSdk(module: Module, sdk: Sdk, currentSdk: Sdk?) {
val project = module.project
(sdk.sdkType as PythonSdkType).setupSdkPaths(sdk)

View File

@@ -1,11 +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.jetbrains.python.sdk
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.EDT
import com.intellij.openapi.application.ModalityState
import com.intellij.openapi.application.asContextElement
import com.intellij.openapi.application.writeIntentReadAction
import com.intellij.openapi.application.*
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.service
import kotlinx.coroutines.CoroutineScope
@@ -13,6 +9,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import org.jetbrains.annotations.ApiStatus
import java.util.function.Consumer
@Service
@@ -21,6 +18,8 @@ private class MyService(val coroutineScope: CoroutineScope)
/**
* collects first item of flow in EDT and calls [consumer] to be used as an adapter.
*/
@ApiStatus.Internal
internal fun <T : Any> Flow<T>.oneShotConsumer(consumer: Consumer<T>) {
ApplicationManager.getApplication().service<MyService>().coroutineScope.launch(Dispatchers.EDT + ModalityState.defaultModalityState().asContextElement()) {
// Platform doesn't guarantee write intent lock on EDT

View File

@@ -1,4 +1,4 @@
// 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.jetbrains.python.sdk;
import com.intellij.openapi.projectRoots.Sdk;
@@ -7,8 +7,11 @@ import com.intellij.remote.RemoteSdkAdditionalData;
import com.intellij.remote.ext.LanguageCaseCollector;
import com.intellij.util.ObjectUtils;
import com.jetbrains.python.remote.PyCredentialsContribution;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
@ApiStatus.Internal
public abstract class CredentialsTypeExChecker {
public boolean check(final @Nullable Sdk sdk) {
if (sdk == null) {

View File

@@ -1,4 +1,4 @@
// 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.jetbrains.python.sdk;
import com.intellij.ide.macro.Macro;
@@ -14,9 +14,11 @@ import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.PathUtil;
import com.jetbrains.python.PyBundle;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ApiStatus.Internal
public final class InterpreterDirectoryMacro extends Macro implements PathMacro {
@Override

View File

@@ -141,17 +141,25 @@ fun resetSystemWideSdksDetectors() {
PythonSdkFlavor.getApplicableFlavors(false).forEach(PythonSdkFlavor<*>::dropCaches)
}
@Internal
fun detectVirtualEnvs(module: Module?, existingSdks: List<Sdk>, context: UserDataHolder): List<PyDetectedSdk> =
filterSuggestedPaths(VirtualEnvSdkFlavor.getInstance(), existingSdks, module, context)
@Internal
fun filterSharedCondaEnvs(module: Module?, existingSdks: List<Sdk>): List<Sdk> {
return existingSdks.filter { it.sdkType is PythonSdkType && PythonSdkUtil.isConda(it) && !it.isAssociatedWithAnotherModule(module) }
}
@Internal
fun filterAssociatedSdks(module: Module, existingSdks: List<Sdk>): List<Sdk> {
return existingSdks.filter { it.sdkType is PythonSdkType && it.isAssociatedWithModule(module) }
}
@Internal
fun detectAssociatedEnvironments(module: Module, existingSdks: List<Sdk>, context: UserDataHolder): List<PyDetectedSdk> =
detectVirtualEnvs(module, existingSdks, context).filter { it.isAssociatedWithModule(module) }
@@ -164,6 +172,8 @@ fun createSdkByGenerateTask(
suggestedSdkName: String?,
): Sdk = createSdkByGenerateTask(generateSdkHomePath, existingSdks, baseSdk, associatedProjectPath, suggestedSdkName, null)
@Internal
fun createSdkByGenerateTask(
generateSdkHomePath: Task.WithResult<String, ExecutionException>,
existingSdks: List<Sdk>,
@@ -238,6 +248,8 @@ fun showSdkExecutionException(sdk: Sdk?, e: ExecutionException, @NlsContexts.Dia
}
}
@Internal
fun Sdk.isAssociatedWithModule(module: Module?): Boolean {
val basePath = module?.basePath
val associatedPath = associatedModulePath
@@ -246,6 +258,8 @@ fun Sdk.isAssociatedWithModule(module: Module?): Boolean {
return isLocatedInsideModule(module) || containsModuleName(module)
}
@Internal
fun Sdk.isAssociatedWithAnotherModule(module: Module?): Boolean {
val basePath = module?.basePath ?: return false
val associatedPath = associatedModulePath ?: return false
@@ -274,6 +288,8 @@ internal fun PyDetectedSdk.setupAssociatedLogged(existingSdks: List<Sdk>, associ
return setupAssociated(existingSdks, associatedModulePath, doAssociate).getOrLogException(LOGGER)
}
@Internal
fun PyDetectedSdk.setupAssociated(existingSdks: List<Sdk>, associatedModulePath: String?, doAssociate: Boolean): Result<Sdk> {
if (!sdkSeemsValid) {
return failure("sdk is not valid")
@@ -343,6 +359,8 @@ var Project.pythonSdk: Sdk?
}
}
@Internal
fun Module.excludeInnerVirtualEnv(sdk: Sdk) {
val root = getInnerVirtualEnvRoot(sdk) ?: return
@@ -366,6 +384,8 @@ fun Project.excludeInnerVirtualEnv(sdk: Sdk) {
ModuleUtil.findModuleForFile(binary, this)?.excludeInnerVirtualEnv(sdk)
}
@Internal
fun getInnerVirtualEnvRoot(sdk: Sdk): VirtualFile? {
val binaryPath = sdk.homePath ?: return null
@@ -416,6 +436,8 @@ private val Sdk.sitePackagesDirectory: VirtualFile?
val Sdk.sdkFlavor: PythonSdkFlavor<*> get() = getOrCreateAdditionalData().flavor
@Internal
fun Sdk.isLocatedInsideModule(module: Module?): Boolean {
val moduleDir = module?.baseDir
val sdkDir = homeDirectory
@@ -504,6 +526,8 @@ val Sdk.remoteSourcesLocalPath: Path
/**
* Configures [targetCommandLineBuilder] (sets a binary path and other stuff) so it could run python on this target
*/
@Internal
fun Sdk.configureBuilderToRunPythonOnTarget(targetCommandLineBuilder: TargetedCommandLineBuilder) {
getOrCreateAdditionalData().flavorAndData.data.prepareTargetCommandLine(this, targetCommandLineBuilder)
}

View File

@@ -1,18 +1,4 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the 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.jetbrains.python.sdk
import com.intellij.openapi.projectRoots.Sdk
@@ -23,8 +9,10 @@ import org.jetbrains.annotations.Nls
import java.awt.Component
import javax.swing.JList
open class PySdkListCellRenderer @JvmOverloads constructor(@Nls private val nullSdkName: String = noInterpreterMarker,
private val nullSdkValue: Sdk? = null) : ColoredListCellRenderer<Any>() {
class PySdkListCellRenderer @JvmOverloads constructor(
@Nls private val nullSdkName: String = noInterpreterMarker,
private val nullSdkValue: Sdk? = null,
) : ColoredListCellRenderer<Any>() {
override fun getListCellRendererComponent(list: JList<out Any>?, value: Any?, index: Int, selected: Boolean,
hasFocus: Boolean): Component =

View File

@@ -1,4 +1,4 @@
// 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.
// 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.sdk
import com.intellij.icons.AllIcons
@@ -13,16 +13,21 @@ import com.intellij.ui.SimpleTextAttributes
import com.jetbrains.python.PyBundle
import com.jetbrains.python.psi.LanguageLevel
import com.jetbrains.python.sdk.flavors.PythonSdkFlavor
import org.jetbrains.annotations.ApiStatus
import org.jetbrains.annotations.Nls
import javax.swing.Icon
val noInterpreterMarker: String = "<${PyBundle.message("python.sdk.there.is.no.interpreter")}>"
@ApiStatus.Internal
fun name(sdk: Sdk): Triple<String?, String, String?> = name(sdk, sdk.name)
/**
* Returns modifier that shortly describes that is wrong with passed [sdk], [name] and additional info.
*/
@ApiStatus.Internal
fun name(sdk: Sdk, name: String): Triple<String?, String, String?> {
val modifier = when {
!sdk.sdkSeemsValid || PythonSdkType.hasInvalidRemoteCredentials(sdk) -> "invalid"
@@ -47,6 +52,8 @@ fun name(sdk: Sdk, name: String): Triple<String?, String, String?> {
*
* @see FileUtil.getLocationRelativeToUserHome
*/
@ApiStatus.Internal
fun path(sdk: Sdk): @NlsSafe String? {
val name = sdk.name
val homePath = sdk.homePath ?: return null
@@ -73,6 +80,8 @@ fun path(sdk: Sdk): @NlsSafe String? {
* @see PythonSdkType.hasInvalidRemoteCredentials
* @see LanguageLevel.SUPPORTED_LEVELS
*/
@ApiStatus.Internal
fun icon(sdk: Sdk): Icon {
val flavor: PythonSdkFlavor<*> = sdk.getOrCreateAdditionalData().flavor
@@ -104,6 +113,8 @@ fun icon(sdk: Sdk): Icon {
* @see PythonSdkUtil.isRemote
* @see PyRenderedSdkType
*/
@ApiStatus.Internal
fun groupModuleSdksByTypes(allSdks: List<Sdk>, module: Module?, invalid: (Sdk) -> Boolean): Map<PyRenderedSdkType, List<Sdk>> {
return allSdks
.asSequence()
@@ -122,6 +133,8 @@ fun groupModuleSdksByTypes(allSdks: List<Sdk>, module: Module?, invalid: (Sdk) -
*
* @see groupModuleSdksByTypes
*/
@ApiStatus.Internal
enum class PyRenderedSdkType {
VIRTUALENV, SYSTEM, REMOTE
}

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2021 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.
// 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.sdk
import com.intellij.execution.ExecutionException
@@ -12,9 +12,15 @@ import com.intellij.openapi.project.Project
import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.util.Disposer
import com.jetbrains.python.PythonHelper
import com.jetbrains.python.run.*
import com.jetbrains.python.run.PythonInterpreterTargetEnvironmentFactory
import com.jetbrains.python.run.buildTargetedCommandLine
import com.jetbrains.python.run.execute
import com.jetbrains.python.run.prepareHelperScriptExecution
import com.jetbrains.python.run.target.HelpersAwareTargetEnvironmentRequest
import com.jetbrains.python.sdk.flavors.PythonSdkFlavor
import org.jetbrains.annotations.ApiStatus
@ApiStatus.Internal
class PyTargetsIntrospectionFacade(val sdk: Sdk, val project: Project) {
private val pyRequest: HelpersAwareTargetEnvironmentRequest =
@@ -34,7 +40,7 @@ class PyTargetsIntrospectionFacade(val sdk: Sdk, val project: Project) {
// PythonExecution doesn't support launching a bare interpreter without a script or module
val cmdBuilder = TargetedCommandLineBuilder(targetEnvRequest)
sdk.configureBuilderToRunPythonOnTarget(cmdBuilder)
val sdkFlavor = sdk.sdkFlavor
sdk.sdkFlavor
cmdBuilder.addParameter(PythonSdkFlavor.PYTHON_VERSION_ARG)
val cmd = cmdBuilder.build()

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2021 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.
// 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.sdk
import com.google.gson.Gson
@@ -32,6 +32,7 @@ import com.jetbrains.python.run.target.HelpersAwareTargetEnvironmentRequest
import com.jetbrains.python.target.PyTargetAwareAdditionalData
import com.jetbrains.python.target.PyTargetAwareAdditionalData.Companion.pathsAddedByUser
import com.jetbrains.python.target.PyTargetAwareAdditionalData.Companion.pathsRemovedByUser
import org.jetbrains.annotations.ApiStatus
import java.nio.file.Files
import java.nio.file.attribute.FileTime
import java.nio.file.attribute.PosixFilePermissions
@@ -43,6 +44,8 @@ import kotlin.io.path.setPosixFilePermissions
private const val STATE_FILE = ".state.json"
@ApiStatus.Internal
class PyTargetsRemoteSourcesRefresher(val sdk: Sdk, private val project: Project) {
private val pyRequest: HelpersAwareTargetEnvironmentRequest =
checkNotNull(PythonInterpreterTargetEnvironmentFactory.findPythonTargetInterpreter(sdk, project))

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// 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.sdk
import com.google.common.collect.MultimapBuilder
@@ -16,10 +16,13 @@ import com.intellij.openapi.util.registry.Registry
import com.intellij.openapi.vfs.VfsUtil
import com.intellij.openapi.vfs.VirtualFile
import com.jetbrains.python.psi.PyUtil
import org.jetbrains.annotations.ApiStatus
/**
* Applies [transferRoots] to all modules having [sdk] as a python sdk.
*/
@ApiStatus.Internal
fun transferRootsToModulesWithSdk(project: Project, sdk: Sdk) {
updateRootsForModulesWithSdk(project, sdk, ::transferRoots)
}
@@ -27,6 +30,8 @@ fun transferRootsToModulesWithSdk(project: Project, sdk: Sdk) {
/**
* See [transferRootsToModulesWithSdk] and [removeTransferredRoots].
*/
@ApiStatus.Internal
fun removeTransferredRootsFromModulesWithSdk(project: Project, sdk: Sdk) {
updateRootsForModulesWithSdk(project, sdk, ::removeTransferredRoots)
}
@@ -44,6 +49,8 @@ private fun updateRootsForModulesWithSdk(project: Project, sdk: Sdk?, action: (M
/**
* Applies [transferRoots] to all modules inheriting python sdk from the [project].
*/
@ApiStatus.Internal
fun transferRootsToModulesWithInheritedSdk(project: Project, sdk: Sdk?) {
updateRootsForModulesWithInheritedSdk(project, sdk, ::transferRoots)
}
@@ -51,6 +58,8 @@ fun transferRootsToModulesWithInheritedSdk(project: Project, sdk: Sdk?) {
/**
* See [transferRootsToModulesWithInheritedSdk] and [removeTransferredRoots].
*/
@ApiStatus.Internal
fun removeTransferredRootsFromModulesWithInheritedSdk(project: Project, sdk: Sdk?) {
updateRootsForModulesWithInheritedSdk(project, sdk, ::removeTransferredRoots)
}
@@ -59,10 +68,14 @@ fun removeTransferredRootsFromModulesWithInheritedSdk(project: Project, sdk: Sdk
* Returns [sdk] paths that are located under project modules and hence should be turned into source roots,
* at least to avoid enabling reader mode for them.
*/
@ApiStatus.Internal
fun getPathsToTransfer(sdk: Sdk): Set<VirtualFile> {
return (sdk.sdkAdditionalData as? PythonSdkAdditionalData)?.pathsToTransfer ?: emptySet()
}
@ApiStatus.Internal
fun setPathsToTransfer(sdk: Sdk, roots: Set<VirtualFile>) {
runInEdt {
if (roots.isNotEmpty() || getPathsToTransfer(sdk).isNotEmpty()) { // do not create additional data with no reason
@@ -78,6 +91,8 @@ fun setPathsToTransfer(sdk: Sdk, roots: Set<VirtualFile>) {
/**
* Turns [getPathsToTransfer] result into [module] source roots and dependencies if [module] python sdk is [sdk].
*/
@ApiStatus.Internal
fun transferRoots(module: Module, sdk: Sdk?) {
if (sdk != null && module.pythonSdk == sdk) {
runInEdt {
@@ -98,6 +113,8 @@ private fun addTransferredRoots(module: Module, newTransferredRoots: ModuleTrans
/**
* Removes [getPathsToTransfer] result from [module] source roots and dependencies if [module] python sdk is [sdk].
*/
@ApiStatus.Internal
fun removeTransferredRoots(module: Module, sdk: Sdk?) {
if (sdk != null && module.pythonSdk == sdk) {
runInEdt {
@@ -115,6 +132,8 @@ private fun removeTransferredRoots(module: Module, newTransferredRoots: ModuleTr
PyUtil.removeModuleDependencies(module, newTransferredRoots.dependencies)
}
@ApiStatus.Internal
fun updateTransferredRoots(project: Project, sdk: Sdk, newInProjectPaths: Set<VirtualFile>) {
val rootsDetector = TransferredRootsDetector(project)
val modulesWithThisSdk = rootsDetector.projectModules.filter { it.pythonSdk == sdk }

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2020 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.
// 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.sdk;
import com.intellij.openapi.actionSystem.ActionUpdateThread;
@@ -10,8 +10,11 @@ import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
@ApiStatus.Internal
public class PyUpdateProjectSdkAction extends DumbAwareAction {
private static final Logger LOG = Logger.getInstance(PyUpdateProjectSdkAction.class);

View File

@@ -1,4 +1,4 @@
// 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.jetbrains.python.sdk
import com.intellij.openapi.application.runReadAction
@@ -17,7 +17,7 @@ import com.intellij.ui.dsl.builder.Panel
import com.intellij.ui.dsl.builder.bindSelected
import com.jetbrains.python.PyBundle
class PyVirtualEnvVcsCustomizer : VcsEnvCustomizer() {
internal class PyVirtualEnvVcsCustomizer : VcsEnvCustomizer() {
override fun customizeCommandAndEnvironment(project: Project?, envs: MutableMap<String, String>, context: VcsExecutableContext) {
if (project == null || !PyVirtualEnvVcsSettings.getInstance(project).virtualEnvActivate) return

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2023 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.jetbrains.python.sdk
import com.intellij.openapi.application.ApplicationManager
@@ -10,9 +10,12 @@ import com.intellij.openapi.startup.ProjectActivity
import com.intellij.openapi.util.text.StringUtil
import com.jetbrains.python.PyBundle
import kotlinx.coroutines.delay
import org.jetbrains.annotations.ApiStatus
import kotlin.time.Duration.Companion.seconds
class PythonHeadlessSdkUpdater : ProjectActivity, DumbAware {
@ApiStatus.Internal
internal class PythonHeadlessSdkUpdater : ProjectActivity, DumbAware {
private val DELAY = 10.seconds
companion object {

View File

@@ -1,12 +1,15 @@
// Copyright 2000-2022 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.jetbrains.python.sdk
import com.google.gson.*
import org.jetbrains.annotations.ApiStatus
import java.lang.reflect.Type
/**
* Mark sealed class to serialize automatically each inheritor
*/
@ApiStatus.Internal
class SealedClassAdapter : JsonSerializer<Any>, JsonDeserializer<Any> {
private companion object {
const val sealedClassChildId = "sealedClassChildId"

View File

@@ -1,41 +0,0 @@
// Copyright 2000-2023 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.execution.target.TargetEnvironmentConfiguration
import com.intellij.openapi.util.Key
import com.intellij.openapi.util.UserDataHolder
import com.intellij.openapi.util.UserDataHolderBase
val TARGET_CONTEXTS_KEY = Key.create<TargetStorage>("TARGET_CONTEXTS")
fun <T> UserDataHolder.getUserData(configuration: TargetEnvironmentConfiguration?, key: Key<T>): T? {
val targetStorage = getUserData(TARGET_CONTEXTS_KEY) ?: TargetStorage().also { putUserData(TARGET_CONTEXTS_KEY, it) }
return targetStorage.getUserData(configuration, key)
}
fun <T> UserDataHolder.putUserData(configuration: TargetEnvironmentConfiguration?, key: Key<T>, value: T?) {
val targetStorage = getUserData(TARGET_CONTEXTS_KEY) ?: TargetStorage().also { putUserData(TARGET_CONTEXTS_KEY, it) }
targetStorage.putUserData(configuration, key, value)
}
/**
* This class stores information for a specific target.
*/
class TargetStorage {
private val context = mutableMapOf<Id, UserDataHolder>()
fun <T> getUserData(configuration: TargetEnvironmentConfiguration?, key: Key<T>): T? = context[configuration.getId()]?.getUserData(key)
fun <T> putUserData(configuration: TargetEnvironmentConfiguration?, key: Key<T>, value: T?): Unit =
context.computeIfAbsent(configuration.getId()) { UserDataHolderBase() }.putUserData(key, value)
private sealed class Id
private data object LocalMachineId : Id()
private data class TargetId(val id: String) : Id()
companion object {
private fun TargetEnvironmentConfiguration?.getId() = if (this == null) LocalMachineId else TargetId(uuid)
}
}

View File

@@ -1,10 +1,13 @@
// Copyright 2000-2023 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.jetbrains.python.sdk.add.collector
import com.intellij.internal.statistic.eventLog.EventLogGroup
import com.intellij.internal.statistic.service.fus.collectors.CounterUsagesCollector
import com.intellij.openapi.projectRoots.Sdk
import com.jetbrains.python.statistics.*
import org.jetbrains.annotations.ApiStatus
@ApiStatus.Internal
object PythonNewInterpreterAddedCollector : CounterUsagesCollector() {

View File

@@ -0,0 +1,5 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
@ApiStatus.Internal
package com.jetbrains.python.sdk.add.v2.conda;
import org.jetbrains.annotations.ApiStatus;

View File

@@ -0,0 +1,5 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
@ApiStatus.Internal
package com.jetbrains.python.sdk.add.v2.hatch;
import org.jetbrains.annotations.ApiStatus;

View File

@@ -0,0 +1,5 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
@ApiStatus.Internal
package com.jetbrains.python.sdk.add.v2.poetry;
import org.jetbrains.annotations.ApiStatus;

View File

@@ -0,0 +1,5 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
@ApiStatus.Internal
package com.jetbrains.python.sdk.add.v2.uv;
import org.jetbrains.annotations.ApiStatus;

View File

@@ -0,0 +1,5 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
@ApiStatus.Internal
package com.jetbrains.python.sdk.conda;
import org.jetbrains.annotations.ApiStatus;

View File

@@ -0,0 +1,5 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
@ApiStatus.Internal
package com.jetbrains.python.sdk.configuration;
import org.jetbrains.annotations.ApiStatus;

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2021 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.
// 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.sdk.flavors;
import com.intellij.execution.ExecutionException;
@@ -16,6 +16,7 @@ import com.intellij.openapi.util.text.HtmlChunk;
import com.intellij.util.concurrency.annotations.RequiresBackgroundThread;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.sdk.PyDetectedSdk;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -28,6 +29,7 @@ import java.util.Set;
import static com.intellij.openapi.util.text.HtmlChunk.raw;
import static com.intellij.openapi.util.text.HtmlChunk.text;
@ApiStatus.Internal
public final class MacPythonSdkFlavor extends CPythonSdkFlavor<PyFlavorData.Empty> {

View File

@@ -1,10 +1,13 @@
// Copyright 2000-2020 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.
// 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.sdk.flavors
import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.annotations.ApiStatus
import java.io.File
@ApiStatus.Internal
class MayaSdkFlavor private constructor() : CPythonSdkFlavor<PyFlavorData.Empty>() {
override fun getFlavorDataClass(): Class<PyFlavorData.Empty> = PyFlavorData.Empty::class.java

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2021 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.
// 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.sdk.flavors;
import com.google.common.collect.Sets;
@@ -19,6 +19,8 @@ import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@ApiStatus.Internal
public final class UnixPythonSdkFlavor extends CPythonSdkFlavor<PyFlavorData.Empty> {
private static final String[] BIN_DIRECTORIES = new String[]{"/usr/bin", "/usr/local/bin"};
@@ -55,9 +57,7 @@ public final class UnixPythonSdkFlavor extends CPythonSdkFlavor<PyFlavorData.Emp
public static @NotNull List<Path> getDefaultUnixPythons(@Nullable Path rootPath) {
var candidates = new ArrayList<Path>();
Arrays.stream(BIN_DIRECTORIES)
.map(Path::of)
.map(binDirectory -> optionallyChangeRoot(rootPath, binDirectory))
Arrays.stream(BIN_DIRECTORIES).map(Path::of).map(binDirectory -> optionallyChangeRoot(rootPath, binDirectory))
.forEach(rootDir -> collectUnixPythons(rootDir, candidates));
collectPyenvPythons(candidates);
@@ -73,10 +73,7 @@ public final class UnixPythonSdkFlavor extends CPythonSdkFlavor<PyFlavorData.Emp
public static void collectUnixPythons(@NotNull Path binDirectory, @NotNull Collection<Path> candidates) {
try (var entries = Files.list(binDirectory)) {
// Hack to exclude system python2
entries
.filter(path ->
ContainerUtil.exists(SYS_PYTHON_FILE_NAMES, regex -> regex.matcher(path.getFileName().toString()).matches())
)
entries.filter(path -> ContainerUtil.exists(SYS_PYTHON_FILE_NAMES, regex -> regex.matcher(path.getFileName().toString()).matches()))
.collect(Collectors.toCollection(() -> candidates));
}
catch (IOException ignored) {

View File

@@ -1,4 +1,4 @@
// 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.jetbrains.python.sdk.flavors;
import com.intellij.openapi.application.ReadAction;
@@ -13,6 +13,7 @@ import com.jetbrains.python.sdk.BasePySdkExtKt;
import com.jetbrains.python.sdk.PySdkExtKt;
import com.jetbrains.python.sdk.PythonSdkUtil;
import com.jetbrains.python.venvReader.VirtualEnvReader;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -24,6 +25,8 @@ import java.util.Collection;
/**
* User : catherine
*/
@ApiStatus.Internal
public final class VirtualEnvSdkFlavor extends CPythonSdkFlavor<PyFlavorData.Empty> {
private VirtualEnvSdkFlavor() {
}

View File

@@ -34,6 +34,8 @@ import static com.jetbrains.python.venvReader.ResolveUtilKt.tryResolvePath;
* This class knows how to find python in Windows Registry according to
* <a href="https://www.python.org/dev/peps/pep-0514/">PEP 514</a>
*/
@ApiStatus.Internal
public class WinPythonSdkFlavor extends CPythonSdkFlavor<PyFlavorData.Empty> {
private static final @NotNull String[] REG_ROOTS = {"HKEY_LOCAL_MACHINE", "HKEY_CURRENT_USER"};
/**

View File

@@ -1,27 +1,16 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the 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.jetbrains.python.sdk.flavors
import com.intellij.openapi.util.io.WindowsRegistryUtil
import org.jetbrains.annotations.ApiStatus
/**
* Win registry access service
*
* @author Ilya.Kazakevich
*/
@ApiStatus.Internal
interface WinRegistryService {
/**
* @param basePath path like "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node"
@@ -36,7 +25,7 @@ interface WinRegistryService {
fun getDefaultKey(path: String): String?
}
class WinRegistryServiceImpl : WinRegistryService {
internal class WinRegistryServiceImpl : WinRegistryService {
override fun listBranches(basePath: String): List<String> = WindowsRegistryUtil.readRegistryBranch(basePath)
override fun getDefaultKey(path: String): String? = WindowsRegistryUtil.readRegistryDefault(path)

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2022 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.jetbrains.python.sdk.flavors.conda
import com.intellij.execution.Platform
@@ -9,6 +9,7 @@ import com.intellij.openapi.projectRoots.Sdk
import com.intellij.util.EnvReader
import com.jetbrains.python.sdk.PySdkUtil
import com.jetbrains.python.sdk.getOrCreateAdditionalData
import org.jetbrains.annotations.ApiStatus
import java.io.IOException
import java.nio.file.Path
import kotlin.io.path.exists
@@ -24,7 +25,7 @@ private val LOG = Logger.getInstance("CondaLogger")
*
* Non-conda, non-local and non-windows command lines are silently ignored
* */
@ApiStatus.Internal
fun TargetedCommandLineBuilder.fixCondaPathEnvIfNeeded(sdk: Sdk) {
if (!localOnWindows) return
val condaData = (sdk.getOrCreateAdditionalData().flavorAndData.data as? PyCondaFlavorData) ?: return
@@ -36,6 +37,8 @@ fun TargetedCommandLineBuilder.fixCondaPathEnvIfNeeded(sdk: Sdk) {
addEnvVars(PySdkUtil.activateVirtualEnv(sdk), condaData.env.fullCondaPathOnTarget)
}
@ApiStatus.Internal
fun TargetedCommandLineBuilder.fixCondaPathEnvIfNeeded(condaPathOnTarget: FullPathOnTarget) {
if (!localOnWindows) return
val condaPath = Path.of(condaPathOnTarget)

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2022 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.jetbrains.python.sdk.flavors.conda
import com.intellij.execution.target.TargetedCommandLineBuilder
@@ -6,6 +6,7 @@ import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.util.registry.Registry
import com.jetbrains.python.packaging.getCondaBasePython
import org.jetbrains.annotations.ApiStatus
import java.nio.file.Path
import kotlin.io.path.isExecutable
@@ -21,6 +22,8 @@ val usePythonForLocalConda: Boolean get() = Registry.`is`("use.python.for.local.
* For the legacy it either takes homePath from [sdk] or base conda but from the base env only.
* So, you should provide sdk or (if you do not have it) base conda env. Otherwise, fallbacks to "conda run" even in legacy mode
*/
@ApiStatus.Internal
fun addCondaPythonToTargetCommandLine(targetedCommandLineBuilder: TargetedCommandLineBuilder,
condaEnv: PyCondaEnv,
sdk: Sdk?) {

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2023 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.jetbrains.python.sdk.flavors.conda
import com.intellij.execution.process.*
@@ -15,7 +15,7 @@ import kotlin.coroutines.CoroutineContext
*
* You could either start [ProcessHandler.startNotify] manually, use constructor that wraps process or use [runProcessAndGetError].
*/
class ProcessHandlerReader(processHandler: ProcessHandler) {
internal class ProcessHandlerReader(processHandler: ProcessHandler) {
private val stdOutImpl: Channel<String> = Channel()
private val stdErrImpl: Channel<String> = Channel()
private val processResult: Channel<Int> = Channel()

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2022 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.jetbrains.python.sdk.flavors.conda
import com.intellij.execution.target.*
@@ -8,10 +8,13 @@ import com.intellij.util.concurrency.annotations.RequiresBackgroundThread
import com.jetbrains.python.pathValidation.PlatformAndRoot.Companion.getPlatformAndRoot
import com.jetbrains.python.pathValidation.ValidationRequest
import com.jetbrains.python.pathValidation.validateExecutableFile
import org.jetbrains.annotations.ApiStatus
/**
* Encapsulates conda binary command to simplify target request creation
*/
@ApiStatus.Internal
class PyCondaCommand(
val fullCondaPathOnTarget: FullPathOnTarget,
internal val targetConfig: TargetEnvironmentConfiguration?,

View File

@@ -27,6 +27,8 @@ import kotlin.io.path.exists
* TODO: Once we get rid of [TargetCommandExecutor] and have access to [com.intellij.execution.target.TargetEnvironmentConfiguration] use it validate conda binary in [getEnvs]
* @see `PyCondaTest`
*/
@ApiStatus.Internal
data class PyCondaEnv(
val envIdentity: PyCondaEnvIdentity,
val fullCondaPathOnTarget: FullPathOnTarget,

View File

@@ -1,15 +1,17 @@
// Copyright 2000-2022 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.jetbrains.python.sdk.flavors.conda
import com.google.gson.annotations.JsonAdapter
import com.intellij.execution.target.FullPathOnTarget
import com.jetbrains.python.sdk.SealedClassAdapter
import org.jetbrains.annotations.ApiStatus
/**
* Conda environment could be either named or unnamed (based on path).
* [userReadableName] used as sdk name
*/
@ApiStatus.Internal
@JsonAdapter(SealedClassAdapter::class)
sealed class PyCondaEnvIdentity(val userReadableName: String) {

View File

@@ -1,9 +1,12 @@
// Copyright 2000-2022 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.jetbrains.python.sdk.flavors.conda
import com.intellij.execution.target.TargetedCommandLineBuilder
import com.intellij.openapi.projectRoots.Sdk
import com.jetbrains.python.sdk.flavors.PyFlavorData
import org.jetbrains.annotations.ApiStatus
@ApiStatus.Internal
data class PyCondaFlavorData(val env: PyCondaEnv) : PyFlavorData {
override fun prepareTargetCommandLine(sdk: Sdk, targetCommandLineBuilder: TargetedCommandLineBuilder) {

View File

@@ -0,0 +1,5 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
@ApiStatus.Internal
package com.jetbrains.python.sdk.pipenv;
import org.jetbrains.annotations.ApiStatus;

View File

@@ -0,0 +1,5 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
@ApiStatus.Internal
package com.jetbrains.python.sdk.pipenv.quickFixes;
import org.jetbrains.annotations.ApiStatus;

View File

@@ -0,0 +1,5 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
@ApiStatus.Internal
package com.jetbrains.python.sdk.pipenv.ui;
import org.jetbrains.annotations.ApiStatus;

View File

@@ -0,0 +1,5 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
@ApiStatus.Internal
package com.jetbrains.python.sdk.poetry.quickFixes;
import org.jetbrains.annotations.ApiStatus;

View File

@@ -0,0 +1,5 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
@ApiStatus.Internal
package com.jetbrains.python.sdk.poetry.ui;
import org.jetbrains.annotations.ApiStatus;

View File

@@ -0,0 +1,5 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
@ApiStatus.Internal
package com.jetbrains.python.sdk.skeletons;
import org.jetbrains.annotations.ApiStatus;

View File

@@ -0,0 +1,5 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
@ApiStatus.Internal
package com.jetbrains.python.sdk.uv.impl;
import org.jetbrains.annotations.ApiStatus;

View File

@@ -0,0 +1,5 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
@ApiStatus.Internal
package com.jetbrains.python.sdk.uv;
import org.jetbrains.annotations.ApiStatus;

View File

@@ -0,0 +1,5 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
@ApiStatus.Internal
package com.jetbrains.python.sdk.uv.run;
import org.jetbrains.annotations.ApiStatus;

View File

@@ -0,0 +1,5 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
@ApiStatus.Internal
package com.jetbrains.python.sdk.uv.ui;
import org.jetbrains.annotations.ApiStatus;