有关烧瓶和烧瓶的困惑导入模块

时间:2014-10-05 17:52:37

标签: python python-2.7 module flask

我有一个烧瓶应用程序,我正在尝试组织并遵循适当的烧瓶文件夹结构和模块/导入,已在许多教程中显示。

我真的不知道为什么我正在做某些事情,这从来都不是一件好事。

我的烧瓶应用程序布局如下:

/steam
    run.py
    /steamapp
        __init__.py
        config.py
        tasks.py
        views.py
        /static
           css.css
        /templates
           template.html

run.py

from steamapp import app
app.run()

初始化的.py

from celery import Celery
from config import secrets, constants
from flask.ext.openid import OpenID
from flask import Flask
import praw

def make_celery(app):
    celery = Celery(app.import_name, backend='amqp', broker='amqp://guest@localhost//')
    celery.conf.update(app.config)
    TaskBase = celery.Task
    class ContextTask(TaskBase):
        abstract = True
        def __call__(self, *args, **kwargs):
            with app.app_context():
                return TaskBase.__call__(self, *args, **kwargs)
    celery.Task = ContextTask
    return celery


app = Flask(__name__)
oid = OpenID(app)
app.debug = True
app.secret_key = secrets.APP_SECRET_KEY
celery = make_celery(app)


reddit = praw.Reddit(constants.USERAGENT)
reddit.login(constants.USERNAME, secrets.PASSWORD)

rs = praw.Reddit(constants.USERAGENT)
rs.set_oauth_app_info(secrets.CLIENT_ID, secrets.CLIENT_SECRET, constants.REDIRECT_URL)


from steamapp import views
from steamapp import tasks

views.py

from steamapp import app, oid, celery
from tasks import get_auth_url, check_reddit_oauth, request_steam_api
from flask import Flask, session, redirect, request, render_template, url_for
from config import secrets, constants
from flask.ext.openid import OpenID
import os
import praw
import time
import json
import string
import random
import requests


def id_generator(size=6, chars=string.ascii_uppercase + string.digits):
    return ''.join(random.choice(chars) for _ in range(size))


def check_session_id(session):
    if "id" in session:
        return True
    else:
        return render_template("error.html", error=["?", "No session ID found."])


@app.route("/register")
def register():
    if "id" not in session:
        session["id"] = id_generator()
    authorize_url = get_auth_url(session)
    return redirect(authorize_url)


@app.route("/redirect/")
@oid.loginhandler
def redirect_to_steam_oauth():
   ...
   ...
   ...
   etc

tasks.py

from steamapp import celery, rs
from config import secrets, constants
import requests

@celery.task
def get_auth_url(session):
    return rs.get_authorize_url(session["id"], scope="identity")

当我运行run.py时,我得到以下回溯:

Traceback (most recent call last):
  File "/home/andy/Desktop/Python Projects/Finished/steam/run.py", line 1, in <module>
    from steamapp import app
  File "/home/andy/Desktop/Python Projects/Finished/steam/steamapp/__init__.py", line 25, in <module>
    from steamapp import views
  File "/home/andy/Desktop/Python Projects/Finished/steam/steamapp/views.py", line 20, in <module>
    @app.route("/register")
NameError: name 'app' is not defined

