# Based on this file:
# https://github.com/pallets/werkzeug/blob/master/werkzeug/_reloader.py
import time, os, sys, subprocess
PY2 = sys.version_info[0] == 2
class Reloader(object):
RELOADING_CODE = 3
def start_process(self):
"""Spawn a new Python interpreter with the same arguments as this one,
but running the reloader thread.
"""
while True:
print("starting Tkinter application...")
args = [sys.executable] + sys.argv
new_environ = os.environ.copy()
new_environ['TKINTER_RUN_MAIN'] = 'true'
# a weird bug on windows. sometimes unicode strings end up in the
# environment and subprocess.call does not like this, encode them
# to latin1 and continue.
if os.name == 'nt' and PY2:
for key, value in new_environ.iteritems():
if isinstance(value, unicode):
new_environ[key] = value.encode('iso-8859-1')
exit_code = subprocess.call(args, env=new_environ,
close_fds=False)
if exit_code != self.RELOADING_CODE:
return exit_code
def trigger_reload(self):
self.log_reload()
sys.exit(self.RELOADING_CODE)
def log_reload(self):
print("reloading...")
def run_with_reloader(root, *hotkeys):
"""Run the given function in an independent python interpreter."""
import signal
signal.signal(signal.SIGTERM, lambda *args: sys.exit(0))
reloader = Reloader()
try:
if os.environ.get('TKINTER_RUN_MAIN') == 'true':
for hotkey in hotkeys:
root.bind_all(hotkey, lambda event: reloader.trigger_reload())
if os.name == 'nt':
root.wm_attributes("-topmost", 1)
root.after(1000, lambda:app.wm_attributes("-topmost", 0))
root.mainloop()
else:
sys.exit(reloader.start_process())
except KeyboardInterrupt:
pass
if __name__ == "__main__":
from tkinter import Tk, Label
class App(Tk):
def __init__(self):
Tk.__init__(self)
Label(self, text="Press Control+r to reload...").pack()
run_with_reloader(App(), "<Control-R>", "<Control-r>")
Diff to Previous Revision
--- revision 3 2016-10-24 16:43:21
+++ revision 4 2016-11-11 18:04:03
@@ -6,13 +6,14 @@
PY2 = sys.version_info[0] == 2
-class ReloaderLoop(object):
+class Reloader(object):
- def restart_with_reloader(self):
+ RELOADING_CODE = 3
+ def start_process(self):
"""Spawn a new Python interpreter with the same arguments as this one,
but running the reloader thread.
"""
- while 1:
+ while True:
print("starting Tkinter application...")
args = [sys.executable] + sys.argv
@@ -23,36 +24,40 @@
# environment and subprocess.call does not like this, encode them
# to latin1 and continue.
if os.name == 'nt' and PY2:
- for key, value in iteritems(new_environ):
- if isinstance(value, text_type):
+ for key, value in new_environ.iteritems():
+ if isinstance(value, unicode):
new_environ[key] = value.encode('iso-8859-1')
exit_code = subprocess.call(args, env=new_environ,
close_fds=False)
- if exit_code != 3:
+ if exit_code != self.RELOADING_CODE:
return exit_code
def trigger_reload(self):
self.log_reload()
- sys.exit(3)
+ sys.exit(self.RELOADING_CODE)
def log_reload(self):
print("reloading...")
-def run_with_reloader(App, *hotkeys):
+def run_with_reloader(root, *hotkeys):
"""Run the given function in an independent python interpreter."""
import signal
signal.signal(signal.SIGTERM, lambda *args: sys.exit(0))
- reloader = ReloaderLoop()
+ reloader = Reloader()
try:
if os.environ.get('TKINTER_RUN_MAIN') == 'true':
- app = App()
for hotkey in hotkeys:
- app.bind_all(hotkey, lambda event: reloader.trigger_reload())
- app.mainloop()
+ root.bind_all(hotkey, lambda event: reloader.trigger_reload())
+
+ if os.name == 'nt':
+ root.wm_attributes("-topmost", 1)
+ root.after(1000, lambda:app.wm_attributes("-topmost", 0))
+
+ root.mainloop()
else:
- sys.exit(reloader.restart_with_reloader())
+ sys.exit(reloader.start_process())
except KeyboardInterrupt:
pass
@@ -65,4 +70,4 @@
Label(self, text="Press Control+r to reload...").pack()
- run_with_reloader(App, "<Control-R>", "<Control-r>")
+ run_with_reloader(App(), "<Control-R>", "<Control-r>")