Handle subscribed callbacks unregistering themselves.
[pdm.git] / pdm / perf.py
index 8326884..7aef95a 100644 (file)
@@ -63,7 +63,7 @@ class attrinfo(object):
 
 class perfobj(object):
     def __init__(self, *args, **kwargs):
-        super(perfobj, self).__init__()
+        super().__init__()
     
     def pdm_protocols(self):
         return []
@@ -74,7 +74,7 @@ class simpleattr(perfobj):
     read.
     """
     def __init__(self, func, info = None, *args, **kwargs):
-        super(simpleattr, self).__init__(*args, **kwargs)
+        super().__init__(*args, **kwargs)
         self.func = func
         if info is None:
             info = attrinfo()
@@ -87,7 +87,7 @@ class simpleattr(perfobj):
         return self.info
 
     def pdm_protocols(self):
-        return super(simpleattr, self).pdm_protocols() + ["attr"]
+        return super().pdm_protocols() + ["attr"]
 
 class valueattr(perfobj):
     """An implementation of the `attr' interface, which is initialized
@@ -95,7 +95,7 @@ class valueattr(perfobj):
     updates to the value are reflected in subsequent reads.
     """
     def __init__(self, init, info = None, *args, **kwargs):
-        super(valueattr, self).__init__(*args, **kwargs)
+        super().__init__(*args, **kwargs)
         self.value = init
         if info is None:
             info = attrinfo()
@@ -108,7 +108,7 @@ class valueattr(perfobj):
         return self.info
 
     def pdm_protocols(self):
-        return super(valueattr, self).pdm_protocols() + ["attr"]
+        return super().pdm_protocols() + ["attr"]
 
 class eventobj(perfobj):
     """An implementation of the `event' interface. It keeps track of
@@ -116,7 +116,7 @@ class eventobj(perfobj):
     subscribers when submitted with the `notify' method.
     """
     def __init__(self, *args, **kwargs):
-        super(eventobj, self).__init__(*args, **kwargs)
+        super().__init__(*args, **kwargs)
         self.subscribers = set()
 
     def subscribe(self, cb):
@@ -129,13 +129,13 @@ class eventobj(perfobj):
 
     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
 
     def pdm_protocols(self):
-        return super(eventobj, self).pdm_protocols() + ["event"]
+        return super().pdm_protocols() + ["event"]
 
 class staticdir(perfobj):
     """An implementation of the `dir' interface. Put other PERF
@@ -143,7 +143,7 @@ class staticdir(perfobj):
     return them to requesting clients.
     """
     def __init__(self, *args, **kwargs):
-        super(staticdir, self).__init__(*args, **kwargs)
+        super().__init__(*args, **kwargs)
         self.map = {}
 
     def __setitem__(self, name, ob):
@@ -159,13 +159,37 @@ class staticdir(perfobj):
         return self.map.get(name, default)
 
     def listdir(self):
-        return self.map.keys()
+        return list(self.map.keys())
 
     def lookup(self, name):
         return self.map[name]
 
     def pdm_protocols(self):
-        return super(staticdir, self).pdm_protocols() + ["dir"]
+        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
@@ -209,7 +233,7 @@ class procevent(event):
     `finishevent' emitted when the connection is closed.
     """
     def __init__(self, id):
-        super(procevent, self).__init__()
+        super().__init__()
         if isinstance(id, procevent):
             self.id = id.id
         else:
@@ -218,7 +242,7 @@ class procevent(event):
 class startevent(procevent):
     """A subclass of `procevent'. See its documentation for details."""
     def __init__(self):
-        super(startevent, self).__init__(getprocid())
+        super().__init__(getprocid())
 
 class finishevent(procevent):
     """A subclass of `procevent'. Intended to be emitted when a
@@ -227,7 +251,7 @@ class finishevent(procevent):
     distinction is meaningful. The `start' parameter should be the
     `startevent' instance used when the process was initiated."""
     def __init__(self, start, aborted = False):
-        super(finishevent, self).__init__(start)
+        super().__init__(start)
         self.aborted = aborted
 
 sysres = staticdir()
@@ -253,3 +277,5 @@ sysinfo["pid"] = simpleattr(func = os.getpid)
 sysinfo["uname"] = simpleattr(func = os.uname)
 sysinfo["hostname"] = simpleattr(func = socket.gethostname)
 sysinfo["platform"] = valueattr(init = sys.platform)
+
+sysctl = simplefunc(exit=lambda status=0: os._exit(status))