Issue: @db.commit_on_success does not work with deferred db
Author: akaRem
State: closed
Created: 2014-11-30 23:31:37

The problem (simplified code):

```
# file: app.py
...
db = PostgresqlExtDatabase(None)
...
def create_app(config_name):
    app = Flask(__name__)
    db.init('demo')
    from api import api
    app.register_blueprint(api, url_prefix='/api')
    return app

...

if __name__ == '__main__':
    create_app(config).run()


# file: api.py
...
from app import db
...
api = Blueprint('api', __name__)

@db.commit_on_success
def log_request():
    # do stuff

@api.before_request
def initialize():
    log_request()
    ...

...
```

everything looks like ok, bur when request comes, exeption in `connect` happens

```
Exception: Error, database not properly initialized before opening connection
```

Ive spent a lot of time to understand reasons which are here:

```
def commit_on_success(self, func):
    @wraps(func)
    def inner(*args, **kwargs):
        with self.transaction():
            return func(*args, **kwargs)
    return inner
```

Also for unknown reasons `id(self)` in `connect` differs from `id(db)` in app.py.
Not sure why..

so .. in closure of commit_on_success db still deferred

full Stacktrace

```
Traceback (most recent call last):
  File "/Users/a_user/a_project/py27/lib/python2.7/site-packages/flask/app.py", line 1836, in __call__
    return self.wsgi_app(environ, start_response)
  File "/Users/a_user/a_project/py27/lib/python2.7/site-packages/flask/app.py", line 1820, in wsgi_app
    response = self.make_response(self.handle_exception(e))
  File "/Users/a_user/a_project/py27/lib/python2.7/site-packages/flask/app.py", line 1403, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/Users/a_user/a_project/py27/lib/python2.7/site-packages/flask/app.py", line 1817, in wsgi_app
    response = self.full_dispatch_request()
  File "/Users/a_user/a_project/py27/lib/python2.7/site-packages/flask/app.py", line 1477, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/Users/a_user/a_project/py27/lib/python2.7/site-packages/flask/app.py", line 1381, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/Users/a_user/a_project/py27/lib/python2.7/site-packages/flask/app.py", line 1473, in full_dispatch_request
    rv = self.preprocess_request()
  File "/Users/a_user/a_project/py27/lib/python2.7/site-packages/flask/app.py", line 1666, in preprocess_request
    rv = func()
  File "/Users/a_user/a_project/backend/blueprints/api.py", line 43, in initialize
    log_request()
  File "/Users/a_user/a_project/py27/lib/python2.7/site-packages/peewee.py", line 2829, in inner
    return func(*args, **kwargs)
  File "/Users/a_user/a_project/py27/lib/python2.7/site-packages/peewee.py", line 3233, in __exit__
    self.rollback()
  File "/Users/a_user/a_project/py27/lib/python2.7/site-packages/peewee.py", line 3220, in rollback
    self.db.rollback()
  File "/Users/a_user/a_project/py27/lib/python2.7/site-packages/peewee.py", line 2801, in rollback
    self.get_conn().rollback()
  File "/Users/a_user/a_project/py27/lib/python2.7/site-packages/peewee.py", line 2740, in get_conn
    self.connect()
  File "/Users/a_user/a_project/py27/lib/python2.7/site-packages/peewee.py", line 2721, in connect
    raise Exception('Error, database not properly initialized '
Exception: Error, database not properly initialized before opening connection
```

peewee is up-to-date


> Also for unknown reasons id(self) in connect differs from id(db) in app.py.
> Not sure why..

I think this is the problem, and I'm not sure how it could be a peewee issue.

``` python
from peewee import *

db = SqliteDatabase(None)

class User(Model):
    username = CharField()

    class Meta:
        database = db

@db.commit_on_success
def create(username):
    User.create(username=username)

db.init(':memory:')
User.create_table()

create('hello')
create('charlie')

for user in User.select():
    print user.username
```

This code works fine.


Yes it does..

I've cut everything and found minimal code for reproduce:

