+ 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)
+ return 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
+ the time it was created, so that listening clients can precisely
+ measure the time between event notifications.
+
+ Subclasses should make sure to call the __init__ method if they
+ override it.
+ """
+ def __init__(self):
+ self.time = time.time()
+
+idlock = threading.Lock()
+procevid = 0
+
+def getprocid():
+ global procevid
+ idlock.acquire()
+ try:
+ ret = procevid
+ procevid += 1
+ return ret
+ finally:
+ idlock.release()
+
+class procevent(event):
+ """A subclass of the `event' class meant to group several events
+ related to the same process. Create a new process by creating (a
+ subclass of) the `startevent' class, and subsequent events in the
+ same process by passing that startevent as the `id' parameter.
+
+ It works by having `startevent' allocate a unique ID for each
+ process, and every other procevent initializing from that
+ startevent copying the ID. The data field `id' contains the ID so
+ that it can be compared by clients.
+
+ An example of such a process might be a client connection, where a
+ `startevent' is emitted when a client connects, another subclass
+ of `procevent' emitted when the client runs a command, and a
+ `finishevent' emitted when the connection is closed.
+ """
+ def __init__(self, id):
+ super().__init__()
+ if isinstance(id, procevent):
+ self.id = id.id
+ else:
+ self.id = id
+
+class startevent(procevent):
+ """A subclass of `procevent'. See its documentation for details."""
+ def __init__(self):
+ super().__init__(getprocid())
+
+class finishevent(procevent):
+ """A subclass of `procevent'. Intended to be emitted when a
+ process finishes and terminates. The `aborted' field can be used
+ to indicate whether the process completed successfully, if such a
+ distinction is meaningful. The `start' parameter should be the
+ `startevent' instance used when the process was initiated."""
+ def __init__(self, start, aborted = False):
+ super().__init__(start)
+ self.aborted = aborted