【问题标题】:ModuleNotFoundError when running imported Flask app运行导入的 Flask 应用程序时出现 ModuleNotFoundError
【发布时间】:2018-12-07 10:23:53
【问题描述】:

我有一个具有以下布局的 python 模块:

 foo
  |  __init__.py
  |  __main__.py
  |  bar.py

__init__.py 为空。

foo/bar.py的内容:

from flask import Flask
app = Flask(__name__)
def baz(): pass

运行python3 -m foo 时,我得到令人困惑的结果。

foo/__main__.py的内容

# Results in a ModuleNotFoundError: No module named 'foo'
from foo.bar import app
app.run()

# Raises no error and correctly prints the type
from foo.bar import app
print(type(app))

# Also runs without an error
from foo.bar import baz
baz()

为什么可以从这个模块导入和执行一个函数,但是当尝试对一个烧瓶应用程序做同样的事情时,它会导致ModuleNotFoundError? 我只是看不出这有什么意义。

编辑:

即使使用此代码,错误仍然存​​在:

from foo.bar import app

print(type(app))
app.run()

输出:

<class 'flask.app.Flask'>
 * Serving Flask app "foo.bar" (lazy loading)
 * Environment: production
   WARNING: Do not use the development server in a production environment.
   Use a production WSGI server instead.
 * Debug mode: on
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat
Traceback (most recent call last):
  File "/home/user/projects/ftest/foo/__main__.py", line 1, in <module>
    from foo.bar import app
ModuleNotFoundError: No module named 'foo'

所以,显然模块可以被导入,因为type(app) 工作得很好并且烧瓶确实启动了。似乎烧瓶重新加载并以某种方式处理导入。

编辑 2:

我关闭了调试模式,它工作得很好。 仅当您设置export FLASK_DEBUG=True 或通过app.config["DEBUG"] = True 显式启用调试时才会出现此错误

【问题讨论】:

  • 我重新创建了您的项目,但没有看到错误,在您的代码中也看不到任何原因。您确定这是您使用的代码和布局吗?您的__init__.py 是空的还是包含代码?你从哪里运行命令?
  • re “为什么可能”:Flask 对这个论点做了一些特别的事情;例如,如果我执行app = Flask("qux.baz"),我会失败,因为模块qux 不存在。所以我的猜测是,要么你传递了一些奇怪的东西,要么可能是一些乱七八糟的东西,比如你剩下的 __pycache__ 不知何故被一个坏名字锁定了......
  • @matejcik:__init__.py 为空,我更新了问题以添加此信息。我正在运行上面目录中的代码。我清理了__pycache__,但没有帮助。我根本没有做任何奇怪的事情,因为帖子中的内容实际上是模块中的所有代码。
  • 当您执行第一个__main__.py 代码时,您确定您在正确的目录中吗? (也许在顶部添加import os;print(os.getcwd()) 以检查)
  • @PRMoureu 都是从同一个目录执行的。

标签: python-3.x flask module


【解决方案1】:

原来这是 werkzeug 中的一个错误。 如果 werkzeug 的重新加载器被禁用,代码将按预期工作。

如何重现行为

目录结构:

 foo
  |  __init__.py
  |  __main__.py

__init__.py的内容:

from flask import Flask
app = Flask(__name__)
app.config["DEBUG"] = True

__main__.py的内容:

from foo import app
app.run()

如果我们运行它:

$python3 -m foo
 * Serving Flask app "foo" (lazy loading)
 * Environment: development
 * Debug mode: on
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat
Traceback (most recent call last):
  File "/home/user/projects/ftest/foo/__main__.py", line 1, in <module>
    from foo import app
ModuleNotFoundError: No module named 'foo'

如果我们改变__main__.py:

from foo import app
app.run(use_reloader=False)

一切正常。

发生了什么

问题出在werkzeug._reloader.ReloaderLoop.restart_with_reloader。它使用werkzeug._reloader._get_args_for_reloading 提供的参数调用子进程,但通过-m 开关执行包时,此函数的行为与预期不同。

def _get_args_for_reloading():
    """Returns the executable. This contains a workaround for windows
    if the executable is incorrectly reported to not have the .exe
    extension which can cause bugs on reloading.
    """
    rv = [sys.executable]
    py_script = sys.argv[0]
    if os.name == 'nt' and not os.path.exists(py_script) and \
       os.path.exists(py_script + '.exe'):
        py_script += '.exe'
    if os.path.splitext(rv[0])[1] == '.exe' and os.path.splitext(py_script)[1] == '.exe':
        rv.pop(0)
    rv.append(py_script)
    rv.extend(sys.argv[1:])
    return rv

在我们的例子中,它返回['/usr/local/bin/python3.7', '/home/user/projects/ftest/foo/__main__.py']。这是因为 sys.argv[0] 设置为模块文件的完整路径,但它应该返回 ['/usr/local/bin/python3.7', '-m', 'foo']` (至少从我的理解它应该并且它以这种方式工作)。

我不知道如何解决此问题,或者是否需要解决。对我来说,我是唯一遇到这个问题的人,这似乎很奇怪,因为对我来说这似乎不是什么极端情况。

【讨论】:

    【解决方案2】:

    在 app.run() 之前添加以下行可以解决 werkzeug reloader 错误:

    os.environ['PYTHONPATH'] = os.getcwd()
    

    感谢@bootc 的提示! https://github.com/pallets/flask/issues/1246

    【讨论】:

      【解决方案3】:

      您是否尝试过 main.py 文件中的 from foo import app?

      【讨论】:

      • 我做到了,在有关重现行为的章节中查看我的解决方案。
      • 你设置了 PYTHONPATH 吗?
      • 更多信息在这里,看起来像你的问题? github.com/pallets/flask/issues/1246
      • 这确实是同一个问题,但似乎 werkzeug 的人也没有看到任何合理的方法来解决这个问题。但至少我现在有一个解决方法。谢谢!
      猜你喜欢
      • 1970-01-01
      • 2021-07-20
      • 2016-05-05
      • 1970-01-01
      • 2021-12-10
      • 2021-05-10
      • 2021-05-09
      • 1970-01-01
      • 2023-03-15
      相关资源
      最近更新 更多