diff options
Diffstat (limited to 'lib/python2.7/site-packages/django/utils/autoreload.py')
-rw-r--r-- | lib/python2.7/site-packages/django/utils/autoreload.py | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/lib/python2.7/site-packages/django/utils/autoreload.py b/lib/python2.7/site-packages/django/utils/autoreload.py new file mode 100644 index 0000000..6de15a2 --- /dev/null +++ b/lib/python2.7/site-packages/django/utils/autoreload.py @@ -0,0 +1,182 @@ +# Autoreloading launcher. +# Borrowed from Peter Hunt and the CherryPy project (http://www.cherrypy.org). +# Some taken from Ian Bicking's Paste (http://pythonpaste.org/). +# +# Portions copyright (c) 2004, CherryPy Team (team@cherrypy.org) +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the CherryPy Team nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import os, sys, time, signal, traceback + +try: + from django.utils.six.moves import _thread as thread +except ImportError: + from django.utils.six.moves import _dummy_thread as thread + +# This import does nothing, but it's necessary to avoid some race conditions +# in the threading module. See http://code.djangoproject.com/ticket/2330 . +try: + import threading +except ImportError: + pass + +try: + import termios +except ImportError: + termios = None + +RUN_RELOADER = True + +_mtimes = {} +_win = (sys.platform == "win32") + +_error_files = [] + +def code_changed(): + global _mtimes, _win + filenames = [] + for m in list(sys.modules.values()): + try: + filenames.append(m.__file__) + except AttributeError: + pass + for filename in filenames + _error_files: + if not filename: + continue + if filename.endswith(".pyc") or filename.endswith(".pyo"): + filename = filename[:-1] + if filename.endswith("$py.class"): + filename = filename[:-9] + ".py" + if not os.path.exists(filename): + continue # File might be in an egg, so it can't be reloaded. + stat = os.stat(filename) + mtime = stat.st_mtime + if _win: + mtime -= stat.st_ctime + if filename not in _mtimes: + _mtimes[filename] = mtime + continue + if mtime != _mtimes[filename]: + _mtimes = {} + try: + del _error_files[_error_files.index(filename)] + except ValueError: + pass + return True + return False + +def check_errors(fn): + def wrapper(*args, **kwargs): + try: + fn(*args, **kwargs) + except (ImportError, IndentationError, NameError, SyntaxError, + TypeError, AttributeError): + et, ev, tb = sys.exc_info() + + if getattr(ev, 'filename', None) is None: + # get the filename from the last item in the stack + filename = traceback.extract_tb(tb)[-1][0] + else: + filename = ev.filename + + if filename not in _error_files: + _error_files.append(filename) + + raise + + return wrapper + +def ensure_echo_on(): + if termios: + fd = sys.stdin + if fd.isatty(): + attr_list = termios.tcgetattr(fd) + if not attr_list[3] & termios.ECHO: + attr_list[3] |= termios.ECHO + if hasattr(signal, 'SIGTTOU'): + old_handler = signal.signal(signal.SIGTTOU, signal.SIG_IGN) + else: + old_handler = None + termios.tcsetattr(fd, termios.TCSANOW, attr_list) + if old_handler is not None: + signal.signal(signal.SIGTTOU, old_handler) + +def reloader_thread(): + ensure_echo_on() + while RUN_RELOADER: + if code_changed(): + sys.exit(3) # force reload + time.sleep(1) + +def restart_with_reloader(): + while True: + args = [sys.executable] + ['-W%s' % o for o in sys.warnoptions] + sys.argv + if sys.platform == "win32": + args = ['"%s"' % arg for arg in args] + new_environ = os.environ.copy() + new_environ["RUN_MAIN"] = 'true' + exit_code = os.spawnve(os.P_WAIT, sys.executable, args, new_environ) + if exit_code != 3: + return exit_code + +def python_reloader(main_func, args, kwargs): + if os.environ.get("RUN_MAIN") == "true": + thread.start_new_thread(main_func, args, kwargs) + try: + reloader_thread() + except KeyboardInterrupt: + pass + else: + try: + exit_code = restart_with_reloader() + if exit_code < 0: + os.kill(os.getpid(), -exit_code) + else: + sys.exit(exit_code) + except KeyboardInterrupt: + pass + +def jython_reloader(main_func, args, kwargs): + from _systemrestart import SystemRestart + thread.start_new_thread(main_func, args) + while True: + if code_changed(): + raise SystemRestart + time.sleep(1) + + +def main(main_func, args=None, kwargs=None): + if args is None: + args = () + if kwargs is None: + kwargs = {} + if sys.platform.startswith('java'): + reloader = jython_reloader + else: + reloader = python_reloader + + wrapped_main_func = check_errors(main_func) + reloader(wrapped_main_func, args, kwargs) + |