Dynamisches Laden Python-Quellcode
Frage
Ich spiele zur Zeit mit Flasche und ich kann nicht herausfinden, wie der Debug-Mechanismus funktioniert. Um genauer zu sein, wenn ich die Python-Datei speichern mit meiner Anwendung Ich brauche nicht den Server neu starten, wird es automatisch geladen werden, wenn ich einen Antrag stellen. Also meine Frage ist, wie weiß das laufende Programm wurde zu, dass Änderungen geändert und darauf zu reagieren?
Lösung
Kolben werden mit Werkzug zugrunde liegende run_with_reloader
Funktion (in serving.py
gefunden) ... die sich die restart_with_reloader
und reloader_loop
Funktion früher in der gleichen Datei erstellt wird.
run_with_reloader
Spawns eine andere Python-Prozess (Lauf Werkzug wieder mit allen den gleichen Argumenten, dass Sie zum ersten bestanden) und dieser neuen Prozesse verwendet das thread
Modul einen neuen Thread oder subprocess zum Laichen, die Ihre Server-Funktion ausgeführt wird. Es läuft dann die reloader_loop
und wartet.
reloader_loop
einfach eine Schleife durch alle Module, die importiert wurden und bekommt ihre letzten geänderten Daten. Dann in bestimmten Abständen (die standardmäßig auf 1 s) er alle die Dateien erneut überprüft, ob sie geändert worden sind. Wenn sie haben, ( Sklave ) die aktuell laufenden Werkzug Prozess beendet (beendet) mit einem Exit-Code 3. Sobald verlässt es das Gewinde oder subprocess es gestartet (die eigentlich die Arbeit tun) beendet auch. Der Master Prozess überprüft, ob der Exit-Code 3 war Wenn es ist, es laicht eine neue Sklave subprocess, so wie zuvor. Ansonsten ist es verläßt mit dem gleichen Exit-Code.
Hier ist der Code als Referenz:
def reloader_loop(extra_files=None, interval=1):
"""When this function is run from the main thread, it will force other
threads to exit when any modules currently loaded change.
Copyright notice. This function is based on the autoreload.py from
the CherryPy trac which originated from WSGIKit which is now dead.
:param extra_files: a list of additional files it should watch.
"""
def iter_module_files():
for module in sys.modules.values():
filename = getattr(module, '__file__', None)
if filename:
old = None
while not os.path.isfile(filename):
old = filename
filename = os.path.dirname(filename)
if filename == old:
break
else:
if filename[-4:] in ('.pyc', '.pyo'):
filename = filename[:-1]
yield filename
mtimes = {}
while 1:
for filename in chain(iter_module_files(), extra_files or ()):
try:
mtime = os.stat(filename).st_mtime
except OSError:
continue
old_time = mtimes.get(filename)
if old_time is None:
mtimes[filename] = mtime
continue
elif mtime > old_time:
_log('info', ' * Detected change in %r, reloading' % filename)
sys.exit(3)
time.sleep(interval)
def restart_with_reloader():
"""Spawn a new Python interpreter with the same arguments as this one,
but running the reloader thread.
"""
while 1:
_log('info', ' * Restarting with reloader...')
args = [sys.executable] + sys.argv
new_environ = os.environ.copy()
new_environ['WERKZEUG_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':
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)
if exit_code != 3:
return exit_code
def run_with_reloader(main_func, extra_files=None, interval=1):
"""Run the given function in an independent python interpreter."""
if os.environ.get('WERKZEUG_RUN_MAIN') == 'true':
thread.start_new_thread(main_func, ())
try:
reloader_loop(extra_files, interval)
except KeyboardInterrupt:
return
try:
sys.exit(restart_with_reloader())
except KeyboardInterrupt:
pass
Andere Tipps
Der eingebaute in reload()
Funktion kann dies für Sie tun. Es ist wahrscheinlich, dass diese Funktion ist hinter dem, was Flask antut Reload-Code (nach zu bemerken, dass es auf der Festplatte in irgendeiner Weise geändert hat).
Die Frage Wie entladen ich (Reload) ein Python-Modul? hat weitere Informationen zu diesem Thema.