Repository navigation
Activate newly installed project application plugins in the same command - #11139
sergioperezcheco wants to merge 3 commits into
Conversation
Rediscover installed entry points without duplicate activation or re-executing existing .pth files. Assisted-by: OpenAI GPT-6.1 Signed-off-by: sergioperezcheco <checo520@outlook.com>
There was a problem hiding this comment.
Hey - I've found 2 issues
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="src/poetry/plugins/plugin_manager.py" line_range="81" />
<code_context>
- addsitedir(str(plugin_path))
+ system_path.insert(0, plugin_path_string)
+ # Existing .pth files must not execute again during rediscovery.
+ if not already_added:
+ addsitedir(plugin_path_string)
+ elif known_pth_files is not None:
</code_context>
<issue_to_address>
**Editable plugins stay undiscoverable**
When the project plugin directory is already on process-wide `sys.path` before discovery, but its `.pth` files have not been processed, `already_added` suppresses `addsitedir()` based only on `sys.path` membership, so the editable source paths and finders are not added; entry-point loading then fails or resolves incorrectly.
Track whether the directory’s `.pth` files have been processed, and run `addsitedir()` when they have not, even if the directory is already on `sys.path`.
Also at `src/poetry/plugins/plugin_manager.py:82-83`.
</issue_to_address>
### Comment 2
<location path="src/poetry/plugins/plugin_manager.py" line_range="100-103" />
<code_context>
+ # plugins that have already registered commands or event listeners.
plugin_entrypoints = self.get_plugin_entry_points()
for ep in plugin_entrypoints:
- self._load_plugin_entry_point(ep)
+ if ep not in self._loaded_entry_points:
+ self._load_plugin_entry_point(ep)
+ self._loaded_entry_points.add(ep)
def get_plugin_entry_points(self) -> list[metadata.EntryPoint]:
</code_context>
<issue_to_address>
**Replacement plugins activate alongside originals**
When a project-required version replaces an already-loaded application plugin and changes its entry-point value while keeping the same entry-point name, a project-installed replacement with the same entry-point name but a different value is treated as new because `_loaded_entry_points` tracks complete entry points. `load_plugins()` instantiates it while retaining the already loaded plugin, so `activate()` runs both and duplicate listeners or conflicting command registrations reach callers.
Recognize replacement entry points for an already-loaded plugin and avoid activating both versions in the same invocation.
</issue_to_address>Sourcery assessment
Needs a human reviewer. 2 findings to address first, and after installation, newly discovered plugins and new .pth import lines execute in the still-running Poetry process; a plugin’s TERMINATE listener can therefore perform side effects before the command exits. Reverting prevents that same-command execution, but cannot undo any side effects that already occurred.
Blocking findings: src/poetry/plugins/plugin_manager.py:81, src/poetry/plugins/plugin_manager.py:103
Assisted-by: Hermes Agent (Nous Research) Signed-off-by: sergioperezcheco <checo520@outlook.com>
|
Addressed both rediscovery findings in b62b0c6: The targeted suites pass (217 passed, 1 skipped), as do mypy and changed-file pre-commit checks. Real install/sync/no-plugins CLI checks pass, and an independent metadata/import probe verifies that the old plugin remains active in-process while the replacement loads in a new process. Full integration-enabled local runs with the same final tests give 17 failures before this commit and 14 afterward, with no new failures; the 14 remaining local environment/license failures are not reported as passing. The earlier Ubuntu/Python 3.14 CI failures remain unproven as unrelated; this push needs its own CI results and documentation preview. |
…dencies Signed-off-by: sergioperezcheco <checo520@outlook.com>
Pull Request Check List
Resolves: #10273
Activate application plugins after project installation
Application plugins are discovered before an install command runs. On a clean checkout, a plugin listed in
tool.poetry.requires-pluginsis therefore installed but cannot register itsTERMINATElistener until the next Poetry invocation.Keep the application's plugin manager and discover newly installed entry points immediately after
ensure_project_plugins()succeeds. Rediscovery neither instantiates existing entry points again nor reactivates their command and event registrations. Default explicit activation still activates all plugins; the incremental behavior is opt-in for this application lifecycle.syncinherits the same behavior, and--no-pluginscontinues to disable installation and activation.Refresh the project plugin path without re-executing existing
.pthfiles. When installation creates a new editable-plugin.pthfile, process that file before entry-point loading. This is discovery, not module hot reload: already imported modules remain loaded, and events dispatched before installation, includingCOMMAND, are not replayed. The documentation describes these boundaries.Verification
Merged current main (20d6940, the dependency-lock refresh) without rewriting the branch, and installed its locked dependencies into a separate Python 3.13 environment. Production code and the existing regression tests are unchanged by this maintenance merge. The application, plugin-manager, install and sync suites pass: 217 passed, 1 skipped. With these same final tests and all three original production files from current main, the selection has 10 failures and 207 passes. Mypy passes for all 380 source files, and all pinned pre-commit hooks pass across the repository.
Real CLI fixtures install an editable application plugin and verify that its TERMINATE listener runs on the first install and sync, COMMAND is not replayed, subsequent invocations activate once, and --no-plugins registers nothing. The same first-install fixture reproduces missing activation and TERMINATE delivery on unmodified main. A real metadata/import probe also confirms .pth processing runs once and a replacement plugin takes effect in a new process rather than alongside the already loaded plugin.
The full integration-enabled local run is not entirely green: 3340 passed, 14 failed, 34 skipped, 2 xfailed. All 14 failures are also present with the same test files and current-main production code, which has 24 failures and 3330 passes. The shared failures concern local Python discovery/environment fixtures, environment-info output and the empty-license initializer; no new full-suite failures were observed. No tests were removed or skipped to obtain this comparison.
The documentation paragraph renders and all three local relative references resolve; this is not a full Hugo website build or a review of a hosted preview. Other operating systems and the complete remote Python matrix were not run locally. New-head hosted CI must be checked separately after publication.
This contribution was developed and checked by an autonomous AI agent on behalf of sergioperezcheco; it has not received human review.