Confusion regarding Flask & importing modules

I have a flash application that I am trying to organize and follow the correct flag structure and module / import that has been shown in many tutorials.

I am at a point where I really don't know why I do certain things, and that is never good.

My flask app is laid out like this:

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

      

INIT .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")

      

When I run run.py I get the following traceback:

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

      

It's hard for me to understand what's going on in general - I need an explanation as to why I am doing what I am doing:

  • What is the reason for splitting app.run()

    into a separate python file that imports the application from steamapp? Why is app.run () not in views.py?

  • What does init .py mean ? Why imported into it views.py

    and tasks.py

    ?

  • Why does this indicate that the "app" trace is not detected when it is imported from __init__.py

    ?

Thanks to everyone who could provide some clarification as I have lost my sense of what is going on.


EDIT:

I updated the code in the OP with the changes I made after reading @ dreamriver's answer.

I'm still a little confused - why am I importing the flask in views.py when it's already imported into init .py, where the views are imported and presumably run?

Also, how does celery work in this? Setting tasks.py as a celery worker returns the following traceback:

 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

      

+3


source to share


1 answer


You need to explicitly import the application into your views file. The error says the app is not defined in views.py because you need to do:

from steamapp import app

      

at the top of your views file.

__init__.py

turns your directory into a python package. When the interpreter starts, all directories that are on $ PYTHONPATH c __init__.py

are appended to sys.path

, making them importable. __init__.py

also executed when the imported module is imported. This makes it extremely useful, for example. by exporting the main code of your code. If you look at the source code of the flask, you can see that all the code you are doing

from flask import Flask, request etc

      

is actually defined by small chunks of functionality in separate files, and interesting snippets are then mapped to __init__.py

.



As stated here Python doesn't want modules in packages to be a boot file. Python packaging is a bit messy. This stackoverflow answer helped me understand some of these questions, namely that relative imports are completely aborted because they are computed with the account __name__

that is set to '__main__'

when executing the file directly, but the name of the file itself when used through the import.

Apart from a few module level globules like __name__

and __package__

, nothing is imported into the top level namespace. Therefore app

is implicitly not available to you in views.py.

Does this answer your questions?

EDIT

You need to import views.py in __init__.py

because otherwise your views.py file will fail and none of your routes, etc. will not be determined. You need to import the app into views.py because the app is not in the namespace that the views.py file has access to. This pattern, where two files are imported with each other, is called circular import and can be tricky, but it's fine here. You should be aware that once a module is loaded, it is cached so it will not re-execute when it is imported again.

The celery problem looks like python doesn't see your app on sys.path

when you start celery. Displaying the output sys.path

at this point would be helpful. My guess is that if you add your working directory to $ PYTHONPATH the problem will be fixed. When you install things with pip and the like, the packages are added to a place where python knows how to find them by default.

+3


source







All Articles