ValueError:尝试在非包中进行相对导入,以便在Flask Web App中运行独立脚本

2024-10-05 10:02:35 发布

您现在位置:Python中文网/ 问答频道 /正文

我有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代码

从..通用导入统计信息

从..方法导入msapi,数据格式化程序

从..db_客户端导入db_连接

def run_daemon():

^{pr2}$

如果名称==“main”:

run_daemon()

所以当我试图运行这个daemon1.py时,它的抛出值错误:试图在非包中进行相对导入

请建议正确的导入方法以及构造这些守护进程。在

提前谢谢。在


Tags: 方法dockerrunpyclientwebappflask
2条回答

@greenbergé谢谢你的解决方案。我试过了,但没用。在

所以为了让事情顺利进行,我稍微修改了一下代码。除了在daemon1.py的main中调用run_daemon()之外,我还直接调用了函数run_daemon()。在

python-m'来自app.cron.daemon1应用程序导入run_daemon();run_daemon()'

因为这不是问题的确切解决办法,但对我有用。在

我在运行烧瓶和芹菜的应用程序中遇到了完全相同的问题。我花了太多时间在谷歌上寻找一个简单的答案。唉,没有。在

我不喜欢“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__应该包含:

^{pr2}$

看起来你的目录不会比这个更高,但是对于任何其他的包级别,你也会做同样的事情。在

2)现在需要将模块的路径附加到path变量。您可以通过运行以下命令查看其中的内容:

sys.path

正如预期的那样,您可能不会在其中看到任何模块。这意味着,当您调用common模块时,Python无法确定您想要什么。为了添加路径,您需要找出目录结构。您需要使此动态以适应目录的更改。在

值得注意的是,每次运行模块时都需要运行这个函数。我不确定您的cron模块是什么,但在我的例子中它是芹菜。所以,这只在我启动workers和初始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”的目录。你的顶级“应用程序”是我的“项目名称”。下一步,假设您已将其更改为“project_name”。在

3)现在可以将每个模块的路径附加到path变量:

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

现在,如果您再次运行sys.path,您应该会在其中看到/app的路径。在

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

我希望这有帮助。在

相关问题 更多 >

    热门问题