Skip to content

Commit b615621

Browse files
committed
fix working_directory creation
fix typos
1 parent be61f23 commit b615621

File tree

4 files changed

+81
-61
lines changed

4 files changed

+81
-61
lines changed

doc/source/intro.rst

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,8 @@ seemed to be unmaintained, and failed to run under python 3.
99
Also the bundled Pidfile implementation was not working anymore, because
1010
of incompatibilities with newer version of external libraries.
1111

12-
The goal of pep3143daemon was to create a complete, and working PEP 3143
13-
library, that only depends on Libs that are shipped with python 2 and 3.
14-
15-
For this reason, also a working PidFile class is bundled with this Package.
12+
The goal of pep3143daemon is to create a complete, and working PEP 3143
13+
library. For this reason, also a working PidFile class is bundled with this Package.
1614

1715
The tests, written for this package, where implemented, using the Python 3
1816
unittest framework. I did not spend any time making the tests run on Python 2.
@@ -24,8 +22,8 @@ Patches to make the tests run under python 2.6 / 2.7 are welcome!
2422
Differences
2523
-----------
2624

27-
pep3143daemon mostly sticks to the PEP but does not implement
28-
some details that seem to be misguided.
25+
pep3143daemon mostly sticks to the PEP, but does not implement
26+
some details that seem to be wrong.
2927
The main difference is the DaemonContext.close() method.
3028

3129
The close method of DeamonContext is implemented as a dummy method.
@@ -38,7 +36,7 @@ daemon in a sane way. But worse, removing the PidFile before the daemon is
3836
terminated, would allow a second instance to start. Which can lead to
3937
undefined behaviour.
4038

41-
The removal of the PidFile is now implemented in the PidFile class, that is
39+
The removal of the PidFile is now implemented in the PidFile class,
4240
distributed with the pep3143daemon package.
4341
The file will be removed via an atexit call.
4442

