From 967119e85f90e7fda745217eba496ea42619424d Mon Sep 17 00:00:00 2001 From: Vladimir Koshelev Date: Thu, 20 Jul 2023 10:51:32 +0200 Subject: [PATCH] [python] add fus events for creating python project and adding python interpreter PY-61461 GitOrigin-RevId: daa2356f445485651eb563d8abd18f48a709d124 --- .../steps/PythonGenerateProjectCallback.java | 1 + .../newProject/PyNewProjectSettings.java | 12 ++++ python/src/META-INF/python-core-common.xml | 2 + .../newProject/PythonProjectGenerator.java | 20 +++++- .../PythonNewProjectWizardCollector.kt | 50 +++++++++++++ .../steps/ProjectSpecificSettingsStep.java | 8 +++ .../newProject/steps/PyAddExistingSdkPanel.kt | 10 ++- .../steps/PyAddNewEnvironmentPanel.kt | 5 ++ .../python/sdk/AddInterpreterActions.kt | 32 +++++---- .../python/sdk/add/PyAddNewCondaEnvPanel.kt | 11 +++ .../python/sdk/add/PyAddNewVirtualEnvPanel.kt | 11 +++ .../jetbrains/python/sdk/add/PyAddSdkPanel.kt | 3 + .../PythonNewInterpreterAddedCollector.kt | 37 ++++++++++ .../python/sdk/pipenv/PyAddPipEnvPanel.kt | 11 +++ .../python/sdk/poetry/PyAddNewPoetryPanel.kt | 11 +++ .../python/statistics/PyStatisticTools.kt | 72 ++++++++++++++----- 16 files changed, 265 insertions(+), 31 deletions(-) create mode 100644 python/src/com/jetbrains/python/newProject/collector/PythonNewProjectWizardCollector.kt create mode 100644 python/src/com/jetbrains/python/sdk/add/collector/PythonNewInterpreterAddedCollector.kt diff --git a/python/ide/impl/src/com/jetbrains/python/newProject/steps/PythonGenerateProjectCallback.java b/python/ide/impl/src/com/jetbrains/python/newProject/steps/PythonGenerateProjectCallback.java index 6ec7c97534f8..478ebe38c6d9 100644 --- a/python/ide/impl/src/com/jetbrains/python/newProject/steps/PythonGenerateProjectCallback.java +++ b/python/ide/impl/src/com/jetbrains/python/newProject/steps/PythonGenerateProjectCallback.java @@ -91,6 +91,7 @@ public class PythonGenerateProjectCallback extends AbstractNewProjectStep.Abs } if (projectSettings instanceof PyNewProjectSettings newProjectSettings) { newProjectSettings.setSdk(settingsStep.getSdk()); + newProjectSettings.setInterpreterInfoForStatistics(settingsStep.getInterpreterInfoForStatistics()); newProjectSettings.setInstallFramework(settingsStep.installFramework()); newProjectSettings.setRemotePath(settingsStep.getRemotePath()); } diff --git a/python/openapi/src/com/jetbrains/python/newProject/PyNewProjectSettings.java b/python/openapi/src/com/jetbrains/python/newProject/PyNewProjectSettings.java index 105d6f7ecb7d..5c479e1ac5b4 100644 --- a/python/openapi/src/com/jetbrains/python/newProject/PyNewProjectSettings.java +++ b/python/openapi/src/com/jetbrains/python/newProject/PyNewProjectSettings.java @@ -32,6 +32,9 @@ public class PyNewProjectSettings { @Nullable private String myRemotePath; + @Nullable + private Object myInterpreterInfoForStatistics; + @Nullable public final Sdk getSdk() { return mySdk; @@ -53,6 +56,15 @@ public class PyNewProjectSettings { myRemotePath = remotePath; } + public final void setInterpreterInfoForStatistics(@Nullable Object interpreterInfoForStatistics) { + myInterpreterInfoForStatistics = interpreterInfoForStatistics; + } + + @Nullable + public final Object getInterpreterInfoForStatistics() { + return myInterpreterInfoForStatistics; + } + @Nullable public final String getRemotePath() { return myRemotePath; diff --git a/python/src/META-INF/python-core-common.xml b/python/src/META-INF/python-core-common.xml index ecd9e9726bc4..a9e97602d4a0 100644 --- a/python/src/META-INF/python-core-common.xml +++ b/python/src/META-INF/python-core-common.xml @@ -425,6 +425,8 @@ + + diff --git a/python/src/com/jetbrains/python/newProject/PythonProjectGenerator.java b/python/src/com/jetbrains/python/newProject/PythonProjectGenerator.java index 94a9574d012a..9b547fecbfdb 100644 --- a/python/src/com/jetbrains/python/newProject/PythonProjectGenerator.java +++ b/python/src/com/jetbrains/python/newProject/PythonProjectGenerator.java @@ -22,7 +22,10 @@ import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; -import com.intellij.openapi.progress.*; +import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil; @@ -35,11 +38,17 @@ import com.intellij.util.BooleanFunction; import com.intellij.util.containers.ContainerUtil; import com.jetbrains.python.PyBundle; import com.jetbrains.python.PyPsiPackageUtil; -import com.jetbrains.python.packaging.*; +import com.jetbrains.python.newProject.collector.InterpreterStatisticsInfo; +import com.jetbrains.python.newProject.collector.PythonNewProjectWizardCollector; +import com.jetbrains.python.packaging.PyPackage; +import com.jetbrains.python.packaging.PyPackageManager; +import com.jetbrains.python.packaging.PyPackageUtil; +import com.jetbrains.python.packaging.PyPackagesNotificationPanel; import com.jetbrains.python.packaging.ui.PyPackageManagementService; import com.jetbrains.python.remote.*; import com.jetbrains.python.sdk.PyLazySdk; import com.jetbrains.python.sdk.PythonSdkUtil; +import com.jetbrains.python.statistics.PyStatisticToolsKt; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -50,6 +59,7 @@ import java.util.Collections; import java.util.List; import java.util.function.Consumer; + /** * This class encapsulates remote settings, so one should extend it for any python project that supports remote generation, at least * Instead of {@link #generateProject(Project, VirtualFile, PyNewProjectSettings, Module)} inheritor shall use @@ -195,6 +205,12 @@ public abstract class PythonProjectGenerator ext } configureProject(project, baseDir, settings, module, synchronizer); + var statisticsInfo = settings.getInterpreterInfoForStatistics(); + if (statisticsInfo instanceof InterpreterStatisticsInfo interpreterStatisticsInfo) { + PythonNewProjectWizardCollector.Companion.logPythonNewProjectGenerated(interpreterStatisticsInfo, + PyStatisticToolsKt.getVersion(settings.getSdk()), + this.getClass()); + } } /** diff --git a/python/src/com/jetbrains/python/newProject/collector/PythonNewProjectWizardCollector.kt b/python/src/com/jetbrains/python/newProject/collector/PythonNewProjectWizardCollector.kt new file mode 100644 index 000000000000..4ce60025a6aa --- /dev/null +++ b/python/src/com/jetbrains/python/newProject/collector/PythonNewProjectWizardCollector.kt @@ -0,0 +1,50 @@ +// 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.newProject.collector + +import com.intellij.internal.statistic.eventLog.EventLogGroup +import com.intellij.internal.statistic.eventLog.events.EventFields +import com.intellij.internal.statistic.service.fus.collectors.CounterUsagesCollector +import com.jetbrains.python.psi.LanguageLevel +import com.jetbrains.python.statistics.* + +class PythonNewProjectWizardCollector : CounterUsagesCollector() { + + override fun getGroup(): EventLogGroup { + return GROUP + } + + companion object { + private val GROUP = EventLogGroup("python.new.project.wizard", 1) + private val INHERIT_GLOBAL_SITE_PACKAGE_FIELD = EventFields.Boolean("inherit_global_site_package") + private val MAKE_AVAILABLE_TO_ALL_PROJECTS = EventFields.Boolean("make_available_to_all_projects") + private val PREVIOUSLY_CONFIGURED = EventFields.Boolean("previously_configured") + private val GENERATOR_FIELD = EventFields.Class("generator") + private val PROJECT_GENERATED_EVENT = GROUP.registerVarargEvent("project.generated", + INTERPRETER_TYPE, + EXECUTION_TYPE, + PYTHON_VERSION, + GENERATOR_FIELD, + INHERIT_GLOBAL_SITE_PACKAGE_FIELD, + MAKE_AVAILABLE_TO_ALL_PROJECTS, + PREVIOUSLY_CONFIGURED) + + fun logPythonNewProjectGenerated(info: InterpreterStatisticsInfo, pythonVersion: LanguageLevel, generatorClass: Class<*>) { + PROJECT_GENERATED_EVENT.log( + INTERPRETER_TYPE.with(info.type.value), + EXECUTION_TYPE.with(info.target.value), + PYTHON_VERSION.with(pythonVersion.toPythonVersion()), + INHERIT_GLOBAL_SITE_PACKAGE_FIELD.with(info.globalSitePackage), + MAKE_AVAILABLE_TO_ALL_PROJECTS.with(info.makeAvailableToAllProjects), + PREVIOUSLY_CONFIGURED.with(info.previouslyConfigured), + GENERATOR_FIELD.with(generatorClass) + ) + } + } +} + +data class InterpreterStatisticsInfo(val type: InterpreterType, + val target: InterpreterTarget, + val globalSitePackage: Boolean, + val makeAvailableToAllProjects: Boolean, + val previouslyConfigured: Boolean) + diff --git a/python/src/com/jetbrains/python/newProject/steps/ProjectSpecificSettingsStep.java b/python/src/com/jetbrains/python/newProject/steps/ProjectSpecificSettingsStep.java index c0cf19d418f7..8a69ba60fa8b 100644 --- a/python/src/com/jetbrains/python/newProject/steps/ProjectSpecificSettingsStep.java +++ b/python/src/com/jetbrains/python/newProject/steps/ProjectSpecificSettingsStep.java @@ -30,6 +30,7 @@ import com.jetbrains.python.PyBundle; import com.jetbrains.python.configuration.PyConfigurableInterpreterList; import com.jetbrains.python.newProject.PyFrameworkProjectGenerator; import com.jetbrains.python.newProject.PythonProjectGenerator; +import com.jetbrains.python.newProject.collector.InterpreterStatisticsInfo; import com.jetbrains.python.packaging.PyPackage; import com.jetbrains.python.packaging.PyPackageUtil; import com.jetbrains.python.psi.PyUtil; @@ -110,6 +111,13 @@ public class ProjectSpecificSettingsStep extends ProjectSettingsStepBase i } } + @Nullable + public InterpreterStatisticsInfo getInterpreterInfoForStatistics() { + if (myInterpreterPanel == null) return null; + PyAddSdkPanel panel = myInterpreterPanel.getSelectedPanel(); + return panel.getStatisticInfo(); + } + @Nullable private Sdk getInterpreterPanelSdk() { final PyAddSdkGroupPanel interpreterPanel = myInterpreterPanel; diff --git a/python/src/com/jetbrains/python/newProject/steps/PyAddExistingSdkPanel.kt b/python/src/com/jetbrains/python/newProject/steps/PyAddExistingSdkPanel.kt index 538048f0bce7..2ad8c27ff110 100644 --- a/python/src/com/jetbrains/python/newProject/steps/PyAddExistingSdkPanel.kt +++ b/python/src/com/jetbrains/python/newProject/steps/PyAddExistingSdkPanel.kt @@ -22,6 +22,7 @@ import com.intellij.util.ui.UIUtil import com.jetbrains.python.PyBundle import com.jetbrains.python.PySdkBundle import com.jetbrains.python.Result +import com.jetbrains.python.newProject.collector.InterpreterStatisticsInfo import com.jetbrains.python.remote.PyProjectSynchronizer import com.jetbrains.python.remote.PyProjectSynchronizerProvider import com.jetbrains.python.remote.PythonSshInterpreterManager @@ -29,8 +30,10 @@ import com.jetbrains.python.run.PythonInterpreterTargetEnvironmentFactory import com.jetbrains.python.sdk.PythonSdkUtil import com.jetbrains.python.sdk.add.PyAddSdkPanel import com.jetbrains.python.sdk.associatedModulePath -import com.jetbrains.python.sdk.targetEnvConfiguration import com.jetbrains.python.sdk.sdkSeemsValid +import com.jetbrains.python.sdk.targetEnvConfiguration +import com.jetbrains.python.statistics.executionType +import com.jetbrains.python.statistics.interpreterType import java.awt.BorderLayout import java.awt.Component import javax.swing.JComboBox @@ -125,6 +128,11 @@ class PyAddExistingSdkPanel(project: Project?, return PythonInterpreterTargetEnvironmentFactory.by(configuration)?.needAssociateWithModule() ?: false } + override fun getStatisticInfo(): InterpreterStatisticsInfo? { + val sdk = sdk ?: return null + return InterpreterStatisticsInfo(sdk.interpreterType, sdk.executionType, false, false, true) + } + override fun validateAll(): List = listOf(validateSdkChooserField(), validateRemotePathField()) diff --git a/python/src/com/jetbrains/python/newProject/steps/PyAddNewEnvironmentPanel.kt b/python/src/com/jetbrains/python/newProject/steps/PyAddNewEnvironmentPanel.kt index cb95a1a4b060..2a8d95b11336 100644 --- a/python/src/com/jetbrains/python/newProject/steps/PyAddNewEnvironmentPanel.kt +++ b/python/src/com/jetbrains/python/newProject/steps/PyAddNewEnvironmentPanel.kt @@ -8,6 +8,7 @@ import com.intellij.openapi.util.UserDataHolder import com.intellij.openapi.util.UserDataHolderBase import com.intellij.ui.SimpleListCellRenderer import com.intellij.util.ui.FormBuilder +import com.jetbrains.python.newProject.collector.InterpreterStatisticsInfo import com.jetbrains.python.sdk.PySdkProvider import com.jetbrains.python.sdk.PySdkSettings import com.jetbrains.python.sdk.add.PyAddNewCondaEnvPanel @@ -78,6 +79,10 @@ class PyAddNewEnvironmentPanel(existingSdks: List, newProjectPath: String?, return createdSdk } + override fun getStatisticInfo(): InterpreterStatisticsInfo? { + return selectedPanel.getStatisticInfo(); + } + override fun validateAll(): List = selectedPanel.validateAll() override fun addChangeListener(listener: Runnable) { diff --git a/python/src/com/jetbrains/python/sdk/AddInterpreterActions.kt b/python/src/com/jetbrains/python/sdk/AddInterpreterActions.kt index 13ed2ab5b6ba..94cc1e681f79 100644 --- a/python/src/com/jetbrains/python/sdk/AddInterpreterActions.kt +++ b/python/src/com/jetbrains/python/sdk/AddInterpreterActions.kt @@ -3,7 +3,10 @@ package com.jetbrains.python.sdk -import com.intellij.execution.target.* +import com.intellij.execution.target.TargetConfigurationWithLocalFsAccess +import com.intellij.execution.target.TargetCustomToolWizardStep +import com.intellij.execution.target.TargetEnvironmentType +import com.intellij.execution.target.TargetEnvironmentWizard import com.intellij.icons.AllIcons import com.intellij.openapi.actionSystem.AnAction import com.intellij.openapi.actionSystem.AnActionEvent @@ -17,6 +20,7 @@ import com.jetbrains.python.configuration.PyConfigurableInterpreterList import com.jetbrains.python.run.PythonInterpreterTargetEnvironmentFactory import com.jetbrains.python.run.allowCreationTargetOfThisType import com.jetbrains.python.sdk.add.PyAddSdkDialog +import com.jetbrains.python.sdk.add.collector.PythonNewInterpreterAddedCollector import com.jetbrains.python.sdk.add.target.PyAddTargetBasedSdkDialog import com.jetbrains.python.target.PythonLanguageRuntimeType import java.util.function.Consumer @@ -56,11 +60,14 @@ private class AddLocalInterpreterAction(private val project: Project, project, module, model.sdks.asList(), - Consumer { - if (it != null && model.findSdk(it.name) == null) { - model.addSdk(it) - model.apply() - onSdkCreated.accept(it) + Consumer {sdk -> + if (sdk != null) { + PythonNewInterpreterAddedCollector.logPythonNewInterpreterAdded(sdk) + if (model.findSdk(sdk.name) == null) { + model.addSdk(sdk) + model.apply() + onSdkCreated.accept(sdk) + } } } ) @@ -77,12 +84,13 @@ private class AddInterpreterOnTargetAction(private val project: Project, if (wizard != null && wizard.showAndGet()) { val model = PyConfigurableInterpreterList.getInstance(project).model val sdk = (wizard.currentStepObject as? TargetCustomToolWizardStep)?.customTool as? Sdk - if (sdk != null && model.findSdk(sdk.name) == null) { - model.addSdk(sdk) - - - model.apply() - onSdkCreated.accept(sdk) + if (sdk != null) { + PythonNewInterpreterAddedCollector.logPythonNewInterpreterAdded(sdk) + if (model.findSdk(sdk.name) == null) { + model.addSdk(sdk) + model.apply() + onSdkCreated.accept(sdk) + } } } } diff --git a/python/src/com/jetbrains/python/sdk/add/PyAddNewCondaEnvPanel.kt b/python/src/com/jetbrains/python/sdk/add/PyAddNewCondaEnvPanel.kt index 0bcff7cbc380..e39ddfdbbe11 100644 --- a/python/src/com/jetbrains/python/sdk/add/PyAddNewCondaEnvPanel.kt +++ b/python/src/com/jetbrains/python/sdk/add/PyAddNewCondaEnvPanel.kt @@ -20,12 +20,15 @@ import com.intellij.util.PathUtil import com.intellij.util.SystemProperties import com.intellij.util.ui.FormBuilder import com.jetbrains.python.PyBundle +import com.jetbrains.python.newProject.collector.InterpreterStatisticsInfo import com.jetbrains.python.packaging.PyCondaPackageManagerImpl import com.jetbrains.python.packaging.PyCondaPackageService import com.jetbrains.python.sdk.* import com.jetbrains.python.sdk.add.target.conda.condaSupportedLanguages import com.jetbrains.python.sdk.conda.PyCondaSdkCustomizer import com.jetbrains.python.sdk.flavors.conda.CondaEnvSdkFlavor +import com.jetbrains.python.statistics.InterpreterTarget +import com.jetbrains.python.statistics.InterpreterType import icons.PythonIcons import org.jetbrains.annotations.SystemIndependent import java.awt.BorderLayout @@ -126,6 +129,14 @@ open class PyAddNewCondaEnvPanel( return sdk } + override fun getStatisticInfo(): InterpreterStatisticsInfo? { + return InterpreterStatisticsInfo(InterpreterType.CONDAVENV, + InterpreterTarget.LOCAL, + false, + makeSharedField.isSelected, + false) + } + override fun addChangeListener(listener: Runnable) { val documentListener = object : DocumentAdapter() { override fun textChanged(e: DocumentEvent) { diff --git a/python/src/com/jetbrains/python/sdk/add/PyAddNewVirtualEnvPanel.kt b/python/src/com/jetbrains/python/sdk/add/PyAddNewVirtualEnvPanel.kt index df269a3c3c6f..c83086ee68b8 100644 --- a/python/src/com/jetbrains/python/sdk/add/PyAddNewVirtualEnvPanel.kt +++ b/python/src/com/jetbrains/python/sdk/add/PyAddNewVirtualEnvPanel.kt @@ -15,9 +15,12 @@ import com.intellij.ui.components.JBCheckBox import com.intellij.util.ui.FormBuilder import com.jetbrains.python.PyBundle import com.jetbrains.python.PySdkBundle +import com.jetbrains.python.newProject.collector.InterpreterStatisticsInfo import com.jetbrains.python.sdk.PySdkSettings import com.jetbrains.python.sdk.basePath import com.jetbrains.python.sdk.configuration.PyProjectVirtualEnvConfiguration +import com.jetbrains.python.statistics.InterpreterTarget +import com.jetbrains.python.statistics.InterpreterType import icons.PythonIcons import org.jetbrains.annotations.SystemIndependent import java.awt.BorderLayout @@ -77,6 +80,14 @@ open class PyAddNewVirtualEnvPanel(private val project: Project?, inheritSitePackagesField.isSelected, makeSharedField.isSelected) } + override fun getStatisticInfo(): InterpreterStatisticsInfo? { + return InterpreterStatisticsInfo(InterpreterType.VIRTUALENV, + InterpreterTarget.LOCAL, + inheritSitePackagesField.isSelected, + makeSharedField.isSelected, + false) + } + override fun addChangeListener(listener: Runnable) { pathField.textField.document.addDocumentListener(object : DocumentAdapter() { override fun textChanged(e: DocumentEvent) { diff --git a/python/src/com/jetbrains/python/sdk/add/PyAddSdkPanel.kt b/python/src/com/jetbrains/python/sdk/add/PyAddSdkPanel.kt index 81f5108fb4c7..aab0d7093674 100644 --- a/python/src/com/jetbrains/python/sdk/add/PyAddSdkPanel.kt +++ b/python/src/com/jetbrains/python/sdk/add/PyAddSdkPanel.kt @@ -29,6 +29,7 @@ import com.intellij.openapi.util.NlsContexts import com.intellij.openapi.util.SystemInfo import com.intellij.openapi.util.UserDataHolder import com.jetbrains.python.PySdkBundle +import com.jetbrains.python.newProject.collector.InterpreterStatisticsInfo import com.jetbrains.python.newProject.steps.PyAddNewEnvironmentPanel import com.jetbrains.python.sdk.* import com.jetbrains.python.sdk.add.PyAddSdkDialogFlowAction.OK @@ -69,6 +70,8 @@ abstract class PyAddSdkPanel : JPanel(), PyAddSdkView { override fun getOrCreateSdk(): Sdk? = sdk + open fun getStatisticInfo(): InterpreterStatisticsInfo? = null + override fun onSelected(): Unit = Unit override fun validateAll(): List = emptyList() diff --git a/python/src/com/jetbrains/python/sdk/add/collector/PythonNewInterpreterAddedCollector.kt b/python/src/com/jetbrains/python/sdk/add/collector/PythonNewInterpreterAddedCollector.kt new file mode 100644 index 000000000000..8dc3d262f929 --- /dev/null +++ b/python/src/com/jetbrains/python/sdk/add/collector/PythonNewInterpreterAddedCollector.kt @@ -0,0 +1,37 @@ +// 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.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.* + +class PythonNewInterpreterAddedCollector : CounterUsagesCollector() { + + override fun getGroup(): EventLogGroup { + return GROUP + } + + companion object { + private val GROUP = EventLogGroup("python.new.interpreter.added", 1) + private val PROJECT_GENERATED_EVENT = GROUP.registerVarargEvent("interpreted.added", + INTERPRETER_TYPE, + EXECUTION_TYPE, + PYTHON_VERSION) + + fun logPythonNewInterpreterAdded(sdk: Sdk) { + PROJECT_GENERATED_EVENT.log( + INTERPRETER_TYPE.with(sdk.interpreterType.value), + EXECUTION_TYPE.with(sdk.executionType.value), + PYTHON_VERSION.with(sdk.version.toPythonVersion()) + ) + } + } +} + +data class InterpreterStatisticsInfo(val type: InterpreterType, + val target: InterpreterTarget, + val globalSitePackage: Boolean, + val makeAvailableToAllProjects: Boolean, + val previouslyConfigured: Boolean) + diff --git a/python/src/com/jetbrains/python/sdk/pipenv/PyAddPipEnvPanel.kt b/python/src/com/jetbrains/python/sdk/pipenv/PyAddPipEnvPanel.kt index 35192764da7a..a03ce05f31da 100644 --- a/python/src/com/jetbrains/python/sdk/pipenv/PyAddPipEnvPanel.kt +++ b/python/src/com/jetbrains/python/sdk/pipenv/PyAddPipEnvPanel.kt @@ -20,6 +20,7 @@ import com.intellij.util.ui.FormBuilder import com.jetbrains.python.PyBundle import com.jetbrains.python.PySdkBundle import com.jetbrains.python.PythonModuleTypeBase +import com.jetbrains.python.newProject.collector.InterpreterStatisticsInfo import com.jetbrains.python.sdk.PySdkSettings import com.jetbrains.python.sdk.add.PyAddNewEnvPanel import com.jetbrains.python.sdk.add.PySdkPathChoosingComboBox @@ -27,6 +28,8 @@ import com.jetbrains.python.sdk.add.addBaseInterpretersAsync import com.jetbrains.python.sdk.associatedModulePath import com.jetbrains.python.sdk.basePath import com.jetbrains.python.sdk.installSdkIfNeeded +import com.jetbrains.python.statistics.InterpreterTarget +import com.jetbrains.python.statistics.InterpreterType import java.awt.BorderLayout import java.awt.Dimension import java.awt.event.ItemEvent @@ -127,6 +130,14 @@ class PyAddPipEnvPanel(private val project: Project?, } } + override fun getStatisticInfo(): InterpreterStatisticsInfo { + return InterpreterStatisticsInfo(type = InterpreterType.PIPENV, + target = InterpreterTarget.LOCAL, + globalSitePackage = false, + makeAvailableToAllProjects = false, + previouslyConfigured = false) + } + override fun validateAll(): List = listOfNotNull(validatePipEnvExecutable(), validatePipEnvIsNotAdded()) diff --git a/python/src/com/jetbrains/python/sdk/poetry/PyAddNewPoetryPanel.kt b/python/src/com/jetbrains/python/sdk/poetry/PyAddNewPoetryPanel.kt index 3a786c174761..1eeb790bf7be 100644 --- a/python/src/com/jetbrains/python/sdk/poetry/PyAddNewPoetryPanel.kt +++ b/python/src/com/jetbrains/python/sdk/poetry/PyAddNewPoetryPanel.kt @@ -20,10 +20,13 @@ import com.intellij.util.text.nullize import com.intellij.util.ui.FormBuilder import com.jetbrains.python.PyBundle import com.jetbrains.python.PySdkBundle +import com.jetbrains.python.newProject.collector.InterpreterStatisticsInfo import com.jetbrains.python.sdk.* import com.jetbrains.python.sdk.add.PyAddNewEnvPanel import com.jetbrains.python.sdk.add.PySdkPathChoosingComboBox import com.jetbrains.python.sdk.add.addInterpretersAsync +import com.jetbrains.python.statistics.InterpreterTarget +import com.jetbrains.python.statistics.InterpreterType import java.awt.BorderLayout import java.awt.Dimension import java.awt.event.ItemEvent @@ -132,6 +135,14 @@ class PyAddNewPoetryPanel(private val project: Project?, } } + override fun getStatisticInfo(): InterpreterStatisticsInfo { + return InterpreterStatisticsInfo(type = InterpreterType.POETRY, + target = InterpreterTarget.LOCAL, + globalSitePackage = false, + makeAvailableToAllProjects = false, + previouslyConfigured = false) + } + override fun validateAll(): List = listOfNotNull(validatePoetryExecutable(), validatePoetryIsNotAdded()) diff --git a/python/src/com/jetbrains/python/statistics/PyStatisticTools.kt b/python/src/com/jetbrains/python/statistics/PyStatisticTools.kt index 77e7a4fa58e7..d19ad4a9391d 100644 --- a/python/src/com/jetbrains/python/statistics/PyStatisticTools.kt +++ b/python/src/com/jetbrains/python/statistics/PyStatisticTools.kt @@ -2,7 +2,6 @@ package com.jetbrains.python.statistics import com.intellij.internal.statistic.eventLog.EventLogGroup -import com.intellij.internal.statistic.eventLog.FeatureUsageData import com.intellij.internal.statistic.eventLog.events.EventField import com.intellij.internal.statistic.eventLog.events.EventFields import com.intellij.internal.statistic.eventLog.events.EventPair @@ -14,12 +13,15 @@ import com.intellij.openapi.project.Project import com.intellij.openapi.projectRoots.Sdk import com.jetbrains.extensions.getSdk import com.jetbrains.python.PythonLanguage +import com.jetbrains.python.psi.LanguageLevel import com.jetbrains.python.remote.PyRemoteSdkAdditionalDataBase import com.jetbrains.python.sdk.PythonSdkType import com.jetbrains.python.sdk.PythonSdkUtil import com.jetbrains.python.sdk.flavors.PythonSdkFlavor import com.jetbrains.python.sdk.pipenv.isPipEnv import com.jetbrains.python.sdk.poetry.isPoetry +import com.jetbrains.python.statistics.InterpreterTarget.* +import com.jetbrains.python.statistics.InterpreterType.* val Project.modules get() = ModuleManager.getInstance(this).modules val Project.sdks get() = modules.mapNotNull(Module::getSdk) @@ -36,10 +38,10 @@ fun getPythonSpecificInfo(module: Module) = fun getPythonSpecificInfo(sdk: Sdk): List> { val data = ArrayList>() data.add(EventFields.Language.with(PythonLanguage.INSTANCE)) - data.add(PYTHON_VERSION.with(sdk.version)) + data.add(PYTHON_VERSION.with(sdk.version.toPythonVersion())) data.add(PYTHON_IMPLEMENTATION.with(sdk.pythonImplementation)) - data.add(EXECUTION_TYPE.with(sdk.executionType)) - data.add(INTERPRETER_TYPE.with(sdk.interpreterType)) + data.add(EXECUTION_TYPE.with(sdk.executionType.value)) + data.add(INTERPRETER_TYPE.with(sdk.interpreterType.value)) return data } @@ -55,28 +57,66 @@ fun registerPythonSpecificEvent(group: EventLogGroup, eventId: String, vararg ex val PYTHON_VERSION = EventFields.StringValidatedByRegexp("python_version", "version") val PYTHON_IMPLEMENTATION = EventFields.String("python_implementation", listOf("PyPy", "Jython", "Python")) -val EXECUTION_TYPE = EventFields.String("executionType", listOf("local", "Remote_Docker", "Remote_Docker_Compose", "Remote_WSL", "Remote_null", "third_party", "Remote_SSH_Credentials", "Remote_Vagrant", "Remote_Web_Deployment", "Remote_Unknown")) -val INTERPRETER_TYPE = EventFields.String("interpreterType", listOf("pipenv", "condavenv", "virtualenv", "regular", "poetry")) -private val Sdk.version get() = PythonSdkType.getLanguageLevelForSdk(this).toPythonVersion() +enum class InterpreterTarget(val value: String) { + LOCAL("local"), + REMOTE_DOCKER("Remote_Docker"), + REMOTE_DOCKER_COMPOSE("Remote_Docker_Compose"), + REMOTE_WSL("Remote_WSL"), + REMOTE_NULL("Remote_null"), + THIRD_PARTY("third_party"), + REMOTE_SSH_CREDENTIALS("Remote_SSH_Credentials"), + REMOTE_VAGRANT("Remote_Vagrant"), + REMOTE_WEB_DEPLOYMENT("Remote_Web_Deployment"), + REMOTE_UNKNOWN("Remote_Unknown"), +} + +val EXECUTION_TYPE = EventFields.String("executionType", listOf( + LOCAL.value, + REMOTE_DOCKER.value, + REMOTE_DOCKER_COMPOSE.value, + REMOTE_WSL.value, + REMOTE_NULL.value, + THIRD_PARTY.value, + REMOTE_SSH_CREDENTIALS.value, + REMOTE_VAGRANT.value, + REMOTE_WEB_DEPLOYMENT.value, + REMOTE_UNKNOWN.value)) + +enum class InterpreterType(val value: String) { + PIPENV("pipenv"), + CONDAVENV("condavenv"), + VIRTUALENV("virtualenv"), + REGULAR("regular"), + POETRY("poetry") +} + +val INTERPRETER_TYPE = EventFields.String("interpreterType", listOf(PIPENV.value, + CONDAVENV.value, + VIRTUALENV.value, + REGULAR.value, + POETRY.value)) + + private val Sdk.pythonImplementation: String get() = PythonSdkFlavor.getFlavor(this)?.name ?: "Python" -private val Sdk.executionType get(): String = (sdkAdditionalData as? PyRemoteSdkAdditionalDataBase)?.executionType ?: "local" -private val Sdk.interpreterType +val Sdk.version: LanguageLevel get() = PythonSdkType.getLanguageLevelForSdk(this) +val Sdk.executionType get(): InterpreterTarget = (sdkAdditionalData as? PyRemoteSdkAdditionalDataBase)?.executionType ?: LOCAL +val Sdk.interpreterType: InterpreterType get() = when { // The order of checks is important here since e.g. a pipenv is a virtualenv - isPipEnv -> "pipenv" - isPoetry -> "poetry" - PythonSdkUtil.isConda(this) -> "condavenv" - PythonSdkUtil.isVirtualEnv(this) -> "virtualenv" - else -> "regular" + isPipEnv -> PIPENV + isPoetry -> POETRY + PythonSdkUtil.isConda(this) -> CONDAVENV + PythonSdkUtil.isVirtualEnv(this) -> VIRTUALENV + else -> REGULAR } -private val PyRemoteSdkAdditionalDataBase.executionType: String +private val PyRemoteSdkAdditionalDataBase.executionType: InterpreterTarget get() = remoteConnectionType.let { type -> when { type == null -> "Remote_null" getPluginInfo(type.javaClass).isDevelopedByJetBrains() -> "Remote_${type.name?.replace(' ', '_')}" else -> "third_party" - } + }.let { name -> InterpreterTarget.values().firstOrNull { it.value == name } ?: REMOTE_UNKNOWN } }