Django

Code

root/django/trunk/django/utils/autoreload.py

Revision 8235, 4.1 kB (checked in by mtredinnick, 5 months ago)

Made auto-reloading for the dev server a little more friendly in the Jython
case. Patch from Leo Soto. Fixed #8147.

In passing, also corrected a typo when reloading .pyo files. Fixed #8157.

  • Property svn:eol-style set to native
Line 
1 # Autoreloading launcher.
2 # Borrowed from Peter Hunt and the CherryPy project (http://www.cherrypy.org).
3 # Some taken from Ian Bicking's Paste (http://pythonpaste.org/).
4 #
5 # Portions copyright (c) 2004, CherryPy Team (team@cherrypy.org)
6 # All rights reserved.
7 #
8 # Redistribution and use in source and binary forms, with or without modification,
9 # are permitted provided that the following conditions are met:
10 #
11 #     * Redistributions of source code must retain the above copyright notice,
12 #       this list of conditions and the following disclaimer.
13 #     * Redistributions in binary form must reproduce the above copyright notice,
14 #       this list of conditions and the following disclaimer in the documentation
15 #       and/or other materials provided with the distribution.
16 #     * Neither the name of the CherryPy Team nor the names of its contributors
17 #       may be used to endorse or promote products derived from this software
18 #       without specific prior written permission.
19 #
20 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
21 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
24 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31 import os, sys, time
32
33 try:
34     import thread
35 except ImportError:
36     import dummy_thread as thread
37
38 # This import does nothing, but it's necessary to avoid some race conditions
39 # in the threading module. See http://code.djangoproject.com/ticket/2330 .
40 try:
41     import threading
42 except ImportError:
43     pass
44
45
46 RUN_RELOADER = True
47
48 _mtimes = {}
49 _win = (sys.platform == "win32")
50
51 def code_changed():
52     global _mtimes, _win
53     for filename in filter(lambda v: v, map(lambda m: getattr(m, "__file__", None), sys.modules.values())):
54         if filename.endswith(".pyc") or filename.endswith(".pyo"):
55             filename = filename[:-1]
56         if not os.path.exists(filename):
57             continue # File might be in an egg, so it can't be reloaded.
58         stat = os.stat(filename)
59         mtime = stat.st_mtime
60         if _win:
61             mtime -= stat.st_ctime
62         if filename not in _mtimes:
63             _mtimes[filename] = mtime
64             continue
65         if mtime != _mtimes[filename]:
66             _mtimes = {}
67             return True
68     return False
69
70 def reloader_thread():
71     while RUN_RELOADER:
72         if code_changed():
73             sys.exit(3) # force reload
74         time.sleep(1)
75
76 def restart_with_reloader():
77     while True:
78         args = [sys.executable] + sys.argv
79         if sys.platform == "win32":
80             args = ['"%s"' % arg for arg in args]
81         new_environ = os.environ.copy()
82         new_environ["RUN_MAIN"] = 'true'
83         exit_code = os.spawnve(os.P_WAIT, sys.executable, args, new_environ)
84         if exit_code != 3:
85             return exit_code
86
87 def python_reloader(main_func, args, kwargs):
88     if os.environ.get("RUN_MAIN") == "true":
89         thread.start_new_thread(main_func, args, kwargs)
90         try:
91             reloader_thread()
92         except KeyboardInterrupt:
93             pass
94     else:
95         try:
96             sys.exit(restart_with_reloader())
97         except KeyboardInterrupt:
98             pass
99
100 def jython_reloader(main_func, args, kwargs):
101     from _systemrestart import SystemRestart
102     thread.start_new_thread(main_func, args)
103     while True:
104         if code_changed():
105             raise SystemRestart
106         time.sleep(1)
107
108
109 def main(main_func, args=None, kwargs=None):
110     if args is None:
111         args = ()
112     if kwargs is None:
113         kwargs = {}
114     if sys.platform.startswith('java'):
115         reloader = jython_reloader
116     else:
117         reloader = python_reloader
118     reloader(main_func, args, kwargs)
Note: See TracBrowser for help on using the browser.