2013-01-06 90 views
0

我有一個IRC bot,我正在解析數據,但爲了刷新它,我必須重新加載插件。我注意到它可以工作,一旦我改變了文件上的某些內容或者只是打開並再次保存,一旦它重新加載它得到正確的信息。這是重新加載插件文件:每分鐘重新加載一次python文件

reload.py

import collections 
import glob 
import os 
import re 
import sys 
import traceback 


if 'mtimes' not in globals(): 
    mtimes = {} 

if 'lastfiles' not in globals(): 
    lastfiles = set() 


def make_signature(f): 
    return f.func_code.co_filename, f.func_name, f.func_code.co_firstlineno 


def format_plug(plug, kind='', lpad=0, width=40): 
    out = ' ' * lpad + '%s:%s:%s' % make_signature(plug[0]) 
    if kind == 'command': 
     out += ' ' * (50 - len(out)) + plug[1]['name'] 

    if kind == 'event': 
     out += ' ' * (50 - len(out)) + ', '.join(plug[1]['events']) 

    if kind == 'regex': 
     out += ' ' * (50 - len(out)) + plug[1]['regex'] 

    return out 


def reload(init=False): 
    changed = False 

    if init: 
     bot.plugs = collections.defaultdict(list) 
     bot.threads = {} 

    core_fileset = set(glob.glob(os.path.join("core", "*.py"))) 

    for filename in core_fileset: 
     mtime = os.stat(filename).st_mtime 
     if mtime != mtimes.get(filename): 
      mtimes[filename] = mtime 

      changed = True 

      try: 
       eval(compile(open(filename, 'U').read(), filename, 'exec'), 
         globals()) 
      except Exception: 
       traceback.print_exc() 
       if init:  # stop if there's an error (syntax?) in a core 
        sys.exit() # script on startup 
       continue 

      if filename == os.path.join('core', 'reload.py'): 
       reload(init=init) 
       return 

    fileset = set(glob.glob(os.path.join('plugins', '*.py'))) 

    # remove deleted/moved plugins 
    for name, data in bot.plugs.iteritems(): 
     bot.plugs[name] = [x for x in data if x[0]._filename in fileset] 

    for filename in list(mtimes): 
     if filename not in fileset and filename not in core_fileset: 
      mtimes.pop(filename) 

    for func, handler in list(bot.threads.iteritems()): 
     if func._filename not in fileset: 
      handler.stop() 
      del bot.threads[func] 

    # compile new plugins 
    for filename in fileset: 
     mtime = os.stat(filename).st_mtime 
     if mtime != mtimes.get(filename): 
      mtimes[filename] = mtime 

      changed = True 

      try: 
       code = compile(open(filename, 'U').read(), filename, 'exec') 
       namespace = {} 
       eval(code, namespace) 
      except Exception: 
       traceback.print_exc() 
       continue 

      # remove plugins already loaded from this filename 
      for name, data in bot.plugs.iteritems(): 
       bot.plugs[name] = [x for x in data 
            if x[0]._filename != filename] 

      for func, handler in list(bot.threads.iteritems()): 
       if func._filename == filename: 
        handler.stop() 
        del bot.threads[func] 

      for obj in namespace.itervalues(): 
       if hasattr(obj, '_hook'): # check for magic 
        if obj._thread: 
         bot.threads[obj] = Handler(obj) 

        for type, data in obj._hook: 
         bot.plugs[type] += [data] 

         if not init: 
          print '### new plugin (type: %s) loaded:' % \ 
            type, format_plug(data) 

    if changed: 
     bot.commands = {} 
     for plug in bot.plugs['command']: 
      name = plug[1]['name'].lower() 
      if not re.match(r'^\w+$', name): 
       print '### ERROR: invalid command name "%s" (%s)' % (name, 
        format_plug(plug)) 
       continue 
      if name in bot.commands: 
       print "### ERROR: command '%s' already registered (%s, %s)" % \ 
        (name, format_plug(bot.commands[name]), 
        format_plug(plug)) 
       continue 
      bot.commands[name] = plug 

     bot.events = collections.defaultdict(list) 
     for func, args in bot.plugs['event']: 
      for event in args['events']: 
       bot.events[event].append((func, args)) 

    if init: 
     print ' plugin listing:' 

     if bot.commands: 
      # hack to make commands with multiple aliases 
      # print nicely 

      print ' command:' 
      commands = collections.defaultdict(list) 

      for name, (func, args) in bot.commands.iteritems(): 
       commands[make_signature(func)].append(name) 

      for sig, names in sorted(commands.iteritems()): 
       names.sort(key=lambda x: (-len(x), x)) # long names first 
       out = ' ' * 6 + '%s:%s:%s' % sig 
       out += ' ' * (50 - len(out)) + ', '.join(names) 
       print out 

     for kind, plugs in sorted(bot.plugs.iteritems()): 
      if kind == 'command': 
       continue 
      print ' %s:' % kind 
      for plug in plugs: 
       print format_plug(plug, kind=kind, lpad=6) 
     print 

比方說,我想重裝一次一分鐘被稱爲flightsinfo.py插件。我怎樣才能做到這一點 ?

+2

相反重裝Python腳本,你真的應該弄清楚__why__它不是在它被再次調用的函數之後的工作,並修復來代替。 –

+0

不,功能正常,我想重新加載文件以刷新數據。 –

+0

重新加載Python模塊以刷新*數據*是可怕的設計... –

回答

1

重要的代碼看起來像它在這裏:

mtime = os.stat(filename).st_mtime 
if mtime != mtimes.get(filename): 
    mtimes[filename] = mtime 

    changed = True 

    try: 
     code = compile(open(filename, 'U').read(), filename, 'exec') 
     namespace = {} 
     eval(code, namespace) 
    except Exception: 
     traceback.print_exc() 
     continue 

如果該文件的修改時間已經改變(例如,當您打開和保存),然後編譯/ EXEC功能調用。

有一對夫婦的辦法來解決這個問題,這取決於您的情況:

  1. 定期更新文件的修改時間。例如在linux上,你可以每分鐘運行一次cron作業到touch /path/to/flightsinfo.py
  2. reload.py重構的功能重新加載到一個函數,並從你的python調用。

    def reload(filename): 
        try: 
         code = compile(open(filename, 'U').read(), filename, 'exec') 
         namespace = {} 
         eval(code, namespace) 
         ... 
    
+0

是的,我想每分鐘重新加載一次,但沒有插件,只有這一個。這裏是我卡住的地方。 –

+1

當然,答案有什麼問題。 – cmh

+0

哦,我通過方法2做到了。它工作,謝謝! –

相關問題