Skip to content

Commit

Permalink
Fixes behavior when using flask teardown
Browse files Browse the repository at this point in the history
  • Loading branch information
sdispater committed Nov 28, 2015
1 parent 7d1b58a commit 57f54a8
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 15 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
### 0.1.1



##### Fixes

- `Orator` class no longer inherits from `DatabaseManager` to avoid errors when setting up teardown context.

##### Improvements

- Automatically disconnects after a request.


### 0.1

(July 7th, 2015)
Expand Down
31 changes: 24 additions & 7 deletions flask_orator/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from flask import current_app, request, jsonify as base_jsonify, Response
from orator import DatabaseManager, Model as BaseModel
from orator.pagination import Paginator, LengthAwarePaginator
from orator.pagination import Paginator
from orator.commands.migrations import (
InstallCommand, MigrateCommand,
MigrateMakeCommand, RollbackCommand,
Expand All @@ -18,13 +18,12 @@
import json


class Orator(DatabaseManager):
class Orator(object):

def __init__(self, app=None):
self.Model = BaseModel
self.cli = None

super(Orator, self).__init__({})
self._db = None

if app is not None:
self.init_app(app)
Expand All @@ -33,19 +32,27 @@ def init_app(self, app):
if 'ORATOR_DATABASES' not in app.config:
raise RuntimeError('Missing "ORATOR_DATABASES" configuration')

# Register request hooks
self.register_handlers(app)

# Getting config databases
self._config = app.config['ORATOR_DATABASES']

self.Model.set_connection_resolver(self)
# Initializing database manager
self._db = DatabaseManager(self._config)

self.Model.set_connection_resolver(self._db)

# Setting current page resolver
def current_page_resolver():
return int(request.args.get('page', 1))

Paginator.current_page_resolver(current_page_resolver)

self.init_commands(app)
# Setting commands
self.init_commands()

def init_commands(self, app):
def init_commands(self):
self.cli = Application(orator_application.get_name(),
orator_application.get_version())

Expand All @@ -56,6 +63,16 @@ def init_commands(self, app):
self.cli.add(StatusCommand(self))
self.cli.add(ResetCommand(self))

def register_handlers(self, app):
teardown = app.teardown_appcontext

@teardown
def disconnect(_):
return self._db.disconnect()

def __getattr__(self, item):
return getattr(self._db, item)


def jsonify(obj, **kwargs):
indent = None
Expand Down
73 changes: 65 additions & 8 deletions tests/test_orator.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,31 @@
# -*- coding: utf-8 -*-

import sys
import os
import json
import traceback
import tempfile
import uuid
from unittest import TestCase
from flask import Flask, jsonify, request
from flask_orator import Orator, jsonify
from sqlite3 import ProgrammingError
from orator.support.collection import Collection


PY2 = sys.version_info[0] == 2


class FlaskOratorTestCase(TestCase):

def setUp(self):
dbname = '%s.db' % str(uuid.uuid4())
self.dbpath = os.path.join(tempfile.gettempdir(), dbname)

app = Flask(__name__)
app.config['ORATOR_DATABASES'] = {
'test': {
'driver': 'sqlite',
'database': ':memory:'
'database': self.dbpath
}
}

Expand All @@ -27,12 +38,7 @@ def setUp(self):

@app.route('/')
def index():
try:
return jsonify(self.User.order_by('id').paginate(5))
except Exception as e:
print(e)
print(traceback.format_exc())
raise
return jsonify(self.User.order_by('id').paginate(5))

@app.route('/users', methods=['POST'])
def create():
Expand All @@ -43,6 +49,9 @@ def create():

self.init_tables()

def tearDown(self):
os.remove(self.dbpath)

def init_tables(self):
with self.schema().create('users') as table:
table.increments('id')
Expand Down Expand Up @@ -77,6 +86,18 @@ def connection(self):
def schema(self):
return self.connection().get_schema_builder()

def assertRaisesRegex(self, expected_exception, expected_regex,
callable_obj=None, *args, **kwargs):
if PY2:
return self.assertRaisesRegexp(
expected_exception, expected_regex,
callable_obj, *args, **kwargs)

return super(FlaskOratorTestCase, self).assertRaisesRegex(
expected_exception, expected_regex,
callable_obj, *args, **kwargs
)


class BasicAppTestCase(FlaskOratorTestCase):

Expand Down Expand Up @@ -146,3 +167,39 @@ def test_page_greater_than_max_page(self):
)

self.assertEqual(0, len(users))


class ConsistenceTestCase(FlaskOratorTestCase):

def test_handlers(self):
connection = self.db.connection().get_connection()

c = self.app.test_client()

self.get(c, '/')

self.assertRaisesRegex(ProgrammingError, 'Cannot operate on a closed database.', connection.commit)

self.assertIsNone(self.db.connection().get_connection())

def test_behaves_like_manager(self):
@self.app.route('/users')
def users():
try:
users = jsonify(Collection(self.db.table('users').get()).map(lambda x: dict(x.items())))
except Exception as e:
print(e)
raise

return users

c = self.app.test_client()

for i in range(10):
self.post(c, '/users',
name='user %s' % i,
email='foo%[email protected]' % i)

users = json.loads(self.get(c, '/users').data.decode())

self.assertEqual(10, len(users))

0 comments on commit 57f54a8

Please sign in to comment.