2010-10-05 80 views
4

如果代碼被更改,我想重新啓動我的Python Web應用程序。但可能會有大量的文件可以更改,因爲進口模塊中的文件可能會更改...如何監視Python文件的更改?

如何從導入的包/模塊中獲取實際的文件名?

如何有效檢測修改後的Python文件?有沒有圖書館可以做到這一點?

+0

有人已經指出你Django(http://stackoverflow.com/questions/3862871),它有代碼來做到這一點。 – 2010-10-05 11:38:52

+0

感謝您提及Django機制。這是這個問題的觸發器(但不是答案)。 – deamon 2010-10-05 11:47:08

+2

不,Django機制*就是答案。在Django中,您提到的代碼就在那裏。 – 2010-10-05 20:55:27

回答

1

gamin是另一種選擇,它比Linux特定的稍差。

1

我不確定如何在您的情況下實施「重新加載應用程序」操作;用內置的reload重新加載更改後的模塊可能不會削減它。

但是,只要檢測是否有變化,以下將是一種方法來處理它。

  • 大多數python模塊具有__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...' 
6

無恥的插頭。還有http://github.com/gorakhargosh/watchdog,我正在努力做到這一點。

HTH。

+0

而我剛剛用Watchdog寫了一個可愛的小腳本:http://www.zolomon.com/wp /?p = 382 - 這是我說的一種真正的魅力! – Zolomon 2010-12-13 22:44:15

1

下面是如何使用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許可證下發布(除知識共享之外)。