python - 仅在部署期间自定义模块导入错误
问题描述
我有一个非常简单的 Flask 应用程序,结构如下:
Dockerfile
requirements.txt
caller --> app.py
--> user.py
--> templates
--> static
我正在初始化并运行我的Flask
应用程序app.py
:
应用程序.py
from twilio.rest import Client
import sys, os
...
from user import User, Anonymous
app = Flask(__name__)
...
def create_app():
app.run(debug=True, host='0.0.0.0', port=5005)
当我在本地运行我的应用程序时,它工作正常,但是当我尝试制作图像并运行图像时,它给了我一个错误:
File "/caller/caller/app.py", line 11, in <module>
from user import User, Anonymous
ModuleNotFoundError: No module named 'user'
dockerfile
FROM python:3.7.5-slim-buster
ENV INSTALL_PATH /caller
RUN mkdir -p $INSTALL_PATH
WORKDIR $INSTALL_PATH
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
RUN pip install flask_login
COPY . .
CMD gunicorn -b 0.0.0.0:8000 --access-logfile - "caller.app"
用户.py
import uuid
class User():
...
class Anonymous():
...
你知道我该如何解决这个问题吗?这也是我的第一次Dockerfile
,这可能是问题所在。构建和运行我正在做的图像docker build -t foo . && docker run -it foo
解决方案
Python 的导入系统通过在解释器定义的路径列表中搜索模块来工作。您可以通过检查来查看此列表sys.path
。如果您查看文档,第一项path[0]
是包含您从中调用解释器的脚本的目录。
您正在通过从您在 Dockerfile 中设置gunicorn
的工作目录运行来调用 Python。/caller
这就是 Pythonpath[0]
用于导入系统的基本目录。因此,当该行from user import User, Anonymous
被击中时,Python 会尝试从 中导入它/caller
,其中包含您的 Dockerfile、requirements.txt 和您复制的 /caller/ 目录(通过COPY . .
在您的 Dockerfile 中)。所以包位于/caller/caller/user.py
而不是/caller/user.py
......导入系统没有看到它,你得到你的错误。
2种方法可以解决:
1.更改您的代码以使用相对导入。这将告诉 Python 导入系统在同一目录中查找:
from .user import User, Anonymous
2.您也可以通过更改 Dockerfile 将其内容复制/caller
到容器中的/caller
工作目录来修复它,而不是通过递归COPY . .
调用复制所有内容。
替换COPY . .
为COPY caller .
并更新gunicorn
以调用只是app
代替caller.app
(因为它不再嵌套在第二个调用者目录中)。
现在,user.py 将位于/caller/user.py
您的容器中,Python 导入系统会在检查时找到它sys.path[0]
推荐阅读
- angular - Angular 6 - rxjs 管道不适用于 valueChanges
- python - 根据列变化选择行
- sql - ON CONSTRAINT ON CONFLICT ON CONSTRAINT 未检测到 postgresql 中的唯一冲突
- mongodb - 不同数量的返回结果在mongo中的执行时间是相同的
- javascript - json.parse 第一次运行两次字符串,第二次运行对象为什么?
- html - 如何创建视频的缩略图
- c# - 字符串的实际长度
- kotlin - Kotlin:使用另一个数组的内部字段创建一个数组
- mongodb - 嵌入式阵列投影的单元素
- java-8 - 是否可以使用流将此方法转换为 java 8?如果是怎么办?