Package: pandaemonium
pandaemoniumn. the abode of all the daemonspandaemonium provides a framework for writing daemons in Python.  The API is
based on thethreading/multiprocessingmodel, so the primary way
of creating your own daemon is to either subclass and override therunmethod, or provide a function as thetargetto theDaemonclass.BesidesDaemonthere is also a locking pid file --PidLockFile.PidLockFilecan either be used manually, or, if a complete path and file
name are provided toDaemon, used automatically.simple usagefrom pandaemonium import Daemon

def DoSomethingInteresting():
    "Just like it says ;)"
    pass

daemon = Daemon(target=DoSomethingInteresting)
daemon.start()
#
# daemon.output will contain any stdout output generated during the
# daemonizing process, up to the stdin/stdout/stderr redirection
#
# daemon.error contains anything sent to the daemon's stderr -- which
# most likely means the daemon died due to an exception
#
# both can be parsed, examined, ignored, etc.or:from pandaemonium import Daemon

class MyDaemon(Daemon):
    def run():
        # do some interesting stuff

md = MyDaemon().start()The sequence of events that takes place whenstart()is called (adapted from
The Linux Programming Interface by Michael Kerrisk) is:detach from the current process, creating a new sessionturn off core dumpsset uid and gidset umaskset working directorycreate pid fileset signal handlersclose inherited file handlesredirect stdin/stdout/stderrIf any exceptions occur or if any feedback is generated during thestartprocess it will be available as theerrorandoutputattributes of the
daemon instance, where the parent process can analyze, print, etc before
quiting.Note:  Most guides on writing daemons specify setting the umask to 0, but
this creates a security hole as all files become world readable/writable by
default.  Pandaemonium sets the umask to 077, but that can be changed if
desired.advanced usageIf more control is needed than what is provided by the parameters of Daemon
then one has a couple options available:if certain set up / initialization steps need to happen somewhere in thestart()sequence, such as after setting the umask and before changing
the working directory::Daemon.stage4()
# stages 1-4 have now been completed
# do custom steps here
Daemon.start()
# stages 5-9 have now been completed, and run() calledone can also override any of the stages in a subclass (make sure and
decorate withcheck_stage):class MyDaemon(Daemon):
    def run(self, ip):
        # do stuff
    @check_stage
    def stage7(self):
        # do some custom stuff with signals set up

md = MyDaemon('192.168.11.1')
md.start()or, to simplify between foreground and daemon operation:foreground = sys.argv[2:3] == ['--foreground']
pid_file = PidLockFile('/some/path/to/lock.pid')
pid_file.acquire()
if foreground:
    pid_file.seal()
else:
    daemon = Daemon()
    daemon.pid_file = pid_file
    daemon.activate()
# at this point, in either foreground or daemon mode, the pid file has
# been sealed (has our correct pid written to it, and it has been
# closed)
run_main_program()If one's desire is to start the daemon and automatically have any output
printed to screen, one can usedaemon.report()which prints whatever was
received from the daemon and then quits.DaemonDaemon(target=None, args=None, kwargs=None, working_directory='/', umask=0, prevent_core=True, process_ids=None, inherit_files=None, signal_map=None, stdin=None, stdout=None, stderr=None)target: function to call when daemonizedargs: positional args to provide to targetkwargs: keyword args to provide to targetdetach:None(default) means figure it out,Truemeans yes,Falsemeans no.
Figuring it out means if the parent process isinit, or asuper server, do not detachworking_directory: directory to change to (relative to chroot, if one is in effect)umask: mask to use when creating filesprevent_core: prevent core dump files from being createdprocess_ids: tuple of (uid, gid) to switch process to (use (None, None) to disable)pid_file:None(default), or
a PidLockFile instance, or
the string of where to create a PidLockFileinherit_files: list of open files or file descriptors to keep opensignal_map: dictionary of signal names or numbers to method names or functionsstdin/stdout/stderr: streams to map the standard streams to.  default
isNonewhich is mapped toos.devnullDaemon.run()Method representing the daemon's activity.You may override this method in a subclass.  The standardrunmethod invokes the callable object passed to the object's constructor as
thetargetargument, if any, with sequential and keyword arguments taken
from theargsandkwargsarguments, respectively.Daemon.start()Start the daemon's activity.This may be called at most once per daemon object.  It arranges for the
object'srunmethod to be invoked as a daemon process.Daemon.monitor()Collects stdout and stderr from Daemon process until stage 9 and attaches
it to the daemon instance asoutputanderror.  Can be overridden
if one wants to do more interesting stuff with the daemon's outputDaemon.stage[1-9]()One can override the various stages for even more customizations options.
Make sure and decorate such functions withcheck_stage.PidLockFilePidLockFile(file_name, timeout)file_name: full path and name of file to use for lockingtimeout: how long to wait before concluding that an existing held lock is
not going to be released (default: -1, meaning conclude immediately)PidLockFile.acquire(timeout=None)attempt to capture the lock file; if timeout isNoneuse the time out
specified when PidLockFile was created.PidLockFile.seal()write the current process' PID into the acquired file and close it --
should only be called by the daemon process or the stored PID will not be
correct.PidLockFile.release()remove the lock file, releasing the lock.