Skip to content

Instantly share code, notes, and snippets.

@jgonggrijp
Last active August 16, 2018 14:05
Show Gist options
  • Save jgonggrijp/e09c3c2c558c16d2c2d5 to your computer and use it in GitHub Desktop.
Save jgonggrijp/e09c3c2c558c16d2c2d5 to your computer and use it in GitHub Desktop.
Demonstration of a curious discrepancy between MySQL and SQLite when using file uploads with Flask-Admin and Flask-SQLAlchemy.
.E
======================================================================
ERROR: test_upload_works (test_flask_admin_testcase.PictureTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_flask_admin_testcase.py", line 118, in test_upload_works
'path': (test_image_path, test_image_name),
File "/path/to/env/lib/python2.7/site-packages/werkzeug/test.py", line 784, in post
return self.open(*args, **kw)
File "/path/to/env/lib/python2.7/site-packages/flask/testing.py", line 108, in open
follow_redirects=follow_redirects)
File "/path/to/env/lib/python2.7/site-packages/werkzeug/test.py", line 742, in open
response = self.run_wsgi_app(environ, buffered=buffered)
File "/path/to/env/lib/python2.7/site-packages/werkzeug/test.py", line 659, in run_wsgi_app
rv = run_wsgi_app(self.application, environ, buffered=buffered)
File "/path/to/env/lib/python2.7/site-packages/werkzeug/test.py", line 867, in run_wsgi_app
app_rv = app(environ, start_response)
File "/path/to/env/lib/python2.7/site-packages/flask/app.py", line 1836, in __call__
return self.wsgi_app(environ, start_response)
File "/path/to/env/lib/python2.7/site-packages/flask/app.py", line 1820, in wsgi_app
response = self.make_response(self.handle_exception(e))
File "/path/to/env/lib/python2.7/site-packages/flask/app.py", line 1403, in handle_exception
reraise(exc_type, exc_value, tb)
File "/path/to/env/lib/python2.7/site-packages/flask/app.py", line 1817, in wsgi_app
response = self.full_dispatch_request()
File "/path/to/env/lib/python2.7/site-packages/flask/app.py", line 1477, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/path/to/env/lib/python2.7/site-packages/flask/app.py", line 1381, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/path/to/env/lib/python2.7/site-packages/flask/app.py", line 1475, in full_dispatch_request
rv = self.dispatch_request()
File "/path/to/env/lib/python2.7/site-packages/flask/app.py", line 1461, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/path/to/env/lib/python2.7/site-packages/flask_admin/base.py", line 68, in inner
return self._run_view(f, *args, **kwargs)
File "/path/to/env/lib/python2.7/site-packages/flask_admin/base.py", line 359, in _run_view
return fn(self, *args, **kwargs)
File "/path/to/env/lib/python2.7/site-packages/flask_admin/model/base.py", line 1585, in create_view
if self.validate_form(form):
File "/path/to/env/lib/python2.7/site-packages/flask_admin/model/base.py", line 1037, in validate_form
return validate_form_on_submit(form)
File "/path/to/env/lib/python2.7/site-packages/flask_admin/helpers.py", line 65, in validate_form_on_submit
return is_form_submitted() and form.validate()
File "/path/to/env/lib/python2.7/site-packages/wtforms/form.py", line 310, in validate
return super(Form, self).validate(extra)
File "/path/to/env/lib/python2.7/site-packages/wtforms/form.py", line 152, in validate
if not field.validate(self, extra):
File "/path/to/env/lib/python2.7/site-packages/wtforms/fields/core.py", line 200, in validate
stop_validation = self._run_validation_chain(form, chain)
File "/path/to/env/lib/python2.7/site-packages/wtforms/fields/core.py", line 220, in _run_validation_chain
validator(form, self)
File "/path/to/env/lib/python2.7/site-packages/flask_admin/contrib/sqla/validators.py", line 37, in __call__
.filter(self.column == field.data)
File "/path/to/env/lib/python2.7/site-packages/sqlalchemy/orm/query.py", line 2473, in one
ret = list(self)
File "/path/to/env/lib/python2.7/site-packages/sqlalchemy/orm/query.py", line 2516, in __iter__
return self._execute_and_instances(context)
File "/path/to/env/lib/python2.7/site-packages/sqlalchemy/orm/query.py", line 2531, in _execute_and_instances
result = conn.execute(querycontext.statement, self._params)
File "/path/to/env/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 914, in execute
return meth(self, multiparams, params)
File "/path/to/env/lib/python2.7/site-packages/sqlalchemy/sql/elements.py", line 323, in _execute_on_connection
return connection._execute_clauseelement(self, multiparams, params)
File "/path/to/env/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1010, in _execute_clauseelement
compiled_sql, distilled_params
File "/path/to/env/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1146, in _execute_context
context)
File "/path/to/env/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1341, in _handle_dbapi_exception
exc_info
File "/path/to/env/lib/python2.7/site-packages/sqlalchemy/util/compat.py", line 199, in raise_from_cause
reraise(type(exception), exception, tb=exc_tb)
File "/path/to/env/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1139, in _execute_context
context)
File "/path/to/env/lib/python2.7/site-packages/sqlalchemy/engine/default.py", line 450, in do_execute
cursor.execute(statement, parameters)
InterfaceError: (sqlite3.InterfaceError) Error binding parameter 0 - probably unsupported type. [SQL: u'SELECT picture.id AS picture_id, picture.name AS picture_name, picture.path AS picture_path \nFROM picture \nWHERE picture.path = ?'] [parameters: (<FileStorage: u'openclipart_hector_gomez_landscape.png' ('image/png')>,)]
----------------------------------------------------------------------
Ran 2 tests in 0.170s
FAILED (errors=1)
CherryPy==3.8.0
Flask==0.10.1
Flask-Admin==1.2.0
Flask-SQLAlchemy==2.0
Jinja2==2.7.3
MarkupSafe==0.23
MySQL-python==1.2.5
Pillow==2.9.0
PyYAML==3.11
SQLAlchemy==1.0.6
WTForms==2.0.2
Werkzeug==0.10.4
argparse==1.3.0
glob2==0.4.1
itsdangerous==0.24
ordereddict==1.1
pip-tools==0.3.6
six==1.9.0
wsgiref==0.1.2
#!/usr/bin/env python
# (c) 2014 Digital Humanities Lab, Faculty of Humanities, Utrecht University
# Author: Julian Gonggrijp, j.gonggrijp@uu.nl
# Prerequisites:
# Create a MySQL database 'example' with user 'example' and no password.
# Create a Python 2.7 virtualenv in which you install the requirements.
# In order to run the application with the built-in server, run
# python test_flask_admin_testcase.py
# and visit 127.0.0.1:5000/admin with your browser.
# Uploading of images should work perfectly fine in this case.
# In order to run the test suite, run
# python -m unittest test_flask_admin_testcase
# You should get something similar to the contents of output.txt.
import os
import os.path as op
from tempfile import mkdtemp
from shutil import rmtree
from unittest import TestCase
from flask import Flask, current_app
from flask.ext.admin import Admin, form
from flask.ext.sqlalchemy import SQLAlchemy
from flask.ext.admin.contrib.sqla import ModelView
db = SQLAlchemy()
class Picture(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(40), nullable=False)
path = db.Column(db.String(50), unique=True, nullable=False)
class PictureView(ModelView):
column_list = ('name',)
form_columns = ('name', 'path')
form_overrides = {
'path': form.FileUploadField,
}
form_args = {
'path': {
'label': 'File',
'base_path': lambda: current_app.instance_path,
'allowed_extensions': ('jpg', 'jpeg', 'png'),
}
}
def __init__(self, session, name='Picture', **kwargs):
super(PictureView, self).__init__(Picture, session, name, **kwargs)
def create_admin(app):
admin = Admin(name='Example')
admin.add_view(PictureView(db.session))
admin.init_app(app)
def create_app(config_obj, instance=None):
app = Flask(__name__, instance_path=instance)
app.config.from_object(config_obj)
db.init_app(app)
db.create_all(app=app)
create_admin(app)
return app
class Configuration(object):
SQLALCHEMY_DATABASE_URI = 'mysql://example@localhost/example?charset=utf8&use_unicode=0'
SECRET_KEY = 'psiodfnvpsdojfnvpaosihrgt'
if __name__ == '__main__':
app = create_app(Configuration)
app.debug = True
app.run()
class FixtureConfiguration(Configuration):
SQLALCHEMY_DATABASE_URI = 'sqlite://'
TESTING = True
class PictureTestCase(TestCase):
def setUp(self):
super(PictureTestCase, self).setUp()
tmpdir = mkdtemp('example_instance')
self.app = create_app(FixtureConfiguration, tmpdir)
self.client = self.app.test_client()
def tearDown(self):
db.drop_all(app=self.app)
rmtree(self.app.instance_path)
super(PictureTestCase, self).tearDown()
def request_context(self):
return self.app.test_request_context()
def test_picture_exists(self):
pic = Picture(name='Test', path='test/test.jpeg')
with self.request_context():
db.session.add(pic)
db.session.commit()
first = db.session.query(Picture).first()
self.assertEqual(pic.id, 1)
self.assertEqual(first, pic)
def test_upload_works(self):
test_image_name = 'openclipart_hector_gomez_landscape.png'
tests_dir = op.dirname(__file__)
test_image_path = op.join(tests_dir, test_image_name)
with self.client as c:
c.post('/admin/picture/new/', data={
'name': 'testimage',
'path': (test_image_path, test_image_name),
})
images = Picture.query.all()
self.assertEqual(len(images), 1)
self.assertEqual(images[0].path, test_image_name)
directory = os.listdir(self.app.instance_path)
self.assertEqual(len(directory), 1)
self.assertIn(test_image_name, directory)
@shadyabhi
Copy link

I have the same issue. What was the fix?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment