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/).
5 # Portions copyright (c) 2004, CherryPy Team (team@cherrypy.org)
8 # Redistribution and use in source and binary forms, with or without modification,
9 # are permitted provided that the following conditions are met:
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.
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.
36 import dummy_thread
as thread
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 .
49 _win
= (sys
.platform
== "win32")
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
)
61 mtime
-= stat
.st_ctime
62 if filename
not in _mtimes
:
63 _mtimes
[filename
] = mtime
65 if mtime
!= _mtimes
[filename
]:
70 def reloader_thread():
73 sys
.exit(3) # force reload
76 def restart_with_reloader():
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
)
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
)
92 except KeyboardInterrupt:
96 sys
.exit(restart_with_reloader())
97 except KeyboardInterrupt:
100 def jython_reloader(main_func
, args
, kwargs
):
101 from _systemrestart
import SystemRestart
102 thread
.start_new_thread(main_func
, args
)
109 def main(main_func
, args
=None, kwargs
=None):
114 if sys
.platform
.startswith('java'):
115 reloader
= jython_reloader
117 reloader
= python_reloader
118 reloader(main_func
, args
, kwargs
)