如何调试ImportError(sys.path正确的情况下)

2 投票
1 回答
926 浏览
提问于 2025-04-19 13:21

我通过CherryPy来提供django页面。当CherryPy在前台启动时,一切都正常。但是,当我使用

Daemonizer(cherrypy.engine).subscribe()

将CherryPy转为后台运行时,我遇到了一个导入错误(ImportError)。在这两种情况下(后台和前台),sys.path完全相同的。我该如何调试这个问题,除了sys.path之外,还有什么其他因素会影响Python的导入?

附加信息

错误追踪信息:

[02/Sep/2014:03:08:46] ENGINE ImproperlyConfigured('Error importing module plinth.modules.first_boot.middleware: "No module named middleware"',)
Traceback (most recent call last):
  File "/usr/lib/python2.7/dist-packages/cherrypy/wsgiserver/wsgiserver2.py", line 1353, in communicate
    req.respond()
  File "/usr/lib/python2.7/dist-packages/cherrypy/wsgiserver/wsgiserver2.py", line 868, in respond
    self.server.gateway(self).respond()
  File "/usr/lib/python2.7/dist-packages/cherrypy/wsgiserver/wsgiserver2.py", line 2267, in respond
    response = self.req.server.wsgi_app(self.env, self.start_response)
  File "/usr/lib/python2.7/dist-packages/cherrypy/_cptree.py", line 299, in call
    return app(environ, start_response)
  File "/usr/lib/python2.7/dist-packages/django/core/handlers/wsgi.py", line 187, in call
    self.load_middleware()
  File "/usr/lib/python2.7/dist-packages/django/core/handlers/base.py", line 45, in load_middleware
    mw_class = import_by_path(middleware_path)
  File "/usr/lib/python2.7/dist-packages/django/utils/module_loading.py", line 26, in import_by_path
    sys.exc_info()[2])
  File "/usr/lib/python2.7/dist-packages/django/utils/module_loading.py", line 21, in import_by_path
    module = import_module(module_path)
  File "/usr/lib/python2.7/dist-packages/django/utils/importlib.py", line 40, in import_module
    import(name)
ImproperlyConfigured: Error importing module plinth.modules.first_boot.middleware: "No module named middleware"
  • 要导入的文件:/home/fbx/code/plinth/plinth/modules/first_boot/middleware.py
  • 相关的sys.path条目(在发生导入错误时也存在):'/home/fbx/code/plinth'
  • 导入错误发生在django的import_module函数中,具体位置在https://github.com/django/django/blob/master/django/utils/importlib.py
  • 传给import_module的参数name"plinth.modules.first_boot.middleware"
  • django的MIDDLEWARE_CLASSES设置是'plinth.modules.first_boot.middleware.FirstBootMiddleware'

还有一点说明:
我在目录/home/fbx/code/plinth中使用python -m plinth来运行后台服务器。
当我用/usr/bin/python /home/fbx/code/plinth/plinth/__main__.py启动后台服务器时,一切都正常!在这种情况下,sys.path多了一个条目:/home/fbx/code/plinth/plinth。但是在以python -m plinth运行时,手动添加这个路径并没有解决导入错误。

我正在运行的代码在这里:https://github.com/freedombox/Plinth/tree/0b5af376102f4210395c15b2366b96a6e56fefb2

更新
感谢@cyraxjoe,os.chdir()__init__.py中缺少模块的组合导致了这个问题。对我来说,这种行为是意外的,我没有找到很多有用的信息或文档,所以我建立了一个github仓库来更方便地展示这个问题:https://github.com/fonfon/ImportError-demo

1 个回答

2

这只是一个理论,但可能是原因所在。

考虑以下几点:

  1. Daemonizer 插件会把目录切换到根目录,代码是 os.chdir('/')
  2. plinth.modules.first_boot 是明确导入了 first_boot,而不是包的 __init__.py 中的中间件。

可能在 Daemonizer 插件切换目录之前,模块 plinth.modules.first_boot 已经被导入,但没有中间件。因此,当 Django 尝试动态导入这个模块时,它只能在导入缓存中找到模块,但找不到中间件,因为路径是相对的。当 Daemonizer 插件切换目录后,中间件就变得无法访问了。

可以尝试在包的 __init__ 中导入中间件模块。

简单来说,就是在 __init__ 中添加一行 from . import middleware

撰写回答