如果代碼被更改,我想重新啓動我的Python Web應用程序。但可能會有大量的文件可以更改,因爲進口模塊中的文件可能會更改...如何監視Python文件的更改?
如何從導入的包/模塊中獲取實際的文件名?
如何有效檢測修改後的Python文件?有沒有圖書館可以做到這一點?
如果代碼被更改,我想重新啓動我的Python Web應用程序。但可能會有大量的文件可以更改,因爲進口模塊中的文件可能會更改...如何監視Python文件的更改?
如何從導入的包/模塊中獲取實際的文件名?
如何有效檢測修改後的Python文件?有沒有圖書館可以做到這一點?
這是操作系統特定的。對於Linux,有一些inotify,例如見。 http://github.com/rvoicilas/inotify-tools/
gamin是另一種選擇,它比Linux特定的稍差。
我不確定如何在您的情況下實施「重新加載應用程序」操作;用內置的reload
重新加載更改後的模塊可能不會削減它。
但是,只要檢測是否有變化,以下將是一種方法來處理它。
__file__
屬性。sys.modules
中。sys.modules
走,並依次尋找各個模塊在磁盤上的變化有時__file__
指向.pyc
文件,而不是一個.py
文件,所以你可能要砍掉落後c。有時會存在.pyc
文件,但.py
不存在;在一個強大的系統中,你必須考慮到這一點。
的代碼概念證明要做到這一點(不健壯):
_module_timestamps = {}
_checking = False
def run_checker():
global _checking
_checking = True
while _checking:
for name, module in sys.modules.iteritems():
if hasattr(module, '__file__'):
filename = module.__file__
if filename.endswith('.pyc'):
filename = filename[:-1]
mtime = os.stat(filename).st_mtime
if name not in _module_timestamps:
_module_timestamps[name] = mtime
else:
if mtime > _module_timestamps[name]:
do_reload(name)
else:
'module %r has no file attribute' % (name,)
time.sleep(1)
def do_reload(modname):
print 'I would reload now, because of %r' % (modname,)
check_thread = threading.Thread(target=run_checker)
check_thread.daemon = True
check_thread.start()
try:
while 1:
time.sleep(0.1)
except KeyboardInterrupt:
print '\nexiting...'
無恥的插頭。還有http://github.com/gorakhargosh/watchdog,我正在努力做到這一點。
HTH。
而我剛剛用Watchdog寫了一個可愛的小腳本:http://www.zolomon.com/wp /?p = 382 - 這是我說的一種真正的魅力! – Zolomon 2010-12-13 22:44:15
下面是如何使用pyinotify(例如,在Linux上)實現這個示例。
from importlib import import_module
class RestartingLauncher:
def __init__(self, module_name, start_function, stop_function, path="."):
self._module_name = module_name
self._filename = '%s.py' % module_name
self._start_function = start_function
self._stop_function = stop_function
self._path = path
self._setup()
def _setup(self):
import pyinotify
self._wm = pyinotify.WatchManager()
self._notifier = pyinotify.ThreadedNotifier(
self._wm, self._on_file_modified)
self._notifier.start()
# We monitor the directory (instead of just the file) because
# otherwise inotify gets confused by editors such a Vim.
flags = pyinotify.EventsCodes.OP_FLAGS['IN_MODIFY']
wdd = self._wm.add_watch(self._path, flags)
def _on_file_modified(self, event):
if event.name == self._filename:
print "File modification detected. Restarting application..."
self._reload_request = True
getattr(self._module, self._stop_function)()
def run(self):
self._module = import_module(self._module_name)
self._reload_request = True
while self._reload_request:
self._reload_request = False
reload(self._module)
getattr(self._module, self._start_function)()
print 'Bye!'
self._notifier.stop()
def launch_app(module_name, start_func, stop_func):
try:
import pyinotify
except ImportError:
print 'Pyinotify not found. Launching app anyway...'
m = import_module(self._module_name)
getattr(m, start_func)()
else:
RestartingLauncher(module_name, start_func, stop_func).run()
if __name__ == '__main__':
launch_app('example', 'main', 'force_exit')
在launch_app呼叫的參數是文件名(沒有「py」爲),該函數開始執行,並且以某種方式停止的執行的功能。
下面是一個「應用程序」,可能是(重新)的一個愚蠢的例子使用前面的代碼發佈:
run = True
def main():
print 'in...'
while run: pass
print 'out'
def force_exit():
global run
run = False
在典型應用中,你會想利用這一點,你可能有某種主循環。這裏有一個更真實例如,能說會道/ GTK +基礎的應用:
from gi.repository import GLib
GLib.threads_init()
loop = GLib.MainLoop()
def main():
print "running..."
loop.run()
def force_exit():
print "stopping..."
loop.quit()
同樣的概念也適用於大多數其他循環(雜波,Qt的,等等)。
監控幾個代碼文件(即。作爲應用程序一部分的所有文件)和錯誤恢復能力(例如,打印異常並在空閒循環中等待,直到代碼被修復,然後再次啓動)作爲練習留給讀者:)。
注意:此答案中的所有代碼均在ISC許可證下發布(除知識共享之外)。
有人已經指出你Django(http://stackoverflow.com/questions/3862871),它有代碼來做到這一點。 – 2010-10-05 11:38:52
感謝您提及Django機制。這是這個問題的觸發器(但不是答案)。 – deamon 2010-10-05 11:47:08
不,Django機制*就是答案。在Django中,您提到的代碼就在那裏。 – 2010-10-05 20:55:27