【问题标题】:webapp2: automatically reload code changeswebapp2:自动重新加载代码更改
【发布时间】:2013-04-05 16:19:03
【问题描述】:

我正在使用 webapp2 进行 Web 开发。在我的开发环境中,如何让它自动重新加载代码更改?我正在使用httpserver.serve(app, host='127.0.0.1', port='8008'),但每次更改代码时,我都需要停止服务器并重新启动它。

我已将 webapp2 与 Google 提供的 Google App Engine 启动器一起使用,并且每次进行更改时都不需要重新启动它。他们是怎么做到的呢?他们是否监控文件系统更改并在模块发生更改时调用reload

【问题讨论】:

  • 这不是一个真正的 GAE 问题。您使用 webapp2 的事实几乎肯定与您的问题无关。
  • 根据您的建议,我删除了 GAE 标签。
  • 经过我的研究,我认为这与 GAE 用户相关,因此我将在 Django 标签中添加标签。

标签: python django google-app-engine webapp2


【解决方案1】:

粘贴有自己的自动重新加载功能(可能在提供原始答案时它不存在)..

app = webapp2.WSGIApplication(...)
def main():
    from paste import httpserver, reload
    reload.install()
    httpserver.serve(app, ...)

然后使用 Paste 提供的 shell 脚本启动你的服务器:

err=3
while test "$err" -eq 3 ; do
    python server.py
    err="$?"
done

现在,每次您在项目中编辑文件时,服务器都会自动重新加载。

参考文档:

【讨论】:

    【解决方案2】:

    原来谷歌提供的谷歌应用引擎启动器是借用了Django框架的自动重载代码,具体如下:https://github.com/django/django/blob/master/django/utils/autoreload.py

    搜索了 Stackoverflow,有一些相关的问题可以提供答案: How to automatically reload Django when files change? 这反过来又链接到这个模块,该模块能够检测和重新加载更改的代码:https://github.com/tjwalch/django-livereload-server

    如果有人想详细了解我是如何做到的。

    在我的启动器中:

    import autoreloader,thread
    thread.start_new_thread(autoreloader.reloader_thread, ())
    ...
    app = webapp2.WSGIApplication(...)
    def main():
        from paste import httpserver
        httpserver.serve(app, ...)
    

    autoreloader.py:

    import sys,os,time,logging
    
    RUN_RELOADER = True
    
    logger = logging.getLogger(__name__)
    
    whitelist = ['webapp2', 'paste', 'logging']
    
    # this code is from autoreloader
    _mtimes = {}
    _win = (sys.platform == "win32")
    _error_files = []
    _cached_modules = set()
    _cached_filenames = []
    
    
    def gen_filenames(only_new=False):
        global _cached_modules, _cached_filenames
        module_values = set(sys.modules.values())
        _cached_filenames = clean_files(_cached_filenames)
        if _cached_modules == module_values:
            # No changes in module list, short-circuit the function
            if only_new:
                return []
            else:
                return _cached_filenames + clean_files(_error_files)
    
        new_modules = module_values - _cached_modules
        new_filenames = clean_files(
            [filename.__file__ for filename in new_modules
             if hasattr(filename, '__file__')])
    
        _cached_modules = _cached_modules.union(new_modules)
        _cached_filenames += new_filenames
        if only_new:
            return new_filenames + clean_files(_error_files)
        else:
            return _cached_filenames + clean_files(_error_files)
    
    def clean_files(filelist):
        filenames = []
        for filename in filelist:
            if not filename:
                continue
            if filename.endswith(".pyc") or filename.endswith(".pyo"):
                filename = filename[:-1]
            if filename.endswith("$py.class"):
                filename = filename[:-9] + ".py"
            if os.path.exists(filename):
                filenames.append(filename)
        return filenames
    
    # this code is modified from autoreloader
    def check_code_changed():
        global _mtimes, _win
        for filename in gen_filenames():
            stat = os.stat(filename)
            mtime = stat.st_mtime
            if _win:
                mtime -= stat.st_ctime
            if filename not in _mtimes:
                _mtimes[filename] = mtime
                continue
            if mtime != _mtimes[filename]:
                _mtimes = {}
                try:
                    del _error_files[_error_files.index(filename)]
                except ValueError:
                    pass
                mname = filename.split('/')[-1].split('.')[0]
                logger.info('CHANGED %s, RELOADING %s' % (filename,mname))
                try:
                    reload(sys.modules[mname])
                except:
                    pass
    
        return False
    
    def reloader_thread():
        while RUN_RELOADER:
            check_code_changed()
            time.sleep(1)
    

    【讨论】:

    • 欢迎对我的自动加载器更改提出意见和建议!
    • 感谢您提供的出色示例。我不确定这是否在其他操作系统上效果更好,或者它是 python 版本问题。我看到一个关键错误,试图在带有 PY3 的 Windows 上使用它。我已经更新为使用线程和 importlib。 sys.modules 字典似乎不仅需要模块名称,而且还需要包=例如“include.lib.utils”而不是“utils”。
    • 这可能不适用于旧版本的 python,但对我来说适用于 python3。我没有通过 sys.modules 中的键访问模块,而是按文件过滤模块以匹配更改的文件:module = next(x for x in sys.modules.values() if hasattr(x,'__file__') and x.__file__ == filename) reload(module)
    猜你喜欢
    • 1970-01-01
    • 2011-10-10
    • 2014-06-17
    • 1970-01-01
    • 1970-01-01
    • 2021-07-11
    • 2013-04-27
    • 1970-01-01
    相关资源
    最近更新 更多