Throw more informative error classes from perf.
[pdm.git] / pdm / perf.py
index bad3112..7c0d561 100644 (file)
@@ -51,6 +51,13 @@ __all__ = ["attrinfo", "simpleattr", "valueattr", "eventobj",
            "staticdir", "event", "procevent", "startevent",
            "finishevent"]
 
            "staticdir", "event", "procevent", "startevent",
            "finishevent"]
 
+class error(Exception):
+    pass
+class nosuchname(LookupError, error):
+    pass
+class nosuchproto(error):
+    pass
+
 class attrinfo(object):
     """The return value of the `attrinfo' method on `attr' objects as
     described in L{pdm.srv.perf}.
 class attrinfo(object):
     """The return value of the `attrinfo' method on `attr' objects as
     described in L{pdm.srv.perf}.
@@ -129,7 +136,7 @@ class eventobj(perfobj):
 
     def notify(self, event):
         """Notify all subscribers with the given event object."""
 
     def notify(self, event):
         """Notify all subscribers with the given event object."""
-        for cb in self.subscribers:
+        for cb in list(self.subscribers):
             try:
                 cb(event)
             except: pass
             try:
                 cb(event)
             except: pass
@@ -167,6 +174,30 @@ class staticdir(perfobj):
     def pdm_protocols(self):
         return super().pdm_protocols() + ["dir"]
 
     def pdm_protocols(self):
         return super().pdm_protocols() + ["dir"]
 
+class simplefunc(perfobj):
+    """An implementation of the `invoke' interface. Put callables in
+    it using the normal dict assignment syntax, and it will call them
+    when invoked with the corresponding method name. Additionally, it
+    updates itself with any keyword-arguments it is initialized with."""
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args)
+        self.map = {}
+        self.map.update(kwargs)
+
+    def __setitem__(self, name, func):
+        self.map[name] = func
+
+    def __delitem__(self, name):
+        del self.map[name]
+
+    def invoke(self, method, *args, **kwargs):
+        if method not in self.map:
+            raise AttributeError(method)
+        self.map[method](*args, **kwargs)
+
+    def pdm_protocols(self):
+        return super().pdm_protocols() + ["invoke"]
+
 class event(object):
     """This class should be subclassed by all event objects sent via
     the `event' interface. Its main utility is that it keeps track of
 class event(object):
     """This class should be subclassed by all event objects sent via
     the `event' interface. Its main utility is that it keeps track of
@@ -253,3 +284,13 @@ sysinfo["pid"] = simpleattr(func = os.getpid)
 sysinfo["uname"] = simpleattr(func = os.uname)
 sysinfo["hostname"] = simpleattr(func = socket.gethostname)
 sysinfo["platform"] = valueattr(init = sys.platform)
 sysinfo["uname"] = simpleattr(func = os.uname)
 sysinfo["hostname"] = simpleattr(func = socket.gethostname)
 sysinfo["platform"] = valueattr(init = sys.platform)
+
+def reload(modname):
+    mod = sys.modules.get(modname)
+    if mod is None:
+        raise ValueError(modname)
+    import importlib
+    importlib.reload(mod)
+
+sysctl = simplefunc(exit=lambda status=0: os._exit(status),
+                    reload=reload)