Commit d57048b0 authored by Serge S. Koval's avatar Serge S. Koval Committed by GitHub

Merge pull request #1427 from pawl/add_flake8

Add flake8 to tests
parents 60483b00 b8bcb4f8
...@@ -3,4 +3,4 @@ __author__ = 'Flask-Admin team' ...@@ -3,4 +3,4 @@ __author__ = 'Flask-Admin team'
__email__ = 'serge.koval+github@gmail.com' __email__ = 'serge.koval+github@gmail.com'
from .base import expose, expose_plugview, Admin, BaseView, AdminIndexView from .base import expose, expose_plugview, Admin, BaseView, AdminIndexView # noqa: F401
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# flake8: noqa
""" """
flask_admin._compat flask_admin._compat
~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~
......
...@@ -9,7 +9,7 @@ from flask_admin._compat import with_metaclass, as_unicode ...@@ -9,7 +9,7 @@ from flask_admin._compat import with_metaclass, as_unicode
from flask_admin import helpers as h from flask_admin import helpers as h
# For compatibility reasons import MenuLink # For compatibility reasons import MenuLink
from flask_admin.menu import MenuCategory, MenuView, MenuLink from flask_admin.menu import MenuCategory, MenuView, MenuLink # noqa: F401
def expose(url='/', methods=('GET',)): def expose(url='/', methods=('GET',)):
...@@ -670,7 +670,6 @@ class Admin(object): ...@@ -670,7 +670,6 @@ class Admin(object):
for view in self._views: for view in self._views:
app.register_blueprint(view.create_blueprint(self)) app.register_blueprint(view.create_blueprint(self))
def _init_extension(self): def _init_extension(self):
if not hasattr(self.app, 'extensions'): if not hasattr(self.app, 'extensions'):
self.app.extensions = dict() self.app.extensions = dict()
...@@ -699,4 +698,4 @@ class Admin(object): ...@@ -699,4 +698,4 @@ class Admin(object):
""" """
Return menu links. Return menu links.
""" """
return self._menu_links return self._menu_links
\ No newline at end of file
# flake8: noqa
try: try:
import wtforms_appengine import wtforms_appengine
except ImportError: except ImportError:
......
...@@ -3,6 +3,7 @@ from google.appengine.ext import ndb ...@@ -3,6 +3,7 @@ from google.appengine.ext import ndb
import decimal import decimal
class GeoPtPropertyField(StringField): class GeoPtPropertyField(StringField):
def process_formdata(self, valuelist): def process_formdata(self, valuelist):
if valuelist: if valuelist:
......
...@@ -2,6 +2,7 @@ from wtforms_appengine.ndb import ModelConverter ...@@ -2,6 +2,7 @@ from wtforms_appengine.ndb import ModelConverter
from .fields import GeoPtPropertyField from .fields import GeoPtPropertyField
from flask_admin.model.form import converts from flask_admin.model.form import converts
class AdminModelConverter(ModelConverter): class AdminModelConverter(ModelConverter):
@converts('GeoPt') @converts('GeoPt')
def convert_GeoPtProperty(self, model, prop, kwargs): def convert_GeoPtProperty(self, model, prop, kwargs):
......
...@@ -11,6 +11,7 @@ from flask_wtf import Form ...@@ -11,6 +11,7 @@ from flask_wtf import Form
from flask_admin.model.form import create_editable_list_form from flask_admin.model.form import create_editable_list_form
from .form import AdminModelConverter from .form import AdminModelConverter
class NdbModelView(BaseModelView): class NdbModelView(BaseModelView):
""" """
AppEngine NDB model scaffolding. AppEngine NDB model scaffolding.
...@@ -32,7 +33,7 @@ class NdbModelView(BaseModelView): ...@@ -32,7 +33,7 @@ class NdbModelView(BaseModelView):
pass pass
def scaffold_filters(self): def scaffold_filters(self):
#TODO: implement # TODO: implement
pass pass
form_args = None form_args = None
...@@ -75,7 +76,7 @@ class NdbModelView(BaseModelView): ...@@ -75,7 +76,7 @@ class NdbModelView(BaseModelView):
def get_list(self, page, sort_field, sort_desc, search, filters, def get_list(self, page, sort_field, sort_desc, search, filters,
page_size=None): page_size=None):
#TODO: implement filters (don't think search can work here) # TODO: implement filters (don't think search can work here)
q = self.model.query() q = self.model.query()
...@@ -88,7 +89,7 @@ class NdbModelView(BaseModelView): ...@@ -88,7 +89,7 @@ class NdbModelView(BaseModelView):
if not page_size: if not page_size:
page_size = self.page_size page_size = self.page_size
results = q.fetch(page_size, offset=page*page_size) results = q.fetch(page_size, offset=page * page_size)
return q.count(), results return q.count(), results
...@@ -102,7 +103,7 @@ class NdbModelView(BaseModelView): ...@@ -102,7 +103,7 @@ class NdbModelView(BaseModelView):
model.put() model.put()
except Exception as ex: except Exception as ex:
if not self.handle_view_exception(ex): if not self.handle_view_exception(ex):
#flash(gettext('Failed to create record. %(error)s', # flash(gettext('Failed to create record. %(error)s',
# error=ex), 'error') # error=ex), 'error')
logging.exception('Failed to create record.') logging.exception('Failed to create record.')
return False return False
...@@ -117,7 +118,7 @@ class NdbModelView(BaseModelView): ...@@ -117,7 +118,7 @@ class NdbModelView(BaseModelView):
model.put() model.put()
except Exception as ex: except Exception as ex:
if not self.handle_view_exception(ex): if not self.handle_view_exception(ex):
#flash(gettext('Failed to update record. %(error)s', # flash(gettext('Failed to update record. %(error)s',
# error=ex), 'error') # error=ex), 'error')
logging.exception('Failed to update record.') logging.exception('Failed to update record.')
return False return False
...@@ -126,19 +127,19 @@ class NdbModelView(BaseModelView): ...@@ -126,19 +127,19 @@ class NdbModelView(BaseModelView):
return True return True
def delete_model(self, model): def delete_model(self, model):
try: try:
model.key.delete() model.key.delete()
except Exception as ex: except Exception as ex:
if not self.handle_view_exception(ex): if not self.handle_view_exception(ex):
#flash(gettext('Failed to delete record. %(error)s', # flash(gettext('Failed to delete record. %(error)s',
# error=ex), # error=ex),
# 'error') # 'error')
logging.exception('Failed to delete record.') logging.exception('Failed to delete record.')
return False return False
else: else:
self.after_model_delete(model) self.after_model_delete(model)
return True return True
...@@ -155,7 +156,8 @@ class DbModelView(BaseModelView): ...@@ -155,7 +156,8 @@ class DbModelView(BaseModelView):
def scaffold_sortable_columns(self): def scaffold_sortable_columns(self):
# We use getattr() because ReferenceProperty does not specify a 'indexed' field # We use getattr() because ReferenceProperty does not specify a 'indexed' field
return [k for (k, v) in self.model.__dict__.iteritems() if isinstance(v, db.Property) and getattr(v, 'indexed', None)] return [k for (k, v) in self.model.__dict__.iteritems()
if isinstance(v, db.Property) and getattr(v, 'indexed', None)]
def init_search(self): def init_search(self):
return None return None
...@@ -164,14 +166,14 @@ class DbModelView(BaseModelView): ...@@ -164,14 +166,14 @@ class DbModelView(BaseModelView):
pass pass
def scaffold_filters(self): def scaffold_filters(self):
#TODO: implement # TODO: implement
pass pass
def scaffold_form(self): def scaffold_form(self):
return wt_db.model_form(self.model()) return wt_db.model_form(self.model())
def get_list(self, page, sort_field, sort_desc, search, filters): def get_list(self, page, sort_field, sort_desc, search, filters):
#TODO: implement filters (don't think search can work here) # TODO: implement filters (don't think search can work here)
q = self.model.all() q = self.model.all()
...@@ -180,7 +182,7 @@ class DbModelView(BaseModelView): ...@@ -180,7 +182,7 @@ class DbModelView(BaseModelView):
sort_field = "-" + sort_field sort_field = "-" + sort_field
q.order(sort_field) q.order(sort_field)
results = q.fetch(self.page_size, offset=page*self.page_size) results = q.fetch(self.page_size, offset=page * self.page_size)
return q.count(), results return q.count(), results
def get_one(self, encoded_key): def get_one(self, encoded_key):
...@@ -194,7 +196,7 @@ class DbModelView(BaseModelView): ...@@ -194,7 +196,7 @@ class DbModelView(BaseModelView):
return model return model
except Exception as ex: except Exception as ex:
if not self.handle_view_exception(ex): if not self.handle_view_exception(ex):
#flash(gettext('Failed to create record. %(error)s', # flash(gettext('Failed to create record. %(error)s',
# error=ex), 'error') # error=ex), 'error')
logging.exception('Failed to create record.') logging.exception('Failed to create record.')
return False return False
...@@ -206,23 +208,24 @@ class DbModelView(BaseModelView): ...@@ -206,23 +208,24 @@ class DbModelView(BaseModelView):
return True return True
except Exception as ex: except Exception as ex:
if not self.handle_view_exception(ex): if not self.handle_view_exception(ex):
#flash(gettext('Failed to update record. %(error)s', # flash(gettext('Failed to update record. %(error)s',
# error=ex), 'error') # error=ex), 'error')
logging.exception('Failed to update record.') logging.exception('Failed to update record.')
return False return False
def delete_model(self, model): def delete_model(self, model):
try: try:
model.delete() model.delete()
return True return True
except Exception as ex: except Exception as ex:
if not self.handle_view_exception(ex): if not self.handle_view_exception(ex):
#flash(gettext('Failed to delete record. %(error)s', # flash(gettext('Failed to delete record. %(error)s',
# error=ex), # error=ex),
# 'error') # 'error')
logging.exception('Failed to delete record.') logging.exception('Failed to delete record.')
return False return False
def ModelView(model): def ModelView(model):
if issubclass(model, ndb.Model): if issubclass(model, ndb.Model):
return NdbModelView(model) return NdbModelView(model)
......
...@@ -300,12 +300,12 @@ class BaseFileAdmin(BaseView, ActionsMixin): ...@@ -300,12 +300,12 @@ class BaseFileAdmin(BaseView, ActionsMixin):
# Convert allowed_extensions to set for quick validation # Convert allowed_extensions to set for quick validation
if (self.allowed_extensions and if (self.allowed_extensions and
not isinstance(self.allowed_extensions, set)): not isinstance(self.allowed_extensions, set)):
self.allowed_extensions = set(self.allowed_extensions) self.allowed_extensions = set(self.allowed_extensions)
# Convert editable_extensions to set for quick validation # Convert editable_extensions to set for quick validation
if (self.editable_extensions and if (self.editable_extensions and
not isinstance(self.editable_extensions, set)): not isinstance(self.editable_extensions, set)):
self.editable_extensions = set(self.editable_extensions) self.editable_extensions = set(self.editable_extensions)
super(BaseFileAdmin, self).__init__(name, category, endpoint, url, super(BaseFileAdmin, self).__init__(name, category, endpoint, url,
...@@ -436,7 +436,7 @@ class BaseFileAdmin(BaseView, ActionsMixin): ...@@ -436,7 +436,7 @@ class BaseFileAdmin(BaseView, ActionsMixin):
if request.form: if request.form:
# Workaround for allowing both CSRF token + FileField to be submitted # Workaround for allowing both CSRF token + FileField to be submitted
# https://bitbucket.org/danjac/flask-wtf/issue/12/fieldlist-filefield-does-not-follow # https://bitbucket.org/danjac/flask-wtf/issue/12/fieldlist-filefield-does-not-follow
formdata = request.form.copy() # as request.form is immutable formdata = request.form.copy() # as request.form is immutable
formdata.update(request.files) formdata.update(request.files)
# admin=self allows the form to use self.is_file_allowed # admin=self allows the form to use self.is_file_allowed
...@@ -827,7 +827,7 @@ class BaseFileAdmin(BaseView, ActionsMixin): ...@@ -827,7 +827,7 @@ class BaseFileAdmin(BaseView, ActionsMixin):
# Sort by type # Sort by type
items.sort(key=itemgetter(2), reverse=True) items.sort(key=itemgetter(2), reverse=True)
# Sort by modified date # Sort by modified date
items.sort(key=lambda values: (values[0], values[1], values[2], values[3], datetime.fromtimestamp(values[4])), reverse=True) items.sort(key=lambda x: (x[0], x[1], x[2], x[3], datetime.fromtimestamp(x[4])), reverse=True)
else: else:
column_index = self.possible_columns.index(sort_column) column_index = self.possible_columns.index(sort_column)
items.sort(key=itemgetter(column_index), reverse=sort_desc) items.sort(key=itemgetter(column_index), reverse=sort_desc)
......
...@@ -55,10 +55,11 @@ class S3Storage(object): ...@@ -55,10 +55,11 @@ class S3Storage(object):
raise ValueError('Could not import boto. You can install boto by ' raise ValueError('Could not import boto. You can install boto by '
'using pip install boto') 'using pip install boto')
connection = s3.connect_to_region(region, connection = s3.connect_to_region(
aws_access_key_id=aws_access_key_id, region,
aws_secret_access_key= aws_access_key_id=aws_access_key_id,
aws_secret_access_key) aws_secret_access_key=aws_secret_access_key,
)
self.bucket = connection.get_bucket(bucket_name) self.bucket = connection.get_bucket(bucket_name)
self.separator = '/' self.separator = '/'
......
# flake8: noqa
try: try:
import geoalchemy2 import geoalchemy2
import shapely import shapely
......
...@@ -38,9 +38,9 @@ class LeafletWidget(TextArea): ...@@ -38,9 +38,9 @@ class LeafletWidget(TextArea):
kwargs.setdefault('data-geometry-type', gtype) kwargs.setdefault('data-geometry-type', gtype)
# set optional values from constructor # set optional values from constructor
if not "data-width" in kwargs: if "data-width" not in kwargs:
kwargs["data-width"] = self.width kwargs["data-width"] = self.width
if not "data-height" in kwargs: if "data-height" not in kwargs:
kwargs["data-height"] = self.height kwargs["data-height"] = self.height
if self.center: if self.center:
kwargs["data-lat"] = lat(self.center) kwargs["data-lat"] = lat(self.center)
......
# flake8: noqa
try: try:
import flask_mongoengine import flask_mongoengine
except ImportError: except ImportError:
......
...@@ -7,7 +7,6 @@ from flask_mongoengine.wtf import orm, fields as mongo_fields ...@@ -7,7 +7,6 @@ from flask_mongoengine.wtf import orm, fields as mongo_fields
from flask_admin import form from flask_admin import form
from flask_admin.model.form import FieldPlaceholder from flask_admin.model.form import FieldPlaceholder
from flask_admin.model.fields import InlineFieldList, AjaxSelectField, AjaxSelectMultipleField from flask_admin.model.fields import InlineFieldList, AjaxSelectField, AjaxSelectMultipleField
from flask_admin.model.widgets import InlineFormWidget
from flask_admin._compat import iteritems from flask_admin._compat import iteritems
from .fields import ModelFormField, MongoFileField, MongoImageField from .fields import ModelFormField, MongoFileField, MongoImageField
......
...@@ -18,6 +18,7 @@ def convert_subdocuments(values): ...@@ -18,6 +18,7 @@ def convert_subdocuments(values):
elif isinstance(p, EmbeddedForm): elif isinstance(p, EmbeddedForm):
result[name] = p result[name] = p
else: else:
raise ValueError('Invalid subdocument type: expecting dict or instance of flask_admin.contrib.mongoengine.EmbeddedForm, got %s' % type(p)) raise ValueError('Invalid subdocument type: expecting dict or '
'instance of flask_admin.contrib.mongoengine.EmbeddedForm, got %s' % type(p))
return result return result
...@@ -2,7 +2,7 @@ def parse_like_term(term): ...@@ -2,7 +2,7 @@ def parse_like_term(term):
""" """
Parse search term into (operation, term) tuple. Recognizes operators Parse search term into (operation, term) tuple. Recognizes operators
in the beginning of the search term. in the beginning of the search term.
* = case insensitive (can precede other operators) * = case insensitive (can precede other operators)
^ = starts with ^ = starts with
= = exact = = exact
...@@ -24,5 +24,5 @@ def parse_like_term(term): ...@@ -24,5 +24,5 @@ def parse_like_term(term):
oper = 'contains' oper = 'contains'
# add case insensitive flag # add case insensitive flag
if case_insensitive: if case_insensitive:
oper = 'i'+oper oper = 'i' + oper
return oper, term return oper, term
...@@ -323,7 +323,7 @@ class ModelView(BaseModelView): ...@@ -323,7 +323,7 @@ class ModelView(BaseModelView):
field_class = type(f) field_class = type(f)
if (field_class == mongoengine.ListField and if (field_class == mongoengine.ListField and
isinstance(f.field, mongoengine.EmbeddedDocumentField)): isinstance(f.field, mongoengine.EmbeddedDocumentField)):
continue continue
if field_class == mongoengine.EmbeddedDocumentField: if field_class == mongoengine.EmbeddedDocumentField:
...@@ -626,7 +626,6 @@ class ModelView(BaseModelView): ...@@ -626,7 +626,6 @@ class ModelView(BaseModelView):
return True return True
# FileField access API # FileField access API
@expose('/api/file/') @expose('/api/file/')
def api_file_view(self): def api_file_view(self):
...@@ -645,9 +644,7 @@ class ModelView(BaseModelView): ...@@ -645,9 +644,7 @@ class ModelView(BaseModelView):
return Response(data.read(), return Response(data.read(),
content_type=data.content_type, content_type=data.content_type,
headers={ headers={'Content-Length': data.length})
'Content-Length': data.length
})
# Default model actions # Default model actions
def is_action_allowed(self, name): def is_action_allowed(self, name):
......
# flake8: noqa
try: try:
import peewee import peewee
import wtfpeewee import wtfpeewee
......
...@@ -36,15 +36,22 @@ class InlineModelFormList(InlineFieldList): ...@@ -36,15 +36,22 @@ class InlineModelFormList(InlineFieldList):
def display_row_controls(self, field): def display_row_controls(self, field):
return field.get_pk() is not None return field.get_pk() is not None
# *** bryhoyt removed def process() entirely, because I believe it was buggy """ bryhoyt removed def process() entirely, because I believe it was buggy
# (but worked because another part of the code had a complimentary bug) (but worked because another part of the code had a complimentary bug)
# and I'm not sure why it was necessary anyway. and I'm not sure why it was necessary anyway.
# If we want it back in, we need to fix the following bogus query:
# self.model.select().where(attr == data).execute() # `data` is not an ID, and only happened to be so because we patched it in in .contribute() below If we want it back in, we need to fix the following bogus query:
# self.model.select().where(attr == data).execute()
# For reference:
# .process() introduced in https://github.com/flask-admin/flask-admin/commit/2845e4b28cb40b25e2bf544b327f6202dc7e5709 `data` is not an ID, and only happened to be so because we patched it
# Fixed, brokenly I think, in https://github.com/flask-admin/flask-admin/commit/4383eef3ce7eb01878f086928f8773adb9de79f8#diff-f87e7cd76fb9bc48c8681b24f238fb13R30 in in .contribute() below
For reference, .process() introduced in:
https://github.com/flask-admin/flask-admin/commit/2845e4b28cb40b25e2bf544b327f6202dc7e5709
Fixed, brokenly I think, in:
https://github.com/flask-admin/flask-admin/commit/4383eef3ce7eb01878f086928f8773adb9de79f8#diff-f87e7cd76fb9bc48c8681b24f238fb13R30
"""
def populate_obj(self, obj, name): def populate_obj(self, obj, name):
pass pass
...@@ -246,7 +253,6 @@ class InlineModelConverter(InlineModelConverterBase): ...@@ -246,7 +253,6 @@ class InlineModelConverter(InlineModelConverterBase):
allow_pk=True, allow_pk=True,
converter=converter) converter=converter)
prop_name = reverse_field.related_name prop_name = reverse_field.related_name
label = self.get_label(info, prop_name) label = self.get_label(info, prop_name)
......
def setup(): def setup():
import warnings import warnings
warnings.warn('Flask-Admin peewee integration module was renamed as flask_admin.contrib.peewee, please use it instead.') warnings.warn('Flask-Admin peewee integration module was renamed as '
'flask_admin.contrib.peewee, please use it instead.')
from flask_admin._backwards import import_redirect from flask_admin._backwards import import_redirect
import_redirect(__name__, 'flask_admin.contrib.peewee') import_redirect(__name__, 'flask_admin.contrib.peewee')
setup() setup()
del setup del setup
from ..peewee.view import ModelView from ..peewee.view import ModelView # noqa: F401
# flake8: noqa
try: try:
import pymongo import pymongo
except ImportError: except ImportError:
......
import re import re
def parse_like_term(term): def parse_like_term(term):
""" """
Parse search term into (operation, term) tuple Parse search term into (operation, term) tuple
......
...@@ -82,8 +82,10 @@ class RedisCli(BaseView): ...@@ -82,8 +82,10 @@ class RedisCli(BaseView):
self._contribute_commands() self._contribute_commands()
if self.shlex_check and VER < (2, 7, 3): if self.shlex_check and VER < (2, 7, 3):
warnings.warn('Warning: rediscli uses shlex library and it does not work with unicode until Python 2.7.3. ' + warnings.warn('Warning: rediscli uses shlex library and it does '
'To remove this warning, upgrade to Python 2.7.3 or suppress it by setting shlex_check attribute ' + 'not work with unicode until Python 2.7.3. To '
'remove this warning, upgrade to Python 2.7.3 or '
'suppress it by setting shlex_check attribute '
'to False.') 'to False.')
def _inspect_commands(self): def _inspect_commands(self):
......
# flake8: noqa
from .view import ModelView from .view import ModelView
...@@ -86,9 +86,9 @@ class FilterSmaller(BaseSQLAFilter): ...@@ -86,9 +86,9 @@ class FilterSmaller(BaseSQLAFilter):
class FilterEmpty(BaseSQLAFilter, filters.BaseBooleanFilter): class FilterEmpty(BaseSQLAFilter, filters.BaseBooleanFilter):
def apply(self, query, value, alias=None): def apply(self, query, value, alias=None):
if value == '1': if value == '1':
return query.filter(self.get_column(alias) == None) return query.filter(self.get_column(alias) == None) # noqa: E711
else: else:
return query.filter(self.get_column(alias) != None) return query.filter(self.get_column(alias) != None) # noqa: E711
def operation(self): def operation(self):
return lazy_gettext('empty') return lazy_gettext('empty')
...@@ -112,7 +112,7 @@ class FilterNotInList(FilterInList): ...@@ -112,7 +112,7 @@ class FilterNotInList(FilterInList):
def apply(self, query, value, alias=None): def apply(self, query, value, alias=None):
# NOT IN can exclude NULL values, so "or_ == None" needed to be added # NOT IN can exclude NULL values, so "or_ == None" needed to be added
column = self.get_column(alias) column = self.get_column(alias)
return query.filter(or_(~column.in_(value), column == None)) return query.filter(or_(~column.in_(value), column == None)) # noqa: E711
def operation(self): def operation(self):
return lazy_gettext('not in list') return lazy_gettext('not in list')
...@@ -323,7 +323,7 @@ class EnumFilterInList(FilterInList): ...@@ -323,7 +323,7 @@ class EnumFilterInList(FilterInList):
def clean(self, value): def clean(self, value):
values = super(EnumFilterInList, self).clean(value) values = super(EnumFilterInList, self).clean(value)
if self.enum_class is not None: if self.enum_class is not None:
values = [self.enum_class(value) for value in values] values = [self.enum_class(val) for val in values]
return values return values
...@@ -335,7 +335,7 @@ class EnumFilterNotInList(FilterNotInList): ...@@ -335,7 +335,7 @@ class EnumFilterNotInList(FilterNotInList):
def clean(self, value): def clean(self, value):
values = super(EnumFilterNotInList, self).clean(value) values = super(EnumFilterNotInList, self).clean(value)
if self.enum_class is not None: if self.enum_class is not None:
values = [self.enum_class(value) for value in values] values = [self.enum_class(val) for val in values]
return values return values
......
...@@ -201,10 +201,10 @@ class AdminModelConverter(ModelConverterBase): ...@@ -201,10 +201,10 @@ class AdminModelConverter(ModelConverterBase):
optional_types = getattr(self.view, 'form_optional_types', (Boolean,)) optional_types = getattr(self.view, 'form_optional_types', (Boolean,))
if ( if (
not column.nullable not column.nullable and
and not isinstance(column.type, optional_types) not isinstance(column.type, optional_types) and
and not column.default not column.default and
and not column.server_default not column.server_default
): ):
kwargs['validators'].append(validators.InputRequired()) kwargs['validators'].append(validators.InputRequired())
...@@ -222,7 +222,7 @@ class AdminModelConverter(ModelConverterBase): ...@@ -222,7 +222,7 @@ class AdminModelConverter(ModelConverterBase):
if value is not None: if value is not None:
if getattr(default, 'is_callable', False): if getattr(default, 'is_callable', False):
value = lambda: default.arg(None) value = lambda: default.arg(None) # noqa: E731
else: else:
if not getattr(default, 'is_scalar', True): if not getattr(default, 'is_scalar', True):
value = None value = None
...@@ -547,8 +547,6 @@ class InlineModelConverter(InlineModelConverterBase): ...@@ -547,8 +547,6 @@ class InlineModelConverter(InlineModelConverterBase):
:return: :return:
A tuple of forward property key and reverse property key A tuple of forward property key and reverse property key
""" """
mapper = model._sa_class_manager.mapper mapper = model._sa_class_manager.mapper
# Find property from target model to current model # Find property from target model to current model
......
...@@ -9,7 +9,7 @@ from sqlalchemy.exc import DBAPIError ...@@ -9,7 +9,7 @@ from sqlalchemy.exc import DBAPIError
from sqlalchemy.orm.attributes import InstrumentedAttribute from sqlalchemy.orm.attributes import InstrumentedAttribute
from flask_admin._compat import filter_list, string_types from flask_admin._compat import filter_list, string_types
from flask_admin.tools import iterencode, iterdecode, escape from flask_admin.tools import iterencode, iterdecode, escape # noqa: F401
def parse_like_term(term): def parse_like_term(term):
...@@ -79,9 +79,9 @@ def tuple_operator_in(model_pk, ids): ...@@ -79,9 +79,9 @@ def tuple_operator_in(model_pk, ids):
for id in ids: for id in ids:
k = [] k = []
for i in range(len(model_pk)): for i in range(len(model_pk)):
k.append(eq(model_pk[i],id[i])) k.append(eq(model_pk[i], id[i]))
l.append(and_(*k)) l.append(and_(*k))
if len(l)>=1: if len(l) >= 1:
return or_(*l) return or_(*l)
else: else:
return None return None
...@@ -117,10 +117,10 @@ def get_query_for_ids(modelquery, model, ids): ...@@ -117,10 +117,10 @@ def get_query_for_ids(modelquery, model, ids):
def get_columns_for_field(field): def get_columns_for_field(field):
if (not field or if (not field or
not hasattr(field, 'property') or not hasattr(field, 'property') or
not hasattr(field.property, 'columns') or not hasattr(field.property, 'columns') or
not field.property.columns): not field.property.columns):
raise Exception('Invalid field %s: does not contains any columns.' % field) raise Exception('Invalid field %s: does not contains any columns.' % field)
return field.property.columns return field.property.columns
...@@ -196,7 +196,7 @@ def is_hybrid_property(model, attr_name): ...@@ -196,7 +196,7 @@ def is_hybrid_property(model, attr_name):
if isinstance(attr_name, string_types): if isinstance(attr_name, string_types):
names = attr_name.split('.') names = attr_name.split('.')
last_model = model last_model = model
for i in range(len(names)-1): for i in range(len(names) - 1):
attr = getattr(last_model, names[i]) attr = getattr(last_model, names[i])
if is_association_proxy(attr): if is_association_proxy(attr):
attr = attr.remote_attr attr = attr.remote_attr
......
...@@ -52,7 +52,7 @@ class ModelView(BaseModelView): ...@@ -52,7 +52,7 @@ class ModelView(BaseModelView):
""" """
column_select_related_list = ObsoleteAttr('column_select_related', column_select_related_list = ObsoleteAttr('column_select_related',
'list_select_related', 'list_select_related',
None) None)
""" """
List of parameters for SQLAlchemy `subqueryload`. Overrides `column_auto_select_related` List of parameters for SQLAlchemy `subqueryload`. Overrides `column_auto_select_related`
...@@ -831,12 +831,12 @@ class ModelView(BaseModelView): ...@@ -831,12 +831,12 @@ class ModelView(BaseModelView):
if isinstance(column, tuple): if isinstance(column, tuple):
query = query.order_by(*map(desc, column)) query = query.order_by(*map(desc, column))
else: else:
query = query.order_by(desc(column)) query = query.order_by(desc(column))
else: else:
if isinstance(column, tuple): if isinstance(column, tuple):
query = query.order_by(*column) query = query.order_by(*column)
else: else:
query = query.order_by(column) query = query.order_by(column)
return query, joins return query, joins
...@@ -940,7 +940,8 @@ class ModelView(BaseModelView): ...@@ -940,7 +940,8 @@ class ModelView(BaseModelView):
spec = inspect.getargspec(flt.apply) spec = inspect.getargspec(flt.apply)
if len(spec.args) == 3: if len(spec.args) == 3:
warnings.warn('Please update your custom filter %s to include additional `alias` parameter.' % repr(flt)) warnings.warn('Please update your custom filter %s to '
'include additional `alias` parameter.' % repr(flt))
else: else:
raise raise
......
def setup(): def setup():
import warnings import warnings
warnings.warn('Flask-Admin sqlalchemy integration module was renamed as flask_admin.contrib.sqla, please use it instead.') warnings.warn('Flask-Admin sqlalchemy integration module was renamed as '
'flask_admin.contrib.sqla, please use it instead.')
from flask_admin._backwards import import_redirect from flask_admin._backwards import import_redirect
import_redirect(__name__, 'flask_admin.contrib.sqla') import_redirect(__name__, 'flask_admin.contrib.sqla')
setup() setup()
del setup del setup
from ..sqla.view import ModelView from ..sqla.view import ModelView # noqa: F401
...@@ -2,9 +2,9 @@ from wtforms import form, __version__ as wtforms_version ...@@ -2,9 +2,9 @@ from wtforms import form, __version__ as wtforms_version
from wtforms.fields.core import UnboundField from wtforms.fields.core import UnboundField
from flask_admin.babel import Translations from flask_admin.babel import Translations
from .fields import * from .fields import * # noqa: F403,F401
from .widgets import * from .widgets import * # noqa: F403,F401
from .upload import * from .upload import * # noqa: F403,F401
class BaseForm(form.Form): class BaseForm(form.Form):
......
...@@ -9,7 +9,8 @@ from flask_admin._compat import text_type, as_unicode ...@@ -9,7 +9,8 @@ from flask_admin._compat import text_type, as_unicode
from . import widgets as admin_widgets from . import widgets as admin_widgets
""" """
An understanding of WTForms's Custom Widgets is helpful for understanding this code: http://wtforms.simplecodes.com/docs/0.6.2/widgets.html#custom-widgets An understanding of WTForms's Custom Widgets is helpful for understanding this code:
http://wtforms.simplecodes.com/docs/0.6.2/widgets.html#custom-widgets
""" """
__all__ = ['DateTimeField', 'TimeField', 'Select2Field', 'Select2TagsField', __all__ = ['DateTimeField', 'TimeField', 'Select2Field', 'Select2TagsField',
...@@ -21,6 +22,7 @@ class DateTimeField(fields.DateTimeField): ...@@ -21,6 +22,7 @@ class DateTimeField(fields.DateTimeField):
Allows modifying the datetime format of a DateTimeField using form_args. Allows modifying the datetime format of a DateTimeField using form_args.
""" """
widget = admin_widgets.DateTimePickerWidget() widget = admin_widgets.DateTimePickerWidget()
def __init__(self, label=None, validators=None, format=None, **kwargs): def __init__(self, label=None, validators=None, format=None, **kwargs):
""" """
Constructor Constructor
......
...@@ -200,9 +200,7 @@ class FileUploadField(fields.StringField): ...@@ -200,9 +200,7 @@ class FileUploadField(fields.StringField):
map(lambda x: x.lower(), self.allowed_extensions)) map(lambda x: x.lower(), self.allowed_extensions))
def _is_uploaded_file(self, data): def _is_uploaded_file(self, data):
return (data return (data and isinstance(data, FileStorage) and data.filename)
and isinstance(data, FileStorage)
and data.filename)
def pre_validate(self, form): def pre_validate(self, form):
if self._is_uploaded_file(self.data) and not self.is_file_allowed(self.data.filename): if self._is_uploaded_file(self.data) and not self.is_file_allowed(self.data.filename):
...@@ -279,7 +277,7 @@ class FileUploadField(fields.StringField): ...@@ -279,7 +277,7 @@ class FileUploadField(fields.StringField):
if not op.exists(op.dirname(path)): if not op.exists(op.dirname(path)):
os.makedirs(os.path.dirname(path), self.permission | 0o111) os.makedirs(os.path.dirname(path), self.permission | 0o111)
if self._allow_overwrite == False and os.path.exists(path): if (self._allow_overwrite is False) and os.path.exists(path):
raise ValueError(gettext('File "%s" already exists.' % path)) raise ValueError(gettext('File "%s" already exists.' % path))
data.save(path) data.save(path)
......
...@@ -37,7 +37,6 @@ class Select2TagsWidget(widgets.TextInput): ...@@ -37,7 +37,6 @@ class Select2TagsWidget(widgets.TextInput):
return super(Select2TagsWidget, self).__call__(field, **kwargs) return super(Select2TagsWidget, self).__call__(field, **kwargs)
class DatePickerWidget(widgets.TextInput): class DatePickerWidget(widgets.TextInput):
""" """
Date picker widget. Date picker widget.
......
...@@ -101,6 +101,7 @@ def flash_errors(form, message): ...@@ -101,6 +101,7 @@ def flash_errors(form, message):
errors = form[field_name].label.text + u": " + u", ".join(errors) errors = form[field_name].label.text + u": " + u", ".join(errors)
flash(gettext(message, error=str(errors)), 'error') flash(gettext(message, error=str(errors)), 'error')
@contextfunction @contextfunction
def resolve_ctx(context): def resolve_ctx(context):
""" """
......
# flake8: noqa
from .base import BaseModelView from .base import BaseModelView
from .form import InlineFormAdmin from .form import InlineFormAdmin
from flask_admin.actions import action from flask_admin.actions import action
...@@ -42,7 +42,8 @@ class ViewArgs(object): ...@@ -42,7 +42,8 @@ class ViewArgs(object):
""" """
List view arguments. List view arguments.
""" """
def __init__(self, page=None, page_size=None, sort=None, sort_desc=None, search=None, filters=None, extra_args=None): def __init__(self, page=None, page_size=None, sort=None, sort_desc=None,
search=None, filters=None, extra_args=None):
self.page = page self.page = page
self.page_size = page_size self.page_size = page_size
self.sort = sort self.sort = sort
...@@ -599,7 +600,10 @@ class BaseModelView(BaseView, ActionsMixin): ...@@ -599,7 +600,10 @@ class BaseModelView(BaseView, ActionsMixin):
start=dict(format='%Y-%m-%d %I:%M %p') # changes how the input is parsed by strptime (12 hour time) start=dict(format='%Y-%m-%d %I:%M %p') # changes how the input is parsed by strptime (12 hour time)
) )
form_widget_args = dict( form_widget_args = dict(
start={'data-date-format': u'yyyy-mm-dd HH:ii P', 'data-show-meridian': 'True'} # changes how the DateTimeField displays the time start={
'data-date-format': u'yyyy-mm-dd HH:ii P',
'data-show-meridian': 'True'
} # changes how the DateTimeField displays the time
) )
""" """
...@@ -939,7 +943,8 @@ class BaseModelView(BaseView, ActionsMixin): ...@@ -939,7 +943,8 @@ class BaseModelView(BaseView, ActionsMixin):
def get_list_row_actions(self): def get_list_row_actions(self):
""" """
Return list of row action objects, each is instance of :class:`~flask_admin.model.template.BaseListRowAction` Return list of row action objects, each is instance of
:class:`~flask_admin.model.template.BaseListRowAction`
""" """
actions = [] actions = []
...@@ -2099,7 +2104,7 @@ class BaseModelView(BaseView, ActionsMixin): ...@@ -2099,7 +2104,7 @@ class BaseModelView(BaseView, ActionsMixin):
form = self.delete_form() form = self.delete_form()
if self.validate_form(form): if self.validate_form(form):
# id is InputRequired() # id is InputRequired()
id = form.id.data id = form.id.data
model = self.get_one(id) model = self.get_one(id)
......
...@@ -248,10 +248,10 @@ class BaseTimeBetweenFilter(BaseFilter): ...@@ -248,10 +248,10 @@ class BaseTimeBetweenFilter(BaseFilter):
def clean(self, value): def clean(self, value):
timetuples = [time.strptime(range, '%H:%M:%S') timetuples = [time.strptime(range, '%H:%M:%S')
for range in value.split(' to ')] for range in value.split(' to ')]
return [datetime.time(timetuple.tm_hour, return [
timetuple.tm_min, datetime.time(timetuple.tm_hour, timetuple.tm_min, timetuple.tm_sec)
timetuple.tm_sec) for timetuple in timetuples
for timetuple in timetuples] ]
def operation(self): def operation(self):
return lazy_gettext('between') return lazy_gettext('between')
......
...@@ -9,6 +9,7 @@ def prettify_name(name): ...@@ -9,6 +9,7 @@ def prettify_name(name):
""" """
return name.replace('_', ' ').title() return name.replace('_', ' ').title()
def get_mdict_item_or_list(mdict, key): def get_mdict_item_or_list(mdict, key):
""" """
Return the value for the given key of the multidict. Return the value for the given key of the multidict.
......
...@@ -126,4 +126,3 @@ def macro(name): ...@@ -126,4 +126,3 @@ def macro(name):
return m(model=model, column=column) return m(model=model, column=column)
return inner return inner
...@@ -134,6 +134,7 @@ def test_file_admin(): ...@@ -134,6 +134,7 @@ def test_file_admin():
ok_('path=dummy_renamed_dir' not in rv.data.decode('utf-8')) ok_('path=dummy_renamed_dir' not in rv.data.decode('utf-8'))
ok_('path=dummy.txt' in rv.data.decode('utf-8')) ok_('path=dummy.txt' in rv.data.decode('utf-8'))
def test_modal_edit(): def test_modal_edit():
# bootstrap 2 - test edit_modal # bootstrap 2 - test edit_modal
app_bs2 = Flask(__name__) app_bs2 = Flask(__name__)
......
...@@ -64,7 +64,8 @@ def test_model(): ...@@ -64,7 +64,8 @@ def test_model():
"name": "test1", "name": "test1",
"point": '{"type": "Point", "coordinates": [125.8, 10.0]}', "point": '{"type": "Point", "coordinates": [125.8, 10.0]}',
"line": '{"type": "LineString", "coordinates": [[50.2345, 94.2], [50.21, 94.87]]}', "line": '{"type": "LineString", "coordinates": [[50.2345, 94.2], [50.21, 94.87]]}',
"polygon": '{"type": "Polygon", "coordinates": [[[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]]]}', "polygon": ('{"type": "Polygon", "coordinates": [[[100.0, 0.0], [101.0, 0.0],'
' [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]]]}'),
"multi": '{"type": "MultiPoint", "coordinates": [[100.0, 0.0], [101.0, 1.0]]}', "multi": '{"type": "MultiPoint", "coordinates": [[100.0, 0.0], [101.0, 1.0]]}',
}) })
eq_(rv.status_code, 302) eq_(rv.status_code, 302)
......
...@@ -61,8 +61,8 @@ def fill_db(Model1, Model2): ...@@ -61,8 +61,8 @@ def fill_db(Model1, Model2):
Model2('string_field_val_4', 9000, 75.5).save() Model2('string_field_val_4', 9000, 75.5).save()
Model2('string_field_val_5', 6169453081680413441).save() Model2('string_field_val_5', 6169453081680413441).save()
Model1('datetime_obj1', datetime_field=datetime(2014,4,3,1,9,0)).save() Model1('datetime_obj1', datetime_field=datetime(2014, 4, 3, 1, 9, 0)).save()
Model1('datetime_obj2', datetime_field=datetime(2013,3,2,0,8,0)).save() Model1('datetime_obj2', datetime_field=datetime(2013, 3, 2, 0, 8, 0)).save()
def test_model(): def test_model():
...@@ -157,7 +157,7 @@ def test_column_editable_list(): ...@@ -157,7 +157,7 @@ def test_column_editable_list():
ok_('data-role="x-editable"' in data) ok_('data-role="x-editable"' in data)
# Form - Test basic in-line edit functionality # Form - Test basic in-line edit functionality
obj1 = Model1.objects.get(test1 = 'test1_val_3') obj1 = Model1.objects.get(test1='test1_val_3')
rv = client.post('/admin/model1/ajax/update/', data={ rv = client.post('/admin/model1/ajax/update/', data={
'list_form_pk': str(obj1.id), 'list_form_pk': str(obj1.id),
'test1': 'change-success-1', 'test1': 'change-success-1',
...@@ -171,7 +171,7 @@ def test_column_editable_list(): ...@@ -171,7 +171,7 @@ def test_column_editable_list():
ok_('change-success-1' in data) ok_('change-success-1' in data)
# Test validation error # Test validation error
obj2 = Model1.objects.get(test1 = 'datetime_obj1') obj2 = Model1.objects.get(test1='datetime_obj1')
rv = client.post('/admin/model1/ajax/update/', data={ rv = client.post('/admin/model1/ajax/update/', data={
'list_form_pk': str(obj2.id), 'list_form_pk': str(obj2.id),
'datetime_field': 'problematic-input', 'datetime_field': 'problematic-input',
...@@ -198,7 +198,7 @@ def test_column_editable_list(): ...@@ -198,7 +198,7 @@ def test_column_editable_list():
view = CustomModelView(Model2, column_editable_list=['model1']) view = CustomModelView(Model2, column_editable_list=['model1'])
admin.add_view(view) admin.add_view(view)
obj3 = Model2.objects.get(string_field = 'string_field_val_1') obj3 = Model2.objects.get(string_field='string_field_val_1')
rv = client.post('/admin/model2/ajax/update/', data={ rv = client.post('/admin/model2/ajax/update/', data={
'list_form_pk': str(obj3.id), 'list_form_pk': str(obj3.id),
'model1': str(obj1.id), 'model1': str(obj1.id),
...@@ -283,7 +283,8 @@ def test_column_filters(): ...@@ -283,7 +283,8 @@ def test_column_filters():
eq_(len(view._filters), 7) eq_(len(view._filters), 7)
eq_([(f['index'], f['operation']) for f in view._filter_groups[u'Test1']], eq_(
[(f['index'], f['operation']) for f in view._filter_groups[u'Test1']],
[ [
(0, 'contains'), (0, 'contains'),
(1, 'not contains'), (1, 'not contains'),
...@@ -292,7 +293,8 @@ def test_column_filters(): ...@@ -292,7 +293,8 @@ def test_column_filters():
(4, 'empty'), (4, 'empty'),
(5, 'in list'), (5, 'in list'),
(6, 'not in list'), (6, 'not in list'),
]) ]
)
# Make some test clients # Make some test clients
client = app.test_client() client = app.test_client()
...@@ -363,7 +365,8 @@ def test_column_filters(): ...@@ -363,7 +365,8 @@ def test_column_filters():
view = CustomModelView(Model2, column_filters=['int_field']) view = CustomModelView(Model2, column_filters=['int_field'])
admin.add_view(view) admin.add_view(view)
eq_([(f['index'], f['operation']) for f in view._filter_groups[u'Int Field']], eq_(
[(f['index'], f['operation']) for f in view._filter_groups[u'Int Field']],
[ [
(0, 'equals'), (0, 'equals'),
(1, 'not equal'), (1, 'not equal'),
...@@ -372,7 +375,8 @@ def test_column_filters(): ...@@ -372,7 +375,8 @@ def test_column_filters():
(4, 'empty'), (4, 'empty'),
(5, 'in list'), (5, 'in list'),
(6, 'not in list'), (6, 'not in list'),
]) ]
)
# integer - equals # integer - equals
rv = client.get('/admin/model2/?flt0_0=5000') rv = client.get('/admin/model2/?flt0_0=5000')
...@@ -469,11 +473,13 @@ def test_column_filters(): ...@@ -469,11 +473,13 @@ def test_column_filters():
endpoint="_bools") endpoint="_bools")
admin.add_view(view) admin.add_view(view)
eq_([(f['index'], f['operation']) for f in view._filter_groups[u'Bool Field']], eq_(
[(f['index'], f['operation']) for f in view._filter_groups[u'Bool Field']],
[ [
(0, 'equals'), (0, 'equals'),
(1, 'not equal'), (1, 'not equal'),
]) ]
)
# boolean - equals - Yes # boolean - equals - Yes
rv = client.get('/admin/_bools/?flt0_0=1') rv = client.get('/admin/_bools/?flt0_0=1')
...@@ -481,7 +487,6 @@ def test_column_filters(): ...@@ -481,7 +487,6 @@ def test_column_filters():
data = rv.data.decode('utf-8') data = rv.data.decode('utf-8')
ok_('string_field_val_1' in data) ok_('string_field_val_1' in data)
ok_('string_field_val_2' not in data) ok_('string_field_val_2' not in data)
#ok_('string_field_val_3' not in data)
# boolean - equals - No # boolean - equals - No
rv = client.get('/admin/_bools/?flt0_0=0') rv = client.get('/admin/_bools/?flt0_0=0')
...@@ -489,7 +494,6 @@ def test_column_filters(): ...@@ -489,7 +494,6 @@ def test_column_filters():
data = rv.data.decode('utf-8') data = rv.data.decode('utf-8')
ok_('string_field_val_1' not in data) ok_('string_field_val_1' not in data)
ok_('string_field_val_2' in data) ok_('string_field_val_2' in data)
#ok_('string_field_val_3' in data)
# boolean - not equals - Yes # boolean - not equals - Yes
rv = client.get('/admin/_bools/?flt0_1=1') rv = client.get('/admin/_bools/?flt0_1=1')
...@@ -497,7 +501,6 @@ def test_column_filters(): ...@@ -497,7 +501,6 @@ def test_column_filters():
data = rv.data.decode('utf-8') data = rv.data.decode('utf-8')
ok_('string_field_val_1' not in data) ok_('string_field_val_1' not in data)
ok_('string_field_val_2' in data) ok_('string_field_val_2' in data)
#ok_('string_field_val_3' in data)
# boolean - not equals - No # boolean - not equals - No
rv = client.get('/admin/_bools/?flt0_1=0') rv = client.get('/admin/_bools/?flt0_1=0')
...@@ -505,14 +508,14 @@ def test_column_filters(): ...@@ -505,14 +508,14 @@ def test_column_filters():
data = rv.data.decode('utf-8') data = rv.data.decode('utf-8')
ok_('string_field_val_1' in data) ok_('string_field_val_1' in data)
ok_('string_field_val_2' not in data) ok_('string_field_val_2' not in data)
#ok_('string_field_val_3' not in data)
# Test float filter # Test float filter
view = CustomModelView(Model2, column_filters=['float_field'], view = CustomModelView(Model2, column_filters=['float_field'],
endpoint="_float") endpoint="_float")
admin.add_view(view) admin.add_view(view)
eq_([(f['index'], f['operation']) for f in view._filter_groups[u'Float Field']], eq_(
[(f['index'], f['operation']) for f in view._filter_groups[u'Float Field']],
[ [
(0, 'equals'), (0, 'equals'),
(1, 'not equal'), (1, 'not equal'),
...@@ -521,7 +524,8 @@ def test_column_filters(): ...@@ -521,7 +524,8 @@ def test_column_filters():
(4, 'empty'), (4, 'empty'),
(5, 'in list'), (5, 'in list'),
(6, 'not in list'), (6, 'not in list'),
]) ]
)
# float - equals # float - equals
rv = client.get('/admin/_float/?flt0_0=25.9') rv = client.get('/admin/_float/?flt0_0=25.9')
...@@ -605,7 +609,8 @@ def test_column_filters(): ...@@ -605,7 +609,8 @@ def test_column_filters():
endpoint="_datetime") endpoint="_datetime")
admin.add_view(view) admin.add_view(view)
eq_([(f['index'], f['operation']) for f in view._filter_groups[u'Datetime Field']], eq_(
[(f['index'], f['operation']) for f in view._filter_groups[u'Datetime Field']],
[ [
(0, 'equals'), (0, 'equals'),
(1, 'not equal'), (1, 'not equal'),
...@@ -614,7 +619,8 @@ def test_column_filters(): ...@@ -614,7 +619,8 @@ def test_column_filters():
(4, 'between'), (4, 'between'),
(5, 'not between'), (5, 'not between'),
(6, 'empty'), (6, 'empty'),
]) ]
)
# datetime - equals # datetime - equals
rv = client.get('/admin/_datetime/?flt0_0=2014-04-03+01%3A09%3A00') rv = client.get('/admin/_datetime/?flt0_0=2014-04-03+01%3A09%3A00')
...@@ -674,6 +680,7 @@ def test_column_filters(): ...@@ -674,6 +680,7 @@ def test_column_filters():
ok_('datetime_obj1' in data) ok_('datetime_obj1' in data)
ok_('datetime_obj2' in data) ok_('datetime_obj2' in data)
def test_default_sort(): def test_default_sort():
app, db, admin = setup() app, db, admin = setup()
M1, _ = create_models(db) M1, _ = create_models(db)
...@@ -780,7 +787,7 @@ def test_subdocument_config(): ...@@ -780,7 +787,7 @@ def test_subdocument_config():
# Check only # Check only
view1 = CustomModelView( view1 = CustomModelView(
Model1, Model1,
form_subdocuments = { form_subdocuments={
'subdoc': { 'subdoc': {
'form_columns': ('name',) 'form_columns': ('name',)
} }
...@@ -796,7 +803,7 @@ def test_subdocument_config(): ...@@ -796,7 +803,7 @@ def test_subdocument_config():
# Check exclude # Check exclude
view2 = CustomModelView( view2 = CustomModelView(
Model1, Model1,
form_subdocuments = { form_subdocuments={
'subdoc': { 'subdoc': {
'form_excluded_columns': ('value',) 'form_excluded_columns': ('value',)
} }
...@@ -827,7 +834,7 @@ def test_subdocument_class_config(): ...@@ -827,7 +834,7 @@ def test_subdocument_class_config():
# Check only # Check only
view1 = CustomModelView( view1 = CustomModelView(
Model1, Model1,
form_subdocuments = { form_subdocuments={
'subdoc': EmbeddedConfig() 'subdoc': EmbeddedConfig()
} }
) )
...@@ -855,7 +862,7 @@ def test_nested_subdocument_config(): ...@@ -855,7 +862,7 @@ def test_nested_subdocument_config():
view1 = CustomModelView( view1 = CustomModelView(
Model1, Model1,
form_subdocuments = { form_subdocuments={
'nested': { 'nested': {
'form_subdocuments': { 'form_subdocuments': {
'comment': { 'comment': {
...@@ -885,7 +892,7 @@ def test_nested_list_subdocument(): ...@@ -885,7 +892,7 @@ def test_nested_list_subdocument():
# Check only # Check only
view1 = CustomModelView( view1 = CustomModelView(
Model1, Model1,
form_subdocuments = { form_subdocuments={
'subdoc': { 'subdoc': {
'form_subdocuments': { 'form_subdocuments': {
None: { None: {
...@@ -918,14 +925,13 @@ def test_nested_sortedlist_subdocument(): ...@@ -918,14 +925,13 @@ def test_nested_sortedlist_subdocument():
# Check only # Check only
view1 = CustomModelView( view1 = CustomModelView(
Model1, Model1,
form_subdocuments = { form_subdocuments={
'subdoc': { 'subdoc': {
'form_subdocuments': { 'form_subdocuments': {
None: { None: {
'form_columns': ('name',) 'form_columns': ('name',)
} }
} }
} }
} }
) )
...@@ -961,6 +967,7 @@ def test_sortedlist_subdocument_validation(): ...@@ -961,6 +967,7 @@ def test_sortedlist_subdocument_validation():
eq_(rv.status_code, 200) eq_(rv.status_code, 200)
ok_('This field is required' in rv.data) ok_('This field is required' in rv.data)
def test_list_subdocument_validation(): def test_list_subdocument_validation():
app, db, admin = setup() app, db, admin = setup()
...@@ -985,6 +992,7 @@ def test_list_subdocument_validation(): ...@@ -985,6 +992,7 @@ def test_list_subdocument_validation():
eq_(rv.status_code, 200) eq_(rv.status_code, 200)
ok_('This field is required' in rv.data) ok_('This field is required' in rv.data)
def test_ajax_fk(): def test_ajax_fk():
app, db, admin = setup() app, db, admin = setup()
...@@ -1066,7 +1074,7 @@ def test_nested_ajax_refs(): ...@@ -1066,7 +1074,7 @@ def test_nested_ajax_refs():
view1 = CustomModelView( view1 = CustomModelView(
Model1, Model1,
form_subdocuments = { form_subdocuments={
'nested': { 'nested': {
'form_ajax_refs': { 'form_ajax_refs': {
'comment': { 'comment': {
...@@ -1127,7 +1135,7 @@ def test_form_args_embeddeddoc(): ...@@ -1127,7 +1135,7 @@ def test_form_args_embeddeddoc():
view = CustomModelView( view = CustomModelView(
Model, Model,
form_args= { form_args={
'info': {'label': 'Information'}, 'info': {'label': 'Information'},
'timestamp': {'label': 'Last Updated Time'} 'timestamp': {'label': 'Last Updated Time'}
} }
......
...@@ -100,12 +100,12 @@ def fill_db(Model1, Model2): ...@@ -100,12 +100,12 @@ def fill_db(Model1, Model2):
Model2('char_field_val_4', 9000, 75.5).save() Model2('char_field_val_4', 9000, 75.5).save()
Model2('char_field_val_5', 6169453081680413441).save() Model2('char_field_val_5', 6169453081680413441).save()
Model1('date_obj1', date_field=date(2014,11,17)).save() Model1('date_obj1', date_field=date(2014, 11, 17)).save()
Model1('date_obj2', date_field=date(2013,10,16)).save() Model1('date_obj2', date_field=date(2013, 10, 16)).save()
Model1('timeonly_obj1', timeonly_field=time(11,10,9)).save() Model1('timeonly_obj1', timeonly_field=time(11, 10, 9)).save()
Model1('timeonly_obj2', timeonly_field=time(10,9,8)).save() Model1('timeonly_obj2', timeonly_field=time(10, 9, 8)).save()
Model1('datetime_obj1', datetime_field=datetime(2014,4,3,1,9,0)).save() Model1('datetime_obj1', datetime_field=datetime(2014, 4, 3, 1, 9, 0)).save()
Model1('datetime_obj2', datetime_field=datetime(2013,3,2,0,8,0)).save() Model1('datetime_obj2', datetime_field=datetime(2013, 3, 2, 0, 8, 0)).save()
def test_model(): def test_model():
...@@ -216,7 +216,8 @@ def test_column_editable_list(): ...@@ -216,7 +216,8 @@ def test_column_editable_list():
# Test validation error # Test validation error
rv = client.post('/admin/model1/ajax/update/', data={ rv = client.post('/admin/model1/ajax/update/', data={
'list_form_pk': '1', 'list_form_pk': '1',
'test1': 'longerthantwentycharacterslongerthantwentycharacterslongerthantwentycharacterslongerthantwentycharacters', 'test1': ('longerthantwentycharacterslongerthantwentycharacterslonger'
'thantwentycharacterslongerthantwentycharacters'),
}) })
data = rv.data.decode('utf-8') data = rv.data.decode('utf-8')
eq_(rv.status_code, 500) eq_(rv.status_code, 500)
...@@ -320,7 +321,8 @@ def test_column_filters(): ...@@ -320,7 +321,8 @@ def test_column_filters():
eq_(len(view._filters), 7) eq_(len(view._filters), 7)
eq_([(f['index'], f['operation']) for f in view._filter_groups[u'Test1']], eq_(
[(f['index'], f['operation']) for f in view._filter_groups[u'Test1']],
[ [
(0, 'contains'), (0, 'contains'),
(1, 'not contains'), (1, 'not contains'),
...@@ -329,7 +331,8 @@ def test_column_filters(): ...@@ -329,7 +331,8 @@ def test_column_filters():
(4, 'empty'), (4, 'empty'),
(5, 'in list'), (5, 'in list'),
(6, 'not in list'), (6, 'not in list'),
]) ]
)
# Make some test clients # Make some test clients
client = app.test_client() client = app.test_client()
...@@ -400,7 +403,8 @@ def test_column_filters(): ...@@ -400,7 +403,8 @@ def test_column_filters():
view = CustomModelView(Model2, column_filters=['int_field']) view = CustomModelView(Model2, column_filters=['int_field'])
admin.add_view(view) admin.add_view(view)
eq_([(f['index'], f['operation']) for f in view._filter_groups[u'Int Field']], eq_(
[(f['index'], f['operation']) for f in view._filter_groups[u'Int Field']],
[ [
(0, 'equals'), (0, 'equals'),
(1, 'not equal'), (1, 'not equal'),
...@@ -409,7 +413,8 @@ def test_column_filters(): ...@@ -409,7 +413,8 @@ def test_column_filters():
(4, 'empty'), (4, 'empty'),
(5, 'in list'), (5, 'in list'),
(6, 'not in list'), (6, 'not in list'),
]) ]
)
# integer - equals # integer - equals
rv = client.get('/admin/model2/?flt0_0=5000') rv = client.get('/admin/model2/?flt0_0=5000')
...@@ -506,11 +511,13 @@ def test_column_filters(): ...@@ -506,11 +511,13 @@ def test_column_filters():
endpoint="_bools") endpoint="_bools")
admin.add_view(view) admin.add_view(view)
eq_([(f['index'], f['operation']) for f in view._filter_groups[u'Bool Field']], eq_(
[(f['index'], f['operation']) for f in view._filter_groups[u'Bool Field']],
[ [
(0, 'equals'), (0, 'equals'),
(1, 'not equal'), (1, 'not equal'),
]) ]
)
# boolean - equals - Yes # boolean - equals - Yes
rv = client.get('/admin/_bools/?flt0_0=1') rv = client.get('/admin/_bools/?flt0_0=1')
...@@ -549,7 +556,8 @@ def test_column_filters(): ...@@ -549,7 +556,8 @@ def test_column_filters():
endpoint="_float") endpoint="_float")
admin.add_view(view) admin.add_view(view)
eq_([(f['index'], f['operation']) for f in view._filter_groups[u'Float Field']], eq_(
[(f['index'], f['operation']) for f in view._filter_groups[u'Float Field']],
[ [
(0, 'equals'), (0, 'equals'),
(1, 'not equal'), (1, 'not equal'),
...@@ -558,7 +566,8 @@ def test_column_filters(): ...@@ -558,7 +566,8 @@ def test_column_filters():
(4, 'empty'), (4, 'empty'),
(5, 'in list'), (5, 'in list'),
(6, 'not in list'), (6, 'not in list'),
]) ]
)
# float - equals # float - equals
rv = client.get('/admin/_float/?flt0_0=25.9') rv = client.get('/admin/_float/?flt0_0=25.9')
...@@ -642,7 +651,8 @@ def test_column_filters(): ...@@ -642,7 +651,8 @@ def test_column_filters():
endpoint="_datetime") endpoint="_datetime")
admin.add_view(view) admin.add_view(view)
eq_([(f['index'], f['operation']) for f in view._filter_groups[u'Date Field']], eq_(
[(f['index'], f['operation']) for f in view._filter_groups[u'Date Field']],
[ [
(0, 'equals'), (0, 'equals'),
(1, 'not equal'), (1, 'not equal'),
...@@ -651,9 +661,11 @@ def test_column_filters(): ...@@ -651,9 +661,11 @@ def test_column_filters():
(4, 'between'), (4, 'between'),
(5, 'not between'), (5, 'not between'),
(6, 'empty'), (6, 'empty'),
]) ]
)
eq_([(f['index'], f['operation']) for f in view._filter_groups[u'Datetime Field']], eq_(
[(f['index'], f['operation']) for f in view._filter_groups[u'Datetime Field']],
[ [
(7, 'equals'), (7, 'equals'),
(8, 'not equal'), (8, 'not equal'),
...@@ -662,9 +674,11 @@ def test_column_filters(): ...@@ -662,9 +674,11 @@ def test_column_filters():
(11, 'between'), (11, 'between'),
(12, 'not between'), (12, 'not between'),
(13, 'empty'), (13, 'empty'),
]) ]
)
eq_([(f['index'], f['operation']) for f in view._filter_groups[u'Timeonly Field']], eq_(
[(f['index'], f['operation']) for f in view._filter_groups[u'Timeonly Field']],
[ [
(14, 'equals'), (14, 'equals'),
(15, 'not equal'), (15, 'not equal'),
...@@ -673,7 +687,8 @@ def test_column_filters(): ...@@ -673,7 +687,8 @@ def test_column_filters():
(18, 'between'), (18, 'between'),
(19, 'not between'), (19, 'not between'),
(20, 'empty'), (20, 'empty'),
]) ]
)
# date - equals # date - equals
rv = client.get('/admin/_datetime/?flt0_0=2014-11-17') rv = client.get('/admin/_datetime/?flt0_0=2014-11-17')
...@@ -849,6 +864,7 @@ def test_column_filters(): ...@@ -849,6 +864,7 @@ def test_column_filters():
ok_('timeonly_obj1' in data) ok_('timeonly_obj1' in data)
ok_('timeonly_obj2' in data) ok_('timeonly_obj2' in data)
def test_default_sort(): def test_default_sort():
app, db, admin = setup() app, db, admin = setup()
M1, _ = create_models(db) M1, _ = create_models(db)
......
...@@ -15,6 +15,7 @@ def setup(): ...@@ -15,6 +15,7 @@ def setup():
return app, db, admin return app, db, admin
def setup_postgres(): def setup_postgres():
app = Flask(__name__) app = Flask(__name__)
app.config['SECRET_KEY'] = '1' app.config['SECRET_KEY'] = '1'
......
...@@ -103,12 +103,12 @@ def fill_db(db, Model1, Model2): ...@@ -103,12 +103,12 @@ def fill_db(db, Model1, Model2):
model2_obj4 = Model2('test2_val_4', int_field=9000, float_field=75.5) model2_obj4 = Model2('test2_val_4', int_field=9000, float_field=75.5)
model2_obj5 = Model2('test2_val_5', int_field=6169453081680413441) model2_obj5 = Model2('test2_val_5', int_field=6169453081680413441)
date_obj1 = Model1('date_obj1', date_field=date(2014,11,17)) date_obj1 = Model1('date_obj1', date_field=date(2014, 11, 17))
date_obj2 = Model1('date_obj2', date_field=date(2013,10,16)) date_obj2 = Model1('date_obj2', date_field=date(2013, 10, 16))
timeonly_obj1 = Model1('timeonly_obj1', time_field=time(11,10,9)) timeonly_obj1 = Model1('timeonly_obj1', time_field=time(11, 10, 9))
timeonly_obj2 = Model1('timeonly_obj2', time_field=time(10,9,8)) timeonly_obj2 = Model1('timeonly_obj2', time_field=time(10, 9, 8))
datetime_obj1 = Model1('datetime_obj1', datetime_field=datetime(2014,4,3,1,9,0)) datetime_obj1 = Model1('datetime_obj1', datetime_field=datetime(2014, 4, 3, 1, 9, 0))
datetime_obj2 = Model1('datetime_obj2', datetime_field=datetime(2013,3,2,0,8,0)) datetime_obj2 = Model1('datetime_obj2', datetime_field=datetime(2013, 3, 2, 0, 8, 0))
enum_obj1 = Model1('enum_obj1', enum_field="model1_v1") enum_obj1 = Model1('enum_obj1', enum_field="model1_v1")
enum_obj2 = Model1('enum_obj2', enum_field="model1_v2") enum_obj2 = Model1('enum_obj2', enum_field="model1_v2")
...@@ -166,7 +166,7 @@ def test_model(): ...@@ -166,7 +166,7 @@ def test_model():
rv = client.post('/admin/model1/new/', rv = client.post('/admin/model1/new/',
data=dict(test1='test1large', data=dict(test1='test1large',
test2='test2', test2='test2',
time_field=time(0,0,0))) time_field=time(0, 0, 0)))
eq_(rv.status_code, 302) eq_(rv.status_code, 302)
model = db.session.query(Model1).first() model = db.session.query(Model1).first()
...@@ -356,7 +356,7 @@ def test_complex_searchable_list(): ...@@ -356,7 +356,7 @@ def test_complex_searchable_list():
ok_('model2-test2-val' not in data) ok_('model2-test2-val' not in data)
view2 = CustomModelView(Model1, db.session, view2 = CustomModelView(Model1, db.session,
column_searchable_list=[Model2.string_field]) column_searchable_list=[Model2.string_field])
admin.add_view(view2) admin.add_view(view2)
# test relation object - Model2.string_field # test relation object - Model2.string_field
...@@ -562,7 +562,8 @@ def test_column_filters(): ...@@ -562,7 +562,8 @@ def test_column_filters():
eq_(len(view._filters), 7) eq_(len(view._filters), 7)
eq_([(f['index'], f['operation']) for f in view._filter_groups[u'Test1']], eq_(
[(f['index'], f['operation']) for f in view._filter_groups[u'Test1']],
[ [
(0, u'contains'), (0, u'contains'),
(1, u'not contains'), (1, u'not contains'),
...@@ -571,13 +572,15 @@ def test_column_filters(): ...@@ -571,13 +572,15 @@ def test_column_filters():
(4, u'empty'), (4, u'empty'),
(5, u'in list'), (5, u'in list'),
(6, u'not in list'), (6, u'not in list'),
]) ]
)
# Test filter that references property # Test filter that references property
view = CustomModelView(Model2, db.session, view = CustomModelView(Model2, db.session,
column_filters=['model1']) column_filters=['model1'])
eq_([(f['index'], f['operation']) for f in view._filter_groups[u'Model1 / Test1']], eq_(
[(f['index'], f['operation']) for f in view._filter_groups[u'Model1 / Test1']],
[ [
(0, u'contains'), (0, u'contains'),
(1, u'not contains'), (1, u'not contains'),
...@@ -586,9 +589,11 @@ def test_column_filters(): ...@@ -586,9 +589,11 @@ def test_column_filters():
(4, u'empty'), (4, u'empty'),
(5, u'in list'), (5, u'in list'),
(6, u'not in list'), (6, u'not in list'),
]) ]
)
eq_([(f['index'], f['operation']) for f in view._filter_groups[u'Model1 / Test2']], eq_(
[(f['index'], f['operation']) for f in view._filter_groups[u'Model1 / Test2']],
[ [
(7, u'contains'), (7, u'contains'),
(8, u'not contains'), (8, u'not contains'),
...@@ -597,9 +602,11 @@ def test_column_filters(): ...@@ -597,9 +602,11 @@ def test_column_filters():
(11, u'empty'), (11, u'empty'),
(12, u'in list'), (12, u'in list'),
(13, u'not in list'), (13, u'not in list'),
]) ]
)
eq_([(f['index'], f['operation']) for f in view._filter_groups[u'Model1 / Test3']], eq_(
[(f['index'], f['operation']) for f in view._filter_groups[u'Model1 / Test3']],
[ [
(14, u'contains'), (14, u'contains'),
(15, u'not contains'), (15, u'not contains'),
...@@ -608,9 +615,11 @@ def test_column_filters(): ...@@ -608,9 +615,11 @@ def test_column_filters():
(18, u'empty'), (18, u'empty'),
(19, u'in list'), (19, u'in list'),
(20, u'not in list'), (20, u'not in list'),
]) ]
)
eq_([(f['index'], f['operation']) for f in view._filter_groups[u'Model1 / Test4']], eq_(
[(f['index'], f['operation']) for f in view._filter_groups[u'Model1 / Test4']],
[ [
(21, u'contains'), (21, u'contains'),
(22, u'not contains'), (22, u'not contains'),
...@@ -619,32 +628,39 @@ def test_column_filters(): ...@@ -619,32 +628,39 @@ def test_column_filters():
(25, u'empty'), (25, u'empty'),
(26, u'in list'), (26, u'in list'),
(27, u'not in list'), (27, u'not in list'),
]) ]
)
eq_([(f['index'], f['operation']) for f in view._filter_groups[u'Model1 / Bool Field']], eq_(
[(f['index'], f['operation']) for f in view._filter_groups[u'Model1 / Bool Field']],
[ [
(28, u'equals'), (28, u'equals'),
(29, u'not equal'), (29, u'not equal'),
]) ]
)
eq_([(f['index'], f['operation']) for f in view._filter_groups[u'Model1 / Enum Field']], eq_(
[(f['index'], f['operation']) for f in view._filter_groups[u'Model1 / Enum Field']],
[ [
(30, u'equals'), (30, u'equals'),
(31, u'not equal'), (31, u'not equal'),
(32, u'empty'), (32, u'empty'),
(33, u'in list'), (33, u'in list'),
(34, u'not in list'), (34, u'not in list'),
]) ]
)
# Test filter with a dot # Test filter with a dot
view = CustomModelView(Model2, db.session, view = CustomModelView(Model2, db.session,
column_filters=['model1.bool_field']) column_filters=['model1.bool_field'])
eq_([(f['index'], f['operation']) for f in view._filter_groups[u'model1 / Model1 / Bool Field']], eq_(
[(f['index'], f['operation']) for f in view._filter_groups[u'model1 / Model1 / Bool Field']],
[ [
(0, 'equals'), (0, 'equals'),
(1, 'not equal'), (1, 'not equal'),
]) ]
)
# Test column_labels on filters # Test column_labels on filters
view = CustomModelView(Model2, db.session, view = CustomModelView(Model2, db.session,
...@@ -681,7 +697,8 @@ def test_column_filters(): ...@@ -681,7 +697,8 @@ def test_column_filters():
column_filters=['test1'], endpoint='_strings') column_filters=['test1'], endpoint='_strings')
admin.add_view(view) admin.add_view(view)
eq_([(f['index'], f['operation']) for f in view._filter_groups[u'Test1']], eq_(
[(f['index'], f['operation']) for f in view._filter_groups[u'Test1']],
[ [
(0, 'contains'), (0, 'contains'),
(1, 'not contains'), (1, 'not contains'),
...@@ -690,7 +707,8 @@ def test_column_filters(): ...@@ -690,7 +707,8 @@ def test_column_filters():
(4, 'empty'), (4, 'empty'),
(5, 'in list'), (5, 'in list'),
(6, 'not in list'), (6, 'not in list'),
]) ]
)
# string - equals # string - equals
rv = client.get('/admin/_strings/?flt0_0=test1_val_1') rv = client.get('/admin/_strings/?flt0_0=test1_val_1')
...@@ -759,7 +777,8 @@ def test_column_filters(): ...@@ -759,7 +777,8 @@ def test_column_filters():
column_filters=['int_field']) column_filters=['int_field'])
admin.add_view(view) admin.add_view(view)
eq_([(f['index'], f['operation']) for f in view._filter_groups[u'Int Field']], eq_(
[(f['index'], f['operation']) for f in view._filter_groups[u'Int Field']],
[ [
(0, 'equals'), (0, 'equals'),
(1, 'not equal'), (1, 'not equal'),
...@@ -768,7 +787,8 @@ def test_column_filters(): ...@@ -768,7 +787,8 @@ def test_column_filters():
(4, 'empty'), (4, 'empty'),
(5, 'in list'), (5, 'in list'),
(6, 'not in list'), (6, 'not in list'),
]) ]
)
# integer - equals # integer - equals
rv = client.get('/admin/model2/?flt0_0=5000') rv = client.get('/admin/model2/?flt0_0=5000')
...@@ -865,11 +885,13 @@ def test_column_filters(): ...@@ -865,11 +885,13 @@ def test_column_filters():
endpoint="_bools") endpoint="_bools")
admin.add_view(view) admin.add_view(view)
eq_([(f['index'], f['operation']) for f in view._filter_groups[u'Bool Field']], eq_(
[(f['index'], f['operation']) for f in view._filter_groups[u'Bool Field']],
[ [
(0, 'equals'), (0, 'equals'),
(1, 'not equal'), (1, 'not equal'),
]) ]
)
# boolean - equals - Yes # boolean - equals - Yes
rv = client.get('/admin/_bools/?flt0_0=1') rv = client.get('/admin/_bools/?flt0_0=1')
...@@ -908,7 +930,8 @@ def test_column_filters(): ...@@ -908,7 +930,8 @@ def test_column_filters():
endpoint="_float") endpoint="_float")
admin.add_view(view) admin.add_view(view)
eq_([(f['index'], f['operation']) for f in view._filter_groups[u'Float Field']], eq_(
[(f['index'], f['operation']) for f in view._filter_groups[u'Float Field']],
[ [
(0, 'equals'), (0, 'equals'),
(1, 'not equal'), (1, 'not equal'),
...@@ -917,7 +940,8 @@ def test_column_filters(): ...@@ -917,7 +940,8 @@ def test_column_filters():
(4, 'empty'), (4, 'empty'),
(5, 'in list'), (5, 'in list'),
(6, 'not in list'), (6, 'not in list'),
]) ]
)
# float - equals # float - equals
rv = client.get('/admin/_float/?flt0_0=25.9') rv = client.get('/admin/_float/?flt0_0=25.9')
...@@ -1037,7 +1061,8 @@ def test_column_filters(): ...@@ -1037,7 +1061,8 @@ def test_column_filters():
endpoint="_datetime") endpoint="_datetime")
admin.add_view(view) admin.add_view(view)
eq_([(f['index'], f['operation']) for f in view._filter_groups[u'Date Field']], eq_(
[(f['index'], f['operation']) for f in view._filter_groups[u'Date Field']],
[ [
(0, 'equals'), (0, 'equals'),
(1, 'not equal'), (1, 'not equal'),
...@@ -1046,9 +1071,11 @@ def test_column_filters(): ...@@ -1046,9 +1071,11 @@ def test_column_filters():
(4, 'between'), (4, 'between'),
(5, 'not between'), (5, 'not between'),
(6, 'empty'), (6, 'empty'),
]) ]
)
eq_([(f['index'], f['operation']) for f in view._filter_groups[u'Datetime Field']], eq_(
[(f['index'], f['operation']) for f in view._filter_groups[u'Datetime Field']],
[ [
(7, 'equals'), (7, 'equals'),
(8, 'not equal'), (8, 'not equal'),
...@@ -1057,9 +1084,11 @@ def test_column_filters(): ...@@ -1057,9 +1084,11 @@ def test_column_filters():
(11, 'between'), (11, 'between'),
(12, 'not between'), (12, 'not between'),
(13, 'empty'), (13, 'empty'),
]) ]
)
eq_([(f['index'], f['operation']) for f in view._filter_groups[u'Time Field']], eq_(
[(f['index'], f['operation']) for f in view._filter_groups[u'Time Field']],
[ [
(14, 'equals'), (14, 'equals'),
(15, 'not equal'), (15, 'not equal'),
...@@ -1068,7 +1097,8 @@ def test_column_filters(): ...@@ -1068,7 +1097,8 @@ def test_column_filters():
(18, 'between'), (18, 'between'),
(19, 'not between'), (19, 'not between'),
(20, 'empty'), (20, 'empty'),
]) ]
)
# date - equals # date - equals
rv = client.get('/admin/_datetime/?flt0_0=2014-11-17') rv = client.get('/admin/_datetime/?flt0_0=2014-11-17')
...@@ -1298,7 +1328,7 @@ def test_column_filters(): ...@@ -1298,7 +1328,7 @@ def test_column_filters():
# Test single custom filter on relation # Test single custom filter on relation
view = CustomModelView(Model2, db.session, view = CustomModelView(Model2, db.session,
column_filters = [ column_filters=[
filters.FilterEqual(Model1.test1, "Test1") filters.FilterEqual(Model1.test1, "Test1")
], endpoint='_relation_test') ], endpoint='_relation_test')
admin.add_view(view) admin.add_view(view)
...@@ -1348,8 +1378,8 @@ def test_hybrid_property(): ...@@ -1348,8 +1378,8 @@ def test_hybrid_property():
view = CustomModelView( view = CustomModelView(
Model1, db.session, Model1, db.session,
column_default_sort='number_of_pixels', column_default_sort='number_of_pixels',
column_filters = [filters.IntGreaterFilter(Model1.number_of_pixels, column_filters=[filters.IntGreaterFilter(Model1.number_of_pixels,
'Number of Pixels')] 'Number of Pixels')]
) )
admin.add_view(view) admin.add_view(view)
...@@ -1510,7 +1540,7 @@ def test_complex_form_columns(): ...@@ -1510,7 +1540,7 @@ def test_complex_form_columns():
# test using a form column in another table # test using a form column in another table
view = CustomModelView(M2, db.session, form_columns=['model1.test1']) view = CustomModelView(M2, db.session, form_columns=['model1.test1'])
form = view.create_form() view.create_form()
def test_form_args(): def test_form_args():
...@@ -1816,13 +1846,14 @@ def test_extra_field_order(): ...@@ -1816,13 +1846,14 @@ def test_extra_field_order():
pos2 = data.find('Test1') pos2 = data.find('Test1')
ok_(pos2 > pos1) ok_(pos2 > pos1)
def test_modelview_localization(): def test_modelview_localization():
def test_locale(locale): def test_locale(locale):
try: try:
app, db, admin = setup() app, db, admin = setup()
app.config['BABEL_DEFAULT_LOCALE'] = locale app.config['BABEL_DEFAULT_LOCALE'] = locale
babel = Babel(app) Babel(app)
Model1, _ = create_models(db) Model1, _ = create_models(db)
......
from nose.tools import eq_, ok_, raises from nose.tools import eq_, ok_
from . import setup from . import setup
from .test_basic import CustomModelView, create_models from .test_basic import CustomModelView, create_models
......
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from nose.tools import eq_, ok_, raises from nose.tools import eq_, ok_
from wtforms import fields from wtforms import fields
...@@ -62,8 +62,8 @@ def test_inline_form(): ...@@ -62,8 +62,8 @@ def test_inline_form():
eq_(User.query.count(), 1) eq_(User.query.count(), 1)
eq_(UserInfo.query.count(), 0) eq_(UserInfo.query.count(), 0)
rv = client.post('/admin/user/new/', data={'name': u'fbar', \ data = {'name': u'fbar', 'info-0-key': 'foo', 'info-0-val': 'bar'}
'info-0-key': 'foo', 'info-0-val' : 'bar'}) rv = client.post('/admin/user/new/', data=data)
eq_(rv.status_code, 302) eq_(rv.status_code, 302)
eq_(User.query.count(), 2) eq_(User.query.count(), 2)
eq_(UserInfo.query.count(), 1) eq_(UserInfo.query.count(), 1)
...@@ -72,15 +72,28 @@ def test_inline_form(): ...@@ -72,15 +72,28 @@ def test_inline_form():
rv = client.get('/admin/user/edit/?id=2') rv = client.get('/admin/user/edit/?id=2')
eq_(rv.status_code, 200) eq_(rv.status_code, 200)
# Edit - update # Edit - update
rv = client.post('/admin/user/edit/?id=2', data={'name': u'barfoo', \ data = {
'info-0-id': 1, 'info-0-key': u'xxx', 'info-0-val':u'yyy'}) 'name': u'barfoo',
'info-0-id': 1,
'info-0-key': u'xxx',
'info-0-val': u'yyy',
}
rv = client.post('/admin/user/edit/?id=2', data=data)
eq_(UserInfo.query.count(), 1) eq_(UserInfo.query.count(), 1)
eq_(UserInfo.query.one().key, u'xxx') eq_(UserInfo.query.one().key, u'xxx')
# Edit - add & delete # Edit - add & delete
rv = client.post('/admin/user/edit/?id=2', data={'name': u'barf', \ data = {
'del-info-0': 'on', 'info-0-id': '1', 'info-0-key': 'yyy', 'info-0-val': 'xxx', 'name': u'barf',
'info-1-id': None, 'info-1-key': u'bar', 'info-1-val' : u'foo'}) 'del-info-0': 'on',
'info-0-id': '1',
'info-0-key': 'yyy',
'info-0-val': 'xxx',
'info-1-id': None,
'info-1-key': u'bar',
'info-1-val': u'foo',
}
rv = client.post('/admin/user/edit/?id=2', data=data)
eq_(rv.status_code, 302) eq_(rv.status_code, 302)
eq_(User.query.count(), 2) eq_(User.query.count(), 2)
eq_(User.query.get(2).name, u'barf') eq_(User.query.get(2).name, u'barf')
...@@ -259,7 +272,7 @@ def test_inline_form_base_class(): ...@@ -259,7 +272,7 @@ def test_inline_form_base_class():
# Set up Admin # Set up Admin
class UserModelView(ModelView): class UserModelView(ModelView):
inline_models = ((UserEmail,{"form_base_class": StubBaseForm}),) inline_models = ((UserEmail, {"form_base_class": StubBaseForm}),)
form_args = { form_args = {
"emails": {"validators": [ItemsRequired()]} "emails": {"validators": [ItemsRequired()]}
} }
......
...@@ -342,7 +342,7 @@ def test_multi_instances_init(): ...@@ -342,7 +342,7 @@ def test_multi_instances_init():
class ManageIndex(base.AdminIndexView): class ManageIndex(base.AdminIndexView):
pass pass
_ = base.Admin(app, index_view=ManageIndex(url='/manage', endpoint='manage')) _ = base.Admin(app, index_view=ManageIndex(url='/manage', endpoint='manage')) # noqa: F841
@raises(Exception) @raises(Exception)
......
...@@ -229,7 +229,6 @@ def test_image_upload_field(): ...@@ -229,7 +229,6 @@ def test_image_upload_field():
eq_(dummy.upload, 'test1.jpg') eq_(dummy.upload, 'test1.jpg')
ok_(op.exists(op.join(path, 'test1.jpg'))) ok_(op.exists(op.join(path, 'test1.jpg')))
# check allowed extensions # check allowed extensions
for extension in ('gif', 'jpg', 'jpeg', 'png', 'tiff'): for extension in ('gif', 'jpg', 'jpeg', 'png', 'tiff'):
filename = 'copyleft.' + extension filename = 'copyleft.' + extension
......
...@@ -579,7 +579,7 @@ def test_export_csv(): ...@@ -579,7 +579,7 @@ def test_export_csv():
# test explicit use of column_export_list # test explicit use of column_export_list
view = MockModelView(Model, view_data, can_export=True, view = MockModelView(Model, view_data, can_export=True,
column_list=['col1', 'col2'], column_list=['col1', 'col2'],
column_export_list=['id','col1','col2'], column_export_list=['id', 'col1', 'col2'],
endpoint='exportinclusion') endpoint='exportinclusion')
admin.add_view(view) admin.add_view(view)
...@@ -629,7 +629,7 @@ def test_export_csv(): ...@@ -629,7 +629,7 @@ def test_export_csv():
view = MockModelView( view = MockModelView(
Model, view_data, can_export=True, column_list=['col1', 'col2'], Model, view_data, can_export=True, column_list=['col1', 'col2'],
column_labels={'col1': 'Str Field', 'col2': 'Int Field'}, column_labels={'col1': 'Str Field', 'col2': 'Int Field'},
column_formatters=dict(col2=lambda v, c, m, p: m.col2*2), column_formatters=dict(col2=lambda v, c, m, p: m.col2 * 2),
endpoint="types_and_formatters" endpoint="types_and_formatters"
) )
admin.add_view(view) admin.add_view(view)
...@@ -647,8 +647,8 @@ def test_export_csv(): ...@@ -647,8 +647,8 @@ def test_export_csv():
view = MockModelView( view = MockModelView(
Model, view_data, can_export=True, column_list=['col1', 'col2'], Model, view_data, can_export=True, column_list=['col1', 'col2'],
column_formatters_export=dict(col2=lambda v, c, m, p: m.col2*3), column_formatters_export=dict(col2=lambda v, c, m, p: m.col2 * 3),
column_formatters=dict(col2=lambda v, c, m, p: m.col2*2), # overridden column_formatters=dict(col2=lambda v, c, m, p: m.col2 * 2), # overridden
column_type_formatters_export=type_formatters, column_type_formatters_export=type_formatters,
endpoint="export_types_and_formatters" endpoint="export_types_and_formatters"
) )
......
...@@ -119,6 +119,7 @@ def iterencode(iter): ...@@ -119,6 +119,7 @@ def iterencode(iter):
.replace(CHAR_SEPARATOR, CHAR_ESCAPE + CHAR_SEPARATOR) .replace(CHAR_SEPARATOR, CHAR_ESCAPE + CHAR_SEPARATOR)
for v in iter) for v in iter)
def iterdecode(value): def iterdecode(value):
""" """
Decode enumerable from string presentation as a tuple Decode enumerable from string presentation as a tuple
......
[tox] [tox]
envlist = py{26,27,33,34,35,36}-WTForms{1,2} envlist = py{26,27,33,34,35,36}-WTForms{1,2},flake8
skipsdist = true skipsdist = true
skip_missing_interpreters = true skip_missing_interpreters = true
[flake8]
max_line_length = 120
ignore = E402
[testenv] [testenv]
usedevelop = true usedevelop = true
deps = deps =
...@@ -11,3 +15,7 @@ deps = ...@@ -11,3 +15,7 @@ deps =
-r{toxinidir}/requirements-dev.txt -r{toxinidir}/requirements-dev.txt
commands = commands =
nosetests flask_admin/tests --with-coverage --cover-erase --cover-inclusive nosetests flask_admin/tests --with-coverage --cover-erase --cover-inclusive
[testenv:flake8]
deps = flake8
commands = flake8 flask_admin
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment