├── .gitignore ├── LICENSE ├── README.md ├── apis ├── configure_secret.py ├── generate_feeds.py ├── handle_accept_header.py ├── paypal_ipn_verifier.py └── wordpress_xml_rpc.py ├── app.py ├── appstructure ├── admin_blueprint │ ├── __init__.py │ └── admin │ │ └── __init__.py ├── cherrpy_deploy │ ├── __init__.py │ ├── cherry.py │ └── hello.py ├── config_static │ └── __init__.py ├── create_with_func │ └── __init__.py ├── json_oriented │ ├── __init__.py │ ├── cherry.py │ └── hello.py ├── simple_config │ ├── __init__.py │ ├── hello.py │ └── websiteconfig.py ├── simple_pagination │ └── __init__.py ├── tornado_deploy │ ├── __init__.py │ ├── cyclone.py │ └── flasky.py └── zc.buildout │ ├── __init__.py │ └── buildout_env │ ├── README │ ├── bootstrap.py │ ├── buildout.cfg │ ├── etc │ └── deploy.ini.in │ ├── setup.py │ └── src │ └── hello │ ├── __init__.py │ ├── script.py │ └── tests.py ├── authentication ├── http_basic.py ├── http_digest.py ├── openid.py └── steamid.py ├── database ├── get_or_404.py ├── get_or_abort.py ├── lazy_sqlalchemy.py ├── mongokit_multithreaded_authentication.py ├── simple_insertion.py ├── simple_persistence.py ├── sqlalchemy_test_issues.py ├── support_objectid.py └── use_tornado_database.py ├── decorators ├── authorization.py ├── before_request_handler_for_coffeescript.py ├── conditional_requests_with_etags.py ├── http_access_control.py ├── http_headers.py ├── jsonp.py ├── rate_limit_with_redis.py ├── ssl_view.py └── view_render.py ├── deployment ├── apache_host.wsgi ├── cherokee_fix.py ├── dotcloud.py ├── fix_connection_reset_post.py ├── fix_url_behind_reverse.py ├── pass_remote_user.py └── webfaction.py ├── forms ├── complex_validation.py ├── form_from_model.py ├── render_wtform_without_syntaxerr.py ├── secure_redirect_back.py └── validate_flatland.py ├── internationalizatioin └── babel_lazyproxy.py ├── javascript ├── filter_for_timeago.py ├── push_notifications.py └── realtime_using_sse.py ├── performance ├── add_caching.py └── sqlite_cache.py ├── security ├── csrf_protect.py ├── redirect_back.py ├── salted_password.py └── serve_https.py ├── sessions ├── beaker_session.py ├── better_client_session.py ├── count_online_users.py ├── file_session.py ├── mongodb_session.py ├── old_new_session.py ├── redis_session.py ├── sqlite_session.py └── unittest_example.py ├── template.py ├── templatetricks ├── enable_line_statement.py ├── gae_correct_errors.py ├── generate_pdf.py ├── latex_second_jinja.py ├── link_form_macro.py ├── nl2br_filter.py ├── number_format.py ├── override_autoescaped.py ├── timesince_filter.py ├── use_genshi.py └── use_markdown.py ├── urls ├── catch_all.py ├── generate_sitemap.py ├── generate_slug.py ├── list_routes.py ├── permalink.py ├── static_cache_buster.py ├── support_semicolon.py ├── url_contain_slash.py └── url_payload.py └── utilities ├── after_request_per.py ├── cms_pages.py ├── content_negotiated_error.py ├── context_global_socketio.py ├── custom_http_method.py ├── flask_mail.py ├── flask_testcase.py ├── import_css_string.py ├── interactive_shell.py ├── json_encoder.py ├── local_proxy.py ├── nice_errors.py ├── override_httpmethod.py ├── reloading.py ├── rq.py ├── serve_transcompiling.py ├── set_cookies.py ├── share_server.py ├── shutdown_server.py ├── sqlite_q.py ├── stream_proxy.py ├── trigger_debuggr.py ├── turbomail.py ├── upload_stringio.py └── wtform_flash_error.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | 3 | # C extensions 4 | *.so 5 | 6 | # Packages 7 | *.egg 8 | *.egg-info 9 | dist 10 | build 11 | eggs 12 | parts 13 | bin 14 | var 15 | sdist 16 | develop-eggs 17 | .installed.cfg 18 | lib 19 | lib64 20 | __pycache__ 21 | 22 | # Installer logs 23 | pip-log.txt 24 | 25 | # Unit test / coverage reports 26 | .coverage 27 | .tox 28 | nosetests.xml 29 | 30 | # Translations 31 | *.mo 32 | 33 | # Mr Developer 34 | .mr.developer.cfg 35 | .project 36 | .pydevproject 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 by Flask snippets authors at 2 | http://flask.pocoo.org/snippets/. 3 | 4 | Some rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are 8 | met: 9 | 10 | * Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above 14 | copyright notice, this list of conditions and the following 15 | disclaimer in the documentation and/or other materials provided 16 | with the distribution. 17 | 18 | * The names of the contributors may not be used to endorse or 19 | promote products derived from this software without specific 20 | prior written permission. 21 | 22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Flask Snippets 2 | ============== 3 | 4 | Code of official [Flask Snippets](http://flask.pocoo.org/snippets/ "flask-snippets"). 5 |
6 | ![Flask Snippets](http://flask.pocoo.org/static/snippets.png "Flask Snippets") 7 | -------------------------------------------------------------------------------- /apis/configure_secret.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | apis.configure_secret 4 | ~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Configure SECRET_KEY from a file in the instance directory. 7 | http://flask.pocoo.org/snippets/104/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from flask import request, Response 15 | 16 | from app import app 17 | 18 | 19 | def install_secret_key(app, filename='secret_key'): 20 | """Configure the SECRET_KEY from a file 21 | in the instance directory. 22 | 23 | If the file does not exist, print instructions 24 | to create it from a shell with a random key, 25 | then exit. 26 | 27 | """ 28 | filename = os.path.join(app.instance_path, filename) 29 | try: 30 | app.config['SECRET_KEY'] = open(filename, 'rb').read() 31 | except IOError: 32 | print 'Error: No secret key. Create it with:' 33 | if not os.path.isdir(os.path.dirname(filename)): 34 | print 'mkdir -p', os.path.dirname(filename) 35 | print 'head -c 24 /dev/urandom >', filename 36 | sys.exit(1) 37 | 38 | 39 | @app.route('/') 40 | def index(): 41 | return 'index' 42 | 43 | 44 | if __name__ == "__main__": 45 | install_secret_key(app) 46 | app.run() 47 | -------------------------------------------------------------------------------- /apis/generate_feeds.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | apis.generate_feeds 4 | ~~~~~~~~~~~~~~~~~~~ 5 | 6 | Generating Feeds with Flask 7 | http://flask.pocoo.org/snippets/10/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | from urlparse import urljoin 14 | 15 | from flask import request, Response 16 | from werkzeug.contrib.atom import AtomFeed 17 | 18 | from app import app 19 | 20 | 21 | def make_external(url): 22 | return urljoin(request.url_root, url) 23 | 24 | 25 | @app.route('/recent.atom') 26 | def recent_feed(): 27 | feed = AtomFeed('Recent Articles', 28 | feed_url=request.url, url=request.url_root) 29 | articles = Article.query.order_by(Article.pub_date.desc()) \ 30 | .limit(15).all() 31 | for article in articles: 32 | feed.add(article.title, unicode(article.rendered_text), 33 | content_type='html', 34 | author=article.author.name, 35 | url=make_external(article.url), 36 | updated=article.last_update, 37 | published=article.published) 38 | return feed.get_response() 39 | 40 | 41 | @app.route('/') 42 | def index(): 43 | return 'index' 44 | 45 | 46 | if __name__ == "__main__": 47 | app.run() 48 | -------------------------------------------------------------------------------- /apis/handle_accept_header.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | apis.handle_accept_headers 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Handling Accept Headers 7 | http://flask.pocoo.org/snippets/45/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from flask import request, Response 15 | from flask import jsonify 16 | 17 | from app import app 18 | 19 | 20 | class Dummy(object): 21 | 22 | def to_json(self): 23 | return {'name': 'fsp'} 24 | 25 | 26 | def get_items_from_database(): 27 | for i in range(10): 28 | yield Dummy() 29 | 30 | 31 | def request_wants_json(): 32 | best = request.accept_mimetypes \ 33 | .best_match(['application/json', 'text/html']) 34 | return best == 'application/json' and \ 35 | request.accept_mimetypes[best] > \ 36 | request.accept_mimetypes['text/html'] 37 | 38 | 39 | @app.route('/') 40 | def show_items(): 41 | items = get_items_from_database() 42 | if request_wants_json(): 43 | return jsonify(items=[x.to_json() for x in items]) 44 | return 'index' 45 | 46 | 47 | if __name__ == "__main__": 48 | app.run() 49 | -------------------------------------------------------------------------------- /apis/paypal_ipn_verifier.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | apis.paypal_ipn_verifier 4 | ~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Paypal IPN Verifier for Flask 7 | http://flask.pocoo.org/snippets/112/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from flask import request, Response 15 | 16 | from app import app 17 | 18 | 19 | IPN_URLSTRING = 'https://www.sandbox.paypal.com/cgi-bin/webscr' 20 | IPN_VERIFY_EXTRA_PARAMS = (('cmd', '_notify-validate'),) 21 | from itertools import chain 22 | 23 | 24 | def ordered_storage(f): 25 | import werkzeug.datastructures 26 | import flask 27 | def decorator(*args, **kwargs): 28 | flask.request.parameter_storage_class = werkzeug.datastructures.ImmutableOrderedMultiDict 29 | return f(*args, **kwargs) 30 | return decorator 31 | 32 | 33 | @app.route('/paypal/', methods=['POST']) 34 | @ordered_storage 35 | def paypal_webhook(): 36 | #probably should have a sanity check here on the size of the form data to guard against DoS attacks 37 | verify_args = chain(request.form.iteritems(), IPN_VERIFY_EXTRA_PARAMS) 38 | verify_string = '&'.join(('%s=%s' % (param, value) for param, value in verify_args)) 39 | #req = Request(verify_string) 40 | response = urlopen(IPN_URLSTRING, data=verify_string) 41 | status = response.read() 42 | print status 43 | if status == 'VERIFIED': 44 | print "PayPal transaction was verified successfully." 45 | # Do something with the verified transaction details. 46 | payer_email = request.form.get('payer_email') 47 | print "Pulled {email} from transaction".format(email=payer_email) 48 | else: 49 | print 'Paypal IPN string {arg} did not validate'.format(arg=verify_string) 50 | 51 | return jsonify({'status':'complete'}) 52 | 53 | 54 | @app.route('/') 55 | def index(): 56 | return 'index' 57 | 58 | 59 | if __name__ == "__main__": 60 | app.run() 61 | -------------------------------------------------------------------------------- /apis/wordpress_xml_rpc.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | apis.wordpress_xml_rpc 4 | ~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Wordpress-compatible XML-RPC API 7 | http://flask.pocoo.org/snippets/96/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from flask import request, Response 15 | 16 | from app import app 17 | 18 | 19 | import string 20 | from datetime import datetime 21 | from flask import url_for 22 | from flask.ext.xmlrpc import XMLRPCHandler, Fault 23 | from labs import app, db 24 | from labs.models import User, Post, Tag, Category 25 | 26 | 27 | POST_ROOT = 'http://127.0.0.1/post/' 28 | 29 | # MetaWeblogAPI XML-RPC 30 | handler = XMLRPCHandler('api') 31 | handler.connect(app, '/api') 32 | metaweblog = handler.namespace('metaWeblog') 33 | blogger = handler.namespace('blogger') 34 | wordpress = handler.namespace('wp') 35 | moveabletype = handler.namespace('mt') 36 | 37 | 38 | @metaweblog.register 39 | def newPost(blog_id, username, password, content, publish): 40 | user = db.session.query(User).filter(User.username == username).first() 41 | if user is None or not user.check_password(password): 42 | raise Fault("invalid_user", 43 | "Invalid username/password, please try again.") 44 | post = Post(content['title'], content['description']) 45 | post.author = user 46 | post.teaser = content['mt_excerpt'] 47 | if 'wp_slug' in content: 48 | post.slug = content['wp_slug'] 49 | if 'dateCreated' in content: 50 | post.create_date = datetime.strptime(str(content['dateCreated']), 51 | "%Y%m%dT%H:%M:%SZ") 52 | if 'custom_fields' in content: 53 | for custom_field in content['custom_fields']: 54 | if custom_field['key'] == 'subtitle': 55 | post.subtitle = custom_field['value'] 56 | elif custom_field['key'] == 'lead_img': 57 | post.lead_img = custom_field['value'] 58 | tag_names = string.split(content['mt_tags'], ',') 59 | for tag_name in tag_names: 60 | tag = Tag.query.filter(Tag.name == tag_name).first() 61 | if tag is None: 62 | tag = Tag(tag_name) 63 | db.session.add(tag) 64 | db.session.commit() 65 | post.tags.append(tag) 66 | db.session.add(post) 67 | db.session.commit() 68 | return post.id 69 | 70 | 71 | @metaweblog.register 72 | def editPost(post_id, username, password, content, publish): 73 | user = db.session.query(User).filter(User.username == username).first() 74 | if user is None or not user.check_password(password): 75 | raise Fault("invalid_user", 76 | "Invalid username/password, please try again.") 77 | post = Post.query.get(post_id) 78 | post.title = content['title'] 79 | post.markdown = content['description'] 80 | post.set_html() 81 | post.teaser = content['mt_excerpt'] 82 | if 'wp_slug' in content: 83 | post.slug = content['wp_slug'] 84 | if 'dateCreated' in content: 85 | post.create_date = datetime.strptime(str(content['dateCreated']), 86 | "%Y%m%dT%H:%M:%SZ") 87 | if 'custom_fields' in content: 88 | for custom_field in content['custom_fields']: 89 | if custom_field['key'] == 'subtitle': 90 | post.subtitle = custom_field['value'] 91 | elif custom_field['key'] == 'lead_img': 92 | post.lead_img = custom_field['value'] 93 | tag_names = string.split(content['mt_tags'], ',') 94 | tags = [] 95 | for tag_name in tag_names: 96 | tag = Tag.query.filter(Tag.name == tag_name).first() 97 | if tag is None: 98 | tag = Tag(tag_name) 99 | db.session.add(tag) 100 | db.session.commit() 101 | tags.append(tag) 102 | post.tags = tags 103 | db.session.add(post) 104 | db.session.commit() 105 | return True 106 | 107 | 108 | @metaweblog.register 109 | def getPost(post_id, username, password): 110 | user = db.session.query(User).filter(User.username == username).first() 111 | if user is None or not user.check_password(password): 112 | raise Fault("invalid_user", 113 | "Invalid username/password, please try again.") 114 | post = Post.query.filter(Post.id == post_id).first() 115 | if not post: 116 | raise Fault("not_found", "Post not found.") 117 | item = {} 118 | item['title'] = post.title 119 | item['link'] = POST_ROOT + post.slug 120 | item['description'] = post.markdown 121 | item['postid'] = post.id 122 | item['mt_excerpt'] = post.teaser 123 | item['custom_fields'] = [ 124 | { 125 | 'key': 'subtitle', 126 | 'value': post.subtitle 127 | }, 128 | { 129 | 'key': 'lead_img', 130 | 'value': post.lead_img 131 | } 132 | ] 133 | item['wp_slug'] = post.slug 134 | if post.tags: 135 | item['mt_tags'] = ','.join(map(lambda tag: tag.name, post.tags)) 136 | item['dateCreated'] = post.create_date 137 | return item 138 | 139 | 140 | @metaweblog.register 141 | def getRecentPosts(blogid, username, password, numberOfPosts): 142 | user = db.session.query(User).filter(User.username == username).first() 143 | if user is None or not user.check_password(password): 144 | raise Fault("invalid_user", 145 | "Invalid username/password, please try again.") 146 | posts = Post.query.order_by('create_date').all() 147 | response = [] 148 | for post in posts: 149 | item = {} 150 | item['title'] = post.title 151 | item['link'] = POST_ROOT + post.slug 152 | item['description'] = post.markdown 153 | item['postid'] = post.id 154 | item['mt_excerpt'] = post.teaser 155 | item['wp_slug'] = post.slug 156 | item['custom_fields'] = [ 157 | { 158 | 'key': 'subtitle', 159 | 'value': post.subtitle 160 | }, 161 | { 162 | 'key': 'lead_img', 163 | 'value': post.lead_img 164 | } 165 | ] 166 | tags = [] 167 | for tag in post.tags: 168 | tags.append(tag.name) 169 | item['mt_tags'] = ','.join(tags) 170 | item['dateCreated'] = post.create_date 171 | # if post['draft']: 172 | # item['draft'] = 'Yes' 173 | response.append(item) 174 | return response 175 | 176 | 177 | @wordpress.register 178 | def getPages(blogid, username, password, numberOfPages): 179 | return [] 180 | 181 | 182 | @wordpress.register 183 | def newCategory(blogid, username, password, new_category): 184 | user = db.session.query(User).filter(User.username == username).first() 185 | if user is None or not user.check_password(password): 186 | raise Fault("invalid_user", 187 | "Invalid username/password, please try again.") 188 | category = Category.query.filter(Category.name == new_category['name']).first() 189 | if category is None: 190 | category = Category(new_category['name']) 191 | db.session.add(category) 192 | db.session.commit() 193 | return category.id 194 | 195 | 196 | @wordpress.register 197 | def getTags(blogid, username, password): 198 | return map(lambda tag: { 199 | 'tag_id': tag.id, 200 | 'name': tag.name 201 | }, Tag.query.all()) 202 | 203 | 204 | @wordpress.register 205 | def getCategories(blogid, username, password): 206 | return map(lambda category: { 207 | 'categoryId': category.id, 208 | 'categoryName': category.name, 209 | 'categoryDescription': category.description 210 | }, Category.query.all()) 211 | 212 | 213 | @moveabletype.register 214 | def setPostCategories(post_id, username, password, post_categories): 215 | post = Post.query.get(post_id) 216 | for post_category in post_categories: 217 | category = Category.query.filter( 218 | Category.name == post_category['categoryName'] 219 | ).first() 220 | # only single category per post supported 221 | post.category = category 222 | db.session.add(post) 223 | db.session.commit() 224 | return True 225 | 226 | 227 | @moveabletype.register 228 | def getPostCategories(post_id, username, password): 229 | # only single per post supported 230 | category = Post.query.get(post_id).category 231 | if category is not None: 232 | post_category = { 233 | 'categoryId': category.id, 234 | 'categoryName': category.name, 235 | 'categoryDescription': category.description 236 | } 237 | return [post_category] 238 | return [] 239 | 240 | 241 | @moveabletype.register 242 | def supportedTextFilters(): 243 | return [] 244 | 245 | 246 | @blogger.register 247 | def deletePost(appkey, post_id, username, password, publish): 248 | user = db.session.query(User).filter(User.username == username).first() 249 | if user is None or not user.check_password(password): 250 | raise Fault("invalid_user", 251 | "Invalid username/password, please try again.") 252 | post = Post.query.get(int(post_id)) 253 | db.session.delete(post) 254 | db.session.commit() 255 | pass 256 | 257 | 258 | @app.route('/') 259 | def index(): 260 | return 'index' 261 | 262 | 263 | if __name__ == "__main__": 264 | app.run() 265 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | flask.app 4 | ~~~~~~~~~ 5 | 6 | App for flask-snippets 7 | 8 | :copyright: (c) 2013 by fsp. 9 | :license: BSD. 10 | """ 11 | 12 | from flask import Flask 13 | 14 | 15 | app = Flask(__name__) 16 | app.debug = True 17 | app.secret_key = 'flask-snippets-fsp' 18 | 19 | 20 | if __name__ == "__main__": 21 | app.run() 22 | -------------------------------------------------------------------------------- /appstructure/admin_blueprint/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | appstructure.admin_blueprint 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Admin Blueprint 7 | http://flask.pocoo.org/snippets/59/ 8 | """ 9 | 10 | from flask import Flask 11 | import admin 12 | 13 | 14 | app = Flask(__name__) 15 | app.register_blueprint(admin.bp, url_prefix='/admin') 16 | -------------------------------------------------------------------------------- /appstructure/admin_blueprint/admin/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from flask import Blueprint 3 | from flask import redirect, request 4 | from google.appengine.api import users 5 | 6 | bp = Blueprint('admin', __name__) 7 | 8 | @bp.before_request 9 | def restrict_bp_to_admins(): 10 | if not users.is_current_user_admin(): 11 | return redirect(users.create_login_url(request.url)) 12 | -------------------------------------------------------------------------------- /appstructure/cherrpy_deploy/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | appstructure.cherrpy_deploy 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Deploying Flask on Cherrypy WSGI server 7 | http://flask.pocoo.org/snippets/24/ 8 | """ 9 | -------------------------------------------------------------------------------- /appstructure/cherrpy_deploy/cherry.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from cherrypy import wsgiserver 3 | 4 | from hello import app 5 | 6 | 7 | d = wsgiserver.WSGIPathInfoDispatcher({'/': app}) 8 | server = wsgiserver.CherryPyWSGIServer(('0.0.0.0', 8080), d) 9 | 10 | 11 | if __name__ == "__main__": 12 | try: 13 | server.start() 14 | except KeyboardInterrupt: 15 | server.stop() 16 | -------------------------------------------------------------------------------- /appstructure/cherrpy_deploy/hello.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from flask import Flask 3 | 4 | 5 | app = Flask(__name__) 6 | 7 | 8 | @app.route("/") 9 | def hello(): 10 | return "Hello World!" 11 | -------------------------------------------------------------------------------- /appstructure/config_static/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | appstructure.config_static 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Config-based static_folder 7 | http://flask.pocoo.org/snippets/102/ 8 | """ 9 | 10 | import flask 11 | 12 | 13 | class MyFlask(flask.Flask): 14 | @property 15 | def static_folder(self): 16 | if self.config.get('STATIC_FOLDER') is not None: 17 | return os.path.join(self.root_path, 18 | self.config.get('STATIC_FOLDER')) 19 | @static_folder.setter 20 | def static_folder(self, value): 21 | self.config.get('STATIC_FOLDER') = value 22 | 23 | 24 | # Now these are equivalent: 25 | app = Flask(__name__, static_folder='foo') 26 | 27 | 28 | app = MyFlask(__name__) 29 | app.config['STATIC_FOLDER'] = 'foo' 30 | -------------------------------------------------------------------------------- /appstructure/create_with_func/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | appstructure.create_with_func 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Create your app with a function 7 | http://flask.pocoo.org/snippets/20/ 8 | """ 9 | 10 | from flask import Flask 11 | from sqlalchemy import create_engine 12 | 13 | from myapp import config 14 | from myapp.views import frontend 15 | 16 | 17 | def create_app(database_uri, debug=False): 18 | app = Flask(__name__) 19 | app.debug = debug 20 | 21 | # set up your database 22 | app.engine = create_engine(database_uri) 23 | 24 | # add your modules 25 | app.register_module(frontend) 26 | 27 | # other setup tasks 28 | 29 | return app 30 | 31 | 32 | if __name__ == "__main__": 33 | app = create_app(config.DATABASE_URI, debug=True) 34 | app.run() 35 | """ 36 | import unittest 37 | 38 | from myapp import config 39 | from myapp import create_app 40 | 41 | class TestCase(unittest.TestCase): 42 | def setUp(self): 43 | self.app = create_app(config.TEST_DATABASE_URI) 44 | self.client = self.app.test_client() 45 | """ 46 | -------------------------------------------------------------------------------- /appstructure/json_oriented/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | appstructure.json_oriented 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Specialized JSON-oriented Flask App 7 | http://flask.pocoo.org/snippets/83/ 8 | """ 9 | from flask import Flask, jsonify 10 | from werkzeug.exceptions import default_exceptions 11 | from werkzeug.exceptions import HTTPException 12 | 13 | __all__ = ['make_json_app'] 14 | 15 | def make_json_app(import_name, **kwargs): 16 | """ 17 | Creates a JSON-oriented Flask app. 18 | 19 | All error responses that you don't specifically 20 | manage yourself will have application/json content 21 | type, and will contain JSON like this (just an example): 22 | 23 | { "message": "405: Method Not Allowed" } 24 | """ 25 | def make_json_error(ex): 26 | response = jsonify(message=str(ex)) 27 | response.status_code = (ex.code 28 | if isinstance(ex, HTTPException) 29 | else 500) 30 | return response 31 | 32 | app = Flask(import_name, **kwargs) 33 | 34 | for code in default_exceptions.iterkeys(): 35 | app.error_handler_spec[None][code] = make_json_error 36 | 37 | return app 38 | -------------------------------------------------------------------------------- /appstructure/json_oriented/cherry.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from cherrypy import wsgiserver 3 | 4 | from hello import app 5 | 6 | 7 | d = wsgiserver.WSGIPathInfoDispatcher({'/': app}) 8 | server = wsgiserver.CherryPyWSGIServer(('0.0.0.0', 8080), d) 9 | 10 | 11 | if __name__ == "__main__": 12 | try: 13 | server.start() 14 | except KeyboardInterrupt: 15 | server.stop() 16 | -------------------------------------------------------------------------------- /appstructure/json_oriented/hello.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from flask import Flask 3 | 4 | 5 | app = Flask(__name__) 6 | 7 | 8 | @app.route("/") 9 | def hello(): 10 | return "Hello World!" 11 | -------------------------------------------------------------------------------- /appstructure/simple_config/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | appstructure.simple_config 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Simple Configuration Module 7 | http://flask.pocoo.org/snippets/2/ 8 | """ 9 | -------------------------------------------------------------------------------- /appstructure/simple_config/hello.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from flask import Flask 3 | 4 | import websiteconfig 5 | 6 | app = Flask(__name__) 7 | 8 | 9 | app.debug = websiteconfig.DEBUG 10 | app.secret_key = websiteconfig.SECRET_KEY 11 | 12 | 13 | @app.route("/") 14 | def hello(): 15 | return "Hello World!" 16 | -------------------------------------------------------------------------------- /appstructure/simple_config/websiteconfig.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | DEBUG = False 3 | SECRET_KEY = 'mysecretkey' 4 | DATABASE_URI = 'sqlite:////tmp/myapp.db 5 | -------------------------------------------------------------------------------- /appstructure/simple_pagination/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | appstructure.simple_pagination 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Simple Pagination 7 | http://flask.pocoo.org/snippets/44/ 8 | """ 9 | from math import ceil 10 | 11 | 12 | class Pagination(object): 13 | 14 | def __init__(self, page, per_page, total_count): 15 | self.page = page 16 | self.per_page = per_page 17 | self.total_count = total_count 18 | 19 | @property 20 | def pages(self): 21 | return int(ceil(self.total_count / float(self.per_page))) 22 | 23 | @property 24 | def has_prev(self): 25 | return self.page > 1 26 | 27 | @property 28 | def has_next(self): 29 | return self.page < self.pages 30 | 31 | def iter_pages(self, left_edge=2, left_current=2, 32 | right_current=5, right_edge=2): 33 | last = 0 34 | for num in xrange(1, self.pages + 1): 35 | if num <= left_edge or \ 36 | (num > self.page - left_current - 1 and \ 37 | num < self.page + right_current) or \ 38 | num > self.pages - right_edge: 39 | if last + 1 != num: 40 | yield None 41 | yield num 42 | last = num 43 | 44 | 45 | def url_for_other_page(page): 46 | args = request.view_args.copy() 47 | args['page'] = page 48 | return url_for(request.endpoint, **args) 49 | app.jinja_env.globals['url_for_other_page'] = url_for_other_page 50 | 51 | 52 | from flask import redirect 53 | 54 | PER_PAGE = 20 55 | 56 | @app.route('/users/', defaults={'page': 1}) 57 | @app.route('/users/page/') 58 | def show_users(page): 59 | count = count_all_users() 60 | users = get_users_for_page(page, PER_PAGE, count) 61 | if not users and page != 1: 62 | abort(404) 63 | pagination = Pagination(page, PER_PAGE, count) 64 | return render_template('users.html', 65 | pagination=pagination, 66 | users=users 67 | ) 68 | 69 | 70 | """ 71 | {% macro render_pagination(pagination) %} 72 | 89 | {% endmacro %} 90 | """ 91 | -------------------------------------------------------------------------------- /appstructure/tornado_deploy/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | appstructure.tornado_deploy 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Mix Flask and Tornado together 7 | http://flask.pocoo.org/snippets/78/ 8 | """ 9 | -------------------------------------------------------------------------------- /appstructure/tornado_deploy/cyclone.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from tornado.wsgi import WSGIContainer 3 | from tornado.ioloop import IOLoop 4 | from tornado.web import FallbackHandler, RequestHandler, Application 5 | 6 | from flasky import app 7 | 8 | 9 | class MainHandler(RequestHandler): 10 | def get(self): 11 | self.write("This message comes from Tornado ^_^") 12 | 13 | tr = WSGIContainer(app) 14 | 15 | 16 | application = Application([ 17 | (r"/tornado", MainHandler), 18 | (r".*", FallbackHandler, dict(fallback=tr)), 19 | ]) 20 | 21 | 22 | if __name__ == "__main__": 23 | application.listen(8000) 24 | IOLoop.instance().start() 25 | -------------------------------------------------------------------------------- /appstructure/tornado_deploy/flasky.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from flask import Flask 3 | 4 | 5 | app = Flask(__name__) 6 | 7 | 8 | @app.route("/flask") 9 | def hello_world(): 10 | return 'This comes from Flask ^_^' 11 | -------------------------------------------------------------------------------- /appstructure/zc.buildout/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | appstructure.zc.buildout 4 | ~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Deploy using zc.buildout and PythonPaste 7 | http://flask.pocoo.org/snippets/27/ 8 | """ 9 | 10 | """ 11 | Deploy the application 12 | First, you could save the buildout directory using your favorite DVCS, or create a tarball for future deployments. 13 | 14 | Then bootstrap the buildout: 15 | 16 | ~/buildout_env $ python bootstrap.py --distribute 17 | Adjust your settings in buildout.cfg, and build the application: 18 | 19 | ~/buildout_env $ bin/buildout 20 | Run the tests: 21 | 22 | ~/buildout_env $ bin/test 23 | Test rendered page. ... ok 24 | 25 | ------------------------------------------------------------ 26 | Ran 1 test in 0.055s 27 | 28 | OK 29 | ~/buildout_env $ 30 | Now launch the server: 31 | 32 | ~/buildout_env $ bin/flask-ctl debug fg 33 | bin/paster serve parts/etc/debug.ini --reload 34 | Starting subprocess with file monitor 35 | Starting server in PID 24862. 36 | serving on http://127.0.0.1:5000 37 | Visit http://127.0.0.1:5000 with your browser. 38 | Visit http://127.0.0.1:5000/?broken to bring the Werkzeug Debugger. Quit the application with Ctrl+C. 39 | 40 | Note: when you change the configuration in buildout.cfg, you need to rebuild the application using bin/buildout. 41 | 42 | Further reading: 43 | 44 | http://www.buildout.org 45 | http://pythonpaste.org 46 | 47 | """ 48 | -------------------------------------------------------------------------------- /appstructure/zc.buildout/buildout_env/README: -------------------------------------------------------------------------------- 1 | / hello / 2 | 3 | "Hello World!" application 4 | -------------------------------------------------------------------------------- /appstructure/zc.buildout/buildout_env/bootstrap.py: -------------------------------------------------------------------------------- 1 | ############################################################################## 2 | # 3 | # Copyright (c) 2006 Zope Foundation and Contributors. 4 | # All Rights Reserved. 5 | # 6 | # This software is subject to the provisions of the Zope Public License, 7 | # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. 8 | # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED 9 | # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 10 | # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS 11 | # FOR A PARTICULAR PURPOSE. 12 | # 13 | ############################################################################## 14 | """Bootstrap a buildout-based project 15 | 16 | Simply run this script in a directory containing a buildout.cfg. 17 | The script accepts buildout command-line options, so you can 18 | use the -c option to specify an alternate configuration file. 19 | """ 20 | 21 | import os, shutil, sys, tempfile, urllib, urllib2, subprocess 22 | from optparse import OptionParser 23 | 24 | if sys.platform == 'win32': 25 | def quote(c): 26 | if ' ' in c: 27 | return '"%s"' % c # work around spawn lamosity on windows 28 | else: 29 | return c 30 | else: 31 | quote = str 32 | 33 | # See zc.buildout.easy_install._has_broken_dash_S for motivation and comments. 34 | stdout, stderr = subprocess.Popen( 35 | [sys.executable, '-Sc', 36 | 'try:\n' 37 | ' import ConfigParser\n' 38 | 'except ImportError:\n' 39 | ' print 1\n' 40 | 'else:\n' 41 | ' print 0\n'], 42 | stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() 43 | has_broken_dash_S = bool(int(stdout.strip())) 44 | 45 | # In order to be more robust in the face of system Pythons, we want to 46 | # run without site-packages loaded. This is somewhat tricky, in 47 | # particular because Python 2.6's distutils imports site, so starting 48 | # with the -S flag is not sufficient. However, we'll start with that: 49 | if not has_broken_dash_S and 'site' in sys.modules: 50 | # We will restart with python -S. 51 | args = sys.argv[:] 52 | args[0:0] = [sys.executable, '-S'] 53 | args = map(quote, args) 54 | os.execv(sys.executable, args) 55 | # Now we are running with -S. We'll get the clean sys.path, import site 56 | # because distutils will do it later, and then reset the path and clean 57 | # out any namespace packages from site-packages that might have been 58 | # loaded by .pth files. 59 | clean_path = sys.path[:] 60 | import site # imported because of its side effects 61 | sys.path[:] = clean_path 62 | for k, v in sys.modules.items(): 63 | if k in ('setuptools', 'pkg_resources') or ( 64 | hasattr(v, '__path__') and 65 | len(v.__path__) == 1 and 66 | not os.path.exists(os.path.join(v.__path__[0], '__init__.py'))): 67 | # This is a namespace package. Remove it. 68 | sys.modules.pop(k) 69 | 70 | is_jython = sys.platform.startswith('java') 71 | 72 | setuptools_source = 'http://peak.telecommunity.com/dist/ez_setup.py' 73 | distribute_source = 'http://python-distribute.org/distribute_setup.py' 74 | 75 | 76 | # parsing arguments 77 | def normalize_to_url(option, opt_str, value, parser): 78 | if value: 79 | if '://' not in value: # It doesn't smell like a URL. 80 | value = 'file://%s' % ( 81 | urllib.pathname2url( 82 | os.path.abspath(os.path.expanduser(value))),) 83 | if opt_str == '--download-base' and not value.endswith('/'): 84 | # Download base needs a trailing slash to make the world happy. 85 | value += '/' 86 | else: 87 | value = None 88 | name = opt_str[2:].replace('-', '_') 89 | setattr(parser.values, name, value) 90 | 91 | usage = '''\ 92 | [DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options] 93 | 94 | Bootstraps a buildout-based project. 95 | 96 | Simply run this script in a directory containing a buildout.cfg, using the 97 | Python that you want bin/buildout to use. 98 | 99 | Note that by using --setup-source and --download-base to point to 100 | local resources, you can keep this script from going over the network. 101 | ''' 102 | 103 | parser = OptionParser(usage=usage) 104 | parser.add_option("-v", "--version", dest="version", 105 | help="use a specific zc.buildout version") 106 | parser.add_option("-d", "--distribute", 107 | action="store_true", dest="use_distribute", default=False, 108 | help="Use Distribute rather than Setuptools.") 109 | parser.add_option("--setup-source", action="callback", dest="setup_source", 110 | callback=normalize_to_url, nargs=1, type="string", 111 | help=("Specify a URL or file location for the setup file. " 112 | "If you use Setuptools, this will default to " + 113 | setuptools_source + "; if you use Distribute, this " 114 | "will default to " + distribute_source + ".")) 115 | parser.add_option("--download-base", action="callback", dest="download_base", 116 | callback=normalize_to_url, nargs=1, type="string", 117 | help=("Specify a URL or directory for downloading " 118 | "zc.buildout and either Setuptools or Distribute. " 119 | "Defaults to PyPI.")) 120 | parser.add_option("--eggs", 121 | help=("Specify a directory for storing eggs. Defaults to " 122 | "a temporary directory that is deleted when the " 123 | "bootstrap script completes.")) 124 | parser.add_option("-t", "--accept-buildout-test-releases", 125 | dest='accept_buildout_test_releases', 126 | action="store_true", default=False, 127 | help=("Normally, if you do not specify a --version, the " 128 | "bootstrap script and buildout gets the newest " 129 | "*final* versions of zc.buildout and its recipes and " 130 | "extensions for you. If you use this flag, " 131 | "bootstrap and buildout will get the newest releases " 132 | "even if they are alphas or betas.")) 133 | parser.add_option("-c", None, action="store", dest="config_file", 134 | help=("Specify the path to the buildout configuration " 135 | "file to be used.")) 136 | 137 | options, args = parser.parse_args() 138 | 139 | # if -c was provided, we push it back into args for buildout's main function 140 | if options.config_file is not None: 141 | args += ['-c', options.config_file] 142 | 143 | if options.eggs: 144 | eggs_dir = os.path.abspath(os.path.expanduser(options.eggs)) 145 | else: 146 | eggs_dir = tempfile.mkdtemp() 147 | 148 | if options.setup_source is None: 149 | if options.use_distribute: 150 | options.setup_source = distribute_source 151 | else: 152 | options.setup_source = setuptools_source 153 | 154 | if options.accept_buildout_test_releases: 155 | args.append('buildout:accept-buildout-test-releases=true') 156 | args.append('bootstrap') 157 | 158 | try: 159 | import pkg_resources 160 | import setuptools # A flag. Sometimes pkg_resources is installed alone. 161 | if not hasattr(pkg_resources, '_distribute'): 162 | raise ImportError 163 | except ImportError: 164 | ez_code = urllib2.urlopen( 165 | options.setup_source).read().replace('\r\n', '\n') 166 | ez = {} 167 | exec ez_code in ez 168 | setup_args = dict(to_dir=eggs_dir, download_delay=0) 169 | if options.download_base: 170 | setup_args['download_base'] = options.download_base 171 | if options.use_distribute: 172 | setup_args['no_fake'] = True 173 | ez['use_setuptools'](**setup_args) 174 | if 'pkg_resources' in sys.modules: 175 | reload(sys.modules['pkg_resources']) 176 | import pkg_resources 177 | # This does not (always?) update the default working set. We will 178 | # do it. 179 | for path in sys.path: 180 | if path not in pkg_resources.working_set.entries: 181 | pkg_resources.working_set.add_entry(path) 182 | 183 | cmd = [quote(sys.executable), 184 | '-c', 185 | quote('from setuptools.command.easy_install import main; main()'), 186 | '-mqNxd', 187 | quote(eggs_dir)] 188 | 189 | if not has_broken_dash_S: 190 | cmd.insert(1, '-S') 191 | 192 | find_links = options.download_base 193 | if not find_links: 194 | find_links = os.environ.get('bootstrap-testing-find-links') 195 | if find_links: 196 | cmd.extend(['-f', quote(find_links)]) 197 | 198 | if options.use_distribute: 199 | setup_requirement = 'distribute' 200 | else: 201 | setup_requirement = 'setuptools' 202 | ws = pkg_resources.working_set 203 | setup_requirement_path = ws.find( 204 | pkg_resources.Requirement.parse(setup_requirement)).location 205 | env = dict( 206 | os.environ, 207 | PYTHONPATH=setup_requirement_path) 208 | 209 | requirement = 'zc.buildout' 210 | version = options.version 211 | if version is None and not options.accept_buildout_test_releases: 212 | # Figure out the most recent final version of zc.buildout. 213 | import setuptools.package_index 214 | _final_parts = '*final-', '*final' 215 | 216 | def _final_version(parsed_version): 217 | for part in parsed_version: 218 | if (part[:1] == '*') and (part not in _final_parts): 219 | return False 220 | return True 221 | index = setuptools.package_index.PackageIndex( 222 | search_path=[setup_requirement_path]) 223 | if find_links: 224 | index.add_find_links((find_links,)) 225 | req = pkg_resources.Requirement.parse(requirement) 226 | if index.obtain(req) is not None: 227 | best = [] 228 | bestv = None 229 | for dist in index[req.project_name]: 230 | distv = dist.parsed_version 231 | if _final_version(distv): 232 | if bestv is None or distv > bestv: 233 | best = [dist] 234 | bestv = distv 235 | elif distv == bestv: 236 | best.append(dist) 237 | if best: 238 | best.sort() 239 | version = best[-1].version 240 | if version: 241 | requirement = '=='.join((requirement, version)) 242 | cmd.append(requirement) 243 | 244 | if is_jython: 245 | import subprocess 246 | exitcode = subprocess.Popen(cmd, env=env).wait() 247 | else: # Windows prefers this, apparently; otherwise we would prefer subprocess 248 | exitcode = os.spawnle(*([os.P_WAIT, sys.executable] + cmd + [env])) 249 | if exitcode != 0: 250 | sys.stdout.flush() 251 | sys.stderr.flush() 252 | print ("An error occurred when trying to install zc.buildout. " 253 | "Look above this message for any errors that " 254 | "were output by easy_install.") 255 | sys.exit(exitcode) 256 | 257 | ws.add_entry(eggs_dir) 258 | ws.require(requirement) 259 | import zc.buildout.buildout 260 | zc.buildout.buildout.main(args) 261 | if not options.eggs: # clean up temporary egg directory 262 | shutil.rmtree(eggs_dir) 263 | -------------------------------------------------------------------------------- /appstructure/zc.buildout/buildout_env/buildout.cfg: -------------------------------------------------------------------------------- 1 | [buildout] 2 | develop = . 3 | parts = 4 | app 5 | mkdirs 6 | deploy_ini 7 | deploy_cfg 8 | debug_ini 9 | debug_cfg 10 | test 11 | newest = false 12 | 13 | # eggs will be installed in the default buildout location 14 | # (see .buildout/default.cfg in your home directory) 15 | # unless you specify an eggs-directory option here. 16 | 17 | [server] 18 | host = 127.0.0.1 19 | port = 5000 20 | logfiles = ${buildout:directory}/var/log 21 | 22 | [app] 23 | recipe = zc.recipe.egg 24 | eggs = hello 25 | Paste 26 | PasteScript 27 | PasteDeploy 28 | 29 | interpreter = python-console 30 | 31 | [mkdirs] 32 | recipe = z3c.recipe.mkdir 33 | paths = 34 | ${server:logfiles} 35 | 36 | [deploy_ini] 37 | recipe = collective.recipe.template 38 | input = etc/deploy.ini.in 39 | output = ${buildout:parts-directory}/etc/${:outfile} 40 | outfile = deploy.ini 41 | app = hello 42 | workers = 10 43 | spawn_if_under = 5 44 | max_requests = 100 45 | 46 | [debug_ini] 47 | <= deploy_ini 48 | outfile = debug.ini 49 | app = hello#debug 50 | workers = 1 51 | spawn_if_under = 1 52 | max_requests = 0 53 | 54 | [deploy_cfg] 55 | recipe = collective.recipe.template 56 | input = inline: 57 | # Deployment configuration 58 | DEBUG = False 59 | SECRET_KEY = 'production key' 60 | USERNAME = 'Fernand' 61 | output = ${buildout:parts-directory}/etc/deploy.cfg 62 | 63 | [debug_cfg] 64 | recipe = collective.recipe.template 65 | input = inline: 66 | # Debugging configuration 67 | DEBUG = True 68 | SECRET_KEY = 'development key' 69 | USERNAME = 'Raoul' 70 | output = ${buildout:parts-directory}/etc/debug.cfg 71 | 72 | [test] 73 | recipe = pbp.recipe.noserunner 74 | eggs = hello 75 | defaults = -v 76 | -------------------------------------------------------------------------------- /appstructure/zc.buildout/buildout_env/etc/deploy.ini.in: -------------------------------------------------------------------------------- 1 | # ${:outfile} 2 | # 3 | # Configuration for use with paster/WSGI 4 | # 5 | 6 | [loggers] 7 | keys = root, wsgi 8 | 9 | [handlers] 10 | keys = console, accesslog 11 | 12 | [formatters] 13 | keys = generic, accesslog 14 | 15 | [formatter_generic] 16 | format = %(asctime)s %(levelname)s [%(name)s] %(message)s 17 | 18 | [formatter_accesslog] 19 | format = %(message)s 20 | 21 | [handler_console] 22 | class = StreamHandler 23 | args = (sys.stderr,) 24 | level = NOTSET 25 | formatter = generic 26 | 27 | [handler_accesslog] 28 | class = FileHandler 29 | args = (os.path.join(r'${server:logfiles}', 'access.log'), 'a') 30 | level = INFO 31 | formatter = accesslog 32 | 33 | [logger_root] 34 | level = INFO 35 | handlers = console 36 | 37 | [logger_wsgi] 38 | level = INFO 39 | handlers = accesslog 40 | qualname = wsgi 41 | propagate = 0 42 | 43 | [filter:translogger] 44 | use = egg:Paste#translogger 45 | setup_console_handler = False 46 | logger_name = wsgi 47 | 48 | [app:main] 49 | use = egg:${:app} 50 | filter-with = translogger 51 | 52 | [server:main] 53 | use = egg:Paste#http 54 | host = ${server:host} 55 | port = ${server:port} 56 | threadpool_workers = ${:workers} 57 | threadpool_spawn_if_under = ${:spawn_if_under} 58 | threadpool_max_requests = ${:max_requests} 59 | -------------------------------------------------------------------------------- /appstructure/zc.buildout/buildout_env/setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from setuptools import setup, find_packages 3 | import os 4 | 5 | name = "hello" 6 | version = "0.1" 7 | 8 | 9 | def read(*rnames): 10 | return open(os.path.join(os.path.dirname(__file__), *rnames)).read() 11 | 12 | 13 | setup( 14 | name=name, 15 | version=version, 16 | description="a hello world demo", 17 | long_description=read('README'), 18 | # Get strings from http://www.python.org/pypi?%3Aaction=list_classifiers 19 | classifiers=[], 20 | keywords="", 21 | author="", 22 | author_email='', 23 | url='', 24 | license='', 25 | package_dir={'': 'src'}, 26 | packages=find_packages('src'), 27 | include_package_data=True, 28 | zip_safe=False, 29 | install_requires=[ 30 | 'setuptools', 31 | 'Flask', 32 | ], 33 | entry_points=""" 34 | [console_scripts] 35 | flask-ctl = hello.script:run 36 | 37 | [paste.app_factory] 38 | main = hello.script:make_app 39 | debug = hello.script:make_debug 40 | """, 41 | ) 42 | -------------------------------------------------------------------------------- /appstructure/zc.buildout/buildout_env/src/hello/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from flask import Flask, request 3 | 4 | 5 | class _DefaultSettings(object): 6 | USERNAME = 'world' 7 | SECRET_KEY = 'development key' 8 | DEBUG = True 9 | 10 | 11 | # create the application 12 | app = Flask(__name__) 13 | app.config.from_object(_DefaultSettings) 14 | del _DefaultSettings 15 | 16 | 17 | def init_db(): 18 | """Create the database tables.""" 19 | pass 20 | 21 | 22 | @app.route('/') 23 | def index(): 24 | if reqeust.args: 25 | BREAK (with_NameError) 26 | return 'Hello %s!' % app.config['USERNAME'].title() 27 | -------------------------------------------------------------------------------- /appstructure/zc.buildout/buildout_env/src/hello/script.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """Startup utilities""" 3 | import os 4 | import sys 5 | from functools import partial 6 | 7 | import paste.script.command 8 | import werkzeug.script 9 | 10 | etc = partial(os.path.join, 'parts', 'etc') 11 | 12 | DEPLOY_INI = etc('deploy.ini') 13 | DEPLOY_CFG = etc('deploy.cfg') 14 | 15 | DEBUG_INI = etc('debug.ini') 16 | DEBUG_CFG = etc('debug.cfg') 17 | 18 | _buildout_path = __file__ 19 | for i in range(2 + __name__.count('.')): 20 | _buildout_path = os.path.dirname(_buildout_path) 21 | 22 | abspath = partial(os.path.join, _buildout_path) 23 | del _buildout_path 24 | 25 | 26 | # bin/paster serve parts/etc/deploy.ini 27 | def make_app(global_conf={}, config=DEPLOY_CFG, debug=False): 28 | from hello import app 29 | app.config.from_pyfile(abspath(config)) 30 | app.debug = debug 31 | return app 32 | 33 | 34 | # bin/paster serve parts/etc/debug.ini 35 | def make_debug(global_conf={}, **conf): 36 | from werkzeug.debug import DebuggedApplication 37 | app = make_app(global_conf, config=DEBUG_CFG, debug=True) 38 | return DebuggedApplication(app, evalex=True) 39 | 40 | 41 | # bin/flask-ctl shell 42 | def make_shell(): 43 | """Interactive Flask Shell""" 44 | from flask import request 45 | from hello import init_db as initdb 46 | app = make_app() 47 | http = app.test_client() 48 | reqctx = app.test_request_context 49 | return locals() 50 | 51 | 52 | def _init_db(debug=False, dry_run=False): 53 | """Initialize the database.""" 54 | from hello import init_db 55 | print 'init_db()' 56 | if dry_run: 57 | return 58 | # Configure the application 59 | if debug: 60 | make_debug() 61 | else: 62 | make_app() 63 | # Create the tables 64 | init_db() 65 | 66 | 67 | def _serve(action, debug=False, dry_run=False): 68 | """Build paster command from 'action' and 'debug' flag.""" 69 | if action == 'initdb': 70 | # First, create the tables 71 | return _init_db(debug=debug, dry_run=dry_run) 72 | if debug: 73 | config = DEBUG_INI 74 | else: 75 | config = DEPLOY_INI 76 | argv = ['bin/paster', 'serve', config] 77 | if action in ('start', 'restart'): 78 | argv += [action, '--daemon'] 79 | elif action in ('', 'fg', 'foreground'): 80 | argv += ['--reload'] 81 | else: 82 | argv += [action] 83 | # Print the 'paster' command 84 | print ' '.join(argv) 85 | if dry_run: 86 | return 87 | # Configure logging and lock file 88 | if action in ('start', 'stop', 'restart', 'status'): 89 | argv += [ 90 | '--log-file', abspath('var', 'log', 'paster.log'), 91 | '--pid-file', abspath('var', 'log', '.paster.pid'), 92 | ] 93 | sys.argv = argv[:2] + [abspath(config)] + argv[3:] 94 | # Run the 'paster' command 95 | paste.script.command.run() 96 | 97 | 98 | # bin/flask-ctl ... 99 | def run(): 100 | action_shell = werkzeug.script.make_shell(make_shell, make_shell.__doc__) 101 | 102 | # bin/flask-ctl serve [fg|start|stop|restart|status|initdb] 103 | def action_serve(action=('a', 'start'), dry_run=False): 104 | """Serve the application. 105 | 106 | This command serves a web application that uses a paste.deploy 107 | configuration file for the server and application. 108 | 109 | Options: 110 | - 'action' is one of [fg|start|stop|restart|status|initdb] 111 | - '--dry-run' print the paster command and exit 112 | """ 113 | _serve(action, debug=False, dry_run=dry_run) 114 | 115 | # bin/flask-ctl debug [fg|start|stop|restart|status|initdb] 116 | def action_debug(action=('a', 'start'), dry_run=False): 117 | """Serve the debugging application.""" 118 | _serve(action, debug=True, dry_run=dry_run) 119 | 120 | # bin/flask-ctl status 121 | def action_status(dry_run=False): 122 | """Status of the application.""" 123 | _serve('status', dry_run=dry_run) 124 | 125 | # bin/flask-ctl stop 126 | def action_stop(dry_run=False): 127 | """Stop the application.""" 128 | _serve('stop', dry_run=dry_run) 129 | 130 | werkzeug.script.run() 131 | -------------------------------------------------------------------------------- /appstructure/zc.buildout/buildout_env/src/hello/tests.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | import hello 4 | 5 | 6 | class HelloTestCase(unittest.TestCase): 7 | 8 | def setUp(self): 9 | """Before each test, set up a blank database""" 10 | self.app = hello.app.test_client() 11 | hello.init_db() 12 | 13 | def tearDown(self): 14 | """Get rid of the database again after each test.""" 15 | pass 16 | 17 | def test_hello(self): 18 | """Test rendered page.""" 19 | hello.app.config['USERNAME'] = 'jean' 20 | rv = self.app.get('/') 21 | assert 'Hello Jean!' in rv.data 22 | 23 | 24 | def suite(): 25 | suite = unittest.TestSuite() 26 | suite.addTest(unittest.makeSuite(HelloTestCase)) 27 | return suite 28 | 29 | 30 | if __name__ == "__main__": 31 | unittest.main() 32 | -------------------------------------------------------------------------------- /authentication/http_basic.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | authentication.basic 4 | ~~~~~~~~~~~~~~~~~~~~ 5 | 6 | HTTP Basic Auth 7 | http://flask.pocoo.org/snippets/8/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | from functools import wraps 14 | 15 | from flask import request, Response 16 | 17 | from app import app 18 | 19 | 20 | def check_auth(username, password): 21 | """This function is called to check if a username / 22 | password combination is valid. 23 | """ 24 | return username == 'admin' and password == 'secret' 25 | 26 | 27 | def authenticate(): 28 | """Sends a 401 response that enables basic auth""" 29 | return Response( 30 | 'Could not verify your access level for that URL.\n' 31 | 'You have to login with proper credentials', 401, 32 | {'WWW-Authenticate': 'Basic realm="Login Required"'}) 33 | 34 | 35 | def requires_auth(f): 36 | @wraps(f) 37 | def decorated(*args, **kwargs): 38 | auth = request.authorization 39 | if not auth or not check_auth(auth.username, auth.password): 40 | return authenticate() 41 | return f(*args, **kwargs) 42 | return decorated 43 | 44 | 45 | @app.route('/') 46 | @requires_auth 47 | def index(): 48 | return 'index' 49 | 50 | 51 | if __name__ == "__main__": 52 | app.run() 53 | -------------------------------------------------------------------------------- /authentication/http_digest.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | authentication.digest 4 | ~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | HTTP Digest Auth 7 | http://flask.pocoo.org/snippets/31/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | from functools import wraps 14 | 15 | from werkzeug.contrib import authdigest 16 | import flask 17 | from flask import request, session 18 | 19 | from app import app 20 | 21 | 22 | from functools import wraps 23 | from werkzeug.contrib import authdigest 24 | import flask 25 | 26 | class FlaskRealmDigestDB(authdigest.RealmDigestDB): 27 | def requires_auth(self, f): 28 | @wraps(f) 29 | def decorated(*args, **kwargs): 30 | request = flask.request 31 | if not self.isAuthenticated(request): 32 | return self.challenge() 33 | 34 | return f(*args, **kwargs) 35 | 36 | return decorated 37 | 38 | 39 | authDB = FlaskRealmDigestDB('MyAuthRealm') 40 | authDB.add_user('admin', 'test') 41 | 42 | 43 | @app.route('/') 44 | @authDB.requires_auth 45 | def auth(): 46 | session['user'] = request.authorization.username 47 | return "

Content for authenticated user

" 48 | 49 | 50 | @app.route('/auth') 51 | def authApi(): 52 | if not authDB.isAuthenticated(request): 53 | return authDB.challenge() 54 | 55 | session['user'] = request.authorization.username 56 | return "

Content for authenticated user

" 57 | 58 | 59 | if __name__ == "__main__": 60 | app.run() 61 | -------------------------------------------------------------------------------- /authentication/openid.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | authentication.openid 4 | ~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Simple OpenID with Flask 7 | http://flask.pocoo.org/snippets/7/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from flask import request, Response 15 | 16 | from app import app 17 | 18 | 19 | """ 20 | There is a Flask Addon Library called Flask-OpenID that implements basic OpenID authentication for Flask on top of python-openid. 21 | 22 | The included example shows how this can be done. Basically all you need to do is this: 23 | 24 | create an instance of OpenID with the path to the stored files. This can be any folder on the filesystem, OpenID will use it to store temporary information required for the authentication process. 25 | Define a loginhandler function. That function has to render the form and call into try_login with the submitted identity URL (the OpenID the user entered). 26 | Define a after_login function. This function is called with the identity URL if authentication worked. This function must redirect to a different page. It usually checks if the user is known to the system and if this is the case, logs the user in or otherwise redirects to a page used to create that profile. 27 | If that is too abstract, look at the example for more information about how to use it. 28 | 29 | Note that Flask-OpenID also has basic support for redirections, so the user will after login end up on the page where he or she previously was. For the redirections to work, it is necessary to have the forms forward the next parameter properly. Make sure to have a look at the template code as well. 30 | 31 | Also check out the website for more information and a detailed documentation: Flask-OpenID 32 | """ 33 | 34 | 35 | @app.route('/') 36 | def index(): 37 | return 'index' 38 | 39 | 40 | if __name__ == "__main__": 41 | app.run() 42 | -------------------------------------------------------------------------------- /authentication/steamid.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | authentication.steamid 4 | ~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Sign in with Steam ID 7 | http://flask.pocoo.org/snippets/42/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | import re 14 | import urllib2 15 | 16 | from flask import Flask, redirect, session, json, g 17 | from flaskext.sqlalchemy import SQLAlchemy 18 | from flaskext.openid import OpenID 19 | 20 | from app import app 21 | 22 | 23 | app.config['STEAM_API_KEY'] = 'ABCDEFG-12345' 24 | db = SQLAlchemy(app) 25 | oid = OpenID(app) 26 | 27 | 28 | class User(db.Model): 29 | id = db.Column(db.Integer, primary_key=True) 30 | steam_id = db.Column(db.String(40)) 31 | nickname = db.String(80) 32 | 33 | @staticmethod 34 | def get_or_create(steam_id): 35 | rv = User.query.filter_by(steam_id=steam_id).first() 36 | if rv is None: 37 | rv = User() 38 | rv.steam_id = steam_id 39 | db.session.add(rv) 40 | return rv 41 | 42 | 43 | def get_steam_userinfo(steam_id): 44 | options = { 45 | 'key': app.config['STEAM_API_KEY'], 46 | 'steamids': steam_id 47 | } 48 | url = 'http://api.steampowered.com/ISteamUser/' \ 49 | 'GetPlayerSummaries/v0001/?%s' % url_encode(options) 50 | rv = json.load(urllib2.urlopen(url)) 51 | return rv['response']['players']['player'][0] or {} 52 | 53 | 54 | _steam_id_re = re.compile('steamcommunity.com/openid/id/(.*?)$') 55 | 56 | 57 | @app.route('/login') 58 | @oid.loginhandler 59 | def login(): 60 | if g.user is not None: 61 | return redirect(oid.get_next_url()) 62 | return oid.try_login('http://steamcommunity.com/openid') 63 | 64 | 65 | @oid.after_login 66 | def create_or_login(resp): 67 | match = _steam_id_re.search(resp.identity_url) 68 | g.user = User.get_or_create(match.group(1)) 69 | steamdata = get_steam_userinfo(g.user.steam_id) 70 | g.user.nickname = steamdata['personaname'] 71 | db.session.commit() 72 | session['user_id'] = g.user.id 73 | flash('You are logged in as %s' % g.user.nickname) 74 | return redirect(oid.get_next_url()) 75 | 76 | 77 | @app.before_request 78 | def before_request(): 79 | g.user = None 80 | if 'user_id' in session: 81 | g.user = User.query.get(session['user_id']) 82 | 83 | 84 | @app.route('/logout') 85 | def logout(): 86 | session.pop('user_id', None) 87 | return redirect(oid.get_next_url()) 88 | 89 | 90 | if __name__ == "__main__": 91 | app.run() 92 | -------------------------------------------------------------------------------- /database/get_or_404.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | database.get_or_404 4 | ~~~~~~~~~~~~~~~~~~~ 5 | 6 | get_object_or_404 7 | http://flask.pocoo.org/snippets/115/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from sqlalchemy.orm import exc 15 | from werkzeug.exceptions import abort 16 | 17 | 18 | def get_object_or_404(model, *criterion): 19 | try: 20 | rv = model.query.filter(*criterion).one() 21 | except exc.NoResultFound, exc.MultipleResultsFound: 22 | abort(404) 23 | else: 24 | return rv 25 | 26 | 27 | board = get_object_or_404(Board, Board.slug == slug) 28 | user = get_object_or_404(User, User.id == id) 29 | -------------------------------------------------------------------------------- /database/get_or_abort.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | database.get_or_abort 4 | ~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Getting an object from a SQLAlchemy model or abort 7 | http://flask.pocoo.org/snippets/39/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | 15 | def get_or_abort(model, object_id, code=404): 16 | """ 17 | get an object with his given id or an abort error (404 is the default) 18 | """ 19 | result = model.query.get(object_id) 20 | return result or abort(code) 21 | 22 | 23 | def theme_detail(theme_id): 24 | # shows a theme 25 | theme = get_or_abort(Theme, theme_id) 26 | return render_template('theme_detail.html', theme=theme) 27 | -------------------------------------------------------------------------------- /database/lazy_sqlalchemy.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | database.lazy_sqlalchemy 4 | ~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Lazy SQLAlchemy setup 7 | http://flask.pocoo.org/snippets/22/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from sqlalchemy import create_engine 15 | from sqlalchemy.orm import scoped_session, create_session 16 | 17 | 18 | engine = None 19 | 20 | 21 | db_session = scoped_session(lambda: create_session(bind=engine)) 22 | 23 | 24 | def init_engine(uri, **kwargs): 25 | global engine 26 | engine = create_engine(uri, **kwargs) 27 | return engine 28 | 29 | 30 | def create_app(config): 31 | 32 | app = Flask(__name__) 33 | app.config.from_pyfile(config) 34 | 35 | init_engine(app.config['DATABASE_URI']) 36 | 37 | return app 38 | -------------------------------------------------------------------------------- /database/mongokit_multithreaded_authentication.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | database.mongokit_multithreaded_authentication 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | MongoKit multithreaded authentication 7 | http://flask.pocoo.org/snippets/66/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | 15 | class ThreadLocalConnectionProxy(object): 16 | """ 17 | A proxy object for a MongoKit connection object. As pymongo authentication 18 | is thread local, we need a seperate connection for each thread, which this 19 | proxy provides in a transparent manner. 20 | """ 21 | def __init__(self, logger): 22 | self.logger = logger 23 | 24 | def connect(self): 25 | """ 26 | Sets the thread local `mongodb_connection` attribute to a new connection 27 | aquired with :func:`get_connection`. 28 | """ 29 | self.thread_local.mongodb_connection = get_connection(self.logger) 30 | 31 | @property 32 | def connected(self): 33 | """ 34 | Returns true if there is a connection object in the thread local 35 | storage. 36 | """ 37 | return hasattr(self.thread_local, "mongodb_connection") 38 | 39 | @property 40 | def thread_local(self): 41 | """ 42 | Thread local storage if possible, else object global. 43 | """ 44 | return flask._request_ctx_stack.top or self 45 | 46 | def __getattr__(self, name): 47 | if name == "logger": 48 | return super(ThreadLocalConnectionProxy, self).logger 49 | if not self.connected: 50 | self.connect() 51 | return getattr(self.thread_local.mongodb_connection, name) 52 | -------------------------------------------------------------------------------- /database/simple_insertion.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | database.simple_insertion 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Simple insertion and row id 7 | http://flask.pocoo.org/snippets/37/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | 15 | def insert(table, fields=(), values=()): 16 | # g.db is the database connection 17 | cur = g.db.cursor() 18 | query = 'INSERT INTO %s (%s) VALUES (%s)' % ( 19 | table, 20 | ', '.join(fields), 21 | ', '.join(['?'] * len(values)) 22 | ) 23 | cur.execute(query, values) 24 | g.db.commit() 25 | id = cur.lastrowid 26 | cur.close() 27 | return id 28 | -------------------------------------------------------------------------------- /database/simple_persistence.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | database.simple_persistence 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Simple persistence 7 | http://flask.pocoo.org/snippets/25/ 8 | """ 9 | 10 | from __future__ import with_statement 11 | import os 12 | import sys 13 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 14 | import shelve 15 | from os import path 16 | from cPickle import HIGHEST_PROTOCOL 17 | from contextlib import closing 18 | 19 | from app import app 20 | 21 | 22 | SHELVE_DB = 'shelve.db' 23 | app.config['SHELVE_DB'] = SHELVE_DB 24 | 25 | 26 | db = shelve.open(path.join(app.root_path, app.config['SHELVE_DB']), 27 | protocol=HIGHEST_PROTOCOL, writeback=True) 28 | 29 | 30 | @app.route('/') 31 | def write_and_list(message): 32 | db.setdefault('messages', []) 33 | db['messages'].append(message) 34 | return app.response_class('\n'.join(db['messages']), mimetype='text/plain') 35 | 36 | 37 | if __name__ == '__main__': 38 | with closing(db): 39 | app.run() 40 | -------------------------------------------------------------------------------- /database/sqlalchemy_test_issues.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | database.sqlalchemy_test_issues 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Testing Issues with SQLAlchemy 7 | http://flask.pocoo.org/snippets/36/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from flask import request, Response 15 | 16 | from app import app 17 | 18 | 19 | """ 20 | You would like to perform some tests to ensure that you can insert and query for objects. 21 | 22 | Insertions work, but when you try to perform a query in your tests you get a problem like this: 23 | 24 | Failed example: 25 | len(MyObject.query.all()) 26 | Exception raised: 27 | Traceback (most recent call last): 28 | File ".../lib/python2.6/doctest.py", line 1248, in __run 29 | compileflags, 1) in test.globs 30 | File "", line 1, in 31 | len(MyObject.query.all()) 32 | AttributeError: 'NoneType' object has no attribute 'all' 33 | What you need to do is ensure that you have initialized a request context for your tests. This can be done by: 34 | 35 | app.test_request_context().push() 36 | Now when you run your tests and query them they should work. 37 | """ 38 | 39 | 40 | @app.route('/') 41 | def index(): 42 | return 'index' 43 | 44 | 45 | if __name__ == "__main__": 46 | app.run() 47 | -------------------------------------------------------------------------------- /database/support_objectid.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | database.support_objectid 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Support PyMongo ObjectIDs in URLs 7 | http://flask.pocoo.org/snippets/106/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from werkzeug.routing import BaseConverter, ValidationError 15 | from itsdangerous import base64_encode, base64_decode 16 | from bson.objectid import ObjectId 17 | from bson.errors import InvalidId 18 | 19 | from app import app 20 | 21 | 22 | class ObjectIDConverter(BaseConverter): 23 | def to_python(self, value): 24 | try: 25 | return ObjectId(base64_decode(value)) 26 | except (InvalidId, ValueError, TypeError): 27 | raise ValidationError() 28 | def to_url(self, value): 29 | return base64_encode(value.binary) 30 | 31 | 32 | app.url_map.converters['objectid'] = ObjectIDConverter 33 | 34 | 35 | @app.route('/users/') 36 | def show_user(user_id): 37 | return 'User ID: %r' % user_id 38 | -------------------------------------------------------------------------------- /database/use_tornado_database.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | database.use_tornado_database 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Using tornado.database with MySQL 7 | http://flask.pocoo.org/snippets/11/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from tornado.database import Connection 15 | from flask import g, render_template 16 | 17 | from app import app 18 | import config 19 | 20 | 21 | @app.before_request 22 | def connect_db(): 23 | g.db = Connection(config.DB_HOST, 24 | config.DB_NAME, 25 | config.DB_USER, 26 | config.DB_PASSWD) 27 | 28 | 29 | @app.after_request 30 | def close_connection(response): 31 | g.db.close() 32 | return response 33 | 34 | 35 | @app.route("/") 36 | def index(): 37 | newsitems = g.db.iter("select * from newsitems") 38 | return render_template("index.html", newsitems=newsitems) 39 | 40 | 41 | """ 42 | {% for item in newsitems %} 43 |

{{ item.title }}

44 | {% endfor %} 45 | You can get much of the same functionality in SQLAlchemy 0.6 using NamedTuples, without using the ORM: 46 | 47 | from sqlalchemy import create_engine 48 | 49 | @app.before_request 50 | def connect_db(): 51 | g.db = create_engine(config.DB_URI) 52 | 53 | @app.route("/") 54 | def index(): 55 | newsitems = g.db.execute("select * from newsitems") 56 | # now you can do newsitem.title... 57 | """ 58 | -------------------------------------------------------------------------------- /decorators/authorization.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | decorators.authorization 4 | ~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Simple Authorization 7 | http://flask.pocoo.org/snippets/98/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | from functools import wraps 14 | 15 | from app import app 16 | 17 | 18 | def requires_roles(*roles): 19 | def wrapper(f): 20 | @wraps(f) 21 | def wrapped(*args, **kwargs): 22 | if get_current_user_role() not in roles: 23 | return error_response() 24 | return f(*args, **kwargs) 25 | return wrapped 26 | return wrapper 27 | 28 | 29 | def get_current_user_role(): 30 | return 'admin' 31 | 32 | 33 | def error_response(): 34 | return "You've got no permission to access this page.", 403 35 | 36 | 37 | @app.route('/') 38 | @requires_roles('admin', 'user') 39 | def user_page(): 40 | return "You've got permission to access this page." 41 | 42 | 43 | if __name__ == "__main__": 44 | app.run() 45 | -------------------------------------------------------------------------------- /decorators/before_request_handler_for_coffeescript.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | decorators.before_request_for_coffeescript 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | app.before_request handlers for less and coffeescript 7 | http://flask.pocoo.org/snippets/94/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | from functools import wraps 14 | 15 | from app import app 16 | 17 | 18 | def _simple_processor(processor, ext_private, ext_public): 19 | if not request.path.endswith(ext_public): 20 | return 21 | public_file = request.path[len(config.app.static_url_path) + 1:] 22 | public_file_path = os.path.join(config.app.static_folder, public_file) 23 | private_file_path = public_file_path[:-len(ext_public)] + ext_private 24 | # File does not exist in app static - check blueprints. 25 | if not os.path.isfile(private_file_path): 26 | for blueprint_name, blueprint in config.app.blueprints.iteritems(): 27 | if request.path.startswith(blueprint.static_url_path): 28 | public_file = request.path[len(blueprint.static_url_path) + 1:] 29 | public_file_path = os.path.join(blueprint.static_folder, public_file) 30 | private_file_path = public_file_path[:-len(ext_public)] + ext_private 31 | break 32 | # If file doesn't exist in the blueprints as well, let flask handle it. 33 | if not os.path.isfile(private_file_path): 34 | return 35 | if not os.path.isfile(public_file_path) or (os.path.getmtime(private_file_path) >= 36 | os.path.getmtime(public_file_path)): 37 | processor(private_file_path, public_file_path) 38 | 39 | @app.before_request 40 | def less_to_css(): 41 | processor = lambda in_file, out_file: subprocess.check_output(['lessc', 42 | in_file, out_file], shell=False) 43 | return _simple_processor(processor, '.less', '.css') 44 | 45 | @app.before_request 46 | def coffee_to_js(): 47 | processor = lambda in_file, out_file: subprocess.check_output(['coffee', 48 | '-c', in_file], shell=False) 49 | return _simple_processor(processor, '.coffee', '.js') 50 | -------------------------------------------------------------------------------- /decorators/conditional_requests_with_etags.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | decorators.etags 4 | ~~~~~~~~~~~~~~~~ 5 | 6 | Conditional Requests with ETags 7 | http://flask.pocoo.org/snippets/95/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | import functools 14 | import hashlib 15 | 16 | import flask 17 | import werkzeug 18 | 19 | from app import app 20 | 21 | 22 | def conditional(func): 23 | '''Start conditional method execution for this resource''' 24 | @functools.wraps(func) 25 | def wrapper(*args, **kwargs): 26 | flask.g.condtnl_etags_start = True 27 | return func(*args, **kwargs) 28 | return wrapper 29 | 30 | 31 | _old_set_etag = werkzeug.ETagResponseMixin.set_etag 32 | @functools.wraps(werkzeug.ETagResponseMixin.set_etag) 33 | def _new_set_etag(self, etag, weak=False): 34 | # only check the first time through; when called twice 35 | # we're modifying 36 | if (hasattr(flask.g, 'condtnl_etags_start') and 37 | flask.g.condtnl_etags_start): 38 | if flask.request.method in ('PUT', 'DELETE', 'PATCH'): 39 | if not flask.request.if_match: 40 | raise PreconditionRequired 41 | if etag not in flask.request.if_match: 42 | flask.abort(412) 43 | elif (flask.request.method == 'GET' and 44 | flask.request.if_none_match and 45 | etag in flask.request.if_none_match): 46 | raise NotModified 47 | flask.g.condtnl_etags_start = False 48 | _old_set_etag(self, etag, weak) 49 | werkzeug.ETagResponseMixin.set_etag = _new_set_etag 50 | 51 | 52 | d = {'a': 'This is "a".\n', 'b': 'This is "b".\n'} 53 | 54 | 55 | @app.route('/', methods=['GET', 'PUT', 'DELETE', 'PATCH']) 56 | @conditional 57 | def view(path): 58 | try: 59 | # SHA1 should generate well-behaved etags 60 | etag = hashlib.sha1(d[path]).hexdigest() 61 | if flask.request.method == 'GET': 62 | response = flask.make_response(d[path]) 63 | response.set_etag(etag) 64 | else: 65 | response = flask.Response(status=204) 66 | del response.headers['content-type'] 67 | response.set_etag(etag) 68 | if flask.request.method == 'DELETE': 69 | del d[path] 70 | del response.headers['etag'] 71 | else: 72 | if flask.request.method == 'PUT': 73 | d[path] = flask.request.data 74 | else: # (PATCH) 75 | # Lame PATCH technique 76 | d[path] += flask.request.data 77 | response.set_etag(hashlib.sha1(d[path]).hexdigest()) 78 | return response 79 | except KeyError: 80 | flask.abort(404) 81 | 82 | 83 | class NotModified(werkzeug.exceptions.HTTPException): 84 | code = 304 85 | def get_response(self, environment): 86 | return flask.Response(status=304) 87 | 88 | 89 | class PreconditionRequired(werkzeug.exceptions.HTTPException): 90 | code = 428 91 | description = ('

This request is required to be ' 92 | 'conditional; try using "If-Match".') 93 | name = 'Precondition Required' 94 | def get_response(self, environment): 95 | resp = super(PreconditionRequired, 96 | self).get_response(environment) 97 | resp.status = str(self.code) + ' ' + self.name.upper() 98 | return resp 99 | 100 | 101 | if __name__ == "__main__": 102 | app.run() 103 | # Testing with curl 104 | # $ curl -i localhost:5000/a 105 | 106 | # $ curl -iH 'If-None-Match: \ 107 | # "56eaadbbd9fa287e7270cf13a41083c94f52ab9b"' localhost:5000/a 108 | 109 | # $ curl -iX DELETE localhost:5000/a 110 | 111 | # $ curl -iX DELETE -H 'If-Match: "badmatch"' localhost:5000/a 112 | 113 | # $ curl -iX DELETE -H 'If-Match: \ 114 | # "56eaadbbd9fa287e7270cf13a41083c94f52ab9b"' localhost:5000/a 115 | 116 | # $ curl -i localhost:5000/a 117 | -------------------------------------------------------------------------------- /decorators/http_access_control.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | decorators.access_control 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Decorator for the HTTP Access Control 7 | http://flask.pocoo.org/snippets/56/ 8 | """ 9 | 10 | from datetime import timedelta 11 | import os 12 | import sys 13 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 14 | from functools import update_wrapper 15 | 16 | from flask import make_response, request, current_app, jsonify 17 | 18 | from app import app 19 | 20 | 21 | def crossdomain(origin=None, methods=None, headers=None, max_age=21600, 22 | attach_to_all=True, automatic_options=True): 23 | if methods is not None: 24 | methods = ', '.join(sorted(x.upper() for x in methods)) 25 | if headers is not None and not isinstance(headers, basestring): 26 | headers = ', '.join(x.upper() for x in headers) 27 | if not isinstance(origin, basestring): 28 | origin = ', '.join(origin) 29 | if isinstance(max_age, timedelta): 30 | max_age = max_age.total_seconds() 31 | 32 | def get_methods(): 33 | if methods is not None: 34 | return methods 35 | 36 | options_resp = current_app.make_default_options_response() 37 | return options_resp.headers['allow'] 38 | 39 | def decorator(f): 40 | def wrapped_function(*args, **kwargs): 41 | if automatic_options and request.method == 'OPTIONS': 42 | resp = current_app.make_default_options_response() 43 | else: 44 | resp = make_response(f(*args, **kwargs)) 45 | if not attach_to_all and request.method != 'OPTIONS': 46 | return resp 47 | 48 | h = resp.headers 49 | 50 | h['Access-Control-Allow-Origin'] = origin 51 | h['Access-Control-Allow-Methods'] = get_methods() 52 | h['Access-Control-Max-Age'] = str(max_age) 53 | if headers is not None: 54 | h['Access-Control-Allow-Headers'] = headers 55 | return resp 56 | 57 | f.provide_automatic_options = False 58 | return update_wrapper(wrapped_function, f) 59 | return decorator 60 | 61 | 62 | @app.route('/my_service') 63 | @crossdomain(origin='*') 64 | def my_service(): 65 | return jsonify(foo='cross domain ftw') 66 | 67 | 68 | if __name__ == "__main__": 69 | app.run() 70 | -------------------------------------------------------------------------------- /decorators/http_headers.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | decorators.headers 4 | ~~~~~~~~~~~~~~~~~~ 5 | 6 | Generic HTTP headers decorator 7 | http://flask.pocoo.org/snippets/100/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | from functools import wraps 14 | 15 | from flask import make_response 16 | 17 | from app import app 18 | 19 | 20 | def add_response_headers(headers={}): 21 | """This decorator adds the headers passed in to the response""" 22 | def decorator(f): 23 | @wraps(f) 24 | def decorated_function(*args, **kwargs): 25 | resp = make_response(f(*args, **kwargs)) 26 | h = resp.headers 27 | for header, value in headers.items(): 28 | h[header] = value 29 | return resp 30 | return decorated_function 31 | return decorator 32 | 33 | 34 | def noindex(f): 35 | """This decorator passes X-Robots-Tag: noindex""" 36 | return add_response_headers({'X-Robots-Tag': 'noindex'})(f) 37 | 38 | 39 | @app.route('/') 40 | @noindex 41 | def no_indexed(): 42 | """ 43 | This page will be served with X-Robots-Tag: noindex 44 | in the response headers 45 | """ 46 | return "Check my headers!" 47 | 48 | 49 | if __name__ == "__main__": 50 | app.run() 51 | # check the headers with: curl -I http://0.0.0.0:5000/ 52 | -------------------------------------------------------------------------------- /decorators/jsonp.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | decorators.jsonp 4 | ~~~~~~~~~~~~~~~~ 5 | 6 | JSONP decorator 7 | http://flask.pocoo.org/snippets/79/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | from functools import wraps 14 | 15 | from flask import request, current_app 16 | from flask import jsonify 17 | 18 | from app import app 19 | 20 | 21 | def jsonp(func): 22 | """Wraps JSONified output for JSONP requests.""" 23 | @wraps(func) 24 | def decorated_function(*args, **kwargs): 25 | callback = request.args.get('callback', False) 26 | if callback: 27 | data = str(func(*args, **kwargs).data) 28 | content = str(callback) + '(' + data + ')' 29 | mimetype = 'application/javascript' 30 | return current_app.response_class(content, mimetype=mimetype) 31 | else: 32 | return func(*args, **kwargs) 33 | return decorated_function 34 | 35 | 36 | @app.route('/') 37 | @jsonp 38 | def jsonped(): 39 | return jsonify({"foo": "bar"}) 40 | 41 | 42 | if __name__ == "__main__": 43 | app.run() 44 | -------------------------------------------------------------------------------- /decorators/rate_limit_with_redis.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | decorators.redis_ratelimit 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Rate Limiting Decorator with Redis 7 | http://flask.pocoo.org/snippets/70/ 8 | """ 9 | 10 | import os 11 | import sys 12 | import time 13 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 14 | from functools import update_wrapper 15 | 16 | from flask import request, g 17 | from redis import Redis 18 | import redis 19 | 20 | from app import app 21 | 22 | 23 | # Connecting to Redis 24 | redis = Redis() 25 | 26 | 27 | class RateLimit(object): 28 | expiration_window = 10 29 | 30 | def __init__(self, key_prefix, limit, per, send_x_headers): 31 | self.reset = (int(time.time()) // per) * per + per 32 | self.key = key_prefix + str(self.reset) 33 | self.limit = limit 34 | self.per = per 35 | self.send_x_headers = send_x_headers 36 | p = redis.pipeline() 37 | p.incr(self.key) 38 | p.expireat(self.key, self.reset + self.expiration_window) 39 | self.current = min(p.execute()[0], limit) 40 | 41 | remaining = property(lambda x: x.limit - x.current) 42 | over_limit = property(lambda x: x.current >= x.limit) 43 | 44 | 45 | def get_view_rate_limit(): 46 | return getattr(g, '_view_rate_limit', None) 47 | 48 | 49 | def on_over_limit(limit): 50 | return 'You hit the rate limit', 400 51 | 52 | 53 | def ratelimit(limit, per=300, send_x_headers=True, over_limit=on_over_limit, 54 | scope_func=lambda: request.remote_addr, 55 | key_func=lambda: request.endpoint): 56 | def decorator(f): 57 | def rate_limited(*args, **kwargs): 58 | key = 'rate-limit/%s/%s/' % (key_func(), scope_func()) 59 | rlimit = RateLimit(key, limit, per, send_x_headers) 60 | g._view_rate_limit = rlimit 61 | if over_limit is not None and rlimit.over_limit: 62 | return over_limit(rlimit) 63 | return f(*args, **kwargs) 64 | return update_wrapper(rate_limited, f) 65 | return decorator 66 | 67 | 68 | @app.after_request 69 | def inject_x_rate_header(response): 70 | limit = get_view_rate_limit() 71 | if limit and limit.send_x_headers: 72 | h = response.headers 73 | h.add('X-RateLimit-Remaining', str(limit.remaining)) 74 | h.add('X-RateLimit-Limit', str(limit.limit)) 75 | h.add('X-RateLimit-Reset', str(limit.reset)) 76 | return response 77 | 78 | 79 | @app.route('/rate-limited') 80 | @ratelimit(limit=300, per=50 * 15) 81 | def index(): 82 | return '

This is a rate limited response

' 83 | 84 | 85 | def main(): 86 | app.debug = False 87 | app.run() 88 | 89 | 90 | if __name__ == "__main__": 91 | from threading import Thread 92 | server = Thread(target=main) 93 | server.setDaemon(True) 94 | server.start() 95 | client = app.test_client() 96 | times = 0 97 | while True: 98 | times += 1 99 | rv = client.get('/rate-limited') 100 | if rv.status_code == 200: 101 | continue 102 | elif rv.status_code == 400: 103 | print 'The %s times visiting...' % times 104 | print 'Response body: ' + rv.data 105 | break 106 | -------------------------------------------------------------------------------- /decorators/ssl_view.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | decorators.sslview 4 | ~~~~~~~~~~~~~~~~~~ 5 | 6 | SSL for particular views 7 | http://flask.pocoo.org/snippets/93/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | from functools import wraps 14 | 15 | from flask import request, current_app, redirect 16 | 17 | from app import app 18 | 19 | 20 | def ssl_required(fn): 21 | @wraps(fn) 22 | def decorated_view(*args, **kwargs): 23 | if current_app.config.get("SSL"): 24 | if request.is_secure: 25 | return fn(*args, **kwargs) 26 | else: 27 | return redirect(request.url.replace("http://", "https://")) 28 | 29 | return fn(*args, **kwargs) 30 | 31 | return decorated_view 32 | 33 | 34 | @app.route('/') 35 | @ssl_required 36 | def index(): 37 | return "ssl_required" 38 | 39 | 40 | if __name__ == "__main__": 41 | app.config["SSL"] = True 42 | app.run() 43 | -------------------------------------------------------------------------------- /decorators/view_render.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | decorators.view_render 4 | ~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | View Rendering Decorator 7 | http://flask.pocoo.org/snippets/18/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | from functools import wraps 14 | 15 | from werkzeug import BaseResponse 16 | 17 | from app import app 18 | 19 | 20 | def render_html(template, **defaults): 21 | def wrapped(result): 22 | variables = defaults.copy() 23 | variables.update(result) 24 | return render_template(template, **variables) 25 | return wrapped 26 | 27 | 28 | def view(self, url, renderer=None, *args, **kwargs): 29 | super_route = self.route 30 | 31 | defaults = kwargs.pop('defaults', {}) 32 | route_id = object() 33 | defaults['_route_id'] = route_id 34 | 35 | def deco(f): 36 | @super_route(url, defaults=defaults, *args, **kwargs) 37 | @wraps(f) 38 | def decorated_function(*args, **kwargs): 39 | this_route = kwargs.get('_route_id') 40 | if not getattr(f, 'is_route', False): 41 | del kwargs['_route_id'] 42 | 43 | result = f(*args, **kwargs) 44 | 45 | if this_route is not route_id: 46 | return result 47 | 48 | # catch redirects. 49 | if isinstance(result, (app.response_class, 50 | BaseResponse)): 51 | return result 52 | 53 | if renderer is None: 54 | return result 55 | return renderer(result) 56 | 57 | decorated_function.is_route = True 58 | return decorated_function 59 | 60 | return deco 61 | 62 | 63 | @view(app, '/', render_html('page.html')) 64 | def show_page(name): 65 | page = load_page(name) 66 | return dict(title=page.title, contents=page.contents) 67 | 68 | 69 | if __name__ == "__main__": 70 | app.run() 71 | -------------------------------------------------------------------------------- /deployment/apache_host.wsgi: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import sys, os 3 | sys.path.insert(0, '/var/www/myapp') 4 | os.chdir("/var/www/myapp") 5 | from srv import app as application 6 | -------------------------------------------------------------------------------- /deployment/cherokee_fix.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | deployment.cherokee_fix 4 | ~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Cherokee fix for URL prefix 7 | http://flask.pocoo.org/snippets/84/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from flask import request, Response 15 | 16 | from app import app 17 | 18 | 19 | class CherrokeeFix(object): 20 | 21 | def __init__(self, app, script_name): 22 | self.app = app 23 | self.script_name = script_name 24 | 25 | def __call__(self, environ, start_response): 26 | path = environ.get('SCRIPT_NAME', '') + environ.get('PATH_INFO', '') 27 | environ['SCRIPT_NAME'] = self.script_name 28 | environ['PATH_INFO'] = path[len(self.script_name):] 29 | assert path[:len(self.script_name)] == self.script_name 30 | return self.app(environ, start_response) 31 | 32 | 33 | @app.route('/') 34 | def index(): 35 | return 'index' 36 | 37 | 38 | if __name__ == "__main__": 39 | app.wsgi_app = CherrokeeFix(app.wsgi_app, '/test') 40 | app.run() 41 | -------------------------------------------------------------------------------- /deployment/dotcloud.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | deployment.dotcloud 4 | ~~~~~~~~~~~~~~~~~~~ 5 | 6 | Deploying a Flask app on Dotcloud 7 | http://flask.pocoo.org/snippets/48/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from flask import request, Response 15 | 16 | from app import app 17 | 18 | 19 | """ 20 | How to deploy a Flask app on Dotcloud 21 | Create the namespace you want: 22 | 23 | dotcloud create 24 | A DotCloud application is described by a build file, which is a simple YAML file named "dotcloud.yml" located in your local source directory. To add a new python service to your app, just add the following lines to /dotcloud.yml: 25 | 26 | www: 27 | type: python 28 | Now create a /wsgi.py file containing: 29 | 30 | import sys 31 | sys.path.append('/home/dotcloud/current') 32 | from import app as application 33 | /home/dotcloud/current is the default path to your app on the server. 34 | 35 | Eventually, create nginx.conf and uwsgi.conf in the source folder. See Dotcloud documentation for further information. 36 | 37 | Create your requirements.txt file: 38 | 39 | pip freeze > ./requirements.txt 40 | Now, make sure that your source folder contains at least: 41 | 42 | ./ 43 | ../ 44 | ./ 45 | ./static 46 | ./__init__.py 47 | ./ ... 48 | ./requirements.txt 49 | ./wsgi.py 50 | ./dotcloud.yml 51 | ./ ... 52 | Create a symbolic link to your static folder: 53 | 54 | cd 55 | ln -s /static static 56 | You can now push the code to Dotcloud: 57 | 58 | dotcloud push 59 | A random URL has been generated for your python service in your application (something like http://my4ppr0x.dotcloud.com/). Point your browser to this URL to see your new app running. 60 | """ 61 | 62 | 63 | @app.route('/') 64 | def index(): 65 | return 'index' 66 | 67 | 68 | if __name__ == "__main__": 69 | app.run() 70 | -------------------------------------------------------------------------------- /deployment/fix_connection_reset_post.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | deployment.fix_post_reset 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Fix for Connection Reset on POST 7 | http://flask.pocoo.org/snippets/47/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from flask import request, Response 15 | from werkzeug.wsgi import LimitedStream 16 | 17 | from app import app 18 | 19 | 20 | class StreamConsumingMiddleware(object): 21 | 22 | def __init__(self, app): 23 | self.app = app 24 | 25 | def __call__(self, environ, start_response): 26 | stream = LimitedStream(environ['wsgi.input'], 27 | int(environ['CONTENT_LENGTH'] or 0)) 28 | environ['wsgi.input'] = stream 29 | app_iter = self.app(environ, start_response) 30 | try: 31 | stream.exhaust() 32 | for event in app_iter: 33 | yield event 34 | finally: 35 | if hasattr(app_iter, 'close'): 36 | app_iter.close() 37 | 38 | 39 | @app.route('/') 40 | def index(): 41 | return 'index' 42 | 43 | 44 | if __name__ == "__main__": 45 | app.wsgi_app = StreamConsumingMiddleware(app.wsgi_app) 46 | app.run() 47 | -------------------------------------------------------------------------------- /deployment/fix_url_behind_reverse.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | deployment.reverse_url_fix 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Fixing SCRIPT_NAME/url_scheme when behind reverse proxy 7 | http://flask.pocoo.org/snippets/35/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from flask import request, Response 15 | 16 | from app import app 17 | 18 | 19 | class ReverseProxied(object): 20 | '''Wrap the application in this middleware and configure the 21 | front-end server to add these headers, to let you quietly bind 22 | this to a URL other than / and to an HTTP scheme that is 23 | different than what is used locally. 24 | 25 | In nginx: 26 | location /myprefix { 27 | proxy_pass http://192.168.0.1:5001; 28 | proxy_set_header Host $host; 29 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 30 | proxy_set_header X-Scheme $scheme; 31 | proxy_set_header X-Script-Name /myprefix; 32 | } 33 | 34 | :param app: the WSGI application 35 | ''' 36 | def __init__(self, app): 37 | self.app = app 38 | 39 | def __call__(self, environ, start_response): 40 | script_name = environ.get('HTTP_X_SCRIPT_NAME', '') 41 | if script_name: 42 | environ['SCRIPT_NAME'] = script_name 43 | path_info = environ['PATH_INFO'] 44 | if path_info.startswith(script_name): 45 | environ['PATH_INFO'] = path_info[len(script_name):] 46 | 47 | scheme = environ.get('HTTP_X_SCHEME', '') 48 | if scheme: 49 | environ['wsgi.url_scheme'] = scheme 50 | return self.app(environ, start_response) 51 | 52 | 53 | @app.route('/') 54 | def index(): 55 | return 'index' 56 | 57 | 58 | if __name__ == "__main__": 59 | app.wsgi_app = ReverseProxied(app.wsgi_app) 60 | app.run() 61 | -------------------------------------------------------------------------------- /deployment/pass_remote_user.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | deployment.pass_remote_user 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Passing REMOTE_USER from Apache as a reverse proxy to web application servers 7 | http://flask.pocoo.org/snippets/69/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from flask import request, Response 15 | 16 | from app import app 17 | 18 | 19 | """ 20 | RequestHeader set X-Proxy-REMOTE-USER %{REMOTE_USER} 21 | """ 22 | 23 | 24 | class RemoteUserMiddleware(object): 25 | def __init__(self, app): 26 | self.app = app 27 | def __call__(self, environ, start_response): 28 | user = environ.pop('HTTP_X_PROXY_REMOTE_USER', None) 29 | environ['REMOTE_USER'] = user 30 | return self.app(environ, start_response) 31 | 32 | 33 | @app.route('/') 34 | def index(): 35 | return 'index' 36 | 37 | 38 | if __name__ == "__main__": 39 | app.wsgi_app = RemoteUserMiddleware(app.wsgi_app) 40 | app.run() 41 | -------------------------------------------------------------------------------- /deployment/webfaction.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | deployment.webfaction 4 | ~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Deploying a Flask app on Webfaction 7 | http://flask.pocoo.org/snippets/65/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from flask import request, Response 15 | 16 | from app import app 17 | 18 | 19 | """ 20 | Webfaction is a Python friendly hosting with affordable pricing and tons of useful features. 21 | 22 | To deploy a Flask application on Webfaction you should follow these steps: 23 | 24 | Create an application in Webfaction control panel choosing "mod_wsgi 3.2/Python 2.6" or another one of the available Python version. 25 | The system will automagically create some folder under the webapps directory in your home folder 26 | webapps/yourapplication/ 27 | |-- apache2 28 | | |-- bin 29 | | |-- conf 30 | | |-- lib 31 | | |-- logs 32 | | `-- modules 33 | `-- htdocs 34 | Install Flask and all the extensions you need using easy_install: 35 | foo@bar:~$ easy_install-2.6 Flask 36 | Note that Webfaction gives you different easy_install executables: use the one that meets the Python version you choose when the application was created. 37 | 38 | Open webapps/yourapp/index.py delete the content and add the following line: 39 | from yourapp import app as application 40 | Modify your webapps/yourapp/apache2/conf/httpd.conf. At the bottom of the file add the following lines changing yourapp and yourusername according to your setup: 41 | WSGIPythonPath /home/yourusername/webapps/yourapp/htdocs/ 42 | #If you do not specify the following directive the app *will* work but you will 43 | #see index.py in the path of all URLs 44 | WSGIScriptAlias / /home/yourusername/webapps/yourapp/htdocs/index.py 45 | 46 | 47 | AddHandler wsgi-script .py 48 | RewriteEngine on 49 | RewriteBase / 50 | WSGIScriptReloading On 51 | 52 | If you have choosed / as the mout point for your application you are done. If you mounted the application somewhere else (i.e. /blog) there is some additional work to do. 53 | 54 | You need to write a WSGI middleware that prefixes SCRIPT_NAME with that prefix otherwise the url_for function will not be able to create the correct URLs for you (the following snippets is kindly provided by Armin himself). 55 | 56 | class WebFactionMiddleware(object): 57 | def __init__(self, app): 58 | self.app = app 59 | def __call__(self, environ, start_response): 60 | environ['SCRIPT_NAME'] = '/yourapp' 61 | return self.app(environ, start_response) 62 | 63 | app.wsgi_app = WebFactionMiddleware(app.wsgi_app) 64 | You can put this snippet in the application's __init__.py. 65 | 66 | Happy Flasking! 67 | """ 68 | 69 | 70 | @app.route('/') 71 | def index(): 72 | return 'index' 73 | 74 | 75 | if __name__ == "__main__": 76 | app.run() 77 | -------------------------------------------------------------------------------- /forms/complex_validation.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | forms.complex_validation 4 | ~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Complex Validation with Flask-WTF 7 | http://flask.pocoo.org/snippets/64/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from flask import render_template, url_for, redirect 15 | from flask.wtf import Form, TextField, PasswordField, validators 16 | 17 | from app import app 18 | from models import User 19 | 20 | 21 | class LoginForm(Form): 22 | username = TextField('Username', [validators.Required()]) 23 | password = PasswordField('Password', [validators.Required()]) 24 | 25 | def __init__(self, *args, **kwargs): 26 | Form.__init__(self, *args, **kwargs) 27 | self.user = None 28 | 29 | def validate(self): 30 | rv = Form.validate(self) 31 | if not rv: 32 | return False 33 | 34 | user = User.query.filter_by( 35 | username=self.username.data).first() 36 | if user is None: 37 | self.username.errors.append('Unknown username') 38 | return False 39 | 40 | if not user.check_password(self.password.data): 41 | self.password.errors.append('Invalid password') 42 | return False 43 | 44 | self.user = user 45 | return True 46 | 47 | 48 | @app.route('/login', methods=['GET', 'POST']) 49 | def login(): 50 | form = LoginForm() 51 | if form.validate_on_submit(): 52 | flash(u'Successfully logged in as %s' % form.user.username) 53 | session['user_id'] = form.user.id 54 | return redirect(url_for('index')) 55 | return render_template('login.html', form=form) 56 | 57 | 58 | if __name__ == '__main__': 59 | app.run() 60 | -------------------------------------------------------------------------------- /forms/form_from_model.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | forms.form_from_model 4 | ~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Automatically create a WTForms Form from model 7 | http://flask.pocoo.org/snippets/60/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from flask import render_template, url_for, redirect 15 | from flaskext.wtf import Form 16 | from wtforms.ext.appengine.db import model_form 17 | from wtforms import validators 18 | 19 | from app import app 20 | from models import MyModel 21 | 22 | 23 | MyForm = model_form(MyModel, Form, field_args = { 24 | 'name' : { 25 | 'validators' : [validators.Length(max=10)] 26 | } 27 | }) 28 | 29 | 30 | @app.route("/edit") 31 | def edit(id): 32 | MyForm = model_form(MyModel, Form) 33 | model = MyModel.get(id) 34 | form = MyForm(request.form, model) 35 | 36 | if form.validate_on_submit(): 37 | form.populate_obj(model) 38 | model.put() 39 | flash("MyModel updated") 40 | return redirect(url_for("index")) 41 | return render_template("edit.html", form=form) 42 | 43 | 44 | if __name__ == "__main__": 45 | app.run() 46 | -------------------------------------------------------------------------------- /forms/render_wtform_without_syntaxerr.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | forms.render_wtform_without_syntaxerr 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Render WTForm fields with html attributes that cause TemplateSyntaxErrors 7 | http://flask.pocoo.org/snippets/107/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from app import app 15 | 16 | 17 | """ 18 | Suppose you had a WTForm TextField that you wanted to use a javascript library like bootstrap-typeahead.js on. You might want the field to render as: 19 | 20 | 21 | 22 | After creating a WTForm in the view and passing it to your template, your first attempt would be to pass the additional keyword arguments: 23 | 24 | {{ form.myfield(name='test', data-provide='typeahead', data-data-items='3', data-source='["x","y","z"]') }} 25 | 26 | But this will lead to a TemplateSyntaxError because a dash is the subtraction operator in Python, and we can't escape the character in a keyword argument's key. 27 | 28 | Instead, pass the HTML attributes that contain invalid syntax as an ad-hoc dictionary: 29 | 30 | {{ form.myfield(name='test', **{'data-provide':'typeahead','data-items':'3','data-source': '["x","y","z"]'}) }} 31 | """ 32 | -------------------------------------------------------------------------------- /forms/secure_redirect_back.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | forms.secure_redirect_back 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Secure Back Redirects with WTForms 7 | http://flask.pocoo.org/snippets/63/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | from urlparse import urlparse, urljoin 14 | 15 | from flask import request, url_for, redirect 16 | from flaskext.wtf import Form, TextField, HiddenField 17 | 18 | from app import app 19 | 20 | 21 | def is_safe_url(target): 22 | ref_url = urlparse(request.host_url) 23 | test_url = urlparse(urljoin(request.host_url, target)) 24 | return test_url.scheme in ('http', 'https') and \ 25 | ref_url.netloc == test_url.netloc 26 | 27 | 28 | def get_redirect_target(): 29 | for target in request.args.get('next'), request.referrer: 30 | if not target: 31 | continue 32 | if is_safe_url(target): 33 | return target 34 | 35 | 36 | class RedirectForm(Form): 37 | next = HiddenField() 38 | 39 | def __init__(self, *args, **kwargs): 40 | Form.__init__(self, *args, **kwargs) 41 | if not self.next.data: 42 | self.next.data = get_redirect_target() or '' 43 | 44 | def redirect(self, endpoint='index', **values): 45 | if is_safe_url(self.next.data): 46 | return redirect(self.next.data) 47 | target = get_redirect_target() 48 | return redirect(target or url_for(endpoint, **values)) 49 | 50 | 51 | class LoginForm(RedirectForm): 52 | username = TextField('Username') 53 | password = TextField('Password') 54 | 55 | 56 | @app.route('/login', methods=['GET', 'POST']) 57 | def login(): 58 | form = LoginForm() 59 | if form.validate_on_submit(): 60 | # do something with the form data here 61 | return form.redirect('index') 62 | return render_template('login.html', form=form) 63 | 64 | 65 | if __name__ == '__main__': 66 | app.run() 67 | -------------------------------------------------------------------------------- /forms/validate_flatland.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | forms.validate_flatland 4 | ~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Validating a Flatland Schema 7 | http://flask.pocoo.org/snippets/72/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from flatland import Form, String 15 | 16 | from app import app 17 | 18 | 19 | class SignInForm(Form): 20 | username = String 21 | password = String 22 | 23 | 24 | """ 25 | The correct way to create an element instance from a Flask request is as follows: 26 | 27 | if request.method in ['POST', 'PUT']: 28 | form = SignInForm.from_flat(request.form.items(multi=True)) 29 | A little wordy, so you might want to write a little helper function: 30 | 31 | def form_from_request(schema): 32 | return schema.from_flat(request.form.items(multi=True)) 33 | Now you can simply do this in a view: 34 | 35 | if request.method in ['POST', 'PUT']: 36 | form = form_from_request(SignInForm) 37 | An alternative could be to subclass Form and add a validate_on_submit method similar to what Flask-WTF does, so that you can refactor out the request.method check. 38 | """ 39 | -------------------------------------------------------------------------------- /internationalizatioin/babel_lazyproxy.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | internationalizatioin.babel_lazyproxy 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Using Babel's LazyProxy with gettext 7 | http://flask.pocoo.org/snippets/4/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from wtforms import Form, fields 15 | from myapp.utils import ugettext_lazy as _ 16 | from flask import g 17 | from babel.support import LazyProxy 18 | 19 | from app import app 20 | 21 | 22 | class MyForm(Form): 23 | name = fields.TextField(_("Name")) 24 | 25 | 26 | def ugettext(s): 27 | # we assume a before_request function 28 | # assigns the correct user-specific 29 | # translations 30 | return g.translations.ugettext(s) 31 | 32 | 33 | ugettext_lazy = LazyProxy(ugettext) 34 | 35 | 36 | @app.route('/') 37 | def index(): 38 | return 'index' 39 | 40 | 41 | if __name__ == "__main__": 42 | app.run() 43 | -------------------------------------------------------------------------------- /javascript/filter_for_timeago.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | javascript.timeago_filter 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | A Filter for the jQuery Timeago Plugin 7 | http://flask.pocoo.org/snippets/49/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from flask import request, Response 15 | 16 | from app import app 17 | 18 | 19 | """ 20 | Timeago is a jQuery plugin that makes it easy to support automatically 21 | updating fuzzy timestamps (e.g. “4 minutes ago” or “about 1 day ago”). 22 | It automatically keeps them updated and only needs a very basic span 23 | tag or something similar with a certain class and title attribute. 24 | 25 | For instance 26 | ... 27 | turns into something like this: 28 | 2 years ago 29 | """ 30 | 31 | 32 | @app.template_filter() 33 | def datetimeformat(datetime, timeago=True): 34 | readable = datetime.strftime('%Y-%m-%d @ %H:%M') 35 | if not timeago: 36 | return readable 37 | iso_format = datetime.strftime('%Y-%m-%dT%H:%M:%SZ') 38 | return '%s' % ( 39 | iso_format, 40 | readable 41 | ) 42 | 43 | 44 | """ 45 | Usage: 46 |

Date: {{ the_date|datetimeformat }} 47 | 48 | $(function() { 49 | $('span.timeago').timeago(); 50 | }); 51 | """ 52 | 53 | 54 | @app.route('/') 55 | def index(): 56 | return 'index' 57 | 58 | 59 | if __name__ == "__main__": 60 | app.run() 61 | -------------------------------------------------------------------------------- /javascript/push_notifications.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | javascript.push 4 | ~~~~~~~~~~~~~~~ 5 | 6 | Push Notifications with socket.io and Juggernaut 7 | http://flask.pocoo.org/snippets/80/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from flask import request 15 | from juggernaut import Juggernaut 16 | 17 | from app import app 18 | 19 | 20 | """ 21 | $ npm install -g juggernaut 22 | $ juggernaut 23 | $ pip install juggernaut 24 | 25 | 26 | 32 | """ 33 | 34 | 35 | @app.route('/') 36 | def index(): 37 | return 'index' 38 | 39 | 40 | @app.route('/publish/') 41 | def publish(): 42 | jug = Juggernaut() 43 | jug.publish('channel', 'The message') 44 | 45 | 46 | if __name__ == "__main__": 47 | app.run() 48 | -------------------------------------------------------------------------------- /javascript/realtime_using_sse.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | javascript.realtime_sse 4 | ~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Realtime server using the SSE protocol 7 | http://flask.pocoo.org/snippets/116/ 8 | """ 9 | # Make sure your gevent version is >= 1.0 10 | 11 | import os 12 | import sys 13 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 14 | import time 15 | 16 | from flask import request, Response 17 | import gevent 18 | from gevent.wsgi import WSGIServer 19 | from gevent.queue import Queue 20 | 21 | from app import app 22 | 23 | 24 | # SSE "protocol" is described here: http://mzl.la/UPFyxY 25 | class ServerSentEvent(object): 26 | 27 | def __init__(self, data): 28 | self.data = data 29 | self.event = None 30 | self.id = None 31 | self.desc_map = { 32 | self.data: "data", 33 | self.event: "event", 34 | self.id: "id" 35 | } 36 | 37 | def encode(self): 38 | if not self.data: 39 | return "" 40 | lines = ["%s: %s" % (v, k) for k, v in self.desc_map.iteritems() if k] 41 | return "%s\n\n" % "\n".join(lines) 42 | 43 | 44 | subscriptions = [] 45 | 46 | 47 | # Client code consumes like this. 48 | @app.route('/') 49 | def index(): 50 | debug_template = """ 51 | 52 | 53 | 54 | 55 |

Server sent events

56 |
57 | 68 | 69 | 70 | """ 71 | return(debug_template) 72 | 73 | 74 | @app.route("/debug") 75 | def debug(): 76 | return "Currently %d subscriptions" % len(subscriptions) 77 | 78 | 79 | @app.route("/publish") 80 | def publish(): 81 | #Dummy data - pick up from request for real data 82 | def notify(): 83 | msg = str(time.time()) 84 | for sub in subscriptions[:]: 85 | sub.put(msg) 86 | 87 | gevent.spawn(notify) 88 | 89 | return "OK" 90 | 91 | 92 | @app.route("/subscribe") 93 | def subscribe(): 94 | def gen(): 95 | q = Queue() 96 | subscriptions.append(q) 97 | try: 98 | while True: 99 | result = q.get() 100 | ev = ServerSentEvent(str(result)) 101 | yield ev.encode() 102 | except GeneratorExit: # Or maybe use flask signals 103 | subscriptions.remove(q) 104 | 105 | return Response(gen(), mimetype="text/event-stream") 106 | 107 | 108 | if __name__ == "__main__": 109 | server = WSGIServer(("", 5000), app) 110 | server.serve_forever() 111 | # Then visit http://localhost:5000 to subscribe 112 | # and send messages by visiting http://localhost:5000/publish 113 | -------------------------------------------------------------------------------- /performance/add_caching.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | performance.caching 4 | ~~~~~~~~~~~~~~~~~~~ 5 | 6 | Adding caching to Flask apps 7 | http://flask.pocoo.org/snippets/9/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from werkzeug.contrib.cache import SimpleCache 15 | from flask import request 16 | 17 | from app import app 18 | 19 | 20 | CACHE_TIMEOUT = 300 21 | 22 | 23 | cache = SimpleCache() 24 | 25 | 26 | class cached(object): 27 | 28 | def __init__(self, timeout=None): 29 | self.timeout = timeout or CACHE_TIMEOUT 30 | 31 | def __call__(self, f): 32 | def decorator(*args, **kwargs): 33 | response = cache.get(request.path) 34 | if response is None: 35 | response = f(*args, **kwargs) 36 | cache.set(request.path, response, self.timeout) 37 | return response 38 | return decorator 39 | 40 | 41 | @app.route('/') 42 | # @cached() 43 | def index(): 44 | return 'index' 45 | 46 | 47 | @app.before_request 48 | def return_cached(): 49 | # if GET and POST not empty 50 | if not request.values: 51 | response = cache.get(request.path) 52 | if response: 53 | return response 54 | 55 | 56 | @app.after_request 57 | def cache_response(response): 58 | if not request.values: 59 | cache.set(request.path, response, CACHE_TIMEOUT) 60 | return response 61 | 62 | 63 | if __name__ == "__main__": 64 | app.run() 65 | -------------------------------------------------------------------------------- /performance/sqlite_cache.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | performance.sqlite_cache 4 | ~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Cache implementation using SQLite 7 | http://flask.pocoo.org/snippets/87/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | import os, errno, sqlite3 15 | from time import sleep, time 16 | from cPickle import loads, dumps 17 | try: 18 | from thread import get_ident 19 | except ImportError: 20 | from dummy_thread import get_ident 21 | from werkzeug.contrib.cache import BaseCache 22 | 23 | from app import app 24 | 25 | 26 | class SqliteCache(BaseCache): 27 | 28 | _create_sql = ( 29 | 'CREATE TABLE IF NOT EXISTS bucket ' 30 | '(' 31 | ' key TEXT PRIMARY KEY,' 32 | ' val BLOB,' 33 | ' exp FLOAT' 34 | ')' 35 | ) 36 | _get_sql = 'SELECT val, exp FROM bucket WHERE key = ?' 37 | _del_sql = 'DELETE FROM bucket WHERE key = ?' 38 | _set_sql = 'REPLACE INTO bucket (key, val, exp) VALUES (?, ?, ?)' 39 | _add_sql = 'INSERT INTO bucket (key, val, exp) VALUES (?, ?, ?)' 40 | 41 | def __init__(self, path, default_timeout=300): 42 | self.path = os.path.abspath(path) 43 | try: 44 | os.mkdir(self.path) 45 | except OSError, e: 46 | if e.errno != errno.EEXIST or not os.path.isdir(self.path): 47 | raise 48 | self.default_timeout = default_timeout 49 | self.connection_cache = {} 50 | 51 | def _get_conn(self, key): 52 | key = dumps(key, 0) 53 | t_id = get_ident() 54 | if t_id not in self.connection_cache: 55 | self.connection_cache[t_id] = {} 56 | if key not in self.connection_cache[t_id]: 57 | bucket_name = str(hash(key)) 58 | bucket_path = os.path.join(self.path, bucket_name) 59 | conn = sqlite3.Connection(bucket_path, timeout=60) 60 | with conn: 61 | conn.execute(self._create_sql) 62 | self.connection_cache[t_id][key] = conn 63 | return self.connection_cache[t_id][key] 64 | 65 | def get(self, key): 66 | rv = None 67 | with self._get_conn(key) as conn: 68 | for row in conn.execute(self._get_sql, (key,)): 69 | expire = row[1] 70 | if expire > time(): 71 | rv = loads(str(row[0])) 72 | break 73 | return rv 74 | 75 | def delete(self, key): 76 | with self._get_conn(key) as conn: 77 | conn.execute(self._del_sql, (key,)) 78 | 79 | def set(self, key, value, timeout=None): 80 | if not timeout: 81 | timeout = self.default_timeout 82 | value = buffer(dumps(value, 2)) 83 | expire = time() + timeout 84 | with self._get_conn(key) as conn: 85 | conn.execute(self._set_sql, (key, value, expire)) 86 | 87 | def add(self, key, value, timeout=None): 88 | if not timeout: 89 | timeout = self.default_timeout 90 | expire = time() + timeout 91 | value = buffer(dumps(value, 2)) 92 | with self._get_conn(key) as conn: 93 | try: 94 | conn.execute(self._add_sql, (key, value, expire)) 95 | except sqlite3.IntegrityError: 96 | pass 97 | 98 | def clear(self): 99 | for bucket in os.listdir(self.path): 100 | os.unlink(os.path.join(self.path, bucket)) 101 | 102 | 103 | @app.route('/') 104 | def index(): 105 | return 'index' 106 | 107 | 108 | if __name__ == "__main__": 109 | app.run() 110 | -------------------------------------------------------------------------------- /security/csrf_protect.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | security.csrf 4 | ~~~~~~~~~~~~~ 5 | 6 | CSRF Protection 7 | http://flask.pocoo.org/snippets/3/ 8 | """ 9 | 10 | import os 11 | import sys 12 | from uuid import uuid4 13 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 14 | 15 | from flask import request, session, abort 16 | from flask import render_template_string 17 | 18 | from app import app 19 | 20 | 21 | @app.before_request 22 | def csrf_protect(): 23 | if request.method == "POST": 24 | token = session.pop('_csrf_token', None) 25 | if not token or token != request.form.get('_csrf_token'): 26 | abort(403) 27 | 28 | 29 | def generate_csrf_token(): 30 | if '_csrf_token' not in session: 31 | session['_csrf_token'] = str(uuid4()) 32 | return session['_csrf_token'] 33 | 34 | app.jinja_env.globals['csrf_token'] = generate_csrf_token 35 | 36 | 37 | @app.route('/', methods=["GET", "POST"]) 38 | def index(): 39 | return render_template_string('
') 40 | 41 | 42 | if __name__ == "__main__": 43 | app.run() 44 | -------------------------------------------------------------------------------- /security/redirect_back.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | security.rback 4 | ~~~~~~~~~~~~~~ 5 | 6 | Securely Redirect Back 7 | http://flask.pocoo.org/snippets/62/ 8 | """ 9 | 10 | import os 11 | import sys 12 | from urlparse import urlparse, urljoin 13 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 14 | 15 | from flask import request, url_for, redirect 16 | from flask import render_template_string 17 | 18 | from app import app 19 | 20 | 21 | def is_safe_url(target): 22 | ref_url = urlparse(request.host_url) 23 | test_url = urlparse(urljoin(request.host_url, target)) 24 | return test_url.scheme in ('http', 'https') and \ 25 | ref_url.netloc == test_url.netloc 26 | 27 | 28 | def get_redirect_target(): 29 | for target in request.values.get('next'), request.referrer: 30 | if not target: 31 | continue 32 | if is_safe_url(target): 33 | return target 34 | 35 | 36 | def redirect_back(endpoint, **values): 37 | target = request.form['next'] 38 | if not target or not is_safe_url(target): 39 | target = url_for(endpoint, **values) 40 | return redirect(target) 41 | 42 | 43 | @app.route('/') 44 | def index(): 45 | return 'index' 46 | 47 | 48 | @app.route('/fsp') 49 | def fsp(): 50 | return 'fsp' 51 | 52 | 53 | @app.route('/login', methods=['GET', 'POST']) 54 | def login(): 55 | next = get_redirect_target() 56 | html_content = """ 57 |
58 |
59 |
Username: 60 |
61 |
Password: 62 |
63 |
64 |

65 | 66 | 67 |

68 | """ 69 | if request.method == 'POST': 70 | # Login code here 71 | return redirect_back('index') 72 | return render_template_string(html_content, next=next) 73 | 74 | 75 | if __name__ == "__main__": 76 | app.run() 77 | -------------------------------------------------------------------------------- /security/salted_password.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | security.salted 4 | ~~~~~~~~~~~~~~~ 5 | 6 | Salted Passwords 7 | http://flask.pocoo.org/snippets/54/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from werkzeug.security import generate_password_hash, check_password_hash 15 | 16 | from app import app 17 | 18 | 19 | class User(object): 20 | 21 | def __init__(self, username, password): 22 | self.username = username 23 | self.set_password(password) 24 | 25 | def set_password(self, password): 26 | self.pw_hash = generate_password_hash(password) 27 | 28 | def check_password(self, password): 29 | return check_password_hash(self.pw_hash, password) 30 | 31 | 32 | @app.route('/') 33 | def index(): 34 | me = User('John Doe', 'default') 35 | print me.pw_hash 36 | print me.check_password('default') 37 | print me.check_password('defaultx') 38 | return 'index' 39 | 40 | 41 | if __name__ == "__main__": 42 | app.run() 43 | -------------------------------------------------------------------------------- /security/serve_https.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | security.https 4 | ~~~~~~~~~~~~~~ 5 | 6 | How to serve HTTPS *directly* from Flask 7 | http://flask.pocoo.org/snippets/111/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from OpenSSL import SSL 15 | 16 | from app import app 17 | 18 | 19 | context = SSL.Context(SSL.SSLv23_METHOD) 20 | context.use_privatekey_file('yourserver.key') 21 | context.use_certificate_file('yourserver.crt') 22 | 23 | 24 | @app.route('/') 25 | def index(): 26 | return 'index' 27 | 28 | 29 | """ 30 | Linux-related: 31 | there is a confirmed bug in pyOpenSSL that generates a runtime error: 32 | https://bugs.launchpad.net/pyopenssl/+bug/900792 33 | 34 | The workaround is to put these 2 lines in werkzeug/serving.py 35 | 36 | in class BaseWSGIServer(HTTPServer, object): 37 | ... 38 | def shutdown_request(self,request): 39 | request.shutdown() 40 | """ 41 | 42 | 43 | if __name__ == "__main__": 44 | app.run(ssl_context=context) 45 | -------------------------------------------------------------------------------- /sessions/beaker_session.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | sessions.beaker_session 4 | ~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Using Beaker session with Flask 7 | http://flask.pocoo.org/snippets/61/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from flask import request 15 | from beaker.middleware import SessionMiddleware 16 | 17 | from app import app 18 | 19 | 20 | session_opts = { 21 | 'session.type': 'ext:memcached', 22 | 'session.url': '127.0.0.1:11211', 23 | 'session.data_dir': './cache', 24 | } 25 | 26 | 27 | @app.route('/') 28 | def index(): 29 | session = request.environ['beaker.session'] 30 | if not session.has_key('value'): 31 | session['value'] = 'Save in session' 32 | session.save() 33 | return "Session value set." 34 | else: 35 | return session['value'] 36 | 37 | if __name__ == '__main__': 38 | app.wsgi_app = SessionMiddleware(app.wsgi_app, session_opts) 39 | app.run(debug=True) 40 | -------------------------------------------------------------------------------- /sessions/better_client_session.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | sessions.better_client_session 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Better Client-side sessions 7 | http://flask.pocoo.org/snippets/51/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from werkzeug.datastructures import CallbackDict 15 | from flask.sessions import SessionInterface, SessionMixin 16 | from itsdangerous import URLSafeTimedSerializer, BadSignature 17 | 18 | from app import app 19 | 20 | 21 | class ItsdangerousSession(CallbackDict, SessionMixin): 22 | 23 | def __init__(self, initial=None): 24 | def on_update(self): 25 | self.modified = True 26 | CallbackDict.__init__(self, initial, on_update) 27 | self.modified = False 28 | 29 | 30 | class ItsdangerousSessionInterface(SessionInterface): 31 | salt = 'cookie-session' 32 | session_class = ItsdangerousSession 33 | 34 | def get_serializer(self, app): 35 | if not app.secret_key: 36 | return None 37 | return URLSafeTimedSerializer(app.secret_key, 38 | salt=self.salt) 39 | 40 | def open_session(self, app, request): 41 | s = self.get_serializer(app) 42 | if s is None: 43 | return None 44 | val = request.cookies.get(app.session_cookie_name) 45 | if not val: 46 | return self.session_class() 47 | max_age = app.permanent_session_lifetime.total_seconds() 48 | try: 49 | data = s.loads(val, max_age=max_age) 50 | return self.session_class(data) 51 | except BadSignature: 52 | return self.session_class() 53 | 54 | def save_session(self, app, session, response): 55 | domain = self.get_cookie_domain(app) 56 | if not session: 57 | if session.modified: 58 | response.delete_cookie(app.session_cookie_name, 59 | domain=domain) 60 | return 61 | expires = self.get_expiration_time(app, session) 62 | val = self.get_serializer(app).dumps(dict(session)) 63 | response.set_cookie(app.session_cookie_name, val, 64 | expires=expires, httponly=True, 65 | domain=domain) 66 | 67 | 68 | app.session_interface = ItsdangerousSessionInterface() 69 | -------------------------------------------------------------------------------- /sessions/count_online_users.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | sessions.count_online_users 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Counting Online Users with Redis 7 | http://flask.pocoo.org/snippets/71/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | import time 14 | from datetime import datetime 15 | 16 | from redis import Redis 17 | from flask import Response, request 18 | 19 | from app import app 20 | 21 | 22 | redis = Redis() 23 | ONLINE_LAST_MINUTES = 5 24 | app.config['ONLINE_LAST_MINUTES'] = ONLINE_LAST_MINUTES 25 | 26 | 27 | def mark_online(user_id): 28 | now = int(time.time()) 29 | expires = now + (app.config['ONLINE_LAST_MINUTES'] * 60) + 10 30 | all_users_key = 'online-users/%d' % (now // 60) 31 | user_key = 'user-activity/%s' % user_id 32 | p = redis.pipeline() 33 | p.sadd(all_users_key, user_id) 34 | p.set(user_key, now) 35 | p.expireat(all_users_key, expires) 36 | p.expireat(user_key, expires) 37 | p.execute() 38 | 39 | 40 | def get_user_last_activity(user_id): 41 | last_active = redis.get('user-activity/%s' % user_id) 42 | if last_active is None: 43 | return None 44 | return datetime.utcfromtimestamp(int(last_active)) 45 | 46 | 47 | def get_online_users(): 48 | current = int(time.time()) // 60 49 | minutes = xrange(app.config['ONLINE_LAST_MINUTES']) 50 | return redis.sunion(['online-users/%d' % (current - x) 51 | for x in minutes]) 52 | 53 | 54 | @app.before_request 55 | def mark_current_user_online(): 56 | mark_online(request.remote_addr) 57 | 58 | 59 | @app.route('/online') 60 | def index(): 61 | return Response('Online: %s' % ', '.join(get_online_users()), 62 | mimetype='text/plain') 63 | 64 | 65 | if __name__ == '__main__': 66 | app.run() 67 | -------------------------------------------------------------------------------- /sessions/file_session.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | sessions.file_session 4 | ~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Generic server-based sessions (file-system, etc) 7 | http://flask.pocoo.org/snippets/109/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | import cPickle as pickle 14 | 15 | import base64 16 | import hmac 17 | import hashlib 18 | import random 19 | import string 20 | 21 | import datetime 22 | from uuid import uuid4 23 | from collections import OrderedDict 24 | 25 | from werkzeug.datastructures import CallbackDict 26 | from flask.sessions import SessionInterface, SessionMixin 27 | 28 | from app import app 29 | 30 | 31 | def _generate_sid(): 32 | return str(uuid4()) 33 | 34 | 35 | def _calc_hmac(body, secret): 36 | return base64.b64encode(hmac.new(secret, body, hashlib.sha1).digest()) 37 | 38 | 39 | class ManagedSession(CallbackDict, SessionMixin): 40 | def __init__(self, initial=None, sid=None, new=False, randval=None, hmac_digest=None): 41 | def on_update(self): 42 | self.modified = True 43 | 44 | CallbackDict.__init__(self, initial, on_update) 45 | self.sid = sid 46 | self.new = new 47 | self.modified = False 48 | self.randval = randval 49 | self.hmac_digest = hmac_digest 50 | 51 | def sign(self, secret): 52 | if not self.hmac_digest: 53 | self.randval = ''.join(random.sample(string.lowercase+string.digits, 20)) 54 | self.hmac_digest = _calc_hmac('%s:%s' % (self.sid, self.randval), secret) 55 | 56 | 57 | class SessionManager(object): 58 | def new_session(self): 59 | 'Create a new session' 60 | raise NotImplementedError 61 | 62 | def exists(self, sid): 63 | 'Does the given session-id exist?' 64 | raise NotImplementedError 65 | 66 | def remove(self, sid): 67 | 'Remove the session' 68 | raise NotImplementedError 69 | 70 | def get(self, sid, digest): 71 | 'Retrieve a managed session by session-id, checking the HMAC digest' 72 | raise NotImplementedError 73 | 74 | def put(self, session): 75 | 'Store a managed session' 76 | raise NotImplementedError 77 | 78 | 79 | class CachingSessionManager(SessionManager): 80 | def __init__(self, parent, num_to_store): 81 | self.parent = parent 82 | self.num_to_store = num_to_store 83 | self._cache = OrderedDict() 84 | 85 | def _normalize(self): 86 | print "Session cache size: %s" % len(self._cache) 87 | if len(self._cache) > self.num_to_store: 88 | while len(self._cache) > (self.num_to_store * 0.8): # flush 20% of the cache 89 | self._cache.popitem(False) 90 | 91 | def new_session(self): 92 | session = self.parent.new_session() 93 | self._cache[session.sid] = session 94 | self._normalize() 95 | return session 96 | 97 | def remove(self, sid): 98 | self.parent.remove(sid) 99 | if sid in self._cache: 100 | del self._cache[sid] 101 | 102 | def exists(self, sid): 103 | if sid in self._cache: 104 | return True 105 | return self.parent.exists(sid) 106 | 107 | def get(self, sid, digest): 108 | session = None 109 | if sid in self._cache: 110 | session = self._cache[sid] 111 | if session.hmac_digest != digest: 112 | session = None 113 | 114 | # reset order in OrderedDict 115 | del self._cache[sid] 116 | 117 | if not session: 118 | session = self.parent.get(sid, digest) 119 | 120 | self._cache[sid] = session 121 | self._normalize() 122 | return session 123 | 124 | def put(self, session): 125 | self.parent.put(session) 126 | if session.sid in self._cache: 127 | del self._cache[session.sid] 128 | self._cache[session.sid] = session 129 | self._normalize() 130 | 131 | 132 | class FileBackedSessionManager(SessionManager): 133 | def __init__(self, path, secret): 134 | self.path = path 135 | self.secret = secret 136 | if not os.path.exists(self.path): 137 | os.makedirs(self.path) 138 | 139 | def exists(self, sid): 140 | fname = os.path.join(self.path, sid) 141 | return os.path.exists(fname) 142 | 143 | def remove(self, sid): 144 | print 'Removing session: %s' % sid 145 | fname = os.path.join(self.path, sid) 146 | if os.path.exists(fname): 147 | os.unlink(fname) 148 | 149 | def new_session(self): 150 | sid = _generate_sid() 151 | fname = os.path.join(self.path, sid) 152 | 153 | while os.path.exists(fname): 154 | sid = _generate_sid() 155 | fname = os.path.join(self.path, sid) 156 | 157 | # touch the file 158 | with open(fname, 'w'): 159 | pass 160 | 161 | print "Created new session: %s" % sid 162 | 163 | return ManagedSession(sid=sid) 164 | 165 | def get(self, sid, digest): 166 | 'Retrieve a managed session by session-id, checking the HMAC digest' 167 | 168 | print "Looking for session: %s, %s" % (sid, digest) 169 | 170 | fname = os.path.join(self.path, sid) 171 | data = None 172 | hmac_digest = None 173 | randval = None 174 | 175 | if os.path.exists(fname): 176 | try: 177 | with open(fname) as f: 178 | randval, hmac_digest, data = pickle.load(f) 179 | except: 180 | print "Error loading session file" 181 | 182 | if not data: 183 | print "Missing data?" 184 | return self.new_session() 185 | 186 | # This assumes the file is correct, if you really want to 187 | # make sure the session is good from the server side, you 188 | # can re-calculate the hmac 189 | 190 | if hmac_digest != digest: 191 | print "Invalid HMAC for session" 192 | return self.new_session() 193 | 194 | return ManagedSession(data, sid=sid, randval=randval, hmac_digest=hmac_digest) 195 | 196 | def put(self, session): 197 | 'Store a managed session' 198 | print "Storing session: %s" % session.sid 199 | 200 | if not session.hmac_digest: 201 | session.sign(self.secret) 202 | 203 | fname = os.path.join(self.path, session.sid) 204 | with open(fname, 'w') as f: 205 | pickle.dump((session.randval, session.hmac_digest, dict(session)), f) 206 | 207 | 208 | class ManagedSessionInterface(SessionInterface): 209 | def __init__(self, manager, skip_paths, cookie_timedelta): 210 | self.manager = manager 211 | self.skip_paths = skip_paths 212 | self.cookie_timedelta = cookie_timedelta 213 | 214 | def get_expiration_time(self, app, session): 215 | if session.permanent: 216 | return app.permanent_session_lifetime 217 | return datetime.datetime.now() + self.cookie_timedelta 218 | 219 | def open_session(self, app, request): 220 | cookie_val = request.cookies.get(app.session_cookie_name) 221 | 222 | if not cookie_val or not '!' in cookie_val: 223 | # Don't bother creating a cookie for static resources 224 | for sp in self.skip_paths: 225 | if request.path.startswith(sp): 226 | return None 227 | 228 | print 'Missing cookie' 229 | return self.manager.new_session() 230 | 231 | sid, digest = cookie_val.split('!', 1) 232 | 233 | if self.manager.exists(sid): 234 | return self.manager.get(sid, digest) 235 | 236 | return self.manager.new_session() 237 | 238 | def save_session(self, app, session, response): 239 | domain = self.get_cookie_domain(app) 240 | if not session: 241 | self.manager.remove(session.sid) 242 | if session.modified: 243 | response.delete_cookie(app.session_cookie_name, domain=domain) 244 | return 245 | 246 | if not session.modified: 247 | # no need to save an unaltered session 248 | # TODO: put logic here to test if the cookie is older than N days, if so, update the expiration date 249 | return 250 | 251 | self.manager.put(session) 252 | session.modified = False 253 | 254 | cookie_exp = self.get_expiration_time(app, session) 255 | response.set_cookie(app.session_cookie_name, 256 | '%s!%s' % (session.sid, session.hmac_digest), 257 | expires=cookie_exp, httponly=True, domain=domain) 258 | 259 | 260 | app.session_interface = ManagedSessionInterface(CachingSessionManager(FileBackedSessionManager(app.config['SESSION_PATH'], app.config['SECRET_KEY']), 1000), skip_paths, datetime.timedelta(days=1)) 261 | -------------------------------------------------------------------------------- /sessions/mongodb_session.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | sessions.mongodb_session 4 | ~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Server-side sessions with MongoDB (pymongo) 7 | http://flask.pocoo.org/snippets/110/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | from uuid import uuid4 14 | from datetime import datetime, timedelta 15 | 16 | from flask.sessions import SessionInterface, SessionMixin 17 | from werkzeug.datastructures import CallbackDict 18 | from pymongo import MongoClient 19 | 20 | from app import app 21 | 22 | 23 | class MongoSession(CallbackDict, SessionMixin): 24 | 25 | def __init__(self, initial=None, sid=None): 26 | CallbackDict.__init__(self, initial) 27 | self.sid = sid 28 | self.modified = False 29 | 30 | 31 | class MongoSessionInterface(SessionInterface): 32 | 33 | def __init__(self, host='localhost', port=27017, 34 | db='', collection='sessions'): 35 | client = MongoClient(host, port) 36 | self.store = client[db][collection] 37 | 38 | def open_session(self, app, request): 39 | sid = request.cookies.get(app.session_cookie_name) 40 | if sid: 41 | stored_session = self.store.find_one({'sid': sid}) 42 | if stored_session: 43 | if stored_session.get('expiration') > datetime.utcnow(): 44 | return MongoSession(initial=stored_session['data'], 45 | sid=stored_session['sid']) 46 | sid = str(uuid4()) 47 | return MongoSession(sid=sid) 48 | 49 | def save_session(self, app, session, response): 50 | domain = self.get_cookie_domain(app) 51 | if not session: 52 | response.delete_cookie(app.session_cookie_name, domain=domain) 53 | return 54 | if self.get_expiration_time(app, session): 55 | expiration = self.get_expiration_time(app, session) 56 | else: 57 | expiration = datetime.utcnow() + timedelta(hours=1) 58 | self.store.update({'sid': session.sid}, 59 | {'sid': session.sid, 60 | 'data': session, 61 | 'expiration': expiration}, True) 62 | response.set_cookie(app.session_cookie_name, session.sid, 63 | expires=self.get_expiration_time(app, session), 64 | httponly=True, domain=domain) 65 | 66 | 67 | app.session_interface = MongoSessionInterface(db='pjuu') 68 | -------------------------------------------------------------------------------- /sessions/old_new_session.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | sessions.old_new_session 4 | ~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Support for Old and New Sessions 7 | http://flask.pocoo.org/snippets/52/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | try: 14 | from flask.sessions import SessionMixin, SessionInterface 15 | except ImportError: 16 | class SessionInterface(object): 17 | pass 18 | 19 | class SessionMixin(object): 20 | def _get_permanent(self): 21 | return self.get('_permanent', False) 22 | def _set_permanent(self, value): 23 | self['_permanent'] = bool(value) 24 | permanent = property(_get_permanent, _set_permanent) 25 | del _get_permanent, _set_permanent 26 | 27 | # you can use a werkzeug.datastructure.CallbackDict 28 | # to automatically update modified if you want, but 29 | # it's not a requirement. 30 | new = False 31 | modified = True 32 | 33 | 34 | class MySession(dict, SessionMixin): 35 | pass 36 | 37 | 38 | class MySessionInterface(object): 39 | 40 | def open_session(self, app, request): 41 | # load the session and return it. 42 | return MySession() 43 | 44 | def save_session(self, app, session, response): 45 | # save the session 46 | ... 47 | 48 | 49 | def init_my_extension(app): 50 | if not hasattr(app, 'session_interface'): 51 | app.open_session = lambda r: \ 52 | app.session_interface.open_session(app, r) 53 | app.save_session = lambda s, r: \ 54 | app.session_interface.save_session(app, s, r) 55 | app.session_interface = MySessionInterface() 56 | -------------------------------------------------------------------------------- /sessions/redis_session.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | sessions.redis_session 4 | ~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Server-side Sessions with Redis 7 | http://flask.pocoo.org/snippets/75/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | import pickle 14 | from datetime import timedelta 15 | from uuid import uuid4 16 | from redis import Redis 17 | from werkzeug.datastructures import CallbackDict 18 | from flask.sessions import SessionInterface, SessionMixin 19 | 20 | from app import app 21 | 22 | 23 | class RedisSession(CallbackDict, SessionMixin): 24 | 25 | def __init__(self, initial=None, sid=None, new=False): 26 | def on_update(self): 27 | self.modified = True 28 | CallbackDict.__init__(self, initial, on_update) 29 | self.sid = sid 30 | self.new = new 31 | self.modified = False 32 | 33 | 34 | class RedisSessionInterface(SessionInterface): 35 | serializer = pickle 36 | session_class = RedisSession 37 | 38 | def __init__(self, redis=None, prefix='session:'): 39 | if redis is None: 40 | redis = Redis() 41 | self.redis = redis 42 | self.prefix = prefix 43 | 44 | def generate_sid(self): 45 | return str(uuid4()) 46 | 47 | def get_redis_expiration_time(self, app, session): 48 | if session.permanent: 49 | return app.permanent_session_lifetime 50 | return timedelta(days=1) 51 | 52 | def open_session(self, app, request): 53 | sid = request.cookies.get(app.session_cookie_name) 54 | if not sid: 55 | sid = self.generate_sid() 56 | return self.session_class(sid=sid, new=True) 57 | val = self.redis.get(self.prefix + sid) 58 | if val is not None: 59 | data = self.serializer.loads(val) 60 | return self.session_class(data, sid=sid) 61 | return self.session_class(sid=sid, new=True) 62 | 63 | def save_session(self, app, session, response): 64 | domain = self.get_cookie_domain(app) 65 | if not session: 66 | self.redis.delete(self.prefix + session.sid) 67 | if session.modified: 68 | response.delete_cookie(app.session_cookie_name, 69 | domain=domain) 70 | return 71 | redis_exp = self.get_redis_expiration_time(app, session) 72 | cookie_exp = self.get_expiration_time(app, session) 73 | val = self.serializer.dumps(dict(session)) 74 | self.redis.setex(self.prefix + session.sid, val, 75 | int(redis_exp.total_seconds())) 76 | response.set_cookie(app.session_cookie_name, session.sid, 77 | expires=cookie_exp, httponly=True, 78 | domain=domain) 79 | 80 | 81 | app.session_interface = RedisSessionInterface() 82 | 83 | 84 | """ 85 | def total_seconds(td): 86 | return td.days * 60 * 60 * 24 + td.seconds 87 | """ 88 | -------------------------------------------------------------------------------- /sessions/sqlite_session.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | sessions.sqlite_session 4 | ~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Server-side sessions with SQLite 7 | http://flask.pocoo.org/snippets/86/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | import errno, sqlite3 14 | from uuid import uuid4 15 | from cPickle import dumps, loads 16 | from collections import MutableMapping 17 | from flask.sessions import SessionInterface, SessionMixin 18 | 19 | from app import app 20 | 21 | 22 | class SqliteSession(MutableMapping, SessionMixin): 23 | 24 | _create_sql = ( 25 | 'CREATE TABLE IF NOT EXISTS session ' 26 | '(' 27 | ' key TEXT PRIMARY KEY,' 28 | ' val BLOB' 29 | ')' 30 | ) 31 | _get_sql = 'SELECT val FROM session WHERE key = ?' 32 | _set_sql = 'REPLACE INTO session (key, val) VALUES (?, ?)' 33 | _del_sql = 'DELETE FROM session WHERE key = ?' 34 | _ite_sql = 'SELECT key FROM session' 35 | _len_sql = 'SELECT COUNT(*) FROM session' 36 | 37 | def __init__(self, directory, sid, *args, **kwargs): 38 | self.path = os.path.join(directory, sid) 39 | self.directory = directory 40 | self.sid = sid 41 | self.modified = False 42 | self.conn = None 43 | if not os.path.exists(self.path): 44 | with self._get_conn() as conn: 45 | conn.execute(self._create_sql) 46 | self.new = True 47 | 48 | def __getitem__(self, key): 49 | key = dumps(key, 0) 50 | rv = None 51 | with self._get_conn() as conn: 52 | for row in conn.execute(self._get_sql, (key,)): 53 | rv = loads(str(row[0])) 54 | break 55 | if rv is None: 56 | raise KeyError('Key not in this session') 57 | return rv 58 | 59 | def __setitem__(self, key, value): 60 | key = dumps(key, 0) 61 | value = buffer(dumps(value, 2)) 62 | with self._get_conn() as conn: 63 | conn.execute(self._set_sql, (key, value)) 64 | self.modified = True 65 | 66 | def __delitem__(self, key): 67 | key = dumps(key, 0) 68 | with self._get_conn() as conn: 69 | conn.execute(self._del_sql, (key,)) 70 | self.modified = True 71 | 72 | def __iter__(self): 73 | with self._get_conn() as conn: 74 | for row in conn.execute(self._ite_sql): 75 | yield loads(str(row[0])) 76 | 77 | def __len__(self): 78 | with self._get_conn() as conn: 79 | for row in conn.execute(self._len_sql): 80 | return row[0] 81 | 82 | def _get_conn(self): 83 | if not self.conn: 84 | self.conn = sqlite3.Connection(self.path) 85 | return self.conn 86 | 87 | # These proxy classes are needed in order 88 | # for this session implementation to work properly. 89 | # That is because sometimes flask will chain method calls 90 | # with session'setdefault' calls. 91 | # Eg: session.setdefault('_flashes', []).append(1) 92 | # With these proxies, the changes made by chained 93 | # method calls will be persisted back to the sqlite 94 | # database. 95 | class CallableAttributeProxy(object): 96 | def __init__(self, session, key, obj, attr): 97 | self.session = session 98 | self.key = key 99 | self.obj = obj 100 | self.attr = attr 101 | def __call__(self, *args, **kwargs): 102 | rv = self.attr(*args, **kwargs) 103 | self.session[self.key] = self.obj 104 | return rv 105 | 106 | class PersistedObjectProxy(object): 107 | def __init__(self, session, key, obj): 108 | self.session = session 109 | self.key = key 110 | self.obj = obj 111 | def __getattr__(self, name): 112 | attr = getattr(self.obj, name) 113 | if callable(attr): 114 | return SqliteSession.CallableAttributeProxy( 115 | self.session, self.key, self.obj, attr) 116 | return attr 117 | 118 | def setdefault(self, key, value): 119 | if key not in self: 120 | self[key] = value 121 | self.modified = True 122 | return SqliteSession.PersistedObjectProxy( 123 | self, key, self[key]) 124 | 125 | 126 | class SqliteSessionInterface(SessionInterface): 127 | 128 | def __init__(self, directory): 129 | directory = os.path.abspath(directory) 130 | if not os.path.exists(directory): 131 | os.mkdir(directory) 132 | self.directory = directory 133 | 134 | def open_session(self, app, request): 135 | sid = request.cookies.get(app.session_cookie_name) 136 | if not sid: 137 | sid = str(uuid4()) 138 | rv = SqliteSession(self.directory, sid) 139 | return rv 140 | 141 | def save_session(self, app, session, response): 142 | domain = self.get_cookie_domain(app) 143 | if not session: 144 | try: 145 | os.unlink(session.path) 146 | except OSError, e: 147 | if e.errno != errno.ENOENT: 148 | raise 149 | if session.modified: 150 | response.delete_cookie(app.session_cookie_name, 151 | domain=domain) 152 | return 153 | cookie_exp = self.get_expiration_time(app, session) 154 | response.set_cookie(app.session_cookie_name, session.sid, 155 | expires=cookie_exp, httponly=True, domain=domain) 156 | 157 | 158 | # Use shared memory (tmpfs) for maximum scalability 159 | # It is possible to use a NFS directory. 160 | # Recent NFS implementions have good fcntl support 161 | # which is the locking mechanism sqlite uses. 162 | path = '/run/shm/app_session' 163 | if not os.path.exists(path): 164 | os.mkdir(path) 165 | os.chmod(path, int('700', 8)) 166 | app.session_interface = SqliteSessionInterface(path) 167 | -------------------------------------------------------------------------------- /sessions/unittest_example.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | sessions.unittest_example 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Unittest example with before and after function calls 7 | http://flask.pocoo.org/snippets/58/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | 15 | def test_set_date_range(self): 16 | arg_dict = { 17 | 'min_date': "2011-7-1", 18 | 'max_date': "2011-7-4", 19 | } 20 | with self.app.test_request_context('/date_range/', 21 | method="POST", data=arg_dict): 22 | 23 | # call the before funcs 24 | rv = self.app.preprocess_request() 25 | if rv != None: 26 | response = self.app.make_response(rv) 27 | else: 28 | # do the main dispatch 29 | rv = self.app.dispatch_request() 30 | response = self.app.make_response(rv) 31 | 32 | # now do the after funcs 33 | response = self.app.process_response(response) 34 | 35 | assert response.mimetype == 'application/json' 36 | assert "OK" in response.data 37 | -------------------------------------------------------------------------------- /template.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | flask-snippets.template 4 | ~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Template Python file for flask-snippets. 7 | """ 8 | 9 | import os 10 | import sys 11 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 12 | 13 | from flask import request, Response 14 | 15 | from app import app 16 | 17 | 18 | @app.route('/') 19 | def index(): 20 | return 'index' 21 | 22 | 23 | if __name__ == "__main__": 24 | app.run() 25 | -------------------------------------------------------------------------------- /templatetricks/enable_line_statement.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | templatetricks.enable_line_statement 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Enable jinja2 line statements 7 | http://flask.pocoo.org/snippets/101/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from flask import request, Response 15 | 16 | from app import app 17 | 18 | 19 | app.jinja_env.line_statement_prefix = '%' 20 | 21 | 22 | @app.route('/') 23 | def index(): 24 | return 'index' 25 | 26 | 27 | """ 28 |
    29 | % for item in items 30 |
  • {{ item }}
  • 31 | % endfor 32 |
33 | """ 34 | 35 | 36 | if __name__ == "__main__": 37 | app.run() 38 | -------------------------------------------------------------------------------- /templatetricks/gae_correct_errors.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | templatetricks.gae_correct_errors 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Show correct Tracebacks for some Errors triggered inside a Template on GAE 7 | http://flask.pocoo.org/snippets/74/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | def format_exception(tb): 15 | return tb.render_as_text() 16 | # undocumented feature 17 | app.jinja_env.exception_formatter = format_exception 18 | 19 | 20 | from flask import make_response 21 | def format_exception(tb): 22 | res = make_response(tb.render_as_text()) 23 | res.content_type = 'text/plain' 24 | return res 25 | app.jinja_env.exception_formatter = format_exception 26 | -------------------------------------------------------------------------------- /templatetricks/generate_pdf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | templatetricks.generate_pdf 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Generating PDF from Flask template (using xhtml2pdf) 7 | http://flask.pocoo.org/snippets/68/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from flask import request, Response, render_template, redirect, url_for 15 | from flaskext.mail import Mail, Message 16 | from xhtml2pdf import pisa 17 | from StringIO import StringIO 18 | 19 | from app import app 20 | 21 | 22 | html_content = """ 23 | 24 | 25 | 26 | 27 | {% block body %} 28 |

Some page title.

29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 41 | 42 | 43 |
Some text.
38 |

Some subtitle

39 |
{{ g.user.get('user_attribute') }}
40 |
44 |
45 | 46 | {% endblock %} 47 | 48 | 49 | """ 50 | 51 | 52 | def create_pdf(pdf_data): 53 | pdf = StringIO() 54 | pisa.CreatePDF(StringIO(pdf_data.encode('utf-8')), pdf) 55 | return pdf 56 | 57 | 58 | mail_ext = Mail(app) 59 | 60 | 61 | @app.route('/your/url') 62 | def your_view(): 63 | subject = "Mail with PDF" 64 | receiver = "receiver@mail.com" 65 | mail_to_be_sent = Message(subject=subject, recipients=[receiver]) 66 | mail_to_be_sent.body = "This email contains PDF." 67 | pdf = create_pdf(render_template('your/template.html')) 68 | mail_to_be_sent.attach("file.pdf", "application/pdf", pdf.getvalue()) 69 | mail_ext.send(mail_to_be_sent) 70 | return redirect(url_for('other_view')) 71 | -------------------------------------------------------------------------------- /templatetricks/latex_second_jinja.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | templatetricks.latex_second_jinja 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Using a second Jinja environment for LaTeX templates. 7 | http://flask.pocoo.org/snippets/55/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from flask import request, Response, render_template, redirect, url_for 15 | 16 | from app import app 17 | 18 | 19 | LATEX_SUBS = ( 20 | (re.compile(r'\\'), r'\\textbackslash'), 21 | (re.compile(r'([{}_#%&$])'), r'\\\1'), 22 | (re.compile(r'~'), r'\~{}'), 23 | (re.compile(r'\^'), r'\^{}'), 24 | (re.compile(r'"'), r"''"), 25 | (re.compile(r'\.\.\.+'), r'\\ldots'), 26 | ) 27 | 28 | def escape_tex(value): 29 | newval = value 30 | for pattern, replacement in LATEX_SUBS: 31 | newval = pattern.sub(replacement, newval) 32 | return newval 33 | 34 | texenv = app.create_jinja_environment() 35 | texenv.block_start_string = '((*' 36 | texenv.block_end_string = '*))' 37 | texenv.variable_start_string = '(((' 38 | texenv.variable_end_string = ')))' 39 | texenv.comment_start_string = '((=' 40 | texenv.comment_end_string = '=))' 41 | texenv.filters['escape_tex'] = escape_tex 42 | 43 | 44 | template = texenv.get_template('template.tex') 45 | template.render(name='Tom') 46 | 47 | 48 | """ 49 | \documentclass{article} 50 | 51 | \begin{document} 52 | Hello, ((( name|escape_tex )))! 53 | \end{document} 54 | """ 55 | -------------------------------------------------------------------------------- /templatetricks/link_form_macro.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | templatetricks.link_form_macro 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | link_to and form_tag macros 7 | http://flask.pocoo.org/snippets/14/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from app import app 15 | 16 | 17 | """ 18 | The HTML/Jinja for a link to a page on your site looks quite awkward. 19 | 20 | Link text! 21 | With this macro: 22 | 23 | {% macro link_to(endpoint, text) -%} 24 | {{ text|safe }} 25 | {%- endmacro %} 26 | The above link will become: 27 | 28 | {{ link_to('some.view', "Link text!", foo=bar) }} 29 | It's shorter and looks cleaner, especially if the content of the link is also a variable. 30 | 31 | A similar technique, using the call tag, can be used for forms: 32 | 33 | {% macro form_tag(endpoint, method='post') -%} 34 |
36 | {{ caller () }} 37 |
38 | {%- endmacro %} 39 | Then, you can create a form with: 40 | 41 | {% call form_tag('create_entry') %} 42 |

43 | 44 |

45 | {% endcall %} 46 | """ 47 | -------------------------------------------------------------------------------- /templatetricks/nl2br_filter.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | templatetricks.nl2br_filter 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | nl2br filter 7 | http://flask.pocoo.org/snippets/28/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | import re 14 | 15 | from jinja2 import evalcontextfilter, Markup, escape 16 | 17 | from app import app 18 | 19 | 20 | _paragraph_re = re.compile(r'(?:\r\n|\r|\n){2,}') 21 | 22 | 23 | @app.template_filter() 24 | @evalcontextfilter 25 | def nl2br(eval_ctx, value): 26 | result = u'\n\n'.join(u'

%s

' % p.replace('\n', '
\n') \ 27 | for p in _paragraph_re.split(escape(value))) 28 | if eval_ctx.autoescape: 29 | result = Markup(result) 30 | return result 31 | -------------------------------------------------------------------------------- /templatetricks/number_format.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | templatetricks.number_format 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | number_format filter 7 | http://flask.pocoo.org/snippets/29/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from app import app 15 | 16 | 17 | @app.template_filter() 18 | def number_format(value, tsep=',', dsep='.'): 19 | s = unicode(value) 20 | cnt = 0 21 | numchars = dsep + '0123456789' 22 | ls = len(s) 23 | while cnt < ls and s[cnt] not in numchars: 24 | cnt += 1 25 | 26 | lhs = s[:cnt] 27 | s = s[cnt:] 28 | if not dsep: 29 | cnt = -1 30 | else: 31 | cnt = s.rfind(dsep) 32 | if cnt > 0: 33 | rhs = dsep + s[cnt+1:] 34 | s = s[:cnt] 35 | else: 36 | rhs = '' 37 | 38 | splt = '' 39 | while s != '': 40 | splt = s[-3:] + tsep + splt 41 | s = s[:-3] 42 | 43 | return lhs + splt[:-1] + rhs 44 | -------------------------------------------------------------------------------- /templatetricks/override_autoescaped.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | templatetricks.override_autoescaped 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Override which templates are autoescaped 7 | http://flask.pocoo.org/snippets/41/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from flask import Flask 15 | 16 | class JHtmlEscapingFlask(Flask): 17 | 18 | def select_jinja_autoescape(self, filename): 19 | if filename.endswith('.jhtml'): 20 | return True 21 | return Flask.select_jinja_autoescape(self, filename) 22 | 23 | app = JHtmlEscapingFlask(__name__) 24 | -------------------------------------------------------------------------------- /templatetricks/timesince_filter.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | templatetricks.timesince_filter 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | timesince filter 7 | http://flask.pocoo.org/snippets/33/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | from datetime import datetime 14 | 15 | from app import app 16 | 17 | 18 | @app.template_filter() 19 | def timesince(dt, default="just now"): 20 | """ 21 | Returns string representing "time since" e.g. 22 | 3 days ago, 5 hours ago etc. 23 | """ 24 | 25 | now = datetime.utcnow() 26 | diff = now - dt 27 | 28 | periods = ( 29 | (diff.days / 365, "year", "years"), 30 | (diff.days / 30, "month", "months"), 31 | (diff.days / 7, "week", "weeks"), 32 | (diff.days, "day", "days"), 33 | (diff.seconds / 3600, "hour", "hours"), 34 | (diff.seconds / 60, "minute", "minutes"), 35 | (diff.seconds, "second", "seconds"), 36 | ) 37 | 38 | for period, singular, plural in periods: 39 | 40 | if period: 41 | return "%d %s ago" % (period, singular if period == 1 else plural) 42 | 43 | return default 44 | -------------------------------------------------------------------------------- /templatetricks/use_genshi.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | templatetricks.use_genshi 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Using Genshi with Flask 7 | http://flask.pocoo.org/snippets/17/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from flask import Flask 15 | from flaskext.genshi import Genshi, render_response 16 | 17 | app = Flask(__name__) 18 | genshi = Genshi(app) 19 | 20 | @app.route('/') 21 | def index(): 22 | render_response('index.html') 23 | -------------------------------------------------------------------------------- /templatetricks/use_markdown.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | templatetricks.use_markdown 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Using the markdown language 7 | http://flask.pocoo.org/snippets/19/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from flask import render_template_string, Markup 15 | import markdown 16 | 17 | from app import app 18 | 19 | 20 | html_content = """ 21 | 22 | 23 | Markdown Snippet 24 | 25 | 26 | {{ content }} 27 | 28 | 29 | """ 30 | 31 | 32 | @app.route('/') 33 | def index(): 34 | content = """ 35 | Chapter 36 | ======= 37 | 38 | Section 39 | ------- 40 | 41 | * Item 1 42 | * Item 2 43 | """ 44 | content = Markup(markdown.markdown(content)) 45 | return render_template_string(html_content, **locals()) 46 | 47 | 48 | if __name__ == "__main__": 49 | app.run() 50 | -------------------------------------------------------------------------------- /urls/catch_all.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | urls.catch_all 4 | ~~~~~~~~~~~~~~ 5 | 6 | Catch-All URL 7 | http://flask.pocoo.org/snippets/57/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from app import app 15 | 16 | 17 | @app.route('/', defaults={'path': ''}) 18 | @app.route('/') 19 | def catch_all(path): 20 | return 'You want path: %s' % path 21 | 22 | 23 | if __name__ == "__main__": 24 | app.run() 25 | """ 26 | % curl 127.0.0.1:5000 # Matches the first rule 27 | % curl 127.0.0.1:5000/foo/bar # Matches the second rule 28 | """ 29 | -------------------------------------------------------------------------------- /urls/generate_sitemap.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | urls.generate_map 4 | ~~~~~~~~~~~~~~~~~ 5 | 6 | Generating a sitemap.xml 7 | http://flask.pocoo.org/snippets/108/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from flask import request, Response 15 | 16 | from app import app 17 | 18 | 19 | 20 | @sk-sqlalchemy model for User 21 | class User(db.Model, UserMixin): 22 | 23 | __tablename__ = 'users' 24 | 25 | id = Column(db.Integer, primary_key=True) 26 | name = Column(db.String(32), nullable=False, unique=True) 27 | email = Column(db.String, nullable=False, unique=True) 28 | activation_key = Column(db.String) 29 | created_time = Column(db.DateTime, default=get_current_time) 30 | modified_time = Column(db.TIMESTAMP, onupdate=get_current_time(), default=get_current_time()) 31 | 32 | 33 | # a route for generating sitemap.xml 34 | @frontend.route('/sitemap.xml', methods=['GET']) 35 | def sitemap(): 36 | """Generate sitemap.xml. Makes a list of urls and date modified.""" 37 | pages=[] 38 | ten_days_ago=datetime.now() - timedelta(days=10).date().isoformat() 39 | # static pages 40 | for rule in current_app.url_map.iter_rules(): 41 | if "GET" in rule.methods and len(rule.arguments)==0: 42 | pages.append( 43 | [rule.rule,ten_days_ago] 44 | ) 45 | 46 | # user model pages 47 | users=User.query.order_by(User.modified_time).all() 48 | for user in users: 49 | url=url_for('user.pub',name=user.name) 50 | modified_time=user.modified_time.date().isoformat() 51 | pages.append([url,modified_time]) 52 | 53 | sitemap_xml = render_template('frontend/sitemap_template.xml', pages=pages) 54 | response= make_response(sitemap_xml) 55 | response.headers["Content-Type"] = "application/xml" 56 | 57 | return responseapp.route('/') 58 | 59 | 60 | """ 61 | 62 | 63 | {% for page in pages %} 64 | 65 | {{page[0]|safe}} 66 | {{page[1]}} 67 | 68 | {% endfor %} 69 | 70 | """ 71 | 72 | 73 | def index(): 74 | return 'index' 75 | 76 | 77 | if __name__ == "__main__": 78 | app.run() 79 | -------------------------------------------------------------------------------- /urls/generate_slug.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | urls.generate_slug 4 | ~~~~~~~~~~~~~~~~~~ 5 | 6 | Generating Slugs 7 | http://flask.pocoo.org/snippets/5/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | import re 14 | from unicodedata import normalize 15 | 16 | from flask import request, Response 17 | #from unidecode import unidecode 18 | 19 | from app import app 20 | 21 | 22 | _punct_re = re.compile(r'[\t !"#$%&\'()*\-/<=>?@\[\\\]^_`{|},.]+') 23 | 24 | 25 | def slugify(text, delim=u'-'): 26 | """Generates an ASCII-only slug.""" 27 | result = [] 28 | for word in _punct_re.split(text.lower()): 29 | word = word.encode('translit/long') 30 | if word: 31 | result.append(word) 32 | return unicode(delim.join(result)) 33 | 34 | 35 | def slugify2(text, delim=u'-'): 36 | """Generates an slightly worse ASCII-only slug.""" 37 | result = [] 38 | for word in _punct_re.split(text.lower()): 39 | word = normalize('NFKD', word).encode('ascii', 'ignore') 40 | if word: 41 | result.append(word) 42 | return unicode(delim.join(result)) 43 | 44 | 45 | def slugify3(text, delim=u'-'): 46 | """Generates an ASCII-only slug.""" 47 | result = [] 48 | for word in _punct_re.split(text.lower()): 49 | result.extend(unidecode(word).split()) 50 | return unicode(delim.join(result)) 51 | 52 | 53 | @app.route('/') 54 | def index(): 55 | return 'index' 56 | 57 | 58 | if __name__ == "__main__": 59 | # print slugify('Hello World') 60 | # print slugify('ü') 61 | print slugify2(u'Hello World') 62 | print slugify2(u'ü') 63 | app.run() 64 | -------------------------------------------------------------------------------- /urls/list_routes.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | urls.routes 4 | ~~~~~~~~~~~ 5 | 6 | Helper to list routes (like Rail's rake routes) 7 | http://flask.pocoo.org/snippets/117/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from flask import request, Response, url_for 15 | 16 | from app import app 17 | 18 | 19 | @app.route('/') 20 | def index(): 21 | return 'index' 22 | 23 | 24 | @app.route('/test//', methods=['GET', 'POST']) 25 | def test(en): 26 | return en 27 | 28 | 29 | def list_routes(): 30 | import urllib 31 | output = [] 32 | for rule in app.url_map.iter_rules(): 33 | options = {} 34 | for arg in rule.arguments: 35 | options[arg] = "[{0}]".format(arg) 36 | 37 | methods = ','.join(rule.methods) 38 | url = url_for(rule.endpoint, **options) 39 | # url = rule.rule 40 | line = urllib.unquote("{:50s} {:20s} {}".format( 41 | rule.endpoint, methods, url)) 42 | output.append(line) 43 | 44 | for line in sorted(output): 45 | print line 46 | 47 | 48 | if __name__ == "__main__": 49 | ctx = app.test_request_context() 50 | ctx.push() 51 | list_routes() 52 | -------------------------------------------------------------------------------- /urls/permalink.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | urls.permalink 4 | ~~~~~~~~~~~~~~ 5 | 6 | Permalink function decorator 7 | http://flask.pocoo.org/snippets/6/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from flask import url_for 15 | from werkzeug.routing import BuildError 16 | 17 | from app import app 18 | 19 | 20 | def permalink(function): 21 | def inner(*args, **kwargs): 22 | endpoint, values = function(*args, **kwargs) 23 | try: 24 | return url_for(endpoint, **values) 25 | except BuildError: 26 | return 27 | return inner 28 | 29 | 30 | @permalink 31 | def absolute_url(): 32 | return 'profiles', {'username': 'fsp'} 33 | 34 | 35 | @app.route('/profiles//') 36 | def profiles(username): 37 | return username 38 | 39 | 40 | if __name__ == "__main__": 41 | ctx = app.test_request_context() 42 | ctx.push() 43 | print absolute_url() 44 | -------------------------------------------------------------------------------- /urls/static_cache_buster.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | urls.static_cache_buster 4 | ~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | static url cache buster 7 | http://flask.pocoo.org/snippets/40/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from flask import request, Response, url_for 15 | 16 | from app import app 17 | 18 | 19 | """ 20 | 22 | """ 23 | 24 | 25 | @app.context_processor 26 | def override_url_for(): 27 | return dict(url_for=dated_url_for) 28 | 29 | 30 | def dated_url_for(endpoint, **values): 31 | if endpoint == 'static': 32 | filename = values.get('filename', None) 33 | if filename: 34 | file_path = os.path.join(app.root_path, endpoint, filename) 35 | values['q'] = int(os.stat(file_path).st_mtime) 36 | return url_for(endpoint, **values) 37 | 38 | 39 | @app.route('/') 40 | def index(): 41 | return dated_url_for('static', filename='fsp.jpg') 42 | 43 | 44 | if __name__ == "__main__": 45 | app.run() 46 | -------------------------------------------------------------------------------- /urls/support_semicolon.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | urls.support_semicolon 4 | ~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Supporting “;” as Delimiter in Legacy Query Strings 7 | http://flask.pocoo.org/snippets/43/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | from functools import wraps 14 | 15 | from flask import request, Response 16 | 17 | from app import app 18 | 19 | 20 | class QueryStringRedirectMiddle(object): 21 | 22 | def __init__(self, application): 23 | self.application = application 24 | 25 | def __call__(self, environ, start_response): 26 | qs = environ.get('QUERY_STRING', '') 27 | environ['QUERY_STRING'] = qs.replace(';', '&') 28 | return self.application(environ, start_response) 29 | 30 | 31 | @app.route('/') 32 | def index(): 33 | print request.args 34 | return 'index' 35 | 36 | 37 | if __name__ == "__main__": 38 | app.wsgi_app = QueryStringRedirectMiddle(app.wsgi_app) 39 | app.run() 40 | -------------------------------------------------------------------------------- /urls/url_contain_slash.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | urls.url_contain_slash 4 | ~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Handling URLs containing slash '/' character 7 | http://flask.pocoo.org/snippets/76/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from flask import request, Response 15 | 16 | from app import app 17 | 18 | 19 | @app.route('//fsp') 20 | def index(test): 21 | return test 22 | 23 | 24 | @app.route('/product/') 25 | def product(code): 26 | return code 27 | 28 | 29 | if __name__ == "__main__": 30 | app.run() 31 | -------------------------------------------------------------------------------- /urls/url_payload.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | urls.url_payload 4 | ~~~~~~~~~~~~~~~~ 5 | 6 | URLs with Payload 7 | http://flask.pocoo.org/snippets/50/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from flask import request, Response 15 | from flask import abort, redirect, flash, url_for 16 | from itsdangerous import URLSafeSerializer, BadSignature 17 | 18 | from app import app 19 | 20 | 21 | def get_serializer(secret_key=None): 22 | if secret_key is None: 23 | secret_key = app.secret_key 24 | return URLSafeSerializer(secret_key) 25 | 26 | 27 | def get_activation_link(user): 28 | s = get_serializer() 29 | payload = s.dumps(user.id) 30 | return url_for('activate_user', payload=payload, _external=True) 31 | 32 | 33 | @app.route('/users/activate/') 34 | def activate_user(payload): 35 | s = get_serializer() 36 | try: 37 | user_id = s.loads(payload) 38 | except BadSignature: 39 | abort(404) 40 | 41 | # user = User.query.get_or_404(user_id) 42 | # user.activate() 43 | flash('User activated') 44 | return redirect(url_for('index')) 45 | 46 | 47 | @app.route('/') 48 | def index(): 49 | return 'index' 50 | 51 | 52 | @app.route('/voucher/redeem/') 53 | def redeem_voucher(payload): 54 | s = get_serializer() 55 | try: 56 | user_id, voucher_id = s.loads(payload) 57 | except BadSignature: 58 | abort(404) 59 | 60 | user = User.query.get_or_404(user_id) 61 | voucher = Voucher.query.get_or_404(voucher_id) 62 | voucher.redeem_for(user) 63 | flash('Voucher redeemed') 64 | return redirect(url_for('index')) 65 | 66 | def get_redeem_link(user, voucher): 67 | s = get_serializer() 68 | payload = s.dumps([user.id, voucher.id]) 69 | return url_for('redeem_voucher', payload=payload, 70 | _external=True) 71 | 72 | 73 | if __name__ == "__main__": 74 | ctx = app.test_request_context() 75 | ctx.push() 76 | class User(object): 77 | id = 10000 78 | user = User() 79 | print get_activation_link(user) 80 | -------------------------------------------------------------------------------- /utilities/after_request_per.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | utilities.after_request_per 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Per-Request After-Request Callbacks 7 | http://flask.pocoo.org/snippets/53/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from flask import g 15 | 16 | from app import app 17 | 18 | 19 | def after_this_request(func): 20 | if not hasattr(g, 'call_after_request'): 21 | g.call_after_request = [] 22 | g.call_after_request.append(func) 23 | return func 24 | 25 | 26 | @app.after_request 27 | def per_request_callbacks(response): 28 | for func in getattr(g, 'call_after_request', ()): 29 | response = func(response) 30 | return response 31 | 32 | 33 | def invalidate_username_cache(): 34 | @after_this_request 35 | def delete_username_cookie(response): 36 | response.delete_cookie('username') 37 | return response 38 | -------------------------------------------------------------------------------- /utilities/cms_pages.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | utilities.cms_pages 4 | ~~~~~~~~~~~~~~~~~~~ 5 | 6 | CMS Pages 7 | http://flask.pocoo.org/snippets/114/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from flask import render_template_string 15 | 16 | from app import app 17 | 18 | 19 | class Page(Base): 20 | __tablename__='pages' 21 | id Column(Integer, primary_key=True) 22 | name = Column(String()) 23 | page_snippets = relationship('PageSnippets', backref='pages', lazy='dynamic') 24 | 25 | 26 | class PageSnippets('base') 27 | __tablename__='page_snippets' 28 | id Column(Integer, primary_key=True) 29 | snippet = Column(String()) 30 | language = Column(String()) 31 | 32 | 33 | html_content = """ 34 |

{{page_snippets.intro}} 35 |

38 | """ 39 | 40 | 41 | @app.route('/') 42 | def a_page(page_id): 43 | page = Page.query.filter_by(id=page_id).one() 44 | page_snippets = page.page_snippets 45 | return render_template_string(html_content, page_snippets=page_snippets) 46 | -------------------------------------------------------------------------------- /utilities/content_negotiated_error.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | utilities.context_global_socketio 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Using Context Globals with Gevent-Socketio 7 | http://flask.pocoo.org/snippets/105/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from socketio import socketio_manage 15 | @app.route('/socket.io/') 16 | def run_socketio(path): 17 | real_request = request._get_current_object() 18 | socketio_manage(request.environ, {'': FlaskNamespace}, 19 | request=real_request) 20 | return Response() 21 | 22 | from socketio.namespace import BaseNamespace 23 | class FlaskNamespace(BaseNamespace): 24 | def __init__(self, *args, **kwargs): 25 | request = kwargs.get('request', None) 26 | self.ctx = None 27 | if request: 28 | self.ctx = current_app.request_context(request.environ) 29 | self.ctx.push() 30 | current_app.preprocess_request() 31 | del kwargs['request'] 32 | super(BaseNamespace, self).__init__(*args, **kwargs) 33 | 34 | def disconnect(self, *args, **kwargs): 35 | if self.ctx: 36 | self.ctx.pop() 37 | super(BaseNamespace, self).disconnect(*args, **kwargs) 38 | -------------------------------------------------------------------------------- /utilities/context_global_socketio.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | utilities.cms_pages 4 | ~~~~~~~~~~~~~~~~~~~ 5 | 6 | CMS Pages 7 | http://flask.pocoo.org/snippets/114/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from flask import render_template_string 15 | 16 | from app import app 17 | 18 | 19 | class Page(Base): 20 | __tablename__='pages' 21 | id Column(Integer, primary_key=True) 22 | name = Column(String()) 23 | page_snippets = relationship('PageSnippets', backref='pages', lazy='dynamic') 24 | 25 | 26 | class PageSnippets('base') 27 | __tablename__='page_snippets' 28 | id Column(Integer, primary_key=True) 29 | snippet = Column(String()) 30 | language = Column(String()) 31 | 32 | 33 | html_content = """ 34 |

{{page_snippets.intro}} 35 |

38 | """ 39 | 40 | 41 | @app.route('/') 42 | def a_page(page_id): 43 | page = Page.query.filter_by(id=page_id).one() 44 | page_snippets = page.page_snippets 45 | return render_template_string(html_content, page_snippets=page_snippets) 46 | -------------------------------------------------------------------------------- /utilities/custom_http_method.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | utilities.custom_http_method 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Custom HTTP methods 7 | http://flask.pocoo.org/snippets/1/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from flask import render_template_string 15 | 16 | from app import app 17 | 18 | 19 | @app.before_request 20 | def before_request(): 21 | method = request.form.get('_method', '').upper() 22 | if method: 23 | request.environ['REQUEST_METHOD'] = method 24 | ctx = flask._request_ctx_stack.top 25 | ctx.url_adapter.default_method = method 26 | assert request.method == method 27 | 28 | 29 | @app.route('/entries/', methods=['DELETE']) 30 | def delete_entry(id): 31 | pass 32 | 33 | """ 34 |
35 | 36 | 37 |
38 | """ 39 | -------------------------------------------------------------------------------- /utilities/flask_mail.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | utilities.flask_mail 4 | ~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Flask-Mail with google apps 7 | http://flask.pocoo.org/snippets/85/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from flask import Flask 15 | from flaskext.mail import Mail, Message 16 | 17 | app =Flask(__name__) 18 | mail=Mail(app) 19 | 20 | app.config.update( 21 | DEBUG=True, 22 | #EMAIL SETTINGS 23 | MAIL_SERVER='smtp.gmail.com', 24 | MAIL_PORT=465, 25 | MAIL_USE_SSL=True, 26 | MAIL_USERNAME = 'you@google.com', 27 | MAIL_PASSWORD = 'GooglePasswordHere' 28 | ) 29 | 30 | mail=Mail(app) 31 | 32 | @app.route("/") 33 | def index(): 34 | msg = Message( 35 | 'Hello', 36 | sender='you@dgoogle.com', 37 | recipients= 38 | ['recipient@recipient_domain.com']) 39 | msg.body = "This is the email body" 40 | mail.send(msg) 41 | return "Sent" 42 | 43 | if __name__ == "__main__": 44 | app.run() 45 | -------------------------------------------------------------------------------- /utilities/flask_testcase.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | utilities.flask_testcase 4 | ~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Flask TestCase 7 | http://flask.pocoo.org/snippets/26/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | import unittest 14 | 15 | from flask import render_template_string 16 | 17 | from app import app 18 | 19 | 20 | class TestCase(unittest.TestCase): 21 | 22 | def create_app(self): 23 | """ 24 | Create your Flask app here, with any 25 | configuration you need 26 | """ 27 | raise NotImplementedError 28 | 29 | def __call__(self, result=None): 30 | """ 31 | Does the required setup, doing it here 32 | means you don't have to call super.setUp 33 | in subclasses. 34 | """ 35 | self._pre_setup() 36 | super(TestCase, self).__call__(result) 37 | self._post_tearDown() 38 | 39 | def _pre_setup(self): 40 | self.app = self.create_app() 41 | self.client = self.app.test_client() 42 | 43 | # now you can use flask thread locals 44 | 45 | self._ctx = self.app.test_request_context() 46 | self._ctx.push() 47 | 48 | def _post_tearDown(self): 49 | self._ctx.pop() 50 | 51 | def assert404(self, response): 52 | """ 53 | Checks if a HTTP 404 returned 54 | e.g. 55 | resp = self.client.get("/") 56 | self.assert404(resp) 57 | """ 58 | self.assertTrue(response.status_code == 404) 59 | -------------------------------------------------------------------------------- /utilities/import_css_string.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | utilities.import_css_string 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Include / Import css file as string 7 | http://flask.pocoo.org/snippets/77/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from flask import render_template_string 15 | 16 | from app import app 17 | 18 | 19 | def get_resource_as_string(name, charset='utf-8'): 20 | with app.open_resource(name) as f: 21 | return f.read().decode(charset) 22 | 23 | app.jinja_env.globals['get_resource_as_string'] = get_resource_as_string 24 | 25 | 26 | """ 27 | 28 | """ 29 | -------------------------------------------------------------------------------- /utilities/interactive_shell.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | utilities.interactive_shell 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Preconfigured interactive shell 7 | http://flask.pocoo.org/snippets/23/ 8 | """ 9 | 10 | import os 11 | import readline 12 | from pprint import pprint 13 | 14 | from flask import * 15 | 16 | from myapp import * 17 | from utils import * 18 | from db import * 19 | from models import * 20 | 21 | 22 | os.environ['PYTHONINSPECT'] = 'True' 23 | -------------------------------------------------------------------------------- /utilities/json_encoder.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | utilities.json_encoder 4 | ~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Custom Flask JSONEncoder 7 | http://flask.pocoo.org/snippets/119/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | from datetime import datetime 14 | import calendar 15 | 16 | from flask import jsonify 17 | from flask.json import JSONEncoder 18 | 19 | from app import app 20 | 21 | 22 | class CustomJSONEncoder(JSONEncoder): 23 | 24 | def default(self, obj): 25 | try: 26 | if isinstance(obj, datetime): 27 | if obj.utcoffset() is not None: 28 | obj = obj - obj.utcoffset() 29 | millis = int( 30 | calendar.timegm(obj.timetuple()) * 1000 + 31 | obj.microsecond / 1000 32 | ) 33 | return millis 34 | iterable = iter(obj) 35 | except TypeError: 36 | pass 37 | else: 38 | return list(iterable) 39 | return JSONEncoder.default(self, obj) 40 | 41 | 42 | app.json_encoder = CustomJSONEncoder 43 | 44 | 45 | @app.route('/custom') 46 | def custom_jsonencoder(): 47 | now = datetime.now() 48 | return jsonify({'now': now}) 49 | 50 | 51 | if __name__ == '__main__': 52 | app.run() 53 | -------------------------------------------------------------------------------- /utilities/local_proxy.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | utilities.local_proxy 4 | ~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Creating your own local proxies 7 | http://flask.pocoo.org/snippets/13/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from werkzeug.local import LocalProxy 15 | 16 | from app import app 17 | 18 | 19 | whatever = LocalProxy(lambda: g.whatever) 20 | method = LocalProxy(lambda: request.method) 21 | -------------------------------------------------------------------------------- /utilities/nice_errors.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | utilities.nice_errors 4 | ~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Nicer Errors with Descriptions from Werkzeug 7 | http://flask.pocoo.org/snippets/15/ 8 | """ 9 | 10 | from flask import Markup, render_template 11 | from werkzeug.exceptions import default_exceptions 12 | 13 | def show_errormessage(error): 14 | desc = error.get_description(flask.request.environ) 15 | return render_template('error.html', 16 | code=error.code, 17 | name=error.name, 18 | description=Markup(desc) 19 | ), error.code 20 | 21 | for _exc in default_exceptions: 22 | app.error_handlers[_exc] = show_errormessage 23 | del _exc 24 | 25 | 26 | """ 27 | {% extends "base.html" %} 28 | {% block title %}Error {{ code }}: {{ name }}{% endblock %} 29 | {% block body %} 30 | {{ description}} 31 | {% endblock %} 32 | """ 33 | -------------------------------------------------------------------------------- /utilities/override_httpmethod.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | utilities.override_httpmethod 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Overriding HTTP Methods for old browsers 7 | http://flask.pocoo.org/snippets/38/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from werkzeug import url_decode 15 | 16 | class MethodRewriteMiddleware(object): 17 | 18 | def __init__(self, app): 19 | self.app = app 20 | 21 | def __call__(self, environ, start_response): 22 | if 'METHOD_OVERRIDE' in environ.get('QUERY_STRING', ''): 23 | args = url_decode(environ['QUERY_STRING']) 24 | method = args.get('__METHOD_OVERRIDE__') 25 | if method: 26 | method = method.encode('ascii', 'replace') 27 | environ['REQUEST_METHOD'] = method 28 | return self.app(environ, start_response) 29 | 30 | 31 | """ 32 |
33 | ... 34 |
35 | """ 36 | -------------------------------------------------------------------------------- /utilities/reloading.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | utilities.reloading 4 | ~~~~~~~~~~~~~~~~~~~ 5 | 6 | Reloading with other WSGI servers 7 | http://flask.pocoo.org/snippets/34/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | import gevent.wsgi 15 | import werkzeug.serving 16 | 17 | from app import app 18 | 19 | 20 | @werkzeug.serving.run_with_reloader 21 | def runServer(): 22 | ws = gevent.wsgi.WSGIServer(('', 5000), app) 23 | ws.serve_forever() 24 | 25 | 26 | if __name__ == "__main__": 27 | runServer() 28 | -------------------------------------------------------------------------------- /utilities/rq.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | utilities.rq 4 | ~~~~~~~~~~~~ 5 | 6 | Basic Message Queue with Redis 7 | http://flask.pocoo.org/snippets/73/ 8 | """ 9 | 10 | import os 11 | import sys 12 | from uuid import uuid4 13 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 14 | from pickle import loads, dumps 15 | 16 | from redis import Redis 17 | from flask import current_app 18 | from flask import session, abort, jsonify 19 | 20 | from app import app 21 | 22 | 23 | # Connecting to Redis 24 | redis = Redis() 25 | 26 | 27 | # The Configuration 28 | app.config['REDIS_QUEUE_KEY'] = 'my_queue' 29 | 30 | 31 | class DelayedResult(object): 32 | def __init__(self, key): 33 | self.key = key 34 | self._rv = None 35 | 36 | @property 37 | def return_value(self): 38 | if self._rv is None: 39 | rv = redis.get(self.key) 40 | if rv is not None: 41 | self._rv = loads(rv) 42 | return self._rv 43 | 44 | 45 | def queuefunc(f): 46 | def delay(*args, **kwargs): 47 | qkey = current_app.config['REDIS_QUEUE_KEY'] 48 | key = '%s:result:%s' % (qkey, str(uuid4())) 49 | s = dumps((f, key, args, kwargs)) 50 | redis.rpush(current_app.config['REDIS_QUEUE_KEY'], s) 51 | return DelayedResult(key) 52 | f.delay = delay 53 | return f 54 | 55 | 56 | def queue_daemon(app, rv_ttl=500): 57 | while 1: 58 | msg = redis.blpop(app.config['REDIS_QUEUE_KEY']) 59 | func, key, args, kwargs = loads(msg[1]) 60 | try: 61 | rv = func(*args, **kwargs) 62 | except Exception, e: 63 | rv = e 64 | if rv is not None: 65 | redis.set(key, dumps(rv)) 66 | redis.expire(key, rv_ttl) 67 | 68 | 69 | @queuefunc 70 | def add(a, b): 71 | return a + b 72 | 73 | 74 | @app.route('/add') 75 | def add_numbers(): 76 | a = request.args.get('a', type=int) 77 | b = request.args.get('b', type=int) 78 | if a is None or b is None: 79 | abort(400) 80 | rv = add.delay(a, b) 81 | session['add_result_key'] = rv.key 82 | return 'Waiting for result...' 83 | 84 | 85 | @app.route('/add-result') 86 | def add_numbers_result(): 87 | key = session.get('add_result_key') 88 | if key is None: 89 | return jsonify(ready=False) 90 | rv = DelayedResult(key) 91 | if rv.return_value is None: 92 | return jsonify(ready=False) 93 | redis.delete(key) 94 | del session['add_result_key'] 95 | return jsonify(ready=True, result=rv.return_value) 96 | 97 | 98 | if __name__ == "__main__": 99 | ctx = app.test_request_context() 100 | ctx.push() 101 | rv = add.delay(1, 2) 102 | import threading 103 | daemon = threading.Thread(target=queue_daemon, args=(app,)) 104 | daemon.setDaemon(True) 105 | daemon.start() 106 | while True: 107 | rt = rv.return_value 108 | if rt is None: 109 | continue 110 | else: 111 | print rt 112 | print rv.key 113 | break 114 | -------------------------------------------------------------------------------- /utilities/serve_transcompiling.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | utilities.serve_transcompiling 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Serve CoffeeScript, SCSS, or other transcompiling file via Python 7 | http://flask.pocoo.org/snippets/90/ 8 | """ 9 | 10 | from subprocess import Popen, PIPE 11 | import shlex 12 | 13 | class NonZeroExitError(Exception): 14 | def __init__(self, command, returncode, output, error): 15 | self.command = command 16 | self.returncode = returncode 17 | self.output = output 18 | self.error = error 19 | def __str__(self): 20 | return '''\ 21 | %s returned non-zero exit status %d with output 22 | %s 23 | and error 24 | %s''' % (self.command, self.returncode, 25 | self.output or "[NO OUTOUT]", 26 | self.error or "[NO ERROR]") 27 | 28 | def command_line_renderer_factory(command): 29 | '''command should be a command reads input from stdin 30 | and prints to stdout''' 31 | 32 | args = shlex.split(command) 33 | 34 | def renderer(script): 35 | '''Accepts a file object or path and return the 36 | rendered string''' 37 | 38 | if isinstance(script, file): 39 | pass 40 | elif isinstance(script, str): 41 | script = open(script) 42 | else: 43 | raise TypeError('script must be a file object of ' 44 | 'or a string to the file') 45 | process = Popen(args, stdin=script, 46 | stdout=PIPE, stderr=PIPE) 47 | 48 | returncode = process.wait() 49 | stdoutdata, stderrdata = process.communicate() 50 | 51 | if returncode != 0: 52 | raise NonZeroExitError(command, returncode, 53 | stdoutdata, stderrdata) 54 | 55 | return stdoutdata 56 | 57 | return renderer 58 | 59 | 60 | """ 61 | #!/usr/bin/env node 62 | 63 | var less = require('less'); 64 | 65 | process.stdin.resume(); 66 | process.stdin.setEncoding('utf8'); 67 | 68 | process.stdin.on('data', function (less_css) { 69 | less.render(less_css, function(e, css){ 70 | console.log(css) 71 | }); 72 | }); 73 | """ 74 | -------------------------------------------------------------------------------- /utilities/set_cookies.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | utilities.set_cookies 4 | ~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Flask Set Cookies by Response 7 | http://flask.pocoo.org/snippets/30/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from flask import redirect, current_app 15 | 16 | from app import app 17 | 18 | 19 | @app.route('/set_cookie') 20 | def cookie_insertion(): 21 | redirect_to_index = redirect('/index') 22 | response = current_app.make_response(redirect_to_index) 23 | response.set_cookie('cookie_name',value='values') 24 | return response 25 | -------------------------------------------------------------------------------- /utilities/share_server.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | utilities.share_server 4 | ~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Share your Local Server with a Friend 7 | http://flask.pocoo.org/snippets/89/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from flask import render_template_string 15 | 16 | from app import app 17 | 18 | 19 | """ 20 | $ sudo gem install localtunnel 21 | $ localtunnel 5000 22 | $ Port 5000 is now publicly accessible from http://54xy.localtunnel.com ... 23 | """ 24 | -------------------------------------------------------------------------------- /utilities/shutdown_server.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | utilities.shutdown_server 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Shutdown The Simple Server 7 | http://flask.pocoo.org/snippets/67/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from flask import request 15 | 16 | from app import app 17 | 18 | 19 | def shutdown_server(): 20 | func = request.environ.get('werkzeug.server.shutdown') 21 | if func is None: 22 | raise RuntimeError('Not running with the Werkzeug Server') 23 | func() 24 | 25 | 26 | @app.route('/shutdown', methods=['GET', 'POST']) 27 | def shutdown(): 28 | shutdown_server() 29 | return 'Server shutting down...' 30 | 31 | 32 | if __name__ == "__main__": 33 | app.run() 34 | -------------------------------------------------------------------------------- /utilities/sqlite_q.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | utilities.sqlite_q 4 | ~~~~~~~~~~~~~~~~~~ 5 | 6 | Job queue implemented using SQLite 7 | http://flask.pocoo.org/snippets/88/ 8 | """ 9 | 10 | import os, sqlite3 11 | from cPickle import loads, dumps 12 | from time import sleep 13 | try: 14 | from thread import get_ident 15 | except ImportError: 16 | from dummy_thread import get_ident 17 | 18 | 19 | class SqliteQueue(object): 20 | 21 | _create = ( 22 | 'CREATE TABLE IF NOT EXISTS queue ' 23 | '(' 24 | ' id INTEGER PRIMARY KEY AUTOINCREMENT,' 25 | ' item BLOB' 26 | ')' 27 | ) 28 | _count = 'SELECT COUNT(*) FROM queue' 29 | _iterate = 'SELECT id, item FROM queue' 30 | _append = 'INSERT INTO queue (item) VALUES (?)' 31 | _write_lock = 'BEGIN IMMEDIATE' 32 | _popleft_get = ( 33 | 'SELECT id, item FROM queue ' 34 | 'ORDER BY id LIMIT 1' 35 | ) 36 | _popleft_del = 'DELETE FROM queue WHERE id = ?' 37 | _peek = ( 38 | 'SELECT item FROM queue ' 39 | 'ORDER BY id LIMIT 1' 40 | ) 41 | 42 | def __init__(self, path): 43 | self.path = os.path.abspath(path) 44 | self._connection_cache = {} 45 | with self._get_conn() as conn: 46 | conn.execute(self._create) 47 | 48 | def __len__(self): 49 | with self._get_conn() as conn: 50 | l = conn.execute(self._count).next()[0] 51 | return l 52 | 53 | def __iter__(self): 54 | with self._get_conn() as conn: 55 | for id, obj_buffer in conn.execute(self._iterate): 56 | yield loads(str(obj_buffer)) 57 | 58 | def _get_conn(self): 59 | id = get_ident() 60 | if id not in self._connection_cache: 61 | self._connection_cache[id] = sqlite3.Connection(self.path, 62 | timeout=60) 63 | return self._connection_cache[id] 64 | 65 | def append(self, obj): 66 | obj_buffer = buffer(dumps(obj, 2)) 67 | with self._get_conn() as conn: 68 | conn.execute(self._append, (obj_buffer,)) 69 | 70 | def popleft(self, sleep_wait=True): 71 | keep_pooling = True 72 | wait = 0.1 73 | max_wait = 2 74 | tries = 0 75 | with self._get_conn() as conn: 76 | id = None 77 | while keep_pooling: 78 | conn.execute(self._write_lock) 79 | cursor = conn.execute(self._popleft_get) 80 | try: 81 | id, obj_buffer = cursor.next() 82 | keep_pooling = False 83 | except StopIteration: 84 | conn.commit() # unlock the database 85 | if not sleep_wait: 86 | keep_pooling = False 87 | continue 88 | tries += 1 89 | sleep(wait) 90 | wait = min(max_wait, tries/10 + wait) 91 | if id: 92 | conn.execute(self._popleft_del, (id,)) 93 | return loads(str(obj_buffer)) 94 | return None 95 | 96 | def peek(self): 97 | with self._get_conn() as conn: 98 | cursor = conn.execute(self._peek) 99 | try: 100 | return loads(str(cursor.next()[0])) 101 | except StopIteration: 102 | return None 103 | -------------------------------------------------------------------------------- /utilities/stream_proxy.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | utilities.stream_proxy 4 | ~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Stream Proxy with Requests 7 | http://flask.pocoo.org/snippets/118/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from flask import Response, stream_with_context 15 | import requests 16 | 17 | from app import app 18 | 19 | 20 | @app.route('/') 21 | def home(url): 22 | req = requests.get(url, stream=True) 23 | return Response(stream_with_context(req.iter_content()), content_type = req.headers['content-type']) 24 | 25 | 26 | if __name__ == '__main__': 27 | app.run() 28 | -------------------------------------------------------------------------------- /utilities/trigger_debuggr.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | utilities.trigger_debugger 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Triggering the debugger on purpose 7 | http://flask.pocoo.org/snippets/21/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from flask import render_template_string 15 | 16 | from app import app 17 | 18 | 19 | @app.route('/') 20 | def index(): 21 | do_something_wrong() 22 | raise 23 | return 'Ohnoes' 24 | 25 | 26 | """ 27 | assert app.debug == False 28 | """ 29 | -------------------------------------------------------------------------------- /utilities/turbomail.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | utilities.turbomail 4 | ~~~~~~~~~~~~~~~~~~~ 5 | 6 | Using TurboMail with Flask 7 | http://flask.pocoo.org/snippets/16/ 8 | """ 9 | 10 | import atexit 11 | 12 | from turbomail.control import interface 13 | from turbomail.message import Message 14 | 15 | from flask import Flask 16 | 17 | # pass in dict of config options 18 | 19 | interface.start({'mail.on' : True}) 20 | 21 | # ensures interface cleanly shutdown when process exits 22 | 23 | atexit.register(interface.stop, force=True) 24 | 25 | app = Flask(__name__) 26 | 27 | @app.route("/") 28 | def index(): 29 | # send an email 30 | msg = Message("from@example.com", 31 | "to@example.com", 32 | "a subject") 33 | msg.plain = "body of message" 34 | msg.send() 35 | -------------------------------------------------------------------------------- /utilities/upload_stringio.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | utilities.upload_stringio 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Upload a StringIO object with send_file 7 | http://flask.pocoo.org/snippets/32/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | import StringIO 14 | 15 | from flask import send_fileg 16 | 17 | from app import app 18 | 19 | 20 | @app.route('/') 21 | def index(): 22 | strIO = StringIO.StringIO() 23 | strIO.write('Hello from Dan Jacob and Stephane Wirtel !') 24 | strIO.seek(0) 25 | return send_file(strIO, 26 | attachment_filename="testing.txt", 27 | as_attachment=True) 28 | 29 | 30 | if __name__ == "__main__": 31 | app.run() 32 | -------------------------------------------------------------------------------- /utilities/wtform_flash_error.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | utilities.wtform_flash_error 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Flashing errors from WTForms forms 7 | http://flask.pocoo.org/snippets/12/ 8 | """ 9 | 10 | import os 11 | import sys 12 | sys.path.insert(0, os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) 13 | 14 | from flask import render_template_string 15 | 16 | from app import app 17 | 18 | 19 | def flash_errors(form): 20 | for field, errors in form.errors.items(): 21 | for error in errors: 22 | flash(u"Error in the %s field - %s" % ( 23 | getattr(form, field).label.text, 24 | error 25 | )) 26 | --------------------------------------------------------------------------------