Context manager, atexit processing, and PEP 3143 DaemonContext.close

Ben Finney ben+python at
Sun May 17 02:50:23 CEST 2009

Howdy all,

I'm slowly developing PEP 3143 and, in parallel, its reference
implementation, the ‘python-daemon’ library
<URL:>. Feedback continues to
be welcome from people wanting to make a program become a daemon; please
try it out and critique the specification and/or the implementation.

Today a flaw has been uncovered by Pavol Babinčák. In diagnosing an
issue, we doscovered that PEP 3143 currently leads, in some common
circumstances, to exiting a context manager twice.

The current specification of the `DaemonContext` class says:

    Return:     None

    Close the daemon context. This performs the following step:

        * If the pidfile attribute is not None, exit its context


__exit__(exc_type, exc_value, exc_traceback)
    Return:        True or False as defined by the context manager

    Call the instance's close() method, then return True if the
    exception was handled or False if it was not.

but also:

    Return:     None

    Open the daemon context, turning the current program into a daemon
    process. This performs the following steps:

        * Register the close method to be called during Python's exit

This leads to the situation where the `DaemonContext.close` method can
be called twice:

    pidfile = FunkyLockFile()
    daemon_context = daemon.DaemonContext(pidfile=pidfile)
    with daemon_context:

According to the current specification, this will cause
`daemon_context.close()` to be called on exiting its context manager (at
the end of the `with` suite) *and* on program exit (via `atexit`

This will cause the `pidfile` context manager to be exited twice in
succession, which surely can't be good and is at least undefined AFAICT.

How should a context manager be implemented to handle situations like
this? One possible way is to raise an exception when trying to close a
not-open context manager. Another is to return immediately if the
attempt is made, making it safe to try closing a context manager
multiple times.

The “Register the close method to be called during Python's exit
processing” is there to ensure clean-up occurs even if the program
isn't using the DaemonContext as a context manager. Ideally, what I'd
like to do is *un*-register the `close` method after having already
closed it, so that exit processing *won't* call it. The `atexit` module,
though, doesn't appear to give me that option.

Ideas? How should this be addressed both Pythonically and respecting the
intent of PEP 3143?

 \       “For fast acting relief, try slowing down.” —Jane Wagner, via |
  `\                                                       Lily Tomlin |
_o__)                                                                  |
Ben Finney

More information about the Python-list mailing list