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()'

因为它不是问题的确切解决方案,但对我有用。