diff -Nru python-daemon-1.5.5/ChangeLog python-daemon-1.6/ChangeLog --- python-daemon-1.5.5/ChangeLog 2010-03-02 09:26:36.000000000 +0000 +++ python-daemon-1.6/ChangeLog 2010-05-10 10:37:50.000000000 +0000 @@ -1,3 +1,25 @@ +2010-05-10 Ben Finney + + Version 1.6 released. + + * Use absolute imports to disambiguate provenance of names. + * setup.py: Require ‘lockfile >=0.9’. + * daemon/pidfile.py: Renamed from ‘daemon/pidlockfile.py’. Change + references elsewhere to use this new name. + * test/test_pidfile.py: Renamed from ‘test/test_pidlockfile.py’. + Change references elsewhere to use this new name. + * daemon/pidfile.py: Remove functionality now migrated to ‘lockfile’ + library. + +2010-03-09 Ben Finney + + * Use ‘unicode’ data type for all text values. + * Prepare for Python 3 upgrade why tweaking some names and imports. + +2010-03-03 Ben Finney + + * MANIFEST.in: Include the documentation in the distribution. + 2010-03-02 Ben Finney Version 1.5.5 released. diff -Nru python-daemon-1.5.5/daemon/daemon.py python-daemon-1.6/daemon/daemon.py --- python-daemon-1.5.5/daemon/daemon.py 2010-02-26 03:09:27.000000000 +0000 +++ python-daemon-1.6/daemon/daemon.py 2010-05-10 10:35:20.000000000 +0000 @@ -18,6 +18,8 @@ """ Daemon process behaviour. """ +from __future__ import absolute_import + import os import sys import resource @@ -206,7 +208,7 @@ def __init__( self, chroot_directory=None, - working_directory='/', + working_directory=u'/', umask=0, uid=None, gid=None, @@ -394,7 +396,7 @@ """ exception = SystemExit( - "Terminating on signal %(signal_number)r" + u"Terminating on signal %(signal_number)r" % vars()) raise exception @@ -470,7 +472,7 @@ os.chdir(directory) except Exception, exc: error = DaemonOSEnvironmentError( - "Unable to change working directory (%(exc)s)" + u"Unable to change working directory (%(exc)s)" % vars()) raise error @@ -488,7 +490,7 @@ os.chroot(directory) except Exception, exc: error = DaemonOSEnvironmentError( - "Unable to change root directory (%(exc)s)" + u"Unable to change root directory (%(exc)s)" % vars()) raise error @@ -500,7 +502,7 @@ os.umask(mask) except Exception, exc: error = DaemonOSEnvironmentError( - "Unable to change file creation mask (%(exc)s)" + u"Unable to change file creation mask (%(exc)s)" % vars()) raise error @@ -518,7 +520,7 @@ os.setuid(uid) except Exception, exc: error = DaemonOSEnvironmentError( - "Unable to change file creation mask (%(exc)s)" + u"Unable to change file creation mask (%(exc)s)" % vars()) raise error @@ -539,7 +541,7 @@ core_limit_prev = resource.getrlimit(core_resource) except ValueError, exc: error = DaemonOSEnvironmentError( - "System does not support RLIMIT_CORE resource limit (%(exc)s)" + u"System does not support RLIMIT_CORE resource limit (%(exc)s)" % vars()) raise error @@ -575,12 +577,12 @@ exc_errno = exc.errno exc_strerror = exc.strerror error = DaemonProcessDetachError( - "%(error_message)s: [%(exc_errno)d] %(exc_strerror)s" % vars()) + u"%(error_message)s: [%(exc_errno)d] %(exc_strerror)s" % vars()) raise error - fork_then_exit_parent(error_message="Failed first fork") + fork_then_exit_parent(error_message=u"Failed first fork") os.setsid() - fork_then_exit_parent(error_message="Failed second fork") + fork_then_exit_parent(error_message=u"Failed second fork") def is_process_started_by_init(): @@ -679,8 +681,8 @@ pass else: error = DaemonOSEnvironmentError( - "Failed to close file descriptor %(fd)d" - " (%(exc)s)" + u"Failed to close file descriptor %(fd)d" + u" (%(exc)s)" % vars()) raise error @@ -742,10 +744,10 @@ """ name_map = { - 'SIGTSTP': None, - 'SIGTTIN': None, - 'SIGTTOU': None, - 'SIGTERM': 'terminate', + u'SIGTSTP': None, + u'SIGTTIN': None, + u'SIGTTOU': None, + u'SIGTERM': u'terminate', } signal_map = dict( (getattr(signal, name), target) diff -Nru python-daemon-1.5.5/daemon/__init__.py python-daemon-1.6/daemon/__init__.py --- python-daemon-1.5.5/daemon/__init__.py 2010-01-20 11:33:10.000000000 +0000 +++ python-daemon-1.6/daemon/__init__.py 2010-05-10 10:35:20.000000000 +0000 @@ -37,11 +37,13 @@ """ -import version -from daemon import DaemonContext +from __future__ import absolute_import + +from . import version +from .daemon import DaemonContext _version = version.version _copyright = version.copyright _license = version.license -_url = "http://pypi.python.org/pypi/python-daemon/" +_url = u"http://pypi.python.org/pypi/python-daemon/" diff -Nru python-daemon-1.5.5/daemon/pidfile.py python-daemon-1.6/daemon/pidfile.py --- python-daemon-1.5.5/daemon/pidfile.py 1970-01-01 00:00:00.000000000 +0000 +++ python-daemon-1.6/daemon/pidfile.py 2010-05-10 10:35:20.000000000 +0000 @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- + +# daemon/pidfile.py +# Part of python-daemon, an implementation of PEP 3143. +# +# Copyright © 2008–2010 Ben Finney +# +# This is free software: you may copy, modify, and/or distribute this work +# under the terms of the Python Software Foundation License, version 2 or +# later as published by the Python Software Foundation. +# No warranty expressed or implied. See the file LICENSE.PSF-2 for details. + +""" Lockfile behaviour implemented via Unix PID files. + """ + +from __future__ import absolute_import + +from lockfile.pidlockfile import PIDLockFile + + +class TimeoutPIDLockFile(PIDLockFile, object): + """ Lockfile with default timeout, implemented as a Unix PID file. + + This uses the ``PIDLockFile`` implementation, with the + following changes: + + * The `acquire_timeout` parameter to the initialiser will be + used as the default `timeout` parameter for the `acquire` + method. + + """ + + def __init__(self, path, acquire_timeout=None, *args, **kwargs): + """ Set up the parameters of a TimeoutPIDLockFile. """ + self.acquire_timeout = acquire_timeout + super(TimeoutPIDLockFile, self).__init__(path, *args, **kwargs) + + def acquire(self, timeout=None, *args, **kwargs): + """ Acquire the lock. """ + if timeout is None: + timeout = self.acquire_timeout + super(TimeoutPIDLockFile, self).acquire(timeout, *args, **kwargs) diff -Nru python-daemon-1.5.5/daemon/pidlockfile.py python-daemon-1.6/daemon/pidlockfile.py --- python-daemon-1.5.5/daemon/pidlockfile.py 2010-01-20 11:33:10.000000000 +0000 +++ python-daemon-1.6/daemon/pidlockfile.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,194 +0,0 @@ -# -*- coding: utf-8 -*- - -# daemon/pidlockfile.py -# Part of python-daemon, an implementation of PEP 3143. -# -# Copyright © 2008–2010 Ben Finney -# -# This is free software: you may copy, modify, and/or distribute this work -# under the terms of the Python Software Foundation License, version 2 or -# later as published by the Python Software Foundation. -# No warranty expressed or implied. See the file LICENSE.PSF-2 for details. - -""" Lockfile behaviour implemented via Unix PID files. - """ - -import os -import errno - -from lockfile import ( - LinkFileLock, - AlreadyLocked, LockFailed, - NotLocked, NotMyLock, - ) - - -class PIDFileError(Exception): - """ Abstract base class for errors specific to PID files. """ - -class PIDFileParseError(ValueError, PIDFileError): - """ Raised when parsing contents of PID file fails. """ - - -class PIDLockFile(LinkFileLock, object): - """ Lockfile implemented as a Unix PID file. - - The PID file is named by the attribute `path`. When locked, - the file will be created with a single line of text, - containing the process ID (PID) of the process that acquired - the lock. - - The lock is acquired and maintained as per `LinkFileLock`. - - """ - - def read_pid(self): - """ Get the PID from the lock file. - """ - result = read_pid_from_pidfile(self.path) - return result - - def acquire(self, *args, **kwargs): - """ Acquire the lock. - - Locks the PID file then creates the PID file for this - lock. The `timeout` parameter is used as for the - `LinkFileLock` class. - - """ - super(PIDLockFile, self).acquire(*args, **kwargs) - try: - write_pid_to_pidfile(self.path) - except OSError, exc: - error = LockFailed("%(exc)s" % vars()) - raise error - - def release(self): - """ Release the lock. - - Removes the PID file then releases the lock, or raises an - error if the current process does not hold the lock. - - """ - if self.i_am_locking(): - remove_existing_pidfile(self.path) - super(PIDLockFile, self).release() - - def break_lock(self): - """ Break an existing lock. - - If the lock is held, breaks the lock and removes the PID - file. - - """ - super(PIDLockFile, self).break_lock() - remove_existing_pidfile(self.path) - - -class TimeoutPIDLockFile(PIDLockFile): - """ Lockfile with default timeout, implemented as a Unix PID file. - - This uses the ``PIDLockFile`` implementation, with the - following changes: - - * The `acquire_timeout` parameter to the initialiser will be - used as the default `timeout` parameter for the `acquire` - method. - - """ - - def __init__(self, path, acquire_timeout=None, *args, **kwargs): - """ Set up the parameters of a DaemonRunnerLock. """ - self.acquire_timeout = acquire_timeout - super(TimeoutPIDLockFile, self).__init__(path, *args, **kwargs) - - def acquire(self, timeout=None, *args, **kwargs): - """ Acquire the lock. """ - if timeout is None: - timeout = self.acquire_timeout - super(TimeoutPIDLockFile, self).acquire(timeout, *args, **kwargs) - - -def read_pid_from_pidfile(pidfile_path): - """ Read the PID recorded in the named PID file. - - Read and return the numeric PID recorded as text in the named - PID file. If the PID file does not exist, return ``None``. If - the content is not a valid PID, raise ``PIDFileParseError``. - - """ - pid = None - pidfile = None - try: - pidfile = open(pidfile_path, 'r') - except IOError, exc: - if exc.errno == errno.ENOENT: - pass - else: - raise - - if pidfile: - # According to the FHS 2.3 section on PID files in ‘/var/run’: - # - # The file must consist of the process identifier in - # ASCII-encoded decimal, followed by a newline character. … - # - # Programs that read PID files should be somewhat flexible - # in what they accept; i.e., they should ignore extra - # whitespace, leading zeroes, absence of the trailing - # newline, or additional lines in the PID file. - - line = pidfile.readline().strip() - try: - pid = int(line) - except ValueError: - raise PIDFileParseError( - "PID file %(pidfile_path)r contents invalid" % vars()) - pidfile.close() - - return pid - - -def write_pid_to_pidfile(pidfile_path): - """ Write the PID in the named PID file. - - Get the numeric process ID (“PID”) of the current process - and write it to the named file as a line of text. - - """ - open_flags = (os.O_CREAT | os.O_EXCL | os.O_WRONLY) - open_mode = ( - ((os.R_OK | os.W_OK) << 6) | - ((os.R_OK) << 3) | - ((os.R_OK))) - pidfile_fd = os.open(pidfile_path, open_flags, open_mode) - pidfile = os.fdopen(pidfile_fd, 'w') - - # According to the FHS 2.3 section on PID files in ‘/var/run’: - # - # The file must consist of the process identifier in - # ASCII-encoded decimal, followed by a newline character. For - # example, if crond was process number 25, /var/run/crond.pid - # would contain three characters: two, five, and newline. - - pid = os.getpid() - line = "%(pid)d\n" % vars() - pidfile.write(line) - pidfile.close() - - -def remove_existing_pidfile(pidfile_path): - """ Remove the named PID file if it exists. - - Remove the named PID file. Ignore the condition if the file - does not exist, since that only means we are already in the - desired state. - - """ - try: - os.remove(pidfile_path) - except OSError, exc: - if exc.errno == errno.ENOENT: - pass - else: - raise diff -Nru python-daemon-1.5.5/daemon/runner.py python-daemon-1.6/daemon/runner.py --- python-daemon-1.5.5/daemon/runner.py 2010-01-20 11:33:10.000000000 +0000 +++ python-daemon-1.6/daemon/runner.py 2010-05-10 10:35:20.000000000 +0000 @@ -17,14 +17,17 @@ """ Daemon runner library. """ +from __future__ import absolute_import + import sys import os import signal import errno -import pidlockfile +import lockfile -from daemon import DaemonContext +from . import pidfile +from .daemon import DaemonContext class DaemonRunnerError(Exception): @@ -51,7 +54,7 @@ """ - start_message = "started with pid %(pid)d" + start_message = u"started with pid %(pid)d" def __init__(self, app): """ Set up the parameters of a new runner. @@ -92,8 +95,8 @@ """ progname = os.path.basename(argv[0]) usage_exit_code = 2 - action_usage = "|".join(self.action_funcs.keys()) - message = "usage: %(progname)s %(action_usage)s" % vars() + action_usage = u"|".join(self.action_funcs.keys()) + message = u"usage: %(progname)s %(action_usage)s" % vars() emit_message(message) sys.exit(usage_exit_code) @@ -107,7 +110,7 @@ if len(argv) < min_args: self._usage_exit(argv) - self.action = argv[1] + self.action = unicode(argv[1]) if self.action not in self.action_funcs: self._usage_exit(argv) @@ -119,10 +122,10 @@ try: self.daemon_context.open() - except pidlockfile.AlreadyLocked: + except lockfile.AlreadyLocked: pidfile_path = self.pidfile.path raise DaemonRunnerStartFailureError( - "PID file %(pidfile_path)r already locked" % vars()) + u"PID file %(pidfile_path)r already locked" % vars()) pid = os.getpid() message = self.start_message % vars() @@ -138,7 +141,7 @@ os.kill(pid, signal.SIGTERM) except OSError, exc: raise DaemonRunnerStopFailureError( - "Failed to terminate %(pid)d: %(exc)s" % vars()) + u"Failed to terminate %(pid)d: %(exc)s" % vars()) def _stop(self): """ Exit the daemon process specified in the current PID file. @@ -146,7 +149,7 @@ if not self.pidfile.is_locked(): pidfile_path = self.pidfile.path raise DaemonRunnerStopFailureError( - "PID file %(pidfile_path)r not locked" % vars()) + u"PID file %(pidfile_path)r not locked" % vars()) if is_pidfile_stale(self.pidfile): self.pidfile.break_lock() @@ -160,9 +163,9 @@ self._start() action_funcs = { - 'start': _start, - 'stop': _stop, - 'restart': _restart, + u'start': _start, + u'stop': _stop, + u'restart': _restart, } def _get_action_func(self): @@ -176,7 +179,7 @@ func = self.action_funcs[self.action] except KeyError: raise DaemonRunnerInvalidActionError( - "Unknown action: %(action)r" % vars(self)) + u"Unknown action: %(action)r" % vars(self)) return func def do_action(self): @@ -190,19 +193,19 @@ """ Emit a message to the specified stream (default `sys.stderr`). """ if stream is None: stream = sys.stderr - stream.write("%(message)s\n" % vars()) + stream.write(u"%(message)s\n" % vars()) stream.flush() def make_pidlockfile(path, acquire_timeout): """ Make a PIDLockFile instance with the given filesystem path. """ if not isinstance(path, basestring): - error = ValueError("Not a filesystem path: %(path)r" % vars()) + error = ValueError(u"Not a filesystem path: %(path)r" % vars()) raise error if not os.path.isabs(path): - error = ValueError("Not an absolute path: %(path)r" % vars()) + error = ValueError(u"Not an absolute path: %(path)r" % vars()) raise error - lockfile = pidlockfile.TimeoutPIDLockFile(path, acquire_timeout) + lockfile = pidfile.TimeoutPIDLockFile(path, acquire_timeout) return lockfile diff -Nru python-daemon-1.5.5/daemon/version/__init__.py python-daemon-1.6/daemon/version/__init__.py --- python-daemon-1.5.5/daemon/version/__init__.py 2010-03-02 09:20:42.000000000 +0000 +++ python-daemon-1.6/daemon/version/__init__.py 2010-05-10 10:37:59.000000000 +0000 @@ -11,9 +11,11 @@ """ Version information for the python-daemon distribution. """ -from version_info import version_info +from __future__ import absolute_import -version_info['version_string'] = u"1.5.5" +from .version_info import version_info + +version_info['version_string'] = u"1.6" version_short = u"%(version_string)s" % version_info version_full = u"%(version_string)s.r%(revno)s" % version_info diff -Nru python-daemon-1.5.5/debian/changelog python-daemon-1.6/debian/changelog --- python-daemon-1.5.5/debian/changelog 2011-12-17 14:09:14.000000000 +0000 +++ python-daemon-1.6/debian/changelog 2012-06-27 22:12:59.000000000 +0000 @@ -1,86 +1,5 @@ -python-daemon (1.5.5-1ubuntu1) precise; urgency=low +python-daemon (1.6-1chl1~precise1) precise; urgency=low - * Build using dh_python2 + * Build for precise - -- Matthias Klose Sat, 17 Dec 2011 14:09:14 +0000 - -python-daemon (1.5.5-1) unstable; urgency=low - - * New upstream version. Highlights since previous release: - + Stop using ‘pkg_resources’ and revert to pre-1.5.3 version-string - handling, until a better way that doesn't break everyone else's - installation can be found. - - -- Ben Finney Sat, 10 Apr 2010 15:44:43 +1000 - -python-daemon (1.5.4-1) unstable; urgency=low - - * New upstream version. Highlights since previous release: - * Invoke the pidfile context manager's ‘__exit__’ - method with the correct arguments (as per - ). - * debian/source/format: - * Declare source package format. - * debian/control: - * Build-Depends on all dependencies, so that ‘pkg_resources.require’ - works for all packaging actions. - * Conform to ‘Standards-Version: 3.8.4’ (no additional changes needed). - - -- Ben Finney Sat, 27 Feb 2010 22:57:50 +1100 - -python-daemon (1.5.2-2) unstable; urgency=medium - - * Urgency ‘medium’ to address serious packaging bug. - * debian/control: - + Fix missing dependency on ‘python-lockfile’. - (Closes: Bug#565352) - - -- Ben Finney Fri, 15 Jan 2010 13:51:34 +1100 - -python-daemon (1.5.2-1) unstable; urgency=low - - * New upstream version. Highlights since previous release: - * Ensure we only prevent core dumps if ‘prevent_core’ is true. - * Implement ‘TimeoutPIDLockFile’ to specify a timeout in advance of - lock acquisition. - * Distinguish different conditions on reading and parsing PID file. - * Write the PID file using correct OS locking and permissions. - * Close the PID file after writing. - * Implement ‘PIDLockFile’ as subclass of ‘lockfile.LinkFileLock’. - * Only inspect the file descriptor of streams if they have one. - * debian/control: - * Drop ‘Provides’ field, since a Python-versioned dependency should - not be necessary (ref. ‘python-support’ documentation). - - -- Ben Finney Fri, 06 Nov 2009 14:29:01 +1100 - -python-daemon (1.4.8-1) unstable; urgency=medium - - * Urgency medium to fix broken behaviour in common scenarios. - * New upstream version. - + Drop default handling of ‘SIGCLD’ signal, to avoid bad interactions - with other Python standard library modules. - * debian/control: - + Set ‘Priority: optional’ to allow other common packages to depend on - this one. - - -- Ben Finney Fri, 18 Sep 2009 08:46:56 +1000 - -python-daemon (1.4.7-1) unstable; urgency=low - - * New upstream version. - + Exclude ‘test’ package from distribution installation. - (Closes: Bug#544391) - * debian/pyversions: - + Require at least Python 2.5. - * debian/control: - + Update to ‘Standards-Version: 3.8.3’ (no additional changes needed). - - -- Ben Finney Fri, 04 Sep 2009 00:13:07 +1000 - -python-daemon (1.4.6-1) unstable; urgency=low - - * Initial Debian packaging. - (Closes: bug#524861) - - -- Ben Finney Sun, 21 Jun 2009 23:55:01 +1000 + -- Chris Lea Wed, 11 Jan 2012 20:25:00 +0000 diff -Nru python-daemon-1.5.5/debian/control python-daemon-1.6/debian/control --- python-daemon-1.5.5/debian/control 2011-12-17 14:09:32.000000000 +0000 +++ python-daemon-1.6/debian/control 2012-06-27 22:12:59.000000000 +0000 @@ -1,35 +1,15 @@ Source: python-daemon -Priority: optional -Maintainer: Ben Finney Section: python -Homepage: http://pypi.python.org/pypi/python-daemon -VCS-bzr: http://bzr.debian.org/bzr/collab-maint/python-daemon/python-daemon.debian/ -VCS-Browser: http://bzr.debian.org/loggerhead/collab-maint/python-daemon/python-daemon.debian/ -Build-Depends: debhelper (>= 7.0.14), - python-setuptools, - python-minimock (>= 1.2.2), - python-lockfile, - python (>= 2.6.6-3~) -Standards-Version: 3.8.4 +Priority: extra +Maintainer: Chris Lea +Build-Depends: debhelper (>= 7), python (>= 2.5), python-support, python-setuptools +Standards-Version: 3.8.3 +Homepage: http://pypi.python.org/pypi/python-daemon/1.6 Package: python-daemon Architecture: all -Depends: - python-lockfile, - ${python:Depends}, ${misc:Depends} -Description: library for making a Unix daemon process - ‘daemon’ is a library that assists a Python program to turn itself - into a well-behaved Unix daemon process, as specified in PEP 3143. - . - This library provides a ‘DaemonContext’ class that manages the - following important tasks for becoming a daemon process: - . - * Detach the process into its own process group. - * Set process environment appropriate for running inside a chroot. - * Renounce suid and sgid privileges. - * Close all open file descriptors. - * Change the working directory, uid, gid, and umask. - * Set appropriate signal handlers. - * Open new file descriptors for stdin, stdout, and stderr. - * Manage a specified PID lock file. - * Register cleanup functions for at-exit processing. +Depends: ${misc:Depends}, python (>= 2.5), python-support, python-lockfile (>= 1:0.9.0) +Description: Library to implement a well-behaved Unix daemon process. + This library implements the well-behaved + daemon specification of PEP 3143, "Standard + daemon process library". diff -Nru python-daemon-1.5.5/debian/copyright python-daemon-1.6/debian/copyright --- python-daemon-1.5.5/debian/copyright 2010-04-10 05:45:30.000000000 +0000 +++ python-daemon-1.6/debian/copyright 2012-06-27 22:12:59.000000000 +0000 @@ -1,71 +1,49 @@ -Format-Specification: - http://wiki.debian.org/Proposals/CopyrightFormat?action=recall&rev=233 -Upstream-Name: python-daemon -Upstream-Maintainer: Ben Finney -Upstream-Source: http://pypi.python.org/packages/source/p/python-daemon/ - -Files: * -License: PSF-2+ - This is free software: you may copy, modify, and/or distribute this work - under the terms of the Python Software Foundation License, version 2 or - later as published by the Python Software Foundation. - No warranty expressed or implied. - -Files: debian/* -License: GPL-2+ - This is free software; you may copy, modify, and/or distribute this work - under the terms of the GNU General Public License, version 2 or later. - No warranty expressed or implied. - . - On Debian systems, the complete text of the GNU General Public License - version 2 can be found in the file ‘/usr/share/common-licenses/GPL-2’. - -License: PSF-2 - PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 - -------------------------------------------- - . - 1. This LICENSE AGREEMENT is between the Python Software Foundation - ("PSF"), and the Individual or Organization ("Licensee") accessing and - otherwise using this software ("Python") in source or binary form and - its associated documentation. - . - 2. Subject to the terms and conditions of this License Agreement, PSF - hereby grants Licensee a nonexclusive, royalty-free, world-wide - license to reproduce, analyze, test, perform and/or display publicly, - prepare derivative works, distribute, and otherwise use Python - alone or in any derivative version, provided, however, that PSF's - License Agreement and PSF's notice of copyright, i.e., "Copyright (c) - 2001, 2002, 2003, 2004, 2005, 2006, 2007 Python Software Foundation; - All Rights Reserved" are retained in Python alone or in any derivative - version prepared by Licensee. - . - 3. In the event Licensee prepares a derivative work that is based on - or incorporates Python or any part thereof, and wants to make - the derivative work available to others as provided herein, then - Licensee hereby agrees to include in any such work a brief summary of - the changes made to Python. - . - 4. PSF is making Python available to Licensee on an "AS IS" - basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR - IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND - DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS - FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT - INFRINGE ANY THIRD PARTY RIGHTS. - . - 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON - FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS - A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, - OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. - . - 6. This License Agreement will automatically terminate upon a material - breach of its terms and conditions. - . - 7. Nothing in this License Agreement shall be deemed to create any - relationship of agency, partnership, or joint venture between PSF and - Licensee. This License Agreement does not grant permission to use PSF - trademarks or trade name in a trademark sense to endorse or promote - products or services of Licensee, or any third party. - . - 8. By copying, installing or otherwise using Python, Licensee - agrees to be bound by the terms and conditions of this License - Agreement. +PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 +-------------------------------------------- + +1. This LICENSE AGREEMENT is between the Python Software Foundation +("PSF"), and the Individual or Organization ("Licensee") accessing and +otherwise using this software ("Python") in source or binary form and +its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, PSF +hereby grants Licensee a nonexclusive, royalty-free, world-wide +license to reproduce, analyze, test, perform and/or display publicly, +prepare derivative works, distribute, and otherwise use Python +alone or in any derivative version, provided, however, that PSF's +License Agreement and PSF's notice of copyright, i.e., "Copyright (c) +2001, 2002, 2003, 2004, 2005, 2006, 2007 Python Software Foundation; +All Rights Reserved" are retained in Python alone or in any derivative +version prepared by Licensee. + +3. In the event Licensee prepares a derivative work that is based on +or incorporates Python or any part thereof, and wants to make +the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to Python. + +4. PSF is making Python available to Licensee on an "AS IS" +basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON +FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, +OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. Nothing in this License Agreement shall be deemed to create any +relationship of agency, partnership, or joint venture between PSF and +Licensee. This License Agreement does not grant permission to use PSF +trademarks or trade name in a trademark sense to endorse or promote +products or services of Licensee, or any third party. + +8. By copying, installing or otherwise using Python, Licensee +agrees to be bound by the terms and conditions of this License +Agreement. + diff -Nru python-daemon-1.5.5/debian/pyversions python-daemon-1.6/debian/pyversions --- python-daemon-1.5.5/debian/pyversions 2010-04-10 05:45:30.000000000 +0000 +++ python-daemon-1.6/debian/pyversions 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -2.5- diff -Nru python-daemon-1.5.5/debian/rules python-daemon-1.6/debian/rules --- python-daemon-1.5.5/debian/rules 2011-12-17 14:10:18.000000000 +0000 +++ python-daemon-1.6/debian/rules 2012-06-27 22:12:59.000000000 +0000 @@ -1,36 +1,13 @@ -#! /usr/bin/make -f -# -*- mode: makefile; coding: utf-8 -*- -# -# debian/rules -# -# Copyright © 2008–2009 Ben Finney -# This is free software; you may copy, modify, and/or distribute this work -# under the terms of the GNU General Public License, version 2 or later. -# No warranty expressed or implied. -# See the file '/usr/share/common-licenses/GPL-2' for details. +#!/usr/bin/make -f +# -*- makefile -*- +# Sample debian/rules that uses debhelper. +# This file was originally written by Joey Hess and Craig Small. +# As a special exception, when this file is copied by dh-make into a +# dh-make output file, you may use that output file without restriction. +# This special exception was added by Craig Small in version 0.37 of dh-make. # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 - -.PHONY: build -build: - dh build --with=python2 - -.PHONY: clean -clean: - dh clean --with=python2 - -.PHONY: install -install: build - dh install --with=python2 - -.PHONY: binary-indep -binary-indep: build install - dh binary-indep --with=python2 - -.PHONY: binary-arch -binary-arch: build install - -.PHONY: binary -binary: build binary-indep binary-arch +%: + dh $@ diff -Nru python-daemon-1.5.5/debian/source/format python-daemon-1.6/debian/source/format --- python-daemon-1.5.5/debian/source/format 2012-06-27 22:12:59.000000000 +0000 +++ python-daemon-1.6/debian/source/format 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -3.0 (quilt) diff -Nru python-daemon-1.5.5/debian/watch python-daemon-1.6/debian/watch --- python-daemon-1.5.5/debian/watch 2010-04-10 05:45:30.000000000 +0000 +++ python-daemon-1.6/debian/watch 1970-01-01 00:00:00.000000000 +0000 @@ -1,9 +0,0 @@ -# debian/watch -# Debian uscan file for python-daemon package. -# Manpage: uscan(1) - -# Compulsory line, this is a version 3 file. -version=3 - -# Current version from Python cheeseshop. -http://pypi.python.org/packages/source/p/python-daemon/python-daemon-(.+).tar.gz diff -Nru python-daemon-1.5.5/doc/FAQ python-daemon-1.6/doc/FAQ --- python-daemon-1.5.5/doc/FAQ 1970-01-01 00:00:00.000000000 +0000 +++ python-daemon-1.6/doc/FAQ 2010-04-10 01:22:44.000000000 +0000 @@ -0,0 +1,130 @@ +python-daemon Frequently Asked Questions +######################################## + +:Author: Ben Finney +:Updated: 2010-04-10 + +.. contents:: +.. + 1 General + 1.1 What is the purpose of the ‘python-daemon’ library? + 1.2 How can I run a service communicating with a separate daemon process? + 2 File descriptors + 2.1 Why does the output stop after opening the daemon context? + 2.2 How can I preserve a ‘logging’ handler's file descriptor? + +General +======= + +What is the purpose of the ‘python-daemon’ library? +--------------------------------------------------- + +The ‘python-daemon’ library has a deliberately narrow focus: that of +being a reference implementation for `PEP 3143`_, “Standard daemon +process library”. + +.. _`PEP 3143`: http://www.python.org/dev/peps/pep-3143 + +How can I run a service communicating with a separate daemon process? +--------------------------------------------------------------------- + +As specified in `PEP 3143`_, the ‘python-daemon’ library is +specifically focussed on the goal of having the *current running +program* become a well-behaved Unix daemon process. This leaves open +the question of how this program is started, or about multiple +programs interacting. As detailed in PEP 3143: + + A daemon is not a service + + There is a related concept in many systems, called a “service”. A + service differs from the model in this PEP, in that rather than + having the *current* program continue to run as a daemon process, + a service starts an *additional* process to run in the background, + and the current process communicates with that additional process + via some defined channels. + + The Unix-style daemon model in this PEP can be used, among other + things, to implement the background-process part of a service; but + this PEP does not address the other aspects of setting up and + managing a service. + +A possible starting point for such a “service” model of execution is +in a `message from 2009-01-30`_ to the ``python-ideas`` forum. + +.. _`message from 2009-01-30`: http://mail.python.org/pipermail/python-ideas/2009-January/002606.html + + +File descriptors +================ + +Why does the output stop after opening the daemon context? +---------------------------------------------------------- + +The specified behaviour in `PEP 3143`_ includes the requirement to +detach the process from the controlling terminal (to allow the process +to continue to run as a daemon), and to close all file descriptors not +known to be safe once detached (to ansure any files that continue to +be used are under the control of the daemon process). + +If you want the process to generate output via the system streams +‘sys.stdout’ and ‘sys.stderr’, set the ‘DaemonContext’'s ‘stdout’ +and/or ‘stderr’ options to a file-like object (e.g. the ‘stream’ +attribute of a ‘logging.Handler’ instance). If these objects have file +descriptors, they will be preserved when the daemon context opens. + +How can I preserve a ‘logging’ handler's file descriptor? +--------------------------------------------------------- + +The ‘DaemonContext.open’ method conforms to `PEP 3143`_ by closing all +open file descriptors, but excluding those files specified in the +‘files_preserve’ option. This option is a list of files or file +descriptors. + +The Python standard library ‘logging’ module provides log handlers +that write to streams, including to files via the ‘StreamHandler’ +class and its sub-classes. The documentation (both the online `logging +module documentation`_ and the docstrings for the code) makes no +mention of a way to get at the stream associated with a handler +object. + +However, looking at the source code for ‘StreamHandler’, in Python 2.5 +as ``/usr/lib/python2.5/logging/__init__.py``, shows a ‘stream’ +attribute that is bound to the stream object. The attribute is not +marked private (i.e. it is not named with a leading underscore), so we +can presume it is part of the public API. + +That attribute can then be used to specify that a logging handler's +file descriptor should, when the ‘DaemonContext’ opens, be excluded +from closure:: + + import logging + import daemon + + # any subclass of StreamHandler should provide the ‘stream’ attribute. + lh = logging.handlers.TimedRotatingFileHandler( + "/var/log/foo.log", + # … + ) + + # … do some logging and other activity … + + daemon_context = daemon.DaemonContext() + daemon_context.files_preserve = [lh.stream] + + daemon_context.open() + + # … continue as a daemon process … + +.. _`logging module documentation`: http://docs.python.org/library/logging + + +.. + Local variables: + mode: rst + coding: utf-8 + time-stamp-format: "%:y-%02m-%02d" + time-stamp-start: "^:Updated:[ ]+" + time-stamp-end: "$" + time-stamp-line-limit: 20 + End: + vim: filetype=rst fileencoding=utf-8 : diff -Nru python-daemon-1.5.5/doc/TODO python-daemon-1.6/doc/TODO --- python-daemon-1.5.5/doc/TODO 1970-01-01 00:00:00.000000000 +0000 +++ python-daemon-1.6/doc/TODO 2009-04-03 01:28:23.000000000 +0000 @@ -0,0 +1,73 @@ +TODO for python-daemon library +############################## + +======= +PENDING +======= + +Tests +===== + +* Write full unit tests for every new or changed behaviour at time of + commit. + +Features +======== + +Important +--------- + +Wishlist +-------- + +* Allow specification of a syslog service name to log as (default: + output to stdout and stderr, not syslog). + +Documentation +============= + +Standard library inclusion +========================== + +* Convert to Python 3. + + +==== +DONE +==== + +* Detect whether started by another process that handles + daemonisation, such as ‘inetd’, and behave appropriately. + +* Detach to new process and session group. + +* Allow specification of working directory (default: '/'). + +* Allow specification of umask (default: 0000). + +* Drop ‘suid’ and ‘sgid’ privileges if set. + +* Close all open file handles. + +* Re-open stdin, stdout, stderr to user-specified files. + +* Default re-open stdin, stdout, stderr to ‘/dev/null’. + +* Allow specification of a non-root user and group to drop to, if + started as ‘root’ (default: no change of user or group). + +* Implement context manager protocol for daemon context. + +* Allow specification of PID file with its own context manager + (default: no PID file). + +* Full docstrings for functions, classes, and modules. + +* PEP 3143 for adding this library to the Python standard library. + +.. + Local variables: + mode: rst + coding: utf-8 + End: + vim: filetype=rst fileencoding=utf-8 : diff -Nru python-daemon-1.5.5/MANIFEST.in python-daemon-1.6/MANIFEST.in --- python-daemon-1.5.5/MANIFEST.in 2010-03-02 09:13:02.000000000 +0000 +++ python-daemon-1.6/MANIFEST.in 2010-03-02 21:29:27.000000000 +0000 @@ -1,4 +1,4 @@ include MANIFEST.in include LICENSE.* include ChangeLog -include TODO +recursive-include doc * diff -Nru python-daemon-1.5.5/PKG-INFO python-daemon-1.6/PKG-INFO --- python-daemon-1.5.5/PKG-INFO 2010-03-02 09:35:54.000000000 +0000 +++ python-daemon-1.6/PKG-INFO 2010-05-10 10:38:35.000000000 +0000 @@ -1,6 +1,6 @@ Metadata-Version: 1.0 Name: python-daemon -Version: 1.5.5 +Version: 1.6 Summary: Library to implement a well-behaved Unix daemon process. Home-page: http://pypi.python.org/pypi/python-daemon/ Author: Ben Finney @@ -17,12 +17,12 @@ Simple example of usage:: - import daemon + import daemon - from spam import do_main_program + from spam import do_main_program - with daemon.DaemonContext(): - do_main_program() + with daemon.DaemonContext(): + do_main_program() Customisation of the steps to become a daemon is available by setting options on the `DaemonContext` instance; see the diff -Nru python-daemon-1.5.5/python_daemon.egg-info/PKG-INFO python-daemon-1.6/python_daemon.egg-info/PKG-INFO --- python-daemon-1.5.5/python_daemon.egg-info/PKG-INFO 2010-03-02 09:35:54.000000000 +0000 +++ python-daemon-1.6/python_daemon.egg-info/PKG-INFO 2010-05-10 10:38:35.000000000 +0000 @@ -1,6 +1,6 @@ Metadata-Version: 1.0 Name: python-daemon -Version: 1.5.5 +Version: 1.6 Summary: Library to implement a well-behaved Unix daemon process. Home-page: http://pypi.python.org/pypi/python-daemon/ Author: Ben Finney @@ -17,12 +17,12 @@ Simple example of usage:: - import daemon + import daemon - from spam import do_main_program + from spam import do_main_program - with daemon.DaemonContext(): - do_main_program() + with daemon.DaemonContext(): + do_main_program() Customisation of the steps to become a daemon is available by setting options on the `DaemonContext` instance; see the diff -Nru python-daemon-1.5.5/python_daemon.egg-info/requires.txt python-daemon-1.6/python_daemon.egg-info/requires.txt --- python-daemon-1.5.5/python_daemon.egg-info/requires.txt 2010-03-02 09:35:54.000000000 +0000 +++ python-daemon-1.6/python_daemon.egg-info/requires.txt 2010-05-10 10:38:35.000000000 +0000 @@ -1,2 +1,2 @@ setuptools -lockfile >=0.7 \ No newline at end of file +lockfile >=0.9 \ No newline at end of file diff -Nru python-daemon-1.5.5/python_daemon.egg-info/SOURCES.txt python-daemon-1.6/python_daemon.egg-info/SOURCES.txt --- python-daemon-1.5.5/python_daemon.egg-info/SOURCES.txt 2010-03-02 09:35:54.000000000 +0000 +++ python-daemon-1.6/python_daemon.egg-info/SOURCES.txt 2010-05-10 10:38:35.000000000 +0000 @@ -5,10 +5,12 @@ setup.py daemon/__init__.py daemon/daemon.py -daemon/pidlockfile.py +daemon/pidfile.py daemon/runner.py daemon/version/__init__.py daemon/version/version_info.py +doc/FAQ +doc/TODO python_daemon.egg-info/PKG-INFO python_daemon.egg-info/SOURCES.txt python_daemon.egg-info/dependency_links.txt @@ -18,5 +20,5 @@ test/__init__.py test/scaffold.py test/test_daemon.py -test/test_pidlockfile.py +test/test_pidfile.py test/test_runner.py \ No newline at end of file diff -Nru python-daemon-1.5.5/setup.py python-daemon-1.6/setup.py --- python-daemon-1.5.5/setup.py 2010-03-02 09:16:34.000000000 +0000 +++ python-daemon-1.6/setup.py 2010-05-10 10:35:20.000000000 +0000 @@ -17,8 +17,8 @@ import textwrap from setuptools import setup, find_packages -distribution_name = "python-daemon" -main_module_name = 'daemon' +distribution_name = u"python-daemon" +main_module_name = u'daemon' main_module = __import__(main_module_name, fromlist=['version']) version = main_module.version @@ -31,17 +31,17 @@ setup( name=distribution_name, version=version.version, - packages=find_packages(exclude=["test"]), + packages=find_packages(exclude=[u"test"]), # setuptools metadata zip_safe=False, - test_suite="test.suite", + test_suite=u"test.suite", tests_require=[ - "MiniMock >=1.2.2", + u"MiniMock >=1.2.2", ], install_requires=[ - "setuptools", - "lockfile >=0.7", + u"setuptools", + u"lockfile >=0.9", ], # PyPI metadata @@ -54,11 +54,11 @@ long_description=long_description, classifiers=[ # Reference: http://pypi.python.org/pypi?%3Aaction=list_classifiers - "Development Status :: 4 - Beta", - "License :: OSI Approved :: Python Software Foundation License", - "Operating System :: POSIX", - "Programming Language :: Python", - "Intended Audience :: Developers", - "Topic :: Software Development :: Libraries :: Python Modules", + u"Development Status :: 4 - Beta", + u"License :: OSI Approved :: Python Software Foundation License", + u"Operating System :: POSIX", + u"Programming Language :: Python", + u"Intended Audience :: Developers", + u"Topic :: Software Development :: Libraries :: Python Modules", ], ) diff -Nru python-daemon-1.5.5/test/scaffold.py python-daemon-1.6/test/scaffold.py --- python-daemon-1.5.5/test/scaffold.py 2010-01-20 11:33:10.000000000 +0000 +++ python-daemon-1.6/test/scaffold.py 2010-03-09 22:57:02.000000000 +0000 @@ -18,6 +18,13 @@ import sys import operator import textwrap +try: + # Python 2.6 or greater? + from functools import reduce +except ImportError: + # Not available, so try the builtin function. + assert reduce + from minimock import ( Mock, TraceTracker as MockTracker, @@ -36,7 +43,7 @@ logging.disable(logging.CRITICAL) -def get_python_module_names(file_list, file_suffix='.py'): +def get_python_module_names(file_list, file_suffix=u'.py'): """ Return a list of module names from a filename list. """ module_names = [m[:m.rfind(file_suffix)] for m in file_list if m.endswith(file_suffix)] @@ -98,19 +105,19 @@ for arg_name in signature['arg_names']: if arg_name in signature['arg_defaults']: arg_default = signature['arg_defaults'][arg_name] - arg_text_template = "%(arg_name)s=%(arg_default)r" + arg_text_template = u"%(arg_name)s=%(arg_default)r" else: - arg_text_template = "%(arg_name)s" + arg_text_template = u"%(arg_name)s" args_text.append(arg_text_template % vars()) if 'var_args' in signature: - args_text.append("*%(var_args)s" % signature) + args_text.append(u"*%(var_args)s" % signature) if 'var_kw_args' in signature: - args_text.append("**%(var_kw_args)s" % signature) - signature_args_text = ", ".join(args_text) + args_text.append(u"**%(var_kw_args)s" % signature) + signature_args_text = u", ".join(args_text) func_name = signature['name'] signature_text = ( - "%(func_name)s(%(signature_args_text)s)" % vars()) + u"%(func_name)s(%(signature_args_text)s)" % vars()) return signature_text @@ -132,9 +139,9 @@ except self.failureException: exc_class_name = exc_class.__name__ msg = ( - "Exception %(exc_class_name)s not raised" - " for function call:" - " func=%(func)r args=%(args)r kwargs=%(kwargs)r" + u"Exception %(exc_class_name)s not raised" + u" for function call:" + u" func=%(func)r args=%(args)r kwargs=%(kwargs)r" ) % vars() raise self.failureException(msg) @@ -147,7 +154,7 @@ """ if first is second: if msg is None: - msg = "%(first)r is %(second)r" % vars() + msg = u"%(first)r is %(second)r" % vars() raise self.failureException(msg) def failUnlessIs(self, first, second, msg=None): @@ -159,7 +166,7 @@ """ if first is not second: if msg is None: - msg = "%(first)r is not %(second)r" % vars() + msg = u"%(first)r is not %(second)r" % vars() raise self.failureException(msg) assertIs = failUnlessIs @@ -174,7 +181,7 @@ """ if second in first: if msg is None: - msg = "%(second)r is in %(first)r" % vars() + msg = u"%(second)r is in %(first)r" % vars() raise self.failureException(msg) def failUnlessIn(self, first, second, msg=None): @@ -186,7 +193,7 @@ """ if second not in first: if msg is None: - msg = "%(second)r is not in %(first)r" % vars() + msg = u"%(second)r is not in %(first)r" % vars() raise self.failureException(msg) assertIn = failUnlessIn @@ -213,9 +220,9 @@ if msg is None: diff = checker.output_difference( example, got, checker_optionflags) - msg = "\n".join([ - "Output received did not match expected output", - "%(diff)s", + msg = u"\n".join([ + u"Output received did not match expected output", + u"%(diff)s", ]) % vars() raise self.failureException(msg) @@ -235,9 +242,9 @@ if not tracker.check(want): if msg is None: diff = tracker.diff(want) - msg = "\n".join([ - "Output received did not match expected output", - "%(diff)s", + msg = u"\n".join([ + u"Output received did not match expected output", + u"%(diff)s", ]) % vars() raise self.failureException(msg) @@ -255,9 +262,9 @@ if tracker.check(want): if msg is None: diff = tracker.diff(want) - msg = "\n".join([ - "Output received matched specified undesired output", - "%(diff)s", + msg = u"\n".join([ + u"Output received matched specified undesired output", + u"%(diff)s", ]) % vars() raise self.failureException(msg) @@ -274,7 +281,7 @@ if isinstance(obj, classes): if msg is None: msg = ( - "%(obj)r is an instance of one of %(classes)r" + u"%(obj)r is an instance of one of %(classes)r" ) % vars() raise self.failureException(msg) @@ -288,7 +295,7 @@ if not isinstance(obj, classes): if msg is None: msg = ( - "%(obj)r is not an instance of any of %(classes)r" + u"%(obj)r is not an instance of any of %(classes)r" ) % vars() raise self.failureException(msg) @@ -314,8 +321,8 @@ if not func_in_traceback: if msg is None: msg = ( - "Traceback did not lead to original function" - " %(function)s" + u"Traceback did not lead to original function" + u" %(function)s" ) % vars() raise self.failureException(msg) @@ -350,7 +357,7 @@ if msg is None: first_signature_text = format_function_signature(first) second_signature_text = format_function_signature(second) - msg = (textwrap.dedent("""\ + msg = (textwrap.dedent(u"""\ Function signatures do not match: %(first_signature)r != %(second_signature)r Expected: @@ -394,8 +401,8 @@ for match_type in params['types']: match_type_name = match_type.__name__ fail_msg = ( - "%(instance)r is not an instance of" - " %(match_type_name)s" + u"%(instance)r is not an instance of" + u" %(match_type_name)s" ) % vars() self.failUnless( isinstance(instance, match_type), diff -Nru python-daemon-1.5.5/test/test_daemon.py python-daemon-1.6/test/test_daemon.py --- python-daemon-1.5.5/test/test_daemon.py 2010-02-26 03:09:27.000000000 +0000 +++ python-daemon-1.6/test/test_daemon.py 2010-05-10 10:35:20.000000000 +0000 @@ -25,12 +25,12 @@ from StringIO import StringIO import scaffold -from test_pidlockfile import ( +from test_pidfile import ( FakeFileDescriptorStringIO, setup_pidfile_fixtures, ) -from daemon import pidlockfile +from lockfile import pidlockfile import daemon @@ -67,25 +67,25 @@ testcase.mock_pidfile_path = tempfile.mktemp() testcase.mock_pidlockfile = scaffold.Mock( - "pidlockfile.PIDLockFile", + u"pidlockfile.PIDLockFile", tracker=testcase.mock_tracker) testcase.mock_pidlockfile.path = testcase.mock_pidfile_path scaffold.mock( - "daemon.daemon.is_detach_process_context_required", + u"daemon.daemon.is_detach_process_context_required", returns=True, tracker=testcase.mock_tracker) scaffold.mock( - "daemon.daemon.make_default_signal_map", + u"daemon.daemon.make_default_signal_map", returns=object(), tracker=testcase.mock_tracker) scaffold.mock( - "os.getuid", + u"os.getuid", returns=object(), tracker=testcase.mock_tracker) scaffold.mock( - "os.getgid", + u"os.getgid", returns=object(), tracker=testcase.mock_tracker) @@ -306,56 +306,56 @@ self.test_instance._is_open = False scaffold.mock( - "daemon.daemon.detach_process_context", + u"daemon.daemon.detach_process_context", tracker=self.mock_tracker) scaffold.mock( - "daemon.daemon.change_working_directory", + u"daemon.daemon.change_working_directory", tracker=self.mock_tracker) scaffold.mock( - "daemon.daemon.change_root_directory", + u"daemon.daemon.change_root_directory", tracker=self.mock_tracker) scaffold.mock( - "daemon.daemon.change_file_creation_mask", + u"daemon.daemon.change_file_creation_mask", tracker=self.mock_tracker) scaffold.mock( - "daemon.daemon.change_process_owner", + u"daemon.daemon.change_process_owner", tracker=self.mock_tracker) scaffold.mock( - "daemon.daemon.prevent_core_dump", + u"daemon.daemon.prevent_core_dump", tracker=self.mock_tracker) scaffold.mock( - "daemon.daemon.close_all_open_files", + u"daemon.daemon.close_all_open_files", tracker=self.mock_tracker) scaffold.mock( - "daemon.daemon.redirect_stream", + u"daemon.daemon.redirect_stream", tracker=self.mock_tracker) scaffold.mock( - "daemon.daemon.set_signal_handlers", + u"daemon.daemon.set_signal_handlers", tracker=self.mock_tracker) scaffold.mock( - "daemon.daemon.register_atexit_function", + u"daemon.daemon.register_atexit_function", tracker=self.mock_tracker) self.test_files_preserve_fds = object() scaffold.mock( - "daemon.daemon.DaemonContext._get_exclude_file_descriptors", + u"daemon.daemon.DaemonContext._get_exclude_file_descriptors", returns=self.test_files_preserve_fds, tracker=self.mock_tracker) self.test_signal_handler_map = object() scaffold.mock( - "daemon.daemon.DaemonContext._make_signal_handler_map", + u"daemon.daemon.DaemonContext._make_signal_handler_map", returns=self.test_signal_handler_map, tracker=self.mock_tracker) scaffold.mock( - "sys.stdin", + u"sys.stdin", tracker=self.mock_tracker) scaffold.mock( - "sys.stdout", + u"sys.stdout", tracker=self.mock_tracker) scaffold.mock( - "sys.stderr", + u"sys.stderr", tracker=self.mock_tracker) def tearDown(self): @@ -368,7 +368,7 @@ instance.chroot_directory = object() instance.detach_process = True instance.pidfile = self.mock_pidlockfile - expect_mock_output = """\ + expect_mock_output = u"""\ Called daemon.daemon.change_root_directory(...) Called daemon.daemon.prevent_core_dump() Called daemon.daemon.change_file_creation_mask(...) @@ -393,7 +393,7 @@ """ Should return immediately if is_open property is true. """ instance = self.test_instance instance._is_open = True - expect_mock_output = """\ + expect_mock_output = u"""\ """ self.mock_tracker.clear() instance.open() @@ -404,7 +404,7 @@ instance = self.test_instance chroot_directory = object() instance.chroot_directory = chroot_directory - expect_mock_output = """\ + expect_mock_output = u"""\ Called daemon.daemon.change_root_directory( %(chroot_directory)r) ... @@ -416,7 +416,7 @@ """ Should omit changing root directory if no `chroot_directory`. """ instance = self.test_instance instance.chroot_directory = None - unwanted_output = """\ + unwanted_output = u"""\ ...Called daemon.daemon.change_root_directory(...)...""" instance.open() self.failIfMockCheckerMatch(unwanted_output) @@ -424,7 +424,7 @@ def test_prevents_core_dump(self): """ Should request prevention of core dumps. """ instance = self.test_instance - expect_mock_output = """\ + expect_mock_output = u"""\ Called daemon.daemon.prevent_core_dump() ... """ % vars() @@ -435,7 +435,7 @@ """ Should omit preventing core dumps if `prevent_core` is false. """ instance = self.test_instance instance.prevent_core = False - unwanted_output = """\ + unwanted_output = u"""\ ...Called daemon.daemon.prevent_core_dump()...""" instance.open() self.failIfMockCheckerMatch(unwanted_output) @@ -444,7 +444,7 @@ """ Should close all open files, excluding `files_preserve`. """ instance = self.test_instance expect_exclude = self.test_files_preserve_fds - expect_mock_output = """\ + expect_mock_output = u"""\ ... Called daemon.daemon.close_all_open_files( exclude=%(expect_exclude)r) @@ -458,7 +458,7 @@ instance = self.test_instance working_directory = object() instance.working_directory = working_directory - expect_mock_output = """\ + expect_mock_output = u"""\ ... Called daemon.daemon.change_working_directory( %(working_directory)r) @@ -472,7 +472,7 @@ instance = self.test_instance umask = object() instance.umask = umask - expect_mock_output = """\ + expect_mock_output = u"""\ ... Called daemon.daemon.change_file_creation_mask(%(umask)r) ... @@ -487,7 +487,7 @@ gid = object() instance.uid = uid instance.gid = gid - expect_mock_output = """\ + expect_mock_output = u"""\ ... Called daemon.daemon.change_process_owner(%(uid)r, %(gid)r) ... @@ -498,7 +498,7 @@ def test_detaches_process_context(self): """ Should request detach of process context. """ instance = self.test_instance - expect_mock_output = """\ + expect_mock_output = u"""\ ... Called daemon.daemon.detach_process_context() ... @@ -510,7 +510,7 @@ """ Should omit detach of process context if not required. """ instance = self.test_instance instance.detach_process = False - unwanted_output = """\ + unwanted_output = u"""\ ...Called daemon.daemon.detach_process_context(...)...""" instance.open() self.failIfMockCheckerMatch(unwanted_output) @@ -520,7 +520,7 @@ instance = self.test_instance instance.signal_map = object() expect_signal_handler_map = self.test_signal_handler_map - expect_mock_output = """\ + expect_mock_output = u"""\ ... Called daemon.daemon.set_signal_handlers( %(expect_signal_handler_map)r) @@ -537,7 +537,7 @@ (target_stdin, target_stdout, target_stderr) = ( self.stream_files_by_name[name] for name in ['stdin', 'stdout', 'stderr']) - expect_mock_output = """\ + expect_mock_output = u"""\ ... Called daemon.daemon.redirect_stream( %(system_stdin)r, %(target_stdin)r) @@ -554,7 +554,7 @@ """ Should enter the PID file context manager. """ instance = self.test_instance instance.pidfile = self.mock_pidlockfile - expect_mock_output = """\ + expect_mock_output = u"""\ ... Called pidlockfile.PIDLockFile.__enter__() ... @@ -572,7 +572,7 @@ """ Should register the `close` method for atexit processing. """ instance = self.test_instance close_method = instance.close - expect_mock_output = """\ + expect_mock_output = u"""\ ... Called daemon.daemon.register_atexit_function(%(close_method)r) """ % vars() @@ -599,7 +599,7 @@ instance = self.test_instance instance._is_open = False instance.pidfile = object() - expect_mock_output = """\ + expect_mock_output = u"""\ """ self.mock_tracker.clear() instance.close() @@ -609,7 +609,7 @@ """ Should exit the PID file context manager. """ instance = self.test_instance instance.pidfile = self.mock_pidlockfile - expect_mock_output = """\ + expect_mock_output = u"""\ Called pidlockfile.PIDLockFile.__exit__(None, None, None) """ instance.close() @@ -638,7 +638,7 @@ self.mock_tracker.clear() scaffold.mock( - "daemon.daemon.DaemonContext.open", + u"daemon.daemon.DaemonContext.open", tracker=self.mock_tracker) def tearDown(self): @@ -648,7 +648,7 @@ def test_opens_daemon_context(self): """ Should open the DaemonContext. """ instance = self.test_instance - expect_mock_output = """\ + expect_mock_output = u"""\ Called daemon.daemon.DaemonContext.open() """ instance.__enter__() @@ -677,7 +677,7 @@ ) scaffold.mock( - "daemon.daemon.DaemonContext.close", + u"daemon.daemon.DaemonContext.close", tracker=self.mock_tracker) def tearDown(self): @@ -688,7 +688,7 @@ """ Should close the DaemonContext. """ instance = self.test_instance args = self.test_args - expect_mock_output = """\ + expect_mock_output = u"""\ Called daemon.daemon.DaemonContext.close() """ instance.__exit__(**args) @@ -881,7 +881,7 @@ def mock_make_signal_handler(target): return self.test_signal_handlers[target] scaffold.mock( - "daemon.daemon.DaemonContext._make_signal_handler", + u"daemon.daemon.DaemonContext._make_signal_handler", returns_func=mock_make_signal_handler, tracker=self.mock_tracker) @@ -905,7 +905,7 @@ self.mock_tracker = scaffold.MockTracker() scaffold.mock( - "os.chdir", + u"os.chdir", tracker=self.mock_tracker) self.test_directory = object() @@ -921,7 +921,7 @@ """ Should change working directory to specified directory. """ args = self.test_args directory = self.test_directory - expect_mock_output = """\ + expect_mock_output = u"""\ Called os.chdir(%(directory)r) """ % vars() daemon.daemon.change_working_directory(**args) @@ -930,7 +930,7 @@ def test_raises_daemon_error_on_os_error(self): """ Should raise a DaemonError on receiving and OSError. """ args = self.test_args - test_error = OSError(errno.ENOENT, "No such directory") + test_error = OSError(errno.ENOENT, u"No such directory") os.chdir.mock_raises = test_error expect_error = daemon.daemon.DaemonOSEnvironmentError self.failUnlessRaises( @@ -940,7 +940,7 @@ def test_error_message_contains_original_error_message(self): """ Should raise a DaemonError with original message. """ args = self.test_args - test_error = OSError(errno.ENOENT, "No such directory") + test_error = OSError(errno.ENOENT, u"No such directory") os.chdir.mock_raises = test_error expect_error = daemon.daemon.DaemonOSEnvironmentError try: @@ -958,10 +958,10 @@ self.mock_tracker = scaffold.MockTracker() scaffold.mock( - "os.chdir", + u"os.chdir", tracker=self.mock_tracker) scaffold.mock( - "os.chroot", + u"os.chroot", tracker=self.mock_tracker) self.test_directory = object() @@ -977,7 +977,7 @@ """ Should change working directory to specified directory. """ args = self.test_args directory = self.test_directory - expect_mock_output = """\ + expect_mock_output = u"""\ Called os.chdir(%(directory)r) ... """ % vars() @@ -988,7 +988,7 @@ """ Should change root directory to specified directory. """ args = self.test_args directory = self.test_directory - expect_mock_output = """\ + expect_mock_output = u"""\ ... Called os.chroot(%(directory)r) """ % vars() @@ -998,7 +998,7 @@ def test_raises_daemon_error_on_os_error_from_chdir(self): """ Should raise a DaemonError on receiving an OSError from chdir. """ args = self.test_args - test_error = OSError(errno.ENOENT, "No such directory") + test_error = OSError(errno.ENOENT, u"No such directory") os.chdir.mock_raises = test_error expect_error = daemon.daemon.DaemonOSEnvironmentError self.failUnlessRaises( @@ -1008,7 +1008,7 @@ def test_raises_daemon_error_on_os_error_from_chroot(self): """ Should raise a DaemonError on receiving an OSError from chroot. """ args = self.test_args - test_error = OSError(errno.EPERM, "No chroot for you!") + test_error = OSError(errno.EPERM, u"No chroot for you!") os.chroot.mock_raises = test_error expect_error = daemon.daemon.DaemonOSEnvironmentError self.failUnlessRaises( @@ -1018,7 +1018,7 @@ def test_error_message_contains_original_error_message(self): """ Should raise a DaemonError with original message. """ args = self.test_args - test_error = OSError(errno.ENOENT, "No such directory") + test_error = OSError(errno.ENOENT, u"No such directory") os.chdir.mock_raises = test_error expect_error = daemon.daemon.DaemonOSEnvironmentError try: @@ -1036,7 +1036,7 @@ self.mock_tracker = scaffold.MockTracker() scaffold.mock( - "os.umask", + u"os.umask", tracker=self.mock_tracker) self.test_mask = object() @@ -1052,7 +1052,7 @@ """ Should change working directory to specified directory. """ args = self.test_args mask = self.test_mask - expect_mock_output = """\ + expect_mock_output = u"""\ Called os.umask(%(mask)r) """ % vars() daemon.daemon.change_file_creation_mask(**args) @@ -1061,7 +1061,7 @@ def test_raises_daemon_error_on_os_error_from_chdir(self): """ Should raise a DaemonError on receiving an OSError from umask. """ args = self.test_args - test_error = OSError(errno.EINVAL, "Whatchoo talkin' 'bout?") + test_error = OSError(errno.EINVAL, u"Whatchoo talkin' 'bout?") os.umask.mock_raises = test_error expect_error = daemon.daemon.DaemonOSEnvironmentError self.failUnlessRaises( @@ -1071,7 +1071,7 @@ def test_error_message_contains_original_error_message(self): """ Should raise a DaemonError with original message. """ args = self.test_args - test_error = OSError(errno.ENOENT, "No such directory") + test_error = OSError(errno.ENOENT, u"No such directory") os.umask.mock_raises = test_error expect_error = daemon.daemon.DaemonOSEnvironmentError try: @@ -1089,10 +1089,10 @@ self.mock_tracker = scaffold.MockTracker() scaffold.mock( - "os.setuid", + u"os.setuid", tracker=self.mock_tracker) scaffold.mock( - "os.setgid", + u"os.setgid", tracker=self.mock_tracker) self.test_uid = object() @@ -1115,7 +1115,7 @@ """ args = self.test_args - expect_mock_output = """\ + expect_mock_output = u"""\ Called os.setgid(...) Called os.setuid(...) """ % vars() @@ -1126,7 +1126,7 @@ """ Should change process GID to specified value. """ args = self.test_args gid = self.test_gid - expect_mock_output = """\ + expect_mock_output = u"""\ Called os.setgid(%(gid)r) ... """ % vars() @@ -1137,7 +1137,7 @@ """ Should change process UID to specified value. """ args = self.test_args uid = self.test_uid - expect_mock_output = """\ + expect_mock_output = u"""\ ... Called os.setuid(%(uid)r) """ % vars() @@ -1147,7 +1147,7 @@ def test_raises_daemon_error_on_os_error_from_setgid(self): """ Should raise a DaemonError on receiving an OSError from setgid. """ args = self.test_args - test_error = OSError(errno.EPERM, "No switching for you!") + test_error = OSError(errno.EPERM, u"No switching for you!") os.setgid.mock_raises = test_error expect_error = daemon.daemon.DaemonOSEnvironmentError self.failUnlessRaises( @@ -1157,7 +1157,7 @@ def test_raises_daemon_error_on_os_error_from_setuid(self): """ Should raise a DaemonError on receiving an OSError from setuid. """ args = self.test_args - test_error = OSError(errno.EPERM, "No switching for you!") + test_error = OSError(errno.EPERM, u"No switching for you!") os.setuid.mock_raises = test_error expect_error = daemon.daemon.DaemonOSEnvironmentError self.failUnlessRaises( @@ -1167,7 +1167,7 @@ def test_error_message_contains_original_error_message(self): """ Should raise a DaemonError with original message. """ args = self.test_args - test_error = OSError(errno.EINVAL, "Whatchoo talkin' 'bout?") + test_error = OSError(errno.EINVAL, u"Whatchoo talkin' 'bout?") os.setuid.mock_raises = test_error expect_error = daemon.daemon.DaemonOSEnvironmentError try: @@ -1186,13 +1186,13 @@ self.RLIMIT_CORE = object() scaffold.mock( - "resource.RLIMIT_CORE", mock_obj=self.RLIMIT_CORE, + u"resource.RLIMIT_CORE", mock_obj=self.RLIMIT_CORE, tracker=self.mock_tracker) scaffold.mock( - "resource.getrlimit", returns=None, + u"resource.getrlimit", returns=None, tracker=self.mock_tracker) scaffold.mock( - "resource.setrlimit", returns=None, + u"resource.setrlimit", returns=None, tracker=self.mock_tracker) def tearDown(self): @@ -1203,7 +1203,7 @@ """ Should set the RLIMIT_CORE resource to zero. """ expect_resource = self.RLIMIT_CORE expect_limit = (0, 0) - expect_mock_output = """\ + expect_mock_output = u"""\ Called resource.getrlimit( %(expect_resource)r) Called resource.setrlimit( @@ -1217,7 +1217,7 @@ """ Should raise DaemonError if no RLIMIT_CORE resource. """ def mock_getrlimit(res): if res == resource.RLIMIT_CORE: - raise ValueError("Bogus platform doesn't have RLIMIT_CORE") + raise ValueError(u"Bogus platform doesn't have RLIMIT_CORE") else: return None resource.getrlimit.mock_returns_func = mock_getrlimit @@ -1237,7 +1237,7 @@ self.test_fd = 274 scaffold.mock( - "os.close", + u"os.close", tracker=self.mock_tracker) def tearDown(self): @@ -1247,7 +1247,7 @@ def test_requests_file_descriptor_close(self): """ Should request close of file descriptor. """ fd = self.test_fd - expect_mock_output = """\ + expect_mock_output = u"""\ Called os.close(%(fd)r) """ % vars() daemon.daemon.close_file_descriptor_if_open(fd) @@ -1256,11 +1256,11 @@ def test_ignores_badfd_error_on_close(self): """ Should ignore OSError EBADF when closing. """ fd = self.test_fd - test_error = OSError(errno.EBADF, "Bad file descriptor") + test_error = OSError(errno.EBADF, u"Bad file descriptor") def os_close(fd): raise test_error os.close.mock_returns_func = os_close - expect_mock_output = """\ + expect_mock_output = u"""\ Called os.close(%(fd)r) """ % vars() daemon.daemon.close_file_descriptor_if_open(fd) @@ -1269,7 +1269,7 @@ def test_raises_error_if_error_on_close(self): """ Should raise DaemonError if an OSError occurs when closing. """ fd = self.test_fd - test_error = OSError(object(), "Unexpected error") + test_error = OSError(object(), u"Unexpected error") def os_close(fd): raise test_error os.close.mock_returns_func = os_close @@ -1305,7 +1305,7 @@ maxfd = daemon.daemon.MAXFD self.failUnless( expect_minimum <= maxfd, - msg="MAXFD should be at least %(expect_minimum)r (got %(maxfd)r)" + msg=u"MAXFD should be at least %(expect_minimum)r (got %(maxfd)r)" % vars()) @@ -1328,17 +1328,17 @@ self.test_maxfd = object() scaffold.mock( - "daemon.daemon.MAXFD", mock_obj=self.test_maxfd, + u"daemon.daemon.MAXFD", mock_obj=self.test_maxfd, tracker=self.mock_tracker) scaffold.mock( - "resource.RLIMIT_NOFILE", mock_obj=self.RLIMIT_NOFILE, + u"resource.RLIMIT_NOFILE", mock_obj=self.RLIMIT_NOFILE, tracker=self.mock_tracker) scaffold.mock( - "resource.RLIM_INFINITY", mock_obj=self.RLIM_INFINITY, + u"resource.RLIM_INFINITY", mock_obj=self.RLIM_INFINITY, tracker=self.mock_tracker) scaffold.mock( - "resource.getrlimit", returns_func=mock_getrlimit, + u"resource.getrlimit", returns_func=mock_getrlimit, tracker=self.mock_tracker) def tearDown(self): @@ -1378,22 +1378,22 @@ self.test_maxfd = 8 scaffold.mock( - "daemon.daemon.get_maximum_file_descriptors", + u"daemon.daemon.get_maximum_file_descriptors", returns=self.test_maxfd, tracker=self.mock_tracker) scaffold.mock( - "resource.RLIMIT_NOFILE", mock_obj=self.RLIMIT_NOFILE, + u"resource.RLIMIT_NOFILE", mock_obj=self.RLIMIT_NOFILE, tracker=self.mock_tracker) scaffold.mock( - "resource.RLIM_INFINITY", mock_obj=self.RLIM_INFINITY, + u"resource.RLIM_INFINITY", mock_obj=self.RLIM_INFINITY, tracker=self.mock_tracker) scaffold.mock( - "resource.getrlimit", returns_func=mock_getrlimit, + u"resource.getrlimit", returns_func=mock_getrlimit, tracker=self.mock_tracker) scaffold.mock( - "daemon.daemon.close_file_descriptor_if_open", + u"daemon.daemon.close_file_descriptor_if_open", tracker=self.mock_tracker) def tearDown(self): @@ -1403,8 +1403,8 @@ def test_requests_all_open_files_to_close(self): """ Should request close of all open files. """ expect_file_descriptors = reversed(range(self.test_maxfd)) - expect_mock_output = "...\n" + "".join( - "Called daemon.daemon.close_file_descriptor_if_open(%(fd)r)\n" + expect_mock_output = u"...\n" + u"".join( + u"Called daemon.daemon.close_file_descriptor_if_open(%(fd)r)\n" % vars() for fd in expect_file_descriptors) daemon.daemon.close_all_open_files() @@ -1419,8 +1419,8 @@ expect_file_descriptors = ( fd for fd in reversed(range(self.test_maxfd)) if fd not in test_exclude) - expect_mock_output = "...\n" + "".join( - "Called daemon.daemon.close_file_descriptor_if_open(%(fd)r)\n" + expect_mock_output = u"...\n" + "".join( + u"Called daemon.daemon.close_file_descriptor_if_open(%(fd)r)\n" % vars() for fd in expect_file_descriptors) daemon.daemon.close_all_open_files(**args) @@ -1439,17 +1439,17 @@ test_pids = [0, 0] scaffold.mock( - "os.fork", returns_iter=test_pids, + u"os.fork", returns_iter=test_pids, tracker=self.mock_tracker) scaffold.mock( - "os.setsid", + u"os.setsid", tracker=self.mock_tracker) def raise_os_exit(status=None): raise self.FakeOSExit(status) scaffold.mock( - "os._exit", returns_func=raise_os_exit, + u"os._exit", returns_func=raise_os_exit, tracker=self.mock_tracker) def tearDown(self): @@ -1459,9 +1459,9 @@ def test_parent_exits(self): """ Parent process should exit. """ parent_pid = 23 - scaffold.mock("os.fork", returns_iter=[parent_pid], + scaffold.mock(u"os.fork", returns_iter=[parent_pid], tracker=self.mock_tracker) - expect_mock_output = """\ + expect_mock_output = u"""\ Called os.fork() Called os._exit(0) """ @@ -1473,20 +1473,22 @@ def test_first_fork_error_raises_error(self): """ Error on first fork should raise DaemonProcessDetachError. """ fork_errno = 13 - fork_strerror = "Bad stuff happened" + fork_strerror = u"Bad stuff happened" fork_error = OSError(fork_errno, fork_strerror) test_pids_iter = iter([fork_error]) def mock_fork(): - next = test_pids_iter.next() - if isinstance(next, Exception): - raise next + next_item = test_pids_iter.next() + if isinstance(next_item, Exception): + raise next_item else: - return next + return next_item - scaffold.mock("os.fork", returns_func=mock_fork, + scaffold.mock( + u"os.fork", + returns_func=mock_fork, tracker=self.mock_tracker) - expect_mock_output = """\ + expect_mock_output = u"""\ Called os.fork() """ self.failUnlessRaises( @@ -1496,7 +1498,7 @@ def test_child_starts_new_process_group(self): """ Child should start new process group. """ - expect_mock_output = """\ + expect_mock_output = u"""\ Called os.fork() Called os.setsid() ... @@ -1507,9 +1509,11 @@ def test_child_forks_next_parent_exits(self): """ Child should fork, then exit if parent. """ test_pids = [0, 42] - scaffold.mock("os.fork", returns_iter=test_pids, + scaffold.mock( + u"os.fork", + returns_iter=test_pids, tracker=self.mock_tracker) - expect_mock_output = """\ + expect_mock_output = u"""\ Called os.fork() Called os.setsid() Called os.fork() @@ -1523,20 +1527,22 @@ def test_second_fork_error_reports_to_stderr(self): """ Error on second fork should cause report to stderr. """ fork_errno = 17 - fork_strerror = "Nasty stuff happened" + fork_strerror = u"Nasty stuff happened" fork_error = OSError(fork_errno, fork_strerror) test_pids_iter = iter([0, fork_error]) def mock_fork(): - next = test_pids_iter.next() - if isinstance(next, Exception): - raise next + next_item = test_pids_iter.next() + if isinstance(next_item, Exception): + raise next_item else: - return next + return next_item - scaffold.mock("os.fork", returns_func=mock_fork, + scaffold.mock( + u"os.fork", + returns_func=mock_fork, tracker=self.mock_tracker) - expect_mock_output = """\ + expect_mock_output = u"""\ Called os.fork() Called os.setsid() Called os.fork() @@ -1548,7 +1554,7 @@ def test_child_forks_next_child_continues(self): """ Child should fork, then continue if child. """ - expect_mock_output = """\ + expect_mock_output = u"""\ Called os.fork() Called os.setsid() Called os.fork() @@ -1567,7 +1573,7 @@ self.test_ppid = 765 scaffold.mock( - "os.getppid", + u"os.getppid", returns=self.test_ppid, tracker=self.mock_tracker) @@ -1607,10 +1613,10 @@ self.mock_socket_error = socket.error( errno.ENOTSOCK, - "Socket operation on non-socket") + u"Socket operation on non-socket") self.mock_socket = scaffold.Mock( - "socket.socket", + u"socket.socket", tracker=self.mock_tracker) self.mock_socket.getsockopt.mock_raises = self.mock_socket_error @@ -1618,7 +1624,7 @@ return self.mock_socket scaffold.mock( - "socket.fromfd", + u"socket.fromfd", returns_func=mock_socket_fromfd, tracker=self.mock_tracker) @@ -1648,7 +1654,7 @@ test_fd = 23 getsockopt = self.mock_socket.getsockopt getsockopt.mock_raises = socket.error( - object(), "Weird socket stuff") + object(), u"Weird socket stuff") expect_result = True result = daemon.daemon.is_socket(test_fd) self.failUnlessIs(expect_result, result) @@ -1671,7 +1677,7 @@ self.mock_stdin_is_socket_func = (lambda: False) scaffold.mock( - "daemon.daemon.is_socket", + u"daemon.daemon.is_socket", returns_func=mock_is_socket, tracker=self.mock_tracker) @@ -1701,10 +1707,10 @@ self.mock_tracker = scaffold.MockTracker() scaffold.mock( - "daemon.daemon.is_process_started_by_init", + u"daemon.daemon.is_process_started_by_init", tracker=self.mock_tracker) scaffold.mock( - "daemon.daemon.is_process_started_by_superserver", + u"daemon.daemon.is_process_started_by_superserver", tracker=self.mock_tracker) def tearDown(self): @@ -1754,7 +1760,7 @@ ) scaffold.mock( - "os.dup2", + u"os.dup2", tracker=testcase.mock_tracker) @@ -1773,11 +1779,11 @@ if path == os.devnull: result = self.test_null_file.fileno() else: - raise OSError(errno.NOENT, "No such file", path) + raise OSError(errno.NOENT, u"No such file", path) return result scaffold.mock( - "os.open", + u"os.open", returns_func=mock_open, tracker=self.mock_tracker) @@ -1791,7 +1797,7 @@ system_fileno = system_stream.fileno() target_stream = self.test_target_stream target_fileno = target_stream.fileno() - expect_mock_output = """\ + expect_mock_output = u"""\ Called os.dup2(%(target_fileno)r, %(system_fileno)r) """ % vars() daemon.daemon.redirect_stream(system_stream, target_stream) @@ -1806,7 +1812,7 @@ null_flag = os.O_RDWR null_file = self.test_null_file null_fileno = null_file.fileno() - expect_mock_output = """\ + expect_mock_output = u"""\ Called os.open(%(null_path)r, %(null_flag)r) Called os.dup2(%(null_fileno)r, %(system_fileno)r) """ % vars() @@ -1835,11 +1841,11 @@ setattr(mock_signal_module, name, object()) scaffold.mock( - "signal", + u"signal", mock_obj=mock_signal_module, tracker=self.mock_tracker) scaffold.mock( - "daemon.daemon.signal", + u"daemon.daemon.signal", mock_obj=mock_signal_module, tracker=self.mock_tracker) @@ -1888,7 +1894,7 @@ self.mock_tracker = scaffold.MockTracker() scaffold.mock( - "signal.signal", + u"signal.signal", tracker=self.mock_tracker) self.signal_handler_map = { @@ -1904,8 +1910,8 @@ def test_sets_signal_handler_for_each_item(self): """ Should set signal handler for each item in map. """ signal_handler_map = self.signal_handler_map - expect_mock_output = "".join( - "Called signal.signal(%(signal_number)r, %(handler)r)\n" + expect_mock_output = u"".join( + u"Called signal.signal(%(signal_number)r, %(handler)r)\n" % vars() for (signal_number, handler) in signal_handler_map.items()) daemon.daemon.set_signal_handlers(signal_handler_map) @@ -1920,7 +1926,7 @@ self.mock_tracker = scaffold.MockTracker() scaffold.mock( - "atexit.register", + u"atexit.register", tracker=self.mock_tracker) def tearDown(self): @@ -1930,7 +1936,7 @@ def test_registers_function_for_atexit_processing(self): """ Should register specified function for atexit processing. """ func = object() - expect_mock_output = """\ + expect_mock_output = u"""\ Called atexit.register(%(func)r) """ % vars() daemon.daemon.register_atexit_function(func) diff -Nru python-daemon-1.5.5/test/test_pidfile.py python-daemon-1.6/test/test_pidfile.py --- python-daemon-1.5.5/test/test_pidfile.py 1970-01-01 00:00:00.000000000 +0000 +++ python-daemon-1.6/test/test_pidfile.py 2010-05-10 10:35:20.000000000 +0000 @@ -0,0 +1,398 @@ +# -*- coding: utf-8 -*- +# +# test/test_pidfile.py +# Part of python-daemon, an implementation of PEP 3143. +# +# Copyright © 2008–2010 Ben Finney +# +# This is free software: you may copy, modify, and/or distribute this work +# under the terms of the Python Software Foundation License, version 2 or +# later as published by the Python Software Foundation. +# No warranty expressed or implied. See the file LICENSE.PSF-2 for details. + +""" Unit test for ‘pidfile’ module. + """ + +import __builtin__ as builtins +import os +from StringIO import StringIO +import itertools +import tempfile +import errno + +import lockfile +from lockfile import pidlockfile + +import scaffold + +import daemon.pidfile + + +class FakeFileDescriptorStringIO(StringIO, object): + """ A StringIO class that fakes a file descriptor. """ + + _fileno_generator = itertools.count() + + def __init__(self, *args, **kwargs): + self._fileno = self._fileno_generator.next() + super_instance = super(FakeFileDescriptorStringIO, self) + super_instance.__init__(*args, **kwargs) + + def fileno(self): + return self._fileno + + +def make_pidlockfile_scenarios(): + """ Make a collection of scenarios for testing PIDLockFile instances. """ + + mock_current_pid = 235 + mock_other_pid = 8642 + mock_pidfile_path = tempfile.mktemp() + + mock_pidfile_empty = FakeFileDescriptorStringIO() + mock_pidfile_current_pid = FakeFileDescriptorStringIO( + u"%(mock_current_pid)d\n" % vars()) + mock_pidfile_other_pid = FakeFileDescriptorStringIO( + u"%(mock_other_pid)d\n" % vars()) + mock_pidfile_bogus = FakeFileDescriptorStringIO( + u"b0gUs") + + scenarios = { + 'simple': {}, + 'not-exist': { + 'open_func_name': 'mock_open_nonexist', + 'os_open_func_name': 'mock_os_open_nonexist', + }, + 'not-exist-write-denied': { + 'open_func_name': 'mock_open_nonexist', + 'os_open_func_name': 'mock_os_open_nonexist', + }, + 'not-exist-write-busy': { + 'open_func_name': 'mock_open_nonexist', + 'os_open_func_name': 'mock_os_open_nonexist', + }, + 'exist-read-denied': { + 'open_func_name': 'mock_open_read_denied', + 'os_open_func_name': 'mock_os_open_read_denied', + }, + 'exist-locked-read-denied': { + 'locking_pid': mock_other_pid, + 'open_func_name': 'mock_open_read_denied', + 'os_open_func_name': 'mock_os_open_read_denied', + }, + 'exist-empty': {}, + 'exist-invalid': { + 'pidfile': mock_pidfile_bogus, + }, + 'exist-current-pid': { + 'pidfile': mock_pidfile_current_pid, + 'pidfile_pid': mock_current_pid, + }, + 'exist-current-pid-locked': { + 'pidfile': mock_pidfile_current_pid, + 'pidfile_pid': mock_current_pid, + 'locking_pid': mock_current_pid, + }, + 'exist-other-pid': { + 'pidfile': mock_pidfile_other_pid, + 'pidfile_pid': mock_other_pid, + }, + 'exist-other-pid-locked': { + 'pidfile': mock_pidfile_other_pid, + 'pidfile_pid': mock_other_pid, + 'locking_pid': mock_other_pid, + }, + } + + for scenario in scenarios.values(): + scenario['pid'] = mock_current_pid + scenario['path'] = mock_pidfile_path + if 'pidfile' not in scenario: + scenario['pidfile'] = mock_pidfile_empty + if 'pidfile_pid' not in scenario: + scenario['pidfile_pid'] = None + if 'locking_pid' not in scenario: + scenario['locking_pid'] = None + if 'open_func_name' not in scenario: + scenario['open_func_name'] = 'mock_open_okay' + if 'os_open_func_name' not in scenario: + scenario['os_open_func_name'] = 'mock_os_open_okay' + + return scenarios + + +def setup_pidfile_fixtures(testcase): + """ Set up common fixtures for PID file test cases. """ + testcase.mock_tracker = scaffold.MockTracker() + + scenarios = make_pidlockfile_scenarios() + testcase.pidlockfile_scenarios = scenarios + + def get_scenario_option(testcase, key, default=None): + value = default + try: + value = testcase.scenario[key] + except (NameError, TypeError, AttributeError, KeyError): + pass + return value + + scaffold.mock( + u"os.getpid", + returns=scenarios['simple']['pid'], + tracker=testcase.mock_tracker) + + def make_mock_open_funcs(testcase): + + def mock_open_nonexist(filename, mode, buffering): + if 'r' in mode: + raise IOError( + errno.ENOENT, u"No such file %(filename)r" % vars()) + else: + result = testcase.scenario['pidfile'] + return result + + def mock_open_read_denied(filename, mode, buffering): + if 'r' in mode: + raise IOError( + errno.EPERM, u"Read denied on %(filename)r" % vars()) + else: + result = testcase.scenario['pidfile'] + return result + + def mock_open_okay(filename, mode, buffering): + result = testcase.scenario['pidfile'] + return result + + def mock_os_open_nonexist(filename, flags, mode): + if (flags & os.O_CREAT): + result = testcase.scenario['pidfile'].fileno() + else: + raise OSError( + errno.ENOENT, u"No such file %(filename)r" % vars()) + return result + + def mock_os_open_read_denied(filename, flags, mode): + if (flags & os.O_CREAT): + result = testcase.scenario['pidfile'].fileno() + else: + raise OSError( + errno.EPERM, u"Read denied on %(filename)r" % vars()) + return result + + def mock_os_open_okay(filename, flags, mode): + result = testcase.scenario['pidfile'].fileno() + return result + + funcs = dict( + (name, obj) for (name, obj) in vars().items() + if hasattr(obj, '__call__')) + + return funcs + + testcase.mock_pidfile_open_funcs = make_mock_open_funcs(testcase) + + def mock_open(filename, mode='r', buffering=None): + scenario_path = get_scenario_option(testcase, 'path') + if filename == scenario_path: + func_name = testcase.scenario['open_func_name'] + mock_open_func = testcase.mock_pidfile_open_funcs[func_name] + result = mock_open_func(filename, mode, buffering) + else: + result = FakeFileDescriptorStringIO() + return result + + scaffold.mock( + u"builtins.open", + returns_func=mock_open, + tracker=testcase.mock_tracker) + + def mock_os_open(filename, flags, mode=None): + scenario_path = get_scenario_option(testcase, 'path') + if filename == scenario_path: + func_name = testcase.scenario['os_open_func_name'] + mock_os_open_func = testcase.mock_pidfile_open_funcs[func_name] + result = mock_os_open_func(filename, flags, mode) + else: + result = FakeFileDescriptorStringIO().fileno() + return result + + scaffold.mock( + u"os.open", + returns_func=mock_os_open, + tracker=testcase.mock_tracker) + + def mock_os_fdopen(fd, mode='r', buffering=None): + scenario_pidfile = get_scenario_option( + testcase, 'pidfile', FakeFileDescriptorStringIO()) + if fd == testcase.scenario['pidfile'].fileno(): + result = testcase.scenario['pidfile'] + else: + raise OSError(errno.EBADF, u"Bad file descriptor") + return result + + scaffold.mock( + u"os.fdopen", + returns_func=mock_os_fdopen, + tracker=testcase.mock_tracker) + + testcase.scenario = NotImplemented + + +def setup_lockfile_method_mocks(testcase, scenario, class_name): + """ Set up common mock methods for lockfile class. """ + + def mock_read_pid(): + return scenario['pidfile_pid'] + def mock_is_locked(): + return (scenario['locking_pid'] is not None) + def mock_i_am_locking(): + return ( + scenario['locking_pid'] == scenario['pid']) + def mock_acquire(timeout=None): + if scenario['locking_pid'] is not None: + raise lockfile.AlreadyLocked() + scenario['locking_pid'] = scenario['pid'] + def mock_release(): + if scenario['locking_pid'] is None: + raise lockfile.NotLocked() + if scenario['locking_pid'] != scenario['pid']: + raise lockfile.NotMyLock() + scenario['locking_pid'] = None + def mock_break_lock(): + scenario['locking_pid'] = None + + for func_name in [ + 'read_pid', + 'is_locked', 'i_am_locking', + 'acquire', 'release', 'break_lock', + ]: + mock_func = vars()["mock_%(func_name)s" % vars()] + lockfile_func_name = u"%(class_name)s.%(func_name)s" % vars() + mock_lockfile_func = scaffold.Mock( + lockfile_func_name, + returns_func=mock_func, + tracker=testcase.mock_tracker) + try: + scaffold.mock( + lockfile_func_name, + mock_obj=mock_lockfile_func, + tracker=testcase.mock_tracker) + except NameError: + pass + + +def setup_pidlockfile_fixtures(testcase, scenario_name=None): + """ Set up common fixtures for PIDLockFile test cases. """ + + setup_pidfile_fixtures(testcase) + + scaffold.mock( + u"pidlockfile.write_pid_to_pidfile", + tracker=testcase.mock_tracker) + scaffold.mock( + u"pidlockfile.remove_existing_pidfile", + tracker=testcase.mock_tracker) + + if scenario_name is not None: + set_pidlockfile_scenario(testcase, scenario_name, clear_tracker=False) + + +def set_pidlockfile_scenario(testcase, scenario_name, clear_tracker=True): + """ Set up the test case to the specified scenario. """ + testcase.scenario = testcase.pidlockfile_scenarios[scenario_name] + setup_lockfile_method_mocks( + testcase, testcase.scenario, u"lockfile.LinkLockFile") + testcase.pidlockfile_args = dict( + path=testcase.scenario['path'], + ) + testcase.test_instance = pidlockfile.PIDLockFile( + **testcase.pidlockfile_args) + if clear_tracker: + testcase.mock_tracker.clear() + + +class TimeoutPIDLockFile_TestCase(scaffold.TestCase): + """ Test cases for ‘TimeoutPIDLockFile’ class. """ + + def setUp(self): + """ Set up test fixtures. """ + self.mock_tracker = scaffold.MockTracker() + + pidlockfile_scenarios = make_pidlockfile_scenarios() + self.pidlockfile_scenario = pidlockfile_scenarios['simple'] + pidfile_path = self.pidlockfile_scenario['path'] + + scaffold.mock( + u"pidlockfile.PIDLockFile.__init__", + tracker=self.mock_tracker) + scaffold.mock( + u"pidlockfile.PIDLockFile.acquire", + tracker=self.mock_tracker) + + self.scenario = { + 'pidfile_path': self.pidlockfile_scenario['path'], + 'acquire_timeout': object(), + } + + self.test_kwargs = dict( + path=self.scenario['pidfile_path'], + acquire_timeout=self.scenario['acquire_timeout'], + ) + self.test_instance = daemon.pidfile.TimeoutPIDLockFile( + **self.test_kwargs) + + def tearDown(self): + """ Tear down test fixtures. """ + scaffold.mock_restore() + + def test_inherits_from_pidlockfile(self): + """ Should inherit from PIDLockFile. """ + instance = self.test_instance + self.failUnlessIsInstance(instance, pidlockfile.PIDLockFile) + + def test_init_has_expected_signature(self): + """ Should have expected signature for ‘__init__’. """ + def test_func(self, path, acquire_timeout=None, *args, **kwargs): pass + test_func.__name__ = '__init__' + self.failUnlessFunctionSignatureMatch( + test_func, + daemon.pidfile.TimeoutPIDLockFile.__init__) + + def test_has_specified_acquire_timeout(self): + """ Should have specified ‘acquire_timeout’ value. """ + instance = self.test_instance + expect_timeout = self.test_kwargs['acquire_timeout'] + self.failUnlessEqual(expect_timeout, instance.acquire_timeout) + + def test_calls_superclass_init(self): + """ Should call the superclass ‘__init__’. """ + expect_path = self.test_kwargs['path'] + expect_mock_output = u"""\ + Called pidlockfile.PIDLockFile.__init__( + %(expect_path)r) + """ % vars() + self.failUnlessMockCheckerMatch(expect_mock_output) + + def test_acquire_uses_specified_timeout(self): + """ Should call the superclass ‘acquire’ with specified timeout. """ + instance = self.test_instance + test_timeout = object() + expect_timeout = test_timeout + self.mock_tracker.clear() + expect_mock_output = u"""\ + Called pidlockfile.PIDLockFile.acquire(%(expect_timeout)r) + """ % vars() + instance.acquire(test_timeout) + self.failUnlessMockCheckerMatch(expect_mock_output) + + def test_acquire_uses_stored_timeout_by_default(self): + """ Should call superclass ‘acquire’ with stored timeout by default. """ + instance = self.test_instance + test_timeout = self.test_kwargs['acquire_timeout'] + expect_timeout = test_timeout + self.mock_tracker.clear() + expect_mock_output = u"""\ + Called pidlockfile.PIDLockFile.acquire(%(expect_timeout)r) + """ % vars() + instance.acquire() + self.failUnlessMockCheckerMatch(expect_mock_output) diff -Nru python-daemon-1.5.5/test/test_pidlockfile.py python-daemon-1.6/test/test_pidlockfile.py --- python-daemon-1.5.5/test/test_pidlockfile.py 2010-01-20 11:33:10.000000000 +0000 +++ python-daemon-1.6/test/test_pidlockfile.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,791 +0,0 @@ -# -*- coding: utf-8 -*- -# -# test/test_pidlockfile.py -# Part of python-daemon, an implementation of PEP 3143. -# -# Copyright © 2008–2010 Ben Finney -# -# This is free software: you may copy, modify, and/or distribute this work -# under the terms of the Python Software Foundation License, version 2 or -# later as published by the Python Software Foundation. -# No warranty expressed or implied. See the file LICENSE.PSF-2 for details. - -""" Unit test for pidlockfile module. - """ - -import __builtin__ -import os -from StringIO import StringIO -import itertools -import tempfile -import errno - -import lockfile - -import scaffold -from daemon import pidlockfile - - -class FakeFileDescriptorStringIO(StringIO, object): - """ A StringIO class that fakes a file descriptor. """ - - _fileno_generator = itertools.count() - - def __init__(self, *args, **kwargs): - self._fileno = self._fileno_generator.next() - super_instance = super(FakeFileDescriptorStringIO, self) - super_instance.__init__(*args, **kwargs) - - def fileno(self): - return self._fileno - - -class Exception_TestCase(scaffold.Exception_TestCase): - """ Test cases for module exception classes. """ - - def __init__(self, *args, **kwargs): - """ Set up a new instance. """ - super(Exception_TestCase, self).__init__(*args, **kwargs) - - self.valid_exceptions = { - pidlockfile.PIDFileError: dict( - min_args = 1, - types = (Exception,), - ), - pidlockfile.PIDFileParseError: dict( - min_args = 2, - types = (pidlockfile.PIDFileError, ValueError), - ), - } - - -def make_pidlockfile_scenarios(): - """ Make a collection of scenarios for testing PIDLockFile instances. """ - - mock_current_pid = 235 - mock_other_pid = 8642 - mock_pidfile_path = tempfile.mktemp() - - mock_pidfile_empty = FakeFileDescriptorStringIO() - mock_pidfile_current_pid = FakeFileDescriptorStringIO( - "%(mock_current_pid)d\n" % vars()) - mock_pidfile_other_pid = FakeFileDescriptorStringIO( - "%(mock_other_pid)d\n" % vars()) - mock_pidfile_bogus = FakeFileDescriptorStringIO( - "b0gUs") - - scenarios = { - 'simple': {}, - 'not-exist': { - 'open_func_name': 'mock_open_nonexist', - 'os_open_func_name': 'mock_os_open_nonexist', - }, - 'not-exist-write-denied': { - 'open_func_name': 'mock_open_nonexist', - 'os_open_func_name': 'mock_os_open_nonexist', - }, - 'not-exist-write-busy': { - 'open_func_name': 'mock_open_nonexist', - 'os_open_func_name': 'mock_os_open_nonexist', - }, - 'exist-read-denied': { - 'open_func_name': 'mock_open_read_denied', - 'os_open_func_name': 'mock_os_open_read_denied', - }, - 'exist-locked-read-denied': { - 'locking_pid': mock_other_pid, - 'open_func_name': 'mock_open_read_denied', - 'os_open_func_name': 'mock_os_open_read_denied', - }, - 'exist-empty': {}, - 'exist-invalid': { - 'pidfile': mock_pidfile_bogus, - }, - 'exist-current-pid': { - 'pidfile': mock_pidfile_current_pid, - 'pidfile_pid': mock_current_pid, - }, - 'exist-current-pid-locked': { - 'pidfile': mock_pidfile_current_pid, - 'pidfile_pid': mock_current_pid, - 'locking_pid': mock_current_pid, - }, - 'exist-other-pid': { - 'pidfile': mock_pidfile_other_pid, - 'pidfile_pid': mock_other_pid, - }, - 'exist-other-pid-locked': { - 'pidfile': mock_pidfile_other_pid, - 'pidfile_pid': mock_other_pid, - 'locking_pid': mock_other_pid, - }, - } - - for scenario in scenarios.values(): - scenario['pid'] = mock_current_pid - scenario['path'] = mock_pidfile_path - if 'pidfile' not in scenario: - scenario['pidfile'] = mock_pidfile_empty - if 'pidfile_pid' not in scenario: - scenario['pidfile_pid'] = None - if 'locking_pid' not in scenario: - scenario['locking_pid'] = None - if 'open_func_name' not in scenario: - scenario['open_func_name'] = 'mock_open_okay' - if 'os_open_func_name' not in scenario: - scenario['os_open_func_name'] = 'mock_os_open_okay' - - return scenarios - - -def setup_pidfile_fixtures(testcase): - """ Set up common fixtures for PID file test cases. """ - testcase.mock_tracker = scaffold.MockTracker() - - scenarios = make_pidlockfile_scenarios() - testcase.pidlockfile_scenarios = scenarios - - def get_scenario_option(testcase, key, default=None): - value = default - try: - value = testcase.scenario[key] - except (NameError, TypeError, AttributeError, KeyError): - pass - return value - - scaffold.mock( - "os.getpid", - returns=scenarios['simple']['pid'], - tracker=testcase.mock_tracker) - - def make_mock_open_funcs(testcase): - - def mock_open_nonexist(filename, mode, buffering): - if 'r' in mode: - raise IOError( - errno.ENOENT, "No such file %(filename)r" % vars()) - else: - result = testcase.scenario['pidfile'] - return result - - def mock_open_read_denied(filename, mode, buffering): - if 'r' in mode: - raise IOError( - errno.EPERM, "Read denied on %(filename)r" % vars()) - else: - result = testcase.scenario['pidfile'] - return result - - def mock_open_okay(filename, mode, buffering): - result = testcase.scenario['pidfile'] - return result - - def mock_os_open_nonexist(filename, flags, mode): - if (flags & os.O_CREAT): - result = testcase.scenario['pidfile'].fileno() - else: - raise OSError( - errno.ENOENT, "No such file %(filename)r" % vars()) - return result - - def mock_os_open_read_denied(filename, flags, mode): - if (flags & os.O_CREAT): - result = testcase.scenario['pidfile'].fileno() - else: - raise OSError( - errno.EPERM, "Read denied on %(filename)r" % vars()) - return result - - def mock_os_open_okay(filename, flags, mode): - result = testcase.scenario['pidfile'].fileno() - return result - - funcs = dict( - (name, obj) for (name, obj) in vars().items() - if hasattr(obj, '__call__')) - - return funcs - - testcase.mock_pidfile_open_funcs = make_mock_open_funcs(testcase) - - def mock_open(filename, mode='r', buffering=None): - scenario_path = get_scenario_option(testcase, 'path') - if filename == scenario_path: - func_name = testcase.scenario['open_func_name'] - mock_open_func = testcase.mock_pidfile_open_funcs[func_name] - result = mock_open_func(filename, mode, buffering) - else: - result = FakeFileDescriptorStringIO() - return result - - scaffold.mock( - "__builtin__.open", - returns_func=mock_open, - tracker=testcase.mock_tracker) - - def mock_os_open(filename, flags, mode=None): - scenario_path = get_scenario_option(testcase, 'path') - if filename == scenario_path: - func_name = testcase.scenario['os_open_func_name'] - mock_os_open_func = testcase.mock_pidfile_open_funcs[func_name] - result = mock_os_open_func(filename, flags, mode) - else: - result = FakeFileDescriptorStringIO().fileno() - return result - - scaffold.mock( - "os.open", - returns_func=mock_os_open, - tracker=testcase.mock_tracker) - - def mock_os_fdopen(fd, mode='r', buffering=None): - scenario_pidfile = get_scenario_option( - testcase, 'pidfile', FakeFileDescriptorStringIO()) - if fd == testcase.scenario['pidfile'].fileno(): - result = testcase.scenario['pidfile'] - else: - raise OSError(errno.EBADF, "Bad file descriptor") - return result - - scaffold.mock( - "os.fdopen", - returns_func=mock_os_fdopen, - tracker=testcase.mock_tracker) - - testcase.scenario = NotImplemented - - -def setup_lockfile_method_mocks(testcase, scenario, class_name): - """ Set up common mock methods for lockfile class. """ - - def mock_read_pid(): - return scenario['pidfile_pid'] - def mock_is_locked(): - return (scenario['locking_pid'] is not None) - def mock_i_am_locking(): - return ( - scenario['locking_pid'] == scenario['pid']) - def mock_acquire(timeout=None): - if scenario['locking_pid'] is not None: - raise lockfile.AlreadyLocked() - scenario['locking_pid'] = scenario['pid'] - def mock_release(): - if scenario['locking_pid'] is None: - raise lockfile.NotLocked() - if scenario['locking_pid'] != scenario['pid']: - raise lockfile.NotMyLock() - scenario['locking_pid'] = None - def mock_break_lock(): - scenario['locking_pid'] = None - - for func_name in [ - 'read_pid', - 'is_locked', 'i_am_locking', - 'acquire', 'release', 'break_lock', - ]: - mock_func = vars()["mock_%(func_name)s" % vars()] - lockfile_func_name = "%(class_name)s.%(func_name)s" % vars() - mock_lockfile_func = scaffold.Mock( - lockfile_func_name, - returns_func=mock_func, - tracker=testcase.mock_tracker) - try: - scaffold.mock( - lockfile_func_name, - mock_obj=mock_lockfile_func, - tracker=testcase.mock_tracker) - except NameError: - pass - - -def setup_pidlockfile_fixtures(testcase, scenario_name=None): - """ Set up common fixtures for PIDLockFile test cases. """ - - setup_pidfile_fixtures(testcase) - - scaffold.mock( - "pidlockfile.write_pid_to_pidfile", - tracker=testcase.mock_tracker) - scaffold.mock( - "pidlockfile.remove_existing_pidfile", - tracker=testcase.mock_tracker) - - if scenario_name is not None: - set_pidlockfile_scenario(testcase, scenario_name, clear_tracker=False) - - -def set_pidlockfile_scenario(testcase, scenario_name, clear_tracker=True): - """ Set up the test case to the specified scenario. """ - testcase.scenario = testcase.pidlockfile_scenarios[scenario_name] - setup_lockfile_method_mocks( - testcase, testcase.scenario, "lockfile.LinkFileLock") - testcase.pidlockfile_args = dict( - path=testcase.scenario['path'], - ) - testcase.test_instance = pidlockfile.PIDLockFile( - **testcase.pidlockfile_args) - if clear_tracker: - testcase.mock_tracker.clear() - - -class PIDLockFile_TestCase(scaffold.TestCase): - """ Test cases for PIDLockFile class. """ - - def setUp(self): - """ Set up test fixtures. """ - setup_pidlockfile_fixtures(self, 'exist-other-pid') - - def tearDown(self): - """ Tear down test fixtures. """ - scaffold.mock_restore() - - def test_instantiate(self): - """ New instance of PIDLockFile should be created. """ - instance = self.test_instance - self.failUnlessIsInstance(instance, pidlockfile.PIDLockFile) - - def test_inherits_from_linkfilelock(self): - """ Should inherit from LinkFileLock. """ - instance = self.test_instance - self.failUnlessIsInstance(instance, lockfile.LinkFileLock) - - def test_has_specified_path(self): - """ Should have specified path. """ - instance = self.test_instance - expect_path = self.scenario['path'] - self.failUnlessEqual(expect_path, instance.path) - - -class PIDLockFile_read_pid_TestCase(scaffold.TestCase): - """ Test cases for PIDLockFile.read_pid method. """ - - def setUp(self): - """ Set up test fixtures. """ - setup_pidlockfile_fixtures(self, 'exist-other-pid') - - def tearDown(self): - """ Tear down test fixtures. """ - scaffold.mock_restore() - - def test_gets_pid_via_read_pid_from_pidfile(self): - """ Should get PID via read_pid_from_pidfile. """ - instance = self.test_instance - test_pid = self.scenario['pidfile_pid'] - expect_pid = test_pid - result = instance.read_pid() - self.failUnlessEqual(expect_pid, result) - - -class PIDLockFile_acquire_TestCase(scaffold.TestCase): - """ Test cases for PIDLockFile.acquire function. """ - - def setUp(self): - """ Set up test fixtures. """ - setup_pidlockfile_fixtures(self) - set_pidlockfile_scenario(self, 'not-exist') - - def tearDown(self): - """ Tear down test fixtures. """ - scaffold.mock_restore() - - def test_calls_linkfilelock_acquire(self): - """ Should first call LinkFileLock.acquire method. """ - instance = self.test_instance - expect_mock_output = """\ - Called lockfile.LinkFileLock.acquire() - ... - """ - instance.acquire() - self.failUnlessMockCheckerMatch(expect_mock_output) - - def test_calls_linkfilelock_acquire_with_timeout(self): - """ Should call LinkFileLock.acquire method with specified timeout. """ - instance = self.test_instance - test_timeout = object() - expect_mock_output = """\ - Called lockfile.LinkFileLock.acquire(timeout=%(test_timeout)r) - ... - """ % vars() - instance.acquire(timeout=test_timeout) - self.failUnlessMockCheckerMatch(expect_mock_output) - - def test_writes_pid_to_specified_file(self): - """ Should request writing current PID to specified file. """ - instance = self.test_instance - pidfile_path = self.scenario['path'] - expect_mock_output = """\ - ... - Called pidlockfile.write_pid_to_pidfile(%(pidfile_path)r) - """ % vars() - instance.acquire() - scaffold.mock_restore() - self.failUnlessMockCheckerMatch(expect_mock_output) - - def test_raises_lock_failed_on_write_error(self): - """ Should raise LockFailed error if write fails. """ - set_pidlockfile_scenario(self, 'not-exist-write-busy') - instance = self.test_instance - pidfile_path = self.scenario['path'] - mock_error = OSError(errno.EBUSY, "Bad stuff", pidfile_path) - pidlockfile.write_pid_to_pidfile.mock_raises = mock_error - expect_error = pidlockfile.LockFailed - self.failUnlessRaises( - expect_error, - instance.acquire) - - -class PIDLockFile_release_TestCase(scaffold.TestCase): - """ Test cases for PIDLockFile.release function. """ - - def setUp(self): - """ Set up test fixtures. """ - setup_pidlockfile_fixtures(self) - - def tearDown(self): - """ Tear down test fixtures. """ - scaffold.mock_restore() - - def test_does_not_remove_existing_pidfile_if_not_locking(self): - """ Should not request removal of PID file if not locking. """ - set_pidlockfile_scenario(self, 'exist-empty') - instance = self.test_instance - expect_error = lockfile.NotLocked - unwanted_mock_output = ( - "..." - "Called pidlockfile.remove_existing_pidfile" - "...") - self.failUnlessRaises( - expect_error, - instance.release) - self.failIfMockCheckerMatch(unwanted_mock_output) - - def test_does_not_remove_existing_pidfile_if_not_my_lock(self): - """ Should not request removal of PID file if we are not locking. """ - set_pidlockfile_scenario(self, 'exist-other-pid-locked') - instance = self.test_instance - expect_error = lockfile.NotMyLock - unwanted_mock_output = ( - "..." - "Called pidlockfile.remove_existing_pidfile" - "...") - self.failUnlessRaises( - expect_error, - instance.release) - self.failIfMockCheckerMatch(unwanted_mock_output) - - def test_removes_existing_pidfile_if_i_am_locking(self): - """ Should request removal of specified PID file if lock is ours. """ - set_pidlockfile_scenario(self, 'exist-current-pid-locked') - instance = self.test_instance - pidfile_path = self.scenario['path'] - expect_mock_output = """\ - ... - Called pidlockfile.remove_existing_pidfile(%(pidfile_path)r) - ... - """ % vars() - instance.release() - self.failUnlessMockCheckerMatch(expect_mock_output) - - def test_calls_linkfilelock_release(self): - """ Should finally call LinkFileLock.release method. """ - set_pidlockfile_scenario(self, 'exist-current-pid-locked') - instance = self.test_instance - expect_mock_output = """\ - ... - Called lockfile.LinkFileLock.release() - """ - instance.release() - self.failUnlessMockCheckerMatch(expect_mock_output) - - -class PIDLockFile_break_lock_TestCase(scaffold.TestCase): - """ Test cases for PIDLockFile.break_lock function. """ - - def setUp(self): - """ Set up test fixtures. """ - setup_pidlockfile_fixtures(self) - set_pidlockfile_scenario(self, 'exist-other-pid-locked') - - def tearDown(self): - """ Tear down test fixtures. """ - scaffold.mock_restore() - - def test_calls_linkfilelock_break_lock(self): - """ Should first call LinkFileLock.break_lock method. """ - instance = self.test_instance - expect_mock_output = """\ - Called lockfile.LinkFileLock.break_lock() - ... - """ - instance.break_lock() - self.failUnlessMockCheckerMatch(expect_mock_output) - - def test_removes_existing_pidfile(self): - """ Should request removal of specified PID file. """ - instance = self.test_instance - pidfile_path = self.scenario['path'] - expect_mock_output = """\ - ... - Called pidlockfile.remove_existing_pidfile(%(pidfile_path)r) - """ % vars() - instance.break_lock() - self.failUnlessMockCheckerMatch(expect_mock_output) - - -class read_pid_from_pidfile_TestCase(scaffold.TestCase): - """ Test cases for read_pid_from_pidfile function. """ - - def setUp(self): - """ Set up test fixtures. """ - setup_pidfile_fixtures(self) - - def tearDown(self): - """ Tear down test fixtures. """ - scaffold.mock_restore() - - def test_opens_specified_filename(self): - """ Should attempt to open specified pidfile filename. """ - set_pidlockfile_scenario(self, 'exist-other-pid') - pidfile_path = self.scenario['path'] - expect_mock_output = """\ - Called __builtin__.open(%(pidfile_path)r, 'r') - """ % vars() - dummy = pidlockfile.read_pid_from_pidfile(pidfile_path) - scaffold.mock_restore() - self.failUnlessMockCheckerMatch(expect_mock_output) - - def test_reads_pid_from_file(self): - """ Should read the PID from the specified file. """ - set_pidlockfile_scenario(self, 'exist-other-pid') - pidfile_path = self.scenario['path'] - expect_pid = self.scenario['pidfile_pid'] - pid = pidlockfile.read_pid_from_pidfile(pidfile_path) - scaffold.mock_restore() - self.failUnlessEqual(expect_pid, pid) - - def test_returns_none_when_file_nonexist(self): - """ Should return None when the PID file does not exist. """ - set_pidlockfile_scenario(self, 'not-exist') - pidfile_path = self.scenario['path'] - pid = pidlockfile.read_pid_from_pidfile(pidfile_path) - scaffold.mock_restore() - self.failUnlessIs(None, pid) - - def test_raises_error_when_file_read_fails(self): - """ Should raise error when the PID file read fails. """ - set_pidlockfile_scenario(self, 'exist-read-denied') - pidfile_path = self.scenario['path'] - expect_error = EnvironmentError - self.failUnlessRaises( - expect_error, - pidlockfile.read_pid_from_pidfile, pidfile_path) - - def test_raises_error_when_file_empty(self): - """ Should raise error when the PID file is empty. """ - set_pidlockfile_scenario(self, 'exist-empty') - pidfile_path = self.scenario['path'] - expect_error = pidlockfile.PIDFileParseError - self.failUnlessRaises( - expect_error, - pidlockfile.read_pid_from_pidfile, pidfile_path) - - def test_raises_error_when_file_contents_invalid(self): - """ Should raise error when the PID file contents are invalid. """ - set_pidlockfile_scenario(self, 'exist-invalid') - pidfile_path = self.scenario['path'] - expect_error = pidlockfile.PIDFileParseError - self.failUnlessRaises( - expect_error, - pidlockfile.read_pid_from_pidfile, pidfile_path) - - -class remove_existing_pidfile_TestCase(scaffold.TestCase): - """ Test cases for remove_existing_pidfile function. """ - - def setUp(self): - """ Set up test fixtures. """ - setup_pidfile_fixtures(self) - - scaffold.mock( - "os.remove", - tracker=self.mock_tracker) - - def tearDown(self): - """ Tear down test fixtures. """ - scaffold.mock_restore() - - def test_removes_specified_filename(self): - """ Should attempt to remove specified PID file filename. """ - set_pidlockfile_scenario(self, 'exist-current-pid') - pidfile_path = self.scenario['path'] - expect_mock_output = """\ - Called os.remove(%(pidfile_path)r) - """ % vars() - pidlockfile.remove_existing_pidfile(pidfile_path) - scaffold.mock_restore() - self.failUnlessMockCheckerMatch(expect_mock_output) - - def test_ignores_file_not_exist_error(self): - """ Should ignore error if file does not exist. """ - set_pidlockfile_scenario(self, 'not-exist') - pidfile_path = self.scenario['path'] - mock_error = OSError(errno.ENOENT, "Not there", pidfile_path) - os.remove.mock_raises = mock_error - expect_mock_output = """\ - Called os.remove(%(pidfile_path)r) - """ % vars() - pidlockfile.remove_existing_pidfile(pidfile_path) - scaffold.mock_restore() - self.failUnlessMockCheckerMatch(expect_mock_output) - - def test_propagates_arbitrary_oserror(self): - """ Should propagate any OSError other than ENOENT. """ - set_pidlockfile_scenario(self, 'exist-current-pid') - pidfile_path = self.scenario['path'] - mock_error = OSError(errno.EACCES, "Denied", pidfile_path) - os.remove.mock_raises = mock_error - self.failUnlessRaises( - type(mock_error), - pidlockfile.remove_existing_pidfile, - pidfile_path) - - -class write_pid_to_pidfile_TestCase(scaffold.TestCase): - """ Test cases for write_pid_to_pidfile function. """ - - def setUp(self): - """ Set up test fixtures. """ - setup_pidfile_fixtures(self) - set_pidlockfile_scenario(self, 'not-exist') - - def tearDown(self): - """ Tear down test fixtures. """ - scaffold.mock_restore() - - def test_opens_specified_filename(self): - """ Should attempt to open specified PID file filename. """ - pidfile_path = self.scenario['path'] - expect_flags = (os.O_CREAT | os.O_EXCL | os.O_WRONLY) - expect_mode = 0644 - expect_mock_output = """\ - Called os.open(%(pidfile_path)r, %(expect_flags)r, %(expect_mode)r) - ... - """ % vars() - pidlockfile.write_pid_to_pidfile(pidfile_path) - scaffold.mock_restore() - self.failUnlessMockCheckerMatch(expect_mock_output) - - def test_writes_pid_to_file(self): - """ Should write the current PID to the specified file. """ - pidfile_path = self.scenario['path'] - self.scenario['pidfile'].close = scaffold.Mock( - "PIDLockFile.close", - tracker=self.mock_tracker) - expect_line = "%(pid)d\n" % self.scenario - pidlockfile.write_pid_to_pidfile(pidfile_path) - scaffold.mock_restore() - self.failUnlessEqual(expect_line, self.scenario['pidfile'].getvalue()) - - def test_closes_file_after_write(self): - """ Should close the specified file after writing. """ - pidfile_path = self.scenario['path'] - self.scenario['pidfile'].write = scaffold.Mock( - "PIDLockFile.write", - tracker=self.mock_tracker) - self.scenario['pidfile'].close = scaffold.Mock( - "PIDLockFile.close", - tracker=self.mock_tracker) - expect_mock_output = """\ - ... - Called PIDLockFile.write(...) - Called PIDLockFile.close() - """ % vars() - pidlockfile.write_pid_to_pidfile(pidfile_path) - scaffold.mock_restore() - self.failUnlessMockCheckerMatch(expect_mock_output) - - -class TimeoutPIDLockFile_TestCase(scaffold.TestCase): - """ Test cases for ‘TimeoutPIDLockFile’ class. """ - - def setUp(self): - """ Set up test fixtures. """ - self.mock_tracker = scaffold.MockTracker() - - pidlockfile_scenarios = make_pidlockfile_scenarios() - self.pidlockfile_scenario = pidlockfile_scenarios['simple'] - pidfile_path = self.pidlockfile_scenario['path'] - - scaffold.mock( - "pidlockfile.PIDLockFile.__init__", - tracker=self.mock_tracker) - scaffold.mock( - "pidlockfile.PIDLockFile.acquire", - tracker=self.mock_tracker) - - self.scenario = { - 'pidfile_path': self.pidlockfile_scenario['path'], - 'acquire_timeout': object(), - } - - self.test_kwargs = dict( - path=self.scenario['pidfile_path'], - acquire_timeout=self.scenario['acquire_timeout'], - ) - self.test_instance = pidlockfile.TimeoutPIDLockFile(**self.test_kwargs) - - def tearDown(self): - """ Tear down test fixtures. """ - scaffold.mock_restore() - - def test_inherits_from_pidlockfile(self): - """ Should inherit from PIDLockFile. """ - instance = self.test_instance - self.failUnlessIsInstance(instance, pidlockfile.PIDLockFile) - - def test_init_has_expected_signature(self): - """ Should have expected signature for ‘__init__’. """ - def test_func(self, path, acquire_timeout=None, *args, **kwargs): pass - test_func.__name__ = '__init__' - self.failUnlessFunctionSignatureMatch( - test_func, - pidlockfile.TimeoutPIDLockFile.__init__) - - def test_has_specified_acquire_timeout(self): - """ Should have specified ‘acquire_timeout’ value. """ - instance = self.test_instance - expect_timeout = self.test_kwargs['acquire_timeout'] - self.failUnlessEqual(expect_timeout, instance.acquire_timeout) - - def test_calls_superclass_init(self): - """ Should call the superclass ‘__init__’. """ - expect_path = self.test_kwargs['path'] - expect_mock_output = """\ - Called pidlockfile.PIDLockFile.__init__( - %(expect_path)r) - """ % vars() - self.failUnlessMockCheckerMatch(expect_mock_output) - - def test_acquire_uses_specified_timeout(self): - """ Should call the superclass ‘acquire’ with specified timeout. """ - instance = self.test_instance - test_timeout = object() - expect_timeout = test_timeout - self.mock_tracker.clear() - expect_mock_output = """\ - Called pidlockfile.PIDLockFile.acquire(%(expect_timeout)r) - """ % vars() - instance.acquire(test_timeout) - self.failUnlessMockCheckerMatch(expect_mock_output) - - def test_acquire_uses_stored_timeout_by_default(self): - """ Should call superclass ‘acquire’ with stored timeout by default. """ - instance = self.test_instance - test_timeout = self.test_kwargs['acquire_timeout'] - expect_timeout = test_timeout - self.mock_tracker.clear() - expect_mock_output = """\ - Called pidlockfile.PIDLockFile.acquire(%(expect_timeout)r) - """ % vars() - instance.acquire() - self.failUnlessMockCheckerMatch(expect_mock_output) diff -Nru python-daemon-1.5.5/test/test_runner.py python-daemon-1.6/test/test_runner.py --- python-daemon-1.5.5/test/test_runner.py 2010-02-05 10:22:13.000000000 +0000 +++ python-daemon-1.6/test/test_runner.py 2010-05-10 10:35:20.000000000 +0000 @@ -13,15 +13,17 @@ """ Unit test for runner module. """ -import __builtin__ +import __builtin__ as builtins import os import sys import tempfile import errno import signal +import lockfile + import scaffold -from test_pidlockfile import ( +from test_pidfile import ( FakeFileDescriptorStringIO, setup_pidfile_fixtures, make_pidlockfile_scenarios, @@ -32,7 +34,7 @@ ) import daemon.daemon -from daemon import pidlockfile +from daemon import pidfile from daemon import runner @@ -119,13 +121,13 @@ testcase.mock_stderr = FakeFileDescriptorStringIO() scaffold.mock( - "sys.stderr", + u"sys.stderr", mock_obj=testcase.mock_stderr, tracker=testcase.mock_tracker) simple_scenario = testcase.runner_scenarios['simple'] - testcase.lockfile_class_name = "pidlockfile.TimeoutPIDLockFile" + testcase.lockfile_class_name = u"pidfile.TimeoutPIDLockFile" testcase.mock_runner_lock = scaffold.Mock( testcase.lockfile_class_name, @@ -147,23 +149,23 @@ self.pidfile_timeout = simple_scenario['pidfile_timeout'] run = scaffold.Mock( - "TestApp.run", + u"TestApp.run", tracker=testcase.mock_tracker) testcase.TestApp = TestApp scaffold.mock( - "daemon.runner.DaemonContext", + u"daemon.runner.DaemonContext", returns=scaffold.Mock( - "DaemonContext", + u"DaemonContext", tracker=testcase.mock_tracker), tracker=testcase.mock_tracker) testcase.test_app = testcase.TestApp() - testcase.test_program_name = "bazprog" + testcase.test_program_name = u"bazprog" testcase.test_program_path = ( - "/foo/bar/%(test_program_name)s" % vars(testcase)) + u"/foo/bar/%(test_program_name)s" % vars(testcase)) testcase.valid_argv_params = { 'start': [testcase.test_program_path, 'start'], 'stop': [testcase.test_program_path, 'stop'], @@ -180,16 +182,16 @@ return result scaffold.mock( - "__builtin__.open", + u"builtins.open", returns_func=mock_open, tracker=testcase.mock_tracker) scaffold.mock( - "os.kill", + u"os.kill", tracker=testcase.mock_tracker) scaffold.mock( - "sys.argv", + u"sys.argv", mock_obj=testcase.valid_argv_params['start'], tracker=testcase.mock_tracker) @@ -207,7 +209,7 @@ set_runner_scenario(self, 'simple') scaffold.mock( - "runner.DaemonRunner.parse_args", + u"runner.DaemonRunner.parse_args", tracker=self.mock_tracker) self.test_instance = runner.DaemonRunner(self.test_app) @@ -222,7 +224,7 @@ def test_parses_commandline_args(self): """ Should parse commandline arguments. """ - expect_mock_output = """\ + expect_mock_output = u"""\ Called runner.DaemonRunner.parse_args() ... """ @@ -251,7 +253,7 @@ def test_error_when_pidfile_path_not_absolute(self): """ Should raise ValueError when PID file path not absolute. """ - pidfile_path = "foo/bar.pid" + pidfile_path = u"foo/bar.pid" self.test_app.pidfile_path = pidfile_path expect_error = ValueError self.failUnlessRaises( @@ -263,7 +265,7 @@ pidfile_path = self.scenario['pidfile_path'] pidfile_timeout = self.scenario['pidfile_timeout'] lockfile_class_name = self.lockfile_class_name - expect_mock_output = """\ + expect_mock_output = u"""\ ... Called %(lockfile_class_name)s( %(pidfile_path)r, @@ -358,7 +360,7 @@ instance = self.test_instance progname = self.test_program_name argv = [self.test_program_path] - expect_stderr_output = """\ + expect_stderr_output = u"""\ usage: %(progname)s ... """ % vars() self.failUnlessRaises( @@ -377,7 +379,7 @@ set_runner_scenario(self, 'simple') scaffold.mock( - "daemon.runner.DaemonRunner._usage_exit", + u"daemon.runner.DaemonRunner._usage_exit", raises=NotImplementedError, tracker=self.mock_tracker) @@ -389,7 +391,7 @@ """ Should emit a usage message and exit if too few arguments. """ instance = self.test_instance argv = [self.test_program_path] - expect_mock_output = """\ + expect_mock_output = u"""\ Called daemon.runner.DaemonRunner._usage_exit(%(argv)r) """ % vars() try: @@ -403,7 +405,7 @@ instance = self.test_instance progname = self.test_program_name argv = [self.test_program_path, 'bogus'] - expect_mock_output = """\ + expect_mock_output = u"""\ Called daemon.runner.DaemonRunner._usage_exit(%(argv)r) """ % vars() try: @@ -415,10 +417,10 @@ def test_should_parse_system_argv_by_default(self): """ Should parse sys.argv by default. """ instance = self.test_instance - expect_action = 'start' + expect_action = u'start' argv = self.valid_argv_params['start'] scaffold.mock( - "sys.argv", + u"sys.argv", mock_obj=argv, tracker=self.mock_tracker) instance.parse_args() @@ -448,7 +450,7 @@ def test_raises_error_if_unknown_action(self): """ Should emit a usage message and exit if action is unknown. """ instance = self.test_instance - instance.action = 'bogus' + instance.action = u'bogus' expect_error = runner.DaemonRunnerInvalidActionError self.failUnlessRaises( expect_error, @@ -463,7 +465,7 @@ setup_runner_fixtures(self) set_runner_scenario(self, 'simple') - self.test_instance.action = 'start' + self.test_instance.action = u'start' def tearDown(self): """ Tear down test fixtures. """ @@ -474,7 +476,7 @@ set_pidlockfile_scenario(self, 'exist-other-pid-locked') instance = self.test_instance instance.daemon_context.open.mock_raises = ( - pidlockfile.AlreadyLocked) + lockfile.AlreadyLocked) pidfile_path = self.scenario['pidfile_path'] expect_error = runner.DaemonRunnerStartFailureError expect_message_content = pidfile_path @@ -484,8 +486,8 @@ pass else: raise self.failureException( - "Failed to raise " + expect_error.__name__) - self.failUnlessIn(str(exc), expect_message_content) + u"Failed to raise " + expect_error.__name__) + self.failUnlessIn(unicode(exc.message), expect_message_content) def test_breaks_lock_if_no_such_process(self): """ Should request breaking lock if PID file process is not running. """ @@ -496,10 +498,10 @@ pidfile_path = self.scenario['pidfile_path'] test_pid = self.scenario['pidlockfile_scenario']['pidfile_pid'] expect_signal = signal.SIG_DFL - error = OSError(errno.ESRCH, "Not running") + error = OSError(errno.ESRCH, u"Not running") os.kill.mock_raises = error lockfile_class_name = self.lockfile_class_name - expect_mock_output = """\ + expect_mock_output = u"""\ ... Called os.kill(%(test_pid)r, %(expect_signal)r) Called %(lockfile_class_name)s.break_lock() @@ -512,7 +514,7 @@ def test_requests_daemon_context_open(self): """ Should request the daemon context to open. """ instance = self.test_instance - expect_mock_output = """\ + expect_mock_output = u"""\ ... Called DaemonContext.open() ... @@ -524,7 +526,7 @@ """ Should emit start message to stderr. """ instance = self.test_instance current_pid = self.scenario['pid'] - expect_stderr = """\ + expect_stderr = u"""\ started with pid %(current_pid)d """ % vars() instance.do_action() @@ -534,7 +536,7 @@ def test_requests_app_run(self): """ Should request the application to run. """ instance = self.test_instance - expect_mock_output = """\ + expect_mock_output = u"""\ ... Called TestApp.run() """ @@ -550,7 +552,7 @@ setup_runner_fixtures(self) set_runner_scenario(self, 'pidfile-locked') - self.test_instance.action = 'stop' + self.test_instance.action = u'stop' self.mock_runner_lock.is_locked.mock_returns = True self.mock_runner_lock.i_am_locking.mock_returns = False @@ -578,7 +580,7 @@ pass else: raise self.failureException( - "Failed to raise " + expect_error.__name__) + u"Failed to raise " + expect_error.__name__) scaffold.mock_restore() self.failUnlessIn(str(exc), expect_message_content) @@ -588,10 +590,10 @@ pidfile_path = self.scenario['pidfile_path'] test_pid = self.scenario['pidlockfile_scenario']['pidfile_pid'] expect_signal = signal.SIG_DFL - error = OSError(errno.ESRCH, "Not running") + error = OSError(errno.ESRCH, u"Not running") os.kill.mock_raises = error lockfile_class_name = self.lockfile_class_name - expect_mock_output = """\ + expect_mock_output = u"""\ ... Called %(lockfile_class_name)s.break_lock() """ % vars() @@ -604,7 +606,7 @@ instance = self.test_instance test_pid = self.scenario['pidlockfile_scenario']['pidfile_pid'] expect_signal = signal.SIGTERM - expect_mock_output = """\ + expect_mock_output = u"""\ ... Called os.kill(%(test_pid)r, %(expect_signal)r) """ % vars() @@ -617,7 +619,7 @@ instance = self.test_instance test_pid = self.scenario['pidlockfile_scenario']['pidfile_pid'] pidfile_path = self.scenario['pidfile_path'] - error = OSError(errno.EPERM, "Nice try") + error = OSError(errno.EPERM, u"Nice try") os.kill.mock_raises = error expect_error = runner.DaemonRunnerStopFailureError expect_message_content = str(test_pid) @@ -627,8 +629,9 @@ pass else: raise self.failureException( - "Failed to raise " + expect_error.__name__) - self.failUnlessIn(str(exc), expect_message_content) + u"Failed to raise " + expect_error.__name__) + scaffold.mock_restore() + self.failUnlessIn(unicode(exc), expect_message_content) class DaemonRunner_do_action_restart_TestCase(scaffold.TestCase): @@ -639,7 +642,7 @@ setup_runner_fixtures(self) set_runner_scenario(self, 'pidfile-locked') - self.test_instance.action = 'restart' + self.test_instance.action = u'restart' def tearDown(self): """ Tear down test fixtures. """ @@ -649,12 +652,12 @@ """ Should request stop, then start. """ instance = self.test_instance scaffold.mock( - "daemon.runner.DaemonRunner._start", + u"daemon.runner.DaemonRunner._start", tracker=self.mock_tracker) scaffold.mock( - "daemon.runner.DaemonRunner._stop", + u"daemon.runner.DaemonRunner._stop", tracker=self.mock_tracker) - expect_mock_output = """\ + expect_mock_output = u"""\ Called daemon.runner.DaemonRunner._stop() Called daemon.runner.DaemonRunner._start() """