user9735110
user9735110

Reputation:

Flask tutorial: AttributeError teardown_appcontext

I'm a beginner of Python and Flask. I was going through Flask tutorial up to "Define and Access the Database" section.

Wrote up all codes, saved, and did below on Windows command prompt.

flask init-db

However, got received the error on the command prompt as follows.

AttributeError: 'ellipsis' object has no attribute 'teardown_appcontext'

I doublechecked the codes to confirm it's written exactly in a way that tutorial specifies and it actually worked fine until the previous section. Searched through Stackoverflows if there is any similar questions, but ended up not finding out a clear cause.

Any advises? Thank you very much for your support.

--Additions--

Thanks Joost. Here is what I did.

Files layout image link

__init__.py

import os

from flask import Flask

def create_app(test_config=None):
    # create and configure the app
    app = Flask(__name__, instance_relative_config=True)
    app.config.from_mapping(
        SECRET_KEY='dev',
        DATABASE=os.path.join(app.instance_path, 'flaskr.sqlite'),
    )

    if test_config is None:
        # Load the instance config, if it exists, when not testing
        app.config.from_pyfile('config.py', silent=True)
    else:
        # Load the test config if passed in
        app.config.from_mapping(test_config)

    # ensure the instance floder exists
    try:
        os.makedirs(app.instance_path)
    except OSError:
        pass

    # a simple page that says hello
    @app.route('/hello')
    def hello():
        return 'Hello, World!'

def create_app():
    app = ...
    # existing code omitted

    from . import db
    db.init_app(app)

    return app

db.py

import sqlite3

import click
from flask import current_app, g
from flask.cli import with_appcontext

def get_db():
    if 'db' not in g:
        g.db = sqlite3.connect(
            current_app.config['DATABASE'],
            detect_types=sqlite3.PARSE_DECLTYPES
        )
        g.db.row_factory = sqlite3.Row

    return g.db

def close_db(e=None):
    db = g.pop('db', None)

    if db is not None:
        db.close()

def init_db():
    db = get_db()

    with current_app.open_resource('schema.sql') as f:
        db.executescript(f.read().decode('utf8'))

@click.command('init-db')
@with_appcontext
def init_db_command():
    """Clear the exisitng data and create new tables."""
    init_db()
    click.echo('Initialized the database.')

def init_app(app):
    app.teardown_appcontext(close_db)
    app.cli.add_command(init_db_command)

schema.sql

DROP TABLE IF EXISTS user;
DROP TABLE IF EXISTS post;

CREATE TABLE user (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  username TEXT UNIQUE NOT NULL,
  password TEXT NOT NULL
);

CREATE TABLE post (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  author_id INTEGER NOT NULL,
  created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  title TEXT NOT NULL,
  body TEXT NOT NULL,
  FOREIGN KEY (author_id) REFERENCES user (id)
);

And finally I did on the command prompt:

set FLASK_APP=flaskr
set FLASK_ENV=development
flask init-db

However it returned like this.

Any advises? Thank you very much.

Upvotes: 5

Views: 5488

Answers (3)

werber bang
werber bang

Reputation: 333

you don't replace the existing code with the new proposed one, but you add to it,

so for example :

def create_app():
app = ...
# existing code omitted

from . import db
db.init_app(app)

return app

should be translated in your code by adding the two new lines :

from . import db
db.init_app(app)

to what's already there so far in the function, just before the last line.

return app

which should translate as other answers mentioned :

 def create_app(test_config=None):
        # create and configure the app
        app = Flask(__name__, instance_relative_config=True)
        app.config.from_mapping(
            SECRET_KEY='dev',
            DATABASE=os.path.join(app.instance_path, 'flaskr.sqlite'),
        )

        if test_config is None:
            # Load the instance config, if it exists, when not testing
            app.config.from_pyfile('config.py', silent=True)
        else:
            # Load the test config if passed in
            app.config.from_mapping(test_config)

        # ensure the instance floder exists
        try:
            os.makedirs(app.instance_path)
        except OSError:
            pass

        # a simple page that says hello
        @app.route('/hello')
        def hello():
            return 'Hello, World!'

        from . import db
        db.init_app(app)

        return app

Upvotes: 0

You defined create_app() twice. To solve your problem, make the following change in your __init__.py files:

import os

from flask import Flask


def create_app(test_config=None):
    """ Application factory function """
    # create and configure the app
    app = Flask(__name__, instance_relative_config=True)
    app.config.from_mapping(
        SECRET_KEY='dev',
        DATABASE=os.path.join(app.instance_path, 'flaskr.sqlite'),
    )

    if test_config is None:
        # load the instance config, if it exists, when not testing
        app.config.from_pyfile('config.py', silent=True)
    else:
        # load the test config if passed in
        app.config.from_mapping(test_config)

    # ensure the instance folder exists
    try:
        os.makedirs(app.instance_path)
    except OSError:
        pass

    # a simple page that says hello
    @app.route('/hello')
    def hello():
        return 'Hello, World! Now We are Introducing Mr. Narendra Singh Parihar.THE BOSS !!'

    from . import db
    db.init_app(app)

    return app

Upvotes: 5

Sam Kihika
Sam Kihika

Reputation: 121

Actually the problem is in your init.py I removed the second create_app() from your init file and edited it like below remember the app factory need to know where your db.py is while creating the app

 import os

    from flask import Flask

    def create_app(test_config=None):
        # create and configure the app
        app = Flask(__name__, instance_relative_config=True)
        app.config.from_mapping(
            SECRET_KEY='dev',
            DATABASE=os.path.join(app.instance_path, 'flaskr.sqlite'),
        )

        if test_config is None:
            # Load the instance config, if it exists, when not testing
            app.config.from_pyfile('config.py', silent=True)
        else:
            # Load the test config if passed in
            app.config.from_mapping(test_config)

        # ensure the instance floder exists
        try:
            os.makedirs(app.instance_path)
        except OSError:
            pass

        # a simple page that says hello
        @app.route('/hello')
        def hello():
            return 'Hello, World!'

        from . import db
        db.init_app(app)

        return app

Upvotes: 0

Related Questions