我无法理解整体上发生的事情 - 我需要解释为什么我正在做我正在做的事情:

  1. app.run()分隔成从steamapp导入应用程序的单独python文件的原因是什么?为什么app.run()不在views.py?

  2. 什么是 init .py实际上意味着什么?为什么导入views.pytasks.py

  3. 为什么在从__init__.py导入“app”时没有定义“app”的追溯?

  4. 感谢任何能够提供一些澄清的人,因为我已经不知道发生了什么。


    编辑:

    我已经更新了OP中的代码,并且在阅读@ dreamriver的回复之后我已经做了更改。

    我仍然有点困惑 - 为什么我在views.py中导入了它已经在 init .py中导入,其中导入了视图并且可能是从中运行的?

    此外,芹菜工人如何与此相关?将tasks.py设置为Celery工作程序将返回以下回溯:

     celery -A tasks worker --loglevel=info
    Traceback (most recent call last):
      File "/usr/local/bin/celery", line 11, in <module>
        sys.exit(main())
      File "/usr/local/lib/python2.7/dist-packages/celery/__main__.py", line 30, in main
        main()
      File "/usr/local/lib/python2.7/dist-packages/celery/bin/celery.py", line 81, in main
        cmd.execute_from_commandline(argv)
      File "/usr/local/lib/python2.7/dist-packages/celery/bin/celery.py", line 769, in execute_from_commandline
        super(CeleryCommand, self).execute_from_commandline(argv)))
      File "/usr/local/lib/python2.7/dist-packages/celery/bin/base.py", line 305, in execute_from_commandline
        argv = self.setup_app_from_commandline(argv)
      File "/usr/local/lib/python2.7/dist-packages/celery/bin/base.py", line 465, in setup_app_from_commandline
        self.app = self.find_app(app)
      File "/usr/local/lib/python2.7/dist-packages/celery/bin/base.py", line 485, in find_app
        return find_app(app, symbol_by_name=self.symbol_by_name)
      File "/usr/local/lib/python2.7/dist-packages/celery/app/utils.py", line 229, in find_app
        sym = symbol_by_name(app, imp=imp)
      File "/usr/local/lib/python2.7/dist-packages/celery/bin/base.py", line 488, in symbol_by_name
        return symbol_by_name(name, imp=imp)
      File "/usr/local/lib/python2.7/dist-packages/kombu/utils/__init__.py", line 92, in symbol_by_name
        module = imp(module_name, package=package, **kwargs)
      File "/usr/local/lib/python2.7/dist-packages/celery/utils/imports.py", line 101, in import_from_cwd
        return imp(module, package=package)
      File "/usr/lib/python2.7/importlib/__init__.py", line 37, in import_module
        __import__(name)
      File "/home/andy/Desktop/Python Projects/Finished/steam/steamapp/tasks.py", line 1, in <module>
        from steamapp import celery, rs
    ImportError: No module named steamapp
    

1 个答案:

答案 0 :(得分:6)

您必须将app明确导入到您的视图文件中。该错误表明在views.py中未定义app,因为您需要这样做:

from steamapp import app

位于视图文件的顶部。

__init__.py将您的目录转换为python包。在解释器启动时,带有__init__.py的$ PYTHONPATH上的所有目录都会添加到sys.path,这使得它们可以导入。导入时定义的模块也会执行__init__.py。这使它对例如非常有用。导出代码的主要api。如果你查看了烧瓶的源代码,你会看到你所做的所有代码

from flask import Flask, request etc

实际上是在单独的文件中以较小的功能块定义的,然后有趣的部分在__init__.py中公开。

如上所述here Python不希望包中的模块成为启动文件。 Python包装有点混乱。 This stackoverflow回答帮助我理解了其中的一些问题,即相对导入完全中断,因为它们是以__name__计算的,当您直接执行文件但文件名设置为'__main__'时通过导入使用它本身。

除了__name____package__之类的一些模块级全局变量外,没有任何内容明确地导入到顶级命名空间。这就是为什么app隐式在views.py文件中无法使用的原因。

这会回答你的问题吗?

修改

您需要将views.py导入__init__.py,否则您的views.py文件将无法执行,您的路由也不会被定义。您需要将app导入views.py,因为app不在您的views.py文件能够访问的命名空间中。这两个文件相互导入的模式称为循环导入,可能很棘手,但这里很好。您应该知道,在加载模块后,它会被缓存,以便在再次导入时不会重新执行。

你的芹菜问题在我看来,当芹菜启动时,python在sys.path上看不到你的应用。在此时显示sys.path的输出会很有帮助。我的猜测是,如果将工作目录添加到$ PYTHONPATH,问题将得到解决。当您使用pip等安装东西时,包将被添加到python默认知道如何找到它们的地方。