diff --git a/mitmproxy/addonmanager.py b/mitmproxy/addonmanager.py index ec82d6507..9094288b7 100644 --- a/mitmproxy/addonmanager.py +++ b/mitmproxy/addonmanager.py @@ -1,3 +1,4 @@ +import types import typing import traceback import contextlib @@ -229,11 +230,18 @@ class AddonManager: for a in traverse([addon]): func = getattr(a, name, None) if func: - if not callable(func): + if callable(func): + func(*args, **kwargs) + elif isinstance(func, types.ModuleType): + # we gracefully exclude module imports with the same name as hooks. + # For example, a user may have "from mitmproxy import log" in an addon, + # which has the same name as the "log" hook. In this particular case, + # we end up in an error loop because we "log" this error. + pass + else: raise exceptions.AddonManagerError( - "Addon handler %s not callable" % name + "Addon handler {} ({}) not callable".format(name, a) ) - func(*args, **kwargs) def trigger(self, name, *args, **kwargs): """ diff --git a/test/mitmproxy/test_addonmanager.py b/test/mitmproxy/test_addonmanager.py index 678bc1b70..5bff61d1c 100644 --- a/test/mitmproxy/test_addonmanager.py +++ b/test/mitmproxy/test_addonmanager.py @@ -117,6 +117,11 @@ def test_simple(): a.trigger("tick") tctx.master.has_log("not callable") + tctx.master.clear() + a.get("one").tick = addons + a.trigger("tick") + assert not tctx.master.has_log("not callable") + a.remove(a.get("one")) assert not a.get("one")