Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions changelog/763.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
``PluginManager.unregister()`` now removes the plugin from
``list_plugin_distinfo()`` and ``list_plugin_distributions()``. Previously
these kept reporting an unregistered plugin loaded via
``load_setuptools_entrypoints()``, and re-registering it added a duplicate
entry.
7 changes: 7 additions & 0 deletions src/pluggy/_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,13 @@ def unregister(
if self._name2plugin.get(name) is not None:
del self._name2plugin[name]

# Drop any setuptools distribution bookkeeping for this plugin so it
# no longer shows up in list_plugin_distinfo()/list_plugin_distributions()
# and a later re-registration does not create duplicate entries.
self._plugin_distinfo[:] = [
(p, dist) for (p, dist) in self._plugin_distinfo if p is not plugin
]

return plugin

def set_blocked(self, name: str) -> None:
Expand Down
44 changes: 44 additions & 0 deletions testing/test_pluginmanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -959,6 +959,50 @@ def my_distributions():
assert ret_distributions == [(plugin, dist)]


def test_unregister_removes_plugin_distinfo(
monkeypatch: pytest.MonkeyPatch, pm: PluginManager
) -> None:
"""Unregistering a setuptools-loaded plugin clears its distinfo entries.

See https://github.com/pytest-dev/pluggy/issues/763.
"""

class EntryPoint:
name = "myname"
group = "hello"
value = "myname:foo"

def load(self):
class PseudoPlugin:
pass

return PseudoPlugin()

class Distribution:
entry_points = (EntryPoint(),)

dist = cast(importlib.metadata.Distribution, Distribution())

monkeypatch.setattr(importlib.metadata, "distributions", lambda: (dist,))

assert pm.load_setuptools_entrypoints("hello") == 1
plugin = pm.get_plugin("myname")
assert plugin is not None
assert len(pm.list_plugin_distinfo()) == 1
assert len(pm.list_plugin_distributions()) == 1

# Unregistering must drop both distinfo views.
pm.unregister(name="myname")
assert pm.get_plugin("myname") is None
assert pm.list_plugin_distinfo() == []
assert pm.list_plugin_distributions() == []

# Re-registration must not leave duplicate distinfo entries behind.
assert pm.load_setuptools_entrypoints("hello") == 1
assert len(pm.list_plugin_distinfo()) == 1
assert len(pm.list_plugin_distributions()) == 1


def test_add_tracefuncs(he_pm: PluginManager) -> None:
out: list[Any] = []

Expand Down