1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
"""
Use this like::
import reloader
reloader.install()
Then make sure your server is installed with a shell script like::
err=3
while test "$err" -eq 3 ; do
python server.py
err="$?"
done
or restart in Python (server.py does this). Use the watch_file(filename)
function to cause a reload/restart for other other non-Python files (e.g.,
configuration files).
"""
import os
import sys
import time
import threading
import atexit
from paste.util.classinstance import classinstancemethod
def install(poll_interval=1, raise_keyboard_interrupt=True):
mon = Monitor(poll_interval=poll_interval,
raise_keyboard_interrupt=raise_keyboard_interrupt)
t = threading.Thread(target=mon.periodic_reload)
t.start()
class Monitor:
instances = []
global_extra_files = []
def __init__(self, poll_interval, raise_keyboard_interrupt):
self.module_mtimes = {}
atexit.register(self.atexit)
self.keep_running = True
self.poll_interval = poll_interval
self.raise_keyboard_interrupt = raise_keyboard_interrupt
self.extra_files = self.global_extra_files[:]
self.instances.append(self)
def atexit(self):
self.keep_running = False
if self.raise_keyboard_interrupt:
# This exception is somehow magic, because it applies
# to more threads and situations (like socket.accept)
# that a mere SystemExit will not.
raise KeyboardInterrupt("Exiting process")
def periodic_reload(self):
while 1:
if not self.keep_running:
break
if not self.check_reload():
os._exit(3)
break
time.sleep(self.poll_interval)
def check_reload(self):
filenames = self.extra_files[:]
for name, module in sys.modules.items():
try:
filenames.append(module.__file__)
except AttributeError:
continue
for filename in filenames:
try:
mtime = os.stat(filename).st_mtime
except (OSError, IOError):
continue
if filename.endswith('.pyc') and os.path.exists(filename[:-1]):
mtime = max(os.stat(filename[:-1]).st_mtime, mtime)
if not self.module_mtimes.has_key(filename):
self.module_mtimes[filename] = mtime
elif self.module_mtimes[filename] < mtime:
print >> sys.stderr, (
"%s changed; reloading..." % filename)
return False
return True
def watch_file(self, cls, filename):
filename = os.path.abspath(filename)
if self is None:
for instance in cls.instances:
instance.watch_file(filename)
cls.global_extra_files.append(filename)
else:
self.extra_files.append(filename)
watch_file = classinstancemethod(watch_file)
watch_file = Monitor.watch_file
def awake_select(addrs):
"""
When using socket.select(), processes will not quit. By connecting
to the addresses locally we move the code out of the select, where
it can terminate properly.
(For now, KeyboardInterrupt seems to terminate these selects
properly)
"""
for addr in addrs:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
sock.connect(addr)
sock.close()
except:
pass
|