2013-01-06 38 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做到了。它工作,谢谢! –

相关问题