ValueError: Attempted relative import in non-package for running standalone scripts In Flask Web App
ValueError: Attempted relative import in non-package for running standalone scripts In Flask Web App
我有一个flask web app,它的结构如下:
/app
/__init__.py
/wsgi.py
/app
/__init__.py
/views.py
/models.py
/method.py
/common.py
/db_client.py
/amqp_client.py
/cron
/__init.py__
/daemon1.py
/daemon2.py
/static/
/main.css
/templates/
/base.html
/scripts
/nginx
/supervisor
/Dockerfile
/docker-compose.yml
在 app/app/cron 中,我编写了我想在 docker 之外调用的独立守护进程。例如
python daemon1.py
daemon1.py代码
来自 ..common 进口统计数据
从 ..method 导入 msapi,dataformater
从 ..db_client 导入 db_connection
def run_daemon():
......
......
......
if name ==main":
run_daemon()
所以当我尝试 运行 这个 daemon1.py 它抛出 ValueError: Attempted relative import in non-package
请建议导入和构建这些守护进程的正确方法。
提前致谢。
我 运行 遇到了与 运行ning Flask 和 Celery 应用程序完全相同的问题。我花了太多时间在谷歌上搜索应该是一个简单的答案。唉,没有。
我不喜欢 "python -m" 语法,因为这对于在 运行ning 代码中调用函数不是很实用。由于我的大脑看似很小,我无法理解其他任何答案。
所以……走错了路,走的路很远。他们都(为我)工作,我相信我会受到社区的抨击。
错误的方式
您可以像这样使用 imp
包直接调用模块:
import imp
common = imp.load_source('common', os.path.dirname(os.path.abspath('__file__')) + '/common.py')
result = common.stats() #not sure how you call stats, but you hopefully get the idea
我快速搜索了表明这是禁忌的参考资料,但我找不到它们...抱歉。
漫漫长路
此方法涉及临时将每个模块附加到您的 PATH。这对我的 Docker 部署很有效,无论容器的目录结构如何,它都能很好地工作。以下是步骤:
1) 您必须从 __init__
文件的父目录中导入相关模块。这确实是 __init__
的全部要点 - 允许其包中的模块可调用。因此,在您的情况下,cron/__init__
应包含:
from . import common
看起来您的目录没有比这更高的目录,但是您也可以对任何其他升级的包执行相同的操作。
2) 现在您需要将模块的路径附加到 PATH 变量。您现在可以通过 运行ning:
查看其中的内容
sys.path
如预期的那样,您可能不会在其中看到任何模块。这意味着,当您调用 common
模块时,Python 无法弄清楚您想要什么。为了添加路径,您需要弄清楚目录结构。您将希望使其动态化以适应不断变化的目录。
值得注意的是,每次您的模块 运行 时都需要 运行。我不确定您的 cron
模块是什么,但在我的例子中是 Celery。所以,这 运行 仅在我启动工作人员和初始 crontab 时才会出现。
这是我拼凑的技巧(我相信有更简洁的方法):
curr_path = os.getcwd() #current path where cron is running
parrent_path = os.path.abspath(os.path.join(os.getcwd(), '..')) #the parent directory path
parrent_dir = os.path.basename(os.path.abspath(parrent_path)) #the parent directory name
while parrent_dir <> 'project_name': #loop until you get to the top directory - should be the project name
parrent_path = os.path.abspath(os.path.join(par_path, '..'))
parrent_dir = os.path.basename(os.path.abspath(parrent_path))
对于您的情况,这可能是一个挑战,因为您有两个名为 'app' 的目录。你的最高级别 'app' 是我的 'project_name'。对于下一步,我们假设您已将其更改为 'project_name'.
3) 现在您可以将每个模块的路径附加到 PATH 变量中:
sys.path.append(parrent_dir + '/app')
现在,如果您再次 运行 sys.path
,您应该会在其中看到 /app
的路径。
总结:确保所有 __init__
都有导入,确定要导入的模块的路径,将路径附加到 PATH 变量。
希望对您有所帮助。
@greenbergé 感谢您的解决方案。我试过了,但没有为我工作。
因此,为了让事情正常进行,我稍微更改了我的代码。除了在 daemon1.py 的 main 中调用 run_daemon() 外,我还直接调用了函数 run_daemon() 。
python-m'from app.cron.daemon1 import run_daemon(); run_daemon()'
因为它不是问题的确切解决方案,但对我有用。
我有一个flask web app,它的结构如下:
/app
/__init__.py
/wsgi.py
/app
/__init__.py
/views.py
/models.py
/method.py
/common.py
/db_client.py
/amqp_client.py
/cron
/__init.py__
/daemon1.py
/daemon2.py
/static/
/main.css
/templates/
/base.html
/scripts
/nginx
/supervisor
/Dockerfile
/docker-compose.yml
在 app/app/cron 中,我编写了我想在 docker 之外调用的独立守护进程。例如 python daemon1.py
daemon1.py代码来自 ..common 进口统计数据
从 ..method 导入 msapi,dataformater
从 ..db_client 导入 db_connection
def run_daemon():
......
......
......
if name ==main":
run_daemon()
所以当我尝试 运行 这个 daemon1.py 它抛出 ValueError: Attempted relative import in non-package
请建议导入和构建这些守护进程的正确方法。
提前致谢。
我 运行 遇到了与 运行ning Flask 和 Celery 应用程序完全相同的问题。我花了太多时间在谷歌上搜索应该是一个简单的答案。唉,没有。
我不喜欢 "python -m" 语法,因为这对于在 运行ning 代码中调用函数不是很实用。由于我的大脑看似很小,我无法理解其他任何答案。
所以……走错了路,走的路很远。他们都(为我)工作,我相信我会受到社区的抨击。
错误的方式
您可以像这样使用 imp
包直接调用模块:
import imp
common = imp.load_source('common', os.path.dirname(os.path.abspath('__file__')) + '/common.py')
result = common.stats() #not sure how you call stats, but you hopefully get the idea
我快速搜索了表明这是禁忌的参考资料,但我找不到它们...抱歉。
漫漫长路
此方法涉及临时将每个模块附加到您的 PATH。这对我的 Docker 部署很有效,无论容器的目录结构如何,它都能很好地工作。以下是步骤:
1) 您必须从 __init__
文件的父目录中导入相关模块。这确实是 __init__
的全部要点 - 允许其包中的模块可调用。因此,在您的情况下,cron/__init__
应包含:
from . import common
看起来您的目录没有比这更高的目录,但是您也可以对任何其他升级的包执行相同的操作。
2) 现在您需要将模块的路径附加到 PATH 变量。您现在可以通过 运行ning:
查看其中的内容sys.path
如预期的那样,您可能不会在其中看到任何模块。这意味着,当您调用 common
模块时,Python 无法弄清楚您想要什么。为了添加路径,您需要弄清楚目录结构。您将希望使其动态化以适应不断变化的目录。
值得注意的是,每次您的模块 运行 时都需要 运行。我不确定您的 cron
模块是什么,但在我的例子中是 Celery。所以,这 运行 仅在我启动工作人员和初始 crontab 时才会出现。
这是我拼凑的技巧(我相信有更简洁的方法):
curr_path = os.getcwd() #current path where cron is running
parrent_path = os.path.abspath(os.path.join(os.getcwd(), '..')) #the parent directory path
parrent_dir = os.path.basename(os.path.abspath(parrent_path)) #the parent directory name
while parrent_dir <> 'project_name': #loop until you get to the top directory - should be the project name
parrent_path = os.path.abspath(os.path.join(par_path, '..'))
parrent_dir = os.path.basename(os.path.abspath(parrent_path))
对于您的情况,这可能是一个挑战,因为您有两个名为 'app' 的目录。你的最高级别 'app' 是我的 'project_name'。对于下一步,我们假设您已将其更改为 'project_name'.
3) 现在您可以将每个模块的路径附加到 PATH 变量中:
sys.path.append(parrent_dir + '/app')
现在,如果您再次 运行 sys.path
,您应该会在其中看到 /app
的路径。
总结:确保所有 __init__
都有导入,确定要导入的模块的路径,将路径附加到 PATH 变量。
希望对您有所帮助。
@greenbergé 感谢您的解决方案。我试过了,但没有为我工作。
因此,为了让事情正常进行,我稍微更改了我的代码。除了在 daemon1.py 的 main 中调用 run_daemon() 外,我还直接调用了函数 run_daemon() 。
python-m'from app.cron.daemon1 import run_daemon(); run_daemon()'
因为它不是问题的确切解决方案,但对我有用。