From 25ba6855169cbbe34bf78449c34c36672d19532e Mon Sep 17 00:00:00 2001 From: Sagi Dayan Date: Sat, 9 May 2015 22:00:14 +0300 Subject: [PATCH] First Commit --- .gitignore | 1 + GithubAPI/GithubAPI.py | 23 + GithubAPI/GithubAPI.pyc | Bin 0 -> 1440 bytes GithubAPI/__init__.py | 1 + GithubAPI/__init__.pyc | Bin 0 -> 172 bytes README.md | 69 + User/User.py | 4 + User/__init__.py | 1 + User/__init__.pyc | Bin 0 -> 167 bytes app.yaml | 38 + appengine_config.py | 6 + appengine_config.pyc | Bin 0 -> 410 bytes lib/Flask-0.10.1-py2.7.egg-info/PKG-INFO | 58 + lib/Flask-0.10.1-py2.7.egg-info/SOURCES.txt | 238 + .../dependency_links.txt | 1 + .../installed-files.txt | 148 + lib/Flask-0.10.1-py2.7.egg-info/not-zip-safe | 1 + lib/Flask-0.10.1-py2.7.egg-info/requires.txt | 3 + lib/Flask-0.10.1-py2.7.egg-info/top_level.txt | 1 + lib/Flask_Cors-2.0.0-py2.7.egg-info/PKG-INFO | 166 + .../SOURCES.txt | 38 + .../dependency_links.txt | 1 + .../installed-files.txt | 17 + .../not-zip-safe | 1 + .../requires.txt | 2 + .../top_level.txt | 1 + .../PKG-INFO | 29 + .../SOURCES.txt | 10 + .../dependency_links.txt | 1 + .../installed-files.txt | 9 + .../not-zip-safe | 1 + .../requires.txt | 2 + .../top_level.txt | 1 + lib/Jinja2-2.7.3-py2.7.egg-info/PKG-INFO | 55 + lib/Jinja2-2.7.3-py2.7.egg-info/SOURCES.txt | 126 + .../dependency_links.txt | 1 + .../entry_points.txt | 4 + .../installed-files.txt | 92 + lib/Jinja2-2.7.3-py2.7.egg-info/not-zip-safe | 1 + lib/Jinja2-2.7.3-py2.7.egg-info/requires.txt | 4 + lib/Jinja2-2.7.3-py2.7.egg-info/top_level.txt | 1 + lib/MarkupSafe-0.23-py2.7.egg-info/PKG-INFO | 119 + .../SOURCES.txt | 17 + .../dependency_links.txt | 1 + .../installed-files.txt | 18 + .../not-zip-safe | 1 + .../top_level.txt | 1 + lib/Werkzeug-0.10.4.dist-info/DESCRIPTION.rst | 54 + lib/Werkzeug-0.10.4.dist-info/METADATA | 73 + lib/Werkzeug-0.10.4.dist-info/RECORD | 91 + lib/Werkzeug-0.10.4.dist-info/WHEEL | 6 + lib/Werkzeug-0.10.4.dist-info/metadata.json | 1 + lib/Werkzeug-0.10.4.dist-info/top_level.txt | 1 + lib/easy_install.py | 5 + lib/flask/__init__.py | 50 + lib/flask/__init__.pyc | Bin 0 -> 2161 bytes lib/flask/_compat.py | 73 + lib/flask/_compat.pyc | Bin 0 -> 3279 bytes lib/flask/app.py | 1842 ++++++ lib/flask/app.pyc | Bin 0 -> 63176 bytes lib/flask/blueprints.py | 401 ++ lib/flask/blueprints.pyc | Bin 0 -> 21196 bytes lib/flask/config.py | 168 + lib/flask/config.pyc | Bin 0 -> 7266 bytes lib/flask/ctx.py | 394 ++ lib/flask/ctx.pyc | Bin 0 -> 13832 bytes lib/flask/debughelpers.py | 87 + lib/flask/debughelpers.pyc | Bin 0 -> 4560 bytes lib/flask/ext/__init__.py | 29 + lib/flask/ext/__init__.pyc | Bin 0 -> 1121 bytes lib/flask/exthook.py | 120 + lib/flask/exthook.pyc | Bin 0 -> 4404 bytes lib/flask/globals.py | 44 + lib/flask/globals.pyc | Bin 0 -> 1569 bytes lib/flask/helpers.py | 849 +++ lib/flask/helpers.pyc | Bin 0 -> 30673 bytes lib/flask/json.py | 243 + lib/flask/json.pyc | Bin 0 -> 9501 bytes lib/flask/logging.py | 45 + lib/flask/logging.pyc | Bin 0 -> 2168 bytes lib/flask/module.py | 42 + lib/flask/module.pyc | Bin 0 -> 1866 bytes lib/flask/sessions.py | 332 ++ lib/flask/sessions.pyc | Bin 0 -> 13475 bytes lib/flask/signals.py | 55 + lib/flask/signals.pyc | Bin 0 -> 2745 bytes lib/flask/templating.py | 143 + lib/flask/templating.pyc | Bin 0 -> 5406 bytes lib/flask/testing.py | 124 + lib/flask/testing.pyc | Bin 0 -> 4647 bytes lib/flask/testsuite/__init__.py | 246 + lib/flask/testsuite/__init__.pyc | Bin 0 -> 10808 bytes lib/flask/testsuite/appctx.py | 101 + lib/flask/testsuite/appctx.pyc | Bin 0 -> 5247 bytes lib/flask/testsuite/basic.py | 1254 ++++ lib/flask/testsuite/basic.pyc | Bin 0 -> 57068 bytes lib/flask/testsuite/blueprints.py | 790 +++ lib/flask/testsuite/blueprints.pyc | Bin 0 -> 37879 bytes lib/flask/testsuite/config.py | 299 + lib/flask/testsuite/config.pyc | Bin 0 -> 12798 bytes lib/flask/testsuite/deprecations.py | 24 + lib/flask/testsuite/deprecations.pyc | Bin 0 -> 1005 bytes lib/flask/testsuite/examples.py | 38 + lib/flask/testsuite/examples.pyc | Bin 0 -> 1325 bytes lib/flask/testsuite/ext.py | 134 + lib/flask/testsuite/ext.pyc | Bin 0 -> 6871 bytes lib/flask/testsuite/helpers.py | 593 ++ lib/flask/testsuite/helpers.pyc | Bin 0 -> 27039 bytes lib/flask/testsuite/regression.py | 116 + lib/flask/testsuite/regression.pyc | Bin 0 -> 5507 bytes lib/flask/testsuite/reqctx.py | 185 + lib/flask/testsuite/reqctx.pyc | Bin 0 -> 7318 bytes lib/flask/testsuite/signals.py | 153 + lib/flask/testsuite/signals.pyc | Bin 0 -> 6795 bytes lib/flask/testsuite/static/index.html | 1 + lib/flask/testsuite/subclassing.py | 46 + lib/flask/testsuite/subclassing.pyc | Bin 0 -> 2292 bytes lib/flask/testsuite/templates/_macro.html | 1 + .../testsuite/templates/context_template.html | 1 + .../templates/escaping_template.html | 6 + lib/flask/testsuite/templates/mail.txt | 1 + .../testsuite/templates/nested/nested.txt | 1 + .../testsuite/templates/simple_template.html | 1 + .../testsuite/templates/template_filter.html | 1 + .../testsuite/templates/template_test.html | 3 + lib/flask/testsuite/templating.py | 302 + lib/flask/testsuite/templating.pyc | Bin 0 -> 17635 bytes .../test_apps/blueprintapp/__init__.py | 7 + .../test_apps/blueprintapp/__init__.pyc | Bin 0 -> 440 bytes .../test_apps/blueprintapp/apps/__init__.py | 0 .../test_apps/blueprintapp/apps/__init__.pyc | Bin 0 -> 168 bytes .../blueprintapp/apps/admin/__init__.py | 15 + .../blueprintapp/apps/admin/__init__.pyc | Bin 0 -> 903 bytes .../apps/admin/static/css/test.css | 1 + .../blueprintapp/apps/admin/static/test.txt | 1 + .../apps/admin/templates/admin/index.html | 1 + .../blueprintapp/apps/frontend/__init__.py | 8 + .../blueprintapp/apps/frontend/__init__.pyc | Bin 0 -> 601 bytes .../frontend/templates/frontend/index.html | 1 + .../testsuite/test_apps/config_module_app.py | 4 + .../testsuite/test_apps/config_module_app.pyc | Bin 0 -> 342 bytes .../test_apps/config_package_app/__init__.py | 4 + .../test_apps/config_package_app/__init__.pyc | Bin 0 -> 352 bytes .../test_apps/flask_broken/__init__.py | 2 + .../test_apps/flask_broken/__init__.pyc | Bin 0 -> 246 bytes .../testsuite/test_apps/flask_broken/b.py | 0 .../testsuite/test_apps/flask_broken/b.pyc | Bin 0 -> 156 bytes .../flask_newext_package/__init__.py | 1 + .../flask_newext_package/__init__.pyc | Bin 0 -> 207 bytes .../flask_newext_package/submodule.py | 2 + .../flask_newext_package/submodule.pyc | Bin 0 -> 362 bytes .../test_apps/flask_newext_simple.py | 1 + .../test_apps/flask_newext_simple.pyc | Bin 0 -> 196 bytes .../testsuite/test_apps/flaskext/__init__.py | 0 .../testsuite/test_apps/flaskext/__init__.pyc | Bin 0 -> 159 bytes .../flaskext/oldext_package/__init__.py | 1 + .../flaskext/oldext_package/__init__.pyc | Bin 0 -> 210 bytes .../flaskext/oldext_package/submodule.py | 2 + .../flaskext/oldext_package/submodule.pyc | Bin 0 -> 368 bytes .../test_apps/flaskext/oldext_simple.py | 1 + .../test_apps/flaskext/oldext_simple.pyc | Bin 0 -> 199 bytes lib/flask/testsuite/test_apps/importerror.py | 2 + lib/flask/testsuite/test_apps/importerror.pyc | Bin 0 -> 183 bytes .../lib/python2.5/site-packages/SiteEgg.egg | Bin 0 -> 1218 bytes .../lib/python2.5/site-packages/site_app.py | 3 + .../lib/python2.5/site-packages/site_app.pyc | Bin 0 -> 253 bytes .../site-packages/site_package/__init__.py | 3 + .../site-packages/site_package/__init__.pyc | Bin 0 -> 266 bytes lib/flask/testsuite/test_apps/main_app.py | 4 + lib/flask/testsuite/test_apps/main_app.pyc | Bin 0 -> 225 bytes .../testsuite/test_apps/moduleapp/__init__.py | 7 + .../test_apps/moduleapp/__init__.pyc | Bin 0 -> 428 bytes .../test_apps/moduleapp/apps/__init__.py | 0 .../test_apps/moduleapp/apps/__init__.pyc | Bin 0 -> 165 bytes .../moduleapp/apps/admin/__init__.py | 14 + .../moduleapp/apps/admin/__init__.pyc | Bin 0 -> 804 bytes .../moduleapp/apps/admin/static/css/test.css | 1 + .../moduleapp/apps/admin/static/test.txt | 1 + .../moduleapp/apps/admin/templates/index.html | 1 + .../moduleapp/apps/frontend/__init__.py | 9 + .../moduleapp/apps/frontend/__init__.pyc | Bin 0 -> 544 bytes .../apps/frontend/templates/index.html | 1 + .../path/installed_package/__init__.py | 3 + .../path/installed_package/__init__.pyc | Bin 0 -> 248 bytes .../test_apps/subdomaintestmodule/__init__.py | 4 + .../subdomaintestmodule/__init__.pyc | Bin 0 -> 288 bytes .../subdomaintestmodule/static/hello.txt | 1 + lib/flask/testsuite/testing.py | 242 + lib/flask/testsuite/testing.pyc | Bin 0 -> 9799 bytes lib/flask/testsuite/views.py | 169 + lib/flask/testsuite/views.pyc | Bin 0 -> 9415 bytes lib/flask/views.py | 149 + lib/flask/views.pyc | Bin 0 -> 5303 bytes lib/flask/wrappers.py | 184 + lib/flask/wrappers.pyc | Bin 0 -> 6680 bytes lib/flask_cors/__init__.py | 15 + lib/flask_cors/__init__.pyc | Bin 0 -> 631 bytes lib/flask_cors/core.py | 374 ++ lib/flask_cors/core.pyc | Bin 0 -> 12966 bytes lib/flask_cors/decorator.py | 127 + lib/flask_cors/decorator.pyc | Bin 0 -> 4851 bytes lib/flask_cors/extension.py | 116 + lib/flask_cors/extension.pyc | Bin 0 -> 4753 bytes lib/flask_cors/version.py | 1 + lib/flask_cors/version.pyc | Bin 0 -> 178 bytes lib/flask_github.py | 206 + lib/flask_github.pyc | Bin 0 -> 8549 bytes lib/itsdangerous-0.24-py2.7.egg-info/PKG-INFO | 13 + .../SOURCES.txt | 27 + .../dependency_links.txt | 1 + .../installed-files.txt | 8 + .../not-zip-safe | 1 + .../top_level.txt | 1 + lib/itsdangerous.py | 872 +++ lib/itsdangerous.pyc | Bin 0 -> 33576 bytes lib/jinja2/__init__.py | 69 + lib/jinja2/__init__.pyc | Bin 0 -> 2425 bytes lib/jinja2/_compat.py | 150 + lib/jinja2/_compat.pyc | Bin 0 -> 5981 bytes lib/jinja2/_stringdefs.py | 132 + lib/jinja2/_stringdefs.pyc | Bin 0 -> 208503 bytes lib/jinja2/bccache.py | 344 ++ lib/jinja2/bccache.pyc | Bin 0 -> 13934 bytes lib/jinja2/compiler.py | 1640 ++++++ lib/jinja2/compiler.pyc | Bin 0 -> 53637 bytes lib/jinja2/constants.py | 32 + lib/jinja2/constants.pyc | Bin 0 -> 1687 bytes lib/jinja2/debug.py | 337 ++ lib/jinja2/debug.pyc | Bin 0 -> 10514 bytes lib/jinja2/defaults.py | 43 + lib/jinja2/defaults.pyc | Bin 0 -> 1610 bytes lib/jinja2/environment.py | 1191 ++++ lib/jinja2/environment.pyc | Bin 0 -> 45572 bytes lib/jinja2/exceptions.py | 146 + lib/jinja2/exceptions.pyc | Bin 0 -> 6121 bytes lib/jinja2/ext.py | 636 +++ lib/jinja2/ext.pyc | Bin 0 -> 23757 bytes lib/jinja2/filters.py | 987 ++++ lib/jinja2/filters.pyc | Bin 0 -> 33475 bytes lib/jinja2/lexer.py | 733 +++ lib/jinja2/lexer.pyc | Bin 0 -> 22343 bytes lib/jinja2/loaders.py | 471 ++ lib/jinja2/loaders.pyc | Bin 0 -> 18639 bytes lib/jinja2/meta.py | 103 + lib/jinja2/meta.pyc | Bin 0 -> 3961 bytes lib/jinja2/nodes.py | 914 +++ lib/jinja2/nodes.pyc | Bin 0 -> 41704 bytes lib/jinja2/optimizer.py | 68 + lib/jinja2/optimizer.pyc | Bin 0 -> 2809 bytes lib/jinja2/parser.py | 895 +++ lib/jinja2/parser.pyc | Bin 0 -> 30834 bytes lib/jinja2/runtime.py | 581 ++ lib/jinja2/runtime.pyc | Bin 0 -> 22559 bytes lib/jinja2/sandbox.py | 368 ++ lib/jinja2/sandbox.pyc | Bin 0 -> 11856 bytes lib/jinja2/tests.py | 149 + lib/jinja2/tests.pyc | Bin 0 -> 4937 bytes lib/jinja2/testsuite/__init__.py | 156 + lib/jinja2/testsuite/__init__.pyc | Bin 0 -> 6365 bytes lib/jinja2/testsuite/api.py | 261 + lib/jinja2/testsuite/api.pyc | Bin 0 -> 13056 bytes lib/jinja2/testsuite/bytecode_cache.py | 37 + lib/jinja2/testsuite/bytecode_cache.pyc | Bin 0 -> 1612 bytes lib/jinja2/testsuite/core_tags.py | 305 + lib/jinja2/testsuite/core_tags.pyc | Bin 0 -> 17576 bytes lib/jinja2/testsuite/debug.py | 58 + lib/jinja2/testsuite/debug.pyc | Bin 0 -> 3052 bytes lib/jinja2/testsuite/doctests.py | 29 + lib/jinja2/testsuite/doctests.pyc | Bin 0 -> 1174 bytes lib/jinja2/testsuite/ext.py | 459 ++ lib/jinja2/testsuite/ext.pyc | Bin 0 -> 22735 bytes lib/jinja2/testsuite/filters.py | 515 ++ lib/jinja2/testsuite/filters.pyc | Bin 0 -> 28629 bytes lib/jinja2/testsuite/imports.py | 141 + lib/jinja2/testsuite/imports.pyc | Bin 0 -> 6733 bytes lib/jinja2/testsuite/inheritance.py | 250 + lib/jinja2/testsuite/inheritance.pyc | Bin 0 -> 10439 bytes lib/jinja2/testsuite/lexnparse.py | 593 ++ lib/jinja2/testsuite/lexnparse.pyc | Bin 0 -> 33134 bytes lib/jinja2/testsuite/loader.py | 226 + lib/jinja2/testsuite/loader.pyc | Bin 0 -> 10443 bytes lib/jinja2/testsuite/regression.py | 279 + lib/jinja2/testsuite/regression.pyc | Bin 0 -> 11572 bytes lib/jinja2/testsuite/res/__init__.py | 0 lib/jinja2/testsuite/res/__init__.pyc | Bin 0 -> 145 bytes .../testsuite/res/templates/broken.html | 3 + .../testsuite/res/templates/foo/test.html | 1 + .../testsuite/res/templates/syntaxerror.html | 4 + lib/jinja2/testsuite/res/templates/test.html | 1 + lib/jinja2/testsuite/security.py | 166 + lib/jinja2/testsuite/security.pyc | Bin 0 -> 8391 bytes lib/jinja2/testsuite/tests.py | 93 + lib/jinja2/testsuite/tests.pyc | Bin 0 -> 4716 bytes lib/jinja2/testsuite/utils.py | 82 + lib/jinja2/testsuite/utils.pyc | Bin 0 -> 3507 bytes lib/jinja2/utils.py | 520 ++ lib/jinja2/utils.pyc | Bin 0 -> 19204 bytes lib/jinja2/visitor.py | 87 + lib/jinja2/visitor.pyc | Bin 0 -> 3756 bytes lib/markupsafe/__init__.py | 298 + lib/markupsafe/__init__.pyc | Bin 0 -> 13832 bytes lib/markupsafe/_compat.py | 26 + lib/markupsafe/_compat.pyc | Bin 0 -> 965 bytes lib/markupsafe/_constants.py | 267 + lib/markupsafe/_constants.pyc | Bin 0 -> 6360 bytes lib/markupsafe/_native.py | 46 + lib/markupsafe/_native.pyc | Bin 0 -> 1693 bytes lib/markupsafe/_speedups.c | 239 + lib/markupsafe/_speedups.so | Bin 0 -> 13280 bytes lib/markupsafe/tests.py | 179 + lib/markupsafe/tests.pyc | Bin 0 -> 9281 bytes lib/pkg_resources.py | 2843 ++++++++++ lib/requests/__init__.py | 77 + lib/requests/__init__.pyc | Bin 0 -> 2525 bytes lib/requests/adapters.py | 388 ++ lib/requests/adapters.pyc | Bin 0 -> 13856 bytes lib/requests/api.py | 120 + lib/requests/api.pyc | Bin 0 -> 5317 bytes lib/requests/auth.py | 193 + lib/requests/auth.pyc | Bin 0 -> 7221 bytes lib/requests/cacert.pem | 5026 +++++++++++++++++ lib/requests/certs.py | 24 + lib/requests/certs.pyc | Bin 0 -> 797 bytes lib/requests/compat.py | 115 + lib/requests/compat.pyc | Bin 0 -> 2582 bytes lib/requests/cookies.py | 454 ++ lib/requests/cookies.pyc | Bin 0 -> 20422 bytes lib/requests/exceptions.py | 75 + lib/requests/exceptions.pyc | Bin 0 -> 4101 bytes lib/requests/hooks.py | 45 + lib/requests/hooks.pyc | Bin 0 -> 1070 bytes lib/requests/models.py | 803 +++ lib/requests/models.pyc | Bin 0 -> 24084 bytes lib/requests/packages/__init__.py | 3 + lib/requests/packages/__init__.pyc | Bin 0 -> 270 bytes lib/requests/packages/chardet/__init__.py | 32 + lib/requests/packages/chardet/__init__.pyc | Bin 0 -> 843 bytes lib/requests/packages/chardet/big5freq.py | 925 +++ lib/requests/packages/chardet/big5freq.pyc | Bin 0 -> 113803 bytes lib/requests/packages/chardet/big5prober.py | 42 + lib/requests/packages/chardet/big5prober.pyc | Bin 0 -> 1184 bytes lib/requests/packages/chardet/chardetect.py | 46 + .../packages/chardet/chardistribution.py | 231 + .../packages/chardet/chardistribution.pyc | Bin 0 -> 8123 bytes .../packages/chardet/charsetgroupprober.py | 106 + .../packages/chardet/charsetgroupprober.pyc | Bin 0 -> 2701 bytes .../packages/chardet/charsetprober.py | 62 + .../packages/chardet/charsetprober.pyc | Bin 0 -> 2380 bytes .../packages/chardet/codingstatemachine.py | 61 + .../packages/chardet/codingstatemachine.pyc | Bin 0 -> 1946 bytes lib/requests/packages/chardet/compat.py | 34 + lib/requests/packages/chardet/compat.pyc | Bin 0 -> 605 bytes lib/requests/packages/chardet/constants.py | 39 + lib/requests/packages/chardet/constants.pyc | Bin 0 -> 355 bytes lib/requests/packages/chardet/cp949prober.py | 44 + lib/requests/packages/chardet/cp949prober.pyc | Bin 0 -> 1192 bytes lib/requests/packages/chardet/escprober.py | 86 + lib/requests/packages/chardet/escprober.pyc | Bin 0 -> 2530 bytes lib/requests/packages/chardet/escsm.py | 242 + lib/requests/packages/chardet/escsm.pyc | Bin 0 -> 7327 bytes lib/requests/packages/chardet/eucjpprober.py | 90 + lib/requests/packages/chardet/eucjpprober.pyc | Bin 0 -> 2939 bytes lib/requests/packages/chardet/euckrfreq.py | 596 ++ lib/requests/packages/chardet/euckrfreq.pyc | Bin 0 -> 88794 bytes lib/requests/packages/chardet/euckrprober.py | 42 + lib/requests/packages/chardet/euckrprober.pyc | Bin 0 -> 1193 bytes lib/requests/packages/chardet/euctwfreq.py | 428 ++ lib/requests/packages/chardet/euctwfreq.pyc | Bin 0 -> 61192 bytes lib/requests/packages/chardet/euctwprober.py | 41 + lib/requests/packages/chardet/euctwprober.pyc | Bin 0 -> 1193 bytes lib/requests/packages/chardet/gb2312freq.py | 472 ++ lib/requests/packages/chardet/gb2312freq.pyc | Bin 0 -> 68810 bytes lib/requests/packages/chardet/gb2312prober.py | 41 + .../packages/chardet/gb2312prober.pyc | Bin 0 -> 1200 bytes lib/requests/packages/chardet/hebrewprober.py | 283 + .../packages/chardet/hebrewprober.pyc | Bin 0 -> 3634 bytes lib/requests/packages/chardet/jisfreq.py | 569 ++ lib/requests/packages/chardet/jisfreq.pyc | Bin 0 -> 84026 bytes lib/requests/packages/chardet/jpcntx.py | 219 + lib/requests/packages/chardet/jpcntx.pyc | Bin 0 -> 24898 bytes .../packages/chardet/langbulgarianmodel.py | 229 + .../packages/chardet/langbulgarianmodel.pyc | Bin 0 -> 24908 bytes .../packages/chardet/langcyrillicmodel.py | 329 ++ .../packages/chardet/langcyrillicmodel.pyc | Bin 0 -> 30590 bytes .../packages/chardet/langgreekmodel.py | 225 + .../packages/chardet/langgreekmodel.pyc | Bin 0 -> 24595 bytes .../packages/chardet/langhebrewmodel.py | 201 + .../packages/chardet/langhebrewmodel.pyc | Bin 0 -> 23415 bytes .../packages/chardet/langhungarianmodel.py | 225 + .../packages/chardet/langhungarianmodel.pyc | Bin 0 -> 24892 bytes .../packages/chardet/langthaimodel.py | 200 + .../packages/chardet/langthaimodel.pyc | Bin 0 -> 23401 bytes lib/requests/packages/chardet/latin1prober.py | 139 + .../packages/chardet/latin1prober.pyc | Bin 0 -> 3615 bytes .../packages/chardet/mbcharsetprober.py | 86 + .../packages/chardet/mbcharsetprober.pyc | Bin 0 -> 2573 bytes .../packages/chardet/mbcsgroupprober.py | 54 + .../packages/chardet/mbcsgroupprober.pyc | Bin 0 -> 1315 bytes lib/requests/packages/chardet/mbcssm.py | 575 ++ lib/requests/packages/chardet/mbcssm.pyc | Bin 0 -> 17684 bytes .../packages/chardet/sbcharsetprober.py | 120 + .../packages/chardet/sbcharsetprober.pyc | Bin 0 -> 3458 bytes .../packages/chardet/sbcsgroupprober.py | 69 + .../packages/chardet/sbcsgroupprober.pyc | Bin 0 -> 2000 bytes lib/requests/packages/chardet/sjisprober.py | 91 + lib/requests/packages/chardet/sjisprober.pyc | Bin 0 -> 2961 bytes .../packages/chardet/universaldetector.py | 170 + .../packages/chardet/universaldetector.pyc | Bin 0 -> 4259 bytes lib/requests/packages/chardet/utf8prober.py | 76 + lib/requests/packages/chardet/utf8prober.pyc | Bin 0 -> 2356 bytes lib/requests/packages/urllib3/__init__.py | 58 + lib/requests/packages/urllib3/__init__.pyc | Bin 0 -> 2164 bytes lib/requests/packages/urllib3/_collections.py | 205 + .../packages/urllib3/_collections.pyc | Bin 0 -> 9871 bytes lib/requests/packages/urllib3/connection.py | 204 + lib/requests/packages/urllib3/connection.pyc | Bin 0 -> 6298 bytes .../packages/urllib3/connectionpool.py | 710 +++ .../packages/urllib3/connectionpool.pyc | Bin 0 -> 20898 bytes .../packages/urllib3/contrib/__init__.py | 0 .../packages/urllib3/contrib/__init__.pyc | Bin 0 -> 170 bytes .../packages/urllib3/contrib/ntlmpool.py | 120 + .../packages/urllib3/contrib/pyopenssl.py | 422 ++ .../packages/urllib3/contrib/pyopenssl.pyc | Bin 0 -> 11968 bytes lib/requests/packages/urllib3/exceptions.py | 126 + lib/requests/packages/urllib3/exceptions.pyc | Bin 0 -> 6812 bytes lib/requests/packages/urllib3/fields.py | 177 + lib/requests/packages/urllib3/fields.pyc | Bin 0 -> 6796 bytes lib/requests/packages/urllib3/filepost.py | 100 + lib/requests/packages/urllib3/filepost.pyc | Bin 0 -> 3368 bytes .../packages/urllib3/packages/__init__.py | 4 + .../packages/urllib3/packages/__init__.pyc | Bin 0 -> 298 bytes .../packages/urllib3/packages/ordered_dict.py | 260 + .../urllib3/packages/ordered_dict.pyc | Bin 0 -> 10570 bytes lib/requests/packages/urllib3/packages/six.py | 385 ++ .../packages/urllib3/packages/six.pyc | Bin 0 -> 14414 bytes .../packages/ssl_match_hostname/__init__.py | 13 + .../packages/ssl_match_hostname/__init__.pyc | Bin 0 -> 533 bytes .../ssl_match_hostname/_implementation.py | 105 + lib/requests/packages/urllib3/poolmanager.py | 258 + lib/requests/packages/urllib3/poolmanager.pyc | Bin 0 -> 9440 bytes lib/requests/packages/urllib3/request.py | 141 + lib/requests/packages/urllib3/request.pyc | Bin 0 -> 5923 bytes lib/requests/packages/urllib3/response.py | 308 + lib/requests/packages/urllib3/response.pyc | Bin 0 -> 10869 bytes .../packages/urllib3/util/__init__.py | 27 + .../packages/urllib3/util/__init__.pyc | Bin 0 -> 762 bytes .../packages/urllib3/util/connection.py | 45 + .../packages/urllib3/util/connection.pyc | Bin 0 -> 1286 bytes lib/requests/packages/urllib3/util/request.py | 68 + .../packages/urllib3/util/request.pyc | Bin 0 -> 2036 bytes .../packages/urllib3/util/response.py | 13 + .../packages/urllib3/util/response.pyc | Bin 0 -> 554 bytes lib/requests/packages/urllib3/util/ssl_.py | 133 + lib/requests/packages/urllib3/util/ssl_.pyc | Bin 0 -> 4024 bytes lib/requests/packages/urllib3/util/timeout.py | 234 + .../packages/urllib3/util/timeout.pyc | Bin 0 -> 9576 bytes lib/requests/packages/urllib3/util/url.py | 162 + lib/requests/packages/urllib3/util/url.pyc | Bin 0 -> 4668 bytes lib/requests/sessions.py | 637 +++ lib/requests/sessions.pyc | Bin 0 -> 18617 bytes lib/requests/status_codes.py | 88 + lib/requests/status_codes.pyc | Bin 0 -> 4613 bytes lib/requests/structures.py | 127 + lib/requests/structures.pyc | Bin 0 -> 6447 bytes lib/requests/utils.py | 673 +++ lib/requests/utils.pyc | Bin 0 -> 19615 bytes lib/six.py | 838 +++ lib/six.pyc | Bin 0 -> 30098 bytes lib/werkzeug/__init__.py | 154 + lib/werkzeug/__init__.pyc | Bin 0 -> 5821 bytes lib/werkzeug/_compat.py | 202 + lib/werkzeug/_compat.pyc | Bin 0 -> 10737 bytes lib/werkzeug/_internal.py | 412 ++ lib/werkzeug/_internal.pyc | Bin 0 -> 15094 bytes lib/werkzeug/_reloader.py | 233 + lib/werkzeug/_reloader.pyc | Bin 0 -> 9431 bytes lib/werkzeug/contrib/__init__.py | 16 + lib/werkzeug/contrib/__init__.pyc | Bin 0 -> 767 bytes lib/werkzeug/contrib/atom.py | 353 ++ lib/werkzeug/contrib/atom.pyc | Bin 0 -> 16274 bytes lib/werkzeug/contrib/cache.py | 714 +++ lib/werkzeug/contrib/cache.pyc | Bin 0 -> 29892 bytes lib/werkzeug/contrib/fixers.py | 248 + lib/werkzeug/contrib/fixers.pyc | Bin 0 -> 11573 bytes lib/werkzeug/contrib/iterio.py | 349 ++ lib/werkzeug/contrib/iterio.pyc | Bin 0 -> 13818 bytes lib/werkzeug/contrib/jsrouting.py | 264 + lib/werkzeug/contrib/jsrouting.pyc | Bin 0 -> 9131 bytes lib/werkzeug/contrib/limiter.py | 40 + lib/werkzeug/contrib/limiter.pyc | Bin 0 -> 1973 bytes lib/werkzeug/contrib/lint.py | 334 ++ lib/werkzeug/contrib/lint.pyc | Bin 0 -> 14600 bytes lib/werkzeug/contrib/profiler.py | 142 + lib/werkzeug/contrib/profiler.pyc | Bin 0 -> 6283 bytes lib/werkzeug/contrib/securecookie.py | 321 ++ lib/werkzeug/contrib/securecookie.pyc | Bin 0 -> 11735 bytes lib/werkzeug/contrib/sessions.py | 348 ++ lib/werkzeug/contrib/sessions.pyc | Bin 0 -> 15528 bytes lib/werkzeug/contrib/testtools.py | 71 + lib/werkzeug/contrib/testtools.pyc | Bin 0 -> 3201 bytes lib/werkzeug/contrib/wrappers.py | 278 + lib/werkzeug/contrib/wrappers.pyc | Bin 0 -> 11780 bytes lib/werkzeug/datastructures.py | 2634 +++++++++ lib/werkzeug/datastructures.pyc | Bin 0 -> 117336 bytes lib/werkzeug/debug/__init__.py | 185 + lib/werkzeug/debug/__init__.pyc | Bin 0 -> 7725 bytes lib/werkzeug/debug/console.py | 211 + lib/werkzeug/debug/console.pyc | Bin 0 -> 9691 bytes lib/werkzeug/debug/repr.py | 280 + lib/werkzeug/debug/repr.pyc | Bin 0 -> 10610 bytes lib/werkzeug/debug/shared/FONT_LICENSE | 96 + lib/werkzeug/debug/shared/console.png | Bin 0 -> 507 bytes lib/werkzeug/debug/shared/debugger.js | 201 + lib/werkzeug/debug/shared/jquery.js | 167 + lib/werkzeug/debug/shared/less.png | Bin 0 -> 191 bytes lib/werkzeug/debug/shared/more.png | Bin 0 -> 200 bytes lib/werkzeug/debug/shared/source.png | Bin 0 -> 818 bytes lib/werkzeug/debug/shared/style.css | 113 + lib/werkzeug/debug/shared/ubuntu.ttf | Bin 0 -> 70220 bytes lib/werkzeug/debug/tbtools.py | 510 ++ lib/werkzeug/debug/tbtools.pyc | Bin 0 -> 17631 bytes lib/werkzeug/exceptions.py | 617 ++ lib/werkzeug/exceptions.pyc | Bin 0 -> 24182 bytes lib/werkzeug/formparser.py | 523 ++ lib/werkzeug/formparser.pyc | Bin 0 -> 18804 bytes lib/werkzeug/http.py | 995 ++++ lib/werkzeug/http.pyc | Bin 0 -> 34490 bytes lib/werkzeug/local.py | 409 ++ lib/werkzeug/local.pyc | Bin 0 -> 24193 bytes lib/werkzeug/posixemulation.py | 104 + lib/werkzeug/posixemulation.pyc | Bin 0 -> 3450 bytes lib/werkzeug/routing.py | 1693 ++++++ lib/werkzeug/routing.pyc | Bin 0 -> 65809 bytes lib/werkzeug/script.py | 317 ++ lib/werkzeug/script.pyc | Bin 0 -> 11736 bytes lib/werkzeug/security.py | 263 + lib/werkzeug/security.pyc | Bin 0 -> 10137 bytes lib/werkzeug/serving.py | 673 +++ lib/werkzeug/serving.pyc | Bin 0 -> 26771 bytes lib/werkzeug/test.py | 892 +++ lib/werkzeug/test.pyc | Bin 0 -> 34619 bytes lib/werkzeug/testapp.py | 230 + lib/werkzeug/testapp.pyc | Bin 0 -> 10390 bytes lib/werkzeug/urls.py | 995 ++++ lib/werkzeug/urls.pyc | Bin 0 -> 37880 bytes lib/werkzeug/useragents.py | 193 + lib/werkzeug/useragents.pyc | Bin 0 -> 6587 bytes lib/werkzeug/utils.py | 624 ++ lib/werkzeug/utils.pyc | Bin 0 -> 24118 bytes lib/werkzeug/wrappers.py | 1823 ++++++ lib/werkzeug/wrappers.pyc | Bin 0 -> 78904 bytes lib/werkzeug/wsgi.py | 1049 ++++ lib/werkzeug/wsgi.pyc | Bin 0 -> 39731 bytes main.py | 122 + main.pyc | Bin 0 -> 5209 bytes models/__init__.py | 0 models/__init__.pyc | Bin 0 -> 139 bytes templates/css/theme.css | 75 + templates/images/wellcome.jpg | Bin 0 -> 105689 bytes templates/index.html | 46 + templates/js/app.js | 39 + templates/js/controllers/mainController.js | 20 + .../js/controllers/registerController.js | 14 + templates/js/services/apiService.js | 21 + templates/views/home.html | 5 + templates/views/index.html | 54 + templates/views/register.html | 31 + 567 files changed, 73834 insertions(+) create mode 100644 .gitignore create mode 100644 GithubAPI/GithubAPI.py create mode 100644 GithubAPI/GithubAPI.pyc create mode 100644 GithubAPI/__init__.py create mode 100644 GithubAPI/__init__.pyc create mode 100644 README.md create mode 100644 User/User.py create mode 100644 User/__init__.py create mode 100644 User/__init__.pyc create mode 100644 app.yaml create mode 100644 appengine_config.py create mode 100644 appengine_config.pyc create mode 100644 lib/Flask-0.10.1-py2.7.egg-info/PKG-INFO create mode 100644 lib/Flask-0.10.1-py2.7.egg-info/SOURCES.txt create mode 100644 lib/Flask-0.10.1-py2.7.egg-info/dependency_links.txt create mode 100644 lib/Flask-0.10.1-py2.7.egg-info/installed-files.txt create mode 100644 lib/Flask-0.10.1-py2.7.egg-info/not-zip-safe create mode 100644 lib/Flask-0.10.1-py2.7.egg-info/requires.txt create mode 100644 lib/Flask-0.10.1-py2.7.egg-info/top_level.txt create mode 100644 lib/Flask_Cors-2.0.0-py2.7.egg-info/PKG-INFO create mode 100644 lib/Flask_Cors-2.0.0-py2.7.egg-info/SOURCES.txt create mode 100644 lib/Flask_Cors-2.0.0-py2.7.egg-info/dependency_links.txt create mode 100644 lib/Flask_Cors-2.0.0-py2.7.egg-info/installed-files.txt create mode 100644 lib/Flask_Cors-2.0.0-py2.7.egg-info/not-zip-safe create mode 100644 lib/Flask_Cors-2.0.0-py2.7.egg-info/requires.txt create mode 100644 lib/Flask_Cors-2.0.0-py2.7.egg-info/top_level.txt create mode 100755 lib/GitHub_Flask-2.0.1-py2.7.egg-info/PKG-INFO create mode 100755 lib/GitHub_Flask-2.0.1-py2.7.egg-info/SOURCES.txt create mode 100755 lib/GitHub_Flask-2.0.1-py2.7.egg-info/dependency_links.txt create mode 100644 lib/GitHub_Flask-2.0.1-py2.7.egg-info/installed-files.txt create mode 100755 lib/GitHub_Flask-2.0.1-py2.7.egg-info/not-zip-safe create mode 100755 lib/GitHub_Flask-2.0.1-py2.7.egg-info/requires.txt create mode 100755 lib/GitHub_Flask-2.0.1-py2.7.egg-info/top_level.txt create mode 100644 lib/Jinja2-2.7.3-py2.7.egg-info/PKG-INFO create mode 100644 lib/Jinja2-2.7.3-py2.7.egg-info/SOURCES.txt create mode 100644 lib/Jinja2-2.7.3-py2.7.egg-info/dependency_links.txt create mode 100644 lib/Jinja2-2.7.3-py2.7.egg-info/entry_points.txt create mode 100644 lib/Jinja2-2.7.3-py2.7.egg-info/installed-files.txt create mode 100644 lib/Jinja2-2.7.3-py2.7.egg-info/not-zip-safe create mode 100644 lib/Jinja2-2.7.3-py2.7.egg-info/requires.txt create mode 100644 lib/Jinja2-2.7.3-py2.7.egg-info/top_level.txt create mode 100644 lib/MarkupSafe-0.23-py2.7.egg-info/PKG-INFO create mode 100644 lib/MarkupSafe-0.23-py2.7.egg-info/SOURCES.txt create mode 100644 lib/MarkupSafe-0.23-py2.7.egg-info/dependency_links.txt create mode 100644 lib/MarkupSafe-0.23-py2.7.egg-info/installed-files.txt create mode 100644 lib/MarkupSafe-0.23-py2.7.egg-info/not-zip-safe create mode 100644 lib/MarkupSafe-0.23-py2.7.egg-info/top_level.txt create mode 100644 lib/Werkzeug-0.10.4.dist-info/DESCRIPTION.rst create mode 100644 lib/Werkzeug-0.10.4.dist-info/METADATA create mode 100644 lib/Werkzeug-0.10.4.dist-info/RECORD create mode 100644 lib/Werkzeug-0.10.4.dist-info/WHEEL create mode 100644 lib/Werkzeug-0.10.4.dist-info/metadata.json create mode 100644 lib/Werkzeug-0.10.4.dist-info/top_level.txt create mode 100644 lib/easy_install.py create mode 100644 lib/flask/__init__.py create mode 100644 lib/flask/__init__.pyc create mode 100644 lib/flask/_compat.py create mode 100644 lib/flask/_compat.pyc create mode 100644 lib/flask/app.py create mode 100644 lib/flask/app.pyc create mode 100644 lib/flask/blueprints.py create mode 100644 lib/flask/blueprints.pyc create mode 100644 lib/flask/config.py create mode 100644 lib/flask/config.pyc create mode 100644 lib/flask/ctx.py create mode 100644 lib/flask/ctx.pyc create mode 100644 lib/flask/debughelpers.py create mode 100644 lib/flask/debughelpers.pyc create mode 100644 lib/flask/ext/__init__.py create mode 100644 lib/flask/ext/__init__.pyc create mode 100644 lib/flask/exthook.py create mode 100644 lib/flask/exthook.pyc create mode 100644 lib/flask/globals.py create mode 100644 lib/flask/globals.pyc create mode 100644 lib/flask/helpers.py create mode 100644 lib/flask/helpers.pyc create mode 100644 lib/flask/json.py create mode 100644 lib/flask/json.pyc create mode 100644 lib/flask/logging.py create mode 100644 lib/flask/logging.pyc create mode 100644 lib/flask/module.py create mode 100644 lib/flask/module.pyc create mode 100644 lib/flask/sessions.py create mode 100644 lib/flask/sessions.pyc create mode 100644 lib/flask/signals.py create mode 100644 lib/flask/signals.pyc create mode 100644 lib/flask/templating.py create mode 100644 lib/flask/templating.pyc create mode 100644 lib/flask/testing.py create mode 100644 lib/flask/testing.pyc create mode 100644 lib/flask/testsuite/__init__.py create mode 100644 lib/flask/testsuite/__init__.pyc create mode 100644 lib/flask/testsuite/appctx.py create mode 100644 lib/flask/testsuite/appctx.pyc create mode 100644 lib/flask/testsuite/basic.py create mode 100644 lib/flask/testsuite/basic.pyc create mode 100644 lib/flask/testsuite/blueprints.py create mode 100644 lib/flask/testsuite/blueprints.pyc create mode 100644 lib/flask/testsuite/config.py create mode 100644 lib/flask/testsuite/config.pyc create mode 100644 lib/flask/testsuite/deprecations.py create mode 100644 lib/flask/testsuite/deprecations.pyc create mode 100644 lib/flask/testsuite/examples.py create mode 100644 lib/flask/testsuite/examples.pyc create mode 100644 lib/flask/testsuite/ext.py create mode 100644 lib/flask/testsuite/ext.pyc create mode 100644 lib/flask/testsuite/helpers.py create mode 100644 lib/flask/testsuite/helpers.pyc create mode 100644 lib/flask/testsuite/regression.py create mode 100644 lib/flask/testsuite/regression.pyc create mode 100644 lib/flask/testsuite/reqctx.py create mode 100644 lib/flask/testsuite/reqctx.pyc create mode 100644 lib/flask/testsuite/signals.py create mode 100644 lib/flask/testsuite/signals.pyc create mode 100644 lib/flask/testsuite/static/index.html create mode 100644 lib/flask/testsuite/subclassing.py create mode 100644 lib/flask/testsuite/subclassing.pyc create mode 100644 lib/flask/testsuite/templates/_macro.html create mode 100644 lib/flask/testsuite/templates/context_template.html create mode 100644 lib/flask/testsuite/templates/escaping_template.html create mode 100644 lib/flask/testsuite/templates/mail.txt create mode 100644 lib/flask/testsuite/templates/nested/nested.txt create mode 100644 lib/flask/testsuite/templates/simple_template.html create mode 100644 lib/flask/testsuite/templates/template_filter.html create mode 100644 lib/flask/testsuite/templates/template_test.html create mode 100644 lib/flask/testsuite/templating.py create mode 100644 lib/flask/testsuite/templating.pyc create mode 100644 lib/flask/testsuite/test_apps/blueprintapp/__init__.py create mode 100644 lib/flask/testsuite/test_apps/blueprintapp/__init__.pyc create mode 100644 lib/flask/testsuite/test_apps/blueprintapp/apps/__init__.py create mode 100644 lib/flask/testsuite/test_apps/blueprintapp/apps/__init__.pyc create mode 100644 lib/flask/testsuite/test_apps/blueprintapp/apps/admin/__init__.py create mode 100644 lib/flask/testsuite/test_apps/blueprintapp/apps/admin/__init__.pyc create mode 100644 lib/flask/testsuite/test_apps/blueprintapp/apps/admin/static/css/test.css create mode 100644 lib/flask/testsuite/test_apps/blueprintapp/apps/admin/static/test.txt create mode 100644 lib/flask/testsuite/test_apps/blueprintapp/apps/admin/templates/admin/index.html create mode 100644 lib/flask/testsuite/test_apps/blueprintapp/apps/frontend/__init__.py create mode 100644 lib/flask/testsuite/test_apps/blueprintapp/apps/frontend/__init__.pyc create mode 100644 lib/flask/testsuite/test_apps/blueprintapp/apps/frontend/templates/frontend/index.html create mode 100644 lib/flask/testsuite/test_apps/config_module_app.py create mode 100644 lib/flask/testsuite/test_apps/config_module_app.pyc create mode 100644 lib/flask/testsuite/test_apps/config_package_app/__init__.py create mode 100644 lib/flask/testsuite/test_apps/config_package_app/__init__.pyc create mode 100644 lib/flask/testsuite/test_apps/flask_broken/__init__.py create mode 100644 lib/flask/testsuite/test_apps/flask_broken/__init__.pyc create mode 100644 lib/flask/testsuite/test_apps/flask_broken/b.py create mode 100644 lib/flask/testsuite/test_apps/flask_broken/b.pyc create mode 100644 lib/flask/testsuite/test_apps/flask_newext_package/__init__.py create mode 100644 lib/flask/testsuite/test_apps/flask_newext_package/__init__.pyc create mode 100644 lib/flask/testsuite/test_apps/flask_newext_package/submodule.py create mode 100644 lib/flask/testsuite/test_apps/flask_newext_package/submodule.pyc create mode 100644 lib/flask/testsuite/test_apps/flask_newext_simple.py create mode 100644 lib/flask/testsuite/test_apps/flask_newext_simple.pyc create mode 100644 lib/flask/testsuite/test_apps/flaskext/__init__.py create mode 100644 lib/flask/testsuite/test_apps/flaskext/__init__.pyc create mode 100644 lib/flask/testsuite/test_apps/flaskext/oldext_package/__init__.py create mode 100644 lib/flask/testsuite/test_apps/flaskext/oldext_package/__init__.pyc create mode 100644 lib/flask/testsuite/test_apps/flaskext/oldext_package/submodule.py create mode 100644 lib/flask/testsuite/test_apps/flaskext/oldext_package/submodule.pyc create mode 100644 lib/flask/testsuite/test_apps/flaskext/oldext_simple.py create mode 100644 lib/flask/testsuite/test_apps/flaskext/oldext_simple.pyc create mode 100644 lib/flask/testsuite/test_apps/importerror.py create mode 100644 lib/flask/testsuite/test_apps/importerror.pyc create mode 100644 lib/flask/testsuite/test_apps/lib/python2.5/site-packages/SiteEgg.egg create mode 100644 lib/flask/testsuite/test_apps/lib/python2.5/site-packages/site_app.py create mode 100644 lib/flask/testsuite/test_apps/lib/python2.5/site-packages/site_app.pyc create mode 100644 lib/flask/testsuite/test_apps/lib/python2.5/site-packages/site_package/__init__.py create mode 100644 lib/flask/testsuite/test_apps/lib/python2.5/site-packages/site_package/__init__.pyc create mode 100644 lib/flask/testsuite/test_apps/main_app.py create mode 100644 lib/flask/testsuite/test_apps/main_app.pyc create mode 100644 lib/flask/testsuite/test_apps/moduleapp/__init__.py create mode 100644 lib/flask/testsuite/test_apps/moduleapp/__init__.pyc create mode 100644 lib/flask/testsuite/test_apps/moduleapp/apps/__init__.py create mode 100644 lib/flask/testsuite/test_apps/moduleapp/apps/__init__.pyc create mode 100644 lib/flask/testsuite/test_apps/moduleapp/apps/admin/__init__.py create mode 100644 lib/flask/testsuite/test_apps/moduleapp/apps/admin/__init__.pyc create mode 100644 lib/flask/testsuite/test_apps/moduleapp/apps/admin/static/css/test.css create mode 100644 lib/flask/testsuite/test_apps/moduleapp/apps/admin/static/test.txt create mode 100644 lib/flask/testsuite/test_apps/moduleapp/apps/admin/templates/index.html create mode 100644 lib/flask/testsuite/test_apps/moduleapp/apps/frontend/__init__.py create mode 100644 lib/flask/testsuite/test_apps/moduleapp/apps/frontend/__init__.pyc create mode 100644 lib/flask/testsuite/test_apps/moduleapp/apps/frontend/templates/index.html create mode 100644 lib/flask/testsuite/test_apps/path/installed_package/__init__.py create mode 100644 lib/flask/testsuite/test_apps/path/installed_package/__init__.pyc create mode 100644 lib/flask/testsuite/test_apps/subdomaintestmodule/__init__.py create mode 100644 lib/flask/testsuite/test_apps/subdomaintestmodule/__init__.pyc create mode 100644 lib/flask/testsuite/test_apps/subdomaintestmodule/static/hello.txt create mode 100644 lib/flask/testsuite/testing.py create mode 100644 lib/flask/testsuite/testing.pyc create mode 100644 lib/flask/testsuite/views.py create mode 100644 lib/flask/testsuite/views.pyc create mode 100644 lib/flask/views.py create mode 100644 lib/flask/views.pyc create mode 100644 lib/flask/wrappers.py create mode 100644 lib/flask/wrappers.pyc create mode 100644 lib/flask_cors/__init__.py create mode 100644 lib/flask_cors/__init__.pyc create mode 100644 lib/flask_cors/core.py create mode 100644 lib/flask_cors/core.pyc create mode 100644 lib/flask_cors/decorator.py create mode 100644 lib/flask_cors/decorator.pyc create mode 100644 lib/flask_cors/extension.py create mode 100644 lib/flask_cors/extension.pyc create mode 100644 lib/flask_cors/version.py create mode 100644 lib/flask_cors/version.pyc create mode 100644 lib/flask_github.py create mode 100644 lib/flask_github.pyc create mode 100644 lib/itsdangerous-0.24-py2.7.egg-info/PKG-INFO create mode 100644 lib/itsdangerous-0.24-py2.7.egg-info/SOURCES.txt create mode 100644 lib/itsdangerous-0.24-py2.7.egg-info/dependency_links.txt create mode 100644 lib/itsdangerous-0.24-py2.7.egg-info/installed-files.txt create mode 100644 lib/itsdangerous-0.24-py2.7.egg-info/not-zip-safe create mode 100644 lib/itsdangerous-0.24-py2.7.egg-info/top_level.txt create mode 100644 lib/itsdangerous.py create mode 100644 lib/itsdangerous.pyc create mode 100644 lib/jinja2/__init__.py create mode 100644 lib/jinja2/__init__.pyc create mode 100644 lib/jinja2/_compat.py create mode 100644 lib/jinja2/_compat.pyc create mode 100644 lib/jinja2/_stringdefs.py create mode 100644 lib/jinja2/_stringdefs.pyc create mode 100644 lib/jinja2/bccache.py create mode 100644 lib/jinja2/bccache.pyc create mode 100644 lib/jinja2/compiler.py create mode 100644 lib/jinja2/compiler.pyc create mode 100644 lib/jinja2/constants.py create mode 100644 lib/jinja2/constants.pyc create mode 100644 lib/jinja2/debug.py create mode 100644 lib/jinja2/debug.pyc create mode 100644 lib/jinja2/defaults.py create mode 100644 lib/jinja2/defaults.pyc create mode 100644 lib/jinja2/environment.py create mode 100644 lib/jinja2/environment.pyc create mode 100644 lib/jinja2/exceptions.py create mode 100644 lib/jinja2/exceptions.pyc create mode 100644 lib/jinja2/ext.py create mode 100644 lib/jinja2/ext.pyc create mode 100644 lib/jinja2/filters.py create mode 100644 lib/jinja2/filters.pyc create mode 100644 lib/jinja2/lexer.py create mode 100644 lib/jinja2/lexer.pyc create mode 100644 lib/jinja2/loaders.py create mode 100644 lib/jinja2/loaders.pyc create mode 100644 lib/jinja2/meta.py create mode 100644 lib/jinja2/meta.pyc create mode 100644 lib/jinja2/nodes.py create mode 100644 lib/jinja2/nodes.pyc create mode 100644 lib/jinja2/optimizer.py create mode 100644 lib/jinja2/optimizer.pyc create mode 100644 lib/jinja2/parser.py create mode 100644 lib/jinja2/parser.pyc create mode 100644 lib/jinja2/runtime.py create mode 100644 lib/jinja2/runtime.pyc create mode 100644 lib/jinja2/sandbox.py create mode 100644 lib/jinja2/sandbox.pyc create mode 100644 lib/jinja2/tests.py create mode 100644 lib/jinja2/tests.pyc create mode 100644 lib/jinja2/testsuite/__init__.py create mode 100644 lib/jinja2/testsuite/__init__.pyc create mode 100644 lib/jinja2/testsuite/api.py create mode 100644 lib/jinja2/testsuite/api.pyc create mode 100644 lib/jinja2/testsuite/bytecode_cache.py create mode 100644 lib/jinja2/testsuite/bytecode_cache.pyc create mode 100644 lib/jinja2/testsuite/core_tags.py create mode 100644 lib/jinja2/testsuite/core_tags.pyc create mode 100644 lib/jinja2/testsuite/debug.py create mode 100644 lib/jinja2/testsuite/debug.pyc create mode 100644 lib/jinja2/testsuite/doctests.py create mode 100644 lib/jinja2/testsuite/doctests.pyc create mode 100644 lib/jinja2/testsuite/ext.py create mode 100644 lib/jinja2/testsuite/ext.pyc create mode 100644 lib/jinja2/testsuite/filters.py create mode 100644 lib/jinja2/testsuite/filters.pyc create mode 100644 lib/jinja2/testsuite/imports.py create mode 100644 lib/jinja2/testsuite/imports.pyc create mode 100644 lib/jinja2/testsuite/inheritance.py create mode 100644 lib/jinja2/testsuite/inheritance.pyc create mode 100644 lib/jinja2/testsuite/lexnparse.py create mode 100644 lib/jinja2/testsuite/lexnparse.pyc create mode 100644 lib/jinja2/testsuite/loader.py create mode 100644 lib/jinja2/testsuite/loader.pyc create mode 100644 lib/jinja2/testsuite/regression.py create mode 100644 lib/jinja2/testsuite/regression.pyc create mode 100644 lib/jinja2/testsuite/res/__init__.py create mode 100644 lib/jinja2/testsuite/res/__init__.pyc create mode 100644 lib/jinja2/testsuite/res/templates/broken.html create mode 100644 lib/jinja2/testsuite/res/templates/foo/test.html create mode 100644 lib/jinja2/testsuite/res/templates/syntaxerror.html create mode 100644 lib/jinja2/testsuite/res/templates/test.html create mode 100644 lib/jinja2/testsuite/security.py create mode 100644 lib/jinja2/testsuite/security.pyc create mode 100644 lib/jinja2/testsuite/tests.py create mode 100644 lib/jinja2/testsuite/tests.pyc create mode 100644 lib/jinja2/testsuite/utils.py create mode 100644 lib/jinja2/testsuite/utils.pyc create mode 100644 lib/jinja2/utils.py create mode 100644 lib/jinja2/utils.pyc create mode 100644 lib/jinja2/visitor.py create mode 100644 lib/jinja2/visitor.pyc create mode 100644 lib/markupsafe/__init__.py create mode 100644 lib/markupsafe/__init__.pyc create mode 100644 lib/markupsafe/_compat.py create mode 100644 lib/markupsafe/_compat.pyc create mode 100644 lib/markupsafe/_constants.py create mode 100644 lib/markupsafe/_constants.pyc create mode 100644 lib/markupsafe/_native.py create mode 100644 lib/markupsafe/_native.pyc create mode 100644 lib/markupsafe/_speedups.c create mode 100755 lib/markupsafe/_speedups.so create mode 100644 lib/markupsafe/tests.py create mode 100644 lib/markupsafe/tests.pyc create mode 100644 lib/pkg_resources.py create mode 100644 lib/requests/__init__.py create mode 100644 lib/requests/__init__.pyc create mode 100644 lib/requests/adapters.py create mode 100644 lib/requests/adapters.pyc create mode 100644 lib/requests/api.py create mode 100644 lib/requests/api.pyc create mode 100644 lib/requests/auth.py create mode 100644 lib/requests/auth.pyc create mode 100644 lib/requests/cacert.pem create mode 100644 lib/requests/certs.py create mode 100644 lib/requests/certs.pyc create mode 100644 lib/requests/compat.py create mode 100644 lib/requests/compat.pyc create mode 100644 lib/requests/cookies.py create mode 100644 lib/requests/cookies.pyc create mode 100644 lib/requests/exceptions.py create mode 100644 lib/requests/exceptions.pyc create mode 100644 lib/requests/hooks.py create mode 100644 lib/requests/hooks.pyc create mode 100644 lib/requests/models.py create mode 100644 lib/requests/models.pyc create mode 100644 lib/requests/packages/__init__.py create mode 100644 lib/requests/packages/__init__.pyc create mode 100644 lib/requests/packages/chardet/__init__.py create mode 100644 lib/requests/packages/chardet/__init__.pyc create mode 100644 lib/requests/packages/chardet/big5freq.py create mode 100644 lib/requests/packages/chardet/big5freq.pyc create mode 100644 lib/requests/packages/chardet/big5prober.py create mode 100644 lib/requests/packages/chardet/big5prober.pyc create mode 100644 lib/requests/packages/chardet/chardetect.py create mode 100644 lib/requests/packages/chardet/chardistribution.py create mode 100644 lib/requests/packages/chardet/chardistribution.pyc create mode 100644 lib/requests/packages/chardet/charsetgroupprober.py create mode 100644 lib/requests/packages/chardet/charsetgroupprober.pyc create mode 100644 lib/requests/packages/chardet/charsetprober.py create mode 100644 lib/requests/packages/chardet/charsetprober.pyc create mode 100644 lib/requests/packages/chardet/codingstatemachine.py create mode 100644 lib/requests/packages/chardet/codingstatemachine.pyc create mode 100644 lib/requests/packages/chardet/compat.py create mode 100644 lib/requests/packages/chardet/compat.pyc create mode 100644 lib/requests/packages/chardet/constants.py create mode 100644 lib/requests/packages/chardet/constants.pyc create mode 100644 lib/requests/packages/chardet/cp949prober.py create mode 100644 lib/requests/packages/chardet/cp949prober.pyc create mode 100644 lib/requests/packages/chardet/escprober.py create mode 100644 lib/requests/packages/chardet/escprober.pyc create mode 100644 lib/requests/packages/chardet/escsm.py create mode 100644 lib/requests/packages/chardet/escsm.pyc create mode 100644 lib/requests/packages/chardet/eucjpprober.py create mode 100644 lib/requests/packages/chardet/eucjpprober.pyc create mode 100644 lib/requests/packages/chardet/euckrfreq.py create mode 100644 lib/requests/packages/chardet/euckrfreq.pyc create mode 100644 lib/requests/packages/chardet/euckrprober.py create mode 100644 lib/requests/packages/chardet/euckrprober.pyc create mode 100644 lib/requests/packages/chardet/euctwfreq.py create mode 100644 lib/requests/packages/chardet/euctwfreq.pyc create mode 100644 lib/requests/packages/chardet/euctwprober.py create mode 100644 lib/requests/packages/chardet/euctwprober.pyc create mode 100644 lib/requests/packages/chardet/gb2312freq.py create mode 100644 lib/requests/packages/chardet/gb2312freq.pyc create mode 100644 lib/requests/packages/chardet/gb2312prober.py create mode 100644 lib/requests/packages/chardet/gb2312prober.pyc create mode 100644 lib/requests/packages/chardet/hebrewprober.py create mode 100644 lib/requests/packages/chardet/hebrewprober.pyc create mode 100644 lib/requests/packages/chardet/jisfreq.py create mode 100644 lib/requests/packages/chardet/jisfreq.pyc create mode 100644 lib/requests/packages/chardet/jpcntx.py create mode 100644 lib/requests/packages/chardet/jpcntx.pyc create mode 100644 lib/requests/packages/chardet/langbulgarianmodel.py create mode 100644 lib/requests/packages/chardet/langbulgarianmodel.pyc create mode 100644 lib/requests/packages/chardet/langcyrillicmodel.py create mode 100644 lib/requests/packages/chardet/langcyrillicmodel.pyc create mode 100644 lib/requests/packages/chardet/langgreekmodel.py create mode 100644 lib/requests/packages/chardet/langgreekmodel.pyc create mode 100644 lib/requests/packages/chardet/langhebrewmodel.py create mode 100644 lib/requests/packages/chardet/langhebrewmodel.pyc create mode 100644 lib/requests/packages/chardet/langhungarianmodel.py create mode 100644 lib/requests/packages/chardet/langhungarianmodel.pyc create mode 100644 lib/requests/packages/chardet/langthaimodel.py create mode 100644 lib/requests/packages/chardet/langthaimodel.pyc create mode 100644 lib/requests/packages/chardet/latin1prober.py create mode 100644 lib/requests/packages/chardet/latin1prober.pyc create mode 100644 lib/requests/packages/chardet/mbcharsetprober.py create mode 100644 lib/requests/packages/chardet/mbcharsetprober.pyc create mode 100644 lib/requests/packages/chardet/mbcsgroupprober.py create mode 100644 lib/requests/packages/chardet/mbcsgroupprober.pyc create mode 100644 lib/requests/packages/chardet/mbcssm.py create mode 100644 lib/requests/packages/chardet/mbcssm.pyc create mode 100644 lib/requests/packages/chardet/sbcharsetprober.py create mode 100644 lib/requests/packages/chardet/sbcharsetprober.pyc create mode 100644 lib/requests/packages/chardet/sbcsgroupprober.py create mode 100644 lib/requests/packages/chardet/sbcsgroupprober.pyc create mode 100644 lib/requests/packages/chardet/sjisprober.py create mode 100644 lib/requests/packages/chardet/sjisprober.pyc create mode 100644 lib/requests/packages/chardet/universaldetector.py create mode 100644 lib/requests/packages/chardet/universaldetector.pyc create mode 100644 lib/requests/packages/chardet/utf8prober.py create mode 100644 lib/requests/packages/chardet/utf8prober.pyc create mode 100644 lib/requests/packages/urllib3/__init__.py create mode 100644 lib/requests/packages/urllib3/__init__.pyc create mode 100644 lib/requests/packages/urllib3/_collections.py create mode 100644 lib/requests/packages/urllib3/_collections.pyc create mode 100644 lib/requests/packages/urllib3/connection.py create mode 100644 lib/requests/packages/urllib3/connection.pyc create mode 100644 lib/requests/packages/urllib3/connectionpool.py create mode 100644 lib/requests/packages/urllib3/connectionpool.pyc create mode 100644 lib/requests/packages/urllib3/contrib/__init__.py create mode 100644 lib/requests/packages/urllib3/contrib/__init__.pyc create mode 100644 lib/requests/packages/urllib3/contrib/ntlmpool.py create mode 100644 lib/requests/packages/urllib3/contrib/pyopenssl.py create mode 100644 lib/requests/packages/urllib3/contrib/pyopenssl.pyc create mode 100644 lib/requests/packages/urllib3/exceptions.py create mode 100644 lib/requests/packages/urllib3/exceptions.pyc create mode 100644 lib/requests/packages/urllib3/fields.py create mode 100644 lib/requests/packages/urllib3/fields.pyc create mode 100644 lib/requests/packages/urllib3/filepost.py create mode 100644 lib/requests/packages/urllib3/filepost.pyc create mode 100644 lib/requests/packages/urllib3/packages/__init__.py create mode 100644 lib/requests/packages/urllib3/packages/__init__.pyc create mode 100644 lib/requests/packages/urllib3/packages/ordered_dict.py create mode 100644 lib/requests/packages/urllib3/packages/ordered_dict.pyc create mode 100644 lib/requests/packages/urllib3/packages/six.py create mode 100644 lib/requests/packages/urllib3/packages/six.pyc create mode 100644 lib/requests/packages/urllib3/packages/ssl_match_hostname/__init__.py create mode 100644 lib/requests/packages/urllib3/packages/ssl_match_hostname/__init__.pyc create mode 100644 lib/requests/packages/urllib3/packages/ssl_match_hostname/_implementation.py create mode 100644 lib/requests/packages/urllib3/poolmanager.py create mode 100644 lib/requests/packages/urllib3/poolmanager.pyc create mode 100644 lib/requests/packages/urllib3/request.py create mode 100644 lib/requests/packages/urllib3/request.pyc create mode 100644 lib/requests/packages/urllib3/response.py create mode 100644 lib/requests/packages/urllib3/response.pyc create mode 100644 lib/requests/packages/urllib3/util/__init__.py create mode 100644 lib/requests/packages/urllib3/util/__init__.pyc create mode 100644 lib/requests/packages/urllib3/util/connection.py create mode 100644 lib/requests/packages/urllib3/util/connection.pyc create mode 100644 lib/requests/packages/urllib3/util/request.py create mode 100644 lib/requests/packages/urllib3/util/request.pyc create mode 100644 lib/requests/packages/urllib3/util/response.py create mode 100644 lib/requests/packages/urllib3/util/response.pyc create mode 100644 lib/requests/packages/urllib3/util/ssl_.py create mode 100644 lib/requests/packages/urllib3/util/ssl_.pyc create mode 100644 lib/requests/packages/urllib3/util/timeout.py create mode 100644 lib/requests/packages/urllib3/util/timeout.pyc create mode 100644 lib/requests/packages/urllib3/util/url.py create mode 100644 lib/requests/packages/urllib3/util/url.pyc create mode 100644 lib/requests/sessions.py create mode 100644 lib/requests/sessions.pyc create mode 100644 lib/requests/status_codes.py create mode 100644 lib/requests/status_codes.pyc create mode 100644 lib/requests/structures.py create mode 100644 lib/requests/structures.pyc create mode 100644 lib/requests/utils.py create mode 100644 lib/requests/utils.pyc create mode 100644 lib/six.py create mode 100644 lib/six.pyc create mode 100644 lib/werkzeug/__init__.py create mode 100644 lib/werkzeug/__init__.pyc create mode 100644 lib/werkzeug/_compat.py create mode 100644 lib/werkzeug/_compat.pyc create mode 100644 lib/werkzeug/_internal.py create mode 100644 lib/werkzeug/_internal.pyc create mode 100644 lib/werkzeug/_reloader.py create mode 100644 lib/werkzeug/_reloader.pyc create mode 100644 lib/werkzeug/contrib/__init__.py create mode 100644 lib/werkzeug/contrib/__init__.pyc create mode 100644 lib/werkzeug/contrib/atom.py create mode 100644 lib/werkzeug/contrib/atom.pyc create mode 100644 lib/werkzeug/contrib/cache.py create mode 100644 lib/werkzeug/contrib/cache.pyc create mode 100644 lib/werkzeug/contrib/fixers.py create mode 100644 lib/werkzeug/contrib/fixers.pyc create mode 100644 lib/werkzeug/contrib/iterio.py create mode 100644 lib/werkzeug/contrib/iterio.pyc create mode 100644 lib/werkzeug/contrib/jsrouting.py create mode 100644 lib/werkzeug/contrib/jsrouting.pyc create mode 100644 lib/werkzeug/contrib/limiter.py create mode 100644 lib/werkzeug/contrib/limiter.pyc create mode 100644 lib/werkzeug/contrib/lint.py create mode 100644 lib/werkzeug/contrib/lint.pyc create mode 100644 lib/werkzeug/contrib/profiler.py create mode 100644 lib/werkzeug/contrib/profiler.pyc create mode 100644 lib/werkzeug/contrib/securecookie.py create mode 100644 lib/werkzeug/contrib/securecookie.pyc create mode 100644 lib/werkzeug/contrib/sessions.py create mode 100644 lib/werkzeug/contrib/sessions.pyc create mode 100644 lib/werkzeug/contrib/testtools.py create mode 100644 lib/werkzeug/contrib/testtools.pyc create mode 100644 lib/werkzeug/contrib/wrappers.py create mode 100644 lib/werkzeug/contrib/wrappers.pyc create mode 100644 lib/werkzeug/datastructures.py create mode 100644 lib/werkzeug/datastructures.pyc create mode 100644 lib/werkzeug/debug/__init__.py create mode 100644 lib/werkzeug/debug/__init__.pyc create mode 100644 lib/werkzeug/debug/console.py create mode 100644 lib/werkzeug/debug/console.pyc create mode 100644 lib/werkzeug/debug/repr.py create mode 100644 lib/werkzeug/debug/repr.pyc create mode 100644 lib/werkzeug/debug/shared/FONT_LICENSE create mode 100644 lib/werkzeug/debug/shared/console.png create mode 100644 lib/werkzeug/debug/shared/debugger.js create mode 100644 lib/werkzeug/debug/shared/jquery.js create mode 100644 lib/werkzeug/debug/shared/less.png create mode 100644 lib/werkzeug/debug/shared/more.png create mode 100644 lib/werkzeug/debug/shared/source.png create mode 100644 lib/werkzeug/debug/shared/style.css create mode 100644 lib/werkzeug/debug/shared/ubuntu.ttf create mode 100644 lib/werkzeug/debug/tbtools.py create mode 100644 lib/werkzeug/debug/tbtools.pyc create mode 100644 lib/werkzeug/exceptions.py create mode 100644 lib/werkzeug/exceptions.pyc create mode 100644 lib/werkzeug/formparser.py create mode 100644 lib/werkzeug/formparser.pyc create mode 100644 lib/werkzeug/http.py create mode 100644 lib/werkzeug/http.pyc create mode 100644 lib/werkzeug/local.py create mode 100644 lib/werkzeug/local.pyc create mode 100644 lib/werkzeug/posixemulation.py create mode 100644 lib/werkzeug/posixemulation.pyc create mode 100644 lib/werkzeug/routing.py create mode 100644 lib/werkzeug/routing.pyc create mode 100644 lib/werkzeug/script.py create mode 100644 lib/werkzeug/script.pyc create mode 100644 lib/werkzeug/security.py create mode 100644 lib/werkzeug/security.pyc create mode 100644 lib/werkzeug/serving.py create mode 100644 lib/werkzeug/serving.pyc create mode 100644 lib/werkzeug/test.py create mode 100644 lib/werkzeug/test.pyc create mode 100644 lib/werkzeug/testapp.py create mode 100644 lib/werkzeug/testapp.pyc create mode 100644 lib/werkzeug/urls.py create mode 100644 lib/werkzeug/urls.pyc create mode 100644 lib/werkzeug/useragents.py create mode 100644 lib/werkzeug/useragents.pyc create mode 100644 lib/werkzeug/utils.py create mode 100644 lib/werkzeug/utils.pyc create mode 100644 lib/werkzeug/wrappers.py create mode 100644 lib/werkzeug/wrappers.pyc create mode 100644 lib/werkzeug/wsgi.py create mode 100644 lib/werkzeug/wsgi.pyc create mode 100644 main.py create mode 100644 main.pyc create mode 100644 models/__init__.py create mode 100644 models/__init__.pyc create mode 100644 templates/css/theme.css create mode 100644 templates/images/wellcome.jpg create mode 100644 templates/index.html create mode 100644 templates/js/app.js create mode 100644 templates/js/controllers/mainController.js create mode 100644 templates/js/controllers/registerController.js create mode 100644 templates/js/services/apiService.js create mode 100644 templates/views/home.html create mode 100644 templates/views/index.html create mode 100644 templates/views/register.html 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 0000000000000000000000000000000000000000..fdf773a2dc605b8f0782be9a7cda0256fb5541f0 GIT binary patch literal 1440 zcmb_bO>fgc5FLLcX-Wz$g+mVr1Q%auRB_>e5FafNRYZ|3L>mdMQhVz-_#?G9QX{3O z@Q?Wc@Mat};(&xi9L@Nx3AXQGGy)h=#}(MK+}tWi}0M zvLc6~Es9+FL9`?~A7b4gZPUc1OT62>{i8uqivq8WQpV+?qc}-^;qokgWb+Xh<}Pj@ z6Z2_y@pjNtr+Qx9vfA*yFc8f;LWxIB1(76Tk^3vkH~JfaYllC0xzkLkvy1=?z^b~0`WwrOy6L|;*}KC*8bI3i85 z#3YQoEhK5VU*y^xV5RLZbZ&ab=F#8(4Rly)BZW>+&I2$e8l|b+%UNz%*}9HO zBD1qzRkBg!sFm00rD0vJB!Bk+NmBI^s5>q)-DP{agLya}mD!*yCOR}#H#m6?XS!fN z7K7I4a5^{Kr&39t7^RxP6`M&`8^4Zqfaq9a2OrHLcC-Ls!GzW0hkePu2*+!`gS07z zTs79F7u^G>_>-f5r^GGQa}WM5 zr#+;#ME~!k&&s%nihFL_?RMMo*{Bd97ds=f_yj=9Eb`1dJV8TO=D)@b9z@>aaVei0 z^!GV&1)281lt~`r6PxPN%zbXszk{^VhM4?AM8#b-@gertq*l6)W@cQJkof^#iHjmm s_2Fnb)p?xc`cPjRp)AtKfPXF`or)@(WGarosy%+q8r2q9yY~LxZ_9ci&;S4c literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..9851c6327e90fa06b00d218a85ea3b517bda9cbe GIT binary patch literal 172 zcmZSn%*%Bm*e^7h0SXv_v;zSyHVrs{*V=m%6LXCxNo1{CFIr6!jY>j%5)dXy&VyJwbU nlqNX_cSyHVrs{*V=m%6LXCxNo1{CFIr6!jY>j%5)dXy&VhZd(6 i>Bq-s=4F<|$LkeTmT&;I+2rP@l;)(`fov%TVg>*Lj3dwh literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..d01aab4acdfb978354eae4c57c61ce0c653db352 GIT binary patch literal 410 zcmZ9HOKQU~5Qax~UM=Yzw9KaQs=HDOrI1w#gl@7?6lr3Qu_a?EgsgLr9Mhkm5|^X^uCyu2IuU1N^Ve8QT=0&H0Y*bEv0TZSLbV4DL9s7Fwb!7}HGCx0*n zoWX^MM{vo8E!bkS7~I2(Wv9CiT}cj=@$Nw7PL>#hY`nH;<*7m^L)3jFS4u4%o+RIB z$mmGkNpjqD2AA~3>y6kEV$RagesMD-Qx>JHH%g^OIEPg8VcF?e#ftpNfvB4+7E@61aM9jrJ{|3wpV{HHc literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..9dc02fbe8c0bd9468ef169e524c083ca91b36ec2 GIT binary patch literal 2161 zcmZ8i>2ecC5dI|jzK{)=%fMnTaY?qhj6)K@fhwvJevCt_(WK(Qe?dk6A^ZQ0>{JXpm|F!=)#`vkz|2On0|E>WEAW7CBYe?!y z8qjr^24n*@)~BGSV5T9bD}5Sz24)s=7G@4|j;u3CW})X{79ba379kg5mLQiZ-yHNZ z%nIa6rO!j3gK0uGVOAkmVb&nmV9rCHhq(ZG0p=p)MVNKSb(l+#mtZbKUasO7ps&DO zg}e%L4e}by2IL0Jb;#>5Hz04o+=RSYy}bw>z}$ko1+xjc33D6rHq0H!JJlOY(05_( zLEfwMW$61bEyz}-uRuS5c?kIs<`Lwh%6bm^G0YRlCopZuHcSVy1G5FW1+xvg4YLEe z1M?K}Dad{Jd-LcfIBh1^9=?c(qi8<;e(iOM+gmb$(O^T~)fEuu<&NSOrDooU&QjuBz?Dd2wRX z{=n@8t@uH(v$ee)bWeh})}&b=@+^u6%C>#dJxvL+Qtbur4t{zZlu89Zf82ln>EJ!p zvVqC13KHd_R8#hHhNj$VZ_{7;A3ZJND%>=QsGD0?sdJ=Sm84e1uEn%=9Q8|NhoizD zRT)QxN;$UGU_U4Lz-x1}bQ0?K5l!bfk5FZiQ+HKn&aIPw)6L!b0#eKU)67k4d!ZVDD!twZhKY|?( z%)^(|MoM98bfz+X6JhL*!_r0Z(5|&mv8|ej&0&UBZs7lN2->r&NibY0?{Q#nSa~O<%LxRxi!cazMt5WbEhe zbSdgMR)yp3GWe4ePDR{DnB+&9yF?D!)fhPH|0^GN^Odg{`6Az1^P(8{IA+v@VHJfL zt-~_UDvil`plIQ0KhKA$I;hb9)cTPeo*NNyu&m*jCKUyOW`jc3mQvsXM%5{@N{KCYoNO(n3ukpfzkzaApFf_9$|=AYpH1;Zd1CBc`@aVJD|!61msEUvJ)O2U6{ z7|%O#jdd>Eo$#&{OkQsr(}e&P*U2Vsu)|-hie2I+TLTuiSZuPm&EgJ=yDaXpxX+?R z!qErf0iQSzgO~PB{I}EivX>t1hs Mm~BqYH=4Eo0a*zTbN~PV literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..aaca4b8689763dafac4867b92da32c434c1069de GIT binary patch literal 3279 zcmb_eUvC>l5T83cPV6}Unzm3>V1Wl*2nnPhqNr5R(1%JWptJH&znso@>tvJj-RX9d z)KcMrRJ0F#2R>v!0Q_dob{YW>Npse&XJ>b2emj45xAuCW75}xf7t{Ew;s1Ly`x;$B z)I;x4;#2BT&m-;8p-)MT?j&_O@~Ky&WQJZ~U7d7|?4P7(sMp|r0D)Q3b3!yJX~?n` zC9^`zQ!*z+TMRTQU7+D2^%lv4wWLKaAiqqyPQ4Y%dZcfR^@13{u&CCnLPPufM0f#@qZr*+)l$eNAWqLs^4q6?i(6cjo(0~4#Uoalh8aqAVH?Km$+rP)7l+o}`aQ=4CYbzk*I z>W6Y@G8N=m6d&kvUF5b?6YI?CZS|=8!j&$oS}DxQQlh2ehrDdroj8b9X!FNJz)yXVsXQ_A_)FZdh>ZZrQ!PZ#PoYhX>t3 zo^6QRH^y#X2XhX~AEeQ+pF|IrSsv}&JYx~_Jmmzzp+{##XWkSFuW<~|I9&>Hq(}A~ zTykY_0q^Zyw5x#%1X%;}CsBH=D@Xw&eLF;V-V)Ia0;qC2hqQ}Y$o8N7 z9M>@5HjU)x7(B;egWjj3CY2w_(BmPZ`nyM&EC7+5=bN~40it2($|%Ca% zy{26MyWKp~_qJO~0;?{}P2)Pv+`CX!#T9*s^z`_8VOsibhga@ikn1vz)u|lv0mm2Q zkm%#(mUHyj4ZheCaW{`)7#?RP&J&Fc=S0&P52UyP4Bztj_!=4{N|iy*>@dXL6@~#{ zkyQj)YC{$JNvJ+Ew+iF+LUFKXNpA>kg;B>%+bykBXS$NlRCJk|;#kksSjDdU{6mFJtLgPJyw~kMT zHGbhRfoDkl4LihkdNUMMg&VVKZX6~Kq~#4T0HUKgDnBM%fOt3|3vj3b_wyQ^)u{{k z7{3A+V}>ZXQMr@1EB6#`DC>sjcg)*H**cO+pJ1{on7l*A54pu6M zobY5VJ3!1_@*)oSR(Xsz4bE+^!^tOy7H|Or(veYw;V@5*Qw#&X9LEddC{3|oP8OKV zI83w7YR`-`xXa!96W(P3-iF{KGy&M~n)taTjB%6UB^H&VPy%0-$vbR?9WC}M%dFtP z&|DJ8`K2>Wwk>Fu7ZSBTob9lkaWs=WhEEuW9a-1L|M+Panrx8E#4k@bC38cQpi=O( ztd_e{xK2NFp`-^3S0yB4E6Ysg9N&ug*ZaDxW&*wy19nXy&nEW0$pfygfc+A%L~sk8 zpd6nyl09jj?Tg)ba)Ae*U|r=k5EXS', + 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 0000000000000000000000000000000000000000..b14e25b3d0cf10857145c688dc9c6db6e901d3d1 GIT binary patch literal 63176 zcmeIb3y@q_dLDLq1{h$500zW^B=~G{31UD3!#9^ZOYZIv7?N0$1Mm*80Ef%%?&-dm zX`mm2zCC!X$kke0t+ryVRI>b%ti+F0C9zZSChjPAUf3ckbidbI;>{|Nr^V`0wnVs{hFo=jzV?8^_-- z;g=m8bFSgsGL9wJ7;~+XTgHi9tl z*S^m!-{;!*yXE^``vJH7fR*0mS`WJRLvHyYyWZ_uW!HY#EkEqqkGSPW?Cu`d`iyHo z>XsjM?Za;Qu-%<@t;byZh+975+B0r>#S<)ij&uWLQ-+E2LUCtUlOTR!I6$KCRA z*PeCDvsU6x*Lu>mpK{Aj+4VlxdfK(0am&xx^?uiS*0rB=%g?#?^KSWh*M7k*zhKV} zxYlP~`$f0>qHBN7Eq~6n=iKs~Yk%G?f8MoUa?3ASxr46tvTJ|AEq}qazvz~~=-OX$ z%U^QsdAB_8O6fNDA*T2h*SO1l3nwRB<8Gatbd7sldXKw^DLuqHDE7|s0^wk3=3auw zFXJ#(#=ncLT6TH1w!W^bZ-jqSx;(qq%*yRh+D<$DtlVEq%XOUfYOV75 zrPofC@p`LSul1YVPPw~sDXsTst%A9Fcl}1Mxw_V$E6>!AmY;d*>8HypH_G$9cC%AX zx}92mE$z+fV{@n??PTd(`IV)U$I4lnmft*eVqtMoW;PqCbrrNqS`?&H72&X!g+E{uJ)Lve9fc7J9vI z&t7DGub(}8X5o50UFX>J_v6l~PCxB+YOSTTcQx&)cz-YMzm@jax{bwdf4L0-QYTB=Gde_oMrJZIO zif8@1@Sugk!o4~NzfoE5buk3}8~uCmsFHRX>)mDtZ}z(F%GG9it#WarQ}6G>!;8%h zira^6$T&ckvTkPv)W)d+zPbIKxRIpUdKWWlPdRKSx}A&7)%kwE*Ie1?r+xOv?#*zR z`o&6U>+9i?B`Un`Uw^IDU8%J)8|;0&-?Le%)ce;fSsx8mll)zsXBY?0 z1V?k#`fxu^m(u!1FFn!iUT&sKRz&l3u~tv56sK;bwUMs(I5^F$VrXH_=AfQzX6vYV0 zcomd|{-7_tK0tzS67FF#nw;AHLEK#J_G9PM2yO&|P`sbk(DKzvqkFB>zZ(w#_;nj% zG$Vgzqe)QerM+4+OEvQuCJZn4Z>$4^gkhK(UG@p(7?N}~?b-7>$Cf|N=n4F?G7f#` z-p8@zJ{)t|{X7A`!JQ9XX$gOp1S5-nj?l11W>7=KYG%z2hM-eV6JY@leGbyq8fIh$ zCr*d#F`PZwZ?E&W^kR1I+-IL`HCLWozX8Fvz8-&J6yLLIPL}Kv-Ze@f> zSDG&EE~y`cYxaXbG~2nK02-+6-*)bUlDbuL-$6e}T3I@~jKg`*m8@JVw}sT@tP7f1 z>zAATGEfcp+2%uFU;T0!bg+@GY^;*bg34Ybbv4S|>}CD3pTF|88eVDj(puw2d9BuI zw9vJAGD+DUn)ACA+`NbE8x+oORFtWX?R)P3OHfscgz$_@}i;fYUHNF9< zMHuHZyiGo0Jce^Frj(_vi#n*%hz~ngp0^>@wU-}P;>>Q`4%2cQvTt|luPe$>7+}ih_;Yj-<@>t;^uDG7-eL8`Z`+!Rybd9~Pai?qSbE{*dln`=pvw62m%WUck z{Ikuy(CE3we*1I4{%psyM_l6|B}2T|*kNTS?dg>Lx!eBSgFlB{W5TZPwLkaag}Yqi zetYi$yZIpg^j+g&yZMOy`3!D8>Kcdbg~#mA5&JXaUf=+H#-$Lw4?DDT`7xIsL6azL zv)TCnsB1jV6L#ha_bn(NxN}Ssh5N^K@`PsWahE=!89V0QecZi^o5x*amIe5gS(a%$ z87`mH&Ku#*8{y8I;m(`k&RgNmTj9=PxU(4UoDO$R>&}_*=`*@~J6yi4 z%OqSTx?BpEOS(K8F3;-nT(~@^%ddpXujul8xIFI~7kIvW!8P8|$vdvGtdnKecvmOy zy2e*^@>SP(PbcrW#@BT6HP@)`^X}LyQCvDg0=%gdi?ed(n)^&|_ z-CuW&D>}L2lBJmqQp$f0;rT51k^~{Is1^0P+GcHze6LoA&IguEmgae#1Qf67mCL8V zs3hIcoF?)Yc6(M&bT=rvW)Q3}r7fsJ=#c63bDW>KDs;{cq#G+y^_89TA|nJc4*~e*TpfHr zo2!cbSJ_Uf0vsy|Zfy)*Xs3q-FJg}9C4f>dh0$y^ArewJoSUorXj$LZ z;PE-2w*0c)o2gU?CY8!jdwq7cTx+zu7+XNr++2BHBf*(}Rr2zgFnjse2x@?sT0j^R ztn+CG$YFw4n*cR6gLAF&*Pv3wHm#(sZf8|R)xkl`l0YtaE&wpq`8Y{gtO;NzNF`8Y zH!>j2F-ZR%2(||LFyBD=gQW&N)b}t(y)IfO0d^G=9jh9E2~rY(LcfS+9L*)j;{79; z7szWJU_5mt!T{^_$OOy;q0#J>Yml!upcAeVQt_u{sK&|+UXKyLZC(H{ARDb~wHs(F zMjA>44K`(|j(L@9Fu6dyXVtOw;S(NKj#)ERk4|_o%4^=)dOs>~wtHp1Xv$gI6p z|5~?rM+9yuDnHe56e`)mg7u0L~R_Q=t9pL)+D2MeEHgGR`y zsP(@{MKK*z1WD_!b$geoY(en^$tp}G33{z_IR{mad-qxn!-9+!tT>pHjdjfK>wa1T z8<7SW;Z%?qyRr^Ca&e=Dw@yIKB2g)TIT1iFgA{GFWzEaVR1g~^)0om&ji(qM1U5}4 zsxMABp+#7IeCh2s=UXrdv~R?!;`faQvSVa-0x`i_Ab|yV(8!iyu33daCT+yJ(0+WO z46PG96Yu3V2SWljq}X)K5mj(A4nm8EW)|z(Sl3MSbBsrgIrYb@t!~ywy)(tGat;KR z-A*g-<9ZV|5EvUm3YOAu)+@B0!icw41p)E5jA7#jrG#pbAYfx9ACFiUsdZMqCQ}B#2`yD{b}sG&GAizv-VL;;n`-rledb6tg3jj3g1`ne;1Kk>#6u3P?`vV^20AzdoC94{hrFC=j4+foTI^ZI zEr+@w01N@pU{`Nh35Fnk8KdwKeZ6H>HyekDIvg~JU=WR4^11XWLxraU&|1U>8`BZf zf?KcLATOrvUQ^@Y2Ym{)vP&J%ZHfdKq+7HKIaGYhn)+)4 zfDqn+d<`>YPCMo(Ux1Laan-ZEjkF5ZX(fblLIw!%g&cG~8M-GSZvF3FX%C{L-HEgLZ`!<~%vjcfo2nRm@mNb5kh3U>dI zgRu?u$kWGKA&6(m%e+Gy_DOikQgaEPw};8+aa-o@gyWYy$pg!Of{_F;j~>ZCi+a7i zdT(j(nC!#n8w>BqvAVRdv~=q9V&%l?({G$w zs4ULEwb19JomoiUnqOR4JX;AR-aPf{!r4=JOb-~R6gU7z4@x6z{kf%u$^{f&Jo)OW zHy7jweDm~cuPr22C!z3o^9-BG)2WQ+^20MN$h|G%;Zcb}hi6Qo!PUEmXGqWN*&Iqj zBj|LGHr|_?%4n@eQS_TPX!ij}5XE7#A{RdF`OtP@FkbGqUBeZyS;lkMp1}hd3h&7;VHR*{` zr&ZW@nqQkga|Ukxc~)3SPMbPv^XJ|? ztB;;d=Fe1KnLk-c7T!JwK&mVx$?0TCqo!wUMm{7<8k4ntf8CGk!mD^;;baAdsmjuc z*B3kleR&B3GQWiXPn2-2OU(}{p{sed0@##^UeeW!v+ID7V;Gs!7*Az66s+?(@> z96u&qcn_`lmb3a!yhxudU7MmLe;W`7f9xd@3y=&@mG|M`7%P#UfO1@(biKDpXh2vj zKIj9)|GdAGPS=LKA`P6-4Wc(b7^g$=eGwhL+T=OO(1h-93swFB_x?8B-=X^xy1&!) zenAv?r~42dRlEXM<)phbX_x+@gAJKVV^+&L6Z?hTLb3wQ1hCl9dd z{)28+?kH9LP@Gk28P|VQCx>1Cv2gQ?>z`nxJ1dHxrwS%wH)v4G66Ptv( z{*(eqrPZbOF7jzQxpX*P+atS%Ip4(rpusV-u!fW|NELI(BZh$Nc;Hrr%A3M{IL9jt zTdE8c$V95llO6dh?Y5bCp?@&op_Z386SY>1z|d=qkYSh!!%v1Dk>bWj5V|lB4E*sG zGE{}Fl)VlyG7u|#m`o-z&u1Z=CR+ZJ&#+Ds%!mk~*23!yEr}sLS@LCECUnG0L}0yb zM1AqbtB5j6lV|uGKc~T|42=$Bs`_{0=~^vg>=Dfg9*BsR(9UIDpeI6MJQ-j)mIIK_ zkV2baw9aqH8*bGQx)OM}U2>6!3J)!oVZc@dtRO>sJHgf^tE7%skh_Pr5&YR zrM-xW*-@Gt+l6!cZ@Pp?fQiZN`^G0ryCx>LP43!1Ik|Ik2Y$Qoo8oc2w0Gy^-pM<6 zZ9|zIlcoKoi9D``m~#TZ>^KeslC4RyQL+Wk0mBiu0nHl+r6VgVNVZ1RPUGev7@O_X z1kto{jP`43D;a@^1wswe!BpL2m0E8r3QkSg>vy3j2S}@S6 z?DshfWZ%w@zqEp&8EEV%n|i4~oPe)`9lV5J&}qg|NR3Uv_FaM}#b#3w{{+pZ3_jTG zZD^r|Zj>fROg90T%uADgdCc`LFdPiCjj06~9HQU>DPx@RRg_M)xyz6e;9y6X67ccT zguAqZq6klRvIOJ;{10K}5JSmO?~+33vI>UptT!T!GM@NAC2+rB)R)GssG~v4lPpAh z7>r%;YRRM`&&4W2L1_t=|Bt158y)Xd%fq>-@eUbS>A3<&-0Yl@r?Y{8!dC5uITH{e z)rktQxq&)q+AvcN8RY2xo$3d>9o2rCFyW}_^_nnG=G8&zMs#dv)o{ZcBe{F(mgdW{ zXSVD~rQ$Ehv%!Bc%Wl!gnkX7M8`LCfn2M>TZ;AIz!^s4d$r^4Xd{uSHi2z=p3tHRR z(;VT%f-iQq2D`*(RyRdpC5d)Z)1^b8ZQDxa9B7Gakw!(JJ>(&COrr7wgh4^xm|H(4 z&?b!{(q-SnAwe`9lx|TTjc%B$>L?|vI_RB_lWuRqCRk@!n&1v|ddwo>t|3sfT!U=~ zUO5CWMSY zg}8yO%t)NhEzQiE=)|I#P~yxC%|`OGD6_S>pdt=lDPuRK2uWexPChF~;-u^>ObX$g zcq}yeF`U?>^bY$IQ!_6CS3v5+%_We4pMD!krRX)ZO*H>gMRD#?GLDo7x)o?)+>=)TGGfl7zik{Lv)BGNodkLn8{df%*= zMB&%zWy-ps``&dt5Wv6^XvC~lJ}Y0}%#nF>ddou-eW06tx#2Bu)8l*owA`&DOdejv z^2}j4^AW(CW=D@4D?j(lCWmmSM1ldTfHRd!Nvr{%jpH(k96cMK=DMp4Z59~hHKaue zf=L%Zm;4M5S8!0kx-Wn~5X-56U1ad6T15)>M{%cMisa=dKpaY=Hq_4%Lulo4yB~zO zyrab9UWmOSUnF7t2~((j7|?$h1hs4y_s#-mt= zfFBqc^RS8|t~mIl7HjGyvC=QIfB3;Py}3su0@fpwJF{=&hJbv)s!T})9q|r`5hw%g ziBaDX0;I@d)`VLY9pjDH-rY%X9|c6w%UZTUpa%CzhvQDvu_-+JbR3o)o9*^AOxUoH zP9YZmK3&Ry4=N5J2E>a6V8!Pm0?ud#lIPC(Kr@?J_1;KOK~X_44k?aFgm{XOxQ#l3 zi^0MNV` zt75BtZ*o6t&|wK5ED$O-+merbi2l%6*Jhv3#|I3GfwCmAS{ZhvTPL(T$O;>b3)a}2 zXh_))4TMR<{AkI)j`z02ev>xdyg)#b*fTi^Re6`u4RTo8Aw)Oc#tF1I0*ut2ua1!? z8fbY{={YW1yR^+++D^~{C=ssmTTqn@;9yW3cXvb4^7_)90J^h1Mqr50)FG0Mm06sz7EwV*9)1do6K~a1sgnKL!;c^ii>l<8M5vw93$W(|{ z#b`zkdJ*=jx!+Y0REi2zV55%-B$2S1v~ccYLx^;bFwat4uGV@Psp9c)cX5WKFWJWf zRh?l~hA?&si|WLq3J^rT0f7taQ^d2pM_53(H4s`wg%=|T?K}to+Fz2E)LW?&iuhw| z1W6C!1ds&X8^Rf=4?zkBdVvezCMQOJ4sdZA@tTak4I!I3p(so%qxe9AxKhhI_TwbZ z%#jJq#rd*Wm!klI)0mZ>6c`46A$ABMnenwbE(X~YEef~^p9$^Z3MD%FvD6CoW=59+ zCL!F#ny&Q_lL`4RmpgoOUh)j4w9UY)o=kmNb0EoVUv#gn`(FCx8f7!;0SpXF? z%*H^DYLqibB5Pa?#nnIzO&K89zEMz$u@E*iz>Ep(6xkr39V@DMM|vwqa)NKm2RX}p zA=jvrKZ9E$ZUqn|tqEU|DVvpV3HY?KlwZuvJ6f(#OtvG8X*X*)bsFv-Jz z1f%MQZlVNay9Cz}-rPfv%1by~lAR)Z6o7t0k>{qZkC4M?g;30&hi4Owx)u?bYl<|r zc-Y1AELhtsRxo$HRsmH@O=1dy(LkA~f)ILPDb7^}5-i^cA1EM>3c3b2GhWbYJVtUi zu>|hx3ce;rnT;pMBGn$O<0S5N_+`57=GTqBucT|Wt4#_G5nD!yQ_shz@^Iu`N%mk4 zlW86>LoT_W2WpeagE+{$(eG-RFv|$cuq3cAxqM*!VQJUPwM78>sLUVzgs5uuaw(hrDWxKh`<`Xne`+=n6gdVqPd4>tZ83 zsu(a>ix3*db?025L7qa#U=E&V@s5E(Xg{r`Tz(D0x{~&uUrlaMI;!8{(}VOBYK<@fqXnXkPODvk`j(!^6#VT3ZDokO&-i(U=x6#k^=+<6#uxv@pgX(Nmg#i(`%_PRbnzKT6}I za$rVaH1tvIr7*RGYY0?|kHA!ro@8K0(fXJxzLA0w>2fUy3wao*7|>hJ@d&L!^_TAT zvF9pdgJ;+J?Uwv9JhPMQxI-~?_BtP$)%Rl-Hk#RB&%TL+&dYB1zJZA1kZ_X(Li6~E;Qz%U|x*B%Ky2mvpjF&e;4$Y&< zY5bnqx*`+RxAe`Zc%It@&!OIl`3m45R^8HeRSq!^qXByZxqnTi{HLlQwhR1 z(1#ivfZ|CttfDXnAcT9(q!#Zf1wd>%BDgpf?*t& z{qDM?Dp@KbcS=Z#Bu+8SPV(>L$~4jEc%SIuo31DZi{Bs)0Zfo^M0(-My6~1W!C+Ta z#)4ZTp9r@bM!YWY*z5{~sM@0!>ms7M@#p2eWZa}jDri0pm5HJeYZcP?$ef@5R z)B*jCj-bSM$6e_>>cte|&B~O!fQzLW#d(y__hiGn2n+f&*G6#79Bd+Bo`?+Xt}}@Y z(3`n~C|?cwm%UCR<38l4Rt-2$Ez@w&-U4wUf+MJji#5&W0_zn-$_TgQJX&95j2&PP z5efY18sVS0N)Vg`M2E&ruOrt<`2(7X#6g(kuvBRWCNgRXHAghKj{0msNO zBniRFB1Tfdk%^+QS!z;x9jSUG75a4}%stcdEHgCjm_A8^01cb5f@&4wa3uv5NUy)F zpq?t$6w&(WSJYrcMNc(El!n#RP-{W{1p?R86@o1oT`D4Hwel*)z1OV!n{cS+1BaS6I^Y_x z&S-J@|Tb`XaSRg4;FaVoC$<&>(w21*cUY!0AUViLQ9^<2dQ zy&&QN9;(Lgs#Oj2%UYOVYrSm3tje?(rYvWEXw_2Mr&*_LMZ;8KUeOsZX>owq#+8%> z2RdJD*R^iv2*V|yL}-vBR8ym<*8n=~C9K|7kWr18iow3=?ZKJGL~)sAQAU3Hsp5Cf zV(5a4k@;?jvW&dv$~fAvxEPtkTdfvCsnNl}KnkDp+-nVCiN?BkM!}1t(ZYIpKx(%$ z%Rxhx_znlDdgQ5D{dYv8R%{x^*Z;G5L@PY#)vh8Bn?MEJO!>?pqX3mCJM1nd^x@H8R6Q8xu#R@r zh=N-pEkGPtNEkP%3y26Zys6cKJ}t75%zi9j6WSH%nTp7Qm%kmx*#0gd@7(|$&kOp& z@zx0&AAiA_1VnlpqiN;rBC^A!z19r?{^+jYo9ENs<*%nm%oN5J;4wfu2HNMB?_-st zUYg}gsC^cAT*(mM)WV`7@(<<&xalVgt3~tP6&$_vjph}~*dDNM$03ER5rofN+kjd?d7}nG?aQeVkON@yQ_2E-yFlB)59lz;n@|u; z$kB|CDUh9lRJDqp%!Zm@E_-f;TDrZ0Q7%?j_!8P5L!Hx{8!}5}!7GMK0M`A77Sw>3y`cwt?6}aGDR}wP0}@A>~?Z zlgW|fg0VJ`VMM~z`WsAXf>a0~lgj@%y0av7{Jtl4VNzplF=)WUiw|@ek*Hv3I${k3 z3=fAdbBt6D>-Y$nGlc+@vx5^MPZBx?dLpF`X-_CZRAClGGzmKc%!l~J#@DgZolwfS z_V``Tu7cjU(djo^Dh=~UutXNCLp3J&F7n{tX;=kTiWHzbKB2IJW$dg~Z+HG8}z5LuWLqS3;X!sN?4ztWR_wEsu zKk{Dr<(JDx@K!F%imCZLF5iG&f>0da+F8lCCp0HH=O_|~f_yXD}DCiQm&wD|LW6Zg#tu&dSu-Hrh zQ80viI1;(U?ErW{ZO|LZwy2}{ZUJFDFx%Qx$jo8&=18teRkJYKVnKzjESlqx0WO@I zfvUwF3vpC_@{+&7!h3KCsBSIE-6_ehu>_e;9hqA3=eEs%YG$E9cc3y0k$9Nw4WU)w zeu@g^S5DxU(cfci&Eg5gtDtLBXvogs79JgE zAa0OqP`cHM^Woo7!bs{CHDsh&rSI7QB%n4ebI24-crc4ttiaD^mO_#2S741&#u`jL zUXAXPive0lYb3c_lEhfcHBwujkOpV8Ls?PKSC4nTrEt$eU}s|6BLDQFr8gkXkps}{ zB2PZZnQx?j?7=MuGMRf75VPqc62#;d_K$MYuq;|zf{EnsVkV!)e48g^XC0@5u?=@^ z1_8)7AC3no_{)HTCFrJxpkWdrJ3#WVz2@5M161P<6*mCv;pvEb{a ztM}$p8SAqtg$nhlOr`&}X$hf&Mqe^?95I|Z<0e5b{tF=UjVLOUmmy~}#C;}8_OM;d znw-17ixu(Q(!}Kvq7l?gIJh~i*>ewUag+>x{to6>pvAsaeD?}uhkhAZHUnYW8l3$- zRP*@=XBNFcDngQT0zbui7D>&AwDF71{ACvLu>?k5iU?IJx0@g~z-Hg}n}JB|cLD1^ zF^J@RbQGH_j4+vj7Akf&TCF(D?4OpZZEaBhK3;z<4(f#HH}xg{Wc=;ngg$V^w`KQG z+k--ap~dQ74mL7KE5waqY$bP>J?J1=sEofYixY>r6^2|WaWny2DHwgViWsYwWxK^~ z5CsI1lwi*FAs`)eE>Uhl1z1p3XZCvuQJR8+tc^K43%UTBjmRYgME6#ayrbX_ksJu! zCpxmFl;90H9=vdXwW(fw!vmmMh~V^sVx0eglW(a(SS11}3akhcrIdmJX+nOE==Ano zC|EO~hA3!nq~ueyROS9{ATs;v>$1FXFzOCCb;15F)~!T)Yjo>^Ad@yYio>ZD@uqD4fGXcMb||zM?T6S{GrRHeg^;B$ zA0^BQ?RCoCM{^m;I!0LR4K9H-+!D}2M#;;OZqe6{d|m-F@S(%Kqe&J0*Lv{9nVmRI z$~-)agJeRpCHoo8M6DC*LhV#K<6ebx3k((RF2=Hap78xZV;4(kkir zDXa1{2@>7^Zt5P`O(sga5uP)-Z3;Cs20(5dOel zm9;4XgM^Xbh<@dd@%F{>NW<J=nths$Vy z;OYHG4rh<>dDu$9OT;V)0a!U-eXB3RqD)Z?Hq0j6+WLGp>z90dlYRaf9=^eYV2=EQ z<`~cSnI9Hgd+@HUtNtrI`wKV-)WYg@rI8iFZ3&i={}vTC2|QZ%F);yy+o96<_-6n< zSnJHMGgdf)4rX4Kwn;fM?;~&Hgvtr&t!%KbA=Z&jMOftUKQf9V{s7Ytx23)IHHAR} zr0nUqTSrFYDV9MMfEZ@;kk1t7444#OY#{p4zJz#4yQvCs^Mf7Cq2Vk46*@;z1LH4$ z;NUvuQ}|86Je7{4bmdp*T*h6t7tNY*r`bAlf+`iq`afW0xC3_k5+NQJvM91RT%n~B z7f_ef;hONaD$6zUkRT0-f4at$Bq)4&-1XK<&`#-; z9gDbx#-W#}dl&CAb`6;y z=Av%glK?M*EW@cE_Dj*Cib5icV7LoZ2Vm_*id?l1*)0lO`IQ(JFWKWJCa^Ejw$)?P zV6+*s)j(+he`%!GXO3>R_Q*RLdGjd*eLzd4dlZ&i&yokjvd?TnKsbMd>rk+5o6Gjj@hikdXyR{$tp>(eAKI*l&QEZi-2yvof$ zpl1fNUa^g%qjCXMH5jy3B=AvV;Hxs)#=a{^Gp{L+x+{PZwb)^40)m4KnZdA*q!-84 zh2sXNmLNMT8VYi*QIr#(i66&=SK|N{tz*(O3hfzP(F+3=owmGFvWV#Yp|}NzKBhDm z>J928q;}JN19Hy>zx( zPW$y)u6ubU&n1cJL9I9Kn4&SveQ&CwDue+C(iV+S&3co}s`~oE{K+a3vk$i+TrY89 zCBZ?gM*xh)2METi77;D4@un4dT*T*x98t6wDsOxMw=fBLqmmjWFa~@1VU=|lBNTVH zf}NBbmO&e7WXi|pL9!BqmMVTCRgG`Eq&{z=%d%Hd|5pZZ49R>H+>R-vuI!fs(a@P* z$2@ab0>nqeoGTyBEF)w#jtbF8lM(meLMHKq1`>5(9T9qeFkHZToBT$&z+lNmtYUDi zNH=17AH;dVaHp_0n* z>-;o7V{Li#(Dmf+O{aqPQPE7+H)!jo`*X5~xv<00;r9 z0Bry%+D*)rWD*5AEh(NrW4wI2jf4+lC#=o>VsUKm;m5uUUX03hiT>u9yPlM2w59yK* z5gHh_OeQ0k9uSE_ha?1GSa>Y|!sZX<=FG4O62<1i0$-i%Nn{_Y8S?h6ZC;&lalH@cjRWroG`2f(GV*?LGOhwMHr5a)10$ous=&|4OtjV? z@!IC58O$ImiD`(}DZGe{svx&#fMVbU9=BInN$^7K>6hQi6 zn~YyQ3`R(9%O8jC1b!KZ4&!9)2(bJs0w0XykzO+R;^4eugo=5cl%*C^*p${F57eyYcJRR^_}!4w zLWRuDh4&#MqplJjn2UF@`HvwhW?w^FPsuc)G<+Qz{U}JRcR}iXxOW(Wa*e!KHVnEb zWC@N-#xRjJ?nHh(y4lOh?LKQpr&)X_q1RHDC*oW}MacA+XL*KUamjzl5>z(8z#!n} zo>p195EYYrvMEgnB`;y7%(Xhk^cmAIMNN*~KlZShng~6dS^oV<72`)Sh966c^prX* zVP*CmIC^qrBgkm^9$1p~1BJBW#muZk#vtTG#L+v!FGyS0>}ZKpqFiW;&s~D(bxIEQ zkJ3qxyBB8ZOtwh`^#W-2?%dq*r{BvZ2T$wLr%&RLXMG6Zbp%x*z9aV+u&Q}O<_(6r< z%okMkkWv&scN22V?l@7Nb%ggk*cB!0f60*K)8PIIcK1KTLDuiE`(z;yRK^y8 z5DMKsMEovZdY2O;{;~7+Ro5lFxFw>)koS*Ga#;9>L~vO3CUVovuoVLWxn??>=nZ_^ z9WDTQW^=d!mX|0QwH8f9P%{!j;@JedD)*R)eC8R(1oUUHM15_xo;F){mR;%f@yVk{ z%TJV_-t=Wwq^}=FO=!VWqgud1z7<*lKGck21LLDnA`RB?#^)c8l#ZCASOZ%X|NZa@ z>79UTXev1&)g*taWb{U)WT_F3FBQqJ=*$vsO=k(woctXZT(L_u0Xe$5BlU`0o6V>p&fef zQ=_@%@}QV!-x;90W_E0JHz4Vcpu3T*JyU+X+{ua4rvqHK?stUwNW*v%2KQf}KA1-A4$p&laeVjqLjXxTvw#w}>s(8SK(E>*Mlf0%S_sD(o)w{_4f zkhtV~B>0~$b^Co(`6q{{8->Uy(3f!$rFjVO-Ua~cfe(X?MxUopGE5=kk|JU;I0E@} zY%8jAN*j<5yg{5azU`8$JWx?L<^BJ}nOR_{ADPaCliQYy6~i*P1J=JAp>_QJd`%{M zEcN98PGWC;4|A>MC-L-VJ%rV>&`GJ%G7E$LwMLdg#Cz%4=vb{vdjI0Phq2rXUg0GO1^FlNBG>pd_Lo0RXM zU%Slo0L;Ga6C`09^x#Mc3+w#)ys)1JZT==i$GU9wTPPn2dULYEa%M6nJz>b#Tou7y zw0y%dZ0r9R&=#wjA4ntT)8>Z8V@Vwhm$HbV!dhBc-UkfAP8EATobV2Z*{8!j&hU?5=CPu=?5Wrr;)D603l}8M(+bTwSk6?R(>QI<~*O;hG{;|-f94N{; z-JwB~3xLcGhGYnRrei}O|J80YPgNI|)8DXFkn}r8PaxuJk zCz;Mq*>iFj1>~Nhr-x6lI4RNpV4d(nx|F#|eSo$EXC6Vvr=kq3_d6$`3wV ztB0Ielcza3p)Ww~N78IG@&D_j8eIsZ3#|K>Po`~ef*ixc{0vQNyVgNalcMqpaI$$; zL94nOEl6X2hmImRa6uE|=L_V-f2;rkw@W7r#7NuKY=Kbv%#C@}$LC_VOo#e95&lzC z5B3+)9AoLn;2%azzZd%j5W~ao1kRBiA;^9Z{0_kv^pVt=1?fWHklaqLI`BCAZ-mS>KYVqJ-AaKV5kt-YV)G8AFKqi zX5~AlZ{jRJ!fyQ#6b%ODawUp}WngpdJ#j`R3jAdYGxDF{6DPn>lq@$4s|KC(5!UMr z%t8diF#2&?ZaxcPF>MSDhB(p)N0H_ZV6@P{%7yZju4 zp}2d~$b$d~=YC@kPIxrMcjLfXLx{f<|n|VNCfU2 zLSBK+Azzt@2b{_(%L;9QxYc&mY73SrAByy!qb09nXrTvE_G5fmE}Q~M3hUdj?1tMV z0n2PZaiPCkiZ1{s{p-kl6+^7~;UHtA6B32ilqjkXocw1n6m zpFiTq!B9>xcNNq%Xc)s&Sy=3d*f6T#%p77meLlx=JoCBszSOE^+Kwn5rwhTpvJ%)6 zOfoG;QoCbi2qN-8ftFRPXOsCel~?9ZR+5Fc&n+yStt=$T>14^2Xe_#;epppTP7&!? zjSs}MZJ4b9yXq?>J<=DNvFd9Y;t-x)dS}}7wcPZeyHy|4}*DEAI zm4;rx#+cb0BN+O+mbTWJm6Dw`^@}K&uM-WuJ)gxeh!HS!h-v54?L!3hWk zqHsQR?yE|X3xdf#MMNVR6L^H!hG;-w8;B~9?L!dbB_SwsV93J1%U_4Y7fV1>CelE~ zJDBnUOM5O&iMney1Cn;+#Q13?<3JLOl0&{L)M{Bj>@AUTd!{cUNyqgUm?({jH? z$@dPsui~Yh?t@9+IAqaa<9^A#uQVN?{!3SW$(=_+4e|=KA61R}AXJQw%l;4sU9e$` zbg8m=h@;L(!wsoO4wW*0a1|y@u`v!i0*X;SrWcwYj1-4;DHgg#X!B5H^H;%X)|$-W z4&xLcmQk$2#8?+`C(0OpL42@2k0irYzXIH&M64)^Gh%Hia>SzNp6XF?^4V`q=mhTc zVE5ui?W37j6k%+oYS>}mBN$npq08@pgbDH(u?J_#PvW51C`<=ZKVIx=aj_v3Lp+n+ zbQ|pAVH69L@K1#!If}y!vB08riFmPI#_nq&8b6}$0{HQKMVWSDkZD-okR?-moA?ZV z67Q-8R;5IW$sH)OHPkNfQ^ZvkqQze)a%)Gnse`3`6AvND(*$_xF8mH*Gm`1j9!vJb zpw@`&e}+97h3qDM0r7x!!f4AY2O(@6ni$gMSjw7!(b$b7l84?!4&DHIUBP3;4|j}> z0~Z7KVc9g0vIHDP&D{Uwk8?vqke(%?wP=ao@|+>ACoL^`0sjQlCN%*AFJoT;8D?eR zDI#hF>>|QOmV%6GmXow-8U!d8K14i-mB5nJOOJa-STF(>9k}35s9$?$+oDa@XE>N= zecJ5^{T!|K2W%OTpLHiaJ`t8=)G;S-`s@)jyAdF&SxjY&0 zAk~(T3f#8b^FqaB4`wKNj37k-!!`m9!#g3Gu5teqo;q7cCQj+s3y9}gJb(kca2RV8^Hdt$+5eDH9K-$Jz~q_C~8tD zxFZn5kc7u=3~Rp&Na1k>u=1<%0a-nG5W--bXmx%6thEq`HEHqWR-4 z6$V_`#GUC;kF1Y~pue*)-FdDKy!%4c_84XyXp)p)dN!kdQ#{u8XG9*p$ zNCdDk0-T++*UaN_4G{yVlw!2Ks~X|Kz-Md~9Q|3bCK4wujHxOo3$wgf8Wx=4Ni}9x z;rcb{Hm25IOOLSS5C>3wtPI4dc@eAJn19RQ$>(0AltL-olisY^-%vn9QMR6Az6!4O z$irTf-^8Sd&@eSj@(*yOJu@tv{%%~p3il`%a3+>>C-MC>`(H?UBGVje$adfrpKrxB zyLcKmBur>|mLK>6!Qus`^Gx?}VxW3E0rl*Rcui$f zBYuX!OJT$9oI(f}mXRQ5NgZDwTzhpDH;m82ipuZmaz;@L13a z{U7j3QU^I2spu+t6Wb2M;sUW6mk=I2yT;iaERCFW%ngZch`-Au9YPimfUn&8GJ3H4K}>DZ;AI(S5}QK;ASDfwR%>X& zWgZ#_&wN6vqZkik8G>pkCP{sIVx%S6#yvtM<}!?1)qH`sAW4f`&}fNENX`=;J_v+v_@GT%0sa~{x+hy|jKZ5J(O2x7C3C7}sr&_)Gsf)Ej_@cQ1ZK$ZcK zAZ(>MXdD8_8$$D~2toz4B(CQMr%}>o4*AJ{gHHIpjVO8{9-)Fn?cAZSGAhFWyQ2N8%j;Yc(gcNQvNqWy8j{;OGrqu6F;Fl#h5M;nRkUrGgOH1yjUocq1 z?MHPR@+*o}oV$)CS13P@O<#9=_yxe0u6)*=Kacm{zQ9T(c4bTqdjiyr#)lMQ0%%bo zKvN)Nc7qOrO?+$$^dUccIb9-LdO7l@Gm3pk3}mq)6k$WkU5Y*D5D=2)dQ`!C0;``7 zlAJMPNjt4!8w@{vP^Yj9cI!ql@@|B5;lm!DK|hl}z{79wa1Doo-1&W8;&a2k3i~|y|X|U}Lx*v~riXipvQJ_Fb(TfUU|3ea7kR0)NkvbaL z#ohl7nkOE$$!10ts?5jYS3&29f@5TvIlECkbR#lY18hyZu&+VxSw+s}LZVRCtjEQg zBgKh9G6*Z${I#NFd214+wTu9l?zKE^pLm(p%pE^IL(waV9MQI&fzz?ps3GHe&$~}D zrl&}bk+g71vGA+DmN0{yC=Dc;X3PnwrOCDQ(tsZKV}-~@F|gn? zh{nqxKzhFjs_6$ zbKvf;!ptvsE6PJgVHw-{{Q~tYv-p`#YqgPCK&HWt6@N9q`Ne&H}>nd_FW2qYhw=r#x~_ReM*fa|5DNzqUeu z7qZrGv^&U>RDOT`N1mO1zTW--C!e#E{DqfC|HER^kNq!_*U=p+3sp_|A%@zBLPS7V zv{CZBg0OE>zgP8ohW>2Q$AsxVcYbgp#9E4P7SAmcGHJ(3w~+_I20sgO?o&akhF3n- zkER{gEk$difARQ>n_5vTpI>_IRPLh*tss?&bSo#J=!D7_1e}lTKgFe$4H;Wt9OOg{ zD5mlKFd+R6ZEYG_Ql2mCj(49D`r5Ge%!F!=`Hc{d#fsvaLnqwd66TPjRcwO{|4~}5 zhC1Yj<{ra95A^&aYciaG0HHl@Sr@EP5c9Afqg6GW{(7h-@e=Gs*x661N^_*DzLmZn zpBVWgTSR+So!SPIl?gPh9v_&KOEfn@uiHYr*c!hayLZ*{T5Kj-1fv0`d`4G z)t)kiL@}lh@*S1g65~&f;`QGnmwyCba1TsD7<&|Hil@i+ZNCTEVs?++$19~So`CD3 zPGNvQnkG-+mobc!j2x0Z7$^+Y;Mr!cz)=~Cc}Lv+5G)9asj(~n3gV;e6>#xblFZyL z5Nfral0QS7@V9n2)HJq)_x-k0KaNi1yM@WNXX3H=8iC2u8++q}>~`J;XyqdGlPr2> z0ILPk{B!}Cp0u!@VB+vWm}DLl>24r;hA}T2>#-&UmlcOfj{S%lY2B? zxGltrYK;=94aEujJ>1EMWPS(7k7TKUC-4w1bes5Fddx1rz|Z3XIJg zL)p@RA8{v$9K1jrF?67q3xN|}Zm7Hvdm*$EuJtlBV1PLu+xzJ2_4`=hc-zUfu|*8Z3fr)XGM)MR(Ij0Do?z6VS}c^Fjw5K!ry;a0(KP zo)110`1}{VB#A1xdTY284YiIXzsxcWu1&s=Ltf$S_)HiA)zpX!Y`p0qdxLNzf5{HU zM%-0;m<~TGPGks#8k>cD;_d#5N5PIKLF@JzF` zlV?Y9$TRgzeO1ESWPzAI&BLH;UMz2G({&fVWxBYgOJHb9?mL_@K6c}X5QSA@ALeZ* znBGo$>&@;-K;s;0?tTX+Hg}jNAT@@YQwHl5xD*D{&{vuxE;&m=e=B3u0KA{`skbl% zhluYmtpVR3=7W>(9r8iM^!+244M%NcC9LOb&|vLj(u46XYVjX~u4@gN66t~J96vV2 zM}?0av5!6EKL$`VGn}vKR|zglSAG?Qh5*6=$i9bJ88pn2U<@rE4c-r#@*x2agto|O zWeXG`>Uk%TH_m$gRE4Wn8ybMd1eGP{GBC#Ef_-7-6u6rOsY0)=VT&{@UBOBNn{GRg{oe55X2B$8#A=GK-0vI6*(JB()yO~ZE@Lv zU&Vp#yTjsMZ}E=JEe!BYMk{}nO1;^}^6@HCOtR(NoLC6g)+&kL;#1)#38>-XXNZPZ zacN;S&3eM3nr(M%l^8)x=Rg(saxNTmLv8vdl1JHW}t>k zwbw(+V6NFNc#R7yV1_iI2sGYnA{0QNl%l%{NYeEY*N2M1&GQg+fF}TXGopfp7a@0G zW&J2L9c}t9>Vwb6HbNhqAIM4Yygrpfb76G@&+P0Rrw|+wN3iwoKX+HL6`T?Y%q$2gU+DTW1vJJINGDWu<$UL7<`o zQYtXk;+r5PYH$b8c}wg$c^q$kn}k3v$lXNxNsxkvz=jcM3buR@qSR(G@QY{%IiE## zK12-zlmL8;SPC2jN2LK;e3lGT24WyOF%)KAWs?Pe1&%^o2OVHV;MX7W+}it} zU~sIeKrxJKg9eamg9d=`;D7U|Z+BPzHH3m=dq$u;+9WPbH#$DEByyUK3D@Q4H0Ul6 z`@m^#pPL5nL-0nALeyNAkC;SN);M`Cwj*wkO$x%G_Pq-Gih+x2pEkecPpx&Wb|dGq zp7DW&2Q?GuVd`f=ea6yNa!$seK;uRQDPqg z8IrJI4LhvBum!@C6ZWH$WktCJ3aFlI+C`c)V56GXE-37E6#+1C4*RXC(a3`N%IGCf z+PZD295`07*}ztxYPb+c!zl6|9CWbjg!V5*ClpZjO};BEjf&6K8MhopjV^K^)|7c60NS4-3Ns?YL2KR*1ZK)%Ltr8A zIG#|9Jb_=fjKfDDFT~-9bimn@@9ibt0@n<~N>`o)er*>M--KWMPWIRMG4mCMi0y)* zJ6JF%!xaFLj8Hq7(jwWBRoz zRBse$nKStiCdtky<8KX4s9qG>^#cM2DU#bQ^yevIQs_?tXFx$@=7!vane5k4AUEa) zzVi(~cgP)-7!x^Rxs9MV`Gh>fyVaOwo%CN`7}^WrXo!OF5S)kuVMdih2caR}z7WCb`!0`;pion}Cs}*(*J~^@MLKdd8=(zX6n(zxiu0vf3$tg5) ze3u~^qedx?sYOp=eDF$GB1yt4t=i%!fF>;_CE`aBn}tN&paM$pREWlC0Ew{yr4QZW zCj)^NlcpPG7>gjc`ixaK8=TlmB9u~2ZO&PRfWgg(cZ)F$xXHh8G}1h}`TdyQY83hw zg_dWFO*Ek;+gM-kBAl3DguwdaA{IG#ilCTJatLyZRbfKtL?{HOaI}2*a^5JfG`}eqv8X%ucf`qUr#qyl{;;A!N`_OtSRiPoXO#xr!5FO))Vw)rE*&L4gkXdFS%xg zeQle+kAIpFZ4aw3RAp`R6IYRGH0}9?GBmU#Z(~T4GdRdQiEUVePeu;WdaH}g6J(1g z=SZIC;f3&?+?>A7txfj@b1F7eHX&y75;0_zZ3p*oe}=)XaClLQZlcAl@*5Dp5{Z_%g4furEp?7*;$ zhRTX<;i%;A5G)F8ITyEz^g8!xf&6o#i$SF1THa05GEA|#N(90RBm-icsc;t;ouVSI%!b5&D8YuoW$5E*f(p+a1{x`M zuAzLz{?jO5Y?3u5r2nKP4CVy_5VMtHJF>ZIXj66^?L4mXS#jaYZ7>*L6r8Td^ph6a zL6*dCa1EoUjRJDXYa19x$ORu6Vw7)W?xT2YP+^SK64gSi9!77}zkCf%&>H|fYN&=b zG&T<1qItwbZK=XCRi@eGpCA<`2a)@Wo;vhR7HIWK*Sknzfhsj`-Yj|*2k~jDw zV@0+8K`RQjMwoY^c>x>$8Hus1_=mXfHKTjSVYZvb+5M$EvHj3wzJh?=I)Pty9ESnM z%mprp8I^w=)X_WBx$s2Pc}ez+#hisDFSDA@;UL4*EDYn=>KkG{oYzQG1!)}Q@fhXH zvK5HS=^1l`teCY%QpMX%Y9_YS;tM!awaFKG_6(YlJDZp&ww@AN>D7K zo8}VWaoi0*4GGr>v9sb=kWF&M=s`SLT7z^~hg?muzz0c&8K};hnDq{3Heb(_C~D#Y z@8Nwr+>V=@a~xR8<7~dvxv@Gbbo{aLYB<*rdZvfw8~4Me_JU6${uWOa**#T>Wd(se4dAwc=!?y!be-O*T2zc(eScm zW6%7)_4GL>PxJ7H_!f;MS&B%Meg&C(EF>GboM9-0;?}*~#D=MGBP36;EWe7?DaaoP z@>|J#u~ze9+Q-H+LVCb_HpDk`AMDOI^x5voQ&ju z;o)!c@DLC5JtTD=eu9VZ;GjN;C&UyN32{RZlKf$w{Sh91j)y{V9{xHH|1}SPmj}8xlE2Txf6oI6O2Q>b$%j1r?>y9a_{Ti_6CQq> zhyRO*-{s+-^YD8-5G#`3=UItoV?2!Wu#Jc9JWTMggNL0w?BYS0L>N+Ube-$Qwcat| z8nQ&BpKE#&uB8ywHzsg`m#^~h8V~fR%9oP7#j`~oPV+!^lAPm#f&yLL}b zPdn+f%$#%# z8Y zl0!V)%ft70kb~oXo;|<=IiQHECwQ4rkN=L(%6!Ha`wX2NqsMqS!UKWdh(C;dSU9fuB#X>_g3pif@W*%{4K^Y{_~(0t!)>6CI`fh-o-c_0 rv*rne+;TmX{)3?KNa>OBS^T{V|J{!(-oJlrX6%vi$??gF$vgiaoa}F3 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..54c663865923d7881c4a5c9571b1a2d7138faa4f GIT binary patch literal 21196 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 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..e6e0fd9000c088a4f8d8bd06d2988d7381dab02e GIT binary patch literal 7266 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' % 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 0000000000000000000000000000000000000000..25a21f634878479a044be645aa11e18e8cd9efd5 GIT binary patch literal 13832 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 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..c5a576d43398e5efe20d3f85430e57585f7d3484 GIT binary patch literal 1121 zcmbVLQESvd5Z>I?ww?%z=$kMv#R!tK`k)*lYVAWo`fz6v^kHu=nOwG)WW(;{YM}L{ z{tthof56#Ik5=%>Kqfoco%z0R@@4q@?kN3raFU9vE8^!nzTIOEnGjz&M&c(gB7u>( z6e9W-iEJQd@z5W;7zi-}zVcGJRf69sWIs07D5O)&w8fM_SBl=7FhTTDj6?n2hflw2T!M_6<+?`kWH_wUk_9d>RV+8iP!3L8CPX~eM(H|lOaDCs z30$M?7AEUJ*K1R*F}nhqq^9YtUKTWgIDHB)p6~C&qJ#Ig(lty?tXemS$i3|4ZIlmf; zY)dQ$f(GJpATAvs8V@VeY{?#?Fh zBi?iImap64z|=w9?NIu39FU&_p+QcnHRYqbA| W+~q!R`k(jh16~Kz?cwe1o#+pIsXNC2 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..299667583c6a9beb8a66a8d2b56942643eb4c384 GIT binary patch literal 4404 zcmbtY-EJJW73S=pq?Pm-(bJ);l>gR^lC9 zy4;j*N6Ifpxswxd-zkC(VPu2<}( zrkdOQWaRf`FMTL~_VJ@fwDQ+>l9w_zrAkNI?(i{tMV3XMhr zAs^5pT_VbgBP30OJ1t5elC&v}sDor#6Ud@(kZP-S79Byd!n0kGt#W5w#Qk2Ej`$av z;H6p%Y3r;(oEK?BAor9iZaS#51u-`Osg;FE6{P}9ro;>x^=bkUL|)Arg19NNtLz~F z@WN3@xKhusKSwO#xkWZr+Ehr`I;j*oHmehbR7i<{=pjEo!Q+03<{}aoLL}%kxPu`( zbc>`AHN+|W8i|)oPb`Id1(=7nI`9<3oe<78y8bqr;EN<3834nvXl7MaX`6&8-@&TN z>S2EF>8;dEOYd(jg-JT~W;o;{d<$Zyi(yO$#x&~T361*zy2BIAe-cOYEF@+8U2+$YJ8(03#d(Hj14MJYLE@vwtp2;hfPeBqajTpqJD>!Z2t{F-{UToL$f( z6=RxX-!a^J7~RYx6p19!FOuW|dbL09NB5(9uki;3H~0fa0}&ewTL=X)&0Z-NQ#ik? zUL`F52>Up)SwtzFLtR1vN9a>@PT&cS(9^H)i%Z5c)EhU2?UL93*bpz!!MaFng@ru^ zFl~0g3VVW$b8n1HI1O8L>1EsXN>n;SzMmzU1tZu^){s;!|@>7gN8^A!g@B;^%uZ_56du*BICa6#a}MNklQIDgn22ycdwb=od3vl^K{$Iwv(!~!Jb zHUbhG@hV$0b#Z}xJ0v;X5HFh|dhuA`TSnsd!2&GbZe6Zk+3*?I5NeHAgzZEit$G>u zzAd&fak0w#l<>l;=pRB+TuV@56T1JIb*Z^CrntL%Xb#Mx+Mg?T3nTSp)XQ6nY?NC0Tm`446twN>6!S|>t>9&;v)aSUf zmDQz3@$U?%gsajS1WVOs)}TaDB9NDT73=o?5 zrx?W_&>~87;{rL5+tdKRZ2X8bf0(2OzY=J()Fi{a(0qH*p-xxz&xEQ#67g@|z&jse zmP5-o^a;NmV9cd4Yqi{p^+Y|IIB#L}&C&1>r)tvc`)EXC1N_lybX#cKZ%6NeV-9-k zHE#G+GB!yvlcJDg)}&e~W{!V@dIb1*iyG33;TF>=S2}X<|15W7s&L-M!zv7-@+2?7(Y0J_-C;1vI1!25kSl{g}wg%JIUZVj$D LJMiE}bhr6GLB9q4 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..03966ea2d74fee5fc09f824a771eb00f08d6fd6c GIT binary patch literal 1569 zcmb_c&2AGh5T4C{(qE8Tal=9gg&!r93n)SeXnR1aBIKx-Tvi*elWgN%FSbJ)R5(!H zgDdaEWAFel<0Q02aHyywPi8-l$1~rIUHq}u5MOr>1uRAh|6k&?-%!K=eUt&j1yBK` z1?U$bpzk86BBUkgmmn=ezl>-JzMy#p;<8t&5LdiX16hJIT&gdX2FNnV8k_~tU-5bY zByOz2S;2#=7eF+dgKJ9=J=d4uI>Zg=HCHI&?~6_R6G5#<=!ICpW{ z9TX1WD1eUvoMJfvCN(g3!4;|6SeMTMWN1^O)l(q0d;X-Zy@Pv?wV5Q@i0P@bNi3Nj zG9%wjrFBa(nq@lTCW>&e5(;+`S|1+8;dGAP0lGSqZWR?i&0LboePguo363yv=gd4o zGR>k?a#ET&=fXZft?kmBX78CjJbc<#$)KIj+*oIA-w5qRBeW3o0V%B~)12Z8=heP} zPHc^w2K8Vy*a)tdv3uzFFN{Tbj^&SBqO;4at)qR2tLKdQtT|E2DYS5X==d@x2*9$Fd>1`LV9`ZDP4cfU!lk3q@BXhK}3~rJ5+0N4XwZ~y=R literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..2a01ea8965ac850dd215244d873cb6970a5bd321 GIT binary patch literal 30673 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 literal 0 HcmV?d00001 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('{{ "K#v6QsTs@cmc29H%2S91!w^pnNr}BF zvZ2E%wHQu>fULX3#2)9-q|z)B=cj=T!0#hh&sIw}aZsvb)am$XAj>*FRVEzI*9l*5o3>M_VGC@c(dPFOAe*hr^2 zKy8kZKq<0-Sl3>zBmQpk5P|m6wBQwQAif{wyJNfm0AN{7)*<3%Awihz7KAU%u0?q*O_dnaAMo})ChJV9kkfHJCfO>rZw3Bq+*txU zdj`>iGoU}!qC_hY$h5E`Pg_wc~6H6=(Zb z4Csvt5jeZIoQBcsi5S@gp|RkRumBh=;-cK@Tk( zlQ_8zHCxaJCcyZ#iv+-qK(Xwem#m^Y;{>ZLt*e|^j;8^oq}fE1_{LyoDCs3wenYaF za6Bl($u$k)YkC0Eq+`hRSt|4LJ}_l=;FcMqa|G!*^QUX)0)2%WY4KaPN$Yz zJ8IGmLw;6C4M}BuoKDI{(ARGFQm142aOVxvmKl4gOH$qKzG1rEQl?yEGnC{)=nIF# zdQGfWuJ_lkU-z+V1ycAuHr~1P5A3(r zeUP19doSS1G7al-4PDn05(>ECRKtX@9*%ASOGm6EIQoisJGeTDZ4sMDgo~RB_=gIy zc~nNXHmyUKpyVnWqi=QA=azJggP@9PJS2YPM!_z)7w~295tAE8YCrVME{M^nf5PQ< z6PDo97rclbnEZvy>IR>#pajSPi>H+lD<{@TK;wO&wI5Sn#@`tt20oin<^u(c7-QKj z!^Mad@f!hbtAu;F!C3`Fh@mR^2FUR6yp%6+!A1ye4<{24Hol*}t!A;Uxxc9Lzf|7i zS><5`-#e)Q=J!rXeE&D<*Ghf$86vdwevV2ROfM7YqW)k+-PY{~BLCYnnFB1!kN_n8I+MwGf(Ni@cC3wmNr$`w#9( z{lJdJXTq0H{Um1ia{-^BmJSHVQBId!4EE+O} z7}>Obuwh~E10Jw^f!U*&jXR&pJXFDz3NjePY}c>M+O`kC@P5BCpn z(I)IJ;-)=L#Eyx_$n_8*M48BMwK%(jkC|Yz-@2_{ih~DHU*3h;!Z8Q@c4DUBPTAS> zDRMQJw{_5)-l#xf`?f&Z8`hwigyt#s^PtgbklbHEq0`)BVyF_1L9Ha=+nl9 zBnd^Sd-Hru8 zo6ExF4-!&-p*)Nm+x;rE4}#*>bH{|xBS3;=h(j+}A$8sZQkFw@*qw?En6rmzUf(9jHoVwle%GP0?DcA&8{f~cyghi#n3Iv*U;u553jL4sg* z84*8Xr3d{a>XV#?4-xogcwD*#aMraVL8rO4L*dent+3m!=*`n?1qyQfMOvRe>V*-; zF8P?-d~6%r7p0-J+sUS@i`LgcABz@v+ZA87*MD)vC*Z@j z`jnL03)85$Z8{#pq}fM< z6UHevk}I}3B^tvTzH3!BGu>ooOOqN0_NK;<=(h~ZvTo616)~{3SnGz(z=f??w!kKWky623REwQ+2wKH)O2ePDIXDHWaFpv_@<{r~v(D%p)#A<@ zb5g`Hc+ZZ8G20I;7_S2bP_>QZl;c&J{e*Q%$0}vJC<`p)J{>AN1EQ~t?(}h7*>7P& zq}kLT| zv9ETyQ^bu4ox7k18Kw>Dtd*KriwJjkk&JBMGDH@DYXE9bKR+pFgr5v`2;Q=8O|sT5 zgo?R=6@>BhzFK&H0WAlB6)Na4*=5p4Qlp;dihF!W3^tE?6pr!mH=?W!T$Ed6=1HGJ zU%;s)FGvB}g`}JZOa-F7pS}s8Ix9f+j|fyPk~JSPCSfTH-eP0|z!%_^R7Xn{*lwtH zvjo)=j&9nxKBbl8gzyDcY6kQrEOfivDis}A#`7i~9;E@NScc0c&#a+~`0`_Fh}NNi zPkrFi1(4K5FrFthb%>WJx!4HeMCYj_hzHDUc^;lg7>x2?r{sLQ!T%8Q9`yq~pOYec zlyFA#BL3;mrF{kidd3c{DB@8)A|kBCwK0`TiGl-x59Bow4h zvpb8(G_N#gn%+`#VX^f)Y(TayvwYXtPt!)y#L>;Asoxdsxn7)Y ZVvZ~|aO|$xoWJ0`*;xI()y>td{{h=NE$aXP literal 0 HcmV?d00001 diff --git a/lib/jinja2/compiler.py b/lib/jinja2/compiler.py new file mode 100644 index 0000000..75a60b8 --- /dev/null +++ b/lib/jinja2/compiler.py @@ -0,0 +1,1640 @@ +# -*- coding: utf-8 -*- +""" + jinja2.compiler + ~~~~~~~~~~~~~~~ + + Compiles nodes into python code. + + :copyright: (c) 2010 by the Jinja Team. + :license: BSD, see LICENSE for more details. +""" +from itertools import chain +from copy import deepcopy +from keyword import iskeyword as is_python_keyword +from jinja2 import nodes +from jinja2.nodes import EvalContext +from jinja2.visitor import NodeVisitor +from jinja2.exceptions import TemplateAssertionError +from jinja2.utils import Markup, concat, escape +from jinja2._compat import range_type, next, text_type, string_types, \ + iteritems, NativeStringIO, imap + + +operators = { + 'eq': '==', + 'ne': '!=', + 'gt': '>', + 'gteq': '>=', + 'lt': '<', + 'lteq': '<=', + 'in': 'in', + 'notin': 'not in' +} + +# what method to iterate over items do we want to use for dict iteration +# in generated code? on 2.x let's go with iteritems, on 3.x with items +if hasattr(dict, 'iteritems'): + dict_item_iter = 'iteritems' +else: + dict_item_iter = 'items' + + +# does if 0: dummy(x) get us x into the scope? +def unoptimize_before_dead_code(): + x = 42 + def f(): + if 0: dummy(x) + return f + +# The getattr is necessary for pypy which does not set this attribute if +# no closure is on the function +unoptimize_before_dead_code = bool( + getattr(unoptimize_before_dead_code(), '__closure__', None)) + + +def generate(node, environment, name, filename, stream=None, + defer_init=False): + """Generate the python source for a node tree.""" + if not isinstance(node, nodes.Template): + raise TypeError('Can\'t compile non template nodes') + generator = CodeGenerator(environment, name, filename, stream, defer_init) + generator.visit(node) + if stream is None: + return generator.stream.getvalue() + + +def has_safe_repr(value): + """Does the node have a safe representation?""" + if value is None or value is NotImplemented or value is Ellipsis: + return True + if isinstance(value, (bool, int, float, complex, range_type, + Markup) + string_types): + return True + if isinstance(value, (tuple, list, set, frozenset)): + for item in value: + if not has_safe_repr(item): + return False + return True + elif isinstance(value, dict): + for key, value in iteritems(value): + if not has_safe_repr(key): + return False + if not has_safe_repr(value): + return False + return True + return False + + +def find_undeclared(nodes, names): + """Check if the names passed are accessed undeclared. The return value + is a set of all the undeclared names from the sequence of names found. + """ + visitor = UndeclaredNameVisitor(names) + try: + for node in nodes: + visitor.visit(node) + except VisitorExit: + pass + return visitor.undeclared + + +class Identifiers(object): + """Tracks the status of identifiers in frames.""" + + def __init__(self): + # variables that are known to be declared (probably from outer + # frames or because they are special for the frame) + self.declared = set() + + # undeclared variables from outer scopes + self.outer_undeclared = set() + + # names that are accessed without being explicitly declared by + # this one or any of the outer scopes. Names can appear both in + # declared and undeclared. + self.undeclared = set() + + # names that are declared locally + self.declared_locally = set() + + # names that are declared by parameters + self.declared_parameter = set() + + def add_special(self, name): + """Register a special name like `loop`.""" + self.undeclared.discard(name) + self.declared.add(name) + + def is_declared(self, name): + """Check if a name is declared in this or an outer scope.""" + if name in self.declared_locally or name in self.declared_parameter: + return True + return name in self.declared + + def copy(self): + return deepcopy(self) + + +class Frame(object): + """Holds compile time information for us.""" + + def __init__(self, eval_ctx, parent=None): + self.eval_ctx = eval_ctx + self.identifiers = Identifiers() + + # a toplevel frame is the root + soft frames such as if conditions. + self.toplevel = False + + # the root frame is basically just the outermost frame, so no if + # conditions. This information is used to optimize inheritance + # situations. + self.rootlevel = False + + # in some dynamic inheritance situations the compiler needs to add + # write tests around output statements. + self.require_output_check = parent and parent.require_output_check + + # inside some tags we are using a buffer rather than yield statements. + # this for example affects {% filter %} or {% macro %}. If a frame + # is buffered this variable points to the name of the list used as + # buffer. + self.buffer = None + + # the name of the block we're in, otherwise None. + self.block = parent and parent.block or None + + # a set of actually assigned names + self.assigned_names = set() + + # the parent of this frame + self.parent = parent + + if parent is not None: + self.identifiers.declared.update( + parent.identifiers.declared | + parent.identifiers.declared_parameter | + parent.assigned_names + ) + self.identifiers.outer_undeclared.update( + parent.identifiers.undeclared - + self.identifiers.declared + ) + self.buffer = parent.buffer + + def copy(self): + """Create a copy of the current one.""" + rv = object.__new__(self.__class__) + rv.__dict__.update(self.__dict__) + rv.identifiers = object.__new__(self.identifiers.__class__) + rv.identifiers.__dict__.update(self.identifiers.__dict__) + return rv + + def inspect(self, nodes): + """Walk the node and check for identifiers. If the scope is hard (eg: + enforce on a python level) overrides from outer scopes are tracked + differently. + """ + visitor = FrameIdentifierVisitor(self.identifiers) + for node in nodes: + visitor.visit(node) + + def find_shadowed(self, extra=()): + """Find all the shadowed names. extra is an iterable of variables + that may be defined with `add_special` which may occour scoped. + """ + i = self.identifiers + return (i.declared | i.outer_undeclared) & \ + (i.declared_locally | i.declared_parameter) | \ + set(x for x in extra if i.is_declared(x)) + + def inner(self): + """Return an inner frame.""" + return Frame(self.eval_ctx, self) + + def soft(self): + """Return a soft frame. A soft frame may not be modified as + standalone thing as it shares the resources with the frame it + was created of, but it's not a rootlevel frame any longer. + """ + rv = self.copy() + rv.rootlevel = False + return rv + + __copy__ = copy + + +class VisitorExit(RuntimeError): + """Exception used by the `UndeclaredNameVisitor` to signal a stop.""" + + +class DependencyFinderVisitor(NodeVisitor): + """A visitor that collects filter and test calls.""" + + def __init__(self): + self.filters = set() + self.tests = set() + + def visit_Filter(self, node): + self.generic_visit(node) + self.filters.add(node.name) + + def visit_Test(self, node): + self.generic_visit(node) + self.tests.add(node.name) + + def visit_Block(self, node): + """Stop visiting at blocks.""" + + +class UndeclaredNameVisitor(NodeVisitor): + """A visitor that checks if a name is accessed without being + declared. This is different from the frame visitor as it will + not stop at closure frames. + """ + + def __init__(self, names): + self.names = set(names) + self.undeclared = set() + + def visit_Name(self, node): + if node.ctx == 'load' and node.name in self.names: + self.undeclared.add(node.name) + if self.undeclared == self.names: + raise VisitorExit() + else: + self.names.discard(node.name) + + def visit_Block(self, node): + """Stop visiting a blocks.""" + + +class FrameIdentifierVisitor(NodeVisitor): + """A visitor for `Frame.inspect`.""" + + def __init__(self, identifiers): + self.identifiers = identifiers + + def visit_Name(self, node): + """All assignments to names go through this function.""" + if node.ctx == 'store': + self.identifiers.declared_locally.add(node.name) + elif node.ctx == 'param': + self.identifiers.declared_parameter.add(node.name) + elif node.ctx == 'load' and not \ + self.identifiers.is_declared(node.name): + self.identifiers.undeclared.add(node.name) + + def visit_If(self, node): + self.visit(node.test) + real_identifiers = self.identifiers + + old_names = real_identifiers.declared_locally | \ + real_identifiers.declared_parameter + + def inner_visit(nodes): + if not nodes: + return set() + self.identifiers = real_identifiers.copy() + for subnode in nodes: + self.visit(subnode) + rv = self.identifiers.declared_locally - old_names + # we have to remember the undeclared variables of this branch + # because we will have to pull them. + real_identifiers.undeclared.update(self.identifiers.undeclared) + self.identifiers = real_identifiers + return rv + + body = inner_visit(node.body) + else_ = inner_visit(node.else_ or ()) + + # the differences between the two branches are also pulled as + # undeclared variables + real_identifiers.undeclared.update(body.symmetric_difference(else_) - + real_identifiers.declared) + + # remember those that are declared. + real_identifiers.declared_locally.update(body | else_) + + def visit_Macro(self, node): + self.identifiers.declared_locally.add(node.name) + + def visit_Import(self, node): + self.generic_visit(node) + self.identifiers.declared_locally.add(node.target) + + def visit_FromImport(self, node): + self.generic_visit(node) + for name in node.names: + if isinstance(name, tuple): + self.identifiers.declared_locally.add(name[1]) + else: + self.identifiers.declared_locally.add(name) + + def visit_Assign(self, node): + """Visit assignments in the correct order.""" + self.visit(node.node) + self.visit(node.target) + + def visit_For(self, node): + """Visiting stops at for blocks. However the block sequence + is visited as part of the outer scope. + """ + self.visit(node.iter) + + def visit_CallBlock(self, node): + self.visit(node.call) + + def visit_FilterBlock(self, node): + self.visit(node.filter) + + def visit_Scope(self, node): + """Stop visiting at scopes.""" + + def visit_Block(self, node): + """Stop visiting at blocks.""" + + +class CompilerExit(Exception): + """Raised if the compiler encountered a situation where it just + doesn't make sense to further process the code. Any block that + raises such an exception is not further processed. + """ + + +class CodeGenerator(NodeVisitor): + + def __init__(self, environment, name, filename, stream=None, + defer_init=False): + if stream is None: + stream = NativeStringIO() + self.environment = environment + self.name = name + self.filename = filename + self.stream = stream + self.created_block_context = False + self.defer_init = defer_init + + # aliases for imports + self.import_aliases = {} + + # a registry for all blocks. Because blocks are moved out + # into the global python scope they are registered here + self.blocks = {} + + # the number of extends statements so far + self.extends_so_far = 0 + + # some templates have a rootlevel extends. In this case we + # can safely assume that we're a child template and do some + # more optimizations. + self.has_known_extends = False + + # the current line number + self.code_lineno = 1 + + # registry of all filters and tests (global, not block local) + self.tests = {} + self.filters = {} + + # the debug information + self.debug_info = [] + self._write_debug_info = None + + # the number of new lines before the next write() + self._new_lines = 0 + + # the line number of the last written statement + self._last_line = 0 + + # true if nothing was written so far. + self._first_write = True + + # used by the `temporary_identifier` method to get new + # unique, temporary identifier + self._last_identifier = 0 + + # the current indentation + self._indentation = 0 + + # -- Various compilation helpers + + def fail(self, msg, lineno): + """Fail with a :exc:`TemplateAssertionError`.""" + raise TemplateAssertionError(msg, lineno, self.name, self.filename) + + def temporary_identifier(self): + """Get a new unique identifier.""" + self._last_identifier += 1 + return 't_%d' % self._last_identifier + + def buffer(self, frame): + """Enable buffering for the frame from that point onwards.""" + frame.buffer = self.temporary_identifier() + self.writeline('%s = []' % frame.buffer) + + def return_buffer_contents(self, frame): + """Return the buffer contents of the frame.""" + if frame.eval_ctx.volatile: + self.writeline('if context.eval_ctx.autoescape:') + self.indent() + self.writeline('return Markup(concat(%s))' % frame.buffer) + self.outdent() + self.writeline('else:') + self.indent() + self.writeline('return concat(%s)' % frame.buffer) + self.outdent() + elif frame.eval_ctx.autoescape: + self.writeline('return Markup(concat(%s))' % frame.buffer) + else: + self.writeline('return concat(%s)' % frame.buffer) + + def indent(self): + """Indent by one.""" + self._indentation += 1 + + def outdent(self, step=1): + """Outdent by step.""" + self._indentation -= step + + def start_write(self, frame, node=None): + """Yield or write into the frame buffer.""" + if frame.buffer is None: + self.writeline('yield ', node) + else: + self.writeline('%s.append(' % frame.buffer, node) + + def end_write(self, frame): + """End the writing process started by `start_write`.""" + if frame.buffer is not None: + self.write(')') + + def simple_write(self, s, frame, node=None): + """Simple shortcut for start_write + write + end_write.""" + self.start_write(frame, node) + self.write(s) + self.end_write(frame) + + def blockvisit(self, nodes, frame): + """Visit a list of nodes as block in a frame. If the current frame + is no buffer a dummy ``if 0: yield None`` is written automatically + unless the force_generator parameter is set to False. + """ + if frame.buffer is None: + self.writeline('if 0: yield None') + else: + self.writeline('pass') + try: + for node in nodes: + self.visit(node, frame) + except CompilerExit: + pass + + def write(self, x): + """Write a string into the output stream.""" + if self._new_lines: + if not self._first_write: + self.stream.write('\n' * self._new_lines) + self.code_lineno += self._new_lines + if self._write_debug_info is not None: + self.debug_info.append((self._write_debug_info, + self.code_lineno)) + self._write_debug_info = None + self._first_write = False + self.stream.write(' ' * self._indentation) + self._new_lines = 0 + self.stream.write(x) + + def writeline(self, x, node=None, extra=0): + """Combination of newline and write.""" + self.newline(node, extra) + self.write(x) + + def newline(self, node=None, extra=0): + """Add one or more newlines before the next write.""" + self._new_lines = max(self._new_lines, 1 + extra) + if node is not None and node.lineno != self._last_line: + self._write_debug_info = node.lineno + self._last_line = node.lineno + + def signature(self, node, frame, extra_kwargs=None): + """Writes a function call to the stream for the current node. + A leading comma is added automatically. The extra keyword + arguments may not include python keywords otherwise a syntax + error could occour. The extra keyword arguments should be given + as python dict. + """ + # if any of the given keyword arguments is a python keyword + # we have to make sure that no invalid call is created. + kwarg_workaround = False + for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()): + if is_python_keyword(kwarg): + kwarg_workaround = True + break + + for arg in node.args: + self.write(', ') + self.visit(arg, frame) + + if not kwarg_workaround: + for kwarg in node.kwargs: + self.write(', ') + self.visit(kwarg, frame) + if extra_kwargs is not None: + for key, value in iteritems(extra_kwargs): + self.write(', %s=%s' % (key, value)) + if node.dyn_args: + self.write(', *') + self.visit(node.dyn_args, frame) + + if kwarg_workaround: + if node.dyn_kwargs is not None: + self.write(', **dict({') + else: + self.write(', **{') + for kwarg in node.kwargs: + self.write('%r: ' % kwarg.key) + self.visit(kwarg.value, frame) + self.write(', ') + if extra_kwargs is not None: + for key, value in iteritems(extra_kwargs): + self.write('%r: %s, ' % (key, value)) + if node.dyn_kwargs is not None: + self.write('}, **') + self.visit(node.dyn_kwargs, frame) + self.write(')') + else: + self.write('}') + + elif node.dyn_kwargs is not None: + self.write(', **') + self.visit(node.dyn_kwargs, frame) + + def pull_locals(self, frame): + """Pull all the references identifiers into the local scope.""" + for name in frame.identifiers.undeclared: + self.writeline('l_%s = context.resolve(%r)' % (name, name)) + + def pull_dependencies(self, nodes): + """Pull all the dependencies.""" + visitor = DependencyFinderVisitor() + for node in nodes: + visitor.visit(node) + for dependency in 'filters', 'tests': + mapping = getattr(self, dependency) + for name in getattr(visitor, dependency): + if name not in mapping: + mapping[name] = self.temporary_identifier() + self.writeline('%s = environment.%s[%r]' % + (mapping[name], dependency, name)) + + def unoptimize_scope(self, frame): + """Disable Python optimizations for the frame.""" + # XXX: this is not that nice but it has no real overhead. It + # mainly works because python finds the locals before dead code + # is removed. If that breaks we have to add a dummy function + # that just accepts the arguments and does nothing. + if frame.identifiers.declared: + self.writeline('%sdummy(%s)' % ( + unoptimize_before_dead_code and 'if 0: ' or '', + ', '.join('l_' + name for name in frame.identifiers.declared) + )) + + def push_scope(self, frame, extra_vars=()): + """This function returns all the shadowed variables in a dict + in the form name: alias and will write the required assignments + into the current scope. No indentation takes place. + + This also predefines locally declared variables from the loop + body because under some circumstances it may be the case that + + `extra_vars` is passed to `Frame.find_shadowed`. + """ + aliases = {} + for name in frame.find_shadowed(extra_vars): + aliases[name] = ident = self.temporary_identifier() + self.writeline('%s = l_%s' % (ident, name)) + to_declare = set() + for name in frame.identifiers.declared_locally: + if name not in aliases: + to_declare.add('l_' + name) + if to_declare: + self.writeline(' = '.join(to_declare) + ' = missing') + return aliases + + def pop_scope(self, aliases, frame): + """Restore all aliases and delete unused variables.""" + for name, alias in iteritems(aliases): + self.writeline('l_%s = %s' % (name, alias)) + to_delete = set() + for name in frame.identifiers.declared_locally: + if name not in aliases: + to_delete.add('l_' + name) + if to_delete: + # we cannot use the del statement here because enclosed + # scopes can trigger a SyntaxError: + # a = 42; b = lambda: a; del a + self.writeline(' = '.join(to_delete) + ' = missing') + + def function_scoping(self, node, frame, children=None, + find_special=True): + """In Jinja a few statements require the help of anonymous + functions. Those are currently macros and call blocks and in + the future also recursive loops. As there is currently + technical limitation that doesn't allow reading and writing a + variable in a scope where the initial value is coming from an + outer scope, this function tries to fall back with a common + error message. Additionally the frame passed is modified so + that the argumetns are collected and callers are looked up. + + This will return the modified frame. + """ + # we have to iterate twice over it, make sure that works + if children is None: + children = node.iter_child_nodes() + children = list(children) + func_frame = frame.inner() + func_frame.inspect(children) + + # variables that are undeclared (accessed before declaration) and + # declared locally *and* part of an outside scope raise a template + # assertion error. Reason: we can't generate reasonable code from + # it without aliasing all the variables. + # this could be fixed in Python 3 where we have the nonlocal + # keyword or if we switch to bytecode generation + overridden_closure_vars = ( + func_frame.identifiers.undeclared & + func_frame.identifiers.declared & + (func_frame.identifiers.declared_locally | + func_frame.identifiers.declared_parameter) + ) + if overridden_closure_vars: + self.fail('It\'s not possible to set and access variables ' + 'derived from an outer scope! (affects: %s)' % + ', '.join(sorted(overridden_closure_vars)), node.lineno) + + # remove variables from a closure from the frame's undeclared + # identifiers. + func_frame.identifiers.undeclared -= ( + func_frame.identifiers.undeclared & + func_frame.identifiers.declared + ) + + # no special variables for this scope, abort early + if not find_special: + return func_frame + + func_frame.accesses_kwargs = False + func_frame.accesses_varargs = False + func_frame.accesses_caller = False + func_frame.arguments = args = ['l_' + x.name for x in node.args] + + undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs')) + + if 'caller' in undeclared: + func_frame.accesses_caller = True + func_frame.identifiers.add_special('caller') + args.append('l_caller') + if 'kwargs' in undeclared: + func_frame.accesses_kwargs = True + func_frame.identifiers.add_special('kwargs') + args.append('l_kwargs') + if 'varargs' in undeclared: + func_frame.accesses_varargs = True + func_frame.identifiers.add_special('varargs') + args.append('l_varargs') + return func_frame + + def macro_body(self, node, frame, children=None): + """Dump the function def of a macro or call block.""" + frame = self.function_scoping(node, frame, children) + # macros are delayed, they never require output checks + frame.require_output_check = False + args = frame.arguments + # XXX: this is an ugly fix for the loop nesting bug + # (tests.test_old_bugs.test_loop_call_bug). This works around + # a identifier nesting problem we have in general. It's just more + # likely to happen in loops which is why we work around it. The + # real solution would be "nonlocal" all the identifiers that are + # leaking into a new python frame and might be used both unassigned + # and assigned. + if 'loop' in frame.identifiers.declared: + args = args + ['l_loop=l_loop'] + self.writeline('def macro(%s):' % ', '.join(args), node) + self.indent() + self.buffer(frame) + self.pull_locals(frame) + self.blockvisit(node.body, frame) + self.return_buffer_contents(frame) + self.outdent() + return frame + + def macro_def(self, node, frame): + """Dump the macro definition for the def created by macro_body.""" + arg_tuple = ', '.join(repr(x.name) for x in node.args) + name = getattr(node, 'name', None) + if len(node.args) == 1: + arg_tuple += ',' + self.write('Macro(environment, macro, %r, (%s), (' % + (name, arg_tuple)) + for arg in node.defaults: + self.visit(arg, frame) + self.write(', ') + self.write('), %r, %r, %r)' % ( + bool(frame.accesses_kwargs), + bool(frame.accesses_varargs), + bool(frame.accesses_caller) + )) + + def position(self, node): + """Return a human readable position for the node.""" + rv = 'line %d' % node.lineno + if self.name is not None: + rv += ' in ' + repr(self.name) + return rv + + # -- Statement Visitors + + def visit_Template(self, node, frame=None): + assert frame is None, 'no root frame allowed' + eval_ctx = EvalContext(self.environment, self.name) + + from jinja2.runtime import __all__ as exported + self.writeline('from __future__ import division') + self.writeline('from jinja2.runtime import ' + ', '.join(exported)) + if not unoptimize_before_dead_code: + self.writeline('dummy = lambda *x: None') + + # if we want a deferred initialization we cannot move the + # environment into a local name + envenv = not self.defer_init and ', environment=environment' or '' + + # do we have an extends tag at all? If not, we can save some + # overhead by just not processing any inheritance code. + have_extends = node.find(nodes.Extends) is not None + + # find all blocks + for block in node.find_all(nodes.Block): + if block.name in self.blocks: + self.fail('block %r defined twice' % block.name, block.lineno) + self.blocks[block.name] = block + + # find all imports and import them + for import_ in node.find_all(nodes.ImportedName): + if import_.importname not in self.import_aliases: + imp = import_.importname + self.import_aliases[imp] = alias = self.temporary_identifier() + if '.' in imp: + module, obj = imp.rsplit('.', 1) + self.writeline('from %s import %s as %s' % + (module, obj, alias)) + else: + self.writeline('import %s as %s' % (imp, alias)) + + # add the load name + self.writeline('name = %r' % self.name) + + # generate the root render function. + self.writeline('def root(context%s):' % envenv, extra=1) + + # process the root + frame = Frame(eval_ctx) + frame.inspect(node.body) + frame.toplevel = frame.rootlevel = True + frame.require_output_check = have_extends and not self.has_known_extends + self.indent() + if have_extends: + self.writeline('parent_template = None') + if 'self' in find_undeclared(node.body, ('self',)): + frame.identifiers.add_special('self') + self.writeline('l_self = TemplateReference(context)') + self.pull_locals(frame) + self.pull_dependencies(node.body) + self.blockvisit(node.body, frame) + self.outdent() + + # make sure that the parent root is called. + if have_extends: + if not self.has_known_extends: + self.indent() + self.writeline('if parent_template is not None:') + self.indent() + self.writeline('for event in parent_template.' + 'root_render_func(context):') + self.indent() + self.writeline('yield event') + self.outdent(2 + (not self.has_known_extends)) + + # at this point we now have the blocks collected and can visit them too. + for name, block in iteritems(self.blocks): + block_frame = Frame(eval_ctx) + block_frame.inspect(block.body) + block_frame.block = name + self.writeline('def block_%s(context%s):' % (name, envenv), + block, 1) + self.indent() + undeclared = find_undeclared(block.body, ('self', 'super')) + if 'self' in undeclared: + block_frame.identifiers.add_special('self') + self.writeline('l_self = TemplateReference(context)') + if 'super' in undeclared: + block_frame.identifiers.add_special('super') + self.writeline('l_super = context.super(%r, ' + 'block_%s)' % (name, name)) + self.pull_locals(block_frame) + self.pull_dependencies(block.body) + self.blockvisit(block.body, block_frame) + self.outdent() + + self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x) + for x in self.blocks), + extra=1) + + # add a function that returns the debug info + self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x + in self.debug_info)) + + def visit_Block(self, node, frame): + """Call a block and register it for the template.""" + level = 1 + if frame.toplevel: + # if we know that we are a child template, there is no need to + # check if we are one + if self.has_known_extends: + return + if self.extends_so_far > 0: + self.writeline('if parent_template is None:') + self.indent() + level += 1 + context = node.scoped and 'context.derived(locals())' or 'context' + self.writeline('for event in context.blocks[%r][0](%s):' % ( + node.name, context), node) + self.indent() + self.simple_write('event', frame) + self.outdent(level) + + def visit_Extends(self, node, frame): + """Calls the extender.""" + if not frame.toplevel: + self.fail('cannot use extend from a non top-level scope', + node.lineno) + + # if the number of extends statements in general is zero so + # far, we don't have to add a check if something extended + # the template before this one. + if self.extends_so_far > 0: + + # if we have a known extends we just add a template runtime + # error into the generated code. We could catch that at compile + # time too, but i welcome it not to confuse users by throwing the + # same error at different times just "because we can". + if not self.has_known_extends: + self.writeline('if parent_template is not None:') + self.indent() + self.writeline('raise TemplateRuntimeError(%r)' % + 'extended multiple times') + + # if we have a known extends already we don't need that code here + # as we know that the template execution will end here. + if self.has_known_extends: + raise CompilerExit() + else: + self.outdent() + + self.writeline('parent_template = environment.get_template(', node) + self.visit(node.template, frame) + self.write(', %r)' % self.name) + self.writeline('for name, parent_block in parent_template.' + 'blocks.%s():' % dict_item_iter) + self.indent() + self.writeline('context.blocks.setdefault(name, []).' + 'append(parent_block)') + self.outdent() + + # if this extends statement was in the root level we can take + # advantage of that information and simplify the generated code + # in the top level from this point onwards + if frame.rootlevel: + self.has_known_extends = True + + # and now we have one more + self.extends_so_far += 1 + + def visit_Include(self, node, frame): + """Handles includes.""" + if node.with_context: + self.unoptimize_scope(frame) + if node.ignore_missing: + self.writeline('try:') + self.indent() + + func_name = 'get_or_select_template' + if isinstance(node.template, nodes.Const): + if isinstance(node.template.value, string_types): + func_name = 'get_template' + elif isinstance(node.template.value, (tuple, list)): + func_name = 'select_template' + elif isinstance(node.template, (nodes.Tuple, nodes.List)): + func_name = 'select_template' + + self.writeline('template = environment.%s(' % func_name, node) + self.visit(node.template, frame) + self.write(', %r)' % self.name) + if node.ignore_missing: + self.outdent() + self.writeline('except TemplateNotFound:') + self.indent() + self.writeline('pass') + self.outdent() + self.writeline('else:') + self.indent() + + if node.with_context: + self.writeline('for event in template.root_render_func(' + 'template.new_context(context.parent, True, ' + 'locals())):') + else: + self.writeline('for event in template.module._body_stream:') + + self.indent() + self.simple_write('event', frame) + self.outdent() + + if node.ignore_missing: + self.outdent() + + def visit_Import(self, node, frame): + """Visit regular imports.""" + if node.with_context: + self.unoptimize_scope(frame) + self.writeline('l_%s = ' % node.target, node) + if frame.toplevel: + self.write('context.vars[%r] = ' % node.target) + self.write('environment.get_template(') + self.visit(node.template, frame) + self.write(', %r).' % self.name) + if node.with_context: + self.write('make_module(context.parent, True, locals())') + else: + self.write('module') + if frame.toplevel and not node.target.startswith('_'): + self.writeline('context.exported_vars.discard(%r)' % node.target) + frame.assigned_names.add(node.target) + + def visit_FromImport(self, node, frame): + """Visit named imports.""" + self.newline(node) + self.write('included_template = environment.get_template(') + self.visit(node.template, frame) + self.write(', %r).' % self.name) + if node.with_context: + self.write('make_module(context.parent, True)') + else: + self.write('module') + + var_names = [] + discarded_names = [] + for name in node.names: + if isinstance(name, tuple): + name, alias = name + else: + alias = name + self.writeline('l_%s = getattr(included_template, ' + '%r, missing)' % (alias, name)) + self.writeline('if l_%s is missing:' % alias) + self.indent() + self.writeline('l_%s = environment.undefined(%r %% ' + 'included_template.__name__, ' + 'name=%r)' % + (alias, 'the template %%r (imported on %s) does ' + 'not export the requested name %s' % ( + self.position(node), + repr(name) + ), name)) + self.outdent() + if frame.toplevel: + var_names.append(alias) + if not alias.startswith('_'): + discarded_names.append(alias) + frame.assigned_names.add(alias) + + if var_names: + if len(var_names) == 1: + name = var_names[0] + self.writeline('context.vars[%r] = l_%s' % (name, name)) + else: + self.writeline('context.vars.update({%s})' % ', '.join( + '%r: l_%s' % (name, name) for name in var_names + )) + if discarded_names: + if len(discarded_names) == 1: + self.writeline('context.exported_vars.discard(%r)' % + discarded_names[0]) + else: + self.writeline('context.exported_vars.difference_' + 'update((%s))' % ', '.join(imap(repr, discarded_names))) + + def visit_For(self, node, frame): + # when calculating the nodes for the inner frame we have to exclude + # the iterator contents from it + children = node.iter_child_nodes(exclude=('iter',)) + if node.recursive: + loop_frame = self.function_scoping(node, frame, children, + find_special=False) + else: + loop_frame = frame.inner() + loop_frame.inspect(children) + + # try to figure out if we have an extended loop. An extended loop + # is necessary if the loop is in recursive mode if the special loop + # variable is accessed in the body. + extended_loop = node.recursive or 'loop' in \ + find_undeclared(node.iter_child_nodes( + only=('body',)), ('loop',)) + + # if we don't have an recursive loop we have to find the shadowed + # variables at that point. Because loops can be nested but the loop + # variable is a special one we have to enforce aliasing for it. + if not node.recursive: + aliases = self.push_scope(loop_frame, ('loop',)) + + # otherwise we set up a buffer and add a function def + else: + self.writeline('def loop(reciter, loop_render_func, depth=0):', node) + self.indent() + self.buffer(loop_frame) + aliases = {} + + # make sure the loop variable is a special one and raise a template + # assertion error if a loop tries to write to loop + if extended_loop: + self.writeline('l_loop = missing') + loop_frame.identifiers.add_special('loop') + for name in node.find_all(nodes.Name): + if name.ctx == 'store' and name.name == 'loop': + self.fail('Can\'t assign to special loop variable ' + 'in for-loop target', name.lineno) + + self.pull_locals(loop_frame) + if node.else_: + iteration_indicator = self.temporary_identifier() + self.writeline('%s = 1' % iteration_indicator) + + # Create a fake parent loop if the else or test section of a + # loop is accessing the special loop variable and no parent loop + # exists. + if 'loop' not in aliases and 'loop' in find_undeclared( + node.iter_child_nodes(only=('else_', 'test')), ('loop',)): + self.writeline("l_loop = environment.undefined(%r, name='loop')" % + ("'loop' is undefined. the filter section of a loop as well " + "as the else block don't have access to the special 'loop'" + " variable of the current loop. Because there is no parent " + "loop it's undefined. Happened in loop on %s" % + self.position(node))) + + self.writeline('for ', node) + self.visit(node.target, loop_frame) + self.write(extended_loop and ', l_loop in LoopContext(' or ' in ') + + # if we have an extened loop and a node test, we filter in the + # "outer frame". + if extended_loop and node.test is not None: + self.write('(') + self.visit(node.target, loop_frame) + self.write(' for ') + self.visit(node.target, loop_frame) + self.write(' in ') + if node.recursive: + self.write('reciter') + else: + self.visit(node.iter, loop_frame) + self.write(' if (') + test_frame = loop_frame.copy() + self.visit(node.test, test_frame) + self.write('))') + + elif node.recursive: + self.write('reciter') + else: + self.visit(node.iter, loop_frame) + + if node.recursive: + self.write(', loop_render_func, depth):') + else: + self.write(extended_loop and '):' or ':') + + # tests in not extended loops become a continue + if not extended_loop and node.test is not None: + self.indent() + self.writeline('if not ') + self.visit(node.test, loop_frame) + self.write(':') + self.indent() + self.writeline('continue') + self.outdent(2) + + self.indent() + self.blockvisit(node.body, loop_frame) + if node.else_: + self.writeline('%s = 0' % iteration_indicator) + self.outdent() + + if node.else_: + self.writeline('if %s:' % iteration_indicator) + self.indent() + self.blockvisit(node.else_, loop_frame) + self.outdent() + + # reset the aliases if there are any. + if not node.recursive: + self.pop_scope(aliases, loop_frame) + + # if the node was recursive we have to return the buffer contents + # and start the iteration code + if node.recursive: + self.return_buffer_contents(loop_frame) + self.outdent() + self.start_write(frame, node) + self.write('loop(') + self.visit(node.iter, frame) + self.write(', loop)') + self.end_write(frame) + + def visit_If(self, node, frame): + if_frame = frame.soft() + self.writeline('if ', node) + self.visit(node.test, if_frame) + self.write(':') + self.indent() + self.blockvisit(node.body, if_frame) + self.outdent() + if node.else_: + self.writeline('else:') + self.indent() + self.blockvisit(node.else_, if_frame) + self.outdent() + + def visit_Macro(self, node, frame): + macro_frame = self.macro_body(node, frame) + self.newline() + if frame.toplevel: + if not node.name.startswith('_'): + self.write('context.exported_vars.add(%r)' % node.name) + self.writeline('context.vars[%r] = ' % node.name) + self.write('l_%s = ' % node.name) + self.macro_def(node, macro_frame) + frame.assigned_names.add(node.name) + + def visit_CallBlock(self, node, frame): + children = node.iter_child_nodes(exclude=('call',)) + call_frame = self.macro_body(node, frame, children) + self.writeline('caller = ') + self.macro_def(node, call_frame) + self.start_write(frame, node) + self.visit_Call(node.call, call_frame, forward_caller=True) + self.end_write(frame) + + def visit_FilterBlock(self, node, frame): + filter_frame = frame.inner() + filter_frame.inspect(node.iter_child_nodes()) + aliases = self.push_scope(filter_frame) + self.pull_locals(filter_frame) + self.buffer(filter_frame) + self.blockvisit(node.body, filter_frame) + self.start_write(frame, node) + self.visit_Filter(node.filter, filter_frame) + self.end_write(frame) + self.pop_scope(aliases, filter_frame) + + def visit_ExprStmt(self, node, frame): + self.newline(node) + self.visit(node.node, frame) + + def visit_Output(self, node, frame): + # if we have a known extends statement, we don't output anything + # if we are in a require_output_check section + if self.has_known_extends and frame.require_output_check: + return + + if self.environment.finalize: + finalize = lambda x: text_type(self.environment.finalize(x)) + else: + finalize = text_type + + # if we are inside a frame that requires output checking, we do so + outdent_later = False + if frame.require_output_check: + self.writeline('if parent_template is None:') + self.indent() + outdent_later = True + + # try to evaluate as many chunks as possible into a static + # string at compile time. + body = [] + for child in node.nodes: + try: + const = child.as_const(frame.eval_ctx) + except nodes.Impossible: + body.append(child) + continue + # the frame can't be volatile here, becaus otherwise the + # as_const() function would raise an Impossible exception + # at that point. + try: + if frame.eval_ctx.autoescape: + if hasattr(const, '__html__'): + const = const.__html__() + else: + const = escape(const) + const = finalize(const) + except Exception: + # if something goes wrong here we evaluate the node + # at runtime for easier debugging + body.append(child) + continue + if body and isinstance(body[-1], list): + body[-1].append(const) + else: + body.append([const]) + + # if we have less than 3 nodes or a buffer we yield or extend/append + if len(body) < 3 or frame.buffer is not None: + if frame.buffer is not None: + # for one item we append, for more we extend + if len(body) == 1: + self.writeline('%s.append(' % frame.buffer) + else: + self.writeline('%s.extend((' % frame.buffer) + self.indent() + for item in body: + if isinstance(item, list): + val = repr(concat(item)) + if frame.buffer is None: + self.writeline('yield ' + val) + else: + self.writeline(val + ', ') + else: + if frame.buffer is None: + self.writeline('yield ', item) + else: + self.newline(item) + close = 1 + if frame.eval_ctx.volatile: + self.write('(context.eval_ctx.autoescape and' + ' escape or to_string)(') + elif frame.eval_ctx.autoescape: + self.write('escape(') + else: + self.write('to_string(') + if self.environment.finalize is not None: + self.write('environment.finalize(') + close += 1 + self.visit(item, frame) + self.write(')' * close) + if frame.buffer is not None: + self.write(', ') + if frame.buffer is not None: + # close the open parentheses + self.outdent() + self.writeline(len(body) == 1 and ')' or '))') + + # otherwise we create a format string as this is faster in that case + else: + format = [] + arguments = [] + for item in body: + if isinstance(item, list): + format.append(concat(item).replace('%', '%%')) + else: + format.append('%s') + arguments.append(item) + self.writeline('yield ') + self.write(repr(concat(format)) + ' % (') + idx = -1 + self.indent() + for argument in arguments: + self.newline(argument) + close = 0 + if frame.eval_ctx.volatile: + self.write('(context.eval_ctx.autoescape and' + ' escape or to_string)(') + close += 1 + elif frame.eval_ctx.autoescape: + self.write('escape(') + close += 1 + if self.environment.finalize is not None: + self.write('environment.finalize(') + close += 1 + self.visit(argument, frame) + self.write(')' * close + ', ') + self.outdent() + self.writeline(')') + + if outdent_later: + self.outdent() + + def visit_Assign(self, node, frame): + self.newline(node) + # toplevel assignments however go into the local namespace and + # the current template's context. We create a copy of the frame + # here and add a set so that the Name visitor can add the assigned + # names here. + if frame.toplevel: + assignment_frame = frame.copy() + assignment_frame.toplevel_assignments = set() + else: + assignment_frame = frame + self.visit(node.target, assignment_frame) + self.write(' = ') + self.visit(node.node, frame) + + # make sure toplevel assignments are added to the context. + if frame.toplevel: + public_names = [x for x in assignment_frame.toplevel_assignments + if not x.startswith('_')] + if len(assignment_frame.toplevel_assignments) == 1: + name = next(iter(assignment_frame.toplevel_assignments)) + self.writeline('context.vars[%r] = l_%s' % (name, name)) + else: + self.writeline('context.vars.update({') + for idx, name in enumerate(assignment_frame.toplevel_assignments): + if idx: + self.write(', ') + self.write('%r: l_%s' % (name, name)) + self.write('})') + if public_names: + if len(public_names) == 1: + self.writeline('context.exported_vars.add(%r)' % + public_names[0]) + else: + self.writeline('context.exported_vars.update((%s))' % + ', '.join(imap(repr, public_names))) + + # -- Expression Visitors + + def visit_Name(self, node, frame): + if node.ctx == 'store' and frame.toplevel: + frame.toplevel_assignments.add(node.name) + self.write('l_' + node.name) + frame.assigned_names.add(node.name) + + def visit_Const(self, node, frame): + val = node.value + if isinstance(val, float): + self.write(str(val)) + else: + self.write(repr(val)) + + def visit_TemplateData(self, node, frame): + try: + self.write(repr(node.as_const(frame.eval_ctx))) + except nodes.Impossible: + self.write('(context.eval_ctx.autoescape and Markup or identity)(%r)' + % node.data) + + def visit_Tuple(self, node, frame): + self.write('(') + idx = -1 + for idx, item in enumerate(node.items): + if idx: + self.write(', ') + self.visit(item, frame) + self.write(idx == 0 and ',)' or ')') + + def visit_List(self, node, frame): + self.write('[') + for idx, item in enumerate(node.items): + if idx: + self.write(', ') + self.visit(item, frame) + self.write(']') + + def visit_Dict(self, node, frame): + self.write('{') + for idx, item in enumerate(node.items): + if idx: + self.write(', ') + self.visit(item.key, frame) + self.write(': ') + self.visit(item.value, frame) + self.write('}') + + def binop(operator, interceptable=True): + def visitor(self, node, frame): + if self.environment.sandboxed and \ + operator in self.environment.intercepted_binops: + self.write('environment.call_binop(context, %r, ' % operator) + self.visit(node.left, frame) + self.write(', ') + self.visit(node.right, frame) + else: + self.write('(') + self.visit(node.left, frame) + self.write(' %s ' % operator) + self.visit(node.right, frame) + self.write(')') + return visitor + + def uaop(operator, interceptable=True): + def visitor(self, node, frame): + if self.environment.sandboxed and \ + operator in self.environment.intercepted_unops: + self.write('environment.call_unop(context, %r, ' % operator) + self.visit(node.node, frame) + else: + self.write('(' + operator) + self.visit(node.node, frame) + self.write(')') + return visitor + + visit_Add = binop('+') + visit_Sub = binop('-') + visit_Mul = binop('*') + visit_Div = binop('/') + visit_FloorDiv = binop('//') + visit_Pow = binop('**') + visit_Mod = binop('%') + visit_And = binop('and', interceptable=False) + visit_Or = binop('or', interceptable=False) + visit_Pos = uaop('+') + visit_Neg = uaop('-') + visit_Not = uaop('not ', interceptable=False) + del binop, uaop + + def visit_Concat(self, node, frame): + if frame.eval_ctx.volatile: + func_name = '(context.eval_ctx.volatile and' \ + ' markup_join or unicode_join)' + elif frame.eval_ctx.autoescape: + func_name = 'markup_join' + else: + func_name = 'unicode_join' + self.write('%s((' % func_name) + for arg in node.nodes: + self.visit(arg, frame) + self.write(', ') + self.write('))') + + def visit_Compare(self, node, frame): + self.visit(node.expr, frame) + for op in node.ops: + self.visit(op, frame) + + def visit_Operand(self, node, frame): + self.write(' %s ' % operators[node.op]) + self.visit(node.expr, frame) + + def visit_Getattr(self, node, frame): + self.write('environment.getattr(') + self.visit(node.node, frame) + self.write(', %r)' % node.attr) + + def visit_Getitem(self, node, frame): + # slices bypass the environment getitem method. + if isinstance(node.arg, nodes.Slice): + self.visit(node.node, frame) + self.write('[') + self.visit(node.arg, frame) + self.write(']') + else: + self.write('environment.getitem(') + self.visit(node.node, frame) + self.write(', ') + self.visit(node.arg, frame) + self.write(')') + + def visit_Slice(self, node, frame): + if node.start is not None: + self.visit(node.start, frame) + self.write(':') + if node.stop is not None: + self.visit(node.stop, frame) + if node.step is not None: + self.write(':') + self.visit(node.step, frame) + + def visit_Filter(self, node, frame): + self.write(self.filters[node.name] + '(') + func = self.environment.filters.get(node.name) + if func is None: + self.fail('no filter named %r' % node.name, node.lineno) + if getattr(func, 'contextfilter', False): + self.write('context, ') + elif getattr(func, 'evalcontextfilter', False): + self.write('context.eval_ctx, ') + elif getattr(func, 'environmentfilter', False): + self.write('environment, ') + + # if the filter node is None we are inside a filter block + # and want to write to the current buffer + if node.node is not None: + self.visit(node.node, frame) + elif frame.eval_ctx.volatile: + self.write('(context.eval_ctx.autoescape and' + ' Markup(concat(%s)) or concat(%s))' % + (frame.buffer, frame.buffer)) + elif frame.eval_ctx.autoescape: + self.write('Markup(concat(%s))' % frame.buffer) + else: + self.write('concat(%s)' % frame.buffer) + self.signature(node, frame) + self.write(')') + + def visit_Test(self, node, frame): + self.write(self.tests[node.name] + '(') + if node.name not in self.environment.tests: + self.fail('no test named %r' % node.name, node.lineno) + self.visit(node.node, frame) + self.signature(node, frame) + self.write(')') + + def visit_CondExpr(self, node, frame): + def write_expr2(): + if node.expr2 is not None: + return self.visit(node.expr2, frame) + self.write('environment.undefined(%r)' % ('the inline if-' + 'expression on %s evaluated to false and ' + 'no else section was defined.' % self.position(node))) + + self.write('(') + self.visit(node.expr1, frame) + self.write(' if ') + self.visit(node.test, frame) + self.write(' else ') + write_expr2() + self.write(')') + + def visit_Call(self, node, frame, forward_caller=False): + if self.environment.sandboxed: + self.write('environment.call(context, ') + else: + self.write('context.call(') + self.visit(node.node, frame) + extra_kwargs = forward_caller and {'caller': 'caller'} or None + self.signature(node, frame, extra_kwargs) + self.write(')') + + def visit_Keyword(self, node, frame): + self.write(node.key + '=') + self.visit(node.value, frame) + + # -- Unused nodes for extensions + + def visit_MarkSafe(self, node, frame): + self.write('Markup(') + self.visit(node.expr, frame) + self.write(')') + + def visit_MarkSafeIfAutoescape(self, node, frame): + self.write('(context.eval_ctx.autoescape and Markup or identity)(') + self.visit(node.expr, frame) + self.write(')') + + def visit_EnvironmentAttribute(self, node, frame): + self.write('environment.' + node.name) + + def visit_ExtensionAttribute(self, node, frame): + self.write('environment.extensions[%r].%s' % (node.identifier, node.name)) + + def visit_ImportedName(self, node, frame): + self.write(self.import_aliases[node.importname]) + + def visit_InternalName(self, node, frame): + self.write(node.name) + + def visit_ContextReference(self, node, frame): + self.write('context') + + def visit_Continue(self, node, frame): + self.writeline('continue', node) + + def visit_Break(self, node, frame): + self.writeline('break', node) + + def visit_Scope(self, node, frame): + scope_frame = frame.inner() + scope_frame.inspect(node.iter_child_nodes()) + aliases = self.push_scope(scope_frame) + self.pull_locals(scope_frame) + self.blockvisit(node.body, scope_frame) + self.pop_scope(aliases, scope_frame) + + def visit_EvalContextModifier(self, node, frame): + for keyword in node.options: + self.writeline('context.eval_ctx.%s = ' % keyword.key) + self.visit(keyword.value, frame) + try: + val = keyword.value.as_const(frame.eval_ctx) + except nodes.Impossible: + frame.eval_ctx.volatile = True + else: + setattr(frame.eval_ctx, keyword.key, val) + + def visit_ScopedEvalContextModifier(self, node, frame): + old_ctx_name = self.temporary_identifier() + safed_ctx = frame.eval_ctx.save() + self.writeline('%s = context.eval_ctx.save()' % old_ctx_name) + self.visit_EvalContextModifier(node, frame) + for child in node.body: + self.visit(child, frame) + frame.eval_ctx.revert(safed_ctx) + self.writeline('context.eval_ctx.revert(%s)' % old_ctx_name) diff --git a/lib/jinja2/compiler.pyc b/lib/jinja2/compiler.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5b4c65dccdeb7d35c522931c0dc1b0cf6a8070c6 GIT binary patch literal 53637 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 literal 0 HcmV?d00001 diff --git a/lib/jinja2/constants.py b/lib/jinja2/constants.py new file mode 100644 index 0000000..cab203c --- /dev/null +++ b/lib/jinja2/constants.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +""" + jinja.constants + ~~~~~~~~~~~~~~~ + + Various constants. + + :copyright: (c) 2010 by the Jinja Team. + :license: BSD, see LICENSE for more details. +""" + + +#: list of lorem ipsum words used by the lipsum() helper function +LOREM_IPSUM_WORDS = u'''\ +a ac accumsan ad adipiscing aenean aliquam aliquet amet ante aptent arcu at +auctor augue bibendum blandit class commodo condimentum congue consectetuer +consequat conubia convallis cras cubilia cum curabitur curae cursus dapibus +diam dictum dictumst dignissim dis dolor donec dui duis egestas eget eleifend +elementum elit enim erat eros est et etiam eu euismod facilisi facilisis fames +faucibus felis fermentum feugiat fringilla fusce gravida habitant habitasse hac +hendrerit hymenaeos iaculis id imperdiet in inceptos integer interdum ipsum +justo lacinia lacus laoreet lectus leo libero ligula litora lobortis lorem +luctus maecenas magna magnis malesuada massa mattis mauris metus mi molestie +mollis montes morbi mus nam nascetur natoque nec neque netus nibh nisi nisl non +nonummy nostra nulla nullam nunc odio orci ornare parturient pede pellentesque +penatibus per pharetra phasellus placerat platea porta porttitor posuere +potenti praesent pretium primis proin pulvinar purus quam quis quisque rhoncus +ridiculus risus rutrum sagittis sapien scelerisque sed sem semper senectus sit +sociis sociosqu sodales sollicitudin suscipit suspendisse taciti tellus tempor +tempus tincidunt torquent tortor tristique turpis ullamcorper ultrices +ultricies urna ut varius vehicula vel velit venenatis vestibulum vitae vivamus +viverra volutpat vulputate''' diff --git a/lib/jinja2/constants.pyc b/lib/jinja2/constants.pyc new file mode 100644 index 0000000000000000000000000000000000000000..da7a52685c271d50d4d0549941aef324f98db2c5 GIT binary patch literal 1687 zcmY+FOOG5y496#lc&H^LxNxrHBEfFR1++p4k?bKT50qs=%4Jnk?U`{@k4`;C+6!ML zACfP?&poRkM%}in+VwB{Z&%Huf4-P@AD-TX&He8I`WN2zC1T!e-Xb4t-agpO4>#9m zkL=3_#N_zB)BMh#hmu?Oxwm!h@Bja%b@ESNwT$LIx}KlrFGE@Gs_qZ{(w&8G+>^)O zKX%(Y*AL=;GjR8Z_;kKvTt*F&n_RkIub+MEnuvSx{OQ%J>npb_)umF!&C5jwm0u^-~L zx|KYSJdyv zn>K(^{Z{*^s|C`i4JK#5=ytSeR-&IZ*j^{qI>tV0Yid)tmPq7t$r9W=)ZXS~FBEOn z-ANSPkLBwa358!d?2SAW#myMv`n8SahN1S?DjVyse$>~IH?7lKkBhJowsG%ZqR zB}C0UL6&X~RC6zN)zyloOB-o=H(D<)5_*PdG+{G28Gk)_t~!!m*k_g;YljdBPP48Ony{TbOcgqU);LNgkkBVLfEG2 zmXG*kI0rnipknm$p0=`*W;s~~ly!SRPzpqJx#Wp=q;!YfI-%!bY_Af$k%KF<7FTLe zMD`q_#aH%F>;6S%#u6g~Y3wsCWZ2i5!nIotEHGG%h8rO)P`S1YMi;)o)Jb+Dk8$G+ z095RJsavX-w(bRzQl6!1f`FwKs<@1JRHDMDfUjruz4fmN%ex**rgT$Px_?*z&}wq@ z3Rv@dUHNXD7s(F(A`P@IZ8CF<;3L*IDA+U-oA#-dpzLC*;EXX_9nn-La2#iXW1ql< z(#?Pu&KiB%=_u0bCpJ3RrB0?m?lh&&17cx<=ud{R(ut{a6|sI)?kHzvN}*JXY(zc> z&eO?I;uw_5jqZ+ItN#$0l^~CvmYUE~Dc-Tf(HD;6 zal~bG%J%B)A$NTL3~_rqmvDRAzrud;`pwnL+vmSu-@Ls2>-C#w*Jn&_{uAvxh8I08 x_Fn(kZf<_K-~e4Lcbzg_tbZ3zF6{bS|1Zv&|C|*+afys5KTp`rHvaVMe*vbKRx' % ( + 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 0000000000000000000000000000000000000000..e82369553059dfc6b2bfbe1640917be65aae9bb4 GIT binary patch literal 10514 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 E02d&uNB{r; literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..408fe81a8c6ed4e23ca6eb6d5cc6f7f587a14141 GIT binary patch literal 1610 zcmbtUTW{Mo6h87TiF0!Hf$5!2Z~t_XD$-qkTzLEMAn1Mu$`G1owR2+2p_e+))k2VMcT4hL)le#IO& z;egkGwQ#Bf+rp^zPk=uFwnIw%Q+Nk3{*3VCodNjoKcqz5_B|^3cZ8;i-#DI( z!zUfaufnNNQggq&|1~xFoD|Jc&%BC-;<+@#2{ToAEjxwMVU%XGJifkBhh{ta!hEv- z)xLQ-Gt~_@3kMz#la6+HDB_4uBtJBd-IK?r9uT%Hbwp5?d&QAfhFT+das(kVr_0J5QRhC|j6-U7Cr z7`u%Cg*D~y>gR$WRz61PswAV~ej`Vtue&0?>}E4{lTNzDId$jf)IoX~4W5cHxn$wd z9(lk4iUP7YQo3Go*M;b=3uE1dh%%xqXi(zva|F!w$NO+=z*_^xK-VX)()y+GQ z_MAcQcxb(^zOyJ~z8vg&GcQ9mcb?{e@$l4t`J+ zN=xSEB~O>{G!&AnRa{{e=Yg)vRqJFybzRIEs?N5)F9KNKjV!xw>5ylZbrE<@Z-Am_ zL8-FX+w#FXl&IQ7II&K9qoEg+Phzp(ic2LO%1fs(*DT)3)`G3wJGb169_FBxr literal 0 HcmV?d00001 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 = '