fix: show interpreter action only on virtualenvs - #221
Conversation
The Set as Project/Module Interpreter action resolved a right-clicked file to its parent directory, so it appeared on ordinary files (e.g. main.py) whose folder happens to contain a venv. Restrict the action to a selected directory that is itself a virtual environment.
There was a problem hiding this comment.
Pull request overview
This PR fixes an IntelliJ action-visibility bug where “Set as Project Interpreter” could appear on ordinary files (e.g. main.py) because the update logic resolved files to their parent directory and then detected an interpreter from a nested venv.
Changes:
- Restricts the action’s visibility to selected directories (not files).
- Aligns
actionPerformedwith the same directory-only selection rule. - Removes verbose logging from the action update flow.
Comments suppressed due to low confidence (1)
src/main/kotlin/com/github/pyvenvmanage/actions/ConfigurePythonActionAbstract.kt:39
actionPerformedis now restricted to directories, but it can still run on a non-venv directory (e.g. via keyboard shortcut) and then apply to whatever nested interpreterPythonSdkUtil.getPythonExecutablefinds. If the action is meant to apply only when the selected directory itself is a venv, validate that here too (e.g. requirepyvenv.cfgin the selected directory) soupdate()andactionPerformed()enforce the same target rule.
val selectedPath = e.getData(CommonDataKeys.VIRTUAL_FILE)?.takeIf { it.isDirectory } ?: return
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Keep update() and actionPerformed() to directory selections only, drop the unused logger, and replace the parent-resolution unit test with coverage that a non-directory selection is ignored (both in update visibility and actionPerformed).
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (2)
src/main/kotlin/com/github/pyvenvmanage/actions/ConfigurePythonActionAbstract.kt:30
PythonSdkUtil.getPythonExecutable(dir.path)can still return an interpreter located in a child venv (as described in the PR body). With the current logic, right-clicking a non-venv directory that merely contains a venv could still enable this action, contradicting the stated behavior (only show on directories that are themselves a venv). Consider verifying that the detected interpreter belongs to the selected directory itself (i.e., the resolved venv root matches the selected directory).
// Only offer the action on a directory that is itself a virtual environment. Resolving a file
// to its parent made it appear on ordinary files (e.g. main.py) whose folder merely contains
// a venv, which is not a valid interpreter target.
val venvDir = e.getData(CommonDataKeys.VIRTUAL_FILE)?.takeIf { it.isDirectory }
val pythonExecutable = venvDir?.let { PythonSdkUtil.getPythonExecutable(it.path) }
src/main/kotlin/com/github/pyvenvmanage/actions/ConfigurePythonActionAbstract.kt:43
actionPerformednow ignores non-directory selections, but it still trustsPythonSdkUtil.getPythonExecutable(selectedPath.path)without checking that the returned interpreter belongs toselectedPathitself. IfgetPythonExecutableresolves an interpreter inside a child venv, this can still apply the action when the user right-clicks a non-venv directory that merely contains a venv.
val selectedPath = e.getData(CommonDataKeys.VIRTUAL_FILE)?.takeIf { it.isDirectory } ?: return
val pythonExecutable = PythonSdkUtil.getPythonExecutable(selectedPath.path)
if (pythonExecutable == null) {
update() decided visibility from getPythonExecutable alone, which also matches non-venv directories (a project root with a configured interpreter) and, via the old file-to-parent fallback, ordinary files. Use VenvUtils.getPyVenvCfg, the same pyvenv.cfg check the project view decorator uses, so the action appears only on actual virtual environments. Tests cover venv, non-venv, and non-directory selections.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (2)
src/main/kotlin/com/github/pyvenvmanage/actions/ConfigurePythonActionAbstract.kt:42
actionPerformedcurrently accepts any selected directory (even non-venv directories) and will attempt to configure an SDK ifPythonSdkUtil.getPythonExecutableresolves (e.g. project root with a configured interpreter). This contradicts the updatedupdate()logic and the PR description that the action should apply only to directories that are actual virtual environments. Consider applying the sameVenvUtils.getPyVenvCfggate here to keep behavior consistent and avoid configuring a non-venv directory as an interpreter target.
override fun actionPerformed(e: AnActionEvent) {
val project = e.project ?: return
val selectedPath = e.getData(CommonDataKeys.VIRTUAL_FILE)?.takeIf { it.isDirectory } ?: return
src/test/kotlin/com/github/pyvenvmanage/actions/ConfigurePythonActionAbstractTest.kt:120
- This test name says it covers a non-directory selection, but the setup doesn’t explicitly make the selection non-directory, and it stubs
VenvUtils.getPyVenvCfgdirectly (so the non-directory behavior isn’t really exercised). To make the intent and coverage clearer, either setvirtualFile.isDirectory = falseand rename the test to reflect what it asserts (no probing viaPythonSdkUtil.getPythonExecutablewhen the selection is not a venv).
@Test
fun `disables action for non-directory selection`() {
every { event.getData(CommonDataKeys.VIRTUAL_FILE) } returns virtualFile
every { VenvUtils.getPyVenvCfg(virtualFile) } returns null
The
🖥️ UI testscheck fails onmain, which blocks every PR (including the Dependabot bumps) because it is a required check.testContextMenuOnPythonFileright-clicksmain.pyand asserts thatSet as Project Interpreteris absent, but the action appears on the file.ConfigurePythonActionAbstract.update()decided visibility fromPythonSdkUtil.getPythonExecutable(dir) != nullalone, resolving a right-clicked file to its parent directory first. That check is weaker than the plugin's own definition of a virtualenv: it also matches non-venv directories, such as a project root once an interpreter is configured, so on the 2026.2 platform the action surfaces onmain.pythrough its parent folder. The action now gates onVenvUtils.getPyVenvCfg, the samepyvenv.cfgcheckVenvProjectViewNodeDecoratoruses to mark venvs, so it appears only on directories that are actual virtual environments.Right-clicking a venv directory still shows and applies the action; files, and directories that merely contain or reference a Python interpreter, no longer surface it. The unit tests cover venv, non-venv, and non-directory selections.