Commit b255126b authored by Serge S. Koval's avatar Serge S. Koval

Get rid of flask-wtf dependency

parent 16b254d1
- Core - Python 3
- View Site button? - Test for raw wtforms form
- Localization
- Create documentation
- Model Admin
- Simplify scaffold_list_columns - remove excluded_list_columns check, update documentation
- Simplify InlineModelFormList implementation - accept property instead of property name
- Reduce number of parameters passed to list view
- Filters
- Use table to draw filters so column names will line up?
- Change boolean filter to True/False instead of Yes/No
- Ability to sort by fields that are not visible?
- List display callables?
- MongoEngine
- EmbeddedDocument customization
- File admin
- Header title
- File size restriction
- Unit tests
- Form generation tests
- Documentation
- Add all new stuff
- Fixed stylesheet
...@@ -15,9 +15,9 @@ with PyMongo: ...@@ -15,9 +15,9 @@ with PyMongo:
This is minimal PyMongo view:: This is minimal PyMongo view::
class UserForm(wtf.Form): class UserForm(Form):
name = wtf.TextForm('Name') name = TextField('Name')
email = wtf.TextForm('Email') email = TextField('Email')
class UserView(ModelView): class UserView(ModelView):
column_list = ('name', 'email') column_list = ('name', 'email')
......
...@@ -97,7 +97,7 @@ you can do something like this:: ...@@ -97,7 +97,7 @@ you can do something like this::
class UserView(ModelView): class UserView(ModelView):
def scaffold_form(self): def scaffold_form(self):
form_class = super(UserView, self).scaffold_form() form_class = super(UserView, self).scaffold_form()
form_class.extra = wtf.TextField('Extra') form_class.extra = TextField('Extra')
return form_class return form_class
Check :doc:`api/mod_contrib_sqlamodel` documentation for list of Check :doc:`api/mod_contrib_sqlamodel` documentation for list of
......
...@@ -163,7 +163,7 @@ Steps to add new model backend: ...@@ -163,7 +163,7 @@ Steps to add new model backend:
class MyDbModel(BaseModelView): class MyDbModel(BaseModelView):
def scaffold_form(self): def scaffold_form(self):
class MyForm(wtf.Form): class MyForm(Form):
pass pass
# Do something # Do something
......
...@@ -24,5 +24,5 @@ field. In this case, you need to manually contribute field:: ...@@ -24,5 +24,5 @@ field. In this case, you need to manually contribute field::
class MyView(ModelView): class MyView(ModelView):
def scaffold_form(self): def scaffold_form(self):
form_class = super(UserView, self).scaffold_form() form_class = super(UserView, self).scaffold_form()
form_class.extra = wtf.TextField('Extra') form_class.extra = TextField('Extra')
return form_class return form_class
from flask import Flask, url_for, redirect, render_template, request from flask import Flask, url_for, redirect, render_template, request
from flask.ext.mongoengine import MongoEngine from flask.ext.mongoengine import MongoEngine
from flask.ext import admin, login, wtf from wtforms import form, fields, validators
from flask.ext import admin, login
from flask.ext.admin.contrib.mongoengine import ModelView from flask.ext.admin.contrib.mongoengine import ModelView
# Create application # Create application
...@@ -42,31 +44,31 @@ class User(db.Document): ...@@ -42,31 +44,31 @@ class User(db.Document):
# Define login and registration forms (for flask-login) # Define login and registration forms (for flask-login)
class LoginForm(wtf.Form): class LoginForm(form.Form):
login = wtf.TextField(validators=[wtf.required()]) login = fields.TextField(validators=[validators.required()])
password = wtf.PasswordField(validators=[wtf.required()]) password = fields.PasswordField(validators=[validators.required()])
def validate_login(self, field): def validate_login(self, field):
user = self.get_user() user = self.get_user()
if user is None: if user is None:
raise wtf.ValidationError('Invalid user') raise validators.ValidationError('Invalid user')
if user.password != self.password.data: if user.password != self.password.data:
raise wtf.ValidationError('Invalid password') raise validators.ValidationError('Invalid password')
def get_user(self): def get_user(self):
return User.objects(login=self.login.data).first() return User.objects(login=self.login.data).first()
class RegistrationForm(wtf.Form): class RegistrationForm(form.Form):
login = wtf.TextField(validators=[wtf.required()]) login = fields.TextField(validators=[validators.required()])
email = wtf.TextField() email = fields.TextField()
password = wtf.PasswordField(validators=[wtf.required()]) password = fields.PasswordField(validators=[validators.required()])
def validate_login(self, field): def validate_login(self, field):
if User.objects(login=self.login.data): if User.objects(login=self.login.data):
raise wtf.ValidationError('Duplicate username') raise validators.ValidationError('Duplicate username')
# Initialize flask-login # Initialize flask-login
......
from flask import Flask, url_for, redirect, render_template, request from flask import Flask, url_for, redirect, render_template, request
from flask.ext.sqlalchemy import SQLAlchemy from flask.ext.sqlalchemy import SQLAlchemy
from flask.ext import admin, login, wtf from wtforms import form, fields, validators
from flask.ext import admin, login
from flask.ext.admin.contrib import sqlamodel from flask.ext.admin.contrib import sqlamodel
# Create Flask application # Create Flask application
...@@ -43,31 +45,31 @@ class User(db.Model): ...@@ -43,31 +45,31 @@ class User(db.Model):
# Define login and registration forms (for flask-login) # Define login and registration forms (for flask-login)
class LoginForm(wtf.Form): class LoginForm(form.Form):
login = wtf.TextField(validators=[wtf.required()]) login = fields.TextField(validators=[validators.required()])
password = wtf.PasswordField(validators=[wtf.required()]) password = fields.PasswordField(validators=[validators.required()])
def validate_login(self, field): def validate_login(self, field):
user = self.get_user() user = self.get_user()
if user is None: if user is None:
raise wtf.ValidationError('Invalid user') raise validators.ValidationError('Invalid user')
if user.password != self.password.data: if user.password != self.password.data:
raise wtf.ValidationError('Invalid password') raise validators.ValidationError('Invalid password')
def get_user(self): def get_user(self):
return db.session.query(User).filter_by(login=self.login.data).first() return db.session.query(User).filter_by(login=self.login.data).first()
class RegistrationForm(wtf.Form): class RegistrationForm(form.Form):
login = wtf.TextField(validators=[wtf.required()]) login = fields.TextField(validators=[validators.required()])
email = wtf.TextField() email = fields.TextField()
password = wtf.PasswordField(validators=[wtf.required()]) password = fields.PasswordField(validators=[validators.required()])
def validate_login(self, field): def validate_login(self, field):
if db.session.query(User).filter_by(login=self.login.data).count() > 0: if db.session.query(User).filter_by(login=self.login.data).count() > 0:
raise wtf.ValidationError('Duplicate username') raise validators.ValidationError('Duplicate username')
# Initialize flask-login # Initialize flask-login
......
...@@ -2,12 +2,13 @@ import pymongo ...@@ -2,12 +2,13 @@ import pymongo
from bson.objectid import ObjectId from bson.objectid import ObjectId
from flask import Flask from flask import Flask
from flask.ext import admin
from flask.ext import admin, wtf from wtforms import form, fields
from flask.ext.admin.form import Select2Widget from flask.ext.admin.form import Select2Widget
from flask.ext.admin.contrib.pymongo import ModelView, filters from flask.ext.admin.contrib.pymongo import ModelView, filters
from flask.ext.admin.model import fields from flask.ext.admin.model import InlineFormField, InlineFieldList
# Create application # Create application
app = Flask(__name__) app = Flask(__name__)
...@@ -21,21 +22,21 @@ db = conn.test ...@@ -21,21 +22,21 @@ db = conn.test
# User admin # User admin
class InnerForm(wtf.Form): class InnerForm(form.Form):
name = wtf.TextField('Name') name = fields.TextField('Name')
test = wtf.TextField('Test') test = fields.TextField('Test')
class UserForm(wtf.Form): class UserForm(form.Form):
name = wtf.TextField('Name') name = fields.TextField('Name')
email = wtf.TextField('Email') email = fields.TextField('Email')
password = wtf.TextField('Password') password = fields.TextField('Password')
# Inner form # Inner form
inner = fields.InlineFormField(InnerForm) inner = InlineFormField(InnerForm)
# Form list # Form list
form_list = fields.InlineFieldList(fields.InlineFormField(InnerForm)) form_list = InlineFieldList(InlineFormField(InnerForm))
class UserView(ModelView): class UserView(ModelView):
...@@ -46,10 +47,10 @@ class UserView(ModelView): ...@@ -46,10 +47,10 @@ class UserView(ModelView):
# Tweet view # Tweet view
class TweetForm(wtf.Form): class TweetForm(form.Form):
name = wtf.TextField('Name') name = fields.TextField('Name')
user_id = wtf.SelectField('User', widget=Select2Widget()) user_id = fields.SelectField('User', widget=Select2Widget())
text = wtf.TextField('Text') text = fields.TextField('Text')
class TweetView(ModelView): class TweetView(ModelView):
......
from flask import Flask from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy from flask.ext.sqlalchemy import SQLAlchemy
from flask.ext import admin, wtf from wtforms import validators
from flask.ext import admin
from flask.ext.admin.contrib import sqlamodel from flask.ext.admin.contrib import sqlamodel
from flask.ext.admin.contrib.sqlamodel import filters from flask.ext.admin.contrib.sqlamodel import filters
...@@ -114,7 +116,7 @@ class PostAdmin(sqlamodel.ModelView): ...@@ -114,7 +116,7 @@ class PostAdmin(sqlamodel.ModelView):
# Pass arguments to WTForms. In this case, change label for text field to # Pass arguments to WTForms. In this case, change label for text field to
# be 'Big Text' and add required() validator. # be 'Big Text' and add required() validator.
form_args = dict( form_args = dict(
text=dict(label='Big Text', validators=[wtf.required()]) text=dict(label='Big Text', validators=[validators.required()])
) )
def __init__(self, session): def __init__(self, session):
......
from flask import Flask from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy from flask.ext.sqlalchemy import SQLAlchemy
from flask.ext import admin, wtf from wtforms import fields, widgets
from flask.ext import admin
from flask.ext.admin.contrib import sqlamodel from flask.ext.admin.contrib import sqlamodel
# Create application # Create application
...@@ -17,13 +19,13 @@ db = SQLAlchemy(app) ...@@ -17,13 +19,13 @@ db = SQLAlchemy(app)
# Define wtforms widget and field # Define wtforms widget and field
class CKTextAreaWidget(wtf.TextArea): class CKTextAreaWidget(widgets.TextArea):
def __call__(self, field, **kwargs): def __call__(self, field, **kwargs):
kwargs.setdefault('class_', 'ckeditor') kwargs.setdefault('class_', 'ckeditor')
return super(CKTextAreaWidget, self).__call__(field, **kwargs) return super(CKTextAreaWidget, self).__call__(field, **kwargs)
class CKTextAreaField(wtf.TextAreaField): class CKTextAreaField(fields.TextAreaField):
widget = CKTextAreaWidget() widget = CKTextAreaWidget()
......
...@@ -6,16 +6,16 @@ import re ...@@ -6,16 +6,16 @@ import re
import shutil import shutil
from operator import itemgetter from operator import itemgetter
from werkzeug import secure_filename from werkzeug import secure_filename
from flask import flash, url_for, redirect, abort, request from flask import flash, url_for, redirect, abort, request
from wtforms import fields, validators
from flask.ext.admin.base import BaseView, expose from flask.ext.admin.base import BaseView, expose
from flask.ext.admin.actions import action, ActionsMixin from flask.ext.admin.actions import action, ActionsMixin
from flask.ext.admin.babel import gettext, lazy_gettext from flask.ext.admin.babel import gettext, lazy_gettext
from flask.ext.admin import form from flask.ext.admin import form
from flask.ext import wtf
class NameForm(form.BaseForm): class NameForm(form.BaseForm):
...@@ -24,13 +24,13 @@ class NameForm(form.BaseForm): ...@@ -24,13 +24,13 @@ class NameForm(form.BaseForm):
Validates if provided name is valid for *nix and Windows systems. Validates if provided name is valid for *nix and Windows systems.
""" """
name = wtf.TextField() name = fields.TextField()
regexp = re.compile(r'^(?!^(PRN|AUX|CLOCK\$|NUL|CON|COM\d|LPT\d|\..*)(\..+)?$)[^\x00-\x1f\\?*:\";|/]+$') regexp = re.compile(r'^(?!^(PRN|AUX|CLOCK\$|NUL|CON|COM\d|LPT\d|\..*)(\..+)?$)[^\x00-\x1f\\?*:\";|/]+$')
def validate_name(self, field): def validate_name(self, field):
if not self.regexp.match(field.data): if not self.regexp.match(field.data):
raise wtf.ValidationError(gettext('Invalid directory name')) raise validators.ValidationError(gettext('Invalid directory name'))
class UploadForm(form.BaseForm): class UploadForm(form.BaseForm):
...@@ -38,7 +38,7 @@ class UploadForm(form.BaseForm): ...@@ -38,7 +38,7 @@ class UploadForm(form.BaseForm):
File upload form. Works with FileAdmin instance to check if it is allowed File upload form. Works with FileAdmin instance to check if it is allowed
to upload file with given extension. to upload file with given extension.
""" """
upload = wtf.FileField(lazy_gettext('File to upload')) upload = fields.FileField(lazy_gettext('File to upload'))
def __init__(self, admin): def __init__(self, admin):
self.admin = admin self.admin = admin
...@@ -47,17 +47,17 @@ class UploadForm(form.BaseForm): ...@@ -47,17 +47,17 @@ class UploadForm(form.BaseForm):
def validate_upload(self, field): def validate_upload(self, field):
if not self.upload.has_file(): if not self.upload.has_file():
raise wtf.ValidationError(gettext('File required.')) raise validators.ValidationError(gettext('File required.'))
filename = self.upload.data.filename filename = self.upload.data.filename
if not self.admin.is_file_allowed(filename): if not self.admin.is_file_allowed(filename):
raise wtf.ValidationError(gettext('Invalid file type.')) raise validators.ValidationError(gettext('Invalid file type.'))
class EditForm(form.BaseForm): class EditForm(form.BaseForm):
content = wtf.TextAreaField(lazy_gettext('Content'), content = fields.TextAreaField(lazy_gettext('Content'),
[wtf.validators.required()]) (validators.required(),))
class FileAdmin(BaseView, ActionsMixin): class FileAdmin(BaseView, ActionsMixin):
...@@ -181,13 +181,13 @@ class FileAdmin(BaseView, ActionsMixin): ...@@ -181,13 +181,13 @@ class FileAdmin(BaseView, ActionsMixin):
self._on_windows = platform.system() == 'Windows' self._on_windows = platform.system() == 'Windows'
# Convert allowed_extensions to set for quick validation # Convert allowed_extensions to set for quick validation
if (self.allowed_extensions if (self.allowed_extensions and
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 if (self.editable_extensions and
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)
# Check if path exists # Check if path exists
......
...@@ -55,7 +55,7 @@ class ModelView(BaseModelView): ...@@ -55,7 +55,7 @@ class ModelView(BaseModelView):
class MyInlineModelConverter(AdminModelConverter): class MyInlineModelConverter(AdminModelConverter):
def post_process(self, form_class, info): def post_process(self, form_class, info):
form_class.value = wtf.TextField('value') form_class.value = TextField('value')
return form_class return form_class
class MyAdminView(ModelView): class MyAdminView(ModelView):
......
import time import time
import datetime import datetime
from wtforms import fields, widgets from wtforms import form, fields, widgets
from flask.globals import _request_ctx_stack from flask.globals import _request_ctx_stack
from flask.ext import wtf
from flask.ext.admin.babel import gettext, ngettext from flask.ext.admin.babel import gettext, ngettext
from flask.ext.admin import helpers as h from flask.ext.admin import helpers as h
class BaseForm(wtf.Form): class BaseForm(form.Form):
""" """
Customized form class. Customized form class.
""" """
...@@ -28,7 +27,7 @@ class BaseForm(wtf.Form): ...@@ -28,7 +27,7 @@ class BaseForm(wtf.Form):
""" """
# TODO: Optimize me # TODO: Optimize me
for f in self: for f in self:
if isinstance(f, wtf.FileField): if isinstance(f, fields.FileField):
return True return True
return False return False
......
...@@ -246,7 +246,7 @@ class BaseModelView(BaseView, ActionsMixin): ...@@ -246,7 +246,7 @@ class BaseModelView(BaseView, ActionsMixin):
For example:: For example::
class MyForm(wtf.Form): class MyForm(Form):
pass pass
class MyModelView(BaseModelView): class MyModelView(BaseModelView):
...@@ -262,7 +262,7 @@ class BaseModelView(BaseView, ActionsMixin): ...@@ -262,7 +262,7 @@ class BaseModelView(BaseView, ActionsMixin):
class MyModelView(BaseModelView): class MyModelView(BaseModelView):
form_args = dict( form_args = dict(
name=dict(label='First Name', validators=[wtf.required()]) name=dict(label='First Name', validators=[required()])
) )
""" """
......
...@@ -48,7 +48,7 @@ class InlineFormAdmin(object): ...@@ -48,7 +48,7 @@ class InlineFormAdmin(object):
class MyInlineForm(InlineFormAdmin): class MyInlineForm(InlineFormAdmin):
def postprocess_form(self, form): def postprocess_form(self, form):
form.value = wtf.TextField('value') form.value = TextField('value')
return form return form
class MyAdmin(ModelView): class MyAdmin(ModelView):
......
from nose.tools import eq_, ok_ from nose.tools import eq_, ok_
from flask.ext import wtf from wtforms import fields
from flask.ext.admin.contrib.mongoengine import ModelView from flask.ext.admin.contrib.mongoengine import ModelView
from . import setup from . import setup
...@@ -62,14 +63,14 @@ def test_model(): ...@@ -62,14 +63,14 @@ def test_model():
# Verify form # Verify form
# TODO: Figure out why there's inconsistency # TODO: Figure out why there's inconsistency
try: try:
eq_(view._create_form_class.test1.field_class, wtf.TextField) eq_(view._create_form_class.test1.field_class, fields.TextField)
eq_(view._create_form_class.test2.field_class, wtf.TextField) eq_(view._create_form_class.test2.field_class, fields.TextField)
except AssertionError: except AssertionError:
eq_(view._create_form_class.test1.field_class, wtf.StringField) eq_(view._create_form_class.test1.field_class, fields.StringField)
eq_(view._create_form_class.test2.field_class, wtf.StringField) eq_(view._create_form_class.test2.field_class, fields.StringField)
eq_(view._create_form_class.test3.field_class, wtf.TextAreaField) eq_(view._create_form_class.test3.field_class, fields.TextAreaField)
eq_(view._create_form_class.test4.field_class, wtf.TextAreaField) eq_(view._create_form_class.test4.field_class, fields.TextAreaField)
# Make some test clients # Make some test clients
client = app.test_client() client = app.test_client()
......
...@@ -2,7 +2,8 @@ from nose.tools import eq_, ok_ ...@@ -2,7 +2,8 @@ from nose.tools import eq_, ok_
import peewee import peewee
from flask.ext import wtf from wtforms import fields
from flask.ext.admin.contrib.peeweemodel import ModelView from flask.ext.admin.contrib.peeweemodel import ModelView
from . import setup from . import setup
...@@ -73,10 +74,10 @@ def test_model(): ...@@ -73,10 +74,10 @@ def test_model():
eq_(view._filters, None) eq_(view._filters, None)
# Verify form # Verify form
eq_(view._create_form_class.test1.field_class, wtf.TextField) eq_(view._create_form_class.test1.field_class, fields.TextField)
eq_(view._create_form_class.test2.field_class, wtf.TextField) eq_(view._create_form_class.test2.field_class, fields.TextField)
eq_(view._create_form_class.test3.field_class, wtf.TextAreaField) eq_(view._create_form_class.test3.field_class, fields.TextAreaField)
eq_(view._create_form_class.test4.field_class, wtf.TextAreaField) eq_(view._create_form_class.test4.field_class, fields.TextAreaField)
# Make some test clients # Make some test clients
client = app.test_client() client = app.test_client()
......
from nose.tools import eq_, ok_, raises from nose.tools import eq_, ok_, raises
from flask.ext import wtf from wtforms import fields
from flask.ext.admin.contrib.sqlamodel import ModelView from flask.ext.admin.contrib.sqlamodel import ModelView
from . import setup from . import setup
...@@ -439,12 +439,12 @@ def test_form_override(): ...@@ -439,12 +439,12 @@ def test_form_override():
db.create_all() db.create_all()
view1 = CustomModelView(Model, db.session, endpoint='view1') view1 = CustomModelView(Model, db.session, endpoint='view1')
view2 = CustomModelView(Model, db.session, endpoint='view2', form_overrides=dict(test=wtf.FileField)) view2 = CustomModelView(Model, db.session, endpoint='view2', form_overrides=dict(test=fields.FileField))
admin.add_view(view1) admin.add_view(view1)
admin.add_view(view2) admin.add_view(view2)
eq_(view1._create_form_class.test.field_class, wtf.TextField) eq_(view1._create_form_class.test.field_class, fields.TextField)
eq_(view2._create_form_class.test.field_class, wtf.FileField) eq_(view2._create_form_class.test.field_class, fields.FileField)
def test_relations(): def test_relations():
...@@ -499,7 +499,7 @@ def test_multiple_delete(): ...@@ -499,7 +499,7 @@ def test_multiple_delete():
client = app.test_client() client = app.test_client()
rv = client.post('/admin/model1view/action/', data=dict(action='delete', rowid=[1,2,3])) rv = client.post('/admin/model1view/action/', data=dict(action='delete', rowid=[1, 2, 3]))
eq_(rv.status_code, 302) eq_(rv.status_code, 302)
eq_(M1.query.count(), 0) eq_(M1.query.count(), 0)
......
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from nose.tools import eq_, ok_, raises from nose.tools import eq_, ok_, raises
from flask.ext import wtf from wtforms import fields
from flask.ext.admin.contrib.sqlamodel import ModelView, fields
from flask.ext.admin.contrib.sqlamodel import ModelView
from flask.ext.admin.contrib.sqlamodel.fields import InlineModelFormList
from . import setup from . import setup
...@@ -42,8 +44,8 @@ def test_inline_form(): ...@@ -42,8 +44,8 @@ def test_inline_form():
eq_(view.endpoint, 'userview') eq_(view.endpoint, 'userview')
# Verify form # Verify form
eq_(view._create_form_class.name.field_class, wtf.TextField) eq_(view._create_form_class.name.field_class, fields.TextField)
eq_(view._create_form_class.info.field_class, fields.InlineModelFormList) eq_(view._create_form_class.info.field_class, InlineModelFormList)
rv = client.get('/admin/userview/') rv = client.get('/admin/userview/')
eq_(rv.status_code, 200) eq_(rv.status_code, 200)
......
from nose.tools import eq_, ok_, raises from nose.tools import eq_, ok_
from flask import Flask from flask import Flask
from flask.helpers import get_flashed_messages
from flask.ext.admin import Admin from wtforms import fields
from flask.ext.admin.model import base, filters
from flask.ext import wtf from flask.ext.admin import Admin, form
from flask.ext.admin.model import base, filters
class Model(object): class Model(object):
...@@ -17,10 +16,10 @@ class Model(object): ...@@ -17,10 +16,10 @@ class Model(object):
self.col3 = c3 self.col3 = c3
class Form(wtf.Form): class Form(form.BaseForm):
col1 = wtf.TextField() col1 = fields.TextField()
col2 = wtf.TextField() col2 = fields.TextField()
col3 = wtf.TextField() col3 = fields.TextField()
class SimpleFilter(filters.BaseFilter): class SimpleFilter(filters.BaseFilter):
...@@ -298,7 +297,7 @@ def test_form(): ...@@ -298,7 +297,7 @@ def test_form():
def test_custom_form(): def test_custom_form():
app, admin = setup() app, admin = setup()
class TestForm(wtf.Form): class TestForm(form.BaseForm):
pass pass
view = MockModelView(Model, form=TestForm) view = MockModelView(Model, form=TestForm)
......
...@@ -43,8 +43,7 @@ setup( ...@@ -43,8 +43,7 @@ setup(
platforms='any', platforms='any',
install_requires=[ install_requires=[
'six>=1.2', 'six>=1.2',
'Flask>=0.7', 'Flask>=0.7'
'Flask-WTF>=0.6',
], ],
tests_require=[ tests_require=[
'nose>=1.0' 'nose>=1.0'
......
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