Merge branch 'master' into python3
authorFredrik Tolf <fredrik@dolda2000.com>
Fri, 23 Dec 2011 01:30:26 +0000 (02:30 +0100)
committerFredrik Tolf <fredrik@dolda2000.com>
Fri, 23 Dec 2011 01:30:26 +0000 (02:30 +0100)
Conflicts:
pdm/perf.py

pdm/cli.py
pdm/perf.py

index 9924d40..32580bb 100644 (file)
@@ -1,7 +1,9 @@
-"""Management for daemon processes
+"""Python Daemon Management -- Client functions
 
-This module provides some client support for the daemon management
-provided in the pdm.srv module.
+This module implements the client part of the PDM protocols. The
+primary objects of interest are the replclient and perfclient classes,
+which implement support for their respective protocols. See their
+documentation for details.
 """
 
 import socket, pickle, struct, select, threading
@@ -315,6 +317,11 @@ class perfclient(client):
         of the slash. For instance, find("pdm.perf.sysres/cputime")
         will return the built-in attribute for reading the CPU time
         used by the server process.
+
+        The proxy objects returned by this function are cached and the
+        same object are returned the next time the same name is
+        requested, which means that they are kept live until the
+        client connection is closed.
         """
         ret = self.names.get(name)
         if ret is None:
index 7d8b48b..feb8b4a 100644 (file)
@@ -1,6 +1,54 @@
+"""Python Daemon Management -- PERF utilities
+
+This module serves two purposes: It has a few utility classes
+for implementing PERF interfaces in common ways, and uses those
+classes to implement some standard PERF objects that can be used by
+PERF clients connecting to any PERF server.
+
+See the documentation for pdm.srv.perf for a description of the
+various PERF interfaces.
+
+It contains two named PERF objects:
+
+ * sysres -- A directory containing the following objects pertaining
+             to the resource usage of the server process:
+   * realtime -- An attribute returning the amount of real time
+                 since the PDM module was imported (which likely
+                 coincides with the amount of time the server process
+                 has been running).
+   * cputime  -- An attribute returning the amount of CPU time
+                 consumed by the server process (in both user and
+                 kernel mode).
+   * utime    -- An attribute returning the amount of CPU time the
+                 server process has spent in user mode.
+   * stime    -- An attribute returning the amount of CPU time the
+                 server process has spent in kernel mode.
+   * maxrss   -- An attribute returning the largest resident set size
+                 the server process has used during its lifetime.
+   * rusage   -- An attribute returning the current rusage of the
+                 server process.
+* sysinfo -- A directory containing the following objects pertaining
+             to the environment of the server process:
+   * pid      -- An attribute returning the PID of the server process.
+   * uname    -- An attribute returning the uname information of the
+                 system.
+   * hostname -- An attribute returning the hostname of the system.
+   * platform -- An attribute returning the Python build platform.
+"""
+
 import os, sys, resource, time, socket, threading
 
+__all__ = ["attrinfo", "simpleattr", "valueattr", "eventobj",
+           "staticdir", "event", "procevent", "startevent",
+           "finishevent"]
+
 class attrinfo(object):
+    """The return value of the `attrinfo' method on `attr' objects as
+    described in pdm.srv.perf.
+
+    Currently contains a single data field, `desc', which should have
+    a human-readable description of the purpose of the attribute.
+    """
     def __init__(self, desc = None):
         self.desc = desc
 
@@ -12,6 +60,10 @@ class perfobj(object):
         return []
 
 class simpleattr(perfobj):
+    """An implementation of the `attr' interface, which is initialized
+    with a function, and returns whatever that function returns when
+    read.
+    """
     def __init__(self, func, info = None, *args, **kwargs):
         super().__init__(*args, **kwargs)
         self.func = func
@@ -29,6 +81,10 @@ class simpleattr(perfobj):
         return super().pdm_protocols() + ["attr"]
 
 class valueattr(perfobj):
+    """An implementation of the `attr' interface, which is initialized
+    with a single value, and returns that value when read. Subsequent
+    updates to the value are reflected in subsequent reads.
+    """
     def __init__(self, init, info = None, *args, **kwargs):
         super().__init__(*args, **kwargs)
         self.value = init
@@ -45,8 +101,11 @@ class valueattr(perfobj):
     def pdm_protocols(self):
         return super().pdm_protocols() + ["attr"]
 
-
 class eventobj(perfobj):
+    """An implementation of the `event' interface. It keeps track of
+    subscribers, and will multiplex any event to all current
+    subscribers when submitted with the `notify' method.
+    """
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
         self.subscribers = set()
@@ -60,6 +119,7 @@ class eventobj(perfobj):
         self.subscribers.remove(cb)
 
     def notify(self, event):
+        """Notify all subscribers with the given event object."""
         for cb in self.subscribers:
             try:
                 cb(event)
@@ -69,6 +129,10 @@ class eventobj(perfobj):
         return super().pdm_protocols() + ["event"]
 
 class staticdir(perfobj):
+    """An implementation of the `dir' interface. Put other PERF
+    objects in it using the normal dict assignment syntax, and it will
+    return them to requesting clients.
+    """
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
         self.map = {}
@@ -95,6 +159,14 @@ class staticdir(perfobj):
         return super().pdm_protocols() + ["dir"]
 
 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()
 
@@ -112,6 +184,21 @@ def getprocid():
         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):
@@ -120,11 +207,17 @@ class procevent(event):
             self.id = id
 
 class startevent(procevent):
+    """A subclass of `procevent'. See its documentation for details."""
     def __init__(self):
         super().__init__(getprocid())
 
 class finishevent(procevent):
-    def __init__(self, start, aborted):
+    """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