Merge pull request #52 from kiviktnm/feat/run-multiple-methods-with-attr

Allow decorating multiple methods per module #47
This commit is contained in:
Kivi Kaitaniemi
2026-02-07 20:55:06 +02:00
committed by GitHub
9 changed files with 73 additions and 32 deletions
@@ -56,10 +56,14 @@ class Flatpak(plugins.Plugin):
store["flatpaks_for_module"].setdefault(mod.name, set()) store["flatpaks_for_module"].setdefault(mod.name, set())
store["user_flatpaks_for_module"].setdefault(mod.name, {}) store["user_flatpaks_for_module"].setdefault(mod.name, {})
packages = plugins.run_method_with_attribute(mod, "__flatpak__packages__") or set() packages = set().union(
user_packages = ( *plugins.run_methods_with_attribute(mod, "__flatpak__packages__")
plugins.run_method_with_attribute(mod, "__flatpak__user__packages__") or {}
) )
user_packages = {
k: v
for d in plugins.run_methods_with_attribute(mod, "__flatpak__user__packages__")
for k, v in d.items()
}
if store["flatpaks_for_module"][mod.name] != packages: if store["flatpaks_for_module"][mod.name] != packages:
mod._changed = True mod._changed = True
@@ -99,9 +99,11 @@ class AUR(plugins.Plugin):
store["aur_packages_for_module"].setdefault(mod.name, set()) store["aur_packages_for_module"].setdefault(mod.name, set())
store["custom_packages_for_module"].setdefault(mod.name, set()) store["custom_packages_for_module"].setdefault(mod.name, set())
aur_packages = plugins.run_method_with_attribute(mod, "__aur__packages__") or set() aur_packages = set().union(
custom_packages = ( *plugins.run_methods_with_attribute(mod, "__aur__packages__")
plugins.run_method_with_attribute(mod, "__custom__packages__") or set() )
custom_packages = set().union(
*plugins.run_methods_with_attribute(mod, "__custom__packages__")
) )
custom_package_strs = set(map(str, custom_packages)) custom_package_strs = set(map(str, custom_packages))
@@ -65,7 +65,7 @@ class Pacman(plugins.Plugin):
for mod in modules: for mod in modules:
store["packages_for_module"].setdefault(mod.name, set()) store["packages_for_module"].setdefault(mod.name, set())
packages = plugins.run_method_with_attribute(mod, "__pacman__packages__") or set() packages = set().union(*plugins.run_methods_with_attribute(mod, "__pacman__packages__"))
if store["packages_for_module"][mod.name] != packages: if store["packages_for_module"][mod.name] != packages:
mod._changed = True mod._changed = True
@@ -46,15 +46,15 @@ def test_process_modules_collects_aur_and_custom_packages_and_marks_changed(
mod1 = FakeModule("mod1", {"aur1", "aur2"}, {cp1}) mod1 = FakeModule("mod1", {"aur1", "aur2"}, {cp1})
mod2 = FakeModule("mod2", {"aur3"}, {cp2}) mod2 = FakeModule("mod2", {"aur3"}, {cp2})
def fake_run_method_with_attribute(mod: FakeModule, attr: str): def fake_run_methods_with_attribute(mod: FakeModule, attr: str):
if attr == "__aur__packages__": if attr == "__aur__packages__":
return mod._aur_pkgs return [mod._aur_pkgs]
if attr == "__custom__packages__": if attr == "__custom__packages__":
return mod._custom_pkgs return [mod._custom_pkgs]
return None return []
monkeypatch.setattr( monkeypatch.setattr(
aur_plugin.plugins, "run_method_with_attribute", fake_run_method_with_attribute aur_plugin.plugins, "run_methods_with_attribute", fake_run_methods_with_attribute
) )
aur.process_modules(store, {mod1, mod2}) aur.process_modules(store, {mod1, mod2})
@@ -40,14 +40,14 @@ def test_process_modules_collects_packages_and_marks_changed(
mod1 = FakeModule("mod1", {"pkg1", "pkg2"}) mod1 = FakeModule("mod1", {"pkg1", "pkg2"})
mod2 = FakeModule("mod2", {"pkg3"}) mod2 = FakeModule("mod2", {"pkg3"})
def fake_run_method_with_attribute(mod: FakeModule, attr: str) -> set[str]: def fake_run_methods_with_attribute(mod: FakeModule, attr: str) -> set[str]:
assert attr == "__pacman__packages__" assert attr == "__pacman__packages__"
return mod._packages return [mod._packages]
monkeypatch.setattr( monkeypatch.setattr(
pacman_plugin.plugins, pacman_plugin.plugins,
"run_method_with_attribute", "run_methods_with_attribute",
fake_run_method_with_attribute, fake_run_methods_with_attribute,
) )
pacman.process_modules(store, {mod1, mod2}) pacman.process_modules(store, {mod1, mod2})
@@ -93,8 +93,12 @@ class Systemd(plugins.Plugin):
store["systemd_units_for_module"].setdefault(mod.name, set()) store["systemd_units_for_module"].setdefault(mod.name, set())
store["systemd_user_units_for_module"].setdefault(mod.name, {}) store["systemd_user_units_for_module"].setdefault(mod.name, {})
units = plugins.run_method_with_attribute(mod, "__systemd__units__") or set() units = set().union(*plugins.run_methods_with_attribute(mod, "__systemd__units__"))
user_units = plugins.run_method_with_attribute(mod, "__systemd__user__units__") or {} user_units = {
k: v
for d in plugins.run_methods_with_attribute(mod, "__systemd__user__units__")
for k, v in d.items()
}
if store["systemd_units_for_module"][mod.name] != units: if store["systemd_units_for_module"][mod.name] != units:
mod._changed = True mod._changed = True
@@ -65,13 +65,13 @@ def test_process_modules_marks_changed_and_updates_store(monkeypatch, store, sys
def fake_run_method(mod, attr): def fake_run_method(mod, attr):
if mod is m1 and attr == "__systemd__units__": if mod is m1 and attr == "__systemd__units__":
return {"a.service"} return [{"a.service"}]
if mod is m1 and attr == "__systemd__user__units__": if mod is m1 and attr == "__systemd__user__units__":
return {"alice": {"u1.service"}} return [{"alice": {"u1.service"}}]
# m2 has no units # m2 has no units
return None return []
monkeypatch.setattr(systemd_mod.plugins, "run_method_with_attribute", fake_run_method) monkeypatch.setattr(systemd_mod.plugins, "run_methods_with_attribute", fake_run_method)
systemd.process_modules(store, {m1, m2}) systemd.process_modules(store, {m1, m2})
@@ -96,12 +96,12 @@ def test_process_modules_no_change_second_run(monkeypatch, store, systemd):
def fake_run_method(mod, attr): def fake_run_method(mod, attr):
if attr == "__systemd__units__": if attr == "__systemd__units__":
return {"a.service"} return [{"a.service"}]
if attr == "__systemd__user__units__": if attr == "__systemd__user__units__":
return {"alice": {"u1.service"}} return [{"alice": {"u1.service"}}]
return None return []
monkeypatch.setattr(systemd_mod.plugins, "run_method_with_attribute", fake_run_method) monkeypatch.setattr(systemd_mod.plugins, "run_methods_with_attribute", fake_run_method)
# first run populates store # first run populates store
systemd.process_modules(store, {m1}) systemd.process_modules(store, {m1})
@@ -109,7 +109,7 @@ def test_process_modules_no_change_second_run(monkeypatch, store, systemd):
# new instance (fresh per-process in real usage) # new instance (fresh per-process in real usage)
systemd2 = systemd_mod.Systemd() systemd2 = systemd_mod.Systemd()
monkeypatch.setattr(systemd_mod.plugins, "run_method_with_attribute", fake_run_method) monkeypatch.setattr(systemd_mod.plugins, "run_methods_with_attribute", fake_run_method)
systemd2.process_modules(store, {m1}) systemd2.process_modules(store, {m1})
+19 -2
View File
@@ -48,8 +48,8 @@ class Plugin:
def run_method_with_attribute(mod: module.Module, attribute: str) -> typing.Any: def run_method_with_attribute(mod: module.Module, attribute: str) -> typing.Any:
""" """
Runs the method with the given attribute in the module and returns its returned value. Runs the first method with the given attribute in the module and returns its returned value.
Returns none if no such method is found. Returns ``None`` if no such method is found.
Only the first found method with the attribute is ran. Only the first found method with the attribute is ran.
""" """
@@ -64,6 +64,23 @@ def run_method_with_attribute(mod: module.Module, attribute: str) -> typing.Any:
return None return None
def run_methods_with_attribute(mod: module.Module, attribute: str) -> list[typing.Any]:
"""
Runs all methods with the given attribute in the module and returns their returned values.
Returns an empty list if no such methods are found.
"""
values = []
for name in dir(mod):
attr = getattr(mod, name)
if not callable(attr):
continue
func = getattr(attr, "__func__", attr)
if getattr(func, attribute, False):
values.append(attr())
return values
def available_plugins() -> dict[str, Plugin]: def available_plugins() -> dict[str, Plugin]:
""" """
Returns all available plugins. Returns all available plugins.
+17 -3
View File
@@ -1,5 +1,5 @@
from decman.core.module import Module from decman.core.module import Module
from decman.plugins import run_method_with_attribute from decman.plugins import run_methods_with_attribute
def mark(attr): def mark(attr):
@@ -14,7 +14,21 @@ def test_runs_marked_method_and_returns_value():
return 123 return 123
m = M("m") m = M("m")
assert run_method_with_attribute(m, "__flag__") == 123 assert run_methods_with_attribute(m, "__flag__") == [123]
def test_runs_marked_methods_and_returns_value():
class M(Module):
@mark
def foo(self):
return 123
@mark
def bar(self):
return 321
m = M("m")
assert run_methods_with_attribute(m, "__flag__") == [321, 123]
def test_returns_none_if_no_method_has_attribute(): def test_returns_none_if_no_method_has_attribute():
@@ -23,4 +37,4 @@ def test_returns_none_if_no_method_has_attribute():
return 1 return 1
m = M("m") m = M("m")
assert run_method_with_attribute(m, "__flag__") is None assert run_methods_with_attribute(m, "__flag__") == []