我有烧瓶网络应用程序,其结构如下:
/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 import msapi,dataformater
来自..db_client导入db_connection
def run_daemon():
......
......
......
如果名称 ==" 主要":
run_daemon()
因此,当我尝试运行此daemon1.py时,它会抛出ValueError:在非包中尝试相对导入
请建议正确的导入方法以及构建这些守护进程。
提前致谢。
答案 0 :(得分:0)
我遇到了与运行Flask和Celery的应用程序完全相同的问题。我花了太多时间谷歌搜索应该是一个简单的答案。唉,没有。
我不喜欢“python -m”语法,因为在运行代码中调用函数并不是非常实用。由于我看起来很小的大脑,我无法掌握那里的任何其他答案。
所以...错误的方式和漫长的道路。他们两个都有效(对我来说),我相信我会从社区中得到一个抨击。
错误的方式
您可以使用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变量。您可以通过运行来查看现在的内容:
sys.path
正如预期的那样,您可能看不到任何模块。这意味着,当您调用common
模块时,Python无法弄清楚您想要的内容。为了添加路径,您需要弄清楚目录结构。您需要将此动态设置为更改目录。
值得注意的是,每次运行模块时都需要运行。我不确定你的cron
模块是什么,但就我而言,它是Celery。所以,这只有在我启动工人和最初的crontabs时才会运行。
这是我扔在一起的黑客攻击(我确信有更简洁的方法):
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”的目录。您的顶级“应用”是我的“project_name”。对于下一步,我们假设您已将其更改为“project_name”。
3)现在,您可以将每个模块的路径附加到PATH变量:
sys.path.append(parrent_dir + '/app')
现在,如果再次运行sys.path
,您应该会看到/app
的路径。
总结:确保所有__init__
都有导入,确定要导入的模块的路径,将路径附加到PATH变量。
我希望有所帮助。
答案 1 :(得分:0)
@greenbergé感谢您的解决方案。我试过,但没有为我工作。
所以为了让事情有效,我已经改变了我的代码。除了在daemon1.py的main中调用run_daemon()之外,我直接调用了函数run_daemon()。
来自app.cron.daemon1的python -m'导入run_daemon(); run_daemon()'
因为这不是问题的确切解决方案,但事情对我有用。