Files
deb-python-pecan/pecan/monitor.py
Ryan Petrello 8ec6f6f5ff Adding (optional) file monitoring functionality to automatically reload pecan apps when .py files change (similar to paster --reload server config.ini). Now in your project, you can do:
pecan.conf.app = {'reload': True, ...}

Additionally, the pecan quick start template has been configured to auto-reload by default.
2010-12-15 12:48:44 -05:00

77 lines
2.6 KiB
Python

import sys, os
import subprocess
class MonitorableProcess(object):
_reloader_environ_key = 'PYTHON_RELOADER_SHOULD_RUN'
def start_monitoring(self):
if os.environ.get(self._reloader_environ_key):
from paste import reloader
reloader.install()
else:
return self.restart_with_reloader()
def restart_with_reloader(self):
print 'Starting subprocess with file monitor'
while 1:
args = [self.quote_first_command_arg(sys.executable)] + sys.argv
new_environ = os.environ.copy()
new_environ[self._reloader_environ_key] = 'true'
proc = None
try:
try:
_turn_sigterm_into_systemexit()
proc = subprocess.Popen(args, env=new_environ)
exit_code = proc.wait()
proc = None
except KeyboardInterrupt:
print '^C caught in monitor process'
raise
finally:
if (proc is not None
and hasattr(os, 'kill')):
import signal
try:
os.kill(proc.pid, signal.SIGTERM)
except (OSError, IOError):
pass
# Reloader always exits with code 3; but if we are
# a monitor, any exit code will restart
if exit_code != 3:
return exit_code
print '-'*20, 'Restarting', '-'*20
def quote_first_command_arg(self, arg):
"""
There's a bug in Windows when running an executable that's
located inside a path with a space in it. This method handles
that case, or on non-Windows systems or an executable with no
spaces, it just leaves well enough alone.
"""
if (sys.platform != 'win32'
or ' ' not in arg):
# Problem does not apply:
return arg
try:
import win32api
except ImportError:
raise ValueError(
"The executable %r contains a space, and in order to "
"handle this issue you must have the win32api module "
"installed" % arg)
arg = win32api.GetShortPathName(arg)
return arg
def _turn_sigterm_into_systemexit():
"""
Attempts to turn a SIGTERM exception into a SystemExit exception.
"""
try:
import signal
except ImportError:
return
def handle_term(signo, frame):
raise SystemExit
signal.signal(signal.SIGTERM, handle_term)