Skip to content

Commit f852386

Browse files
authored
♻️ refactor: use public PluginManager.isPluginInstalled (#188)
The plugin-availability check called `PluginManagerCore.getPlugin(PluginId)`, which is `@ApiStatus.Internal` on 262 and surfaced as an internal-API usage in the verifier report. Unlike the uv/venv SDK flavor, icon, and additional-data APIs (which are internal with no public alternative), this one has a public escape hatch: `com.intellij.ide.plugins.PluginManager.isPluginInstalled(PluginId)`. Swapping to it keeps the behavior identical. `isPluginInstalled` reports presence regardless of enablement, and the existing `PluginManagerCore.isDisabled` guard (which the verifier does not flag as internal) still narrows the result to installed-and-enabled. The check also reads more clearly now that the two plugin IDs share a small helper. Also bumps the dev version to `2.4.1-dev`, superseding the automated #187. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
1 parent 52932b8 commit f852386

3 files changed

Lines changed: 24 additions & 34 deletions

File tree

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@ pluginGroup=com.github.pyvenvmanage
99
pluginName=PyVenv Manage 2
1010
pluginRepositoryUrl=https://github.com/pyvenvmanage/PyVenvManage
1111
pluginSinceBuild=262
12-
pluginVersion=2.4.0-dev
12+
pluginVersion=2.4.1-dev

src/main/kotlin/com/github/pyvenvmanage/PythonRequiredStartupActivity.kt

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.github.pyvenvmanage
22

3+
import com.intellij.ide.plugins.PluginManager
4+
import com.intellij.ide.plugins.PluginManagerCore
35
import com.intellij.notification.NotificationAction
46
import com.intellij.notification.NotificationGroupManager
57
import com.intellij.notification.NotificationType
@@ -28,20 +30,9 @@ class PythonRequiredStartupActivity : ProjectActivity {
2830
).notify(project)
2931
}
3032

31-
private fun isPythonPluginAvailable(): Boolean {
32-
val pythonModuleId = PluginId.getId("com.intellij.modules.python")
33-
val pythonCoreId = PluginId.getId("PythonCore")
34-
return (
35-
com.intellij.ide.plugins.PluginManagerCore
36-
.getPlugin(pythonModuleId) != null &&
37-
!com.intellij.ide.plugins.PluginManagerCore
38-
.isDisabled(pythonModuleId)
39-
) ||
40-
(
41-
com.intellij.ide.plugins.PluginManagerCore
42-
.getPlugin(pythonCoreId) != null &&
43-
!com.intellij.ide.plugins.PluginManagerCore
44-
.isDisabled(pythonCoreId)
45-
)
46-
}
33+
private fun isPythonPluginAvailable(): Boolean =
34+
isEnabled(PluginId.getId("com.intellij.modules.python")) || isEnabled(PluginId.getId("PythonCore"))
35+
36+
private fun isEnabled(id: PluginId): Boolean =
37+
PluginManager.isPluginInstalled(id) && !PluginManagerCore.isDisabled(id)
4738
}

src/test/kotlin/com/github/pyvenvmanage/PythonRequiredStartupActivityTest.kt

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import org.junit.jupiter.api.AfterEach
1313
import org.junit.jupiter.api.BeforeEach
1414
import org.junit.jupiter.api.Test
1515

