commit 25ba6855169cbbe34bf78449c34c36672d19532e Author: Sagi Dayan Date: Sat May 9 22:00:14 2015 +0300 First Commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9f11b75 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.idea/ diff --git a/GithubAPI/GithubAPI.py b/GithubAPI/GithubAPI.py new file mode 100644 index 0000000..ffac4bf --- /dev/null +++ b/GithubAPI/GithubAPI.py @@ -0,0 +1,23 @@ +__author__ = 'sagi' +from google.appengine.ext import db + +class GitHubAPI_Keys(): + + def __init__(self): + self.__clientID = None + self.__clientSecret = None + q = KEYS.all() + for k in q.run(limit=5): + self.__clientID = k.client_id + self.__clientSecret = k.client_secret + break + + def getId(self): + return self.__clientID + + def getSecret(self): + return self.__clientSecret + +class KEYS(db.Model): + client_id = db.StringProperty() + client_secret = db.StringProperty() diff --git a/GithubAPI/GithubAPI.pyc b/GithubAPI/GithubAPI.pyc new file mode 100644 index 0000000..fdf773a Binary files /dev/null and b/GithubAPI/GithubAPI.pyc differ diff --git a/GithubAPI/__init__.py b/GithubAPI/__init__.py new file mode 100644 index 0000000..066a6b3 --- /dev/null +++ b/GithubAPI/__init__.py @@ -0,0 +1 @@ +__author__ = 'sagi' diff --git a/GithubAPI/__init__.pyc b/GithubAPI/__init__.pyc new file mode 100644 index 0000000..9851c63 Binary files /dev/null and b/GithubAPI/__init__.pyc differ diff --git a/README.md b/README.md new file mode 100644 index 0000000..5ea0b44 --- /dev/null +++ b/README.md @@ -0,0 +1,69 @@ +![SE-Hub][Logo] +---- + +[![Gitter][gitterBadge]][gitterChatRoomLink] + +Table of Contents +================= + - [Introduction](#introduction) + - [Website](#website) + - [Documentation](#documentation) + - [License](#license) + - [The MIT License](#the-mit-license-mit) + + +# Introduction + + Our vision in creating SE Hub wasn't to re-invent the wheel, but rather unify all the resources needed to solve these problems under one roof - SE Hub. Bringing to the table features like: +- Lecturer exercise tracking of individual tasks. +- Personal team messages. +- Communications made easy and accessible for both lecturers and students. +- Lecturer and teacher grading, follow up scores and etc. +- Peer assessment and activity on git-hub. +- Scheduling and event logs. + +# Website + + - [SE Hub](http://se-hub.appspot.com/) on GAE + +# Documentation + +[PowerPoint Presentation (Hebrew)](https://drive.google.com/file/d/0BwBOu8RSEI0fLVE4UFRTWERqVjQ/view?usp=sharing) | +[SOW Document (Hebrew)](https://drive.google.com/file/d/0BwBOu8RSEI0fTkxtZE43b3E1SEk/view?usp=sharing) + + +the first thing you should do for you to understand how our platform works is to visit our [wiki][wikiLink]. +there you will find the user manual (both for Students and Lecturers). and for the Developers how wants ti chip in and code, all the technical details. + +# License + +SE-Hub project is part of Software Engineering course at JCE (2015) +The Project is under the [MIT](http://opensource.org/licenses/MIT) License. + +## The MIT License (MIT) + +Copyright (c) 2015 SE-Hub + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +[wikiLink]: https://github.com/sagidayan/SE-Hub/wiki +[Logo]: https://cloud.githubusercontent.com/assets/2984053/6825467/7c9d0402-d303-11e4-9827-62a6d66f937a.png +[gitterBadge]: https://badges.gitter.im/Join%20Chat.svg +[gitterChatRoomLink]: https://gitter.im/sagidayan/SE-Hub \ No newline at end of file diff --git a/User/User.py b/User/User.py new file mode 100644 index 0000000..8d04163 --- /dev/null +++ b/User/User.py @@ -0,0 +1,4 @@ +from google.appengine.ext import db + + + diff --git a/User/__init__.py b/User/__init__.py new file mode 100644 index 0000000..066a6b3 --- /dev/null +++ b/User/__init__.py @@ -0,0 +1 @@ +__author__ = 'sagi' diff --git a/User/__init__.pyc b/User/__init__.pyc new file mode 100644 index 0000000..9fcf14f Binary files /dev/null and b/User/__init__.pyc differ diff --git a/app.yaml b/app.yaml new file mode 100644 index 0000000..13531c2 --- /dev/null +++ b/app.yaml @@ -0,0 +1,38 @@ +# This file specifies your Python application's runtime configuration +# including URL routing, versions, static file uploads, etc. See +# https://developers.google.com/appengine/docs/python/config/appconfig +# for details. + +# TODO: Enter your application id below. If you have signed up +# using cloud.google.com/console use the "project id" for your application +# id. +application: se-hub +version: 1 +runtime: python27 +api_version: 1 +threadsafe: yes + +# Handlers define how to route requests to your application. +handlers: + +# App Engine serves and caches static files contained in the listed directories +# (and subdirectories). Uncomment and set the directory as needed. +#- url: /client +# static_dir: client + +# This handler tells app engine how to route requests to a WSGI application. +# The script value is in the format . +# where is a WSGI application object. +- url: .* # This regex directs all routes to main.app + script: main.app + +# Third party libraries that are included in the App Engine SDK must be listed +# here if you want to use them. See +# https://developers.google.com/appengine/docs/python/tools/libraries27 for +# a list of libraries included in the SDK. Third party libs that are *not* part +# of the App Engine SDK don't need to be listed here, instead add them to your +# project directory, either as a git submodule or as a plain subdirectory. +# TODO: List any other App Engine SDK libs you may need here. +libraries: +- name: ssl + version: latest diff --git a/appengine_config.py b/appengine_config.py new file mode 100644 index 0000000..50e59ee --- /dev/null +++ b/appengine_config.py @@ -0,0 +1,6 @@ +"""`appengine_config` gets loaded when starting a new application instance.""" +import sys +import os.path +# add `lib` subdirectory to `sys.path`, so our `main` module can load +# third-party libraries. +sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'lib')) diff --git a/appengine_config.pyc b/appengine_config.pyc new file mode 100644 index 0000000..d01aab4 Binary files /dev/null and b/appengine_config.pyc differ diff --git a/lib/Flask-0.10.1-py2.7.egg-info/PKG-INFO b/lib/Flask-0.10.1-py2.7.egg-info/PKG-INFO new file mode 100644 index 0000000..1ff4f1a --- /dev/null +++ b/lib/Flask-0.10.1-py2.7.egg-info/PKG-INFO @@ -0,0 +1,58 @@ +Metadata-Version: 1.1 +Name: Flask +Version: 0.10.1 +Summary: A microframework based on Werkzeug, Jinja2 and good intentions +Home-page: http://github.com/mitsuhiko/flask/ +Author: Armin Ronacher +Author-email: armin.ronacher@active-4.com +License: BSD +Description: + Flask + ----- + + Flask is a microframework for Python based on Werkzeug, Jinja 2 and good + intentions. And before you ask: It's BSD licensed! + + Flask is Fun + ```````````` + + .. code:: python + + from flask import Flask + app = Flask(__name__) + + @app.route("/") + def hello(): + return "Hello World!" + + if __name__ == "__main__": + app.run() + + And Easy to Setup + ````````````````` + + .. code:: bash + + $ pip install Flask + $ python hello.py + * Running on http://localhost:5000/ + + Links + ````` + + * `website `_ + * `documentation `_ + * `development version + `_ + + +Platform: any +Classifier: Development Status :: 4 - Beta +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Software Development :: Libraries :: Python Modules diff --git a/lib/Flask-0.10.1-py2.7.egg-info/SOURCES.txt b/lib/Flask-0.10.1-py2.7.egg-info/SOURCES.txt new file mode 100644 index 0000000..e326cfc --- /dev/null +++ b/lib/Flask-0.10.1-py2.7.egg-info/SOURCES.txt @@ -0,0 +1,238 @@ +AUTHORS +CHANGES +LICENSE +MANIFEST.in +Makefile +README +run-tests.py +setup.cfg +setup.py +Flask.egg-info/PKG-INFO +Flask.egg-info/SOURCES.txt +Flask.egg-info/dependency_links.txt +Flask.egg-info/not-zip-safe +Flask.egg-info/requires.txt +Flask.egg-info/top_level.txt +artwork/.DS_Store +artwork/LICENSE +artwork/logo-full.svg +docs/.gitignore +docs/Makefile +docs/advanced_foreword.rst +docs/api.rst +docs/appcontext.rst +docs/becomingbig.rst +docs/blueprints.rst +docs/changelog.rst +docs/conf.py +docs/config.rst +docs/contents.rst.inc +docs/design.rst +docs/errorhandling.rst +docs/extensiondev.rst +docs/extensions.rst +docs/flaskdocext.py +docs/flaskext.py +docs/flaskstyle.sty +docs/foreword.rst +docs/htmlfaq.rst +docs/index.rst +docs/installation.rst +docs/latexindex.rst +docs/license.rst +docs/logo.pdf +docs/make.bat +docs/python3.rst +docs/quickstart.rst +docs/reqcontext.rst +docs/security.rst +docs/shell.rst +docs/signals.rst +docs/styleguide.rst +docs/templating.rst +docs/testing.rst +docs/unicode.rst +docs/upgrading.rst +docs/views.rst +docs/_static/debugger.png +docs/_static/flask.png +docs/_static/flaskr.png +docs/_static/logo-full.png +docs/_static/no.png +docs/_static/touch-icon.png +docs/_static/yes.png +docs/_templates/sidebarintro.html +docs/_templates/sidebarlogo.html +docs/_themes/.git +docs/_themes/.gitignore +docs/_themes/LICENSE +docs/_themes/README +docs/_themes/flask_theme_support.py +docs/_themes/flask/layout.html +docs/_themes/flask/relations.html +docs/_themes/flask/theme.conf +docs/_themes/flask/static/flasky.css_t +docs/_themes/flask/static/small_flask.css +docs/_themes/flask_small/layout.html +docs/_themes/flask_small/theme.conf +docs/_themes/flask_small/static/flasky.css_t +docs/deploying/cgi.rst +docs/deploying/fastcgi.rst +docs/deploying/index.rst +docs/deploying/mod_wsgi.rst +docs/deploying/uwsgi.rst +docs/deploying/wsgi-standalone.rst +docs/patterns/apierrors.rst +docs/patterns/appdispatch.rst +docs/patterns/appfactories.rst +docs/patterns/caching.rst +docs/patterns/celery.rst +docs/patterns/deferredcallbacks.rst +docs/patterns/distribute.rst +docs/patterns/errorpages.rst +docs/patterns/fabric.rst +docs/patterns/favicon.rst +docs/patterns/fileuploads.rst +docs/patterns/flashing.rst +docs/patterns/index.rst +docs/patterns/jquery.rst +docs/patterns/lazyloading.rst +docs/patterns/methodoverrides.rst +docs/patterns/mongokit.rst +docs/patterns/packages.rst +docs/patterns/requestchecksum.rst +docs/patterns/sqlalchemy.rst +docs/patterns/sqlite3.rst +docs/patterns/streaming.rst +docs/patterns/templateinheritance.rst +docs/patterns/urlprocessors.rst +docs/patterns/viewdecorators.rst +docs/patterns/wtforms.rst +docs/tutorial/css.rst +docs/tutorial/dbcon.rst +docs/tutorial/dbinit.rst +docs/tutorial/folders.rst +docs/tutorial/index.rst +docs/tutorial/introduction.rst +docs/tutorial/schema.rst +docs/tutorial/setup.rst +docs/tutorial/templates.rst +docs/tutorial/testing.rst +docs/tutorial/views.rst +examples/.DS_Store +examples/blueprintexample/blueprintexample.py +examples/blueprintexample/blueprintexample_test.py +examples/blueprintexample/simple_page/__init__.py +examples/blueprintexample/simple_page/simple_page.py +examples/blueprintexample/simple_page/templates/pages/hello.html +examples/blueprintexample/simple_page/templates/pages/index.html +examples/blueprintexample/simple_page/templates/pages/layout.html +examples/blueprintexample/simple_page/templates/pages/world.html +examples/flaskr/README +examples/flaskr/flaskr.py +examples/flaskr/flaskr_tests.py +examples/flaskr/schema.sql +examples/flaskr/static/style.css +examples/flaskr/templates/layout.html +examples/flaskr/templates/login.html +examples/flaskr/templates/show_entries.html +examples/jqueryexample/jqueryexample.py +examples/jqueryexample/templates/index.html +examples/jqueryexample/templates/layout.html +examples/minitwit/README +examples/minitwit/minitwit.py +examples/minitwit/minitwit_tests.py +examples/minitwit/schema.sql +examples/minitwit/static/style.css +examples/minitwit/templates/layout.html +examples/minitwit/templates/login.html +examples/minitwit/templates/register.html +examples/minitwit/templates/timeline.html +examples/persona/.DS_Store +examples/persona/persona.py +examples/persona/static/.DS_Store +examples/persona/static/persona.js +examples/persona/static/spinner.png +examples/persona/static/style.css +examples/persona/templates/index.html +examples/persona/templates/layout.html +flask/__init__.py +flask/_compat.py +flask/app.py +flask/blueprints.py +flask/config.py +flask/ctx.py +flask/debughelpers.py +flask/exthook.py +flask/globals.py +flask/helpers.py +flask/json.py +flask/logging.py +flask/module.py +flask/sessions.py +flask/signals.py +flask/templating.py +flask/testing.py +flask/views.py +flask/wrappers.py +flask/ext/__init__.py +flask/testsuite/__init__.py +flask/testsuite/appctx.py +flask/testsuite/basic.py +flask/testsuite/blueprints.py +flask/testsuite/config.py +flask/testsuite/deprecations.py +flask/testsuite/examples.py +flask/testsuite/ext.py +flask/testsuite/helpers.py +flask/testsuite/regression.py +flask/testsuite/reqctx.py +flask/testsuite/signals.py +flask/testsuite/subclassing.py +flask/testsuite/templating.py +flask/testsuite/testing.py +flask/testsuite/views.py +flask/testsuite/static/index.html +flask/testsuite/templates/_macro.html +flask/testsuite/templates/context_template.html +flask/testsuite/templates/escaping_template.html +flask/testsuite/templates/mail.txt +flask/testsuite/templates/simple_template.html +flask/testsuite/templates/template_filter.html +flask/testsuite/templates/template_test.html +flask/testsuite/templates/nested/nested.txt +flask/testsuite/test_apps/config_module_app.py +flask/testsuite/test_apps/flask_newext_simple.py +flask/testsuite/test_apps/importerror.py +flask/testsuite/test_apps/main_app.py +flask/testsuite/test_apps/blueprintapp/__init__.py +flask/testsuite/test_apps/blueprintapp/apps/__init__.py +flask/testsuite/test_apps/blueprintapp/apps/admin/__init__.py +flask/testsuite/test_apps/blueprintapp/apps/admin/static/test.txt +flask/testsuite/test_apps/blueprintapp/apps/admin/static/css/test.css +flask/testsuite/test_apps/blueprintapp/apps/admin/templates/admin/index.html +flask/testsuite/test_apps/blueprintapp/apps/frontend/__init__.py +flask/testsuite/test_apps/blueprintapp/apps/frontend/templates/frontend/index.html +flask/testsuite/test_apps/config_package_app/__init__.py +flask/testsuite/test_apps/flask_broken/__init__.py +flask/testsuite/test_apps/flask_broken/b.py +flask/testsuite/test_apps/flask_newext_package/__init__.py +flask/testsuite/test_apps/flask_newext_package/submodule.py +flask/testsuite/test_apps/flaskext/__init__.py +flask/testsuite/test_apps/flaskext/oldext_simple.py +flask/testsuite/test_apps/flaskext/oldext_package/__init__.py +flask/testsuite/test_apps/flaskext/oldext_package/submodule.py +flask/testsuite/test_apps/lib/python2.5/site-packages/SiteEgg.egg +flask/testsuite/test_apps/lib/python2.5/site-packages/site_app.py +flask/testsuite/test_apps/lib/python2.5/site-packages/site_package/__init__.py +flask/testsuite/test_apps/moduleapp/__init__.py +flask/testsuite/test_apps/moduleapp/apps/__init__.py +flask/testsuite/test_apps/moduleapp/apps/admin/__init__.py +flask/testsuite/test_apps/moduleapp/apps/admin/static/test.txt +flask/testsuite/test_apps/moduleapp/apps/admin/static/css/test.css +flask/testsuite/test_apps/moduleapp/apps/admin/templates/index.html +flask/testsuite/test_apps/moduleapp/apps/frontend/__init__.py +flask/testsuite/test_apps/moduleapp/apps/frontend/templates/index.html +flask/testsuite/test_apps/path/installed_package/__init__.py +flask/testsuite/test_apps/subdomaintestmodule/__init__.py +flask/testsuite/test_apps/subdomaintestmodule/static/hello.txt \ No newline at end of file diff --git a/lib/Flask-0.10.1-py2.7.egg-info/dependency_links.txt b/lib/Flask-0.10.1-py2.7.egg-info/dependency_links.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/lib/Flask-0.10.1-py2.7.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/lib/Flask-0.10.1-py2.7.egg-info/installed-files.txt b/lib/Flask-0.10.1-py2.7.egg-info/installed-files.txt new file mode 100644 index 0000000..209da64 --- /dev/null +++ b/lib/Flask-0.10.1-py2.7.egg-info/installed-files.txt @@ -0,0 +1,148 @@ +../flask/wrappers.py +../flask/views.py +../flask/testing.py +../flask/templating.py +../flask/signals.py +../flask/sessions.py +../flask/module.py +../flask/logging.py +../flask/json.py +../flask/helpers.py +../flask/globals.py +../flask/exthook.py +../flask/debughelpers.py +../flask/ctx.py +../flask/config.py +../flask/blueprints.py +../flask/app.py +../flask/_compat.py +../flask/__init__.py +../flask/ext/__init__.py +../flask/testsuite/views.py +../flask/testsuite/testing.py +../flask/testsuite/templating.py +../flask/testsuite/subclassing.py +../flask/testsuite/signals.py +../flask/testsuite/reqctx.py +../flask/testsuite/regression.py +../flask/testsuite/helpers.py +../flask/testsuite/ext.py +../flask/testsuite/examples.py +../flask/testsuite/deprecations.py +../flask/testsuite/config.py +../flask/testsuite/blueprints.py +../flask/testsuite/basic.py +../flask/testsuite/appctx.py +../flask/testsuite/__init__.py +../flask/testsuite/static/index.html +../flask/testsuite/templates/_macro.html +../flask/testsuite/templates/context_template.html +../flask/testsuite/templates/escaping_template.html +../flask/testsuite/templates/mail.txt +../flask/testsuite/templates/simple_template.html +../flask/testsuite/templates/template_filter.html +../flask/testsuite/templates/template_test.html +../flask/testsuite/templates/nested/nested.txt +../flask/testsuite/test_apps/config_module_app.py +../flask/testsuite/test_apps/flask_newext_simple.py +../flask/testsuite/test_apps/importerror.py +../flask/testsuite/test_apps/main_app.py +../flask/testsuite/test_apps/blueprintapp/__init__.py +../flask/testsuite/test_apps/blueprintapp/apps/__init__.py +../flask/testsuite/test_apps/blueprintapp/apps/admin/__init__.py +../flask/testsuite/test_apps/blueprintapp/apps/admin/static/test.txt +../flask/testsuite/test_apps/blueprintapp/apps/admin/static/css/test.css +../flask/testsuite/test_apps/blueprintapp/apps/admin/templates/admin/index.html +../flask/testsuite/test_apps/blueprintapp/apps/frontend/__init__.py +../flask/testsuite/test_apps/blueprintapp/apps/frontend/templates/frontend/index.html +../flask/testsuite/test_apps/config_package_app/__init__.py +../flask/testsuite/test_apps/flask_broken/__init__.py +../flask/testsuite/test_apps/flask_broken/b.py +../flask/testsuite/test_apps/flask_newext_package/__init__.py +../flask/testsuite/test_apps/flask_newext_package/submodule.py +../flask/testsuite/test_apps/flaskext/__init__.py +../flask/testsuite/test_apps/flaskext/oldext_simple.py +../flask/testsuite/test_apps/flaskext/oldext_package/__init__.py +../flask/testsuite/test_apps/flaskext/oldext_package/submodule.py +../flask/testsuite/test_apps/lib/python2.5/site-packages/SiteEgg.egg +../flask/testsuite/test_apps/lib/python2.5/site-packages/site_app.py +../flask/testsuite/test_apps/lib/python2.5/site-packages/site_package/__init__.py +../flask/testsuite/test_apps/moduleapp/__init__.py +../flask/testsuite/test_apps/moduleapp/apps/__init__.py +../flask/testsuite/test_apps/moduleapp/apps/admin/__init__.py +../flask/testsuite/test_apps/moduleapp/apps/admin/static/test.txt +../flask/testsuite/test_apps/moduleapp/apps/admin/static/css/test.css +../flask/testsuite/test_apps/moduleapp/apps/admin/templates/index.html +../flask/testsuite/test_apps/moduleapp/apps/frontend/__init__.py +../flask/testsuite/test_apps/moduleapp/apps/frontend/templates/index.html +../flask/testsuite/test_apps/path/installed_package/__init__.py +../flask/testsuite/test_apps/subdomaintestmodule/__init__.py +../flask/testsuite/test_apps/subdomaintestmodule/static/hello.txt +../flask/wrappers.pyc +../flask/views.pyc +../flask/testing.pyc +../flask/templating.pyc +../flask/signals.pyc +../flask/sessions.pyc +../flask/module.pyc +../flask/logging.pyc +../flask/json.pyc +../flask/helpers.pyc +../flask/globals.pyc +../flask/exthook.pyc +../flask/debughelpers.pyc +../flask/ctx.pyc +../flask/config.pyc +../flask/blueprints.pyc +../flask/app.pyc +../flask/_compat.pyc +../flask/__init__.pyc +../flask/ext/__init__.pyc +../flask/testsuite/views.pyc +../flask/testsuite/testing.pyc +../flask/testsuite/templating.pyc +../flask/testsuite/subclassing.pyc +../flask/testsuite/signals.pyc +../flask/testsuite/reqctx.pyc +../flask/testsuite/regression.pyc +../flask/testsuite/helpers.pyc +../flask/testsuite/ext.pyc +../flask/testsuite/examples.pyc +../flask/testsuite/deprecations.pyc +../flask/testsuite/config.pyc +../flask/testsuite/blueprints.pyc +../flask/testsuite/basic.pyc +../flask/testsuite/appctx.pyc +../flask/testsuite/__init__.pyc +../flask/testsuite/test_apps/config_module_app.pyc +../flask/testsuite/test_apps/flask_newext_simple.pyc +../flask/testsuite/test_apps/importerror.pyc +../flask/testsuite/test_apps/main_app.pyc +../flask/testsuite/test_apps/blueprintapp/__init__.pyc +../flask/testsuite/test_apps/blueprintapp/apps/__init__.pyc +../flask/testsuite/test_apps/blueprintapp/apps/admin/__init__.pyc +../flask/testsuite/test_apps/blueprintapp/apps/frontend/__init__.pyc +../flask/testsuite/test_apps/config_package_app/__init__.pyc +../flask/testsuite/test_apps/flask_broken/__init__.pyc +../flask/testsuite/test_apps/flask_broken/b.pyc +../flask/testsuite/test_apps/flask_newext_package/__init__.pyc +../flask/testsuite/test_apps/flask_newext_package/submodule.pyc +../flask/testsuite/test_apps/flaskext/__init__.pyc +../flask/testsuite/test_apps/flaskext/oldext_simple.pyc +../flask/testsuite/test_apps/flaskext/oldext_package/__init__.pyc +../flask/testsuite/test_apps/flaskext/oldext_package/submodule.pyc +../flask/testsuite/test_apps/lib/python2.5/site-packages/site_app.pyc +../flask/testsuite/test_apps/lib/python2.5/site-packages/site_package/__init__.pyc +../flask/testsuite/test_apps/moduleapp/__init__.pyc +../flask/testsuite/test_apps/moduleapp/apps/__init__.pyc +../flask/testsuite/test_apps/moduleapp/apps/admin/__init__.pyc +../flask/testsuite/test_apps/moduleapp/apps/frontend/__init__.pyc +../flask/testsuite/test_apps/path/installed_package/__init__.pyc +../flask/testsuite/test_apps/subdomaintestmodule/__init__.pyc +./ +top_level.txt +SOURCES.txt +requires.txt +PKG-INFO +not-zip-safe +dependency_links.txt diff --git a/lib/Flask-0.10.1-py2.7.egg-info/not-zip-safe b/lib/Flask-0.10.1-py2.7.egg-info/not-zip-safe new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/lib/Flask-0.10.1-py2.7.egg-info/not-zip-safe @@ -0,0 +1 @@ + diff --git a/lib/Flask-0.10.1-py2.7.egg-info/requires.txt b/lib/Flask-0.10.1-py2.7.egg-info/requires.txt new file mode 100644 index 0000000..a7281e1 --- /dev/null +++ b/lib/Flask-0.10.1-py2.7.egg-info/requires.txt @@ -0,0 +1,3 @@ +Werkzeug>=0.7 +Jinja2>=2.4 +itsdangerous>=0.21 \ No newline at end of file diff --git a/lib/Flask-0.10.1-py2.7.egg-info/top_level.txt b/lib/Flask-0.10.1-py2.7.egg-info/top_level.txt new file mode 100644 index 0000000..7e10602 --- /dev/null +++ b/lib/Flask-0.10.1-py2.7.egg-info/top_level.txt @@ -0,0 +1 @@ +flask diff --git a/lib/Flask_Cors-2.0.0-py2.7.egg-info/PKG-INFO b/lib/Flask_Cors-2.0.0-py2.7.egg-info/PKG-INFO new file mode 100644 index 0000000..faf071f --- /dev/null +++ b/lib/Flask_Cors-2.0.0-py2.7.egg-info/PKG-INFO @@ -0,0 +1,166 @@ +Metadata-Version: 1.1 +Name: Flask-Cors +Version: 2.0.0 +Summary: A Flask extension adding a decorator for CORS support +Home-page: https://github.com/corydolphin/flask-cors +Author: Cory Dolphin +Author-email: corydolphin@gmail.com +License: MIT +Description: Flask-CORS + ========== + + |Build Status| |Latest Version| |Downloads| |Supported Python versions| + |License| + + A Flask extension for handling Cross Origin Resource Sharing (CORS), + making cross-origin AJAX possible. + + Installation + ------------ + + Install the extension with using pip, or easy\_install. + + .. code:: bash + + $ pip install -U flask-cors + + Usage + ----- + + This extension enables CORS support either via a decorator, or a Flask + extension. There are three examples shown in the + `examples `__ + directory, showing the major use cases. The suggested configuration is + the + `simple\_example.py `__, + or the + `app\_example.py `__. + A full list of options can be found in the + `documentation `__. + + This package has a simple philosophy, when you want to enable CORS, you + wish to enable it for all use cases on a domain. This means no mucking + around with different allowed headers, methods, etc. By default, + submission of cookies across domains is disabled due to the security + implications, please see the documentation for how to enable + credential'ed requests, and please make sure you add some sort of + `CRSF `__ + protection before doing so! + + Simple Usage + ~~~~~~~~~~~~ + + In the simplest case, initialize the Flask-Cors extension with default + arguments in order to allow CORS for all domains on all routes. + + .. code:: python + + + app = Flask(__name__) + cors = CORS(app) + + @app.route("/") + def helloWorld(): + return "Hello, cross-origin-world!" + + Resource specific CORS + ^^^^^^^^^^^^^^^^^^^^^^ + + Alternatively, you can specify CORS options on a resource and origin + level of granularity by passing a dictionary as the 'resources' option, + mapping paths to a set of options. + + .. code:: python + + app = Flask(__name__) + cors = CORS(app, resources={r"/api/*": {"origins": "*"}}) + + @app.route("/api/v1/users") + def list_users(): + return "user example" + + Route specific CORS via decorator + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + This extension also exposes a simple decorator to decorate flask routes + with. Simply add ``@cross_origin()`` below a call to Flask's + ``@app.route(..)`` to allow CORS on a given route. + + .. code:: python + + @app.route("/") + @cross_origin() + def helloWorld(): + return "Hello, cross-origin-world!" + + Logging + ^^^^^^^ + + Flask-Cors uses standard Python logging, using the logger name + '``app.logger_name``.cors'. The app's logger name attribute is usually + the same as the name of the app. You can read more about logging from + `Flask's + documentation `__. + + .. code:: python + + import logging + # make your awesome app + logging.basicConfig(level=logging.INFO) + + Documentation + ------------- + + For a full list of options, please see the full + `documentation `__ + + Tests + ----- + + A simple set of tests is included in ``test/``. To run, install nose, + and simply invoke ``nosetests`` or ``python setup.py test`` to exercise + the tests. + + Contributing + ------------ + + Questions, comments or improvements? Please create an issue on + `Github `__, tweet at + `@corydolphin `__ or send me an email. + I do my best to include every contribution proposed in any way that I + can. + + Credits + ------- + + This Flask extension is based upon the `Decorator for the HTTP Access + Control `__ written by Armin + Ronacher. + + .. |Build Status| image:: https://api.travis-ci.org/corydolphin/flask-cors.svg?branch=master + :target: https://travis-ci.org/corydolphin/flask-cors + .. |Latest Version| image:: https://pypip.in/version/Flask-Cors/badge.svg + :target: https://pypi.python.org/pypi/Flask-Cors/ + .. |Downloads| image:: https://pypip.in/download/Flask-Cors/badge.svg + :target: https://pypi.python.org/pypi/Flask-Cors/ + .. |Supported Python versions| image:: https://pypip.in/py_versions/Flask-Cors/badge.svg + :target: https://pypi.python.org/pypi/Flask-Cors/ + .. |License| image:: https://pypip.in/license/Flask-Cors/badge.svg + :target: https://pypi.python.org/pypi/Flask-Cors/ + +Platform: any +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2.6 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.1 +Classifier: Programming Language :: Python :: 3.2 +Classifier: Programming Language :: Python :: 3.3 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Software Development :: Libraries :: Python Modules diff --git a/lib/Flask_Cors-2.0.0-py2.7.egg-info/SOURCES.txt b/lib/Flask_Cors-2.0.0-py2.7.egg-info/SOURCES.txt new file mode 100644 index 0000000..c850d6f --- /dev/null +++ b/lib/Flask_Cors-2.0.0-py2.7.egg-info/SOURCES.txt @@ -0,0 +1,38 @@ +LICENSE +MANIFEST.in +README.rst +setup.cfg +setup.py +Flask_Cors.egg-info/PKG-INFO +Flask_Cors.egg-info/SOURCES.txt +Flask_Cors.egg-info/dependency_links.txt +Flask_Cors.egg-info/not-zip-safe +Flask_Cors.egg-info/requires.txt +Flask_Cors.egg-info/top_level.txt +docs/Makefile +docs/conf.py +docs/index.rst +examples/app_based_example.py +examples/view_based_example.py +flask_cors/__init__.py +flask_cors/core.py +flask_cors/decorator.py +flask_cors/extension.py +flask_cors/version.py +tests/__init__.py +tests/base_test.py +tests/core/__init__.py +tests/core/helper_tests.py +tests/decorator/__init__.py +tests/decorator/test_allow_headers.py +tests/decorator/test_credentials.py +tests/decorator/test_exception_interception.py +tests/decorator/test_expose_headers.py +tests/decorator/test_max_age.py +tests/decorator/test_methods.py +tests/decorator/test_options.py +tests/decorator/test_origins.py +tests/decorator/test_vary_header.py +tests/decorator/test_w3.py +tests/extension/__init__.py +tests/extension/test_app_extension.py \ No newline at end of file diff --git a/lib/Flask_Cors-2.0.0-py2.7.egg-info/dependency_links.txt b/lib/Flask_Cors-2.0.0-py2.7.egg-info/dependency_links.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/lib/Flask_Cors-2.0.0-py2.7.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/lib/Flask_Cors-2.0.0-py2.7.egg-info/installed-files.txt b/lib/Flask_Cors-2.0.0-py2.7.egg-info/installed-files.txt new file mode 100644 index 0000000..833a604 --- /dev/null +++ b/lib/Flask_Cors-2.0.0-py2.7.egg-info/installed-files.txt @@ -0,0 +1,17 @@ +../flask_cors/__init__.py +../flask_cors/version.py +../flask_cors/decorator.py +../flask_cors/core.py +../flask_cors/extension.py +../flask_cors/__init__.pyc +../flask_cors/version.pyc +../flask_cors/decorator.pyc +../flask_cors/core.pyc +../flask_cors/extension.pyc +./ +SOURCES.txt +requires.txt +not-zip-safe +PKG-INFO +top_level.txt +dependency_links.txt diff --git a/lib/Flask_Cors-2.0.0-py2.7.egg-info/not-zip-safe b/lib/Flask_Cors-2.0.0-py2.7.egg-info/not-zip-safe new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/lib/Flask_Cors-2.0.0-py2.7.egg-info/not-zip-safe @@ -0,0 +1 @@ + diff --git a/lib/Flask_Cors-2.0.0-py2.7.egg-info/requires.txt b/lib/Flask_Cors-2.0.0-py2.7.egg-info/requires.txt new file mode 100644 index 0000000..c820a1d --- /dev/null +++ b/lib/Flask_Cors-2.0.0-py2.7.egg-info/requires.txt @@ -0,0 +1,2 @@ +Flask >= 0.9 +Six \ No newline at end of file diff --git a/lib/Flask_Cors-2.0.0-py2.7.egg-info/top_level.txt b/lib/Flask_Cors-2.0.0-py2.7.egg-info/top_level.txt new file mode 100644 index 0000000..27af988 --- /dev/null +++ b/lib/Flask_Cors-2.0.0-py2.7.egg-info/top_level.txt @@ -0,0 +1 @@ +flask_cors diff --git a/lib/GitHub_Flask-2.0.1-py2.7.egg-info/PKG-INFO b/lib/GitHub_Flask-2.0.1-py2.7.egg-info/PKG-INFO new file mode 100755 index 0000000..44f61c4 --- /dev/null +++ b/lib/GitHub_Flask-2.0.1-py2.7.egg-info/PKG-INFO @@ -0,0 +1,29 @@ +Metadata-Version: 1.1 +Name: GitHub-Flask +Version: 2.0.1 +Summary: GitHub extension for Flask microframework +Home-page: http://github.com/cenkalti/github-flask +Author: Cenk Alti +Author-email: cenkalti@gmail.com +License: MIT +Description: + GitHub-Flask + ------------ + + Adds support to authorize users with GitHub and make API requests with Flask. + + Links + ````` + + * `documentation `_ + * `development version + `_ + + +Platform: any +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Software Development :: Libraries :: Python Modules diff --git a/lib/GitHub_Flask-2.0.1-py2.7.egg-info/SOURCES.txt b/lib/GitHub_Flask-2.0.1-py2.7.egg-info/SOURCES.txt new file mode 100755 index 0000000..5a0b175 --- /dev/null +++ b/lib/GitHub_Flask-2.0.1-py2.7.egg-info/SOURCES.txt @@ -0,0 +1,10 @@ +README.rst +flask_github.py +setup.cfg +setup.py +GitHub_Flask.egg-info/PKG-INFO +GitHub_Flask.egg-info/SOURCES.txt +GitHub_Flask.egg-info/dependency_links.txt +GitHub_Flask.egg-info/not-zip-safe +GitHub_Flask.egg-info/requires.txt +GitHub_Flask.egg-info/top_level.txt \ No newline at end of file diff --git a/lib/GitHub_Flask-2.0.1-py2.7.egg-info/dependency_links.txt b/lib/GitHub_Flask-2.0.1-py2.7.egg-info/dependency_links.txt new file mode 100755 index 0000000..8b13789 --- /dev/null +++ b/lib/GitHub_Flask-2.0.1-py2.7.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/lib/GitHub_Flask-2.0.1-py2.7.egg-info/installed-files.txt b/lib/GitHub_Flask-2.0.1-py2.7.egg-info/installed-files.txt new file mode 100644 index 0000000..4967b49 --- /dev/null +++ b/lib/GitHub_Flask-2.0.1-py2.7.egg-info/installed-files.txt @@ -0,0 +1,9 @@ +../flask_github.py +../flask_github.pyc +./ +SOURCES.txt +requires.txt +not-zip-safe +PKG-INFO +top_level.txt +dependency_links.txt diff --git a/lib/GitHub_Flask-2.0.1-py2.7.egg-info/not-zip-safe b/lib/GitHub_Flask-2.0.1-py2.7.egg-info/not-zip-safe new file mode 100755 index 0000000..8b13789 --- /dev/null +++ b/lib/GitHub_Flask-2.0.1-py2.7.egg-info/not-zip-safe @@ -0,0 +1 @@ + diff --git a/lib/GitHub_Flask-2.0.1-py2.7.egg-info/requires.txt b/lib/GitHub_Flask-2.0.1-py2.7.egg-info/requires.txt new file mode 100755 index 0000000..0eb56cd --- /dev/null +++ b/lib/GitHub_Flask-2.0.1-py2.7.egg-info/requires.txt @@ -0,0 +1,2 @@ +Flask +requests \ No newline at end of file diff --git a/lib/GitHub_Flask-2.0.1-py2.7.egg-info/top_level.txt b/lib/GitHub_Flask-2.0.1-py2.7.egg-info/top_level.txt new file mode 100755 index 0000000..5c0ba08 --- /dev/null +++ b/lib/GitHub_Flask-2.0.1-py2.7.egg-info/top_level.txt @@ -0,0 +1 @@ +flask_github diff --git a/lib/Jinja2-2.7.3-py2.7.egg-info/PKG-INFO b/lib/Jinja2-2.7.3-py2.7.egg-info/PKG-INFO new file mode 100644 index 0000000..7234bf5 --- /dev/null +++ b/lib/Jinja2-2.7.3-py2.7.egg-info/PKG-INFO @@ -0,0 +1,55 @@ +Metadata-Version: 1.1 +Name: Jinja2 +Version: 2.7.3 +Summary: A small but fast and easy to use stand-alone template engine written in pure python. +Home-page: http://jinja.pocoo.org/ +Author: Armin Ronacher +Author-email: armin.ronacher@active-4.com +License: BSD +Description: + Jinja2 + ~~~~~~ + + Jinja2 is a template engine written in pure Python. It provides a + `Django`_ inspired non-XML syntax but supports inline expressions and + an optional `sandboxed`_ environment. + + Nutshell + -------- + + Here a small example of a Jinja template:: + + {% extends 'base.html' %} + {% block title %}Memberlist{% endblock %} + {% block content %} + + {% endblock %} + + Philosophy + ---------- + + Application logic is for the controller but don't try to make the life + for the template designer too hard by giving him too few functionality. + + For more informations visit the new `Jinja2 webpage`_ and `documentation`_. + + .. _sandboxed: http://en.wikipedia.org/wiki/Sandbox_(computer_security) + .. _Django: http://www.djangoproject.com/ + .. _Jinja2 webpage: http://jinja.pocoo.org/ + .. _documentation: http://jinja.pocoo.org/2/documentation/ + +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: Text Processing :: Markup :: HTML diff --git a/lib/Jinja2-2.7.3-py2.7.egg-info/SOURCES.txt b/lib/Jinja2-2.7.3-py2.7.egg-info/SOURCES.txt new file mode 100644 index 0000000..a27a9c4 --- /dev/null +++ b/lib/Jinja2-2.7.3-py2.7.egg-info/SOURCES.txt @@ -0,0 +1,126 @@ +AUTHORS +CHANGES +LICENSE +MANIFEST.in +Makefile +README.rst +run-tests.py +setup.cfg +setup.py +Jinja2.egg-info/PKG-INFO +Jinja2.egg-info/SOURCES.txt +Jinja2.egg-info/dependency_links.txt +Jinja2.egg-info/entry_points.txt +Jinja2.egg-info/not-zip-safe +Jinja2.egg-info/requires.txt +Jinja2.egg-info/top_level.txt +artwork/jinjalogo.svg +docs/Makefile +docs/api.rst +docs/cache_extension.py +docs/changelog.rst +docs/conf.py +docs/contents.rst.inc +docs/extensions.rst +docs/faq.rst +docs/index.rst +docs/integration.rst +docs/intro.rst +docs/jinjaext.py +docs/jinjastyle.sty +docs/latexindex.rst +docs/logo.pdf +docs/sandbox.rst +docs/switching.rst +docs/templates.rst +docs/tricks.rst +docs/_static/.ignore +docs/_static/jinja-small.png +docs/_templates/sidebarintro.html +docs/_templates/sidebarlogo.html +docs/_themes/LICENSE +docs/_themes/README +docs/_themes/jinja/layout.html +docs/_themes/jinja/relations.html +docs/_themes/jinja/theme.conf +docs/_themes/jinja/static/jinja.css_t +examples/bench.py +examples/profile.py +examples/basic/cycle.py +examples/basic/debugger.py +examples/basic/inheritance.py +examples/basic/test.py +examples/basic/test_filter_and_linestatements.py +examples/basic/test_loop_filter.py +examples/basic/translate.py +examples/basic/templates/broken.html +examples/basic/templates/subbroken.html +examples/rwbench/djangoext.py +examples/rwbench/rwbench.py +examples/rwbench/django/_form.html +examples/rwbench/django/_input_field.html +examples/rwbench/django/_textarea.html +examples/rwbench/django/index.html +examples/rwbench/django/layout.html +examples/rwbench/genshi/helpers.html +examples/rwbench/genshi/index.html +examples/rwbench/genshi/layout.html +examples/rwbench/jinja/helpers.html +examples/rwbench/jinja/index.html +examples/rwbench/jinja/layout.html +examples/rwbench/mako/helpers.html +examples/rwbench/mako/index.html +examples/rwbench/mako/layout.html +ext/djangojinja2.py +ext/inlinegettext.py +ext/jinja.el +ext/Vim/jinja.vim +ext/django2jinja/django2jinja.py +ext/django2jinja/example.py +ext/django2jinja/templates/index.html +ext/django2jinja/templates/layout.html +ext/django2jinja/templates/subtemplate.html +jinja2/__init__.py +jinja2/_compat.py +jinja2/_stringdefs.py +jinja2/bccache.py +jinja2/compiler.py +jinja2/constants.py +jinja2/debug.py +jinja2/defaults.py +jinja2/environment.py +jinja2/exceptions.py +jinja2/ext.py +jinja2/filters.py +jinja2/lexer.py +jinja2/loaders.py +jinja2/meta.py +jinja2/nodes.py +jinja2/optimizer.py +jinja2/parser.py +jinja2/runtime.py +jinja2/sandbox.py +jinja2/tests.py +jinja2/utils.py +jinja2/visitor.py +jinja2/testsuite/__init__.py +jinja2/testsuite/api.py +jinja2/testsuite/bytecode_cache.py +jinja2/testsuite/core_tags.py +jinja2/testsuite/debug.py +jinja2/testsuite/doctests.py +jinja2/testsuite/ext.py +jinja2/testsuite/filters.py +jinja2/testsuite/imports.py +jinja2/testsuite/inheritance.py +jinja2/testsuite/lexnparse.py +jinja2/testsuite/loader.py +jinja2/testsuite/regression.py +jinja2/testsuite/security.py +jinja2/testsuite/tests.py +jinja2/testsuite/utils.py +jinja2/testsuite/res/__init__.py +jinja2/testsuite/res/templates/broken.html +jinja2/testsuite/res/templates/syntaxerror.html +jinja2/testsuite/res/templates/test.html +jinja2/testsuite/res/templates/foo/test.html \ No newline at end of file diff --git a/lib/Jinja2-2.7.3-py2.7.egg-info/dependency_links.txt b/lib/Jinja2-2.7.3-py2.7.egg-info/dependency_links.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/lib/Jinja2-2.7.3-py2.7.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/lib/Jinja2-2.7.3-py2.7.egg-info/entry_points.txt b/lib/Jinja2-2.7.3-py2.7.egg-info/entry_points.txt new file mode 100644 index 0000000..32e6b75 --- /dev/null +++ b/lib/Jinja2-2.7.3-py2.7.egg-info/entry_points.txt @@ -0,0 +1,4 @@ + + [babel.extractors] + jinja2 = jinja2.ext:babel_extract[i18n] + \ No newline at end of file diff --git a/lib/Jinja2-2.7.3-py2.7.egg-info/installed-files.txt b/lib/Jinja2-2.7.3-py2.7.egg-info/installed-files.txt new file mode 100644 index 0000000..a629bd5 --- /dev/null +++ b/lib/Jinja2-2.7.3-py2.7.egg-info/installed-files.txt @@ -0,0 +1,92 @@ +../jinja2/visitor.py +../jinja2/utils.py +../jinja2/tests.py +../jinja2/sandbox.py +../jinja2/runtime.py +../jinja2/parser.py +../jinja2/optimizer.py +../jinja2/nodes.py +../jinja2/meta.py +../jinja2/loaders.py +../jinja2/lexer.py +../jinja2/filters.py +../jinja2/ext.py +../jinja2/exceptions.py +../jinja2/environment.py +../jinja2/defaults.py +../jinja2/debug.py +../jinja2/constants.py +../jinja2/compiler.py +../jinja2/bccache.py +../jinja2/_stringdefs.py +../jinja2/_compat.py +../jinja2/__init__.py +../jinja2/testsuite/utils.py +../jinja2/testsuite/tests.py +../jinja2/testsuite/security.py +../jinja2/testsuite/regression.py +../jinja2/testsuite/loader.py +../jinja2/testsuite/lexnparse.py +../jinja2/testsuite/inheritance.py +../jinja2/testsuite/imports.py +../jinja2/testsuite/filters.py +../jinja2/testsuite/ext.py +../jinja2/testsuite/doctests.py +../jinja2/testsuite/debug.py +../jinja2/testsuite/core_tags.py +../jinja2/testsuite/bytecode_cache.py +../jinja2/testsuite/api.py +../jinja2/testsuite/__init__.py +../jinja2/testsuite/res/__init__.py +../jinja2/testsuite/res/templates/broken.html +../jinja2/testsuite/res/templates/syntaxerror.html +../jinja2/testsuite/res/templates/test.html +../jinja2/testsuite/res/templates/foo/test.html +../jinja2/visitor.pyc +../jinja2/utils.pyc +../jinja2/tests.pyc +../jinja2/sandbox.pyc +../jinja2/runtime.pyc +../jinja2/parser.pyc +../jinja2/optimizer.pyc +../jinja2/nodes.pyc +../jinja2/meta.pyc +../jinja2/loaders.pyc +../jinja2/lexer.pyc +../jinja2/filters.pyc +../jinja2/ext.pyc +../jinja2/exceptions.pyc +../jinja2/environment.pyc +../jinja2/defaults.pyc +../jinja2/debug.pyc +../jinja2/constants.pyc +../jinja2/compiler.pyc +../jinja2/bccache.pyc +../jinja2/_stringdefs.pyc +../jinja2/_compat.pyc +../jinja2/__init__.pyc +../jinja2/testsuite/utils.pyc +../jinja2/testsuite/tests.pyc +../jinja2/testsuite/security.pyc +../jinja2/testsuite/regression.pyc +../jinja2/testsuite/loader.pyc +../jinja2/testsuite/lexnparse.pyc +../jinja2/testsuite/inheritance.pyc +../jinja2/testsuite/imports.pyc +../jinja2/testsuite/filters.pyc +../jinja2/testsuite/ext.pyc +../jinja2/testsuite/doctests.pyc +../jinja2/testsuite/debug.pyc +../jinja2/testsuite/core_tags.pyc +../jinja2/testsuite/bytecode_cache.pyc +../jinja2/testsuite/api.pyc +../jinja2/testsuite/__init__.pyc +../jinja2/testsuite/res/__init__.pyc +./ +top_level.txt +SOURCES.txt +requires.txt +PKG-INFO +not-zip-safe +entry_points.txt +dependency_links.txt diff --git a/lib/Jinja2-2.7.3-py2.7.egg-info/not-zip-safe b/lib/Jinja2-2.7.3-py2.7.egg-info/not-zip-safe new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/lib/Jinja2-2.7.3-py2.7.egg-info/not-zip-safe @@ -0,0 +1 @@ + diff --git a/lib/Jinja2-2.7.3-py2.7.egg-info/requires.txt b/lib/Jinja2-2.7.3-py2.7.egg-info/requires.txt new file mode 100644 index 0000000..ccd0e92 --- /dev/null +++ b/lib/Jinja2-2.7.3-py2.7.egg-info/requires.txt @@ -0,0 +1,4 @@ +markupsafe + +[i18n] +Babel>=0.8 \ No newline at end of file diff --git a/lib/Jinja2-2.7.3-py2.7.egg-info/top_level.txt b/lib/Jinja2-2.7.3-py2.7.egg-info/top_level.txt new file mode 100644 index 0000000..7f7afbf --- /dev/null +++ b/lib/Jinja2-2.7.3-py2.7.egg-info/top_level.txt @@ -0,0 +1 @@ +jinja2 diff --git a/lib/MarkupSafe-0.23-py2.7.egg-info/PKG-INFO b/lib/MarkupSafe-0.23-py2.7.egg-info/PKG-INFO new file mode 100644 index 0000000..12aa93e --- /dev/null +++ b/lib/MarkupSafe-0.23-py2.7.egg-info/PKG-INFO @@ -0,0 +1,119 @@ +Metadata-Version: 1.1 +Name: MarkupSafe +Version: 0.23 +Summary: Implements a XML/HTML/XHTML Markup safe string for Python +Home-page: http://github.com/mitsuhiko/markupsafe +Author: Armin Ronacher +Author-email: armin.ronacher@active-4.com +License: BSD +Description: MarkupSafe + ========== + + Implements a unicode subclass that supports HTML strings: + + >>> from markupsafe import Markup, escape + >>> escape("") + Markup(u'<script>alert(document.cookie);</script>') + >>> tmpl = Markup("%s") + >>> tmpl % "Peter > Lustig" + Markup(u'Peter > Lustig') + + If you want to make an object unicode that is not yet unicode + but don't want to lose the taint information, you can use the + `soft_unicode` function. (On Python 3 you can also use `soft_str` which + is a different name for the same function). + + >>> from markupsafe import soft_unicode + >>> soft_unicode(42) + u'42' + >>> soft_unicode(Markup('foo')) + Markup(u'foo') + + HTML Representations + -------------------- + + Objects can customize their HTML markup equivalent by overriding + the `__html__` function: + + >>> class Foo(object): + ... def __html__(self): + ... return 'Nice' + ... + >>> escape(Foo()) + Markup(u'Nice') + >>> Markup(Foo()) + Markup(u'Nice') + + Silent Escapes + -------------- + + Since MarkupSafe 0.10 there is now also a separate escape function + called `escape_silent` that returns an empty string for `None` for + consistency with other systems that return empty strings for `None` + when escaping (for instance Pylons' webhelpers). + + If you also want to use this for the escape method of the Markup + object, you can create your own subclass that does that:: + + from markupsafe import Markup, escape_silent as escape + + class SilentMarkup(Markup): + __slots__ = () + + @classmethod + def escape(cls, s): + return cls(escape(s)) + + New-Style String Formatting + --------------------------- + + Starting with MarkupSafe 0.21 new style string formats from Python 2.6 and + 3.x are now fully supported. Previously the escape behavior of those + functions was spotty at best. The new implementations operates under the + following algorithm: + + 1. if an object has an ``__html_format__`` method it is called as + replacement for ``__format__`` with the format specifier. It either + has to return a string or markup object. + 2. if an object has an ``__html__`` method it is called. + 3. otherwise the default format system of Python kicks in and the result + is HTML escaped. + + Here is how you can implement your own formatting:: + + class User(object): + + def __init__(self, id, username): + self.id = id + self.username = username + + def __html_format__(self, format_spec): + if format_spec == 'link': + return Markup('{1}').format( + self.id, + self.__html__(), + ) + elif format_spec: + raise ValueError('Invalid format spec') + return self.__html__() + + def __html__(self): + return Markup('{0}').format(self.username) + + And to format that user: + + >>> user = User(1, 'foo') + >>> Markup('

User: {0:link}').format(user) + Markup(u'

User: foo') + +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: Text Processing :: Markup :: HTML diff --git a/lib/MarkupSafe-0.23-py2.7.egg-info/SOURCES.txt b/lib/MarkupSafe-0.23-py2.7.egg-info/SOURCES.txt new file mode 100644 index 0000000..dfeb82b --- /dev/null +++ b/lib/MarkupSafe-0.23-py2.7.egg-info/SOURCES.txt @@ -0,0 +1,17 @@ +AUTHORS +LICENSE +MANIFEST.in +README.rst +setup.cfg +setup.py +MarkupSafe.egg-info/PKG-INFO +MarkupSafe.egg-info/SOURCES.txt +MarkupSafe.egg-info/dependency_links.txt +MarkupSafe.egg-info/not-zip-safe +MarkupSafe.egg-info/top_level.txt +markupsafe/__init__.py +markupsafe/_compat.py +markupsafe/_constants.py +markupsafe/_native.py +markupsafe/_speedups.c +markupsafe/tests.py \ No newline at end of file diff --git a/lib/MarkupSafe-0.23-py2.7.egg-info/dependency_links.txt b/lib/MarkupSafe-0.23-py2.7.egg-info/dependency_links.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/lib/MarkupSafe-0.23-py2.7.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/lib/MarkupSafe-0.23-py2.7.egg-info/installed-files.txt b/lib/MarkupSafe-0.23-py2.7.egg-info/installed-files.txt new file mode 100644 index 0000000..8c1e953 --- /dev/null +++ b/lib/MarkupSafe-0.23-py2.7.egg-info/installed-files.txt @@ -0,0 +1,18 @@ +../markupsafe/tests.py +../markupsafe/_native.py +../markupsafe/_constants.py +../markupsafe/_compat.py +../markupsafe/__init__.py +../markupsafe/_speedups.c +../markupsafe/tests.pyc +../markupsafe/_native.pyc +../markupsafe/_constants.pyc +../markupsafe/_compat.pyc +../markupsafe/__init__.pyc +../markupsafe/_speedups.so +./ +top_level.txt +SOURCES.txt +PKG-INFO +not-zip-safe +dependency_links.txt diff --git a/lib/MarkupSafe-0.23-py2.7.egg-info/not-zip-safe b/lib/MarkupSafe-0.23-py2.7.egg-info/not-zip-safe new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/lib/MarkupSafe-0.23-py2.7.egg-info/not-zip-safe @@ -0,0 +1 @@ + diff --git a/lib/MarkupSafe-0.23-py2.7.egg-info/top_level.txt b/lib/MarkupSafe-0.23-py2.7.egg-info/top_level.txt new file mode 100644 index 0000000..75bf729 --- /dev/null +++ b/lib/MarkupSafe-0.23-py2.7.egg-info/top_level.txt @@ -0,0 +1 @@ +markupsafe diff --git a/lib/Werkzeug-0.10.4.dist-info/DESCRIPTION.rst b/lib/Werkzeug-0.10.4.dist-info/DESCRIPTION.rst new file mode 100644 index 0000000..2a6e8bb --- /dev/null +++ b/lib/Werkzeug-0.10.4.dist-info/DESCRIPTION.rst @@ -0,0 +1,54 @@ +Werkzeug +======== + +Werkzeug started as simple collection of various utilities for WSGI +applications and has become one of the most advanced WSGI utility +modules. It includes a powerful debugger, full featured request and +response objects, HTTP utilities to handle entity tags, cache control +headers, HTTP dates, cookie handling, file uploads, a powerful URL +routing system and a bunch of community contributed addon modules. + +Werkzeug is unicode aware and doesn't enforce a specific template +engine, database adapter or anything else. It doesn't even enforce +a specific way of handling requests and leaves all that up to the +developer. It's most useful for end user applications which should work +on as many server environments as possible (such as blogs, wikis, +bulletin boards, etc.). + +Details and example applications are available on the +`Werkzeug website `_. + + +Features +-------- + +- unicode awareness + +- request and response objects + +- various utility functions for dealing with HTTP headers such as + `Accept` and `Cache-Control` headers. + +- thread local objects with proper cleanup at request end + +- an interactive debugger + +- A simple WSGI server with support for threading and forking + with an automatic reloader. + +- a flexible URL routing system with REST support. + +- fully WSGI compatible + + +Development Version +------------------- + +The Werkzeug development version can be installed by cloning the git +repository from `github`_:: + + git clone git@github.com:mitsuhiko/werkzeug.git + +.. _github: http://github.com/mitsuhiko/werkzeug + + diff --git a/lib/Werkzeug-0.10.4.dist-info/METADATA b/lib/Werkzeug-0.10.4.dist-info/METADATA new file mode 100644 index 0000000..ff9693c --- /dev/null +++ b/lib/Werkzeug-0.10.4.dist-info/METADATA @@ -0,0 +1,73 @@ +Metadata-Version: 2.0 +Name: Werkzeug +Version: 0.10.4 +Summary: The Swiss Army knife of Python web development +Home-page: http://werkzeug.pocoo.org/ +Author: Armin Ronacher +Author-email: armin.ronacher@active-4.com +License: BSD +Platform: any +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Software Development :: Libraries :: Python Modules + +Werkzeug +======== + +Werkzeug started as simple collection of various utilities for WSGI +applications and has become one of the most advanced WSGI utility +modules. It includes a powerful debugger, full featured request and +response objects, HTTP utilities to handle entity tags, cache control +headers, HTTP dates, cookie handling, file uploads, a powerful URL +routing system and a bunch of community contributed addon modules. + +Werkzeug is unicode aware and doesn't enforce a specific template +engine, database adapter or anything else. It doesn't even enforce +a specific way of handling requests and leaves all that up to the +developer. It's most useful for end user applications which should work +on as many server environments as possible (such as blogs, wikis, +bulletin boards, etc.). + +Details and example applications are available on the +`Werkzeug website `_. + + +Features +-------- + +- unicode awareness + +- request and response objects + +- various utility functions for dealing with HTTP headers such as + `Accept` and `Cache-Control` headers. + +- thread local objects with proper cleanup at request end + +- an interactive debugger + +- A simple WSGI server with support for threading and forking + with an automatic reloader. + +- a flexible URL routing system with REST support. + +- fully WSGI compatible + + +Development Version +------------------- + +The Werkzeug development version can be installed by cloning the git +repository from `github`_:: + + git clone git@github.com:mitsuhiko/werkzeug.git + +.. _github: http://github.com/mitsuhiko/werkzeug + + diff --git a/lib/Werkzeug-0.10.4.dist-info/RECORD b/lib/Werkzeug-0.10.4.dist-info/RECORD new file mode 100644 index 0000000..f22dcb5 --- /dev/null +++ b/lib/Werkzeug-0.10.4.dist-info/RECORD @@ -0,0 +1,91 @@ +werkzeug/posixemulation.py,sha256=58IrWwAkpafaUgQMVvPfkPrjme73eIuY5PjKL2wT37Y,3483 +werkzeug/security.py,sha256=UxbSD8C-oFid9r5Oncofeuz-EALPpjE10fefDljbVfw,8971 +werkzeug/__init__.py,sha256=iYo261RIx6wL-YWtbovcn5skbouhaWdJJRGLh2kGAeM,7211 +werkzeug/testapp.py,sha256=txTIeAoq83FW6HVTBroW_0AAvnIUpZl0w8Vj2sluLDY,9398 +werkzeug/http.py,sha256=DtyRYXP06JzEdX6YS5mPFYTbtnrH7qpNvYqlqLMeoTs,34279 +werkzeug/routing.py,sha256=9fUMWiQePjbS_tugJgKTCOg9tyEnw9BaEfAj2VraAqY,64428 +werkzeug/utils.py,sha256=Ps0V2dT_HOXgXLxH4S6o_WyQG9IF8dpcAcvPsF_xgO4,23063 +werkzeug/exceptions.py,sha256=BAU0SzpOfZmU_18nyyIAzObKZhE_UrSnhymhrwGQg64,18577 +werkzeug/_reloader.py,sha256=v0WOEKO8b3q9VwKidJRQDGq4ycDZgu2znwphvgdOb_I,7938 +werkzeug/formparser.py,sha256=i0-ZzXhVxSNNMBDRHWzdbte9l5QRlycVHp0BENI2pCY,21205 +werkzeug/_compat.py,sha256=gsFXhixbO2A8rAcfm7oIDPLENSXKdeDkpieP__g8l1M,6190 +werkzeug/datastructures.py,sha256=zNlWB-h7ttq-Q-dvQqs-AAUDGH96EnYS1c60ffYanPw,86857 +werkzeug/wrappers.py,sha256=Fw1xlCuFSdq21pj6QvJkCXYkIykaSngF7w2NGPsGgdU,76919 +werkzeug/test.py,sha256=96zCaMfWMahIW2VeOdERQ66DlqslA5qrehIs6-orwrQ,34255 +werkzeug/urls.py,sha256=NObHlWIyrMA_PpOlRFCsiBn502kjM6giZ02LCgZzOfY,36596 +werkzeug/script.py,sha256=Fq9fTl2217_Chf4F2XRcpLU5xzQsNqK9tHz-CLZJKzw,11365 +werkzeug/useragents.py,sha256=DF0uXjvoKWcWgLHYOIRI98VlN0fezCNXWIJv0tmBE4A,5399 +werkzeug/local.py,sha256=r5qW9-Q2jNfZLBDoboae8A3ngw9olbVnpIs2byMDrLI,14095 +werkzeug/serving.py,sha256=WaJGURZx2uO1O95_J_zJ3eLLZq82qdxBGxFYWdWX5_0,25317 +werkzeug/wsgi.py,sha256=-lFqnoyiAV4pWf1C7gJISitddGTBKf2oqPc0Dt-XJZc,37837 +werkzeug/_internal.py,sha256=3ELUVz48eXOZeDfvgNaSSGdsg0keKw-Jvtl0Gu03WgY,13713 +werkzeug/contrib/fixers.py,sha256=8qM2G4yx1ZWm4wdHLzDVAAvFEVk03CZrY5fRnPFrUyk,10197 +werkzeug/contrib/limiter.py,sha256=wgprYdgFcwwxNy2sQlFrAyd2GxHvft0CObThiv6vPKI,1333 +werkzeug/contrib/__init__.py,sha256=f7PfttZhbrImqpr5Ezre8CXgwvcGUJK7zWNpO34WWrw,623 +werkzeug/contrib/testtools.py,sha256=MxyzW_79JppFjNOasq_KhcmYPLUY2H536pB638SwaSg,2449 +werkzeug/contrib/iterio.py,sha256=UZeSPsHEIE1p-fH0XShk7xsJKBEMbLaTXNEOCe4twug,10811 +werkzeug/contrib/cache.py,sha256=QgVRvCzRxXd3HhUh_fZ1L1d9jwK5BW4LRkou-XAhncQ,24912 +werkzeug/contrib/securecookie.py,sha256=DHXl5WnT3R_nyUnNEiDvyJBl37dZen711_JGeg3fusA,12204 +werkzeug/contrib/lint.py,sha256=TsxFaxqzizN3ClRnv7lEeOILEjd2fYzXDqs6rIZu04M,12282 +werkzeug/contrib/profiler.py,sha256=Xot8BuERy7sXtQowEnmCjkv6KaAAzLDZ3J7KLnyElpI,4921 +werkzeug/contrib/wrappers.py,sha256=7zZmAFuNV-UEqehlfCBuB-BcVr6kH2HQZ2LLcXtmC1I,10331 +werkzeug/contrib/atom.py,sha256=Y-Iv5Dn0iZ8kCi9izPyM0Jo1p2Gc19r-8-3mkfpZ0vs,15498 +werkzeug/contrib/jsrouting.py,sha256=QTmgeDoKXvNK02KzXgx9lr3cAH6fAzpwF5bBdPNvJPs,8564 +werkzeug/contrib/sessions.py,sha256=wXPc0K-bI8VRuaeeTLvfxMk62FlCBb7-i2ACR1v4Ik0,12450 +werkzeug/debug/console.py,sha256=pzd4NmCmEUQ0Oxa1l1FSujBQUIv8U02CtMVnQmaEX5E,5557 +werkzeug/debug/repr.py,sha256=PqLZIJbL6FlAmgjmUeZ3b0J3FmM8Ocd3tng3o1EwBDU,9350 +werkzeug/debug/__init__.py,sha256=x5Wp4s4hMQK-uTsvHwmSDPxnROGaJ2LiX6XzX75Lin8,7800 +werkzeug/debug/tbtools.py,sha256=NbHBRvqsllp89aCFP9RELm-_xNd6R0seiVHx0Q85t7Y,16913 +werkzeug/debug/shared/less.png,sha256=-4-kNRaXJSONVLahrQKUxMwXGm9R4OnZ9SxDGpHlIR4,191 +werkzeug/debug/shared/source.png,sha256=RoGcBTE4CyCB85GBuDGTFlAnUqxwTBiIfDqW15EpnUQ,818 +werkzeug/debug/shared/debugger.js,sha256=YoeX5PlYuX1vSeufjCuCHXaoHQy2gpIm7FC0O9pq9PA,6345 +werkzeug/debug/shared/style.css,sha256=Yeipe9D_NlbxztN0dEazATYBLwGtkrGdbXtVYkJJK0U,6075 +werkzeug/debug/shared/console.png,sha256=bxax6RXXlvOij_KeqvSNX0ojJf83YbnZ7my-3Gx9w2A,507 +werkzeug/debug/shared/FONT_LICENSE,sha256=LwAVEI1oYnvXiNMT9SnCH_TaLCxCpeHziDrMg0gPkAI,4673 +werkzeug/debug/shared/jquery.js,sha256=UXNk8tRRYvtQN0N7W2y5U9ANmys7ebqH2f5X6m7mBww,78601 +werkzeug/debug/shared/ubuntu.ttf,sha256=1eaHFyepmy4FyDvjLVzpITrGEBu_CZYY94jE0nED1c0,70220 +werkzeug/debug/shared/more.png,sha256=GngN7CioHQoV58rH6ojnkYi8c_qED2Aka5FO5UXrReY,200 +Werkzeug-0.10.4.dist-info/DESCRIPTION.rst,sha256=5sTwZ_Sj5aeEN8mlcOdNJ_ng40HiGazGmILLyTMX8o0,1595 +Werkzeug-0.10.4.dist-info/metadata.json,sha256=D5TEHaD4DmqnhCQ00QghGhJerVwqszsbpOOzFS3Bo44,851 +Werkzeug-0.10.4.dist-info/RECORD,, +Werkzeug-0.10.4.dist-info/top_level.txt,sha256=QRyj2VjwJoQkrwjwFIOlB8Xg3r9un0NtqVHQF-15xaw,9 +Werkzeug-0.10.4.dist-info/WHEEL,sha256=AvR0WeTpDaxT645bl5FQxUK6NPsTls2ttpcGJg3j1Xg,110 +Werkzeug-0.10.4.dist-info/METADATA,sha256=S_im0ZAXS1A-ReOQFPve62nnhH0aTnewuDvnNltATd4,2301 +werkzeug/_reloader.pyc,, +werkzeug/contrib/testtools.pyc,, +werkzeug/formparser.pyc,, +werkzeug/_compat.pyc,, +werkzeug/posixemulation.pyc,, +werkzeug/wsgi.pyc,, +werkzeug/serving.pyc,, +werkzeug/contrib/__init__.pyc,, +werkzeug/contrib/iterio.pyc,, +werkzeug/test.pyc,, +werkzeug/contrib/limiter.pyc,, +werkzeug/debug/tbtools.pyc,, +werkzeug/contrib/sessions.pyc,, +werkzeug/local.pyc,, +werkzeug/utils.pyc,, +werkzeug/_internal.pyc,, +werkzeug/security.pyc,, +werkzeug/contrib/cache.pyc,, +werkzeug/contrib/securecookie.pyc,, +werkzeug/script.pyc,, +werkzeug/routing.pyc,, +werkzeug/wrappers.pyc,, +werkzeug/contrib/jsrouting.pyc,, +werkzeug/contrib/fixers.pyc,, +werkzeug/contrib/profiler.pyc,, +werkzeug/debug/console.pyc,, +werkzeug/debug/__init__.pyc,, +werkzeug/datastructures.pyc,, +werkzeug/http.pyc,, +werkzeug/urls.pyc,, +werkzeug/contrib/lint.pyc,, +werkzeug/contrib/wrappers.pyc,, +werkzeug/exceptions.pyc,, +werkzeug/contrib/atom.pyc,, +werkzeug/__init__.pyc,, +werkzeug/testapp.pyc,, +werkzeug/useragents.pyc,, +werkzeug/debug/repr.pyc,, diff --git a/lib/Werkzeug-0.10.4.dist-info/WHEEL b/lib/Werkzeug-0.10.4.dist-info/WHEEL new file mode 100644 index 0000000..9dff69d --- /dev/null +++ b/lib/Werkzeug-0.10.4.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.24.0) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/lib/Werkzeug-0.10.4.dist-info/metadata.json b/lib/Werkzeug-0.10.4.dist-info/metadata.json new file mode 100644 index 0000000..d8c519e --- /dev/null +++ b/lib/Werkzeug-0.10.4.dist-info/metadata.json @@ -0,0 +1 @@ +{"license": "BSD", "name": "Werkzeug", "metadata_version": "2.0", "generator": "bdist_wheel (0.24.0)", "summary": "The Swiss Army knife of Python web development", "platform": "any", "version": "0.10.4", "extensions": {"python.details": {"project_urls": {"Home": "http://werkzeug.pocoo.org/"}, "document_names": {"description": "DESCRIPTION.rst"}, "contacts": [{"role": "author", "email": "armin.ronacher@active-4.com", "name": "Armin Ronacher"}]}}, "classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Software Development :: Libraries :: Python Modules"]} \ No newline at end of file diff --git a/lib/Werkzeug-0.10.4.dist-info/top_level.txt b/lib/Werkzeug-0.10.4.dist-info/top_level.txt new file mode 100644 index 0000000..6fe8da8 --- /dev/null +++ b/lib/Werkzeug-0.10.4.dist-info/top_level.txt @@ -0,0 +1 @@ +werkzeug diff --git a/lib/easy_install.py b/lib/easy_install.py new file mode 100644 index 0000000..d87e984 --- /dev/null +++ b/lib/easy_install.py @@ -0,0 +1,5 @@ +"""Run the EasyInstall command""" + +if __name__ == '__main__': + from setuptools.command.easy_install import main + main() diff --git a/lib/flask/__init__.py b/lib/flask/__init__.py new file mode 100644 index 0000000..3fd8908 --- /dev/null +++ b/lib/flask/__init__.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- +""" + flask + ~~~~~ + + A microframework based on Werkzeug. It's extensively documented + and follows best practice patterns. + + :copyright: (c) 2011 by Armin Ronacher. + :license: BSD, see LICENSE for more details. +""" + +__version__ = '0.10.1' + +# utilities we import from Werkzeug and Jinja2 that are unused +# in the module but are exported as public interface. +from werkzeug.exceptions import abort +from werkzeug.utils import redirect +from jinja2 import Markup, escape + +from .app import Flask, Request, Response +from .config import Config +from .helpers import url_for, flash, send_file, send_from_directory, \ + get_flashed_messages, get_template_attribute, make_response, safe_join, \ + stream_with_context +from .globals import current_app, g, request, session, _request_ctx_stack, \ + _app_ctx_stack +from .ctx import has_request_context, has_app_context, \ + after_this_request, copy_current_request_context +from .module import Module +from .blueprints import Blueprint +from .templating import render_template, render_template_string + +# the signals +from .signals import signals_available, template_rendered, request_started, \ + request_finished, got_request_exception, request_tearing_down, \ + appcontext_tearing_down, appcontext_pushed, \ + appcontext_popped, message_flashed + +# We're not exposing the actual json module but a convenient wrapper around +# it. +from . import json + +# This was the only thing that flask used to export at one point and it had +# a more generic name. +jsonify = json.jsonify + +# backwards compat, goes away in 1.0 +from .sessions import SecureCookieSession as Session +json_available = True diff --git a/lib/flask/__init__.pyc b/lib/flask/__init__.pyc new file mode 100644 index 0000000..9dc02fb Binary files /dev/null and b/lib/flask/__init__.pyc differ diff --git a/lib/flask/_compat.py b/lib/flask/_compat.py new file mode 100644 index 0000000..c342884 --- /dev/null +++ b/lib/flask/_compat.py @@ -0,0 +1,73 @@ +# -*- coding: utf-8 -*- +""" + flask._compat + ~~~~~~~~~~~~~ + + Some py2/py3 compatibility support based on a stripped down + version of six so we don't have to depend on a specific version + of it. + + :copyright: (c) 2013 by Armin Ronacher. + :license: BSD, see LICENSE for more details. +""" +import sys + +PY2 = sys.version_info[0] == 2 +_identity = lambda x: x + + +if not PY2: + text_type = str + string_types = (str,) + integer_types = (int, ) + + iterkeys = lambda d: iter(d.keys()) + itervalues = lambda d: iter(d.values()) + iteritems = lambda d: iter(d.items()) + + from io import StringIO + + def reraise(tp, value, tb=None): + if value.__traceback__ is not tb: + raise value.with_traceback(tb) + raise value + + implements_to_string = _identity + +else: + text_type = unicode + string_types = (str, unicode) + integer_types = (int, long) + + iterkeys = lambda d: d.iterkeys() + itervalues = lambda d: d.itervalues() + iteritems = lambda d: d.iteritems() + + from cStringIO import StringIO + + exec('def reraise(tp, value, tb=None):\n raise tp, value, tb') + + def implements_to_string(cls): + cls.__unicode__ = cls.__str__ + cls.__str__ = lambda x: x.__unicode__().encode('utf-8') + return cls + + +def with_metaclass(meta, *bases): + # This requires a bit of explanation: the basic idea is to make a + # dummy metaclass for one level of class instantiation that replaces + # itself with the actual metaclass. Because of internal type checks + # we also need to make sure that we downgrade the custom metaclass + # for one level to something closer to type (that's why __call__ and + # __init__ comes back from type etc.). + # + # This has the advantage over six.with_metaclass in that it does not + # introduce dummy classes into the final MRO. + class metaclass(meta): + __call__ = type.__call__ + __init__ = type.__init__ + def __new__(cls, name, this_bases, d): + if this_bases is None: + return type.__new__(cls, name, (), d) + return meta(name, bases, d) + return metaclass('temporary_class', None, {}) diff --git a/lib/flask/_compat.pyc b/lib/flask/_compat.pyc new file mode 100644 index 0000000..aaca4b8 Binary files /dev/null and b/lib/flask/_compat.pyc differ diff --git a/lib/flask/app.py b/lib/flask/app.py new file mode 100644 index 0000000..addc40b --- /dev/null +++ b/lib/flask/app.py @@ -0,0 +1,1842 @@ +# -*- coding: utf-8 -*- +""" + flask.app + ~~~~~~~~~ + + This module implements the central WSGI application object. + + :copyright: (c) 2011 by Armin Ronacher. + :license: BSD, see LICENSE for more details. +""" + +import os +import sys +from threading import Lock +from datetime import timedelta +from itertools import chain +from functools import update_wrapper + +from werkzeug.datastructures import ImmutableDict +from werkzeug.routing import Map, Rule, RequestRedirect, BuildError +from werkzeug.exceptions import HTTPException, InternalServerError, \ + MethodNotAllowed, BadRequest + +from .helpers import _PackageBoundObject, url_for, get_flashed_messages, \ + locked_cached_property, _endpoint_from_view_func, find_package +from . import json +from .wrappers import Request, Response +from .config import ConfigAttribute, Config +from .ctx import RequestContext, AppContext, _AppCtxGlobals +from .globals import _request_ctx_stack, request, session, g +from .sessions import SecureCookieSessionInterface +from .module import blueprint_is_module +from .templating import DispatchingJinjaLoader, Environment, \ + _default_template_ctx_processor +from .signals import request_started, request_finished, got_request_exception, \ + request_tearing_down, appcontext_tearing_down +from ._compat import reraise, string_types, text_type, integer_types + +# a lock used for logger initialization +_logger_lock = Lock() + + +def _make_timedelta(value): + if not isinstance(value, timedelta): + return timedelta(seconds=value) + return value + + +def setupmethod(f): + """Wraps a method so that it performs a check in debug mode if the + first request was already handled. + """ + def wrapper_func(self, *args, **kwargs): + if self.debug and self._got_first_request: + raise AssertionError('A setup function was called after the ' + 'first request was handled. This usually indicates a bug ' + 'in the application where a module was not imported ' + 'and decorators or other functionality was called too late.\n' + 'To fix this make sure to import all your view modules, ' + 'database models and everything related at a central place ' + 'before the application starts serving requests.') + return f(self, *args, **kwargs) + return update_wrapper(wrapper_func, f) + + +class Flask(_PackageBoundObject): + """The flask object implements a WSGI application and acts as the central + object. It is passed the name of the module or package of the + application. Once it is created it will act as a central registry for + the view functions, the URL rules, template configuration and much more. + + The name of the package is used to resolve resources from inside the + package or the folder the module is contained in depending on if the + package parameter resolves to an actual python package (a folder with + an `__init__.py` file inside) or a standard module (just a `.py` file). + + For more information about resource loading, see :func:`open_resource`. + + Usually you create a :class:`Flask` instance in your main module or + in the `__init__.py` file of your package like this:: + + from flask import Flask + app = Flask(__name__) + + .. admonition:: About the First Parameter + + The idea of the first parameter is to give Flask an idea what + belongs to your application. This name is used to find resources + on the file system, can be used by extensions to improve debugging + information and a lot more. + + So it's important what you provide there. If you are using a single + module, `__name__` is always the correct value. If you however are + using a package, it's usually recommended to hardcode the name of + your package there. + + For example if your application is defined in `yourapplication/app.py` + you should create it with one of the two versions below:: + + app = Flask('yourapplication') + app = Flask(__name__.split('.')[0]) + + Why is that? The application will work even with `__name__`, thanks + to how resources are looked up. However it will make debugging more + painful. Certain extensions can make assumptions based on the + import name of your application. For example the Flask-SQLAlchemy + extension will look for the code in your application that triggered + an SQL query in debug mode. If the import name is not properly set + up, that debugging information is lost. (For example it would only + pick up SQL queries in `yourapplication.app` and not + `yourapplication.views.frontend`) + + .. versionadded:: 0.7 + The `static_url_path`, `static_folder`, and `template_folder` + parameters were added. + + .. versionadded:: 0.8 + The `instance_path` and `instance_relative_config` parameters were + added. + + :param import_name: the name of the application package + :param static_url_path: can be used to specify a different path for the + static files on the web. Defaults to the name + of the `static_folder` folder. + :param static_folder: the folder with static files that should be served + at `static_url_path`. Defaults to the ``'static'`` + folder in the root path of the application. + :param template_folder: the folder that contains the templates that should + be used by the application. Defaults to + ``'templates'`` folder in the root path of the + application. + :param instance_path: An alternative instance path for the application. + By default the folder ``'instance'`` next to the + package or module is assumed to be the instance + path. + :param instance_relative_config: if set to `True` relative filenames + for loading the config are assumed to + be relative to the instance path instead + of the application root. + """ + + #: The class that is used for request objects. See :class:`~flask.Request` + #: for more information. + request_class = Request + + #: The class that is used for response objects. See + #: :class:`~flask.Response` for more information. + response_class = Response + + #: The class that is used for the :data:`~flask.g` instance. + #: + #: Example use cases for a custom class: + #: + #: 1. Store arbitrary attributes on flask.g. + #: 2. Add a property for lazy per-request database connectors. + #: 3. Return None instead of AttributeError on expected attributes. + #: 4. Raise exception if an unexpected attr is set, a "controlled" flask.g. + #: + #: In Flask 0.9 this property was called `request_globals_class` but it + #: was changed in 0.10 to :attr:`app_ctx_globals_class` because the + #: flask.g object is not application context scoped. + #: + #: .. versionadded:: 0.10 + app_ctx_globals_class = _AppCtxGlobals + + # Backwards compatibility support + def _get_request_globals_class(self): + return self.app_ctx_globals_class + def _set_request_globals_class(self, value): + from warnings import warn + warn(DeprecationWarning('request_globals_class attribute is now ' + 'called app_ctx_globals_class')) + self.app_ctx_globals_class = value + request_globals_class = property(_get_request_globals_class, + _set_request_globals_class) + del _get_request_globals_class, _set_request_globals_class + + #: The debug flag. Set this to `True` to enable debugging of the + #: application. In debug mode the debugger will kick in when an unhandled + #: exception occurs and the integrated server will automatically reload + #: the application if changes in the code are detected. + #: + #: This attribute can also be configured from the config with the `DEBUG` + #: configuration key. Defaults to `False`. + debug = ConfigAttribute('DEBUG') + + #: The testing flag. Set this to `True` to enable the test mode of + #: Flask extensions (and in the future probably also Flask itself). + #: For example this might activate unittest helpers that have an + #: additional runtime cost which should not be enabled by default. + #: + #: If this is enabled and PROPAGATE_EXCEPTIONS is not changed from the + #: default it's implicitly enabled. + #: + #: This attribute can also be configured from the config with the + #: `TESTING` configuration key. Defaults to `False`. + testing = ConfigAttribute('TESTING') + + #: If a secret key is set, cryptographic components can use this to + #: sign cookies and other things. Set this to a complex random value + #: when you want to use the secure cookie for instance. + #: + #: This attribute can also be configured from the config with the + #: `SECRET_KEY` configuration key. Defaults to `None`. + secret_key = ConfigAttribute('SECRET_KEY') + + #: The secure cookie uses this for the name of the session cookie. + #: + #: This attribute can also be configured from the config with the + #: `SESSION_COOKIE_NAME` configuration key. Defaults to ``'session'`` + session_cookie_name = ConfigAttribute('SESSION_COOKIE_NAME') + + #: A :class:`~datetime.timedelta` which is used to set the expiration + #: date of a permanent session. The default is 31 days which makes a + #: permanent session survive for roughly one month. + #: + #: This attribute can also be configured from the config with the + #: `PERMANENT_SESSION_LIFETIME` configuration key. Defaults to + #: ``timedelta(days=31)`` + permanent_session_lifetime = ConfigAttribute('PERMANENT_SESSION_LIFETIME', + get_converter=_make_timedelta) + + #: Enable this if you want to use the X-Sendfile feature. Keep in + #: mind that the server has to support this. This only affects files + #: sent with the :func:`send_file` method. + #: + #: .. versionadded:: 0.2 + #: + #: This attribute can also be configured from the config with the + #: `USE_X_SENDFILE` configuration key. Defaults to `False`. + use_x_sendfile = ConfigAttribute('USE_X_SENDFILE') + + #: The name of the logger to use. By default the logger name is the + #: package name passed to the constructor. + #: + #: .. versionadded:: 0.4 + logger_name = ConfigAttribute('LOGGER_NAME') + + #: Enable the deprecated module support? This is active by default + #: in 0.7 but will be changed to False in 0.8. With Flask 1.0 modules + #: will be removed in favor of Blueprints + enable_modules = True + + #: The logging format used for the debug logger. This is only used when + #: the application is in debug mode, otherwise the attached logging + #: handler does the formatting. + #: + #: .. versionadded:: 0.3 + debug_log_format = ( + '-' * 80 + '\n' + + '%(levelname)s in %(module)s [%(pathname)s:%(lineno)d]:\n' + + '%(message)s\n' + + '-' * 80 + ) + + #: The JSON encoder class to use. Defaults to :class:`~flask.json.JSONEncoder`. + #: + #: .. versionadded:: 0.10 + json_encoder = json.JSONEncoder + + #: The JSON decoder class to use. Defaults to :class:`~flask.json.JSONDecoder`. + #: + #: .. versionadded:: 0.10 + json_decoder = json.JSONDecoder + + #: Options that are passed directly to the Jinja2 environment. + jinja_options = ImmutableDict( + extensions=['jinja2.ext.autoescape', 'jinja2.ext.with_'] + ) + + #: Default configuration parameters. + default_config = ImmutableDict({ + 'DEBUG': False, + 'TESTING': False, + 'PROPAGATE_EXCEPTIONS': None, + 'PRESERVE_CONTEXT_ON_EXCEPTION': None, + 'SECRET_KEY': None, + 'PERMANENT_SESSION_LIFETIME': timedelta(days=31), + 'USE_X_SENDFILE': False, + 'LOGGER_NAME': None, + 'SERVER_NAME': None, + 'APPLICATION_ROOT': None, + 'SESSION_COOKIE_NAME': 'session', + 'SESSION_COOKIE_DOMAIN': None, + 'SESSION_COOKIE_PATH': None, + 'SESSION_COOKIE_HTTPONLY': True, + 'SESSION_COOKIE_SECURE': False, + 'MAX_CONTENT_LENGTH': None, + 'SEND_FILE_MAX_AGE_DEFAULT': 12 * 60 * 60, # 12 hours + 'TRAP_BAD_REQUEST_ERRORS': False, + 'TRAP_HTTP_EXCEPTIONS': False, + 'PREFERRED_URL_SCHEME': 'http', + 'JSON_AS_ASCII': True, + 'JSON_SORT_KEYS': True, + 'JSONIFY_PRETTYPRINT_REGULAR': True, + }) + + #: The rule object to use for URL rules created. This is used by + #: :meth:`add_url_rule`. Defaults to :class:`werkzeug.routing.Rule`. + #: + #: .. versionadded:: 0.7 + url_rule_class = Rule + + #: the test client that is used with when `test_client` is used. + #: + #: .. versionadded:: 0.7 + test_client_class = None + + #: the session interface to use. By default an instance of + #: :class:`~flask.sessions.SecureCookieSessionInterface` is used here. + #: + #: .. versionadded:: 0.8 + session_interface = SecureCookieSessionInterface() + + def __init__(self, import_name, static_path=None, static_url_path=None, + static_folder='static', template_folder='templates', + instance_path=None, instance_relative_config=False): + _PackageBoundObject.__init__(self, import_name, + template_folder=template_folder) + if static_path is not None: + from warnings import warn + warn(DeprecationWarning('static_path is now called ' + 'static_url_path'), stacklevel=2) + static_url_path = static_path + + if static_url_path is not None: + self.static_url_path = static_url_path + if static_folder is not None: + self.static_folder = static_folder + if instance_path is None: + instance_path = self.auto_find_instance_path() + elif not os.path.isabs(instance_path): + raise ValueError('If an instance path is provided it must be ' + 'absolute. A relative path was given instead.') + + #: Holds the path to the instance folder. + #: + #: .. versionadded:: 0.8 + self.instance_path = instance_path + + #: The configuration dictionary as :class:`Config`. This behaves + #: exactly like a regular dictionary but supports additional methods + #: to load a config from files. + self.config = self.make_config(instance_relative_config) + + # Prepare the deferred setup of the logger. + self._logger = None + self.logger_name = self.import_name + + #: A dictionary of all view functions registered. The keys will + #: be function names which are also used to generate URLs and + #: the values are the function objects themselves. + #: To register a view function, use the :meth:`route` decorator. + self.view_functions = {} + + # support for the now deprecated `error_handlers` attribute. The + # :attr:`error_handler_spec` shall be used now. + self._error_handlers = {} + + #: A dictionary of all registered error handlers. The key is `None` + #: for error handlers active on the application, otherwise the key is + #: the name of the blueprint. Each key points to another dictionary + #: where they key is the status code of the http exception. The + #: special key `None` points to a list of tuples where the first item + #: is the class for the instance check and the second the error handler + #: function. + #: + #: To register a error handler, use the :meth:`errorhandler` + #: decorator. + self.error_handler_spec = {None: self._error_handlers} + + #: A list of functions that are called when :meth:`url_for` raises a + #: :exc:`~werkzeug.routing.BuildError`. Each function registered here + #: is called with `error`, `endpoint` and `values`. If a function + #: returns `None` or raises a `BuildError` the next function is + #: tried. + #: + #: .. versionadded:: 0.9 + self.url_build_error_handlers = [] + + #: A dictionary with lists of functions that should be called at the + #: beginning of the request. The key of the dictionary is the name of + #: the blueprint this function is active for, `None` for all requests. + #: This can for example be used to open database connections or + #: getting hold of the currently logged in user. To register a + #: function here, use the :meth:`before_request` decorator. + self.before_request_funcs = {} + + #: A lists of functions that should be called at the beginning of the + #: first request to this instance. To register a function here, use + #: the :meth:`before_first_request` decorator. + #: + #: .. versionadded:: 0.8 + self.before_first_request_funcs = [] + + #: A dictionary with lists of functions that should be called after + #: each request. The key of the dictionary is the name of the blueprint + #: this function is active for, `None` for all requests. This can for + #: example be used to open database connections or getting hold of the + #: currently logged in user. To register a function here, use the + #: :meth:`after_request` decorator. + self.after_request_funcs = {} + + #: A dictionary with lists of functions that are called after + #: each request, even if an exception has occurred. The key of the + #: dictionary is the name of the blueprint this function is active for, + #: `None` for all requests. These functions are not allowed to modify + #: the request, and their return values are ignored. If an exception + #: occurred while processing the request, it gets passed to each + #: teardown_request function. To register a function here, use the + #: :meth:`teardown_request` decorator. + #: + #: .. versionadded:: 0.7 + self.teardown_request_funcs = {} + + #: A list of functions that are called when the application context + #: is destroyed. Since the application context is also torn down + #: if the request ends this is the place to store code that disconnects + #: from databases. + #: + #: .. versionadded:: 0.9 + self.teardown_appcontext_funcs = [] + + #: A dictionary with lists of functions that can be used as URL + #: value processor functions. Whenever a URL is built these functions + #: are called to modify the dictionary of values in place. The key + #: `None` here is used for application wide + #: callbacks, otherwise the key is the name of the blueprint. + #: Each of these functions has the chance to modify the dictionary + #: + #: .. versionadded:: 0.7 + self.url_value_preprocessors = {} + + #: A dictionary with lists of functions that can be used as URL value + #: preprocessors. The key `None` here is used for application wide + #: callbacks, otherwise the key is the name of the blueprint. + #: Each of these functions has the chance to modify the dictionary + #: of URL values before they are used as the keyword arguments of the + #: view function. For each function registered this one should also + #: provide a :meth:`url_defaults` function that adds the parameters + #: automatically again that were removed that way. + #: + #: .. versionadded:: 0.7 + self.url_default_functions = {} + + #: A dictionary with list of functions that are called without argument + #: to populate the template context. The key of the dictionary is the + #: name of the blueprint this function is active for, `None` for all + #: requests. Each returns a dictionary that the template context is + #: updated with. To register a function here, use the + #: :meth:`context_processor` decorator. + self.template_context_processors = { + None: [_default_template_ctx_processor] + } + + #: all the attached blueprints in a dictionary by name. Blueprints + #: can be attached multiple times so this dictionary does not tell + #: you how often they got attached. + #: + #: .. versionadded:: 0.7 + self.blueprints = {} + + #: a place where extensions can store application specific state. For + #: example this is where an extension could store database engines and + #: similar things. For backwards compatibility extensions should register + #: themselves like this:: + #: + #: if not hasattr(app, 'extensions'): + #: app.extensions = {} + #: app.extensions['extensionname'] = SomeObject() + #: + #: The key must match the name of the `flaskext` module. For example in + #: case of a "Flask-Foo" extension in `flaskext.foo`, the key would be + #: ``'foo'``. + #: + #: .. versionadded:: 0.7 + self.extensions = {} + + #: The :class:`~werkzeug.routing.Map` for this instance. You can use + #: this to change the routing converters after the class was created + #: but before any routes are connected. Example:: + #: + #: from werkzeug.routing import BaseConverter + #: + #: class ListConverter(BaseConverter): + #: def to_python(self, value): + #: return value.split(',') + #: def to_url(self, values): + #: return ','.join(BaseConverter.to_url(value) + #: for value in values) + #: + #: app = Flask(__name__) + #: app.url_map.converters['list'] = ListConverter + self.url_map = Map() + + # tracks internally if the application already handled at least one + # request. + self._got_first_request = False + self._before_request_lock = Lock() + + # register the static folder for the application. Do that even + # if the folder does not exist. First of all it might be created + # while the server is running (usually happens during development) + # but also because google appengine stores static files somewhere + # else when mapped with the .yml file. + if self.has_static_folder: + self.add_url_rule(self.static_url_path + '/', + endpoint='static', + view_func=self.send_static_file) + + def _get_error_handlers(self): + from warnings import warn + warn(DeprecationWarning('error_handlers is deprecated, use the ' + 'new error_handler_spec attribute instead.'), stacklevel=1) + return self._error_handlers + def _set_error_handlers(self, value): + self._error_handlers = value + self.error_handler_spec[None] = value + error_handlers = property(_get_error_handlers, _set_error_handlers) + del _get_error_handlers, _set_error_handlers + + @locked_cached_property + def name(self): + """The name of the application. This is usually the import name + with the difference that it's guessed from the run file if the + import name is main. This name is used as a display name when + Flask needs the name of the application. It can be set and overridden + to change the value. + + .. versionadded:: 0.8 + """ + if self.import_name == '__main__': + fn = getattr(sys.modules['__main__'], '__file__', None) + if fn is None: + return '__main__' + return os.path.splitext(os.path.basename(fn))[0] + return self.import_name + + @property + def propagate_exceptions(self): + """Returns the value of the `PROPAGATE_EXCEPTIONS` configuration + value in case it's set, otherwise a sensible default is returned. + + .. versionadded:: 0.7 + """ + rv = self.config['PROPAGATE_EXCEPTIONS'] + if rv is not None: + return rv + return self.testing or self.debug + + @property + def preserve_context_on_exception(self): + """Returns the value of the `PRESERVE_CONTEXT_ON_EXCEPTION` + configuration value in case it's set, otherwise a sensible default + is returned. + + .. versionadded:: 0.7 + """ + rv = self.config['PRESERVE_CONTEXT_ON_EXCEPTION'] + if rv is not None: + return rv + return self.debug + + @property + def logger(self): + """A :class:`logging.Logger` object for this application. The + default configuration is to log to stderr if the application is + in debug mode. This logger can be used to (surprise) log messages. + Here some examples:: + + app.logger.debug('A value for debugging') + app.logger.warning('A warning occurred (%d apples)', 42) + app.logger.error('An error occurred') + + .. versionadded:: 0.3 + """ + if self._logger and self._logger.name == self.logger_name: + return self._logger + with _logger_lock: + if self._logger and self._logger.name == self.logger_name: + return self._logger + from flask.logging import create_logger + self._logger = rv = create_logger(self) + return rv + + @locked_cached_property + def jinja_env(self): + """The Jinja2 environment used to load templates.""" + return self.create_jinja_environment() + + @property + def got_first_request(self): + """This attribute is set to `True` if the application started + handling the first request. + + .. versionadded:: 0.8 + """ + return self._got_first_request + + def make_config(self, instance_relative=False): + """Used to create the config attribute by the Flask constructor. + The `instance_relative` parameter is passed in from the constructor + of Flask (there named `instance_relative_config`) and indicates if + the config should be relative to the instance path or the root path + of the application. + + .. versionadded:: 0.8 + """ + root_path = self.root_path + if instance_relative: + root_path = self.instance_path + return Config(root_path, self.default_config) + + def auto_find_instance_path(self): + """Tries to locate the instance path if it was not provided to the + constructor of the application class. It will basically calculate + the path to a folder named ``instance`` next to your main file or + the package. + + .. versionadded:: 0.8 + """ + prefix, package_path = find_package(self.import_name) + if prefix is None: + return os.path.join(package_path, 'instance') + return os.path.join(prefix, 'var', self.name + '-instance') + + def open_instance_resource(self, resource, mode='rb'): + """Opens a resource from the application's instance folder + (:attr:`instance_path`). Otherwise works like + :meth:`open_resource`. Instance resources can also be opened for + writing. + + :param resource: the name of the resource. To access resources within + subfolders use forward slashes as separator. + :param mode: resource file opening mode, default is 'rb'. + """ + return open(os.path.join(self.instance_path, resource), mode) + + def create_jinja_environment(self): + """Creates the Jinja2 environment based on :attr:`jinja_options` + and :meth:`select_jinja_autoescape`. Since 0.7 this also adds + the Jinja2 globals and filters after initialization. Override + this function to customize the behavior. + + .. versionadded:: 0.5 + """ + options = dict(self.jinja_options) + if 'autoescape' not in options: + options['autoescape'] = self.select_jinja_autoescape + rv = Environment(self, **options) + rv.globals.update( + url_for=url_for, + get_flashed_messages=get_flashed_messages, + config=self.config, + # request, session and g are normally added with the + # context processor for efficiency reasons but for imported + # templates we also want the proxies in there. + request=request, + session=session, + g=g + ) + rv.filters['tojson'] = json.tojson_filter + return rv + + def create_global_jinja_loader(self): + """Creates the loader for the Jinja2 environment. Can be used to + override just the loader and keeping the rest unchanged. It's + discouraged to override this function. Instead one should override + the :meth:`jinja_loader` function instead. + + The global loader dispatches between the loaders of the application + and the individual blueprints. + + .. versionadded:: 0.7 + """ + return DispatchingJinjaLoader(self) + + def init_jinja_globals(self): + """Deprecated. Used to initialize the Jinja2 globals. + + .. versionadded:: 0.5 + .. versionchanged:: 0.7 + This method is deprecated with 0.7. Override + :meth:`create_jinja_environment` instead. + """ + + def select_jinja_autoescape(self, filename): + """Returns `True` if autoescaping should be active for the given + template name. + + .. versionadded:: 0.5 + """ + if filename is None: + return False + return filename.endswith(('.html', '.htm', '.xml', '.xhtml')) + + def update_template_context(self, context): + """Update the template context with some commonly used variables. + This injects request, session, config and g into the template + context as well as everything template context processors want + to inject. Note that the as of Flask 0.6, the original values + in the context will not be overridden if a context processor + decides to return a value with the same key. + + :param context: the context as a dictionary that is updated in place + to add extra variables. + """ + funcs = self.template_context_processors[None] + reqctx = _request_ctx_stack.top + if reqctx is not None: + bp = reqctx.request.blueprint + if bp is not None and bp in self.template_context_processors: + funcs = chain(funcs, self.template_context_processors[bp]) + orig_ctx = context.copy() + for func in funcs: + context.update(func()) + # make sure the original values win. This makes it possible to + # easier add new variables in context processors without breaking + # existing views. + context.update(orig_ctx) + + def run(self, host=None, port=None, debug=None, **options): + """Runs the application on a local development server. If the + :attr:`debug` flag is set the server will automatically reload + for code changes and show a debugger in case an exception happened. + + If you want to run the application in debug mode, but disable the + code execution on the interactive debugger, you can pass + ``use_evalex=False`` as parameter. This will keep the debugger's + traceback screen active, but disable code execution. + + .. admonition:: Keep in Mind + + Flask will suppress any server error with a generic error page + unless it is in debug mode. As such to enable just the + interactive debugger without the code reloading, you have to + invoke :meth:`run` with ``debug=True`` and ``use_reloader=False``. + Setting ``use_debugger`` to `True` without being in debug mode + won't catch any exceptions because there won't be any to + catch. + + .. versionchanged:: 0.10 + The default port is now picked from the ``SERVER_NAME`` variable. + + :param host: the hostname to listen on. Set this to ``'0.0.0.0'`` to + have the server available externally as well. Defaults to + ``'127.0.0.1'``. + :param port: the port of the webserver. Defaults to ``5000`` or the + port defined in the ``SERVER_NAME`` config variable if + present. + :param debug: if given, enable or disable debug mode. + See :attr:`debug`. + :param options: the options to be forwarded to the underlying + Werkzeug server. See + :func:`werkzeug.serving.run_simple` for more + information. + """ + from werkzeug.serving import run_simple + if host is None: + host = '127.0.0.1' + if port is None: + server_name = self.config['SERVER_NAME'] + if server_name and ':' in server_name: + port = int(server_name.rsplit(':', 1)[1]) + else: + port = 5000 + if debug is not None: + self.debug = bool(debug) + options.setdefault('use_reloader', self.debug) + options.setdefault('use_debugger', self.debug) + try: + run_simple(host, port, self, **options) + finally: + # reset the first request information if the development server + # resetted normally. This makes it possible to restart the server + # without reloader and that stuff from an interactive shell. + self._got_first_request = False + + def test_client(self, use_cookies=True): + """Creates a test client for this application. For information + about unit testing head over to :ref:`testing`. + + Note that if you are testing for assertions or exceptions in your + application code, you must set ``app.testing = True`` in order for the + exceptions to propagate to the test client. Otherwise, the exception + will be handled by the application (not visible to the test client) and + the only indication of an AssertionError or other exception will be a + 500 status code response to the test client. See the :attr:`testing` + attribute. For example:: + + app.testing = True + client = app.test_client() + + The test client can be used in a `with` block to defer the closing down + of the context until the end of the `with` block. This is useful if + you want to access the context locals for testing:: + + with app.test_client() as c: + rv = c.get('/?vodka=42') + assert request.args['vodka'] == '42' + + See :class:`~flask.testing.FlaskClient` for more information. + + .. versionchanged:: 0.4 + added support for `with` block usage for the client. + + .. versionadded:: 0.7 + The `use_cookies` parameter was added as well as the ability + to override the client to be used by setting the + :attr:`test_client_class` attribute. + """ + cls = self.test_client_class + if cls is None: + from flask.testing import FlaskClient as cls + return cls(self, self.response_class, use_cookies=use_cookies) + + def open_session(self, request): + """Creates or opens a new session. Default implementation stores all + session data in a signed cookie. This requires that the + :attr:`secret_key` is set. Instead of overriding this method + we recommend replacing the :class:`session_interface`. + + :param request: an instance of :attr:`request_class`. + """ + return self.session_interface.open_session(self, request) + + def save_session(self, session, response): + """Saves the session if it needs updates. For the default + implementation, check :meth:`open_session`. Instead of overriding this + method we recommend replacing the :class:`session_interface`. + + :param session: the session to be saved (a + :class:`~werkzeug.contrib.securecookie.SecureCookie` + object) + :param response: an instance of :attr:`response_class` + """ + return self.session_interface.save_session(self, session, response) + + def make_null_session(self): + """Creates a new instance of a missing session. Instead of overriding + this method we recommend replacing the :class:`session_interface`. + + .. versionadded:: 0.7 + """ + return self.session_interface.make_null_session(self) + + def register_module(self, module, **options): + """Registers a module with this application. The keyword argument + of this function are the same as the ones for the constructor of the + :class:`Module` class and will override the values of the module if + provided. + + .. versionchanged:: 0.7 + The module system was deprecated in favor for the blueprint + system. + """ + assert blueprint_is_module(module), 'register_module requires ' \ + 'actual module objects. Please upgrade to blueprints though.' + if not self.enable_modules: + raise RuntimeError('Module support was disabled but code ' + 'attempted to register a module named %r' % module) + else: + from warnings import warn + warn(DeprecationWarning('Modules are deprecated. Upgrade to ' + 'using blueprints. Have a look into the documentation for ' + 'more information. If this module was registered by a ' + 'Flask-Extension upgrade the extension or contact the author ' + 'of that extension instead. (Registered %r)' % module), + stacklevel=2) + + self.register_blueprint(module, **options) + + @setupmethod + def register_blueprint(self, blueprint, **options): + """Registers a blueprint on the application. + + .. versionadded:: 0.7 + """ + first_registration = False + if blueprint.name in self.blueprints: + assert self.blueprints[blueprint.name] is blueprint, \ + 'A blueprint\'s name collision occurred between %r and ' \ + '%r. Both share the same name "%s". Blueprints that ' \ + 'are created on the fly need unique names.' % \ + (blueprint, self.blueprints[blueprint.name], blueprint.name) + else: + self.blueprints[blueprint.name] = blueprint + first_registration = True + blueprint.register(self, options, first_registration) + + @setupmethod + def add_url_rule(self, rule, endpoint=None, view_func=None, **options): + """Connects a URL rule. Works exactly like the :meth:`route` + decorator. If a view_func is provided it will be registered with the + endpoint. + + Basically this example:: + + @app.route('/') + def index(): + pass + + Is equivalent to the following:: + + def index(): + pass + app.add_url_rule('/', 'index', index) + + If the view_func is not provided you will need to connect the endpoint + to a view function like so:: + + app.view_functions['index'] = index + + Internally :meth:`route` invokes :meth:`add_url_rule` so if you want + to customize the behavior via subclassing you only need to change + this method. + + For more information refer to :ref:`url-route-registrations`. + + .. versionchanged:: 0.2 + `view_func` parameter added. + + .. versionchanged:: 0.6 + `OPTIONS` is added automatically as method. + + :param rule: the URL rule as string + :param endpoint: the endpoint for the registered URL rule. Flask + itself assumes the name of the view function as + endpoint + :param view_func: the function to call when serving a request to the + provided endpoint + :param options: the options to be forwarded to the underlying + :class:`~werkzeug.routing.Rule` object. A change + to Werkzeug is handling of method options. methods + is a list of methods this rule should be limited + to (`GET`, `POST` etc.). By default a rule + just listens for `GET` (and implicitly `HEAD`). + Starting with Flask 0.6, `OPTIONS` is implicitly + added and handled by the standard request handling. + """ + if endpoint is None: + endpoint = _endpoint_from_view_func(view_func) + options['endpoint'] = endpoint + methods = options.pop('methods', None) + + # if the methods are not given and the view_func object knows its + # methods we can use that instead. If neither exists, we go with + # a tuple of only `GET` as default. + if methods is None: + methods = getattr(view_func, 'methods', None) or ('GET',) + methods = set(methods) + + # Methods that should always be added + required_methods = set(getattr(view_func, 'required_methods', ())) + + # starting with Flask 0.8 the view_func object can disable and + # force-enable the automatic options handling. + provide_automatic_options = getattr(view_func, + 'provide_automatic_options', None) + + if provide_automatic_options is None: + if 'OPTIONS' not in methods: + provide_automatic_options = True + required_methods.add('OPTIONS') + else: + provide_automatic_options = False + + # Add the required methods now. + methods |= required_methods + + # due to a werkzeug bug we need to make sure that the defaults are + # None if they are an empty dictionary. This should not be necessary + # with Werkzeug 0.7 + options['defaults'] = options.get('defaults') or None + + rule = self.url_rule_class(rule, methods=methods, **options) + rule.provide_automatic_options = provide_automatic_options + + self.url_map.add(rule) + if view_func is not None: + old_func = self.view_functions.get(endpoint) + if old_func is not None and old_func != view_func: + raise AssertionError('View function mapping is overwriting an ' + 'existing endpoint function: %s' % endpoint) + self.view_functions[endpoint] = view_func + + def route(self, rule, **options): + """A decorator that is used to register a view function for a + given URL rule. This does the same thing as :meth:`add_url_rule` + but is intended for decorator usage:: + + @app.route('/') + def index(): + return 'Hello World' + + For more information refer to :ref:`url-route-registrations`. + + :param rule: the URL rule as string + :param endpoint: the endpoint for the registered URL rule. Flask + itself assumes the name of the view function as + endpoint + :param options: the options to be forwarded to the underlying + :class:`~werkzeug.routing.Rule` object. A change + to Werkzeug is handling of method options. methods + is a list of methods this rule should be limited + to (`GET`, `POST` etc.). By default a rule + just listens for `GET` (and implicitly `HEAD`). + Starting with Flask 0.6, `OPTIONS` is implicitly + added and handled by the standard request handling. + """ + def decorator(f): + endpoint = options.pop('endpoint', None) + self.add_url_rule(rule, endpoint, f, **options) + return f + return decorator + + @setupmethod + def endpoint(self, endpoint): + """A decorator to register a function as an endpoint. + Example:: + + @app.endpoint('example.endpoint') + def example(): + return "example" + + :param endpoint: the name of the endpoint + """ + def decorator(f): + self.view_functions[endpoint] = f + return f + return decorator + + @setupmethod + def errorhandler(self, code_or_exception): + """A decorator that is used to register a function give a given + error code. Example:: + + @app.errorhandler(404) + def page_not_found(error): + return 'This page does not exist', 404 + + You can also register handlers for arbitrary exceptions:: + + @app.errorhandler(DatabaseError) + def special_exception_handler(error): + return 'Database connection failed', 500 + + You can also register a function as error handler without using + the :meth:`errorhandler` decorator. The following example is + equivalent to the one above:: + + def page_not_found(error): + return 'This page does not exist', 404 + app.error_handler_spec[None][404] = page_not_found + + Setting error handlers via assignments to :attr:`error_handler_spec` + however is discouraged as it requires fiddling with nested dictionaries + and the special case for arbitrary exception types. + + The first `None` refers to the active blueprint. If the error + handler should be application wide `None` shall be used. + + .. versionadded:: 0.7 + One can now additionally also register custom exception types + that do not necessarily have to be a subclass of the + :class:`~werkzeug.exceptions.HTTPException` class. + + :param code: the code as integer for the handler + """ + def decorator(f): + self._register_error_handler(None, code_or_exception, f) + return f + return decorator + + def register_error_handler(self, code_or_exception, f): + """Alternative error attach function to the :meth:`errorhandler` + decorator that is more straightforward to use for non decorator + usage. + + .. versionadded:: 0.7 + """ + self._register_error_handler(None, code_or_exception, f) + + @setupmethod + def _register_error_handler(self, key, code_or_exception, f): + if isinstance(code_or_exception, HTTPException): + code_or_exception = code_or_exception.code + if isinstance(code_or_exception, integer_types): + assert code_or_exception != 500 or key is None, \ + 'It is currently not possible to register a 500 internal ' \ + 'server error on a per-blueprint level.' + self.error_handler_spec.setdefault(key, {})[code_or_exception] = f + else: + self.error_handler_spec.setdefault(key, {}).setdefault(None, []) \ + .append((code_or_exception, f)) + + @setupmethod + def template_filter(self, name=None): + """A decorator that is used to register custom template filter. + You can specify a name for the filter, otherwise the function + name will be used. Example:: + + @app.template_filter() + def reverse(s): + return s[::-1] + + :param name: the optional name of the filter, otherwise the + function name will be used. + """ + def decorator(f): + self.add_template_filter(f, name=name) + return f + return decorator + + @setupmethod + def add_template_filter(self, f, name=None): + """Register a custom template filter. Works exactly like the + :meth:`template_filter` decorator. + + :param name: the optional name of the filter, otherwise the + function name will be used. + """ + self.jinja_env.filters[name or f.__name__] = f + + @setupmethod + def template_test(self, name=None): + """A decorator that is used to register custom template test. + You can specify a name for the test, otherwise the function + name will be used. Example:: + + @app.template_test() + def is_prime(n): + if n == 2: + return True + for i in range(2, int(math.ceil(math.sqrt(n))) + 1): + if n % i == 0: + return False + return True + + .. versionadded:: 0.10 + + :param name: the optional name of the test, otherwise the + function name will be used. + """ + def decorator(f): + self.add_template_test(f, name=name) + return f + return decorator + + @setupmethod + def add_template_test(self, f, name=None): + """Register a custom template test. Works exactly like the + :meth:`template_test` decorator. + + .. versionadded:: 0.10 + + :param name: the optional name of the test, otherwise the + function name will be used. + """ + self.jinja_env.tests[name or f.__name__] = f + + + @setupmethod + def template_global(self, name=None): + """A decorator that is used to register a custom template global function. + You can specify a name for the global function, otherwise the function + name will be used. Example:: + + @app.template_global() + def double(n): + return 2 * n + + .. versionadded:: 0.10 + + :param name: the optional name of the global function, otherwise the + function name will be used. + """ + def decorator(f): + self.add_template_global(f, name=name) + return f + return decorator + + @setupmethod + def add_template_global(self, f, name=None): + """Register a custom template global function. Works exactly like the + :meth:`template_global` decorator. + + .. versionadded:: 0.10 + + :param name: the optional name of the global function, otherwise the + function name will be used. + """ + self.jinja_env.globals[name or f.__name__] = f + + @setupmethod + def before_request(self, f): + """Registers a function to run before each request.""" + self.before_request_funcs.setdefault(None, []).append(f) + return f + + @setupmethod + def before_first_request(self, f): + """Registers a function to be run before the first request to this + instance of the application. + + .. versionadded:: 0.8 + """ + self.before_first_request_funcs.append(f) + + @setupmethod + def after_request(self, f): + """Register a function to be run after each request. Your function + must take one parameter, a :attr:`response_class` object and return + a new response object or the same (see :meth:`process_response`). + + As of Flask 0.7 this function might not be executed at the end of the + request in case an unhandled exception occurred. + """ + self.after_request_funcs.setdefault(None, []).append(f) + return f + + @setupmethod + def teardown_request(self, f): + """Register a function to be run at the end of each request, + regardless of whether there was an exception or not. These functions + are executed when the request context is popped, even if not an + actual request was performed. + + Example:: + + ctx = app.test_request_context() + ctx.push() + ... + ctx.pop() + + When ``ctx.pop()`` is executed in the above example, the teardown + functions are called just before the request context moves from the + stack of active contexts. This becomes relevant if you are using + such constructs in tests. + + Generally teardown functions must take every necessary step to avoid + that they will fail. If they do execute code that might fail they + will have to surround the execution of these code by try/except + statements and log occurring errors. + + When a teardown function was called because of a exception it will + be passed an error object. + + .. admonition:: Debug Note + + In debug mode Flask will not tear down a request on an exception + immediately. Instead if will keep it alive so that the interactive + debugger can still access it. This behavior can be controlled + by the ``PRESERVE_CONTEXT_ON_EXCEPTION`` configuration variable. + """ + self.teardown_request_funcs.setdefault(None, []).append(f) + return f + + @setupmethod + def teardown_appcontext(self, f): + """Registers a function to be called when the application context + ends. These functions are typically also called when the request + context is popped. + + Example:: + + ctx = app.app_context() + ctx.push() + ... + ctx.pop() + + When ``ctx.pop()`` is executed in the above example, the teardown + functions are called just before the app context moves from the + stack of active contexts. This becomes relevant if you are using + such constructs in tests. + + Since a request context typically also manages an application + context it would also be called when you pop a request context. + + When a teardown function was called because of an exception it will + be passed an error object. + + .. versionadded:: 0.9 + """ + self.teardown_appcontext_funcs.append(f) + return f + + @setupmethod + def context_processor(self, f): + """Registers a template context processor function.""" + self.template_context_processors[None].append(f) + return f + + @setupmethod + def url_value_preprocessor(self, f): + """Registers a function as URL value preprocessor for all view + functions of the application. It's called before the view functions + are called and can modify the url values provided. + """ + self.url_value_preprocessors.setdefault(None, []).append(f) + return f + + @setupmethod + def url_defaults(self, f): + """Callback function for URL defaults for all view functions of the + application. It's called with the endpoint and values and should + update the values passed in place. + """ + self.url_default_functions.setdefault(None, []).append(f) + return f + + def handle_http_exception(self, e): + """Handles an HTTP exception. By default this will invoke the + registered error handlers and fall back to returning the + exception as response. + + .. versionadded:: 0.3 + """ + handlers = self.error_handler_spec.get(request.blueprint) + # Proxy exceptions don't have error codes. We want to always return + # those unchanged as errors + if e.code is None: + return e + if handlers and e.code in handlers: + handler = handlers[e.code] + else: + handler = self.error_handler_spec[None].get(e.code) + if handler is None: + return e + return handler(e) + + def trap_http_exception(self, e): + """Checks if an HTTP exception should be trapped or not. By default + this will return `False` for all exceptions except for a bad request + key error if ``TRAP_BAD_REQUEST_ERRORS`` is set to `True`. It + also returns `True` if ``TRAP_HTTP_EXCEPTIONS`` is set to `True`. + + This is called for all HTTP exceptions raised by a view function. + If it returns `True` for any exception the error handler for this + exception is not called and it shows up as regular exception in the + traceback. This is helpful for debugging implicitly raised HTTP + exceptions. + + .. versionadded:: 0.8 + """ + if self.config['TRAP_HTTP_EXCEPTIONS']: + return True + if self.config['TRAP_BAD_REQUEST_ERRORS']: + return isinstance(e, BadRequest) + return False + + def handle_user_exception(self, e): + """This method is called whenever an exception occurs that should be + handled. A special case are + :class:`~werkzeug.exception.HTTPException`\s which are forwarded by + this function to the :meth:`handle_http_exception` method. This + function will either return a response value or reraise the + exception with the same traceback. + + .. versionadded:: 0.7 + """ + exc_type, exc_value, tb = sys.exc_info() + assert exc_value is e + + # ensure not to trash sys.exc_info() at that point in case someone + # wants the traceback preserved in handle_http_exception. Of course + # we cannot prevent users from trashing it themselves in a custom + # trap_http_exception method so that's their fault then. + if isinstance(e, HTTPException) and not self.trap_http_exception(e): + return self.handle_http_exception(e) + + blueprint_handlers = () + handlers = self.error_handler_spec.get(request.blueprint) + if handlers is not None: + blueprint_handlers = handlers.get(None, ()) + app_handlers = self.error_handler_spec[None].get(None, ()) + for typecheck, handler in chain(blueprint_handlers, app_handlers): + if isinstance(e, typecheck): + return handler(e) + + reraise(exc_type, exc_value, tb) + + def handle_exception(self, e): + """Default exception handling that kicks in when an exception + occurs that is not caught. In debug mode the exception will + be re-raised immediately, otherwise it is logged and the handler + for a 500 internal server error is used. If no such handler + exists, a default 500 internal server error message is displayed. + + .. versionadded:: 0.3 + """ + exc_type, exc_value, tb = sys.exc_info() + + got_request_exception.send(self, exception=e) + handler = self.error_handler_spec[None].get(500) + + if self.propagate_exceptions: + # if we want to repropagate the exception, we can attempt to + # raise it with the whole traceback in case we can do that + # (the function was actually called from the except part) + # otherwise, we just raise the error again + if exc_value is e: + reraise(exc_type, exc_value, tb) + else: + raise e + + self.log_exception((exc_type, exc_value, tb)) + if handler is None: + return InternalServerError() + return handler(e) + + def log_exception(self, exc_info): + """Logs an exception. This is called by :meth:`handle_exception` + if debugging is disabled and right before the handler is called. + The default implementation logs the exception as error on the + :attr:`logger`. + + .. versionadded:: 0.8 + """ + self.logger.error('Exception on %s [%s]' % ( + request.path, + request.method + ), exc_info=exc_info) + + def raise_routing_exception(self, request): + """Exceptions that are recording during routing are reraised with + this method. During debug we are not reraising redirect requests + for non ``GET``, ``HEAD``, or ``OPTIONS`` requests and we're raising + a different error instead to help debug situations. + + :internal: + """ + if not self.debug \ + or not isinstance(request.routing_exception, RequestRedirect) \ + or request.method in ('GET', 'HEAD', 'OPTIONS'): + raise request.routing_exception + + from .debughelpers import FormDataRoutingRedirect + raise FormDataRoutingRedirect(request) + + def dispatch_request(self): + """Does the request dispatching. Matches the URL and returns the + return value of the view or error handler. This does not have to + be a response object. In order to convert the return value to a + proper response object, call :func:`make_response`. + + .. versionchanged:: 0.7 + This no longer does the exception handling, this code was + moved to the new :meth:`full_dispatch_request`. + """ + req = _request_ctx_stack.top.request + if req.routing_exception is not None: + self.raise_routing_exception(req) + rule = req.url_rule + # if we provide automatic options for this URL and the + # request came with the OPTIONS method, reply automatically + if getattr(rule, 'provide_automatic_options', False) \ + and req.method == 'OPTIONS': + return self.make_default_options_response() + # otherwise dispatch to the handler for that endpoint + return self.view_functions[rule.endpoint](**req.view_args) + + def full_dispatch_request(self): + """Dispatches the request and on top of that performs request + pre and postprocessing as well as HTTP exception catching and + error handling. + + .. versionadded:: 0.7 + """ + self.try_trigger_before_first_request_functions() + try: + request_started.send(self) + rv = self.preprocess_request() + if rv is None: + rv = self.dispatch_request() + except Exception as e: + rv = self.handle_user_exception(e) + response = self.make_response(rv) + response = self.process_response(response) + request_finished.send(self, response=response) + return response + + def try_trigger_before_first_request_functions(self): + """Called before each request and will ensure that it triggers + the :attr:`before_first_request_funcs` and only exactly once per + application instance (which means process usually). + + :internal: + """ + if self._got_first_request: + return + with self._before_request_lock: + if self._got_first_request: + return + self._got_first_request = True + for func in self.before_first_request_funcs: + func() + + def make_default_options_response(self): + """This method is called to create the default `OPTIONS` response. + This can be changed through subclassing to change the default + behavior of `OPTIONS` responses. + + .. versionadded:: 0.7 + """ + adapter = _request_ctx_stack.top.url_adapter + if hasattr(adapter, 'allowed_methods'): + methods = adapter.allowed_methods() + else: + # fallback for Werkzeug < 0.7 + methods = [] + try: + adapter.match(method='--') + except MethodNotAllowed as e: + methods = e.valid_methods + except HTTPException as e: + pass + rv = self.response_class() + rv.allow.update(methods) + return rv + + def should_ignore_error(self, error): + """This is called to figure out if an error should be ignored + or not as far as the teardown system is concerned. If this + function returns `True` then the teardown handlers will not be + passed the error. + + .. versionadded:: 0.10 + """ + return False + + def make_response(self, rv): + """Converts the return value from a view function to a real + response object that is an instance of :attr:`response_class`. + + The following types are allowed for `rv`: + + .. tabularcolumns:: |p{3.5cm}|p{9.5cm}| + + ======================= =========================================== + :attr:`response_class` the object is returned unchanged + :class:`str` a response object is created with the + string as body + :class:`unicode` a response object is created with the + string encoded to utf-8 as body + a WSGI function the function is called as WSGI application + and buffered as response object + :class:`tuple` A tuple in the form ``(response, status, + headers)`` where `response` is any of the + types defined here, `status` is a string + or an integer and `headers` is a list of + a dictionary with header values. + ======================= =========================================== + + :param rv: the return value from the view function + + .. versionchanged:: 0.9 + Previously a tuple was interpreted as the arguments for the + response object. + """ + status = headers = None + if isinstance(rv, tuple): + rv, status, headers = rv + (None,) * (3 - len(rv)) + + if rv is None: + raise ValueError('View function did not return a response') + + if not isinstance(rv, self.response_class): + # When we create a response object directly, we let the constructor + # set the headers and status. We do this because there can be + # some extra logic involved when creating these objects with + # specific values (like default content type selection). + if isinstance(rv, (text_type, bytes, bytearray)): + rv = self.response_class(rv, headers=headers, status=status) + headers = status = None + else: + rv = self.response_class.force_type(rv, request.environ) + + if status is not None: + if isinstance(status, string_types): + rv.status = status + else: + rv.status_code = status + if headers: + rv.headers.extend(headers) + + return rv + + def create_url_adapter(self, request): + """Creates a URL adapter for the given request. The URL adapter + is created at a point where the request context is not yet set up + so the request is passed explicitly. + + .. versionadded:: 0.6 + + .. versionchanged:: 0.9 + This can now also be called without a request object when the + URL adapter is created for the application context. + """ + if request is not None: + return self.url_map.bind_to_environ(request.environ, + server_name=self.config['SERVER_NAME']) + # We need at the very least the server name to be set for this + # to work. + if self.config['SERVER_NAME'] is not None: + return self.url_map.bind( + self.config['SERVER_NAME'], + script_name=self.config['APPLICATION_ROOT'] or '/', + url_scheme=self.config['PREFERRED_URL_SCHEME']) + + def inject_url_defaults(self, endpoint, values): + """Injects the URL defaults for the given endpoint directly into + the values dictionary passed. This is used internally and + automatically called on URL building. + + .. versionadded:: 0.7 + """ + funcs = self.url_default_functions.get(None, ()) + if '.' in endpoint: + bp = endpoint.rsplit('.', 1)[0] + funcs = chain(funcs, self.url_default_functions.get(bp, ())) + for func in funcs: + func(endpoint, values) + + def handle_url_build_error(self, error, endpoint, values): + """Handle :class:`~werkzeug.routing.BuildError` on :meth:`url_for`. + """ + exc_type, exc_value, tb = sys.exc_info() + for handler in self.url_build_error_handlers: + try: + rv = handler(error, endpoint, values) + if rv is not None: + return rv + except BuildError as error: + pass + + # At this point we want to reraise the exception. If the error is + # still the same one we can reraise it with the original traceback, + # otherwise we raise it from here. + if error is exc_value: + reraise(exc_type, exc_value, tb) + raise error + + def preprocess_request(self): + """Called before the actual request dispatching and will + call every as :meth:`before_request` decorated function. + If any of these function returns a value it's handled as + if it was the return value from the view and further + request handling is stopped. + + This also triggers the :meth:`url_value_processor` functions before + the actual :meth:`before_request` functions are called. + """ + bp = _request_ctx_stack.top.request.blueprint + + funcs = self.url_value_preprocessors.get(None, ()) + if bp is not None and bp in self.url_value_preprocessors: + funcs = chain(funcs, self.url_value_preprocessors[bp]) + for func in funcs: + func(request.endpoint, request.view_args) + + funcs = self.before_request_funcs.get(None, ()) + if bp is not None and bp in self.before_request_funcs: + funcs = chain(funcs, self.before_request_funcs[bp]) + for func in funcs: + rv = func() + if rv is not None: + return rv + + def process_response(self, response): + """Can be overridden in order to modify the response object + before it's sent to the WSGI server. By default this will + call all the :meth:`after_request` decorated functions. + + .. versionchanged:: 0.5 + As of Flask 0.5 the functions registered for after request + execution are called in reverse order of registration. + + :param response: a :attr:`response_class` object. + :return: a new response object or the same, has to be an + instance of :attr:`response_class`. + """ + ctx = _request_ctx_stack.top + bp = ctx.request.blueprint + funcs = ctx._after_request_functions + if bp is not None and bp in self.after_request_funcs: + funcs = chain(funcs, reversed(self.after_request_funcs[bp])) + if None in self.after_request_funcs: + funcs = chain(funcs, reversed(self.after_request_funcs[None])) + for handler in funcs: + response = handler(response) + if not self.session_interface.is_null_session(ctx.session): + self.save_session(ctx.session, response) + return response + + def do_teardown_request(self, exc=None): + """Called after the actual request dispatching and will + call every as :meth:`teardown_request` decorated function. This is + not actually called by the :class:`Flask` object itself but is always + triggered when the request context is popped. That way we have a + tighter control over certain resources under testing environments. + + .. versionchanged:: 0.9 + Added the `exc` argument. Previously this was always using the + current exception information. + """ + if exc is None: + exc = sys.exc_info()[1] + funcs = reversed(self.teardown_request_funcs.get(None, ())) + bp = _request_ctx_stack.top.request.blueprint + if bp is not None and bp in self.teardown_request_funcs: + funcs = chain(funcs, reversed(self.teardown_request_funcs[bp])) + for func in funcs: + rv = func(exc) + request_tearing_down.send(self, exc=exc) + + def do_teardown_appcontext(self, exc=None): + """Called when an application context is popped. This works pretty + much the same as :meth:`do_teardown_request` but for the application + context. + + .. versionadded:: 0.9 + """ + if exc is None: + exc = sys.exc_info()[1] + for func in reversed(self.teardown_appcontext_funcs): + func(exc) + appcontext_tearing_down.send(self, exc=exc) + + def app_context(self): + """Binds the application only. For as long as the application is bound + to the current context the :data:`flask.current_app` points to that + application. An application context is automatically created when a + request context is pushed if necessary. + + Example usage:: + + with app.app_context(): + ... + + .. versionadded:: 0.9 + """ + return AppContext(self) + + def request_context(self, environ): + """Creates a :class:`~flask.ctx.RequestContext` from the given + environment and binds it to the current context. This must be used in + combination with the `with` statement because the request is only bound + to the current context for the duration of the `with` block. + + Example usage:: + + with app.request_context(environ): + do_something_with(request) + + The object returned can also be used without the `with` statement + which is useful for working in the shell. The example above is + doing exactly the same as this code:: + + ctx = app.request_context(environ) + ctx.push() + try: + do_something_with(request) + finally: + ctx.pop() + + .. versionchanged:: 0.3 + Added support for non-with statement usage and `with` statement + is now passed the ctx object. + + :param environ: a WSGI environment + """ + return RequestContext(self, environ) + + def test_request_context(self, *args, **kwargs): + """Creates a WSGI environment from the given values (see + :func:`werkzeug.test.EnvironBuilder` for more information, this + function accepts the same arguments). + """ + from flask.testing import make_test_environ_builder + builder = make_test_environ_builder(self, *args, **kwargs) + try: + return self.request_context(builder.get_environ()) + finally: + builder.close() + + def wsgi_app(self, environ, start_response): + """The actual WSGI application. This is not implemented in + `__call__` so that middlewares can be applied without losing a + reference to the class. So instead of doing this:: + + app = MyMiddleware(app) + + It's a better idea to do this instead:: + + app.wsgi_app = MyMiddleware(app.wsgi_app) + + Then you still have the original application object around and + can continue to call methods on it. + + .. versionchanged:: 0.7 + The behavior of the before and after request callbacks was changed + under error conditions and a new callback was added that will + always execute at the end of the request, independent on if an + error occurred or not. See :ref:`callbacks-and-errors`. + + :param environ: a WSGI environment + :param start_response: a callable accepting a status code, + a list of headers and an optional + exception context to start the response + """ + ctx = self.request_context(environ) + ctx.push() + error = None + try: + try: + response = self.full_dispatch_request() + except Exception as e: + error = e + response = self.make_response(self.handle_exception(e)) + return response(environ, start_response) + finally: + if self.should_ignore_error(error): + error = None + ctx.auto_pop(error) + + @property + def modules(self): + from warnings import warn + warn(DeprecationWarning('Flask.modules is deprecated, use ' + 'Flask.blueprints instead'), stacklevel=2) + return self.blueprints + + def __call__(self, environ, start_response): + """Shortcut for :attr:`wsgi_app`.""" + return self.wsgi_app(environ, start_response) + + def __repr__(self): + return '<%s %r>' % ( + self.__class__.__name__, + self.name, + ) diff --git a/lib/flask/app.pyc b/lib/flask/app.pyc new file mode 100644 index 0000000..b14e25b Binary files /dev/null and b/lib/flask/app.pyc differ diff --git a/lib/flask/blueprints.py b/lib/flask/blueprints.py new file mode 100644 index 0000000..4575ec9 --- /dev/null +++ b/lib/flask/blueprints.py @@ -0,0 +1,401 @@ +# -*- coding: utf-8 -*- +""" + flask.blueprints + ~~~~~~~~~~~~~~~~ + + Blueprints are the recommended way to implement larger or more + pluggable applications in Flask 0.7 and later. + + :copyright: (c) 2011 by Armin Ronacher. + :license: BSD, see LICENSE for more details. +""" +from functools import update_wrapper + +from .helpers import _PackageBoundObject, _endpoint_from_view_func + + +class BlueprintSetupState(object): + """Temporary holder object for registering a blueprint with the + application. An instance of this class is created by the + :meth:`~flask.Blueprint.make_setup_state` method and later passed + to all register callback functions. + """ + + def __init__(self, blueprint, app, options, first_registration): + #: a reference to the current application + self.app = app + + #: a reference to the blueprint that created this setup state. + self.blueprint = blueprint + + #: a dictionary with all options that were passed to the + #: :meth:`~flask.Flask.register_blueprint` method. + self.options = options + + #: as blueprints can be registered multiple times with the + #: application and not everything wants to be registered + #: multiple times on it, this attribute can be used to figure + #: out if the blueprint was registered in the past already. + self.first_registration = first_registration + + subdomain = self.options.get('subdomain') + if subdomain is None: + subdomain = self.blueprint.subdomain + + #: The subdomain that the blueprint should be active for, `None` + #: otherwise. + self.subdomain = subdomain + + url_prefix = self.options.get('url_prefix') + if url_prefix is None: + url_prefix = self.blueprint.url_prefix + + #: The prefix that should be used for all URLs defined on the + #: blueprint. + self.url_prefix = url_prefix + + #: A dictionary with URL defaults that is added to each and every + #: URL that was defined with the blueprint. + self.url_defaults = dict(self.blueprint.url_values_defaults) + self.url_defaults.update(self.options.get('url_defaults', ())) + + def add_url_rule(self, rule, endpoint=None, view_func=None, **options): + """A helper method to register a rule (and optionally a view function) + to the application. The endpoint is automatically prefixed with the + blueprint's name. + """ + if self.url_prefix: + rule = self.url_prefix + rule + options.setdefault('subdomain', self.subdomain) + if endpoint is None: + endpoint = _endpoint_from_view_func(view_func) + defaults = self.url_defaults + if 'defaults' in options: + defaults = dict(defaults, **options.pop('defaults')) + self.app.add_url_rule(rule, '%s.%s' % (self.blueprint.name, endpoint), + view_func, defaults=defaults, **options) + + +class Blueprint(_PackageBoundObject): + """Represents a blueprint. A blueprint is an object that records + functions that will be called with the + :class:`~flask.blueprint.BlueprintSetupState` later to register functions + or other things on the main application. See :ref:`blueprints` for more + information. + + .. versionadded:: 0.7 + """ + + warn_on_modifications = False + _got_registered_once = False + + def __init__(self, name, import_name, static_folder=None, + static_url_path=None, template_folder=None, + url_prefix=None, subdomain=None, url_defaults=None): + _PackageBoundObject.__init__(self, import_name, template_folder) + self.name = name + self.url_prefix = url_prefix + self.subdomain = subdomain + self.static_folder = static_folder + self.static_url_path = static_url_path + self.deferred_functions = [] + self.view_functions = {} + if url_defaults is None: + url_defaults = {} + self.url_values_defaults = url_defaults + + def record(self, func): + """Registers a function that is called when the blueprint is + registered on the application. This function is called with the + state as argument as returned by the :meth:`make_setup_state` + method. + """ + if self._got_registered_once and self.warn_on_modifications: + from warnings import warn + warn(Warning('The blueprint was already registered once ' + 'but is getting modified now. These changes ' + 'will not show up.')) + self.deferred_functions.append(func) + + def record_once(self, func): + """Works like :meth:`record` but wraps the function in another + function that will ensure the function is only called once. If the + blueprint is registered a second time on the application, the + function passed is not called. + """ + def wrapper(state): + if state.first_registration: + func(state) + return self.record(update_wrapper(wrapper, func)) + + def make_setup_state(self, app, options, first_registration=False): + """Creates an instance of :meth:`~flask.blueprints.BlueprintSetupState` + object that is later passed to the register callback functions. + Subclasses can override this to return a subclass of the setup state. + """ + return BlueprintSetupState(self, app, options, first_registration) + + def register(self, app, options, first_registration=False): + """Called by :meth:`Flask.register_blueprint` to register a blueprint + on the application. This can be overridden to customize the register + behavior. Keyword arguments from + :func:`~flask.Flask.register_blueprint` are directly forwarded to this + method in the `options` dictionary. + """ + self._got_registered_once = True + state = self.make_setup_state(app, options, first_registration) + if self.has_static_folder: + state.add_url_rule(self.static_url_path + '/', + view_func=self.send_static_file, + endpoint='static') + + for deferred in self.deferred_functions: + deferred(state) + + def route(self, rule, **options): + """Like :meth:`Flask.route` but for a blueprint. The endpoint for the + :func:`url_for` function is prefixed with the name of the blueprint. + """ + def decorator(f): + endpoint = options.pop("endpoint", f.__name__) + self.add_url_rule(rule, endpoint, f, **options) + return f + return decorator + + def add_url_rule(self, rule, endpoint=None, view_func=None, **options): + """Like :meth:`Flask.add_url_rule` but for a blueprint. The endpoint for + the :func:`url_for` function is prefixed with the name of the blueprint. + """ + if endpoint: + assert '.' not in endpoint, "Blueprint endpoint's should not contain dot's" + self.record(lambda s: + s.add_url_rule(rule, endpoint, view_func, **options)) + + def endpoint(self, endpoint): + """Like :meth:`Flask.endpoint` but for a blueprint. This does not + prefix the endpoint with the blueprint name, this has to be done + explicitly by the user of this method. If the endpoint is prefixed + with a `.` it will be registered to the current blueprint, otherwise + it's an application independent endpoint. + """ + def decorator(f): + def register_endpoint(state): + state.app.view_functions[endpoint] = f + self.record_once(register_endpoint) + return f + return decorator + + def app_template_filter(self, name=None): + """Register a custom template filter, available application wide. Like + :meth:`Flask.template_filter` but for a blueprint. + + :param name: the optional name of the filter, otherwise the + function name will be used. + """ + def decorator(f): + self.add_app_template_filter(f, name=name) + return f + return decorator + + def add_app_template_filter(self, f, name=None): + """Register a custom template filter, available application wide. Like + :meth:`Flask.add_template_filter` but for a blueprint. Works exactly + like the :meth:`app_template_filter` decorator. + + :param name: the optional name of the filter, otherwise the + function name will be used. + """ + def register_template(state): + state.app.jinja_env.filters[name or f.__name__] = f + self.record_once(register_template) + + def app_template_test(self, name=None): + """Register a custom template test, available application wide. Like + :meth:`Flask.template_test` but for a blueprint. + + .. versionadded:: 0.10 + + :param name: the optional name of the test, otherwise the + function name will be used. + """ + def decorator(f): + self.add_app_template_test(f, name=name) + return f + return decorator + + def add_app_template_test(self, f, name=None): + """Register a custom template test, available application wide. Like + :meth:`Flask.add_template_test` but for a blueprint. Works exactly + like the :meth:`app_template_test` decorator. + + .. versionadded:: 0.10 + + :param name: the optional name of the test, otherwise the + function name will be used. + """ + def register_template(state): + state.app.jinja_env.tests[name or f.__name__] = f + self.record_once(register_template) + + def app_template_global(self, name=None): + """Register a custom template global, available application wide. Like + :meth:`Flask.template_global` but for a blueprint. + + .. versionadded:: 0.10 + + :param name: the optional name of the global, otherwise the + function name will be used. + """ + def decorator(f): + self.add_app_template_global(f, name=name) + return f + return decorator + + def add_app_template_global(self, f, name=None): + """Register a custom template global, available application wide. Like + :meth:`Flask.add_template_global` but for a blueprint. Works exactly + like the :meth:`app_template_global` decorator. + + .. versionadded:: 0.10 + + :param name: the optional name of the global, otherwise the + function name will be used. + """ + def register_template(state): + state.app.jinja_env.globals[name or f.__name__] = f + self.record_once(register_template) + + def before_request(self, f): + """Like :meth:`Flask.before_request` but for a blueprint. This function + is only executed before each request that is handled by a function of + that blueprint. + """ + self.record_once(lambda s: s.app.before_request_funcs + .setdefault(self.name, []).append(f)) + return f + + def before_app_request(self, f): + """Like :meth:`Flask.before_request`. Such a function is executed + before each request, even if outside of a blueprint. + """ + self.record_once(lambda s: s.app.before_request_funcs + .setdefault(None, []).append(f)) + return f + + def before_app_first_request(self, f): + """Like :meth:`Flask.before_first_request`. Such a function is + executed before the first request to the application. + """ + self.record_once(lambda s: s.app.before_first_request_funcs.append(f)) + return f + + def after_request(self, f): + """Like :meth:`Flask.after_request` but for a blueprint. This function + is only executed after each request that is handled by a function of + that blueprint. + """ + self.record_once(lambda s: s.app.after_request_funcs + .setdefault(self.name, []).append(f)) + return f + + def after_app_request(self, f): + """Like :meth:`Flask.after_request` but for a blueprint. Such a function + is executed after each request, even if outside of the blueprint. + """ + self.record_once(lambda s: s.app.after_request_funcs + .setdefault(None, []).append(f)) + return f + + def teardown_request(self, f): + """Like :meth:`Flask.teardown_request` but for a blueprint. This + function is only executed when tearing down requests handled by a + function of that blueprint. Teardown request functions are executed + when the request context is popped, even when no actual request was + performed. + """ + self.record_once(lambda s: s.app.teardown_request_funcs + .setdefault(self.name, []).append(f)) + return f + + def teardown_app_request(self, f): + """Like :meth:`Flask.teardown_request` but for a blueprint. Such a + function is executed when tearing down each request, even if outside of + the blueprint. + """ + self.record_once(lambda s: s.app.teardown_request_funcs + .setdefault(None, []).append(f)) + return f + + def context_processor(self, f): + """Like :meth:`Flask.context_processor` but for a blueprint. This + function is only executed for requests handled by a blueprint. + """ + self.record_once(lambda s: s.app.template_context_processors + .setdefault(self.name, []).append(f)) + return f + + def app_context_processor(self, f): + """Like :meth:`Flask.context_processor` but for a blueprint. Such a + function is executed each request, even if outside of the blueprint. + """ + self.record_once(lambda s: s.app.template_context_processors + .setdefault(None, []).append(f)) + return f + + def app_errorhandler(self, code): + """Like :meth:`Flask.errorhandler` but for a blueprint. This + handler is used for all requests, even if outside of the blueprint. + """ + def decorator(f): + self.record_once(lambda s: s.app.errorhandler(code)(f)) + return f + return decorator + + def url_value_preprocessor(self, f): + """Registers a function as URL value preprocessor for this + blueprint. It's called before the view functions are called and + can modify the url values provided. + """ + self.record_once(lambda s: s.app.url_value_preprocessors + .setdefault(self.name, []).append(f)) + return f + + def url_defaults(self, f): + """Callback function for URL defaults for this blueprint. It's called + with the endpoint and values and should update the values passed + in place. + """ + self.record_once(lambda s: s.app.url_default_functions + .setdefault(self.name, []).append(f)) + return f + + def app_url_value_preprocessor(self, f): + """Same as :meth:`url_value_preprocessor` but application wide. + """ + self.record_once(lambda s: s.app.url_value_preprocessors + .setdefault(None, []).append(f)) + return f + + def app_url_defaults(self, f): + """Same as :meth:`url_defaults` but application wide. + """ + self.record_once(lambda s: s.app.url_default_functions + .setdefault(None, []).append(f)) + return f + + def errorhandler(self, code_or_exception): + """Registers an error handler that becomes active for this blueprint + only. Please be aware that routing does not happen local to a + blueprint so an error handler for 404 usually is not handled by + a blueprint unless it is caused inside a view function. Another + special case is the 500 internal server error which is always looked + up from the application. + + Otherwise works as the :meth:`~flask.Flask.errorhandler` decorator + of the :class:`~flask.Flask` object. + """ + def decorator(f): + self.record_once(lambda s: s.app._register_error_handler( + self.name, code_or_exception, f)) + return f + return decorator diff --git a/lib/flask/blueprints.pyc b/lib/flask/blueprints.pyc new file mode 100644 index 0000000..54c6638 Binary files /dev/null and b/lib/flask/blueprints.pyc differ diff --git a/lib/flask/config.py b/lib/flask/config.py new file mode 100644 index 0000000..155afa2 --- /dev/null +++ b/lib/flask/config.py @@ -0,0 +1,168 @@ +# -*- coding: utf-8 -*- +""" + flask.config + ~~~~~~~~~~~~ + + Implements the configuration related objects. + + :copyright: (c) 2011 by Armin Ronacher. + :license: BSD, see LICENSE for more details. +""" + +import imp +import os +import errno + +from werkzeug.utils import import_string +from ._compat import string_types + + +class ConfigAttribute(object): + """Makes an attribute forward to the config""" + + def __init__(self, name, get_converter=None): + self.__name__ = name + self.get_converter = get_converter + + def __get__(self, obj, type=None): + if obj is None: + return self + rv = obj.config[self.__name__] + if self.get_converter is not None: + rv = self.get_converter(rv) + return rv + + def __set__(self, obj, value): + obj.config[self.__name__] = value + + +class Config(dict): + """Works exactly like a dict but provides ways to fill it from files + or special dictionaries. There are two common patterns to populate the + config. + + Either you can fill the config from a config file:: + + app.config.from_pyfile('yourconfig.cfg') + + Or alternatively you can define the configuration options in the + module that calls :meth:`from_object` or provide an import path to + a module that should be loaded. It is also possible to tell it to + use the same module and with that provide the configuration values + just before the call:: + + DEBUG = True + SECRET_KEY = 'development key' + app.config.from_object(__name__) + + In both cases (loading from any Python file or loading from modules), + only uppercase keys are added to the config. This makes it possible to use + lowercase values in the config file for temporary values that are not added + to the config or to define the config keys in the same file that implements + the application. + + Probably the most interesting way to load configurations is from an + environment variable pointing to a file:: + + app.config.from_envvar('YOURAPPLICATION_SETTINGS') + + In this case before launching the application you have to set this + environment variable to the file you want to use. On Linux and OS X + use the export statement:: + + export YOURAPPLICATION_SETTINGS='/path/to/config/file' + + On windows use `set` instead. + + :param root_path: path to which files are read relative from. When the + config object is created by the application, this is + the application's :attr:`~flask.Flask.root_path`. + :param defaults: an optional dictionary of default values + """ + + def __init__(self, root_path, defaults=None): + dict.__init__(self, defaults or {}) + self.root_path = root_path + + def from_envvar(self, variable_name, silent=False): + """Loads a configuration from an environment variable pointing to + a configuration file. This is basically just a shortcut with nicer + error messages for this line of code:: + + app.config.from_pyfile(os.environ['YOURAPPLICATION_SETTINGS']) + + :param variable_name: name of the environment variable + :param silent: set to `True` if you want silent failure for missing + files. + :return: bool. `True` if able to load config, `False` otherwise. + """ + rv = os.environ.get(variable_name) + if not rv: + if silent: + return False + raise RuntimeError('The environment variable %r is not set ' + 'and as such configuration could not be ' + 'loaded. Set this variable and make it ' + 'point to a configuration file' % + variable_name) + return self.from_pyfile(rv, silent=silent) + + def from_pyfile(self, filename, silent=False): + """Updates the values in the config from a Python file. This function + behaves as if the file was imported as module with the + :meth:`from_object` function. + + :param filename: the filename of the config. This can either be an + absolute filename or a filename relative to the + root path. + :param silent: set to `True` if you want silent failure for missing + files. + + .. versionadded:: 0.7 + `silent` parameter. + """ + filename = os.path.join(self.root_path, filename) + d = imp.new_module('config') + d.__file__ = filename + try: + with open(filename) as config_file: + exec(compile(config_file.read(), filename, 'exec'), d.__dict__) + except IOError as e: + if silent and e.errno in (errno.ENOENT, errno.EISDIR): + return False + e.strerror = 'Unable to load configuration file (%s)' % e.strerror + raise + self.from_object(d) + return True + + def from_object(self, obj): + """Updates the values from the given object. An object can be of one + of the following two types: + + - a string: in this case the object with that name will be imported + - an actual object reference: that object is used directly + + Objects are usually either modules or classes. + + Just the uppercase variables in that object are stored in the config. + Example usage:: + + app.config.from_object('yourapplication.default_config') + from yourapplication import default_config + app.config.from_object(default_config) + + You should not use this function to load the actual configuration but + rather configuration defaults. The actual config should be loaded + with :meth:`from_pyfile` and ideally from a location not within the + package because the package might be installed system wide. + + :param obj: an import name or object + """ + if isinstance(obj, string_types): + obj = import_string(obj) + for key in dir(obj): + if key.isupper(): + self[key] = getattr(obj, key) + + def __repr__(self): + return '<%s %s>' % (self.__class__.__name__, dict.__repr__(self)) diff --git a/lib/flask/config.pyc b/lib/flask/config.pyc new file mode 100644 index 0000000..e6e0fd9 Binary files /dev/null and b/lib/flask/config.pyc differ diff --git a/lib/flask/ctx.py b/lib/flask/ctx.py new file mode 100644 index 0000000..f134237 --- /dev/null +++ b/lib/flask/ctx.py @@ -0,0 +1,394 @@ +# -*- coding: utf-8 -*- +""" + flask.ctx + ~~~~~~~~~ + + Implements the objects required to keep the context. + + :copyright: (c) 2011 by Armin Ronacher. + :license: BSD, see LICENSE for more details. +""" + +from __future__ import with_statement + +import sys +from functools import update_wrapper + +from werkzeug.exceptions import HTTPException + +from .globals import _request_ctx_stack, _app_ctx_stack +from .module import blueprint_is_module +from .signals import appcontext_pushed, appcontext_popped + + +class _AppCtxGlobals(object): + """A plain object.""" + + def get(self, name, default=None): + return self.__dict__.get(name, default) + + def __contains__(self, item): + return item in self.__dict__ + + def __iter__(self): + return iter(self.__dict__) + + def __repr__(self): + top = _app_ctx_stack.top + if top is not None: + return '' % top.app.name + return object.__repr__(self) + + +def after_this_request(f): + """Executes a function after this request. This is useful to modify + response objects. The function is passed the response object and has + to return the same or a new one. + + Example:: + + @app.route('/') + def index(): + @after_this_request + def add_header(response): + response.headers['X-Foo'] = 'Parachute' + return response + return 'Hello World!' + + This is more useful if a function other than the view function wants to + modify a response. For instance think of a decorator that wants to add + some headers without converting the return value into a response object. + + .. versionadded:: 0.9 + """ + _request_ctx_stack.top._after_request_functions.append(f) + return f + + +def copy_current_request_context(f): + """A helper function that decorates a function to retain the current + request context. This is useful when working with greenlets. The moment + the function is decorated a copy of the request context is created and + then pushed when the function is called. + + Example:: + + import gevent + from flask import copy_current_request_context + + @app.route('/') + def index(): + @copy_current_request_context + def do_some_work(): + # do some work here, it can access flask.request like you + # would otherwise in the view function. + ... + gevent.spawn(do_some_work) + return 'Regular response' + + .. versionadded:: 0.10 + """ + top = _request_ctx_stack.top + if top is None: + raise RuntimeError('This decorator can only be used at local scopes ' + 'when a request context is on the stack. For instance within ' + 'view functions.') + reqctx = top.copy() + def wrapper(*args, **kwargs): + with reqctx: + return f(*args, **kwargs) + return update_wrapper(wrapper, f) + + +def has_request_context(): + """If you have code that wants to test if a request context is there or + not this function can be used. For instance, you may want to take advantage + of request information if the request object is available, but fail + silently if it is unavailable. + + :: + + class User(db.Model): + + def __init__(self, username, remote_addr=None): + self.username = username + if remote_addr is None and has_request_context(): + remote_addr = request.remote_addr + self.remote_addr = remote_addr + + Alternatively you can also just test any of the context bound objects + (such as :class:`request` or :class:`g` for truthness):: + + class User(db.Model): + + def __init__(self, username, remote_addr=None): + self.username = username + if remote_addr is None and request: + remote_addr = request.remote_addr + self.remote_addr = remote_addr + + .. versionadded:: 0.7 + """ + return _request_ctx_stack.top is not None + + +def has_app_context(): + """Works like :func:`has_request_context` but for the application + context. You can also just do a boolean check on the + :data:`current_app` object instead. + + .. versionadded:: 0.9 + """ + return _app_ctx_stack.top is not None + + +class AppContext(object): + """The application context binds an application object implicitly + to the current thread or greenlet, similar to how the + :class:`RequestContext` binds request information. The application + context is also implicitly created if a request context is created + but the application is not on top of the individual application + context. + """ + + def __init__(self, app): + self.app = app + self.url_adapter = app.create_url_adapter(None) + self.g = app.app_ctx_globals_class() + + # Like request context, app contexts can be pushed multiple times + # but there a basic "refcount" is enough to track them. + self._refcnt = 0 + + def push(self): + """Binds the app context to the current context.""" + self._refcnt += 1 + _app_ctx_stack.push(self) + appcontext_pushed.send(self.app) + + def pop(self, exc=None): + """Pops the app context.""" + self._refcnt -= 1 + if self._refcnt <= 0: + if exc is None: + exc = sys.exc_info()[1] + self.app.do_teardown_appcontext(exc) + rv = _app_ctx_stack.pop() + assert rv is self, 'Popped wrong app context. (%r instead of %r)' \ + % (rv, self) + appcontext_popped.send(self.app) + + def __enter__(self): + self.push() + return self + + def __exit__(self, exc_type, exc_value, tb): + self.pop(exc_value) + + +class RequestContext(object): + """The request context contains all request relevant information. It is + created at the beginning of the request and pushed to the + `_request_ctx_stack` and removed at the end of it. It will create the + URL adapter and request object for the WSGI environment provided. + + Do not attempt to use this class directly, instead use + :meth:`~flask.Flask.test_request_context` and + :meth:`~flask.Flask.request_context` to create this object. + + When the request context is popped, it will evaluate all the + functions registered on the application for teardown execution + (:meth:`~flask.Flask.teardown_request`). + + The request context is automatically popped at the end of the request + for you. In debug mode the request context is kept around if + exceptions happen so that interactive debuggers have a chance to + introspect the data. With 0.4 this can also be forced for requests + that did not fail and outside of `DEBUG` mode. By setting + ``'flask._preserve_context'`` to `True` on the WSGI environment the + context will not pop itself at the end of the request. This is used by + the :meth:`~flask.Flask.test_client` for example to implement the + deferred cleanup functionality. + + You might find this helpful for unittests where you need the + information from the context local around for a little longer. Make + sure to properly :meth:`~werkzeug.LocalStack.pop` the stack yourself in + that situation, otherwise your unittests will leak memory. + """ + + def __init__(self, app, environ, request=None): + self.app = app + if request is None: + request = app.request_class(environ) + self.request = request + self.url_adapter = app.create_url_adapter(self.request) + self.flashes = None + self.session = None + + # Request contexts can be pushed multiple times and interleaved with + # other request contexts. Now only if the last level is popped we + # get rid of them. Additionally if an application context is missing + # one is created implicitly so for each level we add this information + self._implicit_app_ctx_stack = [] + + # indicator if the context was preserved. Next time another context + # is pushed the preserved context is popped. + self.preserved = False + + # remembers the exception for pop if there is one in case the context + # preservation kicks in. + self._preserved_exc = None + + # Functions that should be executed after the request on the response + # object. These will be called before the regular "after_request" + # functions. + self._after_request_functions = [] + + self.match_request() + + # XXX: Support for deprecated functionality. This is going away with + # Flask 1.0 + blueprint = self.request.blueprint + if blueprint is not None: + # better safe than sorry, we don't want to break code that + # already worked + bp = app.blueprints.get(blueprint) + if bp is not None and blueprint_is_module(bp): + self.request._is_old_module = True + + def _get_g(self): + return _app_ctx_stack.top.g + def _set_g(self, value): + _app_ctx_stack.top.g = value + g = property(_get_g, _set_g) + del _get_g, _set_g + + def copy(self): + """Creates a copy of this request context with the same request object. + This can be used to move a request context to a different greenlet. + Because the actual request object is the same this cannot be used to + move a request context to a different thread unless access to the + request object is locked. + + .. versionadded:: 0.10 + """ + return self.__class__(self.app, + environ=self.request.environ, + request=self.request + ) + + def match_request(self): + """Can be overridden by a subclass to hook into the matching + of the request. + """ + try: + url_rule, self.request.view_args = \ + self.url_adapter.match(return_rule=True) + self.request.url_rule = url_rule + except HTTPException as e: + self.request.routing_exception = e + + def push(self): + """Binds the request context to the current context.""" + # If an exception occurs in debug mode or if context preservation is + # activated under exception situations exactly one context stays + # on the stack. The rationale is that you want to access that + # information under debug situations. However if someone forgets to + # pop that context again we want to make sure that on the next push + # it's invalidated, otherwise we run at risk that something leaks + # memory. This is usually only a problem in testsuite since this + # functionality is not active in production environments. + top = _request_ctx_stack.top + if top is not None and top.preserved: + top.pop(top._preserved_exc) + + # Before we push the request context we have to ensure that there + # is an application context. + app_ctx = _app_ctx_stack.top + if app_ctx is None or app_ctx.app != self.app: + app_ctx = self.app.app_context() + app_ctx.push() + self._implicit_app_ctx_stack.append(app_ctx) + else: + self._implicit_app_ctx_stack.append(None) + + _request_ctx_stack.push(self) + + # Open the session at the moment that the request context is + # available. This allows a custom open_session method to use the + # request context (e.g. code that access database information + # stored on `g` instead of the appcontext). + self.session = self.app.open_session(self.request) + if self.session is None: + self.session = self.app.make_null_session() + + def pop(self, exc=None): + """Pops the request context and unbinds it by doing that. This will + also trigger the execution of functions registered by the + :meth:`~flask.Flask.teardown_request` decorator. + + .. versionchanged:: 0.9 + Added the `exc` argument. + """ + app_ctx = self._implicit_app_ctx_stack.pop() + + clear_request = False + if not self._implicit_app_ctx_stack: + self.preserved = False + self._preserved_exc = None + if exc is None: + exc = sys.exc_info()[1] + self.app.do_teardown_request(exc) + + # If this interpreter supports clearing the exception information + # we do that now. This will only go into effect on Python 2.x, + # on 3.x it disappears automatically at the end of the exception + # stack. + if hasattr(sys, 'exc_clear'): + sys.exc_clear() + + request_close = getattr(self.request, 'close', None) + if request_close is not None: + request_close() + clear_request = True + + rv = _request_ctx_stack.pop() + assert rv is self, 'Popped wrong request context. (%r instead of %r)' \ + % (rv, self) + + # get rid of circular dependencies at the end of the request + # so that we don't require the GC to be active. + if clear_request: + rv.request.environ['werkzeug.request'] = None + + # Get rid of the app as well if necessary. + if app_ctx is not None: + app_ctx.pop(exc) + + def auto_pop(self, exc): + if self.request.environ.get('flask._preserve_context') or \ + (exc is not None and self.app.preserve_context_on_exception): + self.preserved = True + self._preserved_exc = exc + else: + self.pop(exc) + + def __enter__(self): + self.push() + return self + + def __exit__(self, exc_type, exc_value, tb): + # do not pop the request stack if we are in debug mode and an + # exception happened. This will allow the debugger to still + # access the request object in the interactive shell. Furthermore + # the context can be force kept alive for the test client. + # See flask.testing for how this works. + self.auto_pop(exc_value) + + def __repr__(self): + return '<%s \'%s\' [%s] of %s>' % ( + self.__class__.__name__, + self.request.url, + self.request.method, + self.app.name, + ) diff --git a/lib/flask/ctx.pyc b/lib/flask/ctx.pyc new file mode 100644 index 0000000..25a21f6 Binary files /dev/null and b/lib/flask/ctx.pyc differ diff --git a/lib/flask/debughelpers.py b/lib/flask/debughelpers.py new file mode 100644 index 0000000..2f8510f --- /dev/null +++ b/lib/flask/debughelpers.py @@ -0,0 +1,87 @@ +# -*- coding: utf-8 -*- +""" + flask.debughelpers + ~~~~~~~~~~~~~~~~~~ + + Various helpers to make the development experience better. + + :copyright: (c) 2011 by Armin Ronacher. + :license: BSD, see LICENSE for more details. +""" +from ._compat import implements_to_string + + +class UnexpectedUnicodeError(AssertionError, UnicodeError): + """Raised in places where we want some better error reporting for + unexpected unicode or binary data. + """ + + +@implements_to_string +class DebugFilesKeyError(KeyError, AssertionError): + """Raised from request.files during debugging. The idea is that it can + provide a better error message than just a generic KeyError/BadRequest. + """ + + def __init__(self, request, key): + form_matches = request.form.getlist(key) + buf = ['You tried to access the file "%s" in the request.files ' + 'dictionary but it does not exist. The mimetype for the request ' + 'is "%s" instead of "multipart/form-data" which means that no ' + 'file contents were transmitted. To fix this error you should ' + 'provide enctype="multipart/form-data" in your form.' % + (key, request.mimetype)] + if form_matches: + buf.append('\n\nThe browser instead transmitted some file names. ' + 'This was submitted: %s' % ', '.join('"%s"' % x + for x in form_matches)) + self.msg = ''.join(buf) + + def __str__(self): + return self.msg + + +class FormDataRoutingRedirect(AssertionError): + """This exception is raised by Flask in debug mode if it detects a + redirect caused by the routing system when the request method is not + GET, HEAD or OPTIONS. Reasoning: form data will be dropped. + """ + + def __init__(self, request): + exc = request.routing_exception + buf = ['A request was sent to this URL (%s) but a redirect was ' + 'issued automatically by the routing system to "%s".' + % (request.url, exc.new_url)] + + # In case just a slash was appended we can be extra helpful + if request.base_url + '/' == exc.new_url.split('?')[0]: + buf.append(' The URL was defined with a trailing slash so ' + 'Flask will automatically redirect to the URL ' + 'with the trailing slash if it was accessed ' + 'without one.') + + buf.append(' Make sure to directly send your %s-request to this URL ' + 'since we can\'t make browsers or HTTP clients redirect ' + 'with form data reliably or without user interaction.' % + request.method) + buf.append('\n\nNote: this exception is only raised in debug mode') + AssertionError.__init__(self, ''.join(buf).encode('utf-8')) + + +def attach_enctype_error_multidict(request): + """Since Flask 0.8 we're monkeypatching the files object in case a + request is detected that does not use multipart form data but the files + object is accessed. + """ + oldcls = request.files.__class__ + class newcls(oldcls): + def __getitem__(self, key): + try: + return oldcls.__getitem__(self, key) + except KeyError as e: + if key not in request.form: + raise + raise DebugFilesKeyError(request, key) + newcls.__name__ = oldcls.__name__ + newcls.__module__ = oldcls.__module__ + request.files.__class__ = newcls diff --git a/lib/flask/debughelpers.pyc b/lib/flask/debughelpers.pyc new file mode 100644 index 0000000..11d3941 Binary files /dev/null and b/lib/flask/debughelpers.pyc differ diff --git a/lib/flask/ext/__init__.py b/lib/flask/ext/__init__.py new file mode 100644 index 0000000..f29958a --- /dev/null +++ b/lib/flask/ext/__init__.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +""" + flask.ext + ~~~~~~~~~ + + Redirect imports for extensions. This module basically makes it possible + for us to transition from flaskext.foo to flask_foo without having to + force all extensions to upgrade at the same time. + + When a user does ``from flask.ext.foo import bar`` it will attempt to + import ``from flask_foo import bar`` first and when that fails it will + try to import ``from flaskext.foo import bar``. + + We're switching from namespace packages because it was just too painful for + everybody involved. + + :copyright: (c) 2011 by Armin Ronacher. + :license: BSD, see LICENSE for more details. +""" + + +def setup(): + from ..exthook import ExtensionImporter + importer = ExtensionImporter(['flask_%s', 'flaskext.%s'], __name__) + importer.install() + + +setup() +del setup diff --git a/lib/flask/ext/__init__.pyc b/lib/flask/ext/__init__.pyc new file mode 100644 index 0000000..c5a576d Binary files /dev/null and b/lib/flask/ext/__init__.pyc differ diff --git a/lib/flask/exthook.py b/lib/flask/exthook.py new file mode 100644 index 0000000..d0d814c --- /dev/null +++ b/lib/flask/exthook.py @@ -0,0 +1,120 @@ +# -*- coding: utf-8 -*- +""" + flask.exthook + ~~~~~~~~~~~~~ + + Redirect imports for extensions. This module basically makes it possible + for us to transition from flaskext.foo to flask_foo without having to + force all extensions to upgrade at the same time. + + When a user does ``from flask.ext.foo import bar`` it will attempt to + import ``from flask_foo import bar`` first and when that fails it will + try to import ``from flaskext.foo import bar``. + + We're switching from namespace packages because it was just too painful for + everybody involved. + + This is used by `flask.ext`. + + :copyright: (c) 2011 by Armin Ronacher. + :license: BSD, see LICENSE for more details. +""" +import sys +import os +from ._compat import reraise + + +class ExtensionImporter(object): + """This importer redirects imports from this submodule to other locations. + This makes it possible to transition from the old flaskext.name to the + newer flask_name without people having a hard time. + """ + + def __init__(self, module_choices, wrapper_module): + self.module_choices = module_choices + self.wrapper_module = wrapper_module + self.prefix = wrapper_module + '.' + self.prefix_cutoff = wrapper_module.count('.') + 1 + + def __eq__(self, other): + return self.__class__.__module__ == other.__class__.__module__ and \ + self.__class__.__name__ == other.__class__.__name__ and \ + self.wrapper_module == other.wrapper_module and \ + self.module_choices == other.module_choices + + def __ne__(self, other): + return not self.__eq__(other) + + def install(self): + sys.meta_path[:] = [x for x in sys.meta_path if self != x] + [self] + + def find_module(self, fullname, path=None): + if fullname.startswith(self.prefix): + return self + + def load_module(self, fullname): + if fullname in sys.modules: + return sys.modules[fullname] + modname = fullname.split('.', self.prefix_cutoff)[self.prefix_cutoff] + for path in self.module_choices: + realname = path % modname + try: + __import__(realname) + except ImportError: + exc_type, exc_value, tb = sys.exc_info() + # since we only establish the entry in sys.modules at the + # very this seems to be redundant, but if recursive imports + # happen we will call into the move import a second time. + # On the second invocation we still don't have an entry for + # fullname in sys.modules, but we will end up with the same + # fake module name and that import will succeed since this + # one already has a temporary entry in the modules dict. + # Since this one "succeeded" temporarily that second + # invocation now will have created a fullname entry in + # sys.modules which we have to kill. + sys.modules.pop(fullname, None) + + # If it's an important traceback we reraise it, otherwise + # we swallow it and try the next choice. The skipped frame + # is the one from __import__ above which we don't care about + if self.is_important_traceback(realname, tb): + reraise(exc_type, exc_value, tb.tb_next) + continue + module = sys.modules[fullname] = sys.modules[realname] + if '.' not in modname: + setattr(sys.modules[self.wrapper_module], modname, module) + return module + raise ImportError('No module named %s' % fullname) + + def is_important_traceback(self, important_module, tb): + """Walks a traceback's frames and checks if any of the frames + originated in the given important module. If that is the case then we + were able to import the module itself but apparently something went + wrong when the module was imported. (Eg: import of an import failed). + """ + while tb is not None: + if self.is_important_frame(important_module, tb): + return True + tb = tb.tb_next + return False + + def is_important_frame(self, important_module, tb): + """Checks a single frame if it's important.""" + g = tb.tb_frame.f_globals + if '__name__' not in g: + return False + + module_name = g['__name__'] + + # Python 2.7 Behavior. Modules are cleaned up late so the + # name shows up properly here. Success! + if module_name == important_module: + return True + + # Some python versions will will clean up modules so early that the + # module name at that point is no longer set. Try guessing from + # the filename then. + filename = os.path.abspath(tb.tb_frame.f_code.co_filename) + test_string = os.path.sep + important_module.replace('.', os.path.sep) + return test_string + '.py' in filename or \ + test_string + os.path.sep + '__init__.py' in filename diff --git a/lib/flask/exthook.pyc b/lib/flask/exthook.pyc new file mode 100644 index 0000000..2996675 Binary files /dev/null and b/lib/flask/exthook.pyc differ diff --git a/lib/flask/globals.py b/lib/flask/globals.py new file mode 100644 index 0000000..67d41f5 --- /dev/null +++ b/lib/flask/globals.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +""" + flask.globals + ~~~~~~~~~~~~~ + + Defines all the global objects that are proxies to the current + active context. + + :copyright: (c) 2011 by Armin Ronacher. + :license: BSD, see LICENSE for more details. +""" + +from functools import partial +from werkzeug.local import LocalStack, LocalProxy + + +def _lookup_req_object(name): + top = _request_ctx_stack.top + if top is None: + raise RuntimeError('working outside of request context') + return getattr(top, name) + + +def _lookup_app_object(name): + top = _app_ctx_stack.top + if top is None: + raise RuntimeError('working outside of application context') + return getattr(top, name) + + +def _find_app(): + top = _app_ctx_stack.top + if top is None: + raise RuntimeError('working outside of application context') + return top.app + + +# context locals +_request_ctx_stack = LocalStack() +_app_ctx_stack = LocalStack() +current_app = LocalProxy(_find_app) +request = LocalProxy(partial(_lookup_req_object, 'request')) +session = LocalProxy(partial(_lookup_req_object, 'session')) +g = LocalProxy(partial(_lookup_app_object, 'g')) diff --git a/lib/flask/globals.pyc b/lib/flask/globals.pyc new file mode 100644 index 0000000..03966ea Binary files /dev/null and b/lib/flask/globals.pyc differ diff --git a/lib/flask/helpers.py b/lib/flask/helpers.py new file mode 100644 index 0000000..1e7c87f --- /dev/null +++ b/lib/flask/helpers.py @@ -0,0 +1,849 @@ +# -*- coding: utf-8 -*- +""" + flask.helpers + ~~~~~~~~~~~~~ + + Implements various helpers. + + :copyright: (c) 2011 by Armin Ronacher. + :license: BSD, see LICENSE for more details. +""" + +import os +import sys +import pkgutil +import posixpath +import mimetypes +from time import time +from zlib import adler32 +from threading import RLock +from werkzeug.routing import BuildError +from functools import update_wrapper + +try: + from werkzeug.urls import url_quote +except ImportError: + from urlparse import quote as url_quote + +from werkzeug.datastructures import Headers +from werkzeug.exceptions import NotFound + +# this was moved in 0.7 +try: + from werkzeug.wsgi import wrap_file +except ImportError: + from werkzeug.utils import wrap_file + +from jinja2 import FileSystemLoader + +from .signals import message_flashed +from .globals import session, _request_ctx_stack, _app_ctx_stack, \ + current_app, request +from ._compat import string_types, text_type + + +# sentinel +_missing = object() + + +# what separators does this operating system provide that are not a slash? +# this is used by the send_from_directory function to ensure that nobody is +# able to access files from outside the filesystem. +_os_alt_seps = list(sep for sep in [os.path.sep, os.path.altsep] + if sep not in (None, '/')) + + +def _endpoint_from_view_func(view_func): + """Internal helper that returns the default endpoint for a given + function. This always is the function name. + """ + assert view_func is not None, 'expected view func if endpoint ' \ + 'is not provided.' + return view_func.__name__ + + +def stream_with_context(generator_or_function): + """Request contexts disappear when the response is started on the server. + This is done for efficiency reasons and to make it less likely to encounter + memory leaks with badly written WSGI middlewares. The downside is that if + you are using streamed responses, the generator cannot access request bound + information any more. + + This function however can help you keep the context around for longer:: + + from flask import stream_with_context, request, Response + + @app.route('/stream') + def streamed_response(): + @stream_with_context + def generate(): + yield 'Hello ' + yield request.args['name'] + yield '!' + return Response(generate()) + + Alternatively it can also be used around a specific generator:: + + from flask import stream_with_context, request, Response + + @app.route('/stream') + def streamed_response(): + def generate(): + yield 'Hello ' + yield request.args['name'] + yield '!' + return Response(stream_with_context(generate())) + + .. versionadded:: 0.9 + """ + try: + gen = iter(generator_or_function) + except TypeError: + def decorator(*args, **kwargs): + gen = generator_or_function() + return stream_with_context(gen) + return update_wrapper(decorator, generator_or_function) + + def generator(): + ctx = _request_ctx_stack.top + if ctx is None: + raise RuntimeError('Attempted to stream with context but ' + 'there was no context in the first place to keep around.') + with ctx: + # Dummy sentinel. Has to be inside the context block or we're + # not actually keeping the context around. + yield None + + # The try/finally is here so that if someone passes a WSGI level + # iterator in we're still running the cleanup logic. Generators + # don't need that because they are closed on their destruction + # automatically. + try: + for item in gen: + yield item + finally: + if hasattr(gen, 'close'): + gen.close() + + # The trick is to start the generator. Then the code execution runs until + # the first dummy None is yielded at which point the context was already + # pushed. This item is discarded. Then when the iteration continues the + # real generator is executed. + wrapped_g = generator() + next(wrapped_g) + return wrapped_g + + +def make_response(*args): + """Sometimes it is necessary to set additional headers in a view. Because + views do not have to return response objects but can return a value that + is converted into a response object by Flask itself, it becomes tricky to + add headers to it. This function can be called instead of using a return + and you will get a response object which you can use to attach headers. + + If view looked like this and you want to add a new header:: + + def index(): + return render_template('index.html', foo=42) + + You can now do something like this:: + + def index(): + response = make_response(render_template('index.html', foo=42)) + response.headers['X-Parachutes'] = 'parachutes are cool' + return response + + This function accepts the very same arguments you can return from a + view function. This for example creates a response with a 404 error + code:: + + response = make_response(render_template('not_found.html'), 404) + + The other use case of this function is to force the return value of a + view function into a response which is helpful with view + decorators:: + + response = make_response(view_function()) + response.headers['X-Parachutes'] = 'parachutes are cool' + + Internally this function does the following things: + + - if no arguments are passed, it creates a new response argument + - if one argument is passed, :meth:`flask.Flask.make_response` + is invoked with it. + - if more than one argument is passed, the arguments are passed + to the :meth:`flask.Flask.make_response` function as tuple. + + .. versionadded:: 0.6 + """ + if not args: + return current_app.response_class() + if len(args) == 1: + args = args[0] + return current_app.make_response(args) + + +def url_for(endpoint, **values): + """Generates a URL to the given endpoint with the method provided. + + Variable arguments that are unknown to the target endpoint are appended + to the generated URL as query arguments. If the value of a query argument + is `None`, the whole pair is skipped. In case blueprints are active + you can shortcut references to the same blueprint by prefixing the + local endpoint with a dot (``.``). + + This will reference the index function local to the current blueprint:: + + url_for('.index') + + For more information, head over to the :ref:`Quickstart `. + + To integrate applications, :class:`Flask` has a hook to intercept URL build + errors through :attr:`Flask.build_error_handler`. The `url_for` function + results in a :exc:`~werkzeug.routing.BuildError` when the current app does + not have a URL for the given endpoint and values. When it does, the + :data:`~flask.current_app` calls its :attr:`~Flask.build_error_handler` if + it is not `None`, which can return a string to use as the result of + `url_for` (instead of `url_for`'s default to raise the + :exc:`~werkzeug.routing.BuildError` exception) or re-raise the exception. + An example:: + + def external_url_handler(error, endpoint, **values): + "Looks up an external URL when `url_for` cannot build a URL." + # This is an example of hooking the build_error_handler. + # Here, lookup_url is some utility function you've built + # which looks up the endpoint in some external URL registry. + url = lookup_url(endpoint, **values) + if url is None: + # External lookup did not have a URL. + # Re-raise the BuildError, in context of original traceback. + exc_type, exc_value, tb = sys.exc_info() + if exc_value is error: + raise exc_type, exc_value, tb + else: + raise error + # url_for will use this result, instead of raising BuildError. + return url + + app.build_error_handler = external_url_handler + + Here, `error` is the instance of :exc:`~werkzeug.routing.BuildError`, and + `endpoint` and `**values` are the arguments passed into `url_for`. Note + that this is for building URLs outside the current application, and not for + handling 404 NotFound errors. + + .. versionadded:: 0.10 + The `_scheme` parameter was added. + + .. versionadded:: 0.9 + The `_anchor` and `_method` parameters were added. + + .. versionadded:: 0.9 + Calls :meth:`Flask.handle_build_error` on + :exc:`~werkzeug.routing.BuildError`. + + :param endpoint: the endpoint of the URL (name of the function) + :param values: the variable arguments of the URL rule + :param _external: if set to `True`, an absolute URL is generated. Server + address can be changed via `SERVER_NAME` configuration variable which + defaults to `localhost`. + :param _scheme: a string specifying the desired URL scheme. The `_external` + parameter must be set to `True` or a `ValueError` is raised. + :param _anchor: if provided this is added as anchor to the URL. + :param _method: if provided this explicitly specifies an HTTP method. + """ + appctx = _app_ctx_stack.top + reqctx = _request_ctx_stack.top + if appctx is None: + raise RuntimeError('Attempted to generate a URL without the ' + 'application context being pushed. This has to be ' + 'executed when application context is available.') + + # If request specific information is available we have some extra + # features that support "relative" urls. + if reqctx is not None: + url_adapter = reqctx.url_adapter + blueprint_name = request.blueprint + if not reqctx.request._is_old_module: + if endpoint[:1] == '.': + if blueprint_name is not None: + endpoint = blueprint_name + endpoint + else: + endpoint = endpoint[1:] + else: + # TODO: get rid of this deprecated functionality in 1.0 + if '.' not in endpoint: + if blueprint_name is not None: + endpoint = blueprint_name + '.' + endpoint + elif endpoint.startswith('.'): + endpoint = endpoint[1:] + external = values.pop('_external', False) + + # Otherwise go with the url adapter from the appctx and make + # the urls external by default. + else: + url_adapter = appctx.url_adapter + if url_adapter is None: + raise RuntimeError('Application was not able to create a URL ' + 'adapter for request independent URL generation. ' + 'You might be able to fix this by setting ' + 'the SERVER_NAME config variable.') + external = values.pop('_external', True) + + anchor = values.pop('_anchor', None) + method = values.pop('_method', None) + scheme = values.pop('_scheme', None) + appctx.app.inject_url_defaults(endpoint, values) + + if scheme is not None: + if not external: + raise ValueError('When specifying _scheme, _external must be True') + url_adapter.url_scheme = scheme + + try: + rv = url_adapter.build(endpoint, values, method=method, + force_external=external) + except BuildError as error: + # We need to inject the values again so that the app callback can + # deal with that sort of stuff. + values['_external'] = external + values['_anchor'] = anchor + values['_method'] = method + return appctx.app.handle_url_build_error(error, endpoint, values) + + if anchor is not None: + rv += '#' + url_quote(anchor) + return rv + + +def get_template_attribute(template_name, attribute): + """Loads a macro (or variable) a template exports. This can be used to + invoke a macro from within Python code. If you for example have a + template named `_cider.html` with the following contents: + + .. sourcecode:: html+jinja + + {% macro hello(name) %}Hello {{ name }}!{% endmacro %} + + You can access this from Python code like this:: + + hello = get_template_attribute('_cider.html', 'hello') + return hello('World') + + .. versionadded:: 0.2 + + :param template_name: the name of the template + :param attribute: the name of the variable of macro to access + """ + return getattr(current_app.jinja_env.get_template(template_name).module, + attribute) + + +def flash(message, category='message'): + """Flashes a message to the next request. In order to remove the + flashed message from the session and to display it to the user, + the template has to call :func:`get_flashed_messages`. + + .. versionchanged:: 0.3 + `category` parameter added. + + :param message: the message to be flashed. + :param category: the category for the message. The following values + are recommended: ``'message'`` for any kind of message, + ``'error'`` for errors, ``'info'`` for information + messages and ``'warning'`` for warnings. However any + kind of string can be used as category. + """ + # Original implementation: + # + # session.setdefault('_flashes', []).append((category, message)) + # + # This assumed that changes made to mutable structures in the session are + # are always in sync with the sess on object, which is not true for session + # implementations that use external storage for keeping their keys/values. + flashes = session.get('_flashes', []) + flashes.append((category, message)) + session['_flashes'] = flashes + message_flashed.send(current_app._get_current_object(), + message=message, category=category) + + +def get_flashed_messages(with_categories=False, category_filter=[]): + """Pulls all flashed messages from the session and returns them. + Further calls in the same request to the function will return + the same messages. By default just the messages are returned, + but when `with_categories` is set to `True`, the return value will + be a list of tuples in the form ``(category, message)`` instead. + + Filter the flashed messages to one or more categories by providing those + categories in `category_filter`. This allows rendering categories in + separate html blocks. The `with_categories` and `category_filter` + arguments are distinct: + + * `with_categories` controls whether categories are returned with message + text (`True` gives a tuple, where `False` gives just the message text). + * `category_filter` filters the messages down to only those matching the + provided categories. + + See :ref:`message-flashing-pattern` for examples. + + .. versionchanged:: 0.3 + `with_categories` parameter added. + + .. versionchanged:: 0.9 + `category_filter` parameter added. + + :param with_categories: set to `True` to also receive categories. + :param category_filter: whitelist of categories to limit return values + """ + flashes = _request_ctx_stack.top.flashes + if flashes is None: + _request_ctx_stack.top.flashes = flashes = session.pop('_flashes') \ + if '_flashes' in session else [] + if category_filter: + flashes = list(filter(lambda f: f[0] in category_filter, flashes)) + if not with_categories: + return [x[1] for x in flashes] + return flashes + + +def send_file(filename_or_fp, mimetype=None, as_attachment=False, + attachment_filename=None, add_etags=True, + cache_timeout=None, conditional=False): + """Sends the contents of a file to the client. This will use the + most efficient method available and configured. By default it will + try to use the WSGI server's file_wrapper support. Alternatively + you can set the application's :attr:`~Flask.use_x_sendfile` attribute + to ``True`` to directly emit an `X-Sendfile` header. This however + requires support of the underlying webserver for `X-Sendfile`. + + By default it will try to guess the mimetype for you, but you can + also explicitly provide one. For extra security you probably want + to send certain files as attachment (HTML for instance). The mimetype + guessing requires a `filename` or an `attachment_filename` to be + provided. + + Please never pass filenames to this function from user sources without + checking them first. Something like this is usually sufficient to + avoid security problems:: + + if '..' in filename or filename.startswith('/'): + abort(404) + + .. versionadded:: 0.2 + + .. versionadded:: 0.5 + The `add_etags`, `cache_timeout` and `conditional` parameters were + added. The default behavior is now to attach etags. + + .. versionchanged:: 0.7 + mimetype guessing and etag support for file objects was + deprecated because it was unreliable. Pass a filename if you are + able to, otherwise attach an etag yourself. This functionality + will be removed in Flask 1.0 + + .. versionchanged:: 0.9 + cache_timeout pulls its default from application config, when None. + + :param filename_or_fp: the filename of the file to send. This is + relative to the :attr:`~Flask.root_path` if a + relative path is specified. + Alternatively a file object might be provided + in which case `X-Sendfile` might not work and + fall back to the traditional method. Make sure + that the file pointer is positioned at the start + of data to send before calling :func:`send_file`. + :param mimetype: the mimetype of the file if provided, otherwise + auto detection happens. + :param as_attachment: set to `True` if you want to send this file with + a ``Content-Disposition: attachment`` header. + :param attachment_filename: the filename for the attachment if it + differs from the file's filename. + :param add_etags: set to `False` to disable attaching of etags. + :param conditional: set to `True` to enable conditional responses. + + :param cache_timeout: the timeout in seconds for the headers. When `None` + (default), this value is set by + :meth:`~Flask.get_send_file_max_age` of + :data:`~flask.current_app`. + """ + mtime = None + if isinstance(filename_or_fp, string_types): + filename = filename_or_fp + file = None + else: + from warnings import warn + file = filename_or_fp + filename = getattr(file, 'name', None) + + # XXX: this behavior is now deprecated because it was unreliable. + # removed in Flask 1.0 + if not attachment_filename and not mimetype \ + and isinstance(filename, string_types): + warn(DeprecationWarning('The filename support for file objects ' + 'passed to send_file is now deprecated. Pass an ' + 'attach_filename if you want mimetypes to be guessed.'), + stacklevel=2) + if add_etags: + warn(DeprecationWarning('In future flask releases etags will no ' + 'longer be generated for file objects passed to the send_file ' + 'function because this behavior was unreliable. Pass ' + 'filenames instead if possible, otherwise attach an etag ' + 'yourself based on another value'), stacklevel=2) + + if filename is not None: + if not os.path.isabs(filename): + filename = os.path.join(current_app.root_path, filename) + if mimetype is None and (filename or attachment_filename): + mimetype = mimetypes.guess_type(filename or attachment_filename)[0] + if mimetype is None: + mimetype = 'application/octet-stream' + + headers = Headers() + if as_attachment: + if attachment_filename is None: + if filename is None: + raise TypeError('filename unavailable, required for ' + 'sending as attachment') + attachment_filename = os.path.basename(filename) + headers.add('Content-Disposition', 'attachment', + filename=attachment_filename) + + if current_app.use_x_sendfile and filename: + if file is not None: + file.close() + headers['X-Sendfile'] = filename + headers['Content-Length'] = os.path.getsize(filename) + data = None + else: + if file is None: + file = open(filename, 'rb') + mtime = os.path.getmtime(filename) + headers['Content-Length'] = os.path.getsize(filename) + data = wrap_file(request.environ, file) + + rv = current_app.response_class(data, mimetype=mimetype, headers=headers, + direct_passthrough=True) + + # if we know the file modification date, we can store it as the + # the time of the last modification. + if mtime is not None: + rv.last_modified = int(mtime) + + rv.cache_control.public = True + if cache_timeout is None: + cache_timeout = current_app.get_send_file_max_age(filename) + if cache_timeout is not None: + rv.cache_control.max_age = cache_timeout + rv.expires = int(time() + cache_timeout) + + if add_etags and filename is not None: + rv.set_etag('flask-%s-%s-%s' % ( + os.path.getmtime(filename), + os.path.getsize(filename), + adler32( + filename.encode('utf-8') if isinstance(filename, text_type) + else filename + ) & 0xffffffff + )) + if conditional: + rv = rv.make_conditional(request) + # make sure we don't send x-sendfile for servers that + # ignore the 304 status code for x-sendfile. + if rv.status_code == 304: + rv.headers.pop('x-sendfile', None) + return rv + + +def safe_join(directory, filename): + """Safely join `directory` and `filename`. + + Example usage:: + + @app.route('/wiki/') + def wiki_page(filename): + filename = safe_join(app.config['WIKI_FOLDER'], filename) + with open(filename, 'rb') as fd: + content = fd.read() # Read and process the file content... + + :param directory: the base directory. + :param filename: the untrusted filename relative to that directory. + :raises: :class:`~werkzeug.exceptions.NotFound` if the resulting path + would fall out of `directory`. + """ + filename = posixpath.normpath(filename) + for sep in _os_alt_seps: + if sep in filename: + raise NotFound() + if os.path.isabs(filename) or \ + filename == '..' or \ + filename.startswith('../'): + raise NotFound() + return os.path.join(directory, filename) + + +def send_from_directory(directory, filename, **options): + """Send a file from a given directory with :func:`send_file`. This + is a secure way to quickly expose static files from an upload folder + or something similar. + + Example usage:: + + @app.route('/uploads/') + def download_file(filename): + return send_from_directory(app.config['UPLOAD_FOLDER'], + filename, as_attachment=True) + + .. admonition:: Sending files and Performance + + It is strongly recommended to activate either `X-Sendfile` support in + your webserver or (if no authentication happens) to tell the webserver + to serve files for the given path on its own without calling into the + web application for improved performance. + + .. versionadded:: 0.5 + + :param directory: the directory where all the files are stored. + :param filename: the filename relative to that directory to + download. + :param options: optional keyword arguments that are directly + forwarded to :func:`send_file`. + """ + filename = safe_join(directory, filename) + if not os.path.isfile(filename): + raise NotFound() + options.setdefault('conditional', True) + return send_file(filename, **options) + + +def get_root_path(import_name): + """Returns the path to a package or cwd if that cannot be found. This + returns the path of a package or the folder that contains a module. + + Not to be confused with the package path returned by :func:`find_package`. + """ + # Module already imported and has a file attribute. Use that first. + mod = sys.modules.get(import_name) + if mod is not None and hasattr(mod, '__file__'): + return os.path.dirname(os.path.abspath(mod.__file__)) + + # Next attempt: check the loader. + loader = pkgutil.get_loader(import_name) + + # Loader does not exist or we're referring to an unloaded main module + # or a main module without path (interactive sessions), go with the + # current working directory. + if loader is None or import_name == '__main__': + return os.getcwd() + + # For .egg, zipimporter does not have get_filename until Python 2.7. + # Some other loaders might exhibit the same behavior. + if hasattr(loader, 'get_filename'): + filepath = loader.get_filename(import_name) + else: + # Fall back to imports. + __import__(import_name) + filepath = sys.modules[import_name].__file__ + + # filepath is import_name.py for a module, or __init__.py for a package. + return os.path.dirname(os.path.abspath(filepath)) + + +def find_package(import_name): + """Finds a package and returns the prefix (or None if the package is + not installed) as well as the folder that contains the package or + module as a tuple. The package path returned is the module that would + have to be added to the pythonpath in order to make it possible to + import the module. The prefix is the path below which a UNIX like + folder structure exists (lib, share etc.). + """ + root_mod_name = import_name.split('.')[0] + loader = pkgutil.get_loader(root_mod_name) + if loader is None or import_name == '__main__': + # import name is not found, or interactive/main module + package_path = os.getcwd() + else: + # For .egg, zipimporter does not have get_filename until Python 2.7. + if hasattr(loader, 'get_filename'): + filename = loader.get_filename(root_mod_name) + elif hasattr(loader, 'archive'): + # zipimporter's loader.archive points to the .egg or .zip + # archive filename is dropped in call to dirname below. + filename = loader.archive + else: + # At least one loader is missing both get_filename and archive: + # Google App Engine's HardenedModulesHook + # + # Fall back to imports. + __import__(import_name) + filename = sys.modules[import_name].__file__ + package_path = os.path.abspath(os.path.dirname(filename)) + # package_path ends with __init__.py for a package + if loader.is_package(root_mod_name): + package_path = os.path.dirname(package_path) + + site_parent, site_folder = os.path.split(package_path) + py_prefix = os.path.abspath(sys.prefix) + if package_path.startswith(py_prefix): + return py_prefix, package_path + elif site_folder.lower() == 'site-packages': + parent, folder = os.path.split(site_parent) + # Windows like installations + if folder.lower() == 'lib': + base_dir = parent + # UNIX like installations + elif os.path.basename(parent).lower() == 'lib': + base_dir = os.path.dirname(parent) + else: + base_dir = site_parent + return base_dir, package_path + return None, package_path + + +class locked_cached_property(object): + """A decorator that converts a function into a lazy property. The + function wrapped is called the first time to retrieve the result + and then that calculated result is used the next time you access + the value. Works like the one in Werkzeug but has a lock for + thread safety. + """ + + def __init__(self, func, name=None, doc=None): + self.__name__ = name or func.__name__ + self.__module__ = func.__module__ + self.__doc__ = doc or func.__doc__ + self.func = func + self.lock = RLock() + + def __get__(self, obj, type=None): + if obj is None: + return self + with self.lock: + value = obj.__dict__.get(self.__name__, _missing) + if value is _missing: + value = self.func(obj) + obj.__dict__[self.__name__] = value + return value + + +class _PackageBoundObject(object): + + def __init__(self, import_name, template_folder=None): + #: The name of the package or module. Do not change this once + #: it was set by the constructor. + self.import_name = import_name + + #: location of the templates. `None` if templates should not be + #: exposed. + self.template_folder = template_folder + + #: Where is the app root located? + self.root_path = get_root_path(self.import_name) + + self._static_folder = None + self._static_url_path = None + + def _get_static_folder(self): + if self._static_folder is not None: + return os.path.join(self.root_path, self._static_folder) + def _set_static_folder(self, value): + self._static_folder = value + static_folder = property(_get_static_folder, _set_static_folder) + del _get_static_folder, _set_static_folder + + def _get_static_url_path(self): + if self._static_url_path is None: + if self.static_folder is None: + return None + return '/' + os.path.basename(self.static_folder) + return self._static_url_path + def _set_static_url_path(self, value): + self._static_url_path = value + static_url_path = property(_get_static_url_path, _set_static_url_path) + del _get_static_url_path, _set_static_url_path + + @property + def has_static_folder(self): + """This is `True` if the package bound object's container has a + folder named ``'static'``. + + .. versionadded:: 0.5 + """ + return self.static_folder is not None + + @locked_cached_property + def jinja_loader(self): + """The Jinja loader for this package bound object. + + .. versionadded:: 0.5 + """ + if self.template_folder is not None: + return FileSystemLoader(os.path.join(self.root_path, + self.template_folder)) + + def get_send_file_max_age(self, filename): + """Provides default cache_timeout for the :func:`send_file` functions. + + By default, this function returns ``SEND_FILE_MAX_AGE_DEFAULT`` from + the configuration of :data:`~flask.current_app`. + + Static file functions such as :func:`send_from_directory` use this + function, and :func:`send_file` calls this function on + :data:`~flask.current_app` when the given cache_timeout is `None`. If a + cache_timeout is given in :func:`send_file`, that timeout is used; + otherwise, this method is called. + + This allows subclasses to change the behavior when sending files based + on the filename. For example, to set the cache timeout for .js files + to 60 seconds:: + + class MyFlask(flask.Flask): + def get_send_file_max_age(self, name): + if name.lower().endswith('.js'): + return 60 + return flask.Flask.get_send_file_max_age(self, name) + + .. versionadded:: 0.9 + """ + return current_app.config['SEND_FILE_MAX_AGE_DEFAULT'] + + def send_static_file(self, filename): + """Function used internally to send static files from the static + folder to the browser. + + .. versionadded:: 0.5 + """ + if not self.has_static_folder: + raise RuntimeError('No static folder for this object') + # Ensure get_send_file_max_age is called in all cases. + # Here, we ensure get_send_file_max_age is called for Blueprints. + cache_timeout = self.get_send_file_max_age(filename) + return send_from_directory(self.static_folder, filename, + cache_timeout=cache_timeout) + + def open_resource(self, resource, mode='rb'): + """Opens a resource from the application's resource folder. To see + how this works, consider the following folder structure:: + + /myapplication.py + /schema.sql + /static + /style.css + /templates + /layout.html + /index.html + + If you want to open the `schema.sql` file you would do the + following:: + + with app.open_resource('schema.sql') as f: + contents = f.read() + do_something_with(contents) + + :param resource: the name of the resource. To access resources within + subfolders use forward slashes as separator. + :param mode: resource file opening mode, default is 'rb'. + """ + if mode not in ('r', 'rb'): + raise ValueError('Resources can only be opened for reading') + return open(os.path.join(self.root_path, resource), mode) diff --git a/lib/flask/helpers.pyc b/lib/flask/helpers.pyc new file mode 100644 index 0000000..2a01ea8 Binary files /dev/null and b/lib/flask/helpers.pyc differ diff --git a/lib/flask/json.py b/lib/flask/json.py new file mode 100644 index 0000000..45ba324 --- /dev/null +++ b/lib/flask/json.py @@ -0,0 +1,243 @@ +# -*- coding: utf-8 -*- +""" + flask.jsonimpl + ~~~~~~~~~~~~~~ + + Implementation helpers for the JSON support in Flask. + + :copyright: (c) 2012 by Armin Ronacher. + :license: BSD, see LICENSE for more details. +""" +import io +import uuid +from datetime import datetime +from .globals import current_app, request +from ._compat import text_type, PY2 + +from werkzeug.http import http_date +from jinja2 import Markup + +# Use the same json implementation as itsdangerous on which we +# depend anyways. +try: + from itsdangerous import simplejson as _json +except ImportError: + from itsdangerous import json as _json + + +# figure out if simplejson escapes slashes. This behavior was changed +# from one version to another without reason. +_slash_escape = '\\/' not in _json.dumps('/') + + +__all__ = ['dump', 'dumps', 'load', 'loads', 'htmlsafe_dump', + 'htmlsafe_dumps', 'JSONDecoder', 'JSONEncoder', + 'jsonify'] + + +def _wrap_reader_for_text(fp, encoding): + if isinstance(fp.read(0), bytes): + fp = io.TextIOWrapper(io.BufferedReader(fp), encoding) + return fp + + +def _wrap_writer_for_text(fp, encoding): + try: + fp.write('') + except TypeError: + fp = io.TextIOWrapper(fp, encoding) + return fp + + +class JSONEncoder(_json.JSONEncoder): + """The default Flask JSON encoder. This one extends the default simplejson + encoder by also supporting ``datetime`` objects, ``UUID`` as well as + ``Markup`` objects which are serialized as RFC 822 datetime strings (same + as the HTTP date format). In order to support more data types override the + :meth:`default` method. + """ + + def default(self, o): + """Implement this method in a subclass such that it returns a + serializable object for ``o``, or calls the base implementation (to + raise a ``TypeError``). + + For example, to support arbitrary iterators, you could implement + default like this:: + + def default(self, o): + try: + iterable = iter(o) + except TypeError: + pass + else: + return list(iterable) + return JSONEncoder.default(self, o) + """ + if isinstance(o, datetime): + return http_date(o) + if isinstance(o, uuid.UUID): + return str(o) + if hasattr(o, '__html__'): + return text_type(o.__html__()) + return _json.JSONEncoder.default(self, o) + + +class JSONDecoder(_json.JSONDecoder): + """The default JSON decoder. This one does not change the behavior from + the default simplejson encoder. Consult the :mod:`json` documentation + for more information. This decoder is not only used for the load + functions of this module but also :attr:`~flask.Request`. + """ + + +def _dump_arg_defaults(kwargs): + """Inject default arguments for dump functions.""" + if current_app: + kwargs.setdefault('cls', current_app.json_encoder) + if not current_app.config['JSON_AS_ASCII']: + kwargs.setdefault('ensure_ascii', False) + kwargs.setdefault('sort_keys', current_app.config['JSON_SORT_KEYS']) + else: + kwargs.setdefault('sort_keys', True) + kwargs.setdefault('cls', JSONEncoder) + + +def _load_arg_defaults(kwargs): + """Inject default arguments for load functions.""" + if current_app: + kwargs.setdefault('cls', current_app.json_decoder) + else: + kwargs.setdefault('cls', JSONDecoder) + + +def dumps(obj, **kwargs): + """Serialize ``obj`` to a JSON formatted ``str`` by using the application's + configured encoder (:attr:`~flask.Flask.json_encoder`) if there is an + application on the stack. + + This function can return ``unicode`` strings or ascii-only bytestrings by + default which coerce into unicode strings automatically. That behavior by + default is controlled by the ``JSON_AS_ASCII`` configuration variable + and can be overriden by the simplejson ``ensure_ascii`` parameter. + """ + _dump_arg_defaults(kwargs) + encoding = kwargs.pop('encoding', None) + rv = _json.dumps(obj, **kwargs) + if encoding is not None and isinstance(rv, text_type): + rv = rv.encode(encoding) + return rv + + +def dump(obj, fp, **kwargs): + """Like :func:`dumps` but writes into a file object.""" + _dump_arg_defaults(kwargs) + encoding = kwargs.pop('encoding', None) + if encoding is not None: + fp = _wrap_writer_for_text(fp, encoding) + _json.dump(obj, fp, **kwargs) + + +def loads(s, **kwargs): + """Unserialize a JSON object from a string ``s`` by using the application's + configured decoder (:attr:`~flask.Flask.json_decoder`) if there is an + application on the stack. + """ + _load_arg_defaults(kwargs) + if isinstance(s, bytes): + s = s.decode(kwargs.pop('encoding', None) or 'utf-8') + return _json.loads(s, **kwargs) + + +def load(fp, **kwargs): + """Like :func:`loads` but reads from a file object. + """ + _load_arg_defaults(kwargs) + if not PY2: + fp = _wrap_reader_for_text(fp, kwargs.pop('encoding', None) or 'utf-8') + return _json.load(fp, **kwargs) + + +def htmlsafe_dumps(obj, **kwargs): + """Works exactly like :func:`dumps` but is safe for use in ``') + self.assert_equal(rv, u'"\\u003c/script\\u003e"') + self.assert_equal(type(rv), text_type) + rv = render('{{ ""|tojson }}') + self.assert_equal(rv, '"\\u003c/script\\u003e"') + rv = render('{{ "<\0/script>"|tojson }}') + self.assert_equal(rv, '"\\u003c\\u0000/script\\u003e"') + rv = render('{{ "' % ( + render_traceback(self, full=full), + self.render_as_text().decode('utf-8', 'replace') + ) + + @property + def is_template_syntax_error(self): + """`True` if this is a template syntax error.""" + return isinstance(self.exc_value, TemplateSyntaxError) + + @property + def exc_info(self): + """Exception info tuple with a proxy around the frame objects.""" + return self.exc_type, self.exc_value, self.frames[0] + + @property + def standard_exc_info(self): + """Standard python exc_info for re-raising""" + tb = self.frames[0] + # the frame will be an actual traceback (or transparent proxy) if + # we are on pypy or a python implementation with support for tproxy + if type(tb) is not TracebackType: + tb = tb.tb + return self.exc_type, self.exc_value, tb + + +def make_traceback(exc_info, source_hint=None): + """Creates a processed traceback object from the exc_info.""" + exc_type, exc_value, tb = exc_info + if isinstance(exc_value, TemplateSyntaxError): + exc_info = translate_syntax_error(exc_value, source_hint) + initial_skip = 0 + else: + initial_skip = 1 + return translate_exception(exc_info, initial_skip) + + +def translate_syntax_error(error, source=None): + """Rewrites a syntax error to please traceback systems.""" + error.source = source + error.translated = True + exc_info = (error.__class__, error, None) + filename = error.filename + if filename is None: + filename = '' + return fake_exc_info(exc_info, filename, error.lineno) + + +def translate_exception(exc_info, initial_skip=0): + """If passed an exc_info it will automatically rewrite the exceptions + all the way down to the correct line numbers and frames. + """ + tb = exc_info[2] + frames = [] + + # skip some internal frames if wanted + for x in range(initial_skip): + if tb is not None: + tb = tb.tb_next + initial_tb = tb + + while tb is not None: + # skip frames decorated with @internalcode. These are internal + # calls we can't avoid and that are useless in template debugging + # output. + if tb.tb_frame.f_code in internal_code: + tb = tb.tb_next + continue + + # save a reference to the next frame if we override the current + # one with a faked one. + next = tb.tb_next + + # fake template exceptions + template = tb.tb_frame.f_globals.get('__jinja_template__') + if template is not None: + lineno = template.get_corresponding_lineno(tb.tb_lineno) + tb = fake_exc_info(exc_info[:2] + (tb,), template.filename, + lineno)[2] + + frames.append(make_frame_proxy(tb)) + tb = next + + # if we don't have any exceptions in the frames left, we have to + # reraise it unchanged. + # XXX: can we backup here? when could this happen? + if not frames: + reraise(exc_info[0], exc_info[1], exc_info[2]) + + return ProcessedTraceback(exc_info[0], exc_info[1], frames) + + +def fake_exc_info(exc_info, filename, lineno): + """Helper for `translate_exception`.""" + exc_type, exc_value, tb = exc_info + + # figure the real context out + if tb is not None: + real_locals = tb.tb_frame.f_locals.copy() + ctx = real_locals.get('context') + if ctx: + locals = ctx.get_all() + else: + locals = {} + for name, value in iteritems(real_locals): + if name.startswith('l_') and value is not missing: + locals[name[2:]] = value + + # if there is a local called __jinja_exception__, we get + # rid of it to not break the debug functionality. + locals.pop('__jinja_exception__', None) + else: + locals = {} + + # assamble fake globals we need + globals = { + '__name__': filename, + '__file__': filename, + '__jinja_exception__': exc_info[:2], + + # we don't want to keep the reference to the template around + # to not cause circular dependencies, but we mark it as Jinja + # frame for the ProcessedTraceback + '__jinja_template__': None + } + + # and fake the exception + code = compile('\n' * (lineno - 1) + raise_helper, filename, 'exec') + + # if it's possible, change the name of the code. This won't work + # on some python environments such as google appengine + try: + if tb is None: + location = 'template' + else: + function = tb.tb_frame.f_code.co_name + if function == 'root': + location = 'top-level template code' + elif function.startswith('block_'): + location = 'block "%s"' % function[6:] + else: + location = 'template' + code = code_type(0, code.co_nlocals, code.co_stacksize, + code.co_flags, code.co_code, code.co_consts, + code.co_names, code.co_varnames, filename, + location, code.co_firstlineno, + code.co_lnotab, (), ()) + except: + pass + + # execute the code and catch the new traceback + try: + exec(code, globals, locals) + except: + exc_info = sys.exc_info() + new_tb = exc_info[2].tb_next + + # return without this frame + return exc_info[:2] + (new_tb,) + + +def _init_ugly_crap(): + """This function implements a few ugly things so that we can patch the + traceback objects. The function returned allows resetting `tb_next` on + any python traceback object. Do not attempt to use this on non cpython + interpreters + """ + import ctypes + from types import TracebackType + + # figure out side of _Py_ssize_t + if hasattr(ctypes.pythonapi, 'Py_InitModule4_64'): + _Py_ssize_t = ctypes.c_int64 + else: + _Py_ssize_t = ctypes.c_int + + # regular python + class _PyObject(ctypes.Structure): + pass + _PyObject._fields_ = [ + ('ob_refcnt', _Py_ssize_t), + ('ob_type', ctypes.POINTER(_PyObject)) + ] + + # python with trace + if hasattr(sys, 'getobjects'): + class _PyObject(ctypes.Structure): + pass + _PyObject._fields_ = [ + ('_ob_next', ctypes.POINTER(_PyObject)), + ('_ob_prev', ctypes.POINTER(_PyObject)), + ('ob_refcnt', _Py_ssize_t), + ('ob_type', ctypes.POINTER(_PyObject)) + ] + + class _Traceback(_PyObject): + pass + _Traceback._fields_ = [ + ('tb_next', ctypes.POINTER(_Traceback)), + ('tb_frame', ctypes.POINTER(_PyObject)), + ('tb_lasti', ctypes.c_int), + ('tb_lineno', ctypes.c_int) + ] + + def tb_set_next(tb, next): + """Set the tb_next attribute of a traceback object.""" + if not (isinstance(tb, TracebackType) and + (next is None or isinstance(next, TracebackType))): + raise TypeError('tb_set_next arguments must be traceback objects') + obj = _Traceback.from_address(id(tb)) + if tb.tb_next is not None: + old = _Traceback.from_address(id(tb.tb_next)) + old.ob_refcnt -= 1 + if next is None: + obj.tb_next = ctypes.POINTER(_Traceback)() + else: + next = _Traceback.from_address(id(next)) + next.ob_refcnt += 1 + obj.tb_next = ctypes.pointer(next) + + return tb_set_next + + +# try to get a tb_set_next implementation if we don't have transparent +# proxies. +tb_set_next = None +if tproxy is None: + try: + tb_set_next = _init_ugly_crap() + except: + pass + del _init_ugly_crap diff --git a/lib/jinja2/debug.pyc b/lib/jinja2/debug.pyc new file mode 100644 index 0000000..e823695 Binary files /dev/null and b/lib/jinja2/debug.pyc differ diff --git a/lib/jinja2/defaults.py b/lib/jinja2/defaults.py new file mode 100644 index 0000000..a27cb80 --- /dev/null +++ b/lib/jinja2/defaults.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +""" + jinja2.defaults + ~~~~~~~~~~~~~~~ + + Jinja default filters and tags. + + :copyright: (c) 2010 by the Jinja Team. + :license: BSD, see LICENSE for more details. +""" +from jinja2._compat import range_type +from jinja2.utils import generate_lorem_ipsum, Cycler, Joiner + + +# defaults for the parser / lexer +BLOCK_START_STRING = '{%' +BLOCK_END_STRING = '%}' +VARIABLE_START_STRING = '{{' +VARIABLE_END_STRING = '}}' +COMMENT_START_STRING = '{#' +COMMENT_END_STRING = '#}' +LINE_STATEMENT_PREFIX = None +LINE_COMMENT_PREFIX = None +TRIM_BLOCKS = False +LSTRIP_BLOCKS = False +NEWLINE_SEQUENCE = '\n' +KEEP_TRAILING_NEWLINE = False + + +# default filters, tests and namespace +from jinja2.filters import FILTERS as DEFAULT_FILTERS +from jinja2.tests import TESTS as DEFAULT_TESTS +DEFAULT_NAMESPACE = { + 'range': range_type, + 'dict': lambda **kw: kw, + 'lipsum': generate_lorem_ipsum, + 'cycler': Cycler, + 'joiner': Joiner +} + + +# export all constants +__all__ = tuple(x for x in locals().keys() if x.isupper()) diff --git a/lib/jinja2/defaults.pyc b/lib/jinja2/defaults.pyc new file mode 100644 index 0000000..408fe81 Binary files /dev/null and b/lib/jinja2/defaults.pyc differ diff --git a/lib/jinja2/environment.py b/lib/jinja2/environment.py new file mode 100644 index 0000000..45fabad --- /dev/null +++ b/lib/jinja2/environment.py @@ -0,0 +1,1191 @@ +# -*- coding: utf-8 -*- +""" + jinja2.environment + ~~~~~~~~~~~~~~~~~~ + + Provides a class that holds runtime and parsing time options. + + :copyright: (c) 2010 by the Jinja Team. + :license: BSD, see LICENSE for more details. +""" +import os +import sys +from jinja2 import nodes +from jinja2.defaults import BLOCK_START_STRING, \ + BLOCK_END_STRING, VARIABLE_START_STRING, VARIABLE_END_STRING, \ + COMMENT_START_STRING, COMMENT_END_STRING, LINE_STATEMENT_PREFIX, \ + LINE_COMMENT_PREFIX, TRIM_BLOCKS, NEWLINE_SEQUENCE, \ + DEFAULT_FILTERS, DEFAULT_TESTS, DEFAULT_NAMESPACE, \ + KEEP_TRAILING_NEWLINE, LSTRIP_BLOCKS +from jinja2.lexer import get_lexer, TokenStream +from jinja2.parser import Parser +from jinja2.nodes import EvalContext +from jinja2.optimizer import optimize +from jinja2.compiler import generate +from jinja2.runtime import Undefined, new_context +from jinja2.exceptions import TemplateSyntaxError, TemplateNotFound, \ + TemplatesNotFound, TemplateRuntimeError +from jinja2.utils import import_string, LRUCache, Markup, missing, \ + concat, consume, internalcode +from jinja2._compat import imap, ifilter, string_types, iteritems, \ + text_type, reraise, implements_iterator, implements_to_string, \ + get_next, encode_filename, PY2, PYPY +from functools import reduce + + +# for direct template usage we have up to ten living environments +_spontaneous_environments = LRUCache(10) + +# the function to create jinja traceback objects. This is dynamically +# imported on the first exception in the exception handler. +_make_traceback = None + + +def get_spontaneous_environment(*args): + """Return a new spontaneous environment. A spontaneous environment is an + unnamed and unaccessible (in theory) environment that is used for + templates generated from a string and not from the file system. + """ + try: + env = _spontaneous_environments.get(args) + except TypeError: + return Environment(*args) + if env is not None: + return env + _spontaneous_environments[args] = env = Environment(*args) + env.shared = True + return env + + +def create_cache(size): + """Return the cache class for the given size.""" + if size == 0: + return None + if size < 0: + return {} + return LRUCache(size) + + +def copy_cache(cache): + """Create an empty copy of the given cache.""" + if cache is None: + return None + elif type(cache) is dict: + return {} + return LRUCache(cache.capacity) + + +def load_extensions(environment, extensions): + """Load the extensions from the list and bind it to the environment. + Returns a dict of instantiated environments. + """ + result = {} + for extension in extensions: + if isinstance(extension, string_types): + extension = import_string(extension) + result[extension.identifier] = extension(environment) + return result + + +def _environment_sanity_check(environment): + """Perform a sanity check on the environment.""" + assert issubclass(environment.undefined, Undefined), 'undefined must ' \ + 'be a subclass of undefined because filters depend on it.' + assert environment.block_start_string != \ + environment.variable_start_string != \ + environment.comment_start_string, 'block, variable and comment ' \ + 'start strings must be different' + assert environment.newline_sequence in ('\r', '\r\n', '\n'), \ + 'newline_sequence set to unknown line ending string.' + return environment + + +class Environment(object): + r"""The core component of Jinja is the `Environment`. It contains + important shared variables like configuration, filters, tests, + globals and others. Instances of this class may be modified if + they are not shared and if no template was loaded so far. + Modifications on environments after the first template was loaded + will lead to surprising effects and undefined behavior. + + Here the possible initialization parameters: + + `block_start_string` + The string marking the begin of a block. Defaults to ``'{%'``. + + `block_end_string` + The string marking the end of a block. Defaults to ``'%}'``. + + `variable_start_string` + The string marking the begin of a print statement. + Defaults to ``'{{'``. + + `variable_end_string` + The string marking the end of a print statement. Defaults to + ``'}}'``. + + `comment_start_string` + The string marking the begin of a comment. Defaults to ``'{#'``. + + `comment_end_string` + The string marking the end of a comment. Defaults to ``'#}'``. + + `line_statement_prefix` + If given and a string, this will be used as prefix for line based + statements. See also :ref:`line-statements`. + + `line_comment_prefix` + If given and a string, this will be used as prefix for line based + based comments. See also :ref:`line-statements`. + + .. versionadded:: 2.2 + + `trim_blocks` + If this is set to ``True`` the first newline after a block is + removed (block, not variable tag!). Defaults to `False`. + + `lstrip_blocks` + If this is set to ``True`` leading spaces and tabs are stripped + from the start of a line to a block. Defaults to `False`. + + `newline_sequence` + The sequence that starts a newline. Must be one of ``'\r'``, + ``'\n'`` or ``'\r\n'``. The default is ``'\n'`` which is a + useful default for Linux and OS X systems as well as web + applications. + + `keep_trailing_newline` + Preserve the trailing newline when rendering templates. + The default is ``False``, which causes a single newline, + if present, to be stripped from the end of the template. + + .. versionadded:: 2.7 + + `extensions` + List of Jinja extensions to use. This can either be import paths + as strings or extension classes. For more information have a + look at :ref:`the extensions documentation `. + + `optimized` + should the optimizer be enabled? Default is `True`. + + `undefined` + :class:`Undefined` or a subclass of it that is used to represent + undefined values in the template. + + `finalize` + A callable that can be used to process the result of a variable + expression before it is output. For example one can convert + `None` implicitly into an empty string here. + + `autoescape` + If set to true the XML/HTML autoescaping feature is enabled by + default. For more details about auto escaping see + :class:`~jinja2.utils.Markup`. As of Jinja 2.4 this can also + be a callable that is passed the template name and has to + return `True` or `False` depending on autoescape should be + enabled by default. + + .. versionchanged:: 2.4 + `autoescape` can now be a function + + `loader` + The template loader for this environment. + + `cache_size` + The size of the cache. Per default this is ``50`` which means + that if more than 50 templates are loaded the loader will clean + out the least recently used template. If the cache size is set to + ``0`` templates are recompiled all the time, if the cache size is + ``-1`` the cache will not be cleaned. + + `auto_reload` + Some loaders load templates from locations where the template + sources may change (ie: file system or database). If + `auto_reload` is set to `True` (default) every time a template is + requested the loader checks if the source changed and if yes, it + will reload the template. For higher performance it's possible to + disable that. + + `bytecode_cache` + If set to a bytecode cache object, this object will provide a + cache for the internal Jinja bytecode so that templates don't + have to be parsed if they were not changed. + + See :ref:`bytecode-cache` for more information. + """ + + #: if this environment is sandboxed. Modifying this variable won't make + #: the environment sandboxed though. For a real sandboxed environment + #: have a look at jinja2.sandbox. This flag alone controls the code + #: generation by the compiler. + sandboxed = False + + #: True if the environment is just an overlay + overlayed = False + + #: the environment this environment is linked to if it is an overlay + linked_to = None + + #: shared environments have this set to `True`. A shared environment + #: must not be modified + shared = False + + #: these are currently EXPERIMENTAL undocumented features. + exception_handler = None + exception_formatter = None + + def __init__(self, + block_start_string=BLOCK_START_STRING, + block_end_string=BLOCK_END_STRING, + variable_start_string=VARIABLE_START_STRING, + variable_end_string=VARIABLE_END_STRING, + comment_start_string=COMMENT_START_STRING, + comment_end_string=COMMENT_END_STRING, + line_statement_prefix=LINE_STATEMENT_PREFIX, + line_comment_prefix=LINE_COMMENT_PREFIX, + trim_blocks=TRIM_BLOCKS, + lstrip_blocks=LSTRIP_BLOCKS, + newline_sequence=NEWLINE_SEQUENCE, + keep_trailing_newline=KEEP_TRAILING_NEWLINE, + extensions=(), + optimized=True, + undefined=Undefined, + finalize=None, + autoescape=False, + loader=None, + cache_size=50, + auto_reload=True, + bytecode_cache=None): + # !!Important notice!! + # The constructor accepts quite a few arguments that should be + # passed by keyword rather than position. However it's important to + # not change the order of arguments because it's used at least + # internally in those cases: + # - spontaneous environments (i18n extension and Template) + # - unittests + # If parameter changes are required only add parameters at the end + # and don't change the arguments (or the defaults!) of the arguments + # existing already. + + # lexer / parser information + self.block_start_string = block_start_string + self.block_end_string = block_end_string + self.variable_start_string = variable_start_string + self.variable_end_string = variable_end_string + self.comment_start_string = comment_start_string + self.comment_end_string = comment_end_string + self.line_statement_prefix = line_statement_prefix + self.line_comment_prefix = line_comment_prefix + self.trim_blocks = trim_blocks + self.lstrip_blocks = lstrip_blocks + self.newline_sequence = newline_sequence + self.keep_trailing_newline = keep_trailing_newline + + # runtime information + self.undefined = undefined + self.optimized = optimized + self.finalize = finalize + self.autoescape = autoescape + + # defaults + self.filters = DEFAULT_FILTERS.copy() + self.tests = DEFAULT_TESTS.copy() + self.globals = DEFAULT_NAMESPACE.copy() + + # set the loader provided + self.loader = loader + self.cache = create_cache(cache_size) + self.bytecode_cache = bytecode_cache + self.auto_reload = auto_reload + + # load extensions + self.extensions = load_extensions(self, extensions) + + _environment_sanity_check(self) + + def add_extension(self, extension): + """Adds an extension after the environment was created. + + .. versionadded:: 2.5 + """ + self.extensions.update(load_extensions(self, [extension])) + + def extend(self, **attributes): + """Add the items to the instance of the environment if they do not exist + yet. This is used by :ref:`extensions ` to register + callbacks and configuration values without breaking inheritance. + """ + for key, value in iteritems(attributes): + if not hasattr(self, key): + setattr(self, key, value) + + def overlay(self, block_start_string=missing, block_end_string=missing, + variable_start_string=missing, variable_end_string=missing, + comment_start_string=missing, comment_end_string=missing, + line_statement_prefix=missing, line_comment_prefix=missing, + trim_blocks=missing, lstrip_blocks=missing, + extensions=missing, optimized=missing, + undefined=missing, finalize=missing, autoescape=missing, + loader=missing, cache_size=missing, auto_reload=missing, + bytecode_cache=missing): + """Create a new overlay environment that shares all the data with the + current environment except of cache and the overridden attributes. + Extensions cannot be removed for an overlayed environment. An overlayed + environment automatically gets all the extensions of the environment it + is linked to plus optional extra extensions. + + Creating overlays should happen after the initial environment was set + up completely. Not all attributes are truly linked, some are just + copied over so modifications on the original environment may not shine + through. + """ + args = dict(locals()) + del args['self'], args['cache_size'], args['extensions'] + + rv = object.__new__(self.__class__) + rv.__dict__.update(self.__dict__) + rv.overlayed = True + rv.linked_to = self + + for key, value in iteritems(args): + if value is not missing: + setattr(rv, key, value) + + if cache_size is not missing: + rv.cache = create_cache(cache_size) + else: + rv.cache = copy_cache(self.cache) + + rv.extensions = {} + for key, value in iteritems(self.extensions): + rv.extensions[key] = value.bind(rv) + if extensions is not missing: + rv.extensions.update(load_extensions(rv, extensions)) + + return _environment_sanity_check(rv) + + lexer = property(get_lexer, doc="The lexer for this environment.") + + def iter_extensions(self): + """Iterates over the extensions by priority.""" + return iter(sorted(self.extensions.values(), + key=lambda x: x.priority)) + + def getitem(self, obj, argument): + """Get an item or attribute of an object but prefer the item.""" + try: + return obj[argument] + except (TypeError, LookupError): + if isinstance(argument, string_types): + try: + attr = str(argument) + except Exception: + pass + else: + try: + return getattr(obj, attr) + except AttributeError: + pass + return self.undefined(obj=obj, name=argument) + + def getattr(self, obj, attribute): + """Get an item or attribute of an object but prefer the attribute. + Unlike :meth:`getitem` the attribute *must* be a bytestring. + """ + try: + return getattr(obj, attribute) + except AttributeError: + pass + try: + return obj[attribute] + except (TypeError, LookupError, AttributeError): + return self.undefined(obj=obj, name=attribute) + + def call_filter(self, name, value, args=None, kwargs=None, + context=None, eval_ctx=None): + """Invokes a filter on a value the same way the compiler does it. + + .. versionadded:: 2.7 + """ + func = self.filters.get(name) + if func is None: + raise TemplateRuntimeError('no filter named %r' % name) + args = [value] + list(args or ()) + if getattr(func, 'contextfilter', False): + if context is None: + raise TemplateRuntimeError('Attempted to invoke context ' + 'filter without context') + args.insert(0, context) + elif getattr(func, 'evalcontextfilter', False): + if eval_ctx is None: + if context is not None: + eval_ctx = context.eval_ctx + else: + eval_ctx = EvalContext(self) + args.insert(0, eval_ctx) + elif getattr(func, 'environmentfilter', False): + args.insert(0, self) + return func(*args, **(kwargs or {})) + + def call_test(self, name, value, args=None, kwargs=None): + """Invokes a test on a value the same way the compiler does it. + + .. versionadded:: 2.7 + """ + func = self.tests.get(name) + if func is None: + raise TemplateRuntimeError('no test named %r' % name) + return func(value, *(args or ()), **(kwargs or {})) + + @internalcode + def parse(self, source, name=None, filename=None): + """Parse the sourcecode and return the abstract syntax tree. This + tree of nodes is used by the compiler to convert the template into + executable source- or bytecode. This is useful for debugging or to + extract information from templates. + + If you are :ref:`developing Jinja2 extensions ` + this gives you a good overview of the node tree generated. + """ + try: + return self._parse(source, name, filename) + except TemplateSyntaxError: + exc_info = sys.exc_info() + self.handle_exception(exc_info, source_hint=source) + + def _parse(self, source, name, filename): + """Internal parsing function used by `parse` and `compile`.""" + return Parser(self, source, name, encode_filename(filename)).parse() + + def lex(self, source, name=None, filename=None): + """Lex the given sourcecode and return a generator that yields + tokens as tuples in the form ``(lineno, token_type, value)``. + This can be useful for :ref:`extension development ` + and debugging templates. + + This does not perform preprocessing. If you want the preprocessing + of the extensions to be applied you have to filter source through + the :meth:`preprocess` method. + """ + source = text_type(source) + try: + return self.lexer.tokeniter(source, name, filename) + except TemplateSyntaxError: + exc_info = sys.exc_info() + self.handle_exception(exc_info, source_hint=source) + + def preprocess(self, source, name=None, filename=None): + """Preprocesses the source with all extensions. This is automatically + called for all parsing and compiling methods but *not* for :meth:`lex` + because there you usually only want the actual source tokenized. + """ + return reduce(lambda s, e: e.preprocess(s, name, filename), + self.iter_extensions(), text_type(source)) + + def _tokenize(self, source, name, filename=None, state=None): + """Called by the parser to do the preprocessing and filtering + for all the extensions. Returns a :class:`~jinja2.lexer.TokenStream`. + """ + source = self.preprocess(source, name, filename) + stream = self.lexer.tokenize(source, name, filename, state) + for ext in self.iter_extensions(): + stream = ext.filter_stream(stream) + if not isinstance(stream, TokenStream): + stream = TokenStream(stream, name, filename) + return stream + + def _generate(self, source, name, filename, defer_init=False): + """Internal hook that can be overridden to hook a different generate + method in. + + .. versionadded:: 2.5 + """ + return generate(source, self, name, filename, defer_init=defer_init) + + def _compile(self, source, filename): + """Internal hook that can be overridden to hook a different compile + method in. + + .. versionadded:: 2.5 + """ + return compile(source, filename, 'exec') + + @internalcode + def compile(self, source, name=None, filename=None, raw=False, + defer_init=False): + """Compile a node or template source code. The `name` parameter is + the load name of the template after it was joined using + :meth:`join_path` if necessary, not the filename on the file system. + the `filename` parameter is the estimated filename of the template on + the file system. If the template came from a database or memory this + can be omitted. + + The return value of this method is a python code object. If the `raw` + parameter is `True` the return value will be a string with python + code equivalent to the bytecode returned otherwise. This method is + mainly used internally. + + `defer_init` is use internally to aid the module code generator. This + causes the generated code to be able to import without the global + environment variable to be set. + + .. versionadded:: 2.4 + `defer_init` parameter added. + """ + source_hint = None + try: + if isinstance(source, string_types): + source_hint = source + source = self._parse(source, name, filename) + if self.optimized: + source = optimize(source, self) + source = self._generate(source, name, filename, + defer_init=defer_init) + if raw: + return source + if filename is None: + filename = '