pep3143daemon/daemon.py

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class DaemonContext(object):
3030
on the instance.
3131
3232
Altering attributes after open() is called, will have no effect.
33-
In future versions, trying to do so, will raise a DaemonError.
33+
In future versions, trying to do so, will may raise a DaemonError.
3434
3535
:param chroot_directory:
3636
Full path to the directory that should be set as effective root
@@ -45,7 +45,7 @@ class DaemonContext(object):
4545
:type working_directory: str.
4646
4747
:param umask:
48-
File access creation mask for this after daemon start
48+
File access creation mask for this daemon after start
4949
:type umask: int.
5050
5151
:param uid:
@@ -63,11 +63,12 @@ class DaemonContext(object):
6363
:param detach_process:
6464
If True, do the double fork magic. If the process was started
6565
by inet or an init like program, you may don´t need to detach.
66+
If not set, we try to figure out if forking is needed.
6667
:type detach_process: bool.
6768
6869
:param files_preserve:
6970
List of integers, or objects with a fileno method, that
70-
represent a files that should not be closed while daemoninzing.
71+
represent files that should not be closed while daemoninzing.
7172
:type files_preserve: list
7273
7374
:param pidfile:
@@ -100,6 +101,7 @@ def __init__(
100101
101102
"""
102103
self._is_open = False
104+
self._working_directory = None
103105
self.chroot_directory = chroot_directory
104106
self.umask = umask
105107
self.uid = uid if uid else os.getuid()
@@ -113,11 +115,7 @@ def __init__(
113115
self.stdin = stdin
114116
self.stdout = stdout
115117
self.stderr = stderr
116-
if chroot_directory and not \
117-
working_directory.startswith(chroot_directory):
118-
self.working_directory = chroot_directory + working_directory
119-
else:
120-
self.working_directory = working_directory
118+
self.working_directory = working_directory
121119

122120
def __enter__(self):
123121
""" Context Handler, wrapping self.open()
@@ -135,7 +133,7 @@ def __exit__(self, exc_type, exc_val, exc_tb):
135133
self.close()
136134

137135
def _get_signal_handler(self, handler):
138-
""" get the callback function for a signal handler
136+
""" get the callback function for handler
139137
140138
If the handler is None, returns signal.SIG_IGN.
141139
If the handler is a string, return the matching attribute of this
@@ -159,7 +157,7 @@ def _files_preserve(self):
159157
""" create a set of protected files
160158
161159
create a set of files, based on self.files_preserve and
162-
self.stdin, self,stdout and self.stderr, that shoud not get
160+
self.stdin, self,stdout and self.stderr, that should not get
163161
closed while daemonizing.
164162
165163
:return: set
@@ -178,7 +176,7 @@ def _files_preserve(self):
178176
def _signal_handler_map(self):
179177
""" Create the signal handler map
180178
181-
create a dictinary with signal:handler mapping based on
179+
create a dictionary with signal:handler mapping based on
182180
self.signal_map
183181
184182
:return: dict
@@ -188,9 +186,28 @@ def _signal_handler_map(self):
188186
result[signum] = self._get_signal_handler(handler)
189187
return result
190188

191-
def close(self):
192-
""" Dummy function"""
193-
pass
189+
@property
190+
def working_directory(self):
191+
""" The working_directory property
192+
193+
:return: str
194+
"""
195+
if self.chroot_directory and not \
196+
self._working_directory.startswith(self.chroot_directory):
197+
return self.chroot_directory + self._working_directory
198+
else:
199+
return self._working_directory
200+
201+
@working_directory.setter
202+
def working_directory(self, value):
203+
""" Set working directory
204+
205+
New value is ignored if already daemonized.
206+
207+
:param value: str
208+
:return:
209+
"""
210+
self._working_directory = value
194211

195212
@property
196213
def is_open(self):
@@ -200,6 +217,10 @@ def is_open(self):
200217
"""
201218
return self._is_open
202219

220+
def close(self):
221+
""" Dummy function"""
222+
pass
223+
203224
def open(self):
204225
""" Daemonize this process
205226
@@ -359,7 +380,7 @@ def parent_is_inet():
359380

360381

361382
def detach_required():
362-
""" Check if detaching is requered
383+
""" Check if detaching is required
363384
364385
This is done by collecting the results of parent_is_inet and
365386
parent_is_init. If one of them is True, detaching, aka the daemoninzing,

setup.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
setup(
66
name='pep3143daemon',
7-
version='0.0.1',
7+
version='0.0.2',
88
description='Implementation of PEP 3143, a unix daemon',
99
long_description=pep3143daemon.__doc__,
1010
packages=['pep3143daemon'],
@@ -28,6 +28,8 @@
2828
],
2929
keywords=[
3030
'daemon',
31+
'daemonize'
32+
'daemonizing'
3133
'fork',
3234
'pep 3143',
3335
'3143'

test/unit/test_Daemon.py

Lines changed: 37 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -44,29 +44,28 @@ def setUp(self):
4444
self.addCleanup(patch.stopall)
4545

4646
self.daemoncontext = pep3143daemon.daemon.DaemonContext()
47-
self.mockdaemoncontext = Mock()
4847

4948
# Test DaemonContext.__init__()
5049
def test___init__defaultargs(self):
51-
pep3143daemon.daemon.DaemonContext.__init__(self.mockdaemoncontext)
52-
self.assertIsNone(self.mockdaemoncontext.files_preserve)
53-
self.assertIsNone(self.mockdaemoncontext.chroot_directory)
54-
self.assertEqual(self.mockdaemoncontext.working_directory, '/')
55-
self.assertEqual(self.mockdaemoncontext.umask, 0)
56-
self.assertIsNone(self.mockdaemoncontext.pidfile)
50+
pep3143daemon.daemon.DaemonContext.__init__(self.daemoncontext)
51+
self.assertIsNone(self.daemoncontext.files_preserve)
52+
self.assertIsNone(self.daemoncontext.chroot_directory)
53+
self.assertEqual(self.daemoncontext.working_directory, '/')
54+
self.assertEqual(self.daemoncontext.umask, 0)
55+
self.assertIsNone(self.daemoncontext.pidfile)
5756
detach_required = pep3143daemon.daemon.detach_required()
58-
self.assertEqual(self.mockdaemoncontext.detach_process, detach_required)
57+
self.assertEqual(self.daemoncontext.detach_process, detach_required)
5958
signal_map = pep3143daemon.daemon.default_signal_map()
60-
self.assertEqual(self.mockdaemoncontext.signal_map, signal_map)
61-
self.assertEqual(self.mockdaemoncontext.uid, self.os_mock.getuid())
59+
self.assertEqual(self.daemoncontext.signal_map, signal_map)
60+
self.assertEqual(self.daemoncontext.uid, self.os_mock.getuid())
6261
self.os_mock.getuid.assert_called_with()
63-
self.assertEqual(self.mockdaemoncontext.gid, self.os_mock.getgid())
62+
self.assertEqual(self.daemoncontext.gid, self.os_mock.getgid())
6463
self.os_mock.getgid.assert_called_with()
65-
self.assertTrue(self.mockdaemoncontext.prevent_core)
66-
self.assertIsNone(self.mockdaemoncontext.stdin)
67-
self.assertIsNone(self.mockdaemoncontext.stdout)
68-
self.assertIsNone(self.mockdaemoncontext.stderr)
69-
self.assertFalse(self.mockdaemoncontext._is_open)
64+
self.assertTrue(self.daemoncontext.prevent_core)
65+
self.assertIsNone(self.daemoncontext.stdin)
66+
self.assertIsNone(self.daemoncontext.stdout)
67+
self.assertIsNone(self.daemoncontext.stderr)
68+
self.assertFalse(self.daemoncontext._is_open)
7069

7170
def test___init__customargs(self):
7271
files_preserve = Mock()
@@ -84,7 +83,7 @@ def test___init__customargs(self):
8483
stderr = Mock()
8584

8685
pep3143daemon.daemon.DaemonContext.__init__(
87-
self.mockdaemoncontext,
86+
self.daemoncontext,
8887
files_preserve=files_preserve,
8988
chroot_directory=chroot_directory,
9089
working_directory=working_directory,
@@ -99,33 +98,33 @@ def test___init__customargs(self):
9998
stdout=stdout,
10099
stderr=stderr)
101100

102-
self.assertEqual(self.mockdaemoncontext.files_preserve, files_preserve)
103-
self.assertEqual(self.mockdaemoncontext.chroot_directory, chroot_directory)
104-
self.assertEqual(self.mockdaemoncontext.working_directory, working_directory)
105-
self.assertEqual(self.mockdaemoncontext.umask, umask)
106-
self.assertEqual(self.mockdaemoncontext.pidfile, pidfile)
107-
self.assertEqual(self.mockdaemoncontext.detach_process, detach_process)
108-
self.assertEqual(self.mockdaemoncontext.signal_map, signal_map)
109-
self.assertEqual(self.mockdaemoncontext.uid, uid)
110-
self.assertEqual(self.mockdaemoncontext.gid, gid)
111-
self.assertEqual(self.mockdaemoncontext.prevent_core, prevent_core)
112-
self.assertEqual(self.mockdaemoncontext.stdin, stdin)
113-
self.assertEqual(self.mockdaemoncontext.stdout, stdout)
114-
self.assertEqual(self.mockdaemoncontext.stderr, stderr)
101+
self.assertEqual(self.daemoncontext.files_preserve, files_preserve)
102+
self.assertEqual(self.daemoncontext.chroot_directory, chroot_directory)
103+
self.assertEqual(self.daemoncontext.working_directory, working_directory)
104+
self.assertEqual(self.daemoncontext.umask, umask)
105+
self.assertEqual(self.daemoncontext.pidfile, pidfile)
106+
self.assertEqual(self.daemoncontext.detach_process, detach_process)
107+
self.assertEqual(self.daemoncontext.signal_map, signal_map)
108+
self.assertEqual(self.daemoncontext.uid, uid)
109+
self.assertEqual(self.daemoncontext.gid, gid)
110+
self.assertEqual(self.daemoncontext.prevent_core, prevent_core)
111+
self.assertEqual(self.daemoncontext.stdin, stdin)
112+
self.assertEqual(self.daemoncontext.stdout, stdout)
113+
self.assertEqual(self.daemoncontext.stderr, stderr)
115114

116115
def test___init__chroot_substring_of_workdir(self):
117116
pep3143daemon.daemon.DaemonContext.__init__(
118-
self.mockdaemoncontext,
117+
self.daemoncontext,
119118
working_directory='/foo/bar/baz',
120119
chroot_directory='/foo/bar')
121-
self.assertEqual(self.mockdaemoncontext.working_directory, '/foo/bar/baz')
120+
self.assertEqual(self.daemoncontext.working_directory, '/foo/bar/baz')
122121

123122
def test___init__chroot_not_substring_of_workdir(self):
124123
pep3143daemon.daemon.DaemonContext.__init__(
125-
self.mockdaemoncontext,
124+
self.daemoncontext,
126125
working_directory='/baz',
127126
chroot_directory='/foo/bar')
128-
self.assertEqual(self.mockdaemoncontext.working_directory, '/foo/bar/baz')
127+
self.assertEqual(self.daemoncontext.working_directory, '/foo/bar/baz')
129128

130129
# Test DaemonContext._exclude_filenos
131130
def test_exclude_filenos(self):
@@ -141,20 +140,20 @@ def test_exclude_filenos(self):
141140
# Test DaemonContext._get_signal_handler()
142141
def test__get_signal_handler_None(self):
143142
result = pep3143daemon.daemon.DaemonContext._get_signal_handler(
144-
self.mockdaemoncontext,
143+
self.daemoncontext,
145144
None)
146145
self.assertEqual(result, self.signal_mock.SIG_IGN)
147146

148147
def test__get_signal_handler_attribute(self):
149148
result = pep3143daemon.daemon.DaemonContext._get_signal_handler(
150-
self.mockdaemoncontext,
149+
self.daemoncontext,
151150
'terminate')
152-
self.assertEqual(result, self.mockdaemoncontext.terminate)
151+
self.assertEqual(result, self.daemoncontext.terminate)
153152

154153
def test__get_signal_handler_other(self):
155154
other = Mock()
156155
result = pep3143daemon.daemon.DaemonContext._get_signal_handler(
157-
self.mockdaemoncontext,
156+
self.daemoncontext,
158157
other)
159158
self.assertEqual(result, other)
160159

0 commit comments

Comments
 (0)