2017-09-13 40 views
1

我烧瓶Web App和它的结构如下:ValueError异常:试图相对进口非包独立运行脚本瓶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 

在应用程序/应用/ cron的我已经写了独立的守护进程我想在泊坞窗外打电话。例如 蟒daemon1.py

daemon1.py代码

从..common进口统计

从..method进口msapi,dataformater

从..db_client进口db_connection

DEF run_daemon( ):

...... 

...... 

...... 

如果 ==“主要”:

run_daemon() 

所以,当我试图运行此daemon1.py其抛出ValueError异常:非包尝试相对进口

请建议进口的正确方法以及构建这些守护进程。

在此先感谢。

+0

此主题可以帮助您吗? https://stackoverflow.com/questions/11536764/how-to-fix-attempted-relative-import-in-non-package-even-with-init-py 它建议运行daemon1.py使用“python - m ...“语法,或者在模块中定义'__package__'。 – Simpom

+0

由于缺乏服务器访问权限,因此无法运行CLI命令,因此无法提供帮助。 – meera

回答

0

@greenbergé谢谢你的解决方案。我尝试过,但没有为我工作。

因此,为了使事情有效,我已经改变了我的代码。除了在daemon1.py的主目录中调用run_daemon()之外,我还直接调用了函数run_daemon()。

python -m'from app.cron.daemon1 import run_daemon(); run_daemon()'

由于它不是问题的确切解决方案,但事情为我工作。

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 

我曾经对自己说,引用的快速搜索是一个没有没有,但我找不到他们......对不起。

很长的路要走

这种方法包括临时追加每个模块到您的位置。这对我的Docker部署非常有用,并且很好地工作,无论容器的目录结构如何。步骤如下:

1)您必须从__init__文件的父目录中导入相关模块。这实际上是__init__的全部要点 - 允许其包装中的模块可调用。所以,你的情况,cron/__init__应该包含:

from . import common 

它看起来并不像您的目录去任何比这高,但你会做同样的任何其它软件包水平,直至为好。

2)现在您需要将模块的路径附加到PATH变量。你可以看到什么是在那里,现在通过运行:

sys.path

正如预期的那样,你可能不会看到任何模块在那里。这意味着,当你调用common模块时,Python无法弄清楚你想要什么。为了添加路径,你需要找出目录结构。您将希望使这种动态适用于更改目录。

值得注意的是,每次模块运行时都需要运行。我不知道你的cron模块是什么,但在我的情况下,它是芹菜。所以,只有当我激发工人和最初的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)) 

在你的情况,因为你有两个目录命名,这可能是一个挑战,“应用程序”。您的顶级“应用”是我的'project_name'。下一步,我们假设您已将其更改为“project_name”。

3)现在,你可以追加为每个模块到PATH变量的路径:

sys.path.append(parrent_dir + '/app')

现在,如果你再次运行sys.path,你应该看到的路径/app在那里。

总结:确保您所有的__init__都有导入,确定要导入模块的路径,将路径附加到PATH变量。

我希望有帮助。