summaryrefslogtreecommitdiff
path: root/lib/python2.7/site-packages/django/utils/autoreload.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/python2.7/site-packages/django/utils/autoreload.py')
-rw-r--r--lib/python2.7/site-packages/django/utils/autoreload.py182
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)
+