16-
import com.intellij.ide.plugins.IdeaPluginDescriptor
16+
import com.intellij.ide.plugins.PluginManager
1717
import com.intellij.ide.plugins.PluginManagerCore
1818
import com.intellij.notification.Notification
1919
import com.intellij.notification.NotificationAction
@@ -45,6 +45,7 @@ class PythonRequiredStartupActivityTest {
4545
pythonCoreId = PluginId.getId("PythonCore")
4646

4747
mockkStatic(NotificationGroupManager::class)
48+
mockkStatic(PluginManager::class)
4849
mockkStatic(PluginManagerCore::class)
4950
mockkObject(PyVenvManageSettings)
5051

@@ -61,15 +62,15 @@ class PythonRequiredStartupActivityTest {
6162
@AfterEach
6263
fun tearDown() {
6364
unmockkStatic(NotificationGroupManager::class)
65+
unmockkStatic(PluginManager::class)
6466
unmockkStatic(PluginManagerCore::class)
6567
unmockkObject(PyVenvManageSettings)
6668
}
6769

6870
@Test
6971
fun `does not show notification when python module is available`(): Unit =
7072
runBlocking {
71-
val pythonPlugin: IdeaPluginDescriptor = mockk(relaxed = true)
72-
every { PluginManagerCore.getPlugin(pythonModuleId) } returns pythonPlugin
73+
every { PluginManager.isPluginInstalled(pythonModuleId) } returns true
7374
every { PluginManagerCore.isDisabled(pythonModuleId) } returns false
7475

7576
PythonRequiredStartupActivity().execute(project)
@@ -80,9 +81,8 @@ class PythonRequiredStartupActivityTest {
8081
@Test
8182
fun `does not show notification when PythonCore plugin is available`(): Unit =
8283
runBlocking {
83-
val pythonCorePlugin: IdeaPluginDescriptor = mockk(relaxed = true)
84-
every { PluginManagerCore.getPlugin(pythonModuleId) } returns null
85-
every { PluginManagerCore.getPlugin(pythonCoreId) } returns pythonCorePlugin
84+
every { PluginManager.isPluginInstalled(pythonModuleId) } returns false
85+
every { PluginManager.isPluginInstalled(pythonCoreId) } returns true
8686
every { PluginManagerCore.isDisabled(pythonCoreId) } returns false
8787

8888
PythonRequiredStartupActivity().execute(project)
@@ -93,8 +93,8 @@ class PythonRequiredStartupActivityTest {
9393
@Test
9494
fun `shows warning notification when python is not available`(): Unit =
9595
runBlocking {
96-
every { PluginManagerCore.getPlugin(pythonModuleId) } returns null
97-
every { PluginManagerCore.getPlugin(pythonCoreId) } returns null
96+
every { PluginManager.isPluginInstalled(pythonModuleId) } returns false
97+
every { PluginManager.isPluginInstalled(pythonCoreId) } returns false
9898

9999
PythonRequiredStartupActivity().execute(project)
100100

@@ -111,10 +111,9 @@ class PythonRequiredStartupActivityTest {
111111
@Test
112112
fun `shows warning when python plugin exists but is disabled`(): Unit =
113113
runBlocking {
114-
val disabledPlugin: IdeaPluginDescriptor = mockk(relaxed = true)
115-
every { PluginManagerCore.getPlugin(pythonModuleId) } returns disabledPlugin
114+
every { PluginManager.isPluginInstalled(pythonModuleId) } returns true
116115
every { PluginManagerCore.isDisabled(pythonModuleId) } returns true
117-
every { PluginManagerCore.getPlugin(pythonCoreId) } returns null
116+
every { PluginManager.isPluginInstalled(pythonCoreId) } returns false
118117

119118
PythonRequiredStartupActivity().execute(project)
120119

@@ -124,8 +123,8 @@ class PythonRequiredStartupActivityTest {
124123
@Test
125124
fun `does not show notification when warning was dismissed`(): Unit =
126125
runBlocking {
127-
every { PluginManagerCore.getPlugin(pythonModuleId) } returns null
128-
every { PluginManagerCore.getPlugin(pythonCoreId) } returns null
126+
every { PluginManager.isPluginInstalled(pythonModuleId) } returns false
127+
every { PluginManager.isPluginInstalled(pythonCoreId) } returns false
129128
every { settings.dismissedPythonWarning } returns true
130129

131130
PythonRequiredStartupActivity().execute(project)
@@ -136,8 +135,8 @@ class PythonRequiredStartupActivityTest {
136135
@Test
137136
fun `notification includes dont show again action`(): Unit =
138137
runBlocking {
139-
every { PluginManagerCore.getPlugin(pythonModuleId) } returns null
140-
every { PluginManagerCore.getPlugin(pythonCoreId) } returns null
138+
every { PluginManager.isPluginInstalled(pythonModuleId) } returns false
139+
every { PluginManager.isPluginInstalled(pythonCoreId) } returns false
141140

142141
PythonRequiredStartupActivity().execute(project)
143142

@@ -147,8 +146,8 @@ class PythonRequiredStartupActivityTest {
147146
@Test
148147
fun `dont show again action sets dismissed flag and expires notification`(): Unit =
149148
runBlocking {
150-
every { PluginManagerCore.getPlugin(pythonModuleId) } returns null
151-
every { PluginManagerCore.getPlugin(pythonCoreId) } returns null
149+
every { PluginManager.isPluginInstalled(pythonModuleId) } returns false
150+
every { PluginManager.isPluginInstalled(pythonCoreId) } returns false
152151

153152
val actionSlot = slot<NotificationAction>()
154153
every { notification.addAction(capture(actionSlot)) } returns notification

0 commit comments

Comments
 (0)