diff --git a/{{cookiecutter.app_name}}/manage.py b/{{cookiecutter.app_name}}/manage.py index 2f2fe20..6abed9e 100644 --- a/{{cookiecutter.app_name}}/manage.py +++ b/{{cookiecutter.app_name}}/manage.py @@ -1,8 +1,6 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- import os -import sys -import subprocess from flask_script import Manager, Shell, Server from flask_migrate import MigrateCommand @@ -21,12 +19,14 @@ TEST_PATH = os.path.join(HERE, 'tests') manager = Manager(app) + def _make_context(): """Return context dict for a shell session so you can access app, db, and the User model by default. """ return {'app': app, 'db': db, 'User': User} + @manager.command def test(): """Run the tests.""" @@ -34,6 +34,7 @@ def test(): exit_code = pytest.main([TEST_PATH, '--verbose']) return exit_code + manager.add_command('server', Server()) manager.add_command('shell', Shell(make_context=_make_context)) manager.add_command('db', MigrateCommand) diff --git a/{{cookiecutter.app_name}}/tests/conftest.py b/{{cookiecutter.app_name}}/tests/conftest.py index 1bfe570..31118e7 100644 --- a/{{cookiecutter.app_name}}/tests/conftest.py +++ b/{{cookiecutter.app_name}}/tests/conftest.py @@ -11,6 +11,7 @@ from {{cookiecutter.app_name}}.database import db as _db from .factories import UserFactory + @pytest.yield_fixture(scope='function') def app(): _app = create_app(TestConfig) @@ -21,11 +22,13 @@ def app(): ctx.pop() + @pytest.fixture(scope='function') def testapp(app): """A Webtest app.""" return TestApp(app) + @pytest.yield_fixture(scope='function') def db(app): _db.app = app diff --git a/{{cookiecutter.app_name}}/tests/factories.py b/{{cookiecutter.app_name}}/tests/factories.py index db06fd4..10b98ab 100644 --- a/{{cookiecutter.app_name}}/tests/factories.py +++ b/{{cookiecutter.app_name}}/tests/factories.py @@ -5,6 +5,7 @@ from factory.alchemy import SQLAlchemyModelFactory from {{cookiecutter.app_name}}.user.models import User from {{cookiecutter.app_name}}.database import db + class BaseFactory(SQLAlchemyModelFactory): class Meta: @@ -20,4 +21,3 @@ class UserFactory(BaseFactory): class Meta: model = User - diff --git a/{{cookiecutter.app_name}}/tests/test_config.py b/{{cookiecutter.app_name}}/tests/test_config.py index 691f5f6..c945dc7 100644 --- a/{{cookiecutter.app_name}}/tests/test_config.py +++ b/{{cookiecutter.app_name}}/tests/test_config.py @@ -2,6 +2,7 @@ from {{cookiecutter.app_name}}.app import create_app from {{cookiecutter.app_name}}.settings import ProdConfig, DevConfig + def test_production_config(): app = create_app(ProdConfig) assert app.config['ENV'] == 'prod' diff --git a/{{cookiecutter.app_name}}/tests/test_forms.py b/{{cookiecutter.app_name}}/tests/test_forms.py index 4a37d03..53e5bd0 100644 --- a/{{cookiecutter.app_name}}/tests/test_forms.py +++ b/{{cookiecutter.app_name}}/tests/test_forms.py @@ -5,6 +5,7 @@ from {{cookiecutter.app_name}}.public.forms import LoginForm from {{cookiecutter.app_name}}.user.forms import RegisterForm from .factories import UserFactory + class TestRegisterForm: def test_validate_user_already_registered(self, user): diff --git a/{{cookiecutter.app_name}}/tests/test_models.py b/{{cookiecutter.app_name}}/tests/test_models.py index f8fde0c..feb7078 100644 --- a/{{cookiecutter.app_name}}/tests/test_models.py +++ b/{{cookiecutter.app_name}}/tests/test_models.py @@ -7,6 +7,7 @@ import pytest from {{ cookiecutter.app_name }}.user.models import User, Role from .factories import UserFactory + @pytest.mark.usefixtures('db') class TestUser: diff --git a/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/app.py b/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/app.py index 47901f5..c945411 100644 --- a/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/app.py +++ b/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/app.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -'''The app module, containing the app factory function.''' +"""The app module, containing the app factory function.""" from flask import Flask, render_template from {{cookiecutter.app_name}}.settings import ProdConfig @@ -16,11 +16,11 @@ from {{cookiecutter.app_name}} import public, user def create_app(config_object=ProdConfig): - '''An application factory, as explained here: + """An application factory, as explained here: http://flask.pocoo.org/docs/patterns/appfactories/ :param config_object: The configuration object to use. - ''' + """ app = Flask(__name__) app.config.from_object(config_object) register_extensions(app) diff --git a/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/database.py b/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/database.py index 3120766..09f7f39 100644 --- a/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/database.py +++ b/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/database.py @@ -11,6 +11,7 @@ from .compat import basestring Column = db.Column relationship = relationship + class CRUDMixin(object): """Mixin that adds convenience methods for CRUD (create, read, update, delete) operations. @@ -44,6 +45,7 @@ class Model(CRUDMixin, db.Model): """Base model class that includes CRUD convenience methods.""" __abstract__ = True + # From Mike Bayer's "Building the app" talk # https://speakerdeck.com/zzzeek/building-the-app class SurrogatePK(object): diff --git a/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/public/__init__.py b/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/public/__init__.py index c6fdbc8..4260a43 100644 --- a/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/public/__init__.py +++ b/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/public/__init__.py @@ -1,4 +1,4 @@ # -*- coding: utf-8 -*- -'''The public module, including the homepage and user auth.''' +"""The public module, including the homepage and user auth.""" from . import views diff --git a/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/public/forms.py b/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/public/forms.py index eb834d0..43da1de 100644 --- a/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/public/forms.py +++ b/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/public/forms.py @@ -1,9 +1,11 @@ +# -*- coding: utf-8 -*- from flask_wtf import Form from wtforms import TextField, PasswordField from wtforms.validators import DataRequired from {{cookiecutter.app_name}}.user.models import User + class LoginForm(Form): username = TextField('Username', validators=[DataRequired()]) password = PasswordField('Password', validators=[DataRequired()]) diff --git a/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/public/views.py b/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/public/views.py index 36dce07..455fdb9 100644 --- a/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/public/views.py +++ b/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/public/views.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -'''Public section, including homepage and signup.''' +"""Public section, including homepage and signup.""" from flask import (Blueprint, request, render_template, flash, url_for, redirect, session) from flask.ext.login import login_user, login_required, logout_user @@ -13,6 +13,7 @@ from {{cookiecutter.app_name}}.database import db blueprint = Blueprint('public', __name__, static_folder="../static") + @login_manager.user_loader def load_user(id): return User.get_by_id(int(id)) @@ -32,6 +33,7 @@ def home(): flash_errors(form) return render_template("public/home.html", form=form) + @blueprint.route('/logout/') @login_required def logout(): @@ -39,6 +41,7 @@ def logout(): flash('You are logged out.', 'info') return redirect(url_for('public.home')) + @blueprint.route("/register/", methods=['GET', 'POST']) def register(): form = RegisterForm(request.form, csrf_enabled=False) @@ -53,6 +56,7 @@ def register(): flash_errors(form) return render_template('public/register.html', form=form) + @blueprint.route("/about/") def about(): form = LoginForm(request.form) diff --git a/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/settings.py b/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/settings.py index 51e6b12..683dc52 100644 --- a/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/settings.py +++ b/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/settings.py @@ -3,6 +3,7 @@ import os os_env = os.environ + class Config(object): SECRET_KEY = os_env.get('{{cookiecutter.app_name | upper}}_SECRET', 'secret-key') # TODO: Change me APP_DIR = os.path.abspath(os.path.dirname(__file__)) # This directory diff --git a/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/user/__init__.py b/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/user/__init__.py index fe9e0ac..a655bf1 100644 --- a/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/user/__init__.py +++ b/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/user/__init__.py @@ -1,3 +1,3 @@ -'''The user module.''' - +# -*- coding: utf-8 -*- +"""The user module.""" from . import views diff --git a/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/user/forms.py b/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/user/forms.py index 165e81f..f4ba798 100644 --- a/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/user/forms.py +++ b/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/user/forms.py @@ -1,9 +1,11 @@ +# -*- coding: utf-8 -*- from flask_wtf import Form from wtforms import TextField, PasswordField from wtforms.validators import DataRequired, Email, EqualTo, Length from .models import User + class RegisterForm(Form): username = TextField('Username', validators=[DataRequired(), Length(min=3, max=25)]) diff --git a/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/user/models.py b/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/user/models.py index 0d9c413..06ad15a 100644 --- a/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/user/models.py +++ b/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/user/models.py @@ -26,6 +26,7 @@ class Role(SurrogatePK, Model): def __repr__(self): return ''.format(name=self.name) + class User(UserMixin, SurrogatePK, Model): __tablename__ = 'users' diff --git a/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/user/views.py b/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/user/views.py index 9d6fd2e..e8c41ef 100644 --- a/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/user/views.py +++ b/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/user/views.py @@ -3,7 +3,7 @@ from flask import Blueprint, render_template from flask.ext.login import login_required blueprint = Blueprint("user", __name__, url_prefix='/users', - static_folder="../static") + static_folder="../static") @blueprint.route("/") diff --git a/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/utils.py b/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/utils.py index bfaf4fe..2def30c 100644 --- a/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/utils.py +++ b/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/utils.py @@ -1,10 +1,11 @@ # -*- coding: utf-8 -*- -'''Helper utilities and decorators.''' +"""Helper utilities and decorators.""" from flask import flash + def flash_errors(form, category="warning"): - '''Flash all errors for a form.''' + """Flash all errors for a form.""" for field, errors in form.errors.items(): for error in errors: flash("{0} - {1}" - .format(getattr(form, field).label.text, error), category) + .format(getattr(form, field).label.text, error), category)