**A. Does not work: two files.**

The first one

```
# test.py
# -*- coding: utf-8 -*-
from flask import Flask
from playhouse.postgres_ext import PostgresqlExtDatabase

db = PostgresqlExtDatabase(None)


def create_app():
    app = Flask('calc')
    app.config["DEBUG"] = True
    db.init('demo')
    print db.execute_sql(
        """SELECT table_name FROM information_schema.tables WHERE table_schema = 'public';"""
    ).fetchall()  # ok!
    from test_api import api

    app.register_blueprint(api, url_prefix='/api')
    return app


if __name__ == '__main__':
    create_app().run()
```

The second one

```
# test_api.py
# -*- coding: utf-8 -*-
from flask import Blueprint, jsonify
from test import db

api = Blueprint('api', __name__)


@api.route('/log', methods=["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"])
@db.commit_on_success
def logging_handler():
    return jsonify(hello='world from api')
```

**B. Does Work!**

One file

```
# test.py
# -*- coding: utf-8 -*-
from flask import Flask, Blueprint, jsonify
from playhouse.postgres_ext import PostgresqlExtDatabase

db = PostgresqlExtDatabase(None)
api = Blueprint('api', __name__)


@api.route('/log', methods=["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"])
@db.commit_on_success
def logging_handler():
    return jsonify(hello='world from api')


def create_app():
    app = Flask('calc')
    app.config["DEBUG"] = True
    db.init('demo')
    print db.execute_sql(
        """SELECT table_name FROM information_schema.tables WHERE table_schema = 'public';"""
    ).fetchall()  # ok!

    app.register_blueprint(api, url_prefix='/api')
    return app


if __name__ == '__main__':
    create_app().run()
```


this does not work either (with 2 files):

```
@api.route('/log', methods=["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"])
def logging_handler():
    with db.transaction():
        return jsonify(hello='world from api')
```


.. and this:

```
# -*- coding: utf-8 -*-
from flask import Blueprint, jsonify
import test
db = test.db

api = Blueprint('api', __name__)


@api.route('/log', methods=["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"])
@db.commit_on_success
def logging_handler():
    return jsonify(hello='world from api')
```


The only way I found to fix that is:

```
def create_app():
    app = Flask('calc')
    app.config["DEBUG"] = True
    from test_api import api, db
    db.init('demo')
    print db.execute_sql(
        """SELECT table_name FROM information_schema.tables WHERE table_schema = 'public';"""
    ).fetchall()  # ok!

    app.register_blueprint(api, url_prefix='/api')
    return app
```

But this does not looks like a solution because there could be more than 1 file which imports db from skeleton.


But! If I split app skeleton into 2 files:

```
# -*- coding: utf-8 -*-
from playhouse.postgres_ext import PostgresqlExtDatabase

db = PostgresqlExtDatabase(None)
```

and

```
# -*- coding: utf-8 -*-
from flask import Flask


def create_app():
    app = Flask('calc')
    app.config["DEBUG"] = True
    from test import db
    db.init('demo')
    from test_api import api

    print db.execute_sql(
        """SELECT table_name FROM information_schema.tables WHERE table_schema = 'public';"""
    ).fetchall()  # ok!

    app.register_blueprint(api, url_prefix='/api')
    return app


if __name__ == '__main__':
    create_app().run()
```

then it works.

I really don't understand this ...


I made a very simple example which is working fine for me locally:

``` python
### app.py
from peewee import *

db = SqliteDatabase(None)

def initialize():
    db.init(':memory:')
```

``` python
### db.py
from peewee import *
from app import db

class User(Model):
    username = CharField()
    class Meta:
        database = db

@db.commit_on_success
def test_fn(username):
    User.create(username=username)
```

``` python
### main.py -- use python main.py to run
from app import *
from db import *

initialize()
User.create_table()
test_fn('asdf')
```

It works as expected and the `id()` of the database is consistent. Throughout (verified using interactive debugger).


I'm going to close this as I don't believe there is a peewee bug here.