d54ef825d Merge pull request #1 from commaai/new-usr
e3e0520e4 put back logentries and overpy
c3ad0b3dd remove everything
git-subtree-dir: pyextra
git-subtree-split: d54ef825db8d96de8c960ac57a33ac11fa7728bf
old-commit-hash: 78e4e4ea23
			
			
				commatwo_master
			
			
		
							parent
							
								
									310597c60c
								
							
						
					
					
						commit
						70d60952e2
					
				
				 315 changed files with 325 additions and 74491 deletions
			
			
		| @ -1,103 +0,0 @@ | |||||||
| Metadata-Version: 1.1 |  | ||||||
| Name: Flask |  | ||||||
| Version: 1.0.2 |  | ||||||
| Summary: A simple framework for building complex web applications. |  | ||||||
| Home-page: https://www.palletsprojects.com/p/flask/ |  | ||||||
| Author: Pallets team |  | ||||||
| Author-email: contact@palletsprojects.com |  | ||||||
| License: BSD |  | ||||||
| Description: Flask |  | ||||||
|         ===== |  | ||||||
|          |  | ||||||
|         Flask is a lightweight `WSGI`_ web application framework. It is designed |  | ||||||
|         to make getting started quick and easy, with the ability to scale up to |  | ||||||
|         complex applications. It began as a simple wrapper around `Werkzeug`_ |  | ||||||
|         and `Jinja`_ and has become one of the most popular Python web |  | ||||||
|         application frameworks. |  | ||||||
|          |  | ||||||
|         Flask offers suggestions, but doesn't enforce any dependencies or |  | ||||||
|         project layout. It is up to the developer to choose the tools and |  | ||||||
|         libraries they want to use. There are many extensions provided by the |  | ||||||
|         community that make adding new functionality easy. |  | ||||||
|          |  | ||||||
|          |  | ||||||
|         Installing |  | ||||||
|         ---------- |  | ||||||
|          |  | ||||||
|         Install and update using `pip`_: |  | ||||||
|          |  | ||||||
|         .. code-block:: text |  | ||||||
|          |  | ||||||
|             pip install -U Flask |  | ||||||
|          |  | ||||||
|          |  | ||||||
|         A Simple Example |  | ||||||
|         ---------------- |  | ||||||
|          |  | ||||||
|         .. code-block:: python |  | ||||||
|          |  | ||||||
|             from flask import Flask |  | ||||||
|          |  | ||||||
|             app = Flask(__name__) |  | ||||||
|          |  | ||||||
|             @app.route('/') |  | ||||||
|             def hello(): |  | ||||||
|                 return 'Hello, World!' |  | ||||||
|          |  | ||||||
|         .. code-block:: text |  | ||||||
|          |  | ||||||
|             $ FLASK_APP=hello.py flask run |  | ||||||
|              * Serving Flask app "hello" |  | ||||||
|              * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) |  | ||||||
|          |  | ||||||
|          |  | ||||||
|         Donate |  | ||||||
|         ------ |  | ||||||
|          |  | ||||||
|         The Pallets organization develops and supports Flask and the libraries |  | ||||||
|         it uses. In order to grow the community of contributors and users, and |  | ||||||
|         allow the maintainers to devote more time to the projects, `please |  | ||||||
|         donate today`_. |  | ||||||
|          |  | ||||||
|         .. _please donate today: https://psfmember.org/civicrm/contribute/transact?reset=1&id=20 |  | ||||||
|          |  | ||||||
|          |  | ||||||
|         Links |  | ||||||
|         ----- |  | ||||||
|          |  | ||||||
|         * Website: https://www.palletsprojects.com/p/flask/ |  | ||||||
|         * Documentation: http://flask.pocoo.org/docs/ |  | ||||||
|         * License: `BSD <https://github.com/pallets/flask/blob/master/LICENSE>`_ |  | ||||||
|         * Releases: https://pypi.org/project/Flask/ |  | ||||||
|         * Code: https://github.com/pallets/flask |  | ||||||
|         * Issue tracker: https://github.com/pallets/flask/issues |  | ||||||
|         * Test status: |  | ||||||
|          |  | ||||||
|           * Linux, Mac: https://travis-ci.org/pallets/flask |  | ||||||
|           * Windows: https://ci.appveyor.com/project/pallets/flask |  | ||||||
|          |  | ||||||
|         * Test coverage: https://codecov.io/gh/pallets/flask |  | ||||||
|          |  | ||||||
|         .. _WSGI: https://wsgi.readthedocs.io |  | ||||||
|         .. _Werkzeug: https://www.palletsprojects.com/p/werkzeug/ |  | ||||||
|         .. _Jinja: https://www.palletsprojects.com/p/jinja/ |  | ||||||
|         .. _pip: https://pip.pypa.io/en/stable/quickstart/ |  | ||||||
|          |  | ||||||
| Platform: any |  | ||||||
| Classifier: Development Status :: 5 - Production/Stable |  | ||||||
| Classifier: Environment :: Web Environment |  | ||||||
| Classifier: Framework :: Flask |  | ||||||
| Classifier: Intended Audience :: Developers |  | ||||||
| Classifier: License :: OSI Approved :: BSD License |  | ||||||
| Classifier: Operating System :: OS Independent |  | ||||||
| Classifier: Programming Language :: Python |  | ||||||
| Classifier: Programming Language :: Python :: 2 |  | ||||||
| Classifier: Programming Language :: Python :: 2.7 |  | ||||||
| Classifier: Programming Language :: Python :: 3 |  | ||||||
| Classifier: Programming Language :: Python :: 3.4 |  | ||||||
| Classifier: Programming Language :: Python :: 3.5 |  | ||||||
| Classifier: Programming Language :: Python :: 3.6 |  | ||||||
| Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content |  | ||||||
| Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application |  | ||||||
| Classifier: Topic :: Software Development :: Libraries :: Application Frameworks |  | ||||||
| Classifier: Topic :: Software Development :: Libraries :: Python Modules |  | ||||||
| @ -1,223 +0,0 @@ | |||||||
| AUTHORS |  | ||||||
| CHANGES.rst |  | ||||||
| LICENSE |  | ||||||
| MANIFEST.in |  | ||||||
| Makefile |  | ||||||
| README.rst |  | ||||||
| setup.cfg |  | ||||||
| setup.py |  | ||||||
| tox.ini |  | ||||||
| Flask.egg-info/PKG-INFO |  | ||||||
| Flask.egg-info/SOURCES.txt |  | ||||||
| Flask.egg-info/dependency_links.txt |  | ||||||
| Flask.egg-info/entry_points.txt |  | ||||||
| Flask.egg-info/not-zip-safe |  | ||||||
| Flask.egg-info/requires.txt |  | ||||||
| Flask.egg-info/top_level.txt |  | ||||||
| artwork/LICENSE |  | ||||||
| artwork/logo-full.svg |  | ||||||
| artwork/logo-lineart.svg |  | ||||||
| docs/Makefile |  | ||||||
| docs/advanced_foreword.rst |  | ||||||
| docs/api.rst |  | ||||||
| docs/appcontext.rst |  | ||||||
| docs/becomingbig.rst |  | ||||||
| docs/blueprints.rst |  | ||||||
| docs/changelog.rst |  | ||||||
| docs/cli.rst |  | ||||||
| docs/conf.py |  | ||||||
| docs/config.rst |  | ||||||
| docs/contents.rst.inc |  | ||||||
| docs/contributing.rst |  | ||||||
| docs/design.rst |  | ||||||
| docs/errorhandling.rst |  | ||||||
| docs/extensiondev.rst |  | ||||||
| docs/extensions.rst |  | ||||||
| docs/flaskstyle.sty |  | ||||||
| docs/foreword.rst |  | ||||||
| docs/htmlfaq.rst |  | ||||||
| docs/index.rst |  | ||||||
| docs/installation.rst |  | ||||||
| docs/latexindex.rst |  | ||||||
| docs/license.rst |  | ||||||
| docs/logging.rst |  | ||||||
| docs/logo.pdf |  | ||||||
| docs/make.bat |  | ||||||
| docs/quickstart.rst |  | ||||||
| docs/reqcontext.rst |  | ||||||
| docs/security.rst |  | ||||||
| docs/server.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-favicon.ico |  | ||||||
| docs/_static/flask.png |  | ||||||
| docs/_static/logo-full.png |  | ||||||
| docs/_static/no.png |  | ||||||
| docs/_static/pycharm-runconfig.png |  | ||||||
| docs/_static/touch-icon.png |  | ||||||
| docs/_static/yes.png |  | ||||||
| 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/subclassing.rst |  | ||||||
| docs/patterns/templateinheritance.rst |  | ||||||
| docs/patterns/urlprocessors.rst |  | ||||||
| docs/patterns/viewdecorators.rst |  | ||||||
| docs/patterns/wtforms.rst |  | ||||||
| docs/tutorial/blog.rst |  | ||||||
| docs/tutorial/database.rst |  | ||||||
| docs/tutorial/deploy.rst |  | ||||||
| docs/tutorial/factory.rst |  | ||||||
| docs/tutorial/flaskr_edit.png |  | ||||||
| docs/tutorial/flaskr_index.png |  | ||||||
| docs/tutorial/flaskr_login.png |  | ||||||
| docs/tutorial/index.rst |  | ||||||
| docs/tutorial/install.rst |  | ||||||
| docs/tutorial/layout.rst |  | ||||||
| docs/tutorial/next.rst |  | ||||||
| docs/tutorial/static.rst |  | ||||||
| docs/tutorial/templates.rst |  | ||||||
| docs/tutorial/tests.rst |  | ||||||
| docs/tutorial/views.rst |  | ||||||
| examples/javascript/.gitignore |  | ||||||
| examples/javascript/LICENSE |  | ||||||
| examples/javascript/MANIFEST.in |  | ||||||
| examples/javascript/README.rst |  | ||||||
| examples/javascript/setup.cfg |  | ||||||
| examples/javascript/setup.py |  | ||||||
| examples/javascript/js_example/__init__.py |  | ||||||
| examples/javascript/js_example/views.py |  | ||||||
| examples/javascript/js_example/templates/base.html |  | ||||||
| examples/javascript/js_example/templates/fetch.html |  | ||||||
| examples/javascript/js_example/templates/jquery.html |  | ||||||
| examples/javascript/js_example/templates/plain.html |  | ||||||
| examples/javascript/tests/conftest.py |  | ||||||
| examples/javascript/tests/test_js_example.py |  | ||||||
| examples/tutorial/.gitignore |  | ||||||
| examples/tutorial/LICENSE |  | ||||||
| examples/tutorial/MANIFEST.in |  | ||||||
| examples/tutorial/README.rst |  | ||||||
| examples/tutorial/setup.cfg |  | ||||||
| examples/tutorial/setup.py |  | ||||||
| examples/tutorial/flaskr/__init__.py |  | ||||||
| examples/tutorial/flaskr/auth.py |  | ||||||
| examples/tutorial/flaskr/blog.py |  | ||||||
| examples/tutorial/flaskr/db.py |  | ||||||
| examples/tutorial/flaskr/schema.sql |  | ||||||
| examples/tutorial/flaskr/static/style.css |  | ||||||
| examples/tutorial/flaskr/templates/base.html |  | ||||||
| examples/tutorial/flaskr/templates/auth/login.html |  | ||||||
| examples/tutorial/flaskr/templates/auth/register.html |  | ||||||
| examples/tutorial/flaskr/templates/blog/create.html |  | ||||||
| examples/tutorial/flaskr/templates/blog/index.html |  | ||||||
| examples/tutorial/flaskr/templates/blog/update.html |  | ||||||
| examples/tutorial/tests/conftest.py |  | ||||||
| examples/tutorial/tests/data.sql |  | ||||||
| examples/tutorial/tests/test_auth.py |  | ||||||
| examples/tutorial/tests/test_blog.py |  | ||||||
| examples/tutorial/tests/test_db.py |  | ||||||
| examples/tutorial/tests/test_factory.py |  | ||||||
| flask/__init__.py |  | ||||||
| flask/__main__.py |  | ||||||
| flask/_compat.py |  | ||||||
| flask/app.py |  | ||||||
| flask/blueprints.py |  | ||||||
| flask/cli.py |  | ||||||
| flask/config.py |  | ||||||
| flask/ctx.py |  | ||||||
| flask/debughelpers.py |  | ||||||
| flask/globals.py |  | ||||||
| flask/helpers.py |  | ||||||
| flask/logging.py |  | ||||||
| flask/sessions.py |  | ||||||
| flask/signals.py |  | ||||||
| flask/templating.py |  | ||||||
| flask/testing.py |  | ||||||
| flask/views.py |  | ||||||
| flask/wrappers.py |  | ||||||
| flask/json/__init__.py |  | ||||||
| flask/json/tag.py |  | ||||||
| tests/conftest.py |  | ||||||
| tests/test_appctx.py |  | ||||||
| tests/test_basic.py |  | ||||||
| tests/test_blueprints.py |  | ||||||
| tests/test_cli.py |  | ||||||
| tests/test_config.py |  | ||||||
| tests/test_helpers.py |  | ||||||
| tests/test_instance_config.py |  | ||||||
| tests/test_json_tag.py |  | ||||||
| tests/test_logging.py |  | ||||||
| tests/test_regression.py |  | ||||||
| tests/test_reqctx.py |  | ||||||
| tests/test_signals.py |  | ||||||
| tests/test_subclassing.py |  | ||||||
| tests/test_templating.py |  | ||||||
| tests/test_testing.py |  | ||||||
| tests/test_user_error_handler.py |  | ||||||
| tests/test_views.py |  | ||||||
| tests/static/config.json |  | ||||||
| tests/static/index.html |  | ||||||
| tests/templates/_macro.html |  | ||||||
| tests/templates/context_template.html |  | ||||||
| tests/templates/escaping_template.html |  | ||||||
| tests/templates/mail.txt |  | ||||||
| tests/templates/non_escaping_template.txt |  | ||||||
| tests/templates/simple_template.html |  | ||||||
| tests/templates/template_filter.html |  | ||||||
| tests/templates/template_test.html |  | ||||||
| tests/templates/nested/nested.txt |  | ||||||
| tests/test_apps/.env |  | ||||||
| tests/test_apps/.flaskenv |  | ||||||
| tests/test_apps/blueprintapp/__init__.py |  | ||||||
| tests/test_apps/blueprintapp/apps/__init__.py |  | ||||||
| tests/test_apps/blueprintapp/apps/admin/__init__.py |  | ||||||
| tests/test_apps/blueprintapp/apps/admin/static/test.txt |  | ||||||
| tests/test_apps/blueprintapp/apps/admin/static/css/test.css |  | ||||||
| tests/test_apps/blueprintapp/apps/admin/templates/admin/index.html |  | ||||||
| tests/test_apps/blueprintapp/apps/frontend/__init__.py |  | ||||||
| tests/test_apps/blueprintapp/apps/frontend/templates/frontend/index.html |  | ||||||
| tests/test_apps/cliapp/__init__.py |  | ||||||
| tests/test_apps/cliapp/app.py |  | ||||||
| tests/test_apps/cliapp/factory.py |  | ||||||
| tests/test_apps/cliapp/importerrorapp.py |  | ||||||
| tests/test_apps/cliapp/message.txt |  | ||||||
| tests/test_apps/cliapp/multiapp.py |  | ||||||
| tests/test_apps/cliapp/inner1/__init__.py |  | ||||||
| tests/test_apps/cliapp/inner1/inner2/__init__.py |  | ||||||
| tests/test_apps/cliapp/inner1/inner2/flask.py |  | ||||||
| tests/test_apps/helloworld/hello.py |  | ||||||
| tests/test_apps/helloworld/wsgi.py |  | ||||||
| tests/test_apps/subdomaintestmodule/__init__.py |  | ||||||
| tests/test_apps/subdomaintestmodule/static/hello.txt |  | ||||||
| @ -1 +0,0 @@ | |||||||
| 
 |  | ||||||
| @ -1,3 +0,0 @@ | |||||||
| [console_scripts] |  | ||||||
| flask = flask.cli:main |  | ||||||
| 
 |  | ||||||
| @ -1,48 +0,0 @@ | |||||||
| ../flask/testing.py |  | ||||||
| ../flask/templating.py |  | ||||||
| ../flask/__main__.py |  | ||||||
| ../flask/sessions.py |  | ||||||
| ../flask/signals.py |  | ||||||
| ../flask/helpers.py |  | ||||||
| ../flask/debughelpers.py |  | ||||||
| ../flask/wrappers.py |  | ||||||
| ../flask/app.py |  | ||||||
| ../flask/ctx.py |  | ||||||
| ../flask/config.py |  | ||||||
| ../flask/logging.py |  | ||||||
| ../flask/blueprints.py |  | ||||||
| ../flask/views.py |  | ||||||
| ../flask/cli.py |  | ||||||
| ../flask/_compat.py |  | ||||||
| ../flask/globals.py |  | ||||||
| ../flask/__init__.py |  | ||||||
| ../flask/json/tag.py |  | ||||||
| ../flask/json/__init__.py |  | ||||||
| ../flask/testing.pyc |  | ||||||
| ../flask/templating.pyc |  | ||||||
| ../flask/__main__.pyc |  | ||||||
| ../flask/sessions.pyc |  | ||||||
| ../flask/signals.pyc |  | ||||||
| ../flask/helpers.pyc |  | ||||||
| ../flask/debughelpers.pyc |  | ||||||
| ../flask/wrappers.pyc |  | ||||||
| ../flask/app.pyc |  | ||||||
| ../flask/ctx.pyc |  | ||||||
| ../flask/config.pyc |  | ||||||
| ../flask/logging.pyc |  | ||||||
| ../flask/blueprints.pyc |  | ||||||
| ../flask/views.pyc |  | ||||||
| ../flask/cli.pyc |  | ||||||
| ../flask/_compat.pyc |  | ||||||
| ../flask/globals.pyc |  | ||||||
| ../flask/__init__.pyc |  | ||||||
| ../flask/json/tag.pyc |  | ||||||
| ../flask/json/__init__.pyc |  | ||||||
| not-zip-safe |  | ||||||
| entry_points.txt |  | ||||||
| dependency_links.txt |  | ||||||
| PKG-INFO |  | ||||||
| top_level.txt |  | ||||||
| requires.txt |  | ||||||
| SOURCES.txt |  | ||||||
| ../../../../bin/flask |  | ||||||
| @ -1 +0,0 @@ | |||||||
| 
 |  | ||||||
| @ -1,20 +0,0 @@ | |||||||
| Werkzeug>=0.14 |  | ||||||
| Jinja2>=2.10 |  | ||||||
| itsdangerous>=0.24 |  | ||||||
| click>=5.1 |  | ||||||
| 
 |  | ||||||
| [dev] |  | ||||||
| pytest>=3 |  | ||||||
| coverage |  | ||||||
| tox |  | ||||||
| sphinx |  | ||||||
| pallets-sphinx-themes |  | ||||||
| sphinxcontrib-log-cabinet |  | ||||||
| 
 |  | ||||||
| [docs] |  | ||||||
| sphinx |  | ||||||
| pallets-sphinx-themes |  | ||||||
| sphinxcontrib-log-cabinet |  | ||||||
| 
 |  | ||||||
| [dotenv] |  | ||||||
| python-dotenv |  | ||||||
| @ -1 +0,0 @@ | |||||||
| flask |  | ||||||
| @ -1,62 +0,0 @@ | |||||||
| Metadata-Version: 1.1 |  | ||||||
| Name: Jinja2 |  | ||||||
| Version: 2.10 |  | ||||||
| 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 %} |  | ||||||
|               <ul> |  | ||||||
|               {% for user in users %} |  | ||||||
|                 <li><a href="{{ user.url }}">{{ user.username }}</a></li> |  | ||||||
|               {% endfor %} |  | ||||||
|               </ul> |  | ||||||
|             {% 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: https://en.wikipedia.org/wiki/Sandbox_(computer_security) |  | ||||||
|         .. _Django: https://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 :: 2 |  | ||||||
| Classifier: Programming Language :: Python :: 2.6 |  | ||||||
| Classifier: Programming Language :: Python :: 2.7 |  | ||||||
| Classifier: Programming Language :: Python :: 3 |  | ||||||
| Classifier: Programming Language :: Python :: 3.3 |  | ||||||
| Classifier: Programming Language :: Python :: 3.4 |  | ||||||
| Classifier: Programming Language :: Python :: 3.5 |  | ||||||
| Classifier: Programming Language :: Python :: 3.6 |  | ||||||
| Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content |  | ||||||
| Classifier: Topic :: Software Development :: Libraries :: Python Modules |  | ||||||
| Classifier: Topic :: Text Processing :: Markup :: HTML |  | ||||||
| @ -1,133 +0,0 @@ | |||||||
| AUTHORS |  | ||||||
| CHANGES.rst |  | ||||||
| LICENSE |  | ||||||
| MANIFEST.in |  | ||||||
| README.rst |  | ||||||
| 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/nativetypes.rst |  | ||||||
| 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/_identifier.py |  | ||||||
| jinja2/asyncfilters.py |  | ||||||
| jinja2/asyncsupport.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/idtracking.py |  | ||||||
| jinja2/lexer.py |  | ||||||
| jinja2/loaders.py |  | ||||||
| jinja2/meta.py |  | ||||||
| jinja2/nativetypes.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 |  | ||||||
| tests/conftest.py |  | ||||||
| tests/test_api.py |  | ||||||
| tests/test_async.py |  | ||||||
| tests/test_asyncfilters.py |  | ||||||
| tests/test_bytecode_cache.py |  | ||||||
| tests/test_core_tags.py |  | ||||||
| tests/test_debug.py |  | ||||||
| tests/test_ext.py |  | ||||||
| tests/test_features.py |  | ||||||
| tests/test_filters.py |  | ||||||
| tests/test_idtracking.py |  | ||||||
| tests/test_imports.py |  | ||||||
| tests/test_inheritance.py |  | ||||||
| tests/test_lexnparse.py |  | ||||||
| tests/test_loader.py |  | ||||||
| tests/test_nativetypes.py |  | ||||||
| tests/test_regression.py |  | ||||||
| tests/test_security.py |  | ||||||
| tests/test_tests.py |  | ||||||
| tests/test_utils.py |  | ||||||
| tests/res/__init__.py |  | ||||||
| tests/res/templates/broken.html |  | ||||||
| tests/res/templates/syntaxerror.html |  | ||||||
| tests/res/templates/test.html |  | ||||||
| tests/res/templates/foo/test.html |  | ||||||
| @ -1 +0,0 @@ | |||||||
| 
 |  | ||||||
| @ -1,4 +0,0 @@ | |||||||
| 
 |  | ||||||
|     [babel.extractors] |  | ||||||
|     jinja2 = jinja2.ext:babel_extract[i18n] |  | ||||||
|      |  | ||||||
| @ -1,61 +0,0 @@ | |||||||
| ../jinja2/lexer.py |  | ||||||
| ../jinja2/idtracking.py |  | ||||||
| ../jinja2/_identifier.py |  | ||||||
| ../jinja2/nodes.py |  | ||||||
| ../jinja2/asyncfilters.py |  | ||||||
| ../jinja2/loaders.py |  | ||||||
| ../jinja2/defaults.py |  | ||||||
| ../jinja2/meta.py |  | ||||||
| ../jinja2/compiler.py |  | ||||||
| ../jinja2/environment.py |  | ||||||
| ../jinja2/tests.py |  | ||||||
| ../jinja2/sandbox.py |  | ||||||
| ../jinja2/filters.py |  | ||||||
| ../jinja2/exceptions.py |  | ||||||
| ../jinja2/asyncsupport.py |  | ||||||
| ../jinja2/visitor.py |  | ||||||
| ../jinja2/constants.py |  | ||||||
| ../jinja2/utils.py |  | ||||||
| ../jinja2/ext.py |  | ||||||
| ../jinja2/optimizer.py |  | ||||||
| ../jinja2/nativetypes.py |  | ||||||
| ../jinja2/parser.py |  | ||||||
| ../jinja2/runtime.py |  | ||||||
| ../jinja2/debug.py |  | ||||||
| ../jinja2/_compat.py |  | ||||||
| ../jinja2/bccache.py |  | ||||||
| ../jinja2/__init__.py |  | ||||||
| ../jinja2/lexer.pyc |  | ||||||
| ../jinja2/idtracking.pyc |  | ||||||
| ../jinja2/_identifier.pyc |  | ||||||
| ../jinja2/nodes.pyc |  | ||||||
| ../jinja2/asyncfilters.pyc |  | ||||||
| ../jinja2/loaders.pyc |  | ||||||
| ../jinja2/defaults.pyc |  | ||||||
| ../jinja2/meta.pyc |  | ||||||
| ../jinja2/compiler.pyc |  | ||||||
| ../jinja2/environment.pyc |  | ||||||
| ../jinja2/tests.pyc |  | ||||||
| ../jinja2/sandbox.pyc |  | ||||||
| ../jinja2/filters.pyc |  | ||||||
| ../jinja2/exceptions.pyc |  | ||||||
| ../jinja2/asyncsupport.pyc |  | ||||||
| ../jinja2/visitor.pyc |  | ||||||
| ../jinja2/constants.pyc |  | ||||||
| ../jinja2/utils.pyc |  | ||||||
| ../jinja2/ext.pyc |  | ||||||
| ../jinja2/optimizer.pyc |  | ||||||
| ../jinja2/nativetypes.pyc |  | ||||||
| ../jinja2/parser.pyc |  | ||||||
| ../jinja2/runtime.pyc |  | ||||||
| ../jinja2/debug.pyc |  | ||||||
| ../jinja2/_compat.pyc |  | ||||||
| ../jinja2/bccache.pyc |  | ||||||
| ../jinja2/__init__.pyc |  | ||||||
| not-zip-safe |  | ||||||
| entry_points.txt |  | ||||||
| dependency_links.txt |  | ||||||
| PKG-INFO |  | ||||||
| top_level.txt |  | ||||||
| requires.txt |  | ||||||
| SOURCES.txt |  | ||||||
| @ -1 +0,0 @@ | |||||||
| 
 |  | ||||||
| @ -1,4 +0,0 @@ | |||||||
| MarkupSafe>=0.23 |  | ||||||
| 
 |  | ||||||
| [i18n] |  | ||||||
| Babel>=0.8 |  | ||||||
| @ -1 +0,0 @@ | |||||||
| jinja2 |  | ||||||
| @ -1,36 +0,0 @@ | |||||||
| 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 %} |  | ||||||
|       <ul> |  | ||||||
|       {% for user in users %} |  | ||||||
|         <li><a href="{{ user.url }}">{{ user.username }}</a></li> |  | ||||||
|       {% endfor %} |  | ||||||
|       </ul> |  | ||||||
|     {% 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/ |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| @ -1 +0,0 @@ | |||||||
| pip |  | ||||||
| @ -1,31 +0,0 @@ | |||||||
| Copyright (c) 2009 by the Jinja Team, see AUTHORS for more details. |  | ||||||
| 
 |  | ||||||
| Some rights reserved. |  | ||||||
| 
 |  | ||||||
| Redistribution and use in source and binary forms, with or without |  | ||||||
| modification, are permitted provided that the following conditions are |  | ||||||
| met: |  | ||||||
| 
 |  | ||||||
|     * Redistributions of source code must retain the above copyright |  | ||||||
|       notice, this list of conditions and the following disclaimer. |  | ||||||
| 
 |  | ||||||
|     * Redistributions in binary form must reproduce the above |  | ||||||
|       copyright notice, this list of conditions and the following |  | ||||||
|       disclaimer in the documentation and/or other materials provided |  | ||||||
|       with the distribution. |  | ||||||
| 
 |  | ||||||
|     * The names of the contributors may not be used to endorse or |  | ||||||
|       promote products derived from this software without specific |  | ||||||
|       prior written permission. |  | ||||||
| 
 |  | ||||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |  | ||||||
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |  | ||||||
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |  | ||||||
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |  | ||||||
| OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |  | ||||||
| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |  | ||||||
| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |  | ||||||
| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |  | ||||||
| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |  | ||||||
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |  | ||||||
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |  | ||||||
| @ -1,65 +0,0 @@ | |||||||
| Metadata-Version: 2.0 |  | ||||||
| Name: Jinja2 |  | ||||||
| Version: 2.9.6 |  | ||||||
| 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 |  | ||||||
| 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 :: 2 |  | ||||||
| Classifier: Programming Language :: Python :: 2.6 |  | ||||||
| Classifier: Programming Language :: Python :: 2.7 |  | ||||||
| Classifier: Programming Language :: Python :: 3 |  | ||||||
| Classifier: Programming Language :: Python :: 3.3 |  | ||||||
| Classifier: Programming Language :: Python :: 3.4 |  | ||||||
| Classifier: Programming Language :: Python :: 3.5 |  | ||||||
| Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content |  | ||||||
| Classifier: Topic :: Software Development :: Libraries :: Python Modules |  | ||||||
| Classifier: Topic :: Text Processing :: Markup :: HTML |  | ||||||
| Requires-Dist: MarkupSafe (>=0.23) |  | ||||||
| Provides-Extra: i18n |  | ||||||
| Requires-Dist: Babel (>=0.8); extra == 'i18n' |  | ||||||
| 
 |  | ||||||
| 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 %} |  | ||||||
|       <ul> |  | ||||||
|       {% for user in users %} |  | ||||||
|         <li><a href="{{ user.url }}">{{ user.username }}</a></li> |  | ||||||
|       {% endfor %} |  | ||||||
|       </ul> |  | ||||||
|     {% 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/ |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| @ -1,59 +0,0 @@ | |||||||
| jinja2/__init__.py,sha256=Cx_UnJO4i_GqvKQsOu__mvGE_eMJSsBqITa26irtg5A,2565 |  | ||||||
| jinja2/_compat.py,sha256=xP60CE5Qr8FTYcDE1f54tbZLKGvMwYml4-8T7Q4KG9k,2596 |  | ||||||
| jinja2/_stringdefs.py,sha256=PYtqTmmWIhjXlFBoH-eE6fJkQvlu7nxUyQ2YlFB97VA,589381 |  | ||||||
| jinja2/asyncfilters.py,sha256=cTDPvrS8Hp_IkwsZ1m9af_lr5nHysw7uTa5gV0NmZVE,4144 |  | ||||||
| jinja2/asyncsupport.py,sha256=ZJO1Fdd9R93sDLrk6TZNuMQGgtuDmpTlENNRkLwZF7c,7765 |  | ||||||
| jinja2/bccache.py,sha256=0xoVw0R9nj3vtzPl9g-zB5BKTLFJ7FFMq2ABbn1IkCI,12793 |  | ||||||
| jinja2/compiler.py,sha256=lE5owyPwT1cGGZxWyzQtZLW7Uj1g3Vw1oVtBU8Uc_uM,62929 |  | ||||||
| jinja2/constants.py,sha256=uwwV8ZUhHhacAuz5PTwckfsbqBaqM7aKfyJL7kGX5YQ,1626 |  | ||||||
| jinja2/debug.py,sha256=UqEbKb4zofBABwvyA77Kr0-5IAQawKqC9t8ZeTIzpGU,12038 |  | ||||||
| jinja2/defaults.py,sha256=GvVEQqIRvRMCbQF2NZSr0mlEN8lxvGixU5wIIAeRe1A,1323 |  | ||||||
| jinja2/environment.py,sha256=z91L_efdYs-KNs6DBxQWDyYncOwOqn_0J4M5CfFj0Q8,50848 |  | ||||||
| jinja2/exceptions.py,sha256=_Rj-NVi98Q6AiEjYQOsP8dEIdu5AlmRHzcSNOPdWix4,4428 |  | ||||||
| jinja2/ext.py,sha256=9xq8fd_QPBIe4Z7hE1XawB7f1EDHrVZjpb2JiRTiG94,23867 |  | ||||||
| jinja2/filters.py,sha256=1OYGhyN84yVmFUIOwJNRV_StqTCfPhnRLfJTmWbEe_8,33424 |  | ||||||
| jinja2/idtracking.py,sha256=HHcCOMsQhCrrjwYAmikKqq_XetXLovCjXAThh9WbRAc,8760 |  | ||||||
| jinja2/lexer.py,sha256=W4A830e-fj12zRT6rL7H91F4D6xwED5LjR8iMxjWuVQ,28238 |  | ||||||
| jinja2/loaders.py,sha256=xiTuURKAEObyym0nU8PCIXu_Qp8fn0AJ5oIADUUm-5Q,17382 |  | ||||||
| jinja2/meta.py,sha256=fmKHxkmZYAOm9QyWWy8EMd6eefAIh234rkBMW2X4ZR8,4340 |  | ||||||
| jinja2/nodes.py,sha256=4_Ucxbkohtj4BAlpV0w_MpVmIxJNaVXDTBb4EHBA2JI,29392 |  | ||||||
| jinja2/optimizer.py,sha256=MsdlFACJ0FRdPtjmCAdt7JQ9SGrXFaDNUaslsWQaG3M,1722 |  | ||||||
| jinja2/parser.py,sha256=3tc82qO1Ovs9och_PjirbAmnWNT77n4wWjIQ8pEVKvU,35465 |  | ||||||
| jinja2/runtime.py,sha256=axkTQXg2-oc_Cm35NEMDDas3Jbq3ATxNrDOEa5v3wIw,26835 |  | ||||||
| jinja2/sandbox.py,sha256=Jx4MTxly8KvdkSWyui_kHY1_ZZ0RAQL4ojAy1KDRyK0,16707 |  | ||||||
| jinja2/tests.py,sha256=iFuUTbUYv7TFffq2aTswCRdIhQ6wyrby1YevChVPqkE,4428 |  | ||||||
| jinja2/utils.py,sha256=BIFqeXXsCUSjWx6MEwYhY6V4tXzVNs9WRXfB60MA9HY,19941 |  | ||||||
| jinja2/visitor.py,sha256=JD1H1cANA29JcntFfN5fPyqQxB4bI4wC00BzZa-XHks,3316 |  | ||||||
| Jinja2-2.9.6.dist-info/DESCRIPTION.rst,sha256=CXIS1UnPSk5_lZBS6Lb8ko-3lqGfjsiUwNBLXCTj2lc,975 |  | ||||||
| Jinja2-2.9.6.dist-info/entry_points.txt,sha256=NdzVcOrqyNyKDxD09aERj__3bFx2paZhizFDsKmVhiA,72 |  | ||||||
| Jinja2-2.9.6.dist-info/LICENSE.txt,sha256=JvzUNv3Io51EiWrAPm8d_SXjhJnEjyDYvB3Tvwqqils,1554 |  | ||||||
| Jinja2-2.9.6.dist-info/METADATA,sha256=53LSXlqC86JTyLSPsDyAOmyV4pXIzzmmZoUXz7ogytA,2172 |  | ||||||
| Jinja2-2.9.6.dist-info/metadata.json,sha256=vzvX25T4hwMOe1EIOBo9rpfiZerOB_KVLcplGG_qYtE,1394 |  | ||||||
| Jinja2-2.9.6.dist-info/RECORD,, |  | ||||||
| Jinja2-2.9.6.dist-info/top_level.txt,sha256=PkeVWtLb3-CqjWi1fO29OCbj55EhX_chhKrCdrVe_zs,7 |  | ||||||
| Jinja2-2.9.6.dist-info/WHEEL,sha256=AvR0WeTpDaxT645bl5FQxUK6NPsTls2ttpcGJg3j1Xg,110 |  | ||||||
| Jinja2-2.9.6.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 |  | ||||||
| jinja2/_compat.pyc,, |  | ||||||
| jinja2/sandbox.pyc,, |  | ||||||
| jinja2/_stringdefs.pyc,, |  | ||||||
| jinja2/bccache.pyc,, |  | ||||||
| jinja2/runtime.pyc,, |  | ||||||
| jinja2/utils.pyc,, |  | ||||||
| jinja2/parser.pyc,, |  | ||||||
| jinja2/debug.pyc,, |  | ||||||
| jinja2/lexer.pyc,, |  | ||||||
| jinja2/defaults.pyc,, |  | ||||||
| jinja2/visitor.pyc,, |  | ||||||
| jinja2/nodes.pyc,, |  | ||||||
| jinja2/environment.pyc,, |  | ||||||
| jinja2/compiler.pyc,, |  | ||||||
| jinja2/exceptions.pyc,, |  | ||||||
| jinja2/filters.pyc,, |  | ||||||
| jinja2/__init__.pyc,, |  | ||||||
| jinja2/meta.pyc,, |  | ||||||
| jinja2/loaders.pyc,, |  | ||||||
| jinja2/ext.pyc,, |  | ||||||
| jinja2/optimizer.pyc,, |  | ||||||
| jinja2/constants.pyc,, |  | ||||||
| jinja2/tests.pyc,, |  | ||||||
| jinja2/idtracking.pyc,, |  | ||||||
| @ -1,6 +0,0 @@ | |||||||
| Wheel-Version: 1.0 |  | ||||||
| Generator: bdist_wheel (0.24.0) |  | ||||||
| Root-Is-Purelib: true |  | ||||||
| Tag: py2-none-any |  | ||||||
| Tag: py3-none-any |  | ||||||
| 
 |  | ||||||
| @ -1,4 +0,0 @@ | |||||||
| 
 |  | ||||||
|     [babel.extractors] |  | ||||||
|     jinja2 = jinja2.ext:babel_extract[i18n] |  | ||||||
|      |  | ||||||
| @ -1 +0,0 @@ | |||||||
| {"license": "BSD", "name": "Jinja2", "metadata_version": "2.0", "generator": "bdist_wheel (0.24.0)", "summary": "A small but fast and easy to use stand-alone template engine written in pure python.", "run_requires": [{"requires": ["Babel (>=0.8)"], "extra": "i18n"}, {"requires": ["MarkupSafe (>=0.23)"]}], "version": "2.9.6", "extensions": {"python.details": {"project_urls": {"Home": "http://jinja.pocoo.org/"}, "document_names": {"description": "DESCRIPTION.rst", "license": "LICENSE.txt"}, "contacts": [{"role": "author", "email": "armin.ronacher@active-4.com", "name": "Armin Ronacher"}]}, "python.exports": {"babel.extractors": {"jinja2": "jinja2.ext:babel_extract [i18n]"}}}, "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 :: 2", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Text Processing :: Markup :: HTML"], "extras": ["i18n"]} |  | ||||||
| @ -1 +0,0 @@ | |||||||
| jinja2 |  | ||||||
| @ -1,133 +0,0 @@ | |||||||
| Metadata-Version: 1.1 |  | ||||||
| Name: MarkupSafe |  | ||||||
| Version: 1.0 |  | ||||||
| Summary: Implements a XML/HTML/XHTML Markup safe string for Python |  | ||||||
| Home-page: http://github.com/pallets/markupsafe |  | ||||||
| Author: Armin Ronacher |  | ||||||
| Author-email: armin.ronacher@active-4.com |  | ||||||
| License: BSD |  | ||||||
| Description: MarkupSafe |  | ||||||
|         ========== |  | ||||||
|          |  | ||||||
|         Implements a unicode subclass that supports HTML strings: |  | ||||||
|          |  | ||||||
|         .. code-block:: python |  | ||||||
|          |  | ||||||
|             >>> from markupsafe import Markup, escape |  | ||||||
|             >>> escape("<script>alert(document.cookie);</script>") |  | ||||||
|             Markup(u'<script>alert(document.cookie);</script>') |  | ||||||
|             >>> tmpl = Markup("<em>%s</em>") |  | ||||||
|             >>> tmpl % "Peter > Lustig" |  | ||||||
|             Markup(u'<em>Peter > Lustig</em>') |  | ||||||
|          |  | ||||||
|         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). |  | ||||||
|          |  | ||||||
|         .. code-block:: python |  | ||||||
|          |  | ||||||
|             >>> 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: |  | ||||||
|          |  | ||||||
|         .. code-block:: python |  | ||||||
|          |  | ||||||
|             >>> class Foo(object): |  | ||||||
|             ...  def __html__(self): |  | ||||||
|             ...   return '<strong>Nice</strong>' |  | ||||||
|             ... |  | ||||||
|             >>> escape(Foo()) |  | ||||||
|             Markup(u'<strong>Nice</strong>') |  | ||||||
|             >>> Markup(Foo()) |  | ||||||
|             Markup(u'<strong>Nice</strong>') |  | ||||||
|          |  | ||||||
|         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: |  | ||||||
|          |  | ||||||
|         .. code-block:: python |  | ||||||
|          |  | ||||||
|             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: |  | ||||||
|          |  | ||||||
|         .. code-block:: python |  | ||||||
|          |  | ||||||
|             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('<a href="/user/{0}">{1}</a>').format( |  | ||||||
|                             self.id, |  | ||||||
|                             self.__html__(), |  | ||||||
|                         ) |  | ||||||
|                     elif format_spec: |  | ||||||
|                         raise ValueError('Invalid format spec') |  | ||||||
|                     return self.__html__() |  | ||||||
|          |  | ||||||
|                 def __html__(self): |  | ||||||
|                     return Markup('<span class=user>{0}</span>').format(self.username) |  | ||||||
|          |  | ||||||
|         And to format that user: |  | ||||||
|          |  | ||||||
|         .. code-block:: python |  | ||||||
|          |  | ||||||
|             >>> user = User(1, 'foo') |  | ||||||
|             >>> Markup('<p>User: {0:link}').format(user) |  | ||||||
|             Markup(u'<p>User: <a href="/user/1"><span class=user>foo</span></a>') |  | ||||||
|          |  | ||||||
|         Markupsafe supports Python 2.6, 2.7 and Python 3.3 and higher. |  | ||||||
|          |  | ||||||
| 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 |  | ||||||
| @ -1,18 +0,0 @@ | |||||||
| AUTHORS |  | ||||||
| CHANGES |  | ||||||
| LICENSE |  | ||||||
| MANIFEST.in |  | ||||||
| README.rst |  | ||||||
| setup.cfg |  | ||||||
| setup.py |  | ||||||
| tests.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 |  | ||||||
| @ -1 +0,0 @@ | |||||||
| 
 |  | ||||||
| @ -1,15 +0,0 @@ | |||||||
| ../markupsafe/__init__.py |  | ||||||
| ../markupsafe/_compat.py |  | ||||||
| ../markupsafe/_constants.py |  | ||||||
| ../markupsafe/_native.py |  | ||||||
| ../markupsafe/_speedups.c |  | ||||||
| ../markupsafe/__init__.pyc |  | ||||||
| ../markupsafe/_compat.pyc |  | ||||||
| ../markupsafe/_constants.pyc |  | ||||||
| ../markupsafe/_native.pyc |  | ||||||
| ../markupsafe/_speedups.so |  | ||||||
| dependency_links.txt |  | ||||||
| not-zip-safe |  | ||||||
| PKG-INFO |  | ||||||
| SOURCES.txt |  | ||||||
| top_level.txt |  | ||||||
| @ -1 +0,0 @@ | |||||||
| 
 |  | ||||||
| @ -1 +0,0 @@ | |||||||
| markupsafe |  | ||||||
| @ -1,70 +0,0 @@ | |||||||
| Metadata-Version: 1.1 |  | ||||||
| Name: PyJWT |  | ||||||
| Version: 1.4.1 |  | ||||||
| Summary: JSON Web Token implementation in Python |  | ||||||
| Home-page: http://github.com/jpadilla/pyjwt |  | ||||||
| Author: José Padilla |  | ||||||
| Author-email: hello@jpadilla.com |  | ||||||
| License: MIT |  | ||||||
| Description: # PyJWT |  | ||||||
|          |  | ||||||
|         [![travis-status-image]][travis] |  | ||||||
|         [![appveyor-status-image]][appveyor] |  | ||||||
|         [![pypi-version-image]][pypi] |  | ||||||
|         [![coveralls-status-image]][coveralls] |  | ||||||
|         [![docs-status-image]][docs] |  | ||||||
|          |  | ||||||
|         A Python implementation of [RFC 7519][jwt-spec]. |  | ||||||
|         Original implementation was written by [@progrium][progrium]. |  | ||||||
|          |  | ||||||
|         ## Installing |  | ||||||
|          |  | ||||||
|         ``` |  | ||||||
|         $ pip install PyJWT |  | ||||||
|         ``` |  | ||||||
|          |  | ||||||
|         ## Usage |  | ||||||
|          |  | ||||||
|         ```python |  | ||||||
|         >>> import jwt |  | ||||||
|         >>> encoded = jwt.encode({'some': 'payload'}, 'secret', algorithm='HS256') |  | ||||||
|         'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.4twFt5NiznN84AWoo1d7KO1T_yoc0Z6XOpOVswacPZg' |  | ||||||
|          |  | ||||||
|         >>> jwt.decode(encoded, 'secret', algorithms=['HS256']) |  | ||||||
|         {'some': 'payload'} |  | ||||||
|         ``` |  | ||||||
|          |  | ||||||
|         ## Tests |  | ||||||
|          |  | ||||||
|         You can run tests from the project root after cloning with: |  | ||||||
|          |  | ||||||
|         ``` |  | ||||||
|         $ python setup.py test |  | ||||||
|         ``` |  | ||||||
|          |  | ||||||
|         [travis-status-image]: https://secure.travis-ci.org/jpadilla/pyjwt.svg?branch=master |  | ||||||
|         [travis]: http://travis-ci.org/jpadilla/pyjwt?branch=master |  | ||||||
|         [appveyor-status-image]: https://ci.appveyor.com/api/projects/status/h8nt70aqtwhht39t?svg=true |  | ||||||
|         [appveyor]: https://ci.appveyor.com/project/jpadilla/pyjwt |  | ||||||
|         [pypi-version-image]: https://img.shields.io/pypi/v/pyjwt.svg |  | ||||||
|         [pypi]: https://pypi.python.org/pypi/pyjwt |  | ||||||
|         [coveralls-status-image]: https://coveralls.io/repos/jpadilla/pyjwt/badge.svg?branch=master |  | ||||||
|         [coveralls]: https://coveralls.io/r/jpadilla/pyjwt?branch=master |  | ||||||
|         [docs-status-image]: https://readthedocs.org/projects/pyjwt/badge/?version=latest |  | ||||||
|         [docs]: http://pyjwt.readthedocs.org |  | ||||||
|         [jwt-spec]: https://tools.ietf.org/html/rfc7519 |  | ||||||
|         [progrium]: https://github.com/progrium |  | ||||||
|          |  | ||||||
| Keywords: jwt json web token security signing |  | ||||||
| Platform: UNKNOWN |  | ||||||
| Classifier: Development Status :: 5 - Production/Stable |  | ||||||
| Classifier: Intended Audience :: Developers |  | ||||||
| Classifier: Natural Language :: English |  | ||||||
| Classifier: License :: OSI Approved :: MIT License |  | ||||||
| Classifier: Programming Language :: Python |  | ||||||
| Classifier: Programming Language :: Python :: 2.6 |  | ||||||
| Classifier: Programming Language :: Python :: 2.7 |  | ||||||
| Classifier: Programming Language :: Python :: 3.3 |  | ||||||
| Classifier: Programming Language :: Python :: 3.4 |  | ||||||
| Classifier: Programming Language :: Python :: 3.5 |  | ||||||
| Classifier: Topic :: Utilities |  | ||||||
| @ -1,49 +0,0 @@ | |||||||
| AUTHORS |  | ||||||
| CHANGELOG.md |  | ||||||
| LICENSE |  | ||||||
| MANIFEST.in |  | ||||||
| README.md |  | ||||||
| setup.cfg |  | ||||||
| setup.py |  | ||||||
| tox.ini |  | ||||||
| PyJWT.egg-info/PKG-INFO |  | ||||||
| PyJWT.egg-info/SOURCES.txt |  | ||||||
| PyJWT.egg-info/dependency_links.txt |  | ||||||
| PyJWT.egg-info/entry_points.txt |  | ||||||
| PyJWT.egg-info/requires.txt |  | ||||||
| PyJWT.egg-info/top_level.txt |  | ||||||
| jwt/__init__.py |  | ||||||
| jwt/__main__.py |  | ||||||
| jwt/algorithms.py |  | ||||||
| jwt/api_jws.py |  | ||||||
| jwt/api_jwt.py |  | ||||||
| jwt/compat.py |  | ||||||
| jwt/exceptions.py |  | ||||||
| jwt/utils.py |  | ||||||
| jwt/contrib/__init__.py |  | ||||||
| jwt/contrib/algorithms/__init__.py |  | ||||||
| jwt/contrib/algorithms/py_ecdsa.py |  | ||||||
| jwt/contrib/algorithms/pycrypto.py |  | ||||||
| tests/__init__.py |  | ||||||
| tests/compat.py |  | ||||||
| tests/test_algorithms.py |  | ||||||
| tests/test_api_jws.py |  | ||||||
| tests/test_api_jwt.py |  | ||||||
| tests/test_compat.py |  | ||||||
| tests/test_exceptions.py |  | ||||||
| tests/test_jwt.py |  | ||||||
| tests/utils.py |  | ||||||
| tests/contrib/__init__.py |  | ||||||
| tests/contrib/test_algorithms.py |  | ||||||
| tests/keys/__init__.py |  | ||||||
| tests/keys/jwk_ec_key.json |  | ||||||
| tests/keys/jwk_ec_pub.json |  | ||||||
| tests/keys/jwk_hmac.json |  | ||||||
| tests/keys/jwk_rsa_key.json |  | ||||||
| tests/keys/jwk_rsa_pub.json |  | ||||||
| tests/keys/testkey2_rsa.pub.pem |  | ||||||
| tests/keys/testkey_ec |  | ||||||
| tests/keys/testkey_ec.pub |  | ||||||
| tests/keys/testkey_rsa |  | ||||||
| tests/keys/testkey_rsa.cer |  | ||||||
| tests/keys/testkey_rsa.pub |  | ||||||
| @ -1 +0,0 @@ | |||||||
| 
 |  | ||||||
| @ -1,3 +0,0 @@ | |||||||
| [console_scripts] |  | ||||||
| jwt = jwt.__main__:main |  | ||||||
| 
 |  | ||||||
| @ -1,31 +0,0 @@ | |||||||
| ../../../../bin/jwt |  | ||||||
| ../jwt/__init__.py |  | ||||||
| ../jwt/__init__.pyc |  | ||||||
| ../jwt/__main__.py |  | ||||||
| ../jwt/__main__.pyc |  | ||||||
| ../jwt/algorithms.py |  | ||||||
| ../jwt/algorithms.pyc |  | ||||||
| ../jwt/api_jws.py |  | ||||||
| ../jwt/api_jws.pyc |  | ||||||
| ../jwt/api_jwt.py |  | ||||||
| ../jwt/api_jwt.pyc |  | ||||||
| ../jwt/compat.py |  | ||||||
| ../jwt/compat.pyc |  | ||||||
| ../jwt/contrib/__init__.py |  | ||||||
| ../jwt/contrib/__init__.pyc |  | ||||||
| ../jwt/contrib/algorithms/__init__.py |  | ||||||
| ../jwt/contrib/algorithms/__init__.pyc |  | ||||||
| ../jwt/contrib/algorithms/py_ecdsa.py |  | ||||||
| ../jwt/contrib/algorithms/py_ecdsa.pyc |  | ||||||
| ../jwt/contrib/algorithms/pycrypto.py |  | ||||||
| ../jwt/contrib/algorithms/pycrypto.pyc |  | ||||||
| ../jwt/exceptions.py |  | ||||||
| ../jwt/exceptions.pyc |  | ||||||
| ../jwt/utils.py |  | ||||||
| ../jwt/utils.pyc |  | ||||||
| PKG-INFO |  | ||||||
| SOURCES.txt |  | ||||||
| dependency_links.txt |  | ||||||
| entry_points.txt |  | ||||||
| requires.txt |  | ||||||
| top_level.txt |  | ||||||
| @ -1,13 +0,0 @@ | |||||||
| 
 |  | ||||||
| [crypto] |  | ||||||
| cryptography |  | ||||||
| 
 |  | ||||||
| [flake8] |  | ||||||
| flake8 |  | ||||||
| flake8-import-order |  | ||||||
| pep8-naming |  | ||||||
| 
 |  | ||||||
| [test] |  | ||||||
| pytest==2.7.3 |  | ||||||
| pytest-cov |  | ||||||
| pytest-runner |  | ||||||
| @ -1 +0,0 @@ | |||||||
| jwt |  | ||||||
| @ -1,104 +0,0 @@ | |||||||
| Metadata-Version: 1.1 |  | ||||||
| Name: Werkzeug |  | ||||||
| Version: 0.14.1 |  | ||||||
| Summary: The comprehensive WSGI web application library. |  | ||||||
| Home-page: https://www.palletsprojects.org/p/werkzeug/ |  | ||||||
| Author: Armin Ronacher |  | ||||||
| Author-email: armin.ronacher@active-4.com |  | ||||||
| License: BSD |  | ||||||
| Description: Werkzeug |  | ||||||
|         ======== |  | ||||||
|          |  | ||||||
|         Werkzeug is a comprehensive `WSGI`_ web application library. It began as |  | ||||||
|         a simple collection of various utilities for WSGI applications and has |  | ||||||
|         become one of the most advanced WSGI utility libraries. |  | ||||||
|          |  | ||||||
|         It includes: |  | ||||||
|          |  | ||||||
|         * An interactive debugger that allows inspecting stack traces and source |  | ||||||
|           code in the browser with an interactive interpreter for any frame in |  | ||||||
|           the stack. |  | ||||||
|         * A full-featured request object with objects to interact with headers, |  | ||||||
|           query args, form data, files, and cookies. |  | ||||||
|         * A response object that can wrap other WSGI applications and handle |  | ||||||
|           streaming data. |  | ||||||
|         * A routing system for matching URLs to endpoints and generating URLs |  | ||||||
|           for endpoints, with an extensible system for capturing variables from |  | ||||||
|           URLs. |  | ||||||
|         * HTTP utilities to handle entity tags, cache control, dates, user |  | ||||||
|           agents, cookies, files, and more. |  | ||||||
|         * A threaded WSGI server for use while developing applications locally. |  | ||||||
|         * A test client for simulating HTTP requests during testing without |  | ||||||
|           requiring running a server. |  | ||||||
|          |  | ||||||
|         Werkzeug is Unicode aware and doesn't enforce any dependencies. It is up |  | ||||||
|         to the developer to choose a template engine, database adapter, and even |  | ||||||
|         how to handle requests. It can be used to build all sorts of end user |  | ||||||
|         applications such as blogs, wikis, or bulletin boards. |  | ||||||
|          |  | ||||||
|         `Flask`_ wraps Werkzeug, using it to handle the details of WSGI while |  | ||||||
|         providing more structure and patterns for defining powerful |  | ||||||
|         applications. |  | ||||||
|          |  | ||||||
|          |  | ||||||
|         Installing |  | ||||||
|         ---------- |  | ||||||
|          |  | ||||||
|         Install and update using `pip`_: |  | ||||||
|          |  | ||||||
|         .. code-block:: text |  | ||||||
|          |  | ||||||
|             pip install -U Werkzeug |  | ||||||
|          |  | ||||||
|          |  | ||||||
|         A Simple Example |  | ||||||
|         ---------------- |  | ||||||
|          |  | ||||||
|         .. code-block:: python |  | ||||||
|          |  | ||||||
|             from werkzeug.wrappers import Request, Response |  | ||||||
|          |  | ||||||
|             @Request.application |  | ||||||
|             def application(request): |  | ||||||
|                 return Response('Hello, World!') |  | ||||||
|          |  | ||||||
|             if __name__ == '__main__': |  | ||||||
|                 from werkzeug.serving import run_simple |  | ||||||
|                 run_simple('localhost', 4000, application) |  | ||||||
|          |  | ||||||
|          |  | ||||||
|         Links |  | ||||||
|         ----- |  | ||||||
|          |  | ||||||
|         * Website: https://www.palletsprojects.com/p/werkzeug/ |  | ||||||
|         * Releases: https://pypi.org/project/Werkzeug/ |  | ||||||
|         * Code: https://github.com/pallets/werkzeug |  | ||||||
|         * Issue tracker: https://github.com/pallets/werkzeug/issues |  | ||||||
|         * Test status: |  | ||||||
|          |  | ||||||
|           * Linux, Mac: https://travis-ci.org/pallets/werkzeug |  | ||||||
|           * Windows: https://ci.appveyor.com/project/davidism/werkzeug |  | ||||||
|          |  | ||||||
|         * Test coverage: https://codecov.io/gh/pallets/werkzeug |  | ||||||
|          |  | ||||||
|         .. _WSGI: https://wsgi.readthedocs.io/en/latest/ |  | ||||||
|         .. _Flask: https://www.palletsprojects.com/p/flask/ |  | ||||||
|         .. _pip: https://pip.pypa.io/en/stable/quickstart/ |  | ||||||
|          |  | ||||||
| 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 :: 2 |  | ||||||
| Classifier: Programming Language :: Python :: 2.6 |  | ||||||
| Classifier: Programming Language :: Python :: 2.7 |  | ||||||
| Classifier: Programming Language :: Python :: 3 |  | ||||||
| Classifier: Programming Language :: Python :: 3.3 |  | ||||||
| Classifier: Programming Language :: Python :: 3.4 |  | ||||||
| Classifier: Programming Language :: Python :: 3.5 |  | ||||||
| Classifier: Programming Language :: Python :: 3.6 |  | ||||||
| Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content |  | ||||||
| Classifier: Topic :: Software Development :: Libraries :: Python Modules |  | ||||||
| @ -1,299 +0,0 @@ | |||||||
| AUTHORS |  | ||||||
| CHANGES.rst |  | ||||||
| LICENSE |  | ||||||
| MANIFEST.in |  | ||||||
| Makefile |  | ||||||
| README.rst |  | ||||||
| setup.cfg |  | ||||||
| setup.py |  | ||||||
| tox.ini |  | ||||||
| Werkzeug.egg-info/PKG-INFO |  | ||||||
| Werkzeug.egg-info/SOURCES.txt |  | ||||||
| Werkzeug.egg-info/dependency_links.txt |  | ||||||
| Werkzeug.egg-info/not-zip-safe |  | ||||||
| Werkzeug.egg-info/requires.txt |  | ||||||
| Werkzeug.egg-info/top_level.txt |  | ||||||
| artwork/.DS_Store |  | ||||||
| artwork/logo.png |  | ||||||
| artwork/logo.svg |  | ||||||
| docs/.DS_Store |  | ||||||
| docs/Makefile |  | ||||||
| docs/changes.rst |  | ||||||
| docs/conf.py |  | ||||||
| docs/contents.rst.inc |  | ||||||
| docs/datastructures.rst |  | ||||||
| docs/debug.rst |  | ||||||
| docs/exceptions.rst |  | ||||||
| docs/filesystem.rst |  | ||||||
| docs/http.rst |  | ||||||
| docs/index.rst |  | ||||||
| docs/installation.rst |  | ||||||
| docs/latexindex.rst |  | ||||||
| docs/levels.rst |  | ||||||
| docs/local.rst |  | ||||||
| docs/logo.pdf |  | ||||||
| docs/make.bat |  | ||||||
| docs/makearchive.py |  | ||||||
| docs/middlewares.rst |  | ||||||
| docs/python3.rst |  | ||||||
| docs/quickstart.rst |  | ||||||
| docs/request_data.rst |  | ||||||
| docs/routing.rst |  | ||||||
| docs/serving.rst |  | ||||||
| docs/terms.rst |  | ||||||
| docs/test.rst |  | ||||||
| docs/transition.rst |  | ||||||
| docs/tutorial.rst |  | ||||||
| docs/unicode.rst |  | ||||||
| docs/urls.rst |  | ||||||
| docs/utils.rst |  | ||||||
| docs/werkzeugext.py |  | ||||||
| docs/werkzeugstyle.sty |  | ||||||
| docs/wrappers.rst |  | ||||||
| docs/wsgi.rst |  | ||||||
| docs/_static/background.png |  | ||||||
| docs/_static/codebackground.png |  | ||||||
| docs/_static/contents.png |  | ||||||
| docs/_static/debug-screenshot.png |  | ||||||
| docs/_static/favicon.ico |  | ||||||
| docs/_static/header.png |  | ||||||
| docs/_static/navigation.png |  | ||||||
| docs/_static/navigation_active.png |  | ||||||
| docs/_static/shortly.png |  | ||||||
| docs/_static/shorty-screenshot.png |  | ||||||
| docs/_static/style.css |  | ||||||
| docs/_static/werkzeug.js |  | ||||||
| docs/_static/werkzeug.png |  | ||||||
| docs/_templates/sidebarintro.html |  | ||||||
| docs/_templates/sidebarlogo.html |  | ||||||
| docs/contrib/atom.rst |  | ||||||
| docs/contrib/cache.rst |  | ||||||
| docs/contrib/fixers.rst |  | ||||||
| docs/contrib/index.rst |  | ||||||
| docs/contrib/iterio.rst |  | ||||||
| docs/contrib/lint.rst |  | ||||||
| docs/contrib/profiler.rst |  | ||||||
| docs/contrib/securecookie.rst |  | ||||||
| docs/contrib/sessions.rst |  | ||||||
| docs/contrib/wrappers.rst |  | ||||||
| docs/deployment/cgi.rst |  | ||||||
| docs/deployment/fastcgi.rst |  | ||||||
| docs/deployment/index.rst |  | ||||||
| docs/deployment/mod_wsgi.rst |  | ||||||
| docs/deployment/proxying.rst |  | ||||||
| examples/README |  | ||||||
| examples/cookieauth.py |  | ||||||
| examples/httpbasicauth.py |  | ||||||
| examples/manage-coolmagic.py |  | ||||||
| examples/manage-couchy.py |  | ||||||
| examples/manage-cupoftee.py |  | ||||||
| examples/manage-i18nurls.py |  | ||||||
| examples/manage-plnt.py |  | ||||||
| examples/manage-shorty.py |  | ||||||
| examples/manage-simplewiki.py |  | ||||||
| examples/manage-webpylike.py |  | ||||||
| examples/upload.py |  | ||||||
| examples/contrib/README |  | ||||||
| examples/contrib/securecookie.py |  | ||||||
| examples/contrib/sessions.py |  | ||||||
| examples/coolmagic/__init__.py |  | ||||||
| examples/coolmagic/application.py |  | ||||||
| examples/coolmagic/helpers.py |  | ||||||
| examples/coolmagic/utils.py |  | ||||||
| examples/coolmagic/public/style.css |  | ||||||
| examples/coolmagic/templates/layout.html |  | ||||||
| examples/coolmagic/templates/static/about.html |  | ||||||
| examples/coolmagic/templates/static/index.html |  | ||||||
| examples/coolmagic/templates/static/not_found.html |  | ||||||
| examples/coolmagic/views/__init__.py |  | ||||||
| examples/coolmagic/views/static.py |  | ||||||
| examples/couchy/README |  | ||||||
| examples/couchy/__init__.py |  | ||||||
| examples/couchy/application.py |  | ||||||
| examples/couchy/models.py |  | ||||||
| examples/couchy/utils.py |  | ||||||
| examples/couchy/views.py |  | ||||||
| examples/couchy/static/style.css |  | ||||||
| examples/couchy/templates/display.html |  | ||||||
| examples/couchy/templates/layout.html |  | ||||||
| examples/couchy/templates/list.html |  | ||||||
| examples/couchy/templates/new.html |  | ||||||
| examples/couchy/templates/not_found.html |  | ||||||
| examples/cupoftee/__init__.py |  | ||||||
| examples/cupoftee/application.py |  | ||||||
| examples/cupoftee/db.py |  | ||||||
| examples/cupoftee/network.py |  | ||||||
| examples/cupoftee/pages.py |  | ||||||
| examples/cupoftee/utils.py |  | ||||||
| examples/cupoftee/shared/content.png |  | ||||||
| examples/cupoftee/shared/down.png |  | ||||||
| examples/cupoftee/shared/favicon.ico |  | ||||||
| examples/cupoftee/shared/header.png |  | ||||||
| examples/cupoftee/shared/logo.png |  | ||||||
| examples/cupoftee/shared/style.css |  | ||||||
| examples/cupoftee/shared/up.png |  | ||||||
| examples/cupoftee/templates/layout.html |  | ||||||
| examples/cupoftee/templates/missingpage.html |  | ||||||
| examples/cupoftee/templates/search.html |  | ||||||
| examples/cupoftee/templates/server.html |  | ||||||
| examples/cupoftee/templates/serverlist.html |  | ||||||
| examples/i18nurls/__init__.py |  | ||||||
| examples/i18nurls/application.py |  | ||||||
| examples/i18nurls/urls.py |  | ||||||
| examples/i18nurls/views.py |  | ||||||
| examples/i18nurls/templates/about.html |  | ||||||
| examples/i18nurls/templates/blog.html |  | ||||||
| examples/i18nurls/templates/index.html |  | ||||||
| examples/i18nurls/templates/layout.html |  | ||||||
| examples/partial/README |  | ||||||
| examples/partial/complex_routing.py |  | ||||||
| examples/plnt/__init__.py |  | ||||||
| examples/plnt/database.py |  | ||||||
| examples/plnt/sync.py |  | ||||||
| examples/plnt/utils.py |  | ||||||
| examples/plnt/views.py |  | ||||||
| examples/plnt/webapp.py |  | ||||||
| examples/plnt/shared/style.css |  | ||||||
| examples/plnt/templates/about.html |  | ||||||
| examples/plnt/templates/index.html |  | ||||||
| examples/plnt/templates/layout.html |  | ||||||
| examples/shortly/shortly.py |  | ||||||
| examples/shortly/static/style.css |  | ||||||
| examples/shortly/templates/404.html |  | ||||||
| examples/shortly/templates/layout.html |  | ||||||
| examples/shortly/templates/new_url.html |  | ||||||
| examples/shortly/templates/short_link_details.html |  | ||||||
| examples/shorty/__init__.py |  | ||||||
| examples/shorty/application.py |  | ||||||
| examples/shorty/models.py |  | ||||||
| examples/shorty/utils.py |  | ||||||
| examples/shorty/views.py |  | ||||||
| examples/shorty/static/style.css |  | ||||||
| examples/shorty/templates/display.html |  | ||||||
| examples/shorty/templates/layout.html |  | ||||||
| examples/shorty/templates/list.html |  | ||||||
| examples/shorty/templates/new.html |  | ||||||
| examples/shorty/templates/not_found.html |  | ||||||
| examples/simplewiki/__init__.py |  | ||||||
| examples/simplewiki/actions.py |  | ||||||
| examples/simplewiki/application.py |  | ||||||
| examples/simplewiki/database.py |  | ||||||
| examples/simplewiki/specialpages.py |  | ||||||
| examples/simplewiki/utils.py |  | ||||||
| examples/simplewiki/shared/style.css |  | ||||||
| examples/simplewiki/templates/action_diff.html |  | ||||||
| examples/simplewiki/templates/action_edit.html |  | ||||||
| examples/simplewiki/templates/action_log.html |  | ||||||
| examples/simplewiki/templates/action_revert.html |  | ||||||
| examples/simplewiki/templates/action_show.html |  | ||||||
| examples/simplewiki/templates/layout.html |  | ||||||
| examples/simplewiki/templates/macros.xml |  | ||||||
| examples/simplewiki/templates/missing_action.html |  | ||||||
| examples/simplewiki/templates/page_index.html |  | ||||||
| examples/simplewiki/templates/page_missing.html |  | ||||||
| examples/simplewiki/templates/recent_changes.html |  | ||||||
| examples/webpylike/example.py |  | ||||||
| examples/webpylike/webpylike.py |  | ||||||
| tests/__init__.py |  | ||||||
| tests/conftest.py |  | ||||||
| tests/test_compat.py |  | ||||||
| tests/test_datastructures.py |  | ||||||
| tests/test_debug.py |  | ||||||
| tests/test_exceptions.py |  | ||||||
| tests/test_formparser.py |  | ||||||
| tests/test_http.py |  | ||||||
| tests/test_internal.py |  | ||||||
| tests/test_local.py |  | ||||||
| tests/test_routing.py |  | ||||||
| tests/test_security.py |  | ||||||
| tests/test_serving.py |  | ||||||
| tests/test_test.py |  | ||||||
| tests/test_urls.py |  | ||||||
| tests/test_utils.py |  | ||||||
| tests/test_wrappers.py |  | ||||||
| tests/test_wsgi.py |  | ||||||
| tests/contrib/__init__.py |  | ||||||
| tests/contrib/test_atom.py |  | ||||||
| tests/contrib/test_cache.py |  | ||||||
| tests/contrib/test_fixers.py |  | ||||||
| tests/contrib/test_iterio.py |  | ||||||
| tests/contrib/test_securecookie.py |  | ||||||
| tests/contrib/test_sessions.py |  | ||||||
| tests/contrib/test_wrappers.py |  | ||||||
| tests/contrib/cache/conftest.py |  | ||||||
| tests/contrib/cache/test_cache.py |  | ||||||
| tests/hypothesis/__init__.py |  | ||||||
| tests/hypothesis/test_urls.py |  | ||||||
| tests/multipart/__init__.py |  | ||||||
| tests/multipart/ie7_full_path_request.txt |  | ||||||
| tests/multipart/test_collect.py |  | ||||||
| tests/multipart/firefox3-2png1txt/file1.png |  | ||||||
| tests/multipart/firefox3-2png1txt/file2.png |  | ||||||
| tests/multipart/firefox3-2png1txt/request.txt |  | ||||||
| tests/multipart/firefox3-2png1txt/text.txt |  | ||||||
| tests/multipart/firefox3-2pnglongtext/file1.png |  | ||||||
| tests/multipart/firefox3-2pnglongtext/file2.png |  | ||||||
| tests/multipart/firefox3-2pnglongtext/request.txt |  | ||||||
| tests/multipart/firefox3-2pnglongtext/text.txt |  | ||||||
| tests/multipart/ie6-2png1txt/file1.png |  | ||||||
| tests/multipart/ie6-2png1txt/file2.png |  | ||||||
| tests/multipart/ie6-2png1txt/request.txt |  | ||||||
| tests/multipart/ie6-2png1txt/text.txt |  | ||||||
| tests/multipart/opera8-2png1txt/file1.png |  | ||||||
| tests/multipart/opera8-2png1txt/file2.png |  | ||||||
| tests/multipart/opera8-2png1txt/request.txt |  | ||||||
| tests/multipart/opera8-2png1txt/text.txt |  | ||||||
| tests/multipart/webkit3-2png1txt/file1.png |  | ||||||
| tests/multipart/webkit3-2png1txt/file2.png |  | ||||||
| tests/multipart/webkit3-2png1txt/request.txt |  | ||||||
| tests/multipart/webkit3-2png1txt/text.txt |  | ||||||
| tests/res/chunked.txt |  | ||||||
| tests/res/test.txt |  | ||||||
| werkzeug/__init__.py |  | ||||||
| werkzeug/_compat.py |  | ||||||
| werkzeug/_internal.py |  | ||||||
| werkzeug/_reloader.py |  | ||||||
| werkzeug/datastructures.py |  | ||||||
| werkzeug/exceptions.py |  | ||||||
| werkzeug/filesystem.py |  | ||||||
| werkzeug/formparser.py |  | ||||||
| werkzeug/http.py |  | ||||||
| werkzeug/local.py |  | ||||||
| werkzeug/posixemulation.py |  | ||||||
| werkzeug/routing.py |  | ||||||
| werkzeug/security.py |  | ||||||
| werkzeug/serving.py |  | ||||||
| werkzeug/test.py |  | ||||||
| werkzeug/testapp.py |  | ||||||
| werkzeug/urls.py |  | ||||||
| werkzeug/useragents.py |  | ||||||
| werkzeug/utils.py |  | ||||||
| werkzeug/websocket.py |  | ||||||
| werkzeug/wrappers.py |  | ||||||
| werkzeug/wsgi.py |  | ||||||
| werkzeug/contrib/__init__.py |  | ||||||
| werkzeug/contrib/atom.py |  | ||||||
| werkzeug/contrib/cache.py |  | ||||||
| werkzeug/contrib/fixers.py |  | ||||||
| werkzeug/contrib/iterio.py |  | ||||||
| werkzeug/contrib/jsrouting.py |  | ||||||
| werkzeug/contrib/limiter.py |  | ||||||
| werkzeug/contrib/lint.py |  | ||||||
| werkzeug/contrib/profiler.py |  | ||||||
| werkzeug/contrib/securecookie.py |  | ||||||
| werkzeug/contrib/sessions.py |  | ||||||
| werkzeug/contrib/testtools.py |  | ||||||
| werkzeug/contrib/wrappers.py |  | ||||||
| werkzeug/debug/__init__.py |  | ||||||
| werkzeug/debug/console.py |  | ||||||
| werkzeug/debug/repr.py |  | ||||||
| werkzeug/debug/tbtools.py |  | ||||||
| werkzeug/debug/shared/FONT_LICENSE |  | ||||||
| werkzeug/debug/shared/console.png |  | ||||||
| werkzeug/debug/shared/debugger.js |  | ||||||
| werkzeug/debug/shared/jquery.js |  | ||||||
| werkzeug/debug/shared/less.png |  | ||||||
| werkzeug/debug/shared/more.png |  | ||||||
| werkzeug/debug/shared/source.png |  | ||||||
| werkzeug/debug/shared/style.css |  | ||||||
| werkzeug/debug/shared/ubuntu.ttf |  | ||||||
| @ -1 +0,0 @@ | |||||||
| 
 |  | ||||||
| @ -1,93 +0,0 @@ | |||||||
| ../werkzeug/_reloader.py |  | ||||||
| ../werkzeug/_internal.py |  | ||||||
| ../werkzeug/serving.py |  | ||||||
| ../werkzeug/local.py |  | ||||||
| ../werkzeug/filesystem.py |  | ||||||
| ../werkzeug/security.py |  | ||||||
| ../werkzeug/__init__.py |  | ||||||
| ../werkzeug/test.py |  | ||||||
| ../werkzeug/formparser.py |  | ||||||
| ../werkzeug/posixemulation.py |  | ||||||
| ../werkzeug/utils.py |  | ||||||
| ../werkzeug/wrappers.py |  | ||||||
| ../werkzeug/routing.py |  | ||||||
| ../werkzeug/http.py |  | ||||||
| ../werkzeug/useragents.py |  | ||||||
| ../werkzeug/exceptions.py |  | ||||||
| ../werkzeug/_compat.py |  | ||||||
| ../werkzeug/datastructures.py |  | ||||||
| ../werkzeug/urls.py |  | ||||||
| ../werkzeug/websocket.py |  | ||||||
| ../werkzeug/wsgi.py |  | ||||||
| ../werkzeug/testapp.py |  | ||||||
| ../werkzeug/contrib/sessions.py |  | ||||||
| ../werkzeug/contrib/cache.py |  | ||||||
| ../werkzeug/contrib/__init__.py |  | ||||||
| ../werkzeug/contrib/testtools.py |  | ||||||
| ../werkzeug/contrib/wrappers.py |  | ||||||
| ../werkzeug/contrib/jsrouting.py |  | ||||||
| ../werkzeug/contrib/fixers.py |  | ||||||
| ../werkzeug/contrib/profiler.py |  | ||||||
| ../werkzeug/contrib/iterio.py |  | ||||||
| ../werkzeug/contrib/atom.py |  | ||||||
| ../werkzeug/contrib/securecookie.py |  | ||||||
| ../werkzeug/contrib/limiter.py |  | ||||||
| ../werkzeug/contrib/lint.py |  | ||||||
| ../werkzeug/debug/console.py |  | ||||||
| ../werkzeug/debug/tbtools.py |  | ||||||
| ../werkzeug/debug/__init__.py |  | ||||||
| ../werkzeug/debug/repr.py |  | ||||||
| ../werkzeug/debug/shared/FONT_LICENSE |  | ||||||
| ../werkzeug/debug/shared/console.png |  | ||||||
| ../werkzeug/debug/shared/debugger.js |  | ||||||
| ../werkzeug/debug/shared/jquery.js |  | ||||||
| ../werkzeug/debug/shared/less.png |  | ||||||
| ../werkzeug/debug/shared/more.png |  | ||||||
| ../werkzeug/debug/shared/source.png |  | ||||||
| ../werkzeug/debug/shared/style.css |  | ||||||
| ../werkzeug/debug/shared/ubuntu.ttf |  | ||||||
| ../werkzeug/_reloader.pyc |  | ||||||
| ../werkzeug/_internal.pyc |  | ||||||
| ../werkzeug/serving.pyc |  | ||||||
| ../werkzeug/local.pyc |  | ||||||
| ../werkzeug/filesystem.pyc |  | ||||||
| ../werkzeug/security.pyc |  | ||||||
| ../werkzeug/__init__.pyc |  | ||||||
| ../werkzeug/test.pyc |  | ||||||
| ../werkzeug/formparser.pyc |  | ||||||
| ../werkzeug/posixemulation.pyc |  | ||||||
| ../werkzeug/utils.pyc |  | ||||||
| ../werkzeug/wrappers.pyc |  | ||||||
| ../werkzeug/routing.pyc |  | ||||||
| ../werkzeug/http.pyc |  | ||||||
| ../werkzeug/useragents.pyc |  | ||||||
| ../werkzeug/exceptions.pyc |  | ||||||
| ../werkzeug/_compat.pyc |  | ||||||
| ../werkzeug/datastructures.pyc |  | ||||||
| ../werkzeug/urls.pyc |  | ||||||
| ../werkzeug/websocket.pyc |  | ||||||
| ../werkzeug/wsgi.pyc |  | ||||||
| ../werkzeug/testapp.pyc |  | ||||||
| ../werkzeug/contrib/sessions.pyc |  | ||||||
| ../werkzeug/contrib/cache.pyc |  | ||||||
| ../werkzeug/contrib/__init__.pyc |  | ||||||
| ../werkzeug/contrib/testtools.pyc |  | ||||||
| ../werkzeug/contrib/wrappers.pyc |  | ||||||
| ../werkzeug/contrib/jsrouting.pyc |  | ||||||
| ../werkzeug/contrib/fixers.pyc |  | ||||||
| ../werkzeug/contrib/profiler.pyc |  | ||||||
| ../werkzeug/contrib/iterio.pyc |  | ||||||
| ../werkzeug/contrib/atom.pyc |  | ||||||
| ../werkzeug/contrib/securecookie.pyc |  | ||||||
| ../werkzeug/contrib/limiter.pyc |  | ||||||
| ../werkzeug/contrib/lint.pyc |  | ||||||
| ../werkzeug/debug/console.pyc |  | ||||||
| ../werkzeug/debug/tbtools.pyc |  | ||||||
| ../werkzeug/debug/__init__.pyc |  | ||||||
| ../werkzeug/debug/repr.pyc |  | ||||||
| PKG-INFO |  | ||||||
| not-zip-safe |  | ||||||
| SOURCES.txt |  | ||||||
| requires.txt |  | ||||||
| top_level.txt |  | ||||||
| dependency_links.txt |  | ||||||
| @ -1 +0,0 @@ | |||||||
| 
 |  | ||||||
| @ -1,12 +0,0 @@ | |||||||
| 
 |  | ||||||
| [dev] |  | ||||||
| pytest |  | ||||||
| coverage |  | ||||||
| tox |  | ||||||
| sphinx |  | ||||||
| 
 |  | ||||||
| [termcolor] |  | ||||||
| termcolor |  | ||||||
| 
 |  | ||||||
| [watchdog] |  | ||||||
| watchdog |  | ||||||
| @ -1 +0,0 @@ | |||||||
| werkzeug |  | ||||||
| @ -1,89 +0,0 @@ | |||||||
| Metadata-Version: 1.1 |  | ||||||
| Name: backports.ssl-match-hostname |  | ||||||
| Version: 3.7.0.1 |  | ||||||
| Summary: The ssl.match_hostname() function from Python 3.5 |  | ||||||
| Home-page: http://bitbucket.org/brandon/backports.ssl_match_hostname |  | ||||||
| Author: Toshio Kuratomi |  | ||||||
| Author-email: toshio@fedoraproject.org |  | ||||||
| License: Python Software Foundation License |  | ||||||
| Description:  |  | ||||||
|         The ssl.match_hostname() function from Python 3.7 |  | ||||||
|         ================================================= |  | ||||||
|          |  | ||||||
|         The Secure Sockets Layer is only actually *secure* |  | ||||||
|         if you check the hostname in the certificate returned |  | ||||||
|         by the server to which you are connecting, |  | ||||||
|         and verify that it matches to hostname |  | ||||||
|         that you are trying to reach. |  | ||||||
|          |  | ||||||
|         But the matching logic, defined in `RFC2818`_, |  | ||||||
|         can be a bit tricky to implement on your own. |  | ||||||
|         So the ``ssl`` package in the Standard Library of Python 3.2 |  | ||||||
|         and greater now includes a ``match_hostname()`` function |  | ||||||
|         for performing this check instead of requiring every application |  | ||||||
|         to implement the check separately. |  | ||||||
|          |  | ||||||
|         This backport brings ``match_hostname()`` to users |  | ||||||
|         of earlier versions of Python. |  | ||||||
|         Simply make this distribution a dependency of your package, |  | ||||||
|         and then use it like this:: |  | ||||||
|          |  | ||||||
|             from backports.ssl_match_hostname import match_hostname, CertificateError |  | ||||||
|             [...] |  | ||||||
|             sslsock = ssl.wrap_socket(sock, ssl_version=ssl.PROTOCOL_SSLv23, |  | ||||||
|                                       cert_reqs=ssl.CERT_REQUIRED, ca_certs=...) |  | ||||||
|             try: |  | ||||||
|                 match_hostname(sslsock.getpeercert(), hostname) |  | ||||||
|             except CertificateError, ce: |  | ||||||
|                 ... |  | ||||||
|          |  | ||||||
|         Brandon Craig Rhodes is merely the packager of this distribution; |  | ||||||
|         the actual code inside comes from Python 3.7 with small changes for |  | ||||||
|         portability. |  | ||||||
|          |  | ||||||
|          |  | ||||||
|         Requirements |  | ||||||
|         ------------ |  | ||||||
|          |  | ||||||
|         * If you need to use this on Python versions earlier than 2.6 you will need to |  | ||||||
|           install the `ssl module`_.  From Python 2.6 upwards ``ssl`` is included in |  | ||||||
|           the Python Standard Library so you do not need to install it separately. |  | ||||||
|          |  | ||||||
|         .. _`ssl module`:: https://pypi.python.org/pypi/ssl |  | ||||||
|          |  | ||||||
|         History |  | ||||||
|         ------- |  | ||||||
|          |  | ||||||
|         * This function was introduced in python-3.2 |  | ||||||
|         * It was updated for python-3.4a1 for a CVE  |  | ||||||
|           (backports-ssl_match_hostname-3.4.0.1) |  | ||||||
|         * It was updated from RFC2818 to RFC 6125 compliance in order to fix another |  | ||||||
|           security flaw for python-3.3.3 and python-3.4a5 |  | ||||||
|           (backports-ssl_match_hostname-3.4.0.2) |  | ||||||
|         * It was updated in python-3.5 to handle IPAddresses in ServerAltName fields |  | ||||||
|           (something that backports.ssl_match_hostname will do if you also install the |  | ||||||
|           ipaddress library from pypi). |  | ||||||
|         * It was updated in python-3.7 to handle IPAddresses without the ipaddress library and dropped |  | ||||||
|           support for partial wildcards |  | ||||||
|          |  | ||||||
|         .. _`ipaddress module`:: https://pypi.python.org/pypi/ipaddress |  | ||||||
|          |  | ||||||
|         .. _RFC2818: http://tools.ietf.org/html/rfc2818.html |  | ||||||
|          |  | ||||||
| Platform: UNKNOWN |  | ||||||
| Classifier: Development Status :: 5 - Production/Stable |  | ||||||
| Classifier: License :: OSI Approved :: Python Software Foundation License |  | ||||||
| Classifier: Programming Language :: Python :: 2.4 |  | ||||||
| Classifier: Programming Language :: Python :: 2.5 |  | ||||||
| Classifier: Programming Language :: Python :: 2.6 |  | ||||||
| Classifier: Programming Language :: Python :: 2.7 |  | ||||||
| Classifier: Programming Language :: Python :: 3 |  | ||||||
| Classifier: Programming Language :: Python :: 3.0 |  | ||||||
| Classifier: Programming Language :: Python :: 3.1 |  | ||||||
| Classifier: Programming Language :: Python :: 3.2 |  | ||||||
| Classifier: Programming Language :: Python :: 3.3 |  | ||||||
| Classifier: Programming Language :: Python :: 3.4 |  | ||||||
| Classifier: Programming Language :: Python :: 3.5 |  | ||||||
| Classifier: Programming Language :: Python :: 3.6 |  | ||||||
| Classifier: Programming Language :: Python :: 3.7 |  | ||||||
| Classifier: Topic :: Security :: Cryptography |  | ||||||
| @ -1,8 +0,0 @@ | |||||||
| README.txt |  | ||||||
| setup.cfg |  | ||||||
| backports/__init__.py |  | ||||||
| backports.ssl_match_hostname.egg-info/PKG-INFO |  | ||||||
| backports.ssl_match_hostname.egg-info/SOURCES.txt |  | ||||||
| backports.ssl_match_hostname.egg-info/dependency_links.txt |  | ||||||
| backports.ssl_match_hostname.egg-info/top_level.txt |  | ||||||
| backports/ssl_match_hostname/__init__.py |  | ||||||
| @ -1 +0,0 @@ | |||||||
| 
 |  | ||||||
| @ -1,8 +0,0 @@ | |||||||
| ../backports/__init__.py |  | ||||||
| ../backports/__init__.pyc |  | ||||||
| ../backports/ssl_match_hostname/__init__.py |  | ||||||
| ../backports/ssl_match_hostname/__init__.pyc |  | ||||||
| PKG-INFO |  | ||||||
| SOURCES.txt |  | ||||||
| dependency_links.txt |  | ||||||
| top_level.txt |  | ||||||
| @ -1 +0,0 @@ | |||||||
| backports |  | ||||||
| @ -1,3 +0,0 @@ | |||||||
| # This is a Python "namespace package" http://www.python.org/dev/peps/pep-0382/ |  | ||||||
| from pkgutil import extend_path |  | ||||||
| __path__ = extend_path(__path__, __name__) |  | ||||||
| @ -1,204 +0,0 @@ | |||||||
| """The match_hostname() function from Python 3.7.0, essential when using SSL.""" |  | ||||||
| 
 |  | ||||||
| import sys |  | ||||||
| import socket as _socket |  | ||||||
| 
 |  | ||||||
| try: |  | ||||||
|     # Divergence: Python-3.7+'s _ssl has this exception type but older Pythons do not |  | ||||||
|     from _ssl import SSLCertVerificationError |  | ||||||
|     CertificateError = SSLCertVerificationError |  | ||||||
| except: |  | ||||||
|     class CertificateError(ValueError): |  | ||||||
|         pass |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| __version__ = '3.7.0.1' |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| # Divergence: Added to deal with ipaddess as bytes on python2 |  | ||||||
| def _to_text(obj): |  | ||||||
|     if isinstance(obj, str) and sys.version_info < (3,): |  | ||||||
|         obj = unicode(obj, encoding='ascii', errors='strict') |  | ||||||
|     elif sys.version_info >= (3,) and isinstance(obj, bytes): |  | ||||||
|         obj = str(obj, encoding='ascii', errors='strict') |  | ||||||
|     return obj |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def _to_bytes(obj): |  | ||||||
|     if isinstance(obj, str) and sys.version_info >= (3,): |  | ||||||
|         obj = bytes(obj, encoding='ascii', errors='strict') |  | ||||||
|     elif sys.version_info < (3,) and isinstance(obj, unicode): |  | ||||||
|         obj = obj.encode('ascii', 'strict') |  | ||||||
|     return obj |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def _dnsname_match(dn, hostname): |  | ||||||
|     """Matching according to RFC 6125, section 6.4.3 |  | ||||||
| 
 |  | ||||||
|     - Hostnames are compared lower case. |  | ||||||
|     - For IDNA, both dn and hostname must be encoded as IDN A-label (ACE). |  | ||||||
|     - Partial wildcards like 'www*.example.org', multiple wildcards, sole |  | ||||||
|       wildcard or wildcards in labels other then the left-most label are not |  | ||||||
|       supported and a CertificateError is raised. |  | ||||||
|     - A wildcard must match at least one character. |  | ||||||
|     """ |  | ||||||
|     if not dn: |  | ||||||
|         return False |  | ||||||
| 
 |  | ||||||
|     wildcards = dn.count('*') |  | ||||||
|     # speed up common case w/o wildcards |  | ||||||
|     if not wildcards: |  | ||||||
|         return dn.lower() == hostname.lower() |  | ||||||
| 
 |  | ||||||
|     if wildcards > 1: |  | ||||||
|         # Divergence .format() to percent formatting for Python < 2.6 |  | ||||||
|         raise CertificateError( |  | ||||||
|             "too many wildcards in certificate DNS name: %s" % repr(dn)) |  | ||||||
| 
 |  | ||||||
|     dn_leftmost, sep, dn_remainder = dn.partition('.') |  | ||||||
| 
 |  | ||||||
|     if '*' in dn_remainder: |  | ||||||
|         # Only match wildcard in leftmost segment. |  | ||||||
|         # Divergence .format() to percent formatting for Python < 2.6 |  | ||||||
|         raise CertificateError( |  | ||||||
|             "wildcard can only be present in the leftmost label: " |  | ||||||
|             "%s." % repr(dn)) |  | ||||||
| 
 |  | ||||||
|     if not sep: |  | ||||||
|         # no right side |  | ||||||
|         # Divergence .format() to percent formatting for Python < 2.6 |  | ||||||
|         raise CertificateError( |  | ||||||
|             "sole wildcard without additional labels are not support: " |  | ||||||
|             "%s." % repr(dn)) |  | ||||||
| 
 |  | ||||||
|     if dn_leftmost != '*': |  | ||||||
|         # no partial wildcard matching |  | ||||||
|         # Divergence .format() to percent formatting for Python < 2.6 |  | ||||||
|         raise CertificateError( |  | ||||||
|             "partial wildcards in leftmost label are not supported: " |  | ||||||
|             "%s." % repr(dn)) |  | ||||||
| 
 |  | ||||||
|     hostname_leftmost, sep, hostname_remainder = hostname.partition('.') |  | ||||||
|     if not hostname_leftmost or not sep: |  | ||||||
|         # wildcard must match at least one char |  | ||||||
|         return False |  | ||||||
|     return dn_remainder.lower() == hostname_remainder.lower() |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def _inet_paton(ipname): |  | ||||||
|     """Try to convert an IP address to packed binary form |  | ||||||
| 
 |  | ||||||
|     Supports IPv4 addresses on all platforms and IPv6 on platforms with IPv6 |  | ||||||
|     support. |  | ||||||
|     """ |  | ||||||
|     # inet_aton() also accepts strings like '1' |  | ||||||
|     # Divergence: We make sure we have native string type for all python versions |  | ||||||
|     try: |  | ||||||
|         b_ipname = _to_bytes(ipname) |  | ||||||
|     except UnicodeError: |  | ||||||
|         raise ValueError("%s must be an all-ascii string." % repr(ipname)) |  | ||||||
| 
 |  | ||||||
|     # Set ipname in native string format |  | ||||||
|     if sys.version_info < (3,): |  | ||||||
|         n_ipname = b_ipname |  | ||||||
|     else: |  | ||||||
|         n_ipname = ipname |  | ||||||
| 
 |  | ||||||
|     if n_ipname.count('.') == 3: |  | ||||||
|         try: |  | ||||||
|             return _socket.inet_aton(n_ipname) |  | ||||||
|         # Divergence: OSError on late python3.  socket.error earlier. |  | ||||||
|         # Null bytes generate ValueError on python3(we want to raise |  | ||||||
|         # ValueError anyway), TypeError # earlier |  | ||||||
|         except (OSError, _socket.error, TypeError): |  | ||||||
|             pass |  | ||||||
| 
 |  | ||||||
|     try: |  | ||||||
|         return _socket.inet_pton(_socket.AF_INET6, n_ipname) |  | ||||||
|     # Divergence: OSError on late python3.  socket.error earlier. |  | ||||||
|     # Null bytes generate ValueError on python3(we want to raise |  | ||||||
|     # ValueError anyway), TypeError # earlier |  | ||||||
|     except (OSError, _socket.error, TypeError): |  | ||||||
|         # Divergence .format() to percent formatting for Python < 2.6 |  | ||||||
|         raise ValueError("%s is neither an IPv4 nor an IP6 " |  | ||||||
|                          "address." % repr(ipname)) |  | ||||||
|     except AttributeError: |  | ||||||
|         # AF_INET6 not available |  | ||||||
|         pass |  | ||||||
| 
 |  | ||||||
|     # Divergence .format() to percent formatting for Python < 2.6 |  | ||||||
|     raise ValueError("%s is not an IPv4 address." % repr(ipname)) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def _ipaddress_match(ipname, host_ip): |  | ||||||
|     """Exact matching of IP addresses. |  | ||||||
| 
 |  | ||||||
|     RFC 6125 explicitly doesn't define an algorithm for this |  | ||||||
|     (section 1.7.2 - "Out of Scope"). |  | ||||||
|     """ |  | ||||||
|     # OpenSSL may add a trailing newline to a subjectAltName's IP address |  | ||||||
|     ip = _inet_paton(ipname.rstrip()) |  | ||||||
|     return ip == host_ip |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def match_hostname(cert, hostname): |  | ||||||
|     """Verify that *cert* (in decoded format as returned by |  | ||||||
|     SSLSocket.getpeercert()) matches the *hostname*.  RFC 2818 and RFC 6125 |  | ||||||
|     rules are followed. |  | ||||||
| 
 |  | ||||||
|     The function matches IP addresses rather than dNSNames if hostname is a |  | ||||||
|     valid ipaddress string. IPv4 addresses are supported on all platforms. |  | ||||||
|     IPv6 addresses are supported on platforms with IPv6 support (AF_INET6 |  | ||||||
|     and inet_pton). |  | ||||||
| 
 |  | ||||||
|     CertificateError is raised on failure. On success, the function |  | ||||||
|     returns nothing. |  | ||||||
|     """ |  | ||||||
|     if not cert: |  | ||||||
|         raise ValueError("empty or no certificate, match_hostname needs a " |  | ||||||
|                          "SSL socket or SSL context with either " |  | ||||||
|                          "CERT_OPTIONAL or CERT_REQUIRED") |  | ||||||
|     try: |  | ||||||
|         # Divergence: Deal with hostname as bytes |  | ||||||
|         host_ip = _inet_paton(_to_text(hostname)) |  | ||||||
|     except ValueError: |  | ||||||
|         # Not an IP address (common case) |  | ||||||
|         host_ip = None |  | ||||||
|     except UnicodeError: |  | ||||||
|         # Divergence: Deal with hostname as byte strings. |  | ||||||
|         # IP addresses should be all ascii, so we consider it not |  | ||||||
|         # an IP address if this fails |  | ||||||
|         host_ip = None |  | ||||||
|     dnsnames = [] |  | ||||||
|     san = cert.get('subjectAltName', ()) |  | ||||||
|     for key, value in san: |  | ||||||
|         if key == 'DNS': |  | ||||||
|             if host_ip is None and _dnsname_match(value, hostname): |  | ||||||
|                 return |  | ||||||
|             dnsnames.append(value) |  | ||||||
|         elif key == 'IP Address': |  | ||||||
|             if host_ip is not None and _ipaddress_match(value, host_ip): |  | ||||||
|                 return |  | ||||||
|             dnsnames.append(value) |  | ||||||
|     if not dnsnames: |  | ||||||
|         # The subject is only checked when there is no dNSName entry |  | ||||||
|         # in subjectAltName |  | ||||||
|         for sub in cert.get('subject', ()): |  | ||||||
|             for key, value in sub: |  | ||||||
|                 # XXX according to RFC 2818, the most specific Common Name |  | ||||||
|                 # must be used. |  | ||||||
|                 if key == 'commonName': |  | ||||||
|                     if _dnsname_match(value, hostname): |  | ||||||
|                         return |  | ||||||
|                     dnsnames.append(value) |  | ||||||
|     if len(dnsnames) > 1: |  | ||||||
|         raise CertificateError("hostname %r " |  | ||||||
|             "doesn't match either of %s" |  | ||||||
|             % (hostname, ', '.join(map(repr, dnsnames)))) |  | ||||||
|     elif len(dnsnames) == 1: |  | ||||||
|         raise CertificateError("hostname %r " |  | ||||||
|             "doesn't match %r" |  | ||||||
|             % (hostname, dnsnames[0])) |  | ||||||
|     else: |  | ||||||
|         raise CertificateError("no appropriate commonName or " |  | ||||||
|             "subjectAltName fields were found") |  | ||||||
| @ -1,10 +0,0 @@ | |||||||
| #!/usr/local/bin/python |  | ||||||
| # EASY-INSTALL-ENTRY-SCRIPT: 'Flask==1.0.2','console_scripts','flask' |  | ||||||
| __requires__ = 'Flask==1.0.2' |  | ||||||
| import sys |  | ||||||
| from pkg_resources import load_entry_point |  | ||||||
| 
 |  | ||||||
| if __name__ == '__main__': |  | ||||||
|     sys.exit( |  | ||||||
|         load_entry_point('Flask==1.0.2', 'console_scripts', 'flask')() |  | ||||||
|     ) |  | ||||||
| @ -1,201 +0,0 @@ | |||||||
| #!/usr/local/bin/python |  | ||||||
| 
 |  | ||||||
| import argparse |  | ||||||
| import code |  | ||||||
| import sys |  | ||||||
| import threading |  | ||||||
| import time |  | ||||||
| import ssl |  | ||||||
| 
 |  | ||||||
| import six |  | ||||||
| from six.moves.urllib.parse import urlparse |  | ||||||
| 
 |  | ||||||
| import websocket |  | ||||||
| 
 |  | ||||||
| try: |  | ||||||
|     import readline |  | ||||||
| except ImportError: |  | ||||||
|     pass |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def get_encoding(): |  | ||||||
|     encoding = getattr(sys.stdin, "encoding", "") |  | ||||||
|     if not encoding: |  | ||||||
|         return "utf-8" |  | ||||||
|     else: |  | ||||||
|         return encoding.lower() |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| OPCODE_DATA = (websocket.ABNF.OPCODE_TEXT, websocket.ABNF.OPCODE_BINARY) |  | ||||||
| ENCODING = get_encoding() |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class VAction(argparse.Action): |  | ||||||
| 
 |  | ||||||
|     def __call__(self, parser, args, values, option_string=None): |  | ||||||
|         if values is None: |  | ||||||
|             values = "1" |  | ||||||
|         try: |  | ||||||
|             values = int(values) |  | ||||||
|         except ValueError: |  | ||||||
|             values = values.count("v") + 1 |  | ||||||
|         setattr(args, self.dest, values) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def parse_args(): |  | ||||||
|     parser = argparse.ArgumentParser(description="WebSocket Simple Dump Tool") |  | ||||||
|     parser.add_argument("url", metavar="ws_url", |  | ||||||
|                         help="websocket url. ex. ws://echo.websocket.org/") |  | ||||||
|     parser.add_argument("-p", "--proxy", |  | ||||||
|                         help="proxy url. ex. http://127.0.0.1:8080") |  | ||||||
|     parser.add_argument("-v", "--verbose", default=0, nargs='?', action=VAction, |  | ||||||
|                         dest="verbose", |  | ||||||
|                         help="set verbose mode. If set to 1, show opcode. " |  | ||||||
|                         "If set to 2, enable to trace  websocket module") |  | ||||||
|     parser.add_argument("-n", "--nocert", action='store_true', |  | ||||||
|                         help="Ignore invalid SSL cert") |  | ||||||
|     parser.add_argument("-r", "--raw", action="store_true", |  | ||||||
|                         help="raw output") |  | ||||||
|     parser.add_argument("-s", "--subprotocols", nargs='*', |  | ||||||
|                         help="Set subprotocols") |  | ||||||
|     parser.add_argument("-o", "--origin", |  | ||||||
|                         help="Set origin") |  | ||||||
|     parser.add_argument("--eof-wait", default=0, type=int, |  | ||||||
|                         help="wait time(second) after 'EOF' received.") |  | ||||||
|     parser.add_argument("-t", "--text", |  | ||||||
|                         help="Send initial text") |  | ||||||
|     parser.add_argument("--timings", action="store_true", |  | ||||||
|                         help="Print timings in seconds") |  | ||||||
|     parser.add_argument("--headers", |  | ||||||
|                         help="Set custom headers. Use ',' as separator") |  | ||||||
| 
 |  | ||||||
|     return parser.parse_args() |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class RawInput: |  | ||||||
| 
 |  | ||||||
|     def raw_input(self, prompt): |  | ||||||
|         if six.PY3: |  | ||||||
|             line = input(prompt) |  | ||||||
|         else: |  | ||||||
|             line = raw_input(prompt) |  | ||||||
| 
 |  | ||||||
|         if ENCODING and ENCODING != "utf-8" and not isinstance(line, six.text_type): |  | ||||||
|             line = line.decode(ENCODING).encode("utf-8") |  | ||||||
|         elif isinstance(line, six.text_type): |  | ||||||
|             line = line.encode("utf-8") |  | ||||||
| 
 |  | ||||||
|         return line |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class InteractiveConsole(RawInput, code.InteractiveConsole): |  | ||||||
| 
 |  | ||||||
|     def write(self, data): |  | ||||||
|         sys.stdout.write("\033[2K\033[E") |  | ||||||
|         # sys.stdout.write("\n") |  | ||||||
|         sys.stdout.write("\033[34m< " + data + "\033[39m") |  | ||||||
|         sys.stdout.write("\n> ") |  | ||||||
|         sys.stdout.flush() |  | ||||||
| 
 |  | ||||||
|     def read(self): |  | ||||||
|         return self.raw_input("> ") |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class NonInteractive(RawInput): |  | ||||||
| 
 |  | ||||||
|     def write(self, data): |  | ||||||
|         sys.stdout.write(data) |  | ||||||
|         sys.stdout.write("\n") |  | ||||||
|         sys.stdout.flush() |  | ||||||
| 
 |  | ||||||
|     def read(self): |  | ||||||
|         return self.raw_input("") |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def main(): |  | ||||||
|     start_time = time.time() |  | ||||||
|     args = parse_args() |  | ||||||
|     if args.verbose > 1: |  | ||||||
|         websocket.enableTrace(True) |  | ||||||
|     options = {} |  | ||||||
|     if args.proxy: |  | ||||||
|         p = urlparse(args.proxy) |  | ||||||
|         options["http_proxy_host"] = p.hostname |  | ||||||
|         options["http_proxy_port"] = p.port |  | ||||||
|     if args.origin: |  | ||||||
|         options["origin"] = args.origin |  | ||||||
|     if args.subprotocols: |  | ||||||
|         options["subprotocols"] = args.subprotocols |  | ||||||
|     opts = {} |  | ||||||
|     if args.nocert: |  | ||||||
|         opts = {"cert_reqs": ssl.CERT_NONE, "check_hostname": False} |  | ||||||
|     if args.headers: |  | ||||||
|         options['header'] = map(str.strip, args.headers.split(',')) |  | ||||||
|     ws = websocket.create_connection(args.url, sslopt=opts, **options) |  | ||||||
|     if args.raw: |  | ||||||
|         console = NonInteractive() |  | ||||||
|     else: |  | ||||||
|         console = InteractiveConsole() |  | ||||||
|         print("Press Ctrl+C to quit") |  | ||||||
| 
 |  | ||||||
|     def recv(): |  | ||||||
|         try: |  | ||||||
|             frame = ws.recv_frame() |  | ||||||
|         except websocket.WebSocketException: |  | ||||||
|             return websocket.ABNF.OPCODE_CLOSE, None |  | ||||||
|         if not frame: |  | ||||||
|             raise websocket.WebSocketException("Not a valid frame %s" % frame) |  | ||||||
|         elif frame.opcode in OPCODE_DATA: |  | ||||||
|             return frame.opcode, frame.data |  | ||||||
|         elif frame.opcode == websocket.ABNF.OPCODE_CLOSE: |  | ||||||
|             ws.send_close() |  | ||||||
|             return frame.opcode, None |  | ||||||
|         elif frame.opcode == websocket.ABNF.OPCODE_PING: |  | ||||||
|             ws.pong(frame.data) |  | ||||||
|             return frame.opcode, frame.data |  | ||||||
| 
 |  | ||||||
|         return frame.opcode, frame.data |  | ||||||
| 
 |  | ||||||
|     def recv_ws(): |  | ||||||
|         while True: |  | ||||||
|             opcode, data = recv() |  | ||||||
|             msg = None |  | ||||||
|             if six.PY3 and opcode == websocket.ABNF.OPCODE_TEXT and isinstance(data, bytes): |  | ||||||
|                 data = str(data, "utf-8") |  | ||||||
|             if not args.verbose and opcode in OPCODE_DATA: |  | ||||||
|                 msg = data |  | ||||||
|             elif args.verbose: |  | ||||||
|                 msg = "%s: %s" % (websocket.ABNF.OPCODE_MAP.get(opcode), data) |  | ||||||
| 
 |  | ||||||
|             if msg is not None: |  | ||||||
|                 if args.timings: |  | ||||||
|                     console.write(str(time.time() - start_time) + ": " + msg) |  | ||||||
|                 else: |  | ||||||
|                     console.write(msg) |  | ||||||
| 
 |  | ||||||
|             if opcode == websocket.ABNF.OPCODE_CLOSE: |  | ||||||
|                 break |  | ||||||
| 
 |  | ||||||
|     thread = threading.Thread(target=recv_ws) |  | ||||||
|     thread.daemon = True |  | ||||||
|     thread.start() |  | ||||||
| 
 |  | ||||||
|     if args.text: |  | ||||||
|         ws.send(args.text) |  | ||||||
| 
 |  | ||||||
|     while True: |  | ||||||
|         try: |  | ||||||
|             message = console.read() |  | ||||||
|             ws.send(message) |  | ||||||
|         except KeyboardInterrupt: |  | ||||||
|             return |  | ||||||
|         except EOFError: |  | ||||||
|             time.sleep(args.eof_wait) |  | ||||||
|             return |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| if __name__ == "__main__": |  | ||||||
|     try: |  | ||||||
|         main() |  | ||||||
|     except Exception as e: |  | ||||||
|         print(e) |  | ||||||
| @ -1,13 +0,0 @@ | |||||||
| Metadata-Version: 1.1 |  | ||||||
| Name: click |  | ||||||
| Version: 6.7 |  | ||||||
| Summary: A simple wrapper around optparse for powerful command line utilities. |  | ||||||
| Home-page: http://github.com/mitsuhiko/click |  | ||||||
| Author: Armin Ronacher |  | ||||||
| Author-email: armin.ronacher@active-4.com |  | ||||||
| License: UNKNOWN |  | ||||||
| Description: UNKNOWN |  | ||||||
| Platform: UNKNOWN |  | ||||||
| Classifier: License :: OSI Approved :: BSD License |  | ||||||
| Classifier: Programming Language :: Python |  | ||||||
| Classifier: Programming Language :: Python :: 3 |  | ||||||
| @ -1,114 +0,0 @@ | |||||||
| CHANGES |  | ||||||
| LICENSE |  | ||||||
| MANIFEST.in |  | ||||||
| Makefile |  | ||||||
| README |  | ||||||
| setup.cfg |  | ||||||
| setup.py |  | ||||||
| artwork/logo.svg |  | ||||||
| click/__init__.py |  | ||||||
| click/_bashcomplete.py |  | ||||||
| click/_compat.py |  | ||||||
| click/_termui_impl.py |  | ||||||
| click/_textwrap.py |  | ||||||
| click/_unicodefun.py |  | ||||||
| click/_winconsole.py |  | ||||||
| click/core.py |  | ||||||
| click/decorators.py |  | ||||||
| click/exceptions.py |  | ||||||
| click/formatting.py |  | ||||||
| click/globals.py |  | ||||||
| click/parser.py |  | ||||||
| click/termui.py |  | ||||||
| click/testing.py |  | ||||||
| click/types.py |  | ||||||
| click/utils.py |  | ||||||
| click.egg-info/PKG-INFO |  | ||||||
| click.egg-info/SOURCES.txt |  | ||||||
| click.egg-info/dependency_links.txt |  | ||||||
| click.egg-info/top_level.txt |  | ||||||
| docs/Makefile |  | ||||||
| docs/advanced.rst |  | ||||||
| docs/api.rst |  | ||||||
| docs/arguments.rst |  | ||||||
| docs/bashcomplete.rst |  | ||||||
| docs/changelog.rst |  | ||||||
| docs/clickdoctools.py |  | ||||||
| docs/commands.rst |  | ||||||
| docs/complex.rst |  | ||||||
| docs/conf.py |  | ||||||
| docs/contrib.rst |  | ||||||
| docs/documentation.rst |  | ||||||
| docs/exceptions.rst |  | ||||||
| docs/index.rst |  | ||||||
| docs/license.rst |  | ||||||
| docs/make.bat |  | ||||||
| docs/options.rst |  | ||||||
| docs/parameters.rst |  | ||||||
| docs/prompts.rst |  | ||||||
| docs/python3.rst |  | ||||||
| docs/quickstart.rst |  | ||||||
| docs/setuptools.rst |  | ||||||
| docs/testing.rst |  | ||||||
| docs/upgrading.rst |  | ||||||
| docs/utils.rst |  | ||||||
| docs/why.rst |  | ||||||
| docs/wincmd.rst |  | ||||||
| docs/_static/click-small.png |  | ||||||
| docs/_static/click-small@2x.png |  | ||||||
| docs/_static/click.png |  | ||||||
| docs/_static/click@2x.png |  | ||||||
| docs/_templates/sidebarintro.html |  | ||||||
| docs/_templates/sidebarlogo.html |  | ||||||
| examples/README |  | ||||||
| examples/aliases/README |  | ||||||
| examples/aliases/aliases.ini |  | ||||||
| examples/aliases/aliases.py |  | ||||||
| examples/aliases/setup.py |  | ||||||
| examples/colors/README |  | ||||||
| examples/colors/colors.py |  | ||||||
| examples/colors/setup.py |  | ||||||
| examples/complex/README |  | ||||||
| examples/complex/setup.py |  | ||||||
| examples/complex/complex/__init__.py |  | ||||||
| examples/complex/complex/cli.py |  | ||||||
| examples/complex/complex/commands/__init__.py |  | ||||||
| examples/complex/complex/commands/cmd_init.py |  | ||||||
| examples/complex/complex/commands/cmd_status.py |  | ||||||
| examples/imagepipe/.gitignore |  | ||||||
| examples/imagepipe/README |  | ||||||
| examples/imagepipe/example01.jpg |  | ||||||
| examples/imagepipe/example02.jpg |  | ||||||
| examples/imagepipe/imagepipe.py |  | ||||||
| examples/imagepipe/setup.py |  | ||||||
| examples/inout/README |  | ||||||
| examples/inout/inout.py |  | ||||||
| examples/inout/setup.py |  | ||||||
| examples/naval/README |  | ||||||
| examples/naval/naval.py |  | ||||||
| examples/naval/setup.py |  | ||||||
| examples/repo/README |  | ||||||
| examples/repo/repo.py |  | ||||||
| examples/repo/setup.py |  | ||||||
| examples/termui/README |  | ||||||
| examples/termui/setup.py |  | ||||||
| examples/termui/termui.py |  | ||||||
| examples/validation/README |  | ||||||
| examples/validation/setup.py |  | ||||||
| examples/validation/validation.py |  | ||||||
| tests/conftest.py |  | ||||||
| tests/test_arguments.py |  | ||||||
| tests/test_bashcomplete.py |  | ||||||
| tests/test_basic.py |  | ||||||
| tests/test_chain.py |  | ||||||
| tests/test_commands.py |  | ||||||
| tests/test_compat.py |  | ||||||
| tests/test_context.py |  | ||||||
| tests/test_defaults.py |  | ||||||
| tests/test_formatting.py |  | ||||||
| tests/test_imports.py |  | ||||||
| tests/test_normalization.py |  | ||||||
| tests/test_options.py |  | ||||||
| tests/test_termui.py |  | ||||||
| tests/test_testing.py |  | ||||||
| tests/test_utils.py |  | ||||||
| @ -1 +0,0 @@ | |||||||
| 
 |  | ||||||
| @ -1,38 +0,0 @@ | |||||||
| ../click/exceptions.py |  | ||||||
| ../click/testing.py |  | ||||||
| ../click/decorators.py |  | ||||||
| ../click/parser.py |  | ||||||
| ../click/formatting.py |  | ||||||
| ../click/globals.py |  | ||||||
| ../click/_termui_impl.py |  | ||||||
| ../click/__init__.py |  | ||||||
| ../click/_compat.py |  | ||||||
| ../click/_winconsole.py |  | ||||||
| ../click/_unicodefun.py |  | ||||||
| ../click/_textwrap.py |  | ||||||
| ../click/_bashcomplete.py |  | ||||||
| ../click/core.py |  | ||||||
| ../click/types.py |  | ||||||
| ../click/termui.py |  | ||||||
| ../click/utils.py |  | ||||||
| ../click/exceptions.pyc |  | ||||||
| ../click/testing.pyc |  | ||||||
| ../click/decorators.pyc |  | ||||||
| ../click/parser.pyc |  | ||||||
| ../click/formatting.pyc |  | ||||||
| ../click/globals.pyc |  | ||||||
| ../click/_termui_impl.pyc |  | ||||||
| ../click/__init__.pyc |  | ||||||
| ../click/_compat.pyc |  | ||||||
| ../click/_winconsole.pyc |  | ||||||
| ../click/_unicodefun.pyc |  | ||||||
| ../click/_textwrap.pyc |  | ||||||
| ../click/_bashcomplete.pyc |  | ||||||
| ../click/core.pyc |  | ||||||
| ../click/types.pyc |  | ||||||
| ../click/termui.pyc |  | ||||||
| ../click/utils.pyc |  | ||||||
| SOURCES.txt |  | ||||||
| top_level.txt |  | ||||||
| PKG-INFO |  | ||||||
| dependency_links.txt |  | ||||||
| @ -1 +0,0 @@ | |||||||
| click |  | ||||||
| @ -1,98 +0,0 @@ | |||||||
| # -*- coding: utf-8 -*- |  | ||||||
| """ |  | ||||||
|     click |  | ||||||
|     ~~~~~ |  | ||||||
| 
 |  | ||||||
|     Click is a simple Python module that wraps the stdlib's optparse to make |  | ||||||
|     writing command line scripts fun.  Unlike other modules, it's based around |  | ||||||
|     a simple API that does not come with too much magic and is composable. |  | ||||||
| 
 |  | ||||||
|     In case optparse ever gets removed from the stdlib, it will be shipped by |  | ||||||
|     this module. |  | ||||||
| 
 |  | ||||||
|     :copyright: (c) 2014 by Armin Ronacher. |  | ||||||
|     :license: BSD, see LICENSE for more details. |  | ||||||
| """ |  | ||||||
| 
 |  | ||||||
| # Core classes |  | ||||||
| from .core import Context, BaseCommand, Command, MultiCommand, Group, \ |  | ||||||
|      CommandCollection, Parameter, Option, Argument |  | ||||||
| 
 |  | ||||||
| # Globals |  | ||||||
| from .globals import get_current_context |  | ||||||
| 
 |  | ||||||
| # Decorators |  | ||||||
| from .decorators import pass_context, pass_obj, make_pass_decorator, \ |  | ||||||
|      command, group, argument, option, confirmation_option, \ |  | ||||||
|      password_option, version_option, help_option |  | ||||||
| 
 |  | ||||||
| # Types |  | ||||||
| from .types import ParamType, File, Path, Choice, IntRange, Tuple, \ |  | ||||||
|      STRING, INT, FLOAT, BOOL, UUID, UNPROCESSED |  | ||||||
| 
 |  | ||||||
| # Utilities |  | ||||||
| from .utils import echo, get_binary_stream, get_text_stream, open_file, \ |  | ||||||
|      format_filename, get_app_dir, get_os_args |  | ||||||
| 
 |  | ||||||
| # Terminal functions |  | ||||||
| from .termui import prompt, confirm, get_terminal_size, echo_via_pager, \ |  | ||||||
|      progressbar, clear, style, unstyle, secho, edit, launch, getchar, \ |  | ||||||
|      pause |  | ||||||
| 
 |  | ||||||
| # Exceptions |  | ||||||
| from .exceptions import ClickException, UsageError, BadParameter, \ |  | ||||||
|      FileError, Abort, NoSuchOption, BadOptionUsage, BadArgumentUsage, \ |  | ||||||
|      MissingParameter |  | ||||||
| 
 |  | ||||||
| # Formatting |  | ||||||
| from .formatting import HelpFormatter, wrap_text |  | ||||||
| 
 |  | ||||||
| # Parsing |  | ||||||
| from .parser import OptionParser |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| __all__ = [ |  | ||||||
|     # Core classes |  | ||||||
|     'Context', 'BaseCommand', 'Command', 'MultiCommand', 'Group', |  | ||||||
|     'CommandCollection', 'Parameter', 'Option', 'Argument', |  | ||||||
| 
 |  | ||||||
|     # Globals |  | ||||||
|     'get_current_context', |  | ||||||
| 
 |  | ||||||
|     # Decorators |  | ||||||
|     'pass_context', 'pass_obj', 'make_pass_decorator', 'command', 'group', |  | ||||||
|     'argument', 'option', 'confirmation_option', 'password_option', |  | ||||||
|     'version_option', 'help_option', |  | ||||||
| 
 |  | ||||||
|     # Types |  | ||||||
|     'ParamType', 'File', 'Path', 'Choice', 'IntRange', 'Tuple', 'STRING', |  | ||||||
|     'INT', 'FLOAT', 'BOOL', 'UUID', 'UNPROCESSED', |  | ||||||
| 
 |  | ||||||
|     # Utilities |  | ||||||
|     'echo', 'get_binary_stream', 'get_text_stream', 'open_file', |  | ||||||
|     'format_filename', 'get_app_dir', 'get_os_args', |  | ||||||
| 
 |  | ||||||
|     # Terminal functions |  | ||||||
|     'prompt', 'confirm', 'get_terminal_size', 'echo_via_pager', |  | ||||||
|     'progressbar', 'clear', 'style', 'unstyle', 'secho', 'edit', 'launch', |  | ||||||
|     'getchar', 'pause', |  | ||||||
| 
 |  | ||||||
|     # Exceptions |  | ||||||
|     'ClickException', 'UsageError', 'BadParameter', 'FileError', |  | ||||||
|     'Abort', 'NoSuchOption', 'BadOptionUsage', 'BadArgumentUsage', |  | ||||||
|     'MissingParameter', |  | ||||||
| 
 |  | ||||||
|     # Formatting |  | ||||||
|     'HelpFormatter', 'wrap_text', |  | ||||||
| 
 |  | ||||||
|     # Parsing |  | ||||||
|     'OptionParser', |  | ||||||
| ] |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| # Controls if click should emit the warning about the use of unicode |  | ||||||
| # literals. |  | ||||||
| disable_unicode_literals_warning = False |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| __version__ = '6.7' |  | ||||||
| @ -1,83 +0,0 @@ | |||||||
| import os |  | ||||||
| import re |  | ||||||
| from .utils import echo |  | ||||||
| from .parser import split_arg_string |  | ||||||
| from .core import MultiCommand, Option |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| COMPLETION_SCRIPT = ''' |  | ||||||
| %(complete_func)s() { |  | ||||||
|     COMPREPLY=( $( env COMP_WORDS="${COMP_WORDS[*]}" \\ |  | ||||||
|                    COMP_CWORD=$COMP_CWORD \\ |  | ||||||
|                    %(autocomplete_var)s=complete $1 ) ) |  | ||||||
|     return 0 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| complete -F %(complete_func)s -o default %(script_names)s |  | ||||||
| ''' |  | ||||||
| 
 |  | ||||||
| _invalid_ident_char_re = re.compile(r'[^a-zA-Z0-9_]') |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def get_completion_script(prog_name, complete_var): |  | ||||||
|     cf_name = _invalid_ident_char_re.sub('', prog_name.replace('-', '_')) |  | ||||||
|     return (COMPLETION_SCRIPT % { |  | ||||||
|         'complete_func': '_%s_completion' % cf_name, |  | ||||||
|         'script_names': prog_name, |  | ||||||
|         'autocomplete_var': complete_var, |  | ||||||
|     }).strip() + ';' |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def resolve_ctx(cli, prog_name, args): |  | ||||||
|     ctx = cli.make_context(prog_name, args, resilient_parsing=True) |  | ||||||
|     while ctx.protected_args + ctx.args and isinstance(ctx.command, MultiCommand): |  | ||||||
|         a = ctx.protected_args + ctx.args |  | ||||||
|         cmd = ctx.command.get_command(ctx, a[0]) |  | ||||||
|         if cmd is None: |  | ||||||
|             return None |  | ||||||
|         ctx = cmd.make_context(a[0], a[1:], parent=ctx, resilient_parsing=True) |  | ||||||
|     return ctx |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def get_choices(cli, prog_name, args, incomplete): |  | ||||||
|     ctx = resolve_ctx(cli, prog_name, args) |  | ||||||
|     if ctx is None: |  | ||||||
|         return |  | ||||||
| 
 |  | ||||||
|     choices = [] |  | ||||||
|     if incomplete and not incomplete[:1].isalnum(): |  | ||||||
|         for param in ctx.command.params: |  | ||||||
|             if not isinstance(param, Option): |  | ||||||
|                 continue |  | ||||||
|             choices.extend(param.opts) |  | ||||||
|             choices.extend(param.secondary_opts) |  | ||||||
|     elif isinstance(ctx.command, MultiCommand): |  | ||||||
|         choices.extend(ctx.command.list_commands(ctx)) |  | ||||||
| 
 |  | ||||||
|     for item in choices: |  | ||||||
|         if item.startswith(incomplete): |  | ||||||
|             yield item |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def do_complete(cli, prog_name): |  | ||||||
|     cwords = split_arg_string(os.environ['COMP_WORDS']) |  | ||||||
|     cword = int(os.environ['COMP_CWORD']) |  | ||||||
|     args = cwords[1:cword] |  | ||||||
|     try: |  | ||||||
|         incomplete = cwords[cword] |  | ||||||
|     except IndexError: |  | ||||||
|         incomplete = '' |  | ||||||
| 
 |  | ||||||
|     for item in get_choices(cli, prog_name, args, incomplete): |  | ||||||
|         echo(item) |  | ||||||
| 
 |  | ||||||
|     return True |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def bashcomplete(cli, prog_name, complete_var, complete_instr): |  | ||||||
|     if complete_instr == 'source': |  | ||||||
|         echo(get_completion_script(prog_name, complete_var)) |  | ||||||
|         return True |  | ||||||
|     elif complete_instr == 'complete': |  | ||||||
|         return do_complete(cli, prog_name) |  | ||||||
|     return False |  | ||||||
| @ -1,648 +0,0 @@ | |||||||
| import re |  | ||||||
| import io |  | ||||||
| import os |  | ||||||
| import sys |  | ||||||
| import codecs |  | ||||||
| from weakref import WeakKeyDictionary |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| PY2 = sys.version_info[0] == 2 |  | ||||||
| WIN = sys.platform.startswith('win') |  | ||||||
| DEFAULT_COLUMNS = 80 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| _ansi_re = re.compile('\033\[((?:\d|;)*)([a-zA-Z])') |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def get_filesystem_encoding(): |  | ||||||
|     return sys.getfilesystemencoding() or sys.getdefaultencoding() |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def _make_text_stream(stream, encoding, errors): |  | ||||||
|     if encoding is None: |  | ||||||
|         encoding = get_best_encoding(stream) |  | ||||||
|     if errors is None: |  | ||||||
|         errors = 'replace' |  | ||||||
|     return _NonClosingTextIOWrapper(stream, encoding, errors, |  | ||||||
|                                     line_buffering=True) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def is_ascii_encoding(encoding): |  | ||||||
|     """Checks if a given encoding is ascii.""" |  | ||||||
|     try: |  | ||||||
|         return codecs.lookup(encoding).name == 'ascii' |  | ||||||
|     except LookupError: |  | ||||||
|         return False |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def get_best_encoding(stream): |  | ||||||
|     """Returns the default stream encoding if not found.""" |  | ||||||
|     rv = getattr(stream, 'encoding', None) or sys.getdefaultencoding() |  | ||||||
|     if is_ascii_encoding(rv): |  | ||||||
|         return 'utf-8' |  | ||||||
|     return rv |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class _NonClosingTextIOWrapper(io.TextIOWrapper): |  | ||||||
| 
 |  | ||||||
|     def __init__(self, stream, encoding, errors, **extra): |  | ||||||
|         self._stream = stream = _FixupStream(stream) |  | ||||||
|         io.TextIOWrapper.__init__(self, stream, encoding, errors, **extra) |  | ||||||
| 
 |  | ||||||
|     # The io module is a place where the Python 3 text behavior |  | ||||||
|     # was forced upon Python 2, so we need to unbreak |  | ||||||
|     # it to look like Python 2. |  | ||||||
|     if PY2: |  | ||||||
|         def write(self, x): |  | ||||||
|             if isinstance(x, str) or is_bytes(x): |  | ||||||
|                 try: |  | ||||||
|                     self.flush() |  | ||||||
|                 except Exception: |  | ||||||
|                     pass |  | ||||||
|                 return self.buffer.write(str(x)) |  | ||||||
|             return io.TextIOWrapper.write(self, x) |  | ||||||
| 
 |  | ||||||
|         def writelines(self, lines): |  | ||||||
|             for line in lines: |  | ||||||
|                 self.write(line) |  | ||||||
| 
 |  | ||||||
|     def __del__(self): |  | ||||||
|         try: |  | ||||||
|             self.detach() |  | ||||||
|         except Exception: |  | ||||||
|             pass |  | ||||||
| 
 |  | ||||||
|     def isatty(self): |  | ||||||
|         # https://bitbucket.org/pypy/pypy/issue/1803 |  | ||||||
|         return self._stream.isatty() |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class _FixupStream(object): |  | ||||||
|     """The new io interface needs more from streams than streams |  | ||||||
|     traditionally implement.  As such, this fix-up code is necessary in |  | ||||||
|     some circumstances. |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     def __init__(self, stream): |  | ||||||
|         self._stream = stream |  | ||||||
| 
 |  | ||||||
|     def __getattr__(self, name): |  | ||||||
|         return getattr(self._stream, name) |  | ||||||
| 
 |  | ||||||
|     def read1(self, size): |  | ||||||
|         f = getattr(self._stream, 'read1', None) |  | ||||||
|         if f is not None: |  | ||||||
|             return f(size) |  | ||||||
|         # We only dispatch to readline instead of read in Python 2 as we |  | ||||||
|         # do not want cause problems with the different implementation |  | ||||||
|         # of line buffering. |  | ||||||
|         if PY2: |  | ||||||
|             return self._stream.readline(size) |  | ||||||
|         return self._stream.read(size) |  | ||||||
| 
 |  | ||||||
|     def readable(self): |  | ||||||
|         x = getattr(self._stream, 'readable', None) |  | ||||||
|         if x is not None: |  | ||||||
|             return x() |  | ||||||
|         try: |  | ||||||
|             self._stream.read(0) |  | ||||||
|         except Exception: |  | ||||||
|             return False |  | ||||||
|         return True |  | ||||||
| 
 |  | ||||||
|     def writable(self): |  | ||||||
|         x = getattr(self._stream, 'writable', None) |  | ||||||
|         if x is not None: |  | ||||||
|             return x() |  | ||||||
|         try: |  | ||||||
|             self._stream.write('') |  | ||||||
|         except Exception: |  | ||||||
|             try: |  | ||||||
|                 self._stream.write(b'') |  | ||||||
|             except Exception: |  | ||||||
|                 return False |  | ||||||
|         return True |  | ||||||
| 
 |  | ||||||
|     def seekable(self): |  | ||||||
|         x = getattr(self._stream, 'seekable', None) |  | ||||||
|         if x is not None: |  | ||||||
|             return x() |  | ||||||
|         try: |  | ||||||
|             self._stream.seek(self._stream.tell()) |  | ||||||
|         except Exception: |  | ||||||
|             return False |  | ||||||
|         return True |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| if PY2: |  | ||||||
|     text_type = unicode |  | ||||||
|     bytes = str |  | ||||||
|     raw_input = raw_input |  | ||||||
|     string_types = (str, unicode) |  | ||||||
|     iteritems = lambda x: x.iteritems() |  | ||||||
|     range_type = xrange |  | ||||||
| 
 |  | ||||||
|     def is_bytes(x): |  | ||||||
|         return isinstance(x, (buffer, bytearray)) |  | ||||||
| 
 |  | ||||||
|     _identifier_re = re.compile(r'^[a-zA-Z_][a-zA-Z0-9_]*$') |  | ||||||
| 
 |  | ||||||
|     # For Windows, we need to force stdout/stdin/stderr to binary if it's |  | ||||||
|     # fetched for that.  This obviously is not the most correct way to do |  | ||||||
|     # it as it changes global state.  Unfortunately, there does not seem to |  | ||||||
|     # be a clear better way to do it as just reopening the file in binary |  | ||||||
|     # mode does not change anything. |  | ||||||
|     # |  | ||||||
|     # An option would be to do what Python 3 does and to open the file as |  | ||||||
|     # binary only, patch it back to the system, and then use a wrapper |  | ||||||
|     # stream that converts newlines.  It's not quite clear what's the |  | ||||||
|     # correct option here. |  | ||||||
|     # |  | ||||||
|     # This code also lives in _winconsole for the fallback to the console |  | ||||||
|     # emulation stream. |  | ||||||
|     # |  | ||||||
|     # There are also Windows environments where the `msvcrt` module is not |  | ||||||
|     # available (which is why we use try-catch instead of the WIN variable |  | ||||||
|     # here), such as the Google App Engine development server on Windows. In |  | ||||||
|     # those cases there is just nothing we can do. |  | ||||||
|     try: |  | ||||||
|         import msvcrt |  | ||||||
|     except ImportError: |  | ||||||
|         set_binary_mode = lambda x: x |  | ||||||
|     else: |  | ||||||
|         def set_binary_mode(f): |  | ||||||
|             try: |  | ||||||
|                 fileno = f.fileno() |  | ||||||
|             except Exception: |  | ||||||
|                 pass |  | ||||||
|             else: |  | ||||||
|                 msvcrt.setmode(fileno, os.O_BINARY) |  | ||||||
|             return f |  | ||||||
| 
 |  | ||||||
|     def isidentifier(x): |  | ||||||
|         return _identifier_re.search(x) is not None |  | ||||||
| 
 |  | ||||||
|     def get_binary_stdin(): |  | ||||||
|         return set_binary_mode(sys.stdin) |  | ||||||
| 
 |  | ||||||
|     def get_binary_stdout(): |  | ||||||
|         return set_binary_mode(sys.stdout) |  | ||||||
| 
 |  | ||||||
|     def get_binary_stderr(): |  | ||||||
|         return set_binary_mode(sys.stderr) |  | ||||||
| 
 |  | ||||||
|     def get_text_stdin(encoding=None, errors=None): |  | ||||||
|         rv = _get_windows_console_stream(sys.stdin, encoding, errors) |  | ||||||
|         if rv is not None: |  | ||||||
|             return rv |  | ||||||
|         return _make_text_stream(sys.stdin, encoding, errors) |  | ||||||
| 
 |  | ||||||
|     def get_text_stdout(encoding=None, errors=None): |  | ||||||
|         rv = _get_windows_console_stream(sys.stdout, encoding, errors) |  | ||||||
|         if rv is not None: |  | ||||||
|             return rv |  | ||||||
|         return _make_text_stream(sys.stdout, encoding, errors) |  | ||||||
| 
 |  | ||||||
|     def get_text_stderr(encoding=None, errors=None): |  | ||||||
|         rv = _get_windows_console_stream(sys.stderr, encoding, errors) |  | ||||||
|         if rv is not None: |  | ||||||
|             return rv |  | ||||||
|         return _make_text_stream(sys.stderr, encoding, errors) |  | ||||||
| 
 |  | ||||||
|     def filename_to_ui(value): |  | ||||||
|         if isinstance(value, bytes): |  | ||||||
|             value = value.decode(get_filesystem_encoding(), 'replace') |  | ||||||
|         return value |  | ||||||
| else: |  | ||||||
|     import io |  | ||||||
|     text_type = str |  | ||||||
|     raw_input = input |  | ||||||
|     string_types = (str,) |  | ||||||
|     range_type = range |  | ||||||
|     isidentifier = lambda x: x.isidentifier() |  | ||||||
|     iteritems = lambda x: iter(x.items()) |  | ||||||
| 
 |  | ||||||
|     def is_bytes(x): |  | ||||||
|         return isinstance(x, (bytes, memoryview, bytearray)) |  | ||||||
| 
 |  | ||||||
|     def _is_binary_reader(stream, default=False): |  | ||||||
|         try: |  | ||||||
|             return isinstance(stream.read(0), bytes) |  | ||||||
|         except Exception: |  | ||||||
|             return default |  | ||||||
|             # This happens in some cases where the stream was already |  | ||||||
|             # closed.  In this case, we assume the default. |  | ||||||
| 
 |  | ||||||
|     def _is_binary_writer(stream, default=False): |  | ||||||
|         try: |  | ||||||
|             stream.write(b'') |  | ||||||
|         except Exception: |  | ||||||
|             try: |  | ||||||
|                 stream.write('') |  | ||||||
|                 return False |  | ||||||
|             except Exception: |  | ||||||
|                 pass |  | ||||||
|             return default |  | ||||||
|         return True |  | ||||||
| 
 |  | ||||||
|     def _find_binary_reader(stream): |  | ||||||
|         # We need to figure out if the given stream is already binary. |  | ||||||
|         # This can happen because the official docs recommend detaching |  | ||||||
|         # the streams to get binary streams.  Some code might do this, so |  | ||||||
|         # we need to deal with this case explicitly. |  | ||||||
|         if _is_binary_reader(stream, False): |  | ||||||
|             return stream |  | ||||||
| 
 |  | ||||||
|         buf = getattr(stream, 'buffer', None) |  | ||||||
| 
 |  | ||||||
|         # Same situation here; this time we assume that the buffer is |  | ||||||
|         # actually binary in case it's closed. |  | ||||||
|         if buf is not None and _is_binary_reader(buf, True): |  | ||||||
|             return buf |  | ||||||
| 
 |  | ||||||
|     def _find_binary_writer(stream): |  | ||||||
|         # We need to figure out if the given stream is already binary. |  | ||||||
|         # This can happen because the official docs recommend detatching |  | ||||||
|         # the streams to get binary streams.  Some code might do this, so |  | ||||||
|         # we need to deal with this case explicitly. |  | ||||||
|         if _is_binary_writer(stream, False): |  | ||||||
|             return stream |  | ||||||
| 
 |  | ||||||
|         buf = getattr(stream, 'buffer', None) |  | ||||||
| 
 |  | ||||||
|         # Same situation here; this time we assume that the buffer is |  | ||||||
|         # actually binary in case it's closed. |  | ||||||
|         if buf is not None and _is_binary_writer(buf, True): |  | ||||||
|             return buf |  | ||||||
| 
 |  | ||||||
|     def _stream_is_misconfigured(stream): |  | ||||||
|         """A stream is misconfigured if its encoding is ASCII.""" |  | ||||||
|         # If the stream does not have an encoding set, we assume it's set |  | ||||||
|         # to ASCII.  This appears to happen in certain unittest |  | ||||||
|         # environments.  It's not quite clear what the correct behavior is |  | ||||||
|         # but this at least will force Click to recover somehow. |  | ||||||
|         return is_ascii_encoding(getattr(stream, 'encoding', None) or 'ascii') |  | ||||||
| 
 |  | ||||||
|     def _is_compatible_text_stream(stream, encoding, errors): |  | ||||||
|         stream_encoding = getattr(stream, 'encoding', None) |  | ||||||
|         stream_errors = getattr(stream, 'errors', None) |  | ||||||
| 
 |  | ||||||
|         # Perfect match. |  | ||||||
|         if stream_encoding == encoding and stream_errors == errors: |  | ||||||
|             return True |  | ||||||
| 
 |  | ||||||
|         # Otherwise, it's only a compatible stream if we did not ask for |  | ||||||
|         # an encoding. |  | ||||||
|         if encoding is None: |  | ||||||
|             return stream_encoding is not None |  | ||||||
| 
 |  | ||||||
|         return False |  | ||||||
| 
 |  | ||||||
|     def _force_correct_text_reader(text_reader, encoding, errors): |  | ||||||
|         if _is_binary_reader(text_reader, False): |  | ||||||
|             binary_reader = text_reader |  | ||||||
|         else: |  | ||||||
|             # If there is no target encoding set, we need to verify that the |  | ||||||
|             # reader is not actually misconfigured. |  | ||||||
|             if encoding is None and not _stream_is_misconfigured(text_reader): |  | ||||||
|                 return text_reader |  | ||||||
| 
 |  | ||||||
|             if _is_compatible_text_stream(text_reader, encoding, errors): |  | ||||||
|                 return text_reader |  | ||||||
| 
 |  | ||||||
|             # If the reader has no encoding, we try to find the underlying |  | ||||||
|             # binary reader for it.  If that fails because the environment is |  | ||||||
|             # misconfigured, we silently go with the same reader because this |  | ||||||
|             # is too common to happen.  In that case, mojibake is better than |  | ||||||
|             # exceptions. |  | ||||||
|             binary_reader = _find_binary_reader(text_reader) |  | ||||||
|             if binary_reader is None: |  | ||||||
|                 return text_reader |  | ||||||
| 
 |  | ||||||
|         # At this point, we default the errors to replace instead of strict |  | ||||||
|         # because nobody handles those errors anyways and at this point |  | ||||||
|         # we're so fundamentally fucked that nothing can repair it. |  | ||||||
|         if errors is None: |  | ||||||
|             errors = 'replace' |  | ||||||
|         return _make_text_stream(binary_reader, encoding, errors) |  | ||||||
| 
 |  | ||||||
|     def _force_correct_text_writer(text_writer, encoding, errors): |  | ||||||
|         if _is_binary_writer(text_writer, False): |  | ||||||
|             binary_writer = text_writer |  | ||||||
|         else: |  | ||||||
|             # If there is no target encoding set, we need to verify that the |  | ||||||
|             # writer is not actually misconfigured. |  | ||||||
|             if encoding is None and not _stream_is_misconfigured(text_writer): |  | ||||||
|                 return text_writer |  | ||||||
| 
 |  | ||||||
|             if _is_compatible_text_stream(text_writer, encoding, errors): |  | ||||||
|                 return text_writer |  | ||||||
| 
 |  | ||||||
|             # If the writer has no encoding, we try to find the underlying |  | ||||||
|             # binary writer for it.  If that fails because the environment is |  | ||||||
|             # misconfigured, we silently go with the same writer because this |  | ||||||
|             # is too common to happen.  In that case, mojibake is better than |  | ||||||
|             # exceptions. |  | ||||||
|             binary_writer = _find_binary_writer(text_writer) |  | ||||||
|             if binary_writer is None: |  | ||||||
|                 return text_writer |  | ||||||
| 
 |  | ||||||
|         # At this point, we default the errors to replace instead of strict |  | ||||||
|         # because nobody handles those errors anyways and at this point |  | ||||||
|         # we're so fundamentally fucked that nothing can repair it. |  | ||||||
|         if errors is None: |  | ||||||
|             errors = 'replace' |  | ||||||
|         return _make_text_stream(binary_writer, encoding, errors) |  | ||||||
| 
 |  | ||||||
|     def get_binary_stdin(): |  | ||||||
|         reader = _find_binary_reader(sys.stdin) |  | ||||||
|         if reader is None: |  | ||||||
|             raise RuntimeError('Was not able to determine binary ' |  | ||||||
|                                'stream for sys.stdin.') |  | ||||||
|         return reader |  | ||||||
| 
 |  | ||||||
|     def get_binary_stdout(): |  | ||||||
|         writer = _find_binary_writer(sys.stdout) |  | ||||||
|         if writer is None: |  | ||||||
|             raise RuntimeError('Was not able to determine binary ' |  | ||||||
|                                'stream for sys.stdout.') |  | ||||||
|         return writer |  | ||||||
| 
 |  | ||||||
|     def get_binary_stderr(): |  | ||||||
|         writer = _find_binary_writer(sys.stderr) |  | ||||||
|         if writer is None: |  | ||||||
|             raise RuntimeError('Was not able to determine binary ' |  | ||||||
|                                'stream for sys.stderr.') |  | ||||||
|         return writer |  | ||||||
| 
 |  | ||||||
|     def get_text_stdin(encoding=None, errors=None): |  | ||||||
|         rv = _get_windows_console_stream(sys.stdin, encoding, errors) |  | ||||||
|         if rv is not None: |  | ||||||
|             return rv |  | ||||||
|         return _force_correct_text_reader(sys.stdin, encoding, errors) |  | ||||||
| 
 |  | ||||||
|     def get_text_stdout(encoding=None, errors=None): |  | ||||||
|         rv = _get_windows_console_stream(sys.stdout, encoding, errors) |  | ||||||
|         if rv is not None: |  | ||||||
|             return rv |  | ||||||
|         return _force_correct_text_writer(sys.stdout, encoding, errors) |  | ||||||
| 
 |  | ||||||
|     def get_text_stderr(encoding=None, errors=None): |  | ||||||
|         rv = _get_windows_console_stream(sys.stderr, encoding, errors) |  | ||||||
|         if rv is not None: |  | ||||||
|             return rv |  | ||||||
|         return _force_correct_text_writer(sys.stderr, encoding, errors) |  | ||||||
| 
 |  | ||||||
|     def filename_to_ui(value): |  | ||||||
|         if isinstance(value, bytes): |  | ||||||
|             value = value.decode(get_filesystem_encoding(), 'replace') |  | ||||||
|         else: |  | ||||||
|             value = value.encode('utf-8', 'surrogateescape') \ |  | ||||||
|                 .decode('utf-8', 'replace') |  | ||||||
|         return value |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def get_streerror(e, default=None): |  | ||||||
|     if hasattr(e, 'strerror'): |  | ||||||
|         msg = e.strerror |  | ||||||
|     else: |  | ||||||
|         if default is not None: |  | ||||||
|             msg = default |  | ||||||
|         else: |  | ||||||
|             msg = str(e) |  | ||||||
|     if isinstance(msg, bytes): |  | ||||||
|         msg = msg.decode('utf-8', 'replace') |  | ||||||
|     return msg |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def open_stream(filename, mode='r', encoding=None, errors='strict', |  | ||||||
|                 atomic=False): |  | ||||||
|     # Standard streams first.  These are simple because they don't need |  | ||||||
|     # special handling for the atomic flag.  It's entirely ignored. |  | ||||||
|     if filename == '-': |  | ||||||
|         if 'w' in mode: |  | ||||||
|             if 'b' in mode: |  | ||||||
|                 return get_binary_stdout(), False |  | ||||||
|             return get_text_stdout(encoding=encoding, errors=errors), False |  | ||||||
|         if 'b' in mode: |  | ||||||
|             return get_binary_stdin(), False |  | ||||||
|         return get_text_stdin(encoding=encoding, errors=errors), False |  | ||||||
| 
 |  | ||||||
|     # Non-atomic writes directly go out through the regular open functions. |  | ||||||
|     if not atomic: |  | ||||||
|         if encoding is None: |  | ||||||
|             return open(filename, mode), True |  | ||||||
|         return io.open(filename, mode, encoding=encoding, errors=errors), True |  | ||||||
| 
 |  | ||||||
|     # Some usability stuff for atomic writes |  | ||||||
|     if 'a' in mode: |  | ||||||
|         raise ValueError( |  | ||||||
|             'Appending to an existing file is not supported, because that ' |  | ||||||
|             'would involve an expensive `copy`-operation to a temporary ' |  | ||||||
|             'file. Open the file in normal `w`-mode and copy explicitly ' |  | ||||||
|             'if that\'s what you\'re after.' |  | ||||||
|         ) |  | ||||||
|     if 'x' in mode: |  | ||||||
|         raise ValueError('Use the `overwrite`-parameter instead.') |  | ||||||
|     if 'w' not in mode: |  | ||||||
|         raise ValueError('Atomic writes only make sense with `w`-mode.') |  | ||||||
| 
 |  | ||||||
|     # Atomic writes are more complicated.  They work by opening a file |  | ||||||
|     # as a proxy in the same folder and then using the fdopen |  | ||||||
|     # functionality to wrap it in a Python file.  Then we wrap it in an |  | ||||||
|     # atomic file that moves the file over on close. |  | ||||||
|     import tempfile |  | ||||||
|     fd, tmp_filename = tempfile.mkstemp(dir=os.path.dirname(filename), |  | ||||||
|                                         prefix='.__atomic-write') |  | ||||||
| 
 |  | ||||||
|     if encoding is not None: |  | ||||||
|         f = io.open(fd, mode, encoding=encoding, errors=errors) |  | ||||||
|     else: |  | ||||||
|         f = os.fdopen(fd, mode) |  | ||||||
| 
 |  | ||||||
|     return _AtomicFile(f, tmp_filename, filename), True |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| # Used in a destructor call, needs extra protection from interpreter cleanup. |  | ||||||
| if hasattr(os, 'replace'): |  | ||||||
|     _replace = os.replace |  | ||||||
|     _can_replace = True |  | ||||||
| else: |  | ||||||
|     _replace = os.rename |  | ||||||
|     _can_replace = not WIN |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class _AtomicFile(object): |  | ||||||
| 
 |  | ||||||
|     def __init__(self, f, tmp_filename, real_filename): |  | ||||||
|         self._f = f |  | ||||||
|         self._tmp_filename = tmp_filename |  | ||||||
|         self._real_filename = real_filename |  | ||||||
|         self.closed = False |  | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def name(self): |  | ||||||
|         return self._real_filename |  | ||||||
| 
 |  | ||||||
|     def close(self, delete=False): |  | ||||||
|         if self.closed: |  | ||||||
|             return |  | ||||||
|         self._f.close() |  | ||||||
|         if not _can_replace: |  | ||||||
|             try: |  | ||||||
|                 os.remove(self._real_filename) |  | ||||||
|             except OSError: |  | ||||||
|                 pass |  | ||||||
|         _replace(self._tmp_filename, self._real_filename) |  | ||||||
|         self.closed = True |  | ||||||
| 
 |  | ||||||
|     def __getattr__(self, name): |  | ||||||
|         return getattr(self._f, name) |  | ||||||
| 
 |  | ||||||
|     def __enter__(self): |  | ||||||
|         return self |  | ||||||
| 
 |  | ||||||
|     def __exit__(self, exc_type, exc_value, tb): |  | ||||||
|         self.close(delete=exc_type is not None) |  | ||||||
| 
 |  | ||||||
|     def __repr__(self): |  | ||||||
|         return repr(self._f) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| auto_wrap_for_ansi = None |  | ||||||
| colorama = None |  | ||||||
| get_winterm_size = None |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def strip_ansi(value): |  | ||||||
|     return _ansi_re.sub('', value) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def should_strip_ansi(stream=None, color=None): |  | ||||||
|     if color is None: |  | ||||||
|         if stream is None: |  | ||||||
|             stream = sys.stdin |  | ||||||
|         return not isatty(stream) |  | ||||||
|     return not color |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| # If we're on Windows, we provide transparent integration through |  | ||||||
| # colorama.  This will make ANSI colors through the echo function |  | ||||||
| # work automatically. |  | ||||||
| if WIN: |  | ||||||
|     # Windows has a smaller terminal |  | ||||||
|     DEFAULT_COLUMNS = 79 |  | ||||||
| 
 |  | ||||||
|     from ._winconsole import _get_windows_console_stream |  | ||||||
| 
 |  | ||||||
|     def _get_argv_encoding(): |  | ||||||
|         import locale |  | ||||||
|         return locale.getpreferredencoding() |  | ||||||
| 
 |  | ||||||
|     if PY2: |  | ||||||
|         def raw_input(prompt=''): |  | ||||||
|             sys.stderr.flush() |  | ||||||
|             if prompt: |  | ||||||
|                 stdout = _default_text_stdout() |  | ||||||
|                 stdout.write(prompt) |  | ||||||
|             stdin = _default_text_stdin() |  | ||||||
|             return stdin.readline().rstrip('\r\n') |  | ||||||
| 
 |  | ||||||
|     try: |  | ||||||
|         import colorama |  | ||||||
|     except ImportError: |  | ||||||
|         pass |  | ||||||
|     else: |  | ||||||
|         _ansi_stream_wrappers = WeakKeyDictionary() |  | ||||||
| 
 |  | ||||||
|         def auto_wrap_for_ansi(stream, color=None): |  | ||||||
|             """This function wraps a stream so that calls through colorama |  | ||||||
|             are issued to the win32 console API to recolor on demand.  It |  | ||||||
|             also ensures to reset the colors if a write call is interrupted |  | ||||||
|             to not destroy the console afterwards. |  | ||||||
|             """ |  | ||||||
|             try: |  | ||||||
|                 cached = _ansi_stream_wrappers.get(stream) |  | ||||||
|             except Exception: |  | ||||||
|                 cached = None |  | ||||||
|             if cached is not None: |  | ||||||
|                 return cached |  | ||||||
|             strip = should_strip_ansi(stream, color) |  | ||||||
|             ansi_wrapper = colorama.AnsiToWin32(stream, strip=strip) |  | ||||||
|             rv = ansi_wrapper.stream |  | ||||||
|             _write = rv.write |  | ||||||
| 
 |  | ||||||
|             def _safe_write(s): |  | ||||||
|                 try: |  | ||||||
|                     return _write(s) |  | ||||||
|                 except: |  | ||||||
|                     ansi_wrapper.reset_all() |  | ||||||
|                     raise |  | ||||||
| 
 |  | ||||||
|             rv.write = _safe_write |  | ||||||
|             try: |  | ||||||
|                 _ansi_stream_wrappers[stream] = rv |  | ||||||
|             except Exception: |  | ||||||
|                 pass |  | ||||||
|             return rv |  | ||||||
| 
 |  | ||||||
|         def get_winterm_size(): |  | ||||||
|             win = colorama.win32.GetConsoleScreenBufferInfo( |  | ||||||
|                 colorama.win32.STDOUT).srWindow |  | ||||||
|             return win.Right - win.Left, win.Bottom - win.Top |  | ||||||
| else: |  | ||||||
|     def _get_argv_encoding(): |  | ||||||
|         return getattr(sys.stdin, 'encoding', None) or get_filesystem_encoding() |  | ||||||
| 
 |  | ||||||
|     _get_windows_console_stream = lambda *x: None |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def term_len(x): |  | ||||||
|     return len(strip_ansi(x)) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def isatty(stream): |  | ||||||
|     try: |  | ||||||
|         return stream.isatty() |  | ||||||
|     except Exception: |  | ||||||
|         return False |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def _make_cached_stream_func(src_func, wrapper_func): |  | ||||||
|     cache = WeakKeyDictionary() |  | ||||||
|     def func(): |  | ||||||
|         stream = src_func() |  | ||||||
|         try: |  | ||||||
|             rv = cache.get(stream) |  | ||||||
|         except Exception: |  | ||||||
|             rv = None |  | ||||||
|         if rv is not None: |  | ||||||
|             return rv |  | ||||||
|         rv = wrapper_func() |  | ||||||
|         try: |  | ||||||
|             cache[stream] = rv |  | ||||||
|         except Exception: |  | ||||||
|             pass |  | ||||||
|         return rv |  | ||||||
|     return func |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| _default_text_stdin = _make_cached_stream_func( |  | ||||||
|     lambda: sys.stdin, get_text_stdin) |  | ||||||
| _default_text_stdout = _make_cached_stream_func( |  | ||||||
|     lambda: sys.stdout, get_text_stdout) |  | ||||||
| _default_text_stderr = _make_cached_stream_func( |  | ||||||
|     lambda: sys.stderr, get_text_stderr) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| binary_streams = { |  | ||||||
|     'stdin': get_binary_stdin, |  | ||||||
|     'stdout': get_binary_stdout, |  | ||||||
|     'stderr': get_binary_stderr, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| text_streams = { |  | ||||||
|     'stdin': get_text_stdin, |  | ||||||
|     'stdout': get_text_stdout, |  | ||||||
|     'stderr': get_text_stderr, |  | ||||||
| } |  | ||||||
| @ -1,547 +0,0 @@ | |||||||
| """ |  | ||||||
|     click._termui_impl |  | ||||||
|     ~~~~~~~~~~~~~~~~~~ |  | ||||||
| 
 |  | ||||||
|     This module contains implementations for the termui module.  To keep the |  | ||||||
|     import time of Click down, some infrequently used functionality is placed |  | ||||||
|     in this module and only imported as needed. |  | ||||||
| 
 |  | ||||||
|     :copyright: (c) 2014 by Armin Ronacher. |  | ||||||
|     :license: BSD, see LICENSE for more details. |  | ||||||
| """ |  | ||||||
| import os |  | ||||||
| import sys |  | ||||||
| import time |  | ||||||
| import math |  | ||||||
| from ._compat import _default_text_stdout, range_type, PY2, isatty, \ |  | ||||||
|      open_stream, strip_ansi, term_len, get_best_encoding, WIN |  | ||||||
| from .utils import echo |  | ||||||
| from .exceptions import ClickException |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| if os.name == 'nt': |  | ||||||
|     BEFORE_BAR = '\r' |  | ||||||
|     AFTER_BAR = '\n' |  | ||||||
| else: |  | ||||||
|     BEFORE_BAR = '\r\033[?25l' |  | ||||||
|     AFTER_BAR = '\033[?25h\n' |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def _length_hint(obj): |  | ||||||
|     """Returns the length hint of an object.""" |  | ||||||
|     try: |  | ||||||
|         return len(obj) |  | ||||||
|     except (AttributeError, TypeError): |  | ||||||
|         try: |  | ||||||
|             get_hint = type(obj).__length_hint__ |  | ||||||
|         except AttributeError: |  | ||||||
|             return None |  | ||||||
|         try: |  | ||||||
|             hint = get_hint(obj) |  | ||||||
|         except TypeError: |  | ||||||
|             return None |  | ||||||
|         if hint is NotImplemented or \ |  | ||||||
|            not isinstance(hint, (int, long)) or \ |  | ||||||
|            hint < 0: |  | ||||||
|             return None |  | ||||||
|         return hint |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class ProgressBar(object): |  | ||||||
| 
 |  | ||||||
|     def __init__(self, iterable, length=None, fill_char='#', empty_char=' ', |  | ||||||
|                  bar_template='%(bar)s', info_sep='  ', show_eta=True, |  | ||||||
|                  show_percent=None, show_pos=False, item_show_func=None, |  | ||||||
|                  label=None, file=None, color=None, width=30): |  | ||||||
|         self.fill_char = fill_char |  | ||||||
|         self.empty_char = empty_char |  | ||||||
|         self.bar_template = bar_template |  | ||||||
|         self.info_sep = info_sep |  | ||||||
|         self.show_eta = show_eta |  | ||||||
|         self.show_percent = show_percent |  | ||||||
|         self.show_pos = show_pos |  | ||||||
|         self.item_show_func = item_show_func |  | ||||||
|         self.label = label or '' |  | ||||||
|         if file is None: |  | ||||||
|             file = _default_text_stdout() |  | ||||||
|         self.file = file |  | ||||||
|         self.color = color |  | ||||||
|         self.width = width |  | ||||||
|         self.autowidth = width == 0 |  | ||||||
| 
 |  | ||||||
|         if length is None: |  | ||||||
|             length = _length_hint(iterable) |  | ||||||
|         if iterable is None: |  | ||||||
|             if length is None: |  | ||||||
|                 raise TypeError('iterable or length is required') |  | ||||||
|             iterable = range_type(length) |  | ||||||
|         self.iter = iter(iterable) |  | ||||||
|         self.length = length |  | ||||||
|         self.length_known = length is not None |  | ||||||
|         self.pos = 0 |  | ||||||
|         self.avg = [] |  | ||||||
|         self.start = self.last_eta = time.time() |  | ||||||
|         self.eta_known = False |  | ||||||
|         self.finished = False |  | ||||||
|         self.max_width = None |  | ||||||
|         self.entered = False |  | ||||||
|         self.current_item = None |  | ||||||
|         self.is_hidden = not isatty(self.file) |  | ||||||
|         self._last_line = None |  | ||||||
| 
 |  | ||||||
|     def __enter__(self): |  | ||||||
|         self.entered = True |  | ||||||
|         self.render_progress() |  | ||||||
|         return self |  | ||||||
| 
 |  | ||||||
|     def __exit__(self, exc_type, exc_value, tb): |  | ||||||
|         self.render_finish() |  | ||||||
| 
 |  | ||||||
|     def __iter__(self): |  | ||||||
|         if not self.entered: |  | ||||||
|             raise RuntimeError('You need to use progress bars in a with block.') |  | ||||||
|         self.render_progress() |  | ||||||
|         return self |  | ||||||
| 
 |  | ||||||
|     def render_finish(self): |  | ||||||
|         if self.is_hidden: |  | ||||||
|             return |  | ||||||
|         self.file.write(AFTER_BAR) |  | ||||||
|         self.file.flush() |  | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def pct(self): |  | ||||||
|         if self.finished: |  | ||||||
|             return 1.0 |  | ||||||
|         return min(self.pos / (float(self.length) or 1), 1.0) |  | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def time_per_iteration(self): |  | ||||||
|         if not self.avg: |  | ||||||
|             return 0.0 |  | ||||||
|         return sum(self.avg) / float(len(self.avg)) |  | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def eta(self): |  | ||||||
|         if self.length_known and not self.finished: |  | ||||||
|             return self.time_per_iteration * (self.length - self.pos) |  | ||||||
|         return 0.0 |  | ||||||
| 
 |  | ||||||
|     def format_eta(self): |  | ||||||
|         if self.eta_known: |  | ||||||
|             t = self.eta + 1 |  | ||||||
|             seconds = t % 60 |  | ||||||
|             t /= 60 |  | ||||||
|             minutes = t % 60 |  | ||||||
|             t /= 60 |  | ||||||
|             hours = t % 24 |  | ||||||
|             t /= 24 |  | ||||||
|             if t > 0: |  | ||||||
|                 days = t |  | ||||||
|                 return '%dd %02d:%02d:%02d' % (days, hours, minutes, seconds) |  | ||||||
|             else: |  | ||||||
|                 return '%02d:%02d:%02d' % (hours, minutes, seconds) |  | ||||||
|         return '' |  | ||||||
| 
 |  | ||||||
|     def format_pos(self): |  | ||||||
|         pos = str(self.pos) |  | ||||||
|         if self.length_known: |  | ||||||
|             pos += '/%s' % self.length |  | ||||||
|         return pos |  | ||||||
| 
 |  | ||||||
|     def format_pct(self): |  | ||||||
|         return ('% 4d%%' % int(self.pct * 100))[1:] |  | ||||||
| 
 |  | ||||||
|     def format_progress_line(self): |  | ||||||
|         show_percent = self.show_percent |  | ||||||
| 
 |  | ||||||
|         info_bits = [] |  | ||||||
|         if self.length_known: |  | ||||||
|             bar_length = int(self.pct * self.width) |  | ||||||
|             bar = self.fill_char * bar_length |  | ||||||
|             bar += self.empty_char * (self.width - bar_length) |  | ||||||
|             if show_percent is None: |  | ||||||
|                 show_percent = not self.show_pos |  | ||||||
|         else: |  | ||||||
|             if self.finished: |  | ||||||
|                 bar = self.fill_char * self.width |  | ||||||
|             else: |  | ||||||
|                 bar = list(self.empty_char * (self.width or 1)) |  | ||||||
|                 if self.time_per_iteration != 0: |  | ||||||
|                     bar[int((math.cos(self.pos * self.time_per_iteration) |  | ||||||
|                         / 2.0 + 0.5) * self.width)] = self.fill_char |  | ||||||
|                 bar = ''.join(bar) |  | ||||||
| 
 |  | ||||||
|         if self.show_pos: |  | ||||||
|             info_bits.append(self.format_pos()) |  | ||||||
|         if show_percent: |  | ||||||
|             info_bits.append(self.format_pct()) |  | ||||||
|         if self.show_eta and self.eta_known and not self.finished: |  | ||||||
|             info_bits.append(self.format_eta()) |  | ||||||
|         if self.item_show_func is not None: |  | ||||||
|             item_info = self.item_show_func(self.current_item) |  | ||||||
|             if item_info is not None: |  | ||||||
|                 info_bits.append(item_info) |  | ||||||
| 
 |  | ||||||
|         return (self.bar_template % { |  | ||||||
|             'label': self.label, |  | ||||||
|             'bar': bar, |  | ||||||
|             'info': self.info_sep.join(info_bits) |  | ||||||
|         }).rstrip() |  | ||||||
| 
 |  | ||||||
|     def render_progress(self): |  | ||||||
|         from .termui import get_terminal_size |  | ||||||
|         nl = False |  | ||||||
| 
 |  | ||||||
|         if self.is_hidden: |  | ||||||
|             buf = [self.label] |  | ||||||
|             nl = True |  | ||||||
|         else: |  | ||||||
|             buf = [] |  | ||||||
|             # Update width in case the terminal has been resized |  | ||||||
|             if self.autowidth: |  | ||||||
|                 old_width = self.width |  | ||||||
|                 self.width = 0 |  | ||||||
|                 clutter_length = term_len(self.format_progress_line()) |  | ||||||
|                 new_width = max(0, get_terminal_size()[0] - clutter_length) |  | ||||||
|                 if new_width < old_width: |  | ||||||
|                     buf.append(BEFORE_BAR) |  | ||||||
|                     buf.append(' ' * self.max_width) |  | ||||||
|                     self.max_width = new_width |  | ||||||
|                 self.width = new_width |  | ||||||
| 
 |  | ||||||
|             clear_width = self.width |  | ||||||
|             if self.max_width is not None: |  | ||||||
|                 clear_width = self.max_width |  | ||||||
| 
 |  | ||||||
|             buf.append(BEFORE_BAR) |  | ||||||
|             line = self.format_progress_line() |  | ||||||
|             line_len = term_len(line) |  | ||||||
|             if self.max_width is None or self.max_width < line_len: |  | ||||||
|                 self.max_width = line_len |  | ||||||
|             buf.append(line) |  | ||||||
| 
 |  | ||||||
|             buf.append(' ' * (clear_width - line_len)) |  | ||||||
|         line = ''.join(buf) |  | ||||||
| 
 |  | ||||||
|         # Render the line only if it changed. |  | ||||||
|         if line != self._last_line: |  | ||||||
|             self._last_line = line |  | ||||||
|             echo(line, file=self.file, color=self.color, nl=nl) |  | ||||||
|             self.file.flush() |  | ||||||
| 
 |  | ||||||
|     def make_step(self, n_steps): |  | ||||||
|         self.pos += n_steps |  | ||||||
|         if self.length_known and self.pos >= self.length: |  | ||||||
|             self.finished = True |  | ||||||
| 
 |  | ||||||
|         if (time.time() - self.last_eta) < 1.0: |  | ||||||
|             return |  | ||||||
| 
 |  | ||||||
|         self.last_eta = time.time() |  | ||||||
|         self.avg = self.avg[-6:] + [-(self.start - time.time()) / (self.pos)] |  | ||||||
| 
 |  | ||||||
|         self.eta_known = self.length_known |  | ||||||
| 
 |  | ||||||
|     def update(self, n_steps): |  | ||||||
|         self.make_step(n_steps) |  | ||||||
|         self.render_progress() |  | ||||||
| 
 |  | ||||||
|     def finish(self): |  | ||||||
|         self.eta_known = 0 |  | ||||||
|         self.current_item = None |  | ||||||
|         self.finished = True |  | ||||||
| 
 |  | ||||||
|     def next(self): |  | ||||||
|         if self.is_hidden: |  | ||||||
|             return next(self.iter) |  | ||||||
|         try: |  | ||||||
|             rv = next(self.iter) |  | ||||||
|             self.current_item = rv |  | ||||||
|         except StopIteration: |  | ||||||
|             self.finish() |  | ||||||
|             self.render_progress() |  | ||||||
|             raise StopIteration() |  | ||||||
|         else: |  | ||||||
|             self.update(1) |  | ||||||
|             return rv |  | ||||||
| 
 |  | ||||||
|     if not PY2: |  | ||||||
|         __next__ = next |  | ||||||
|         del next |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def pager(text, color=None): |  | ||||||
|     """Decide what method to use for paging through text.""" |  | ||||||
|     stdout = _default_text_stdout() |  | ||||||
|     if not isatty(sys.stdin) or not isatty(stdout): |  | ||||||
|         return _nullpager(stdout, text, color) |  | ||||||
|     pager_cmd = (os.environ.get('PAGER', None) or '').strip() |  | ||||||
|     if pager_cmd: |  | ||||||
|         if WIN: |  | ||||||
|             return _tempfilepager(text, pager_cmd, color) |  | ||||||
|         return _pipepager(text, pager_cmd, color) |  | ||||||
|     if os.environ.get('TERM') in ('dumb', 'emacs'): |  | ||||||
|         return _nullpager(stdout, text, color) |  | ||||||
|     if WIN or sys.platform.startswith('os2'): |  | ||||||
|         return _tempfilepager(text, 'more <', color) |  | ||||||
|     if hasattr(os, 'system') and os.system('(less) 2>/dev/null') == 0: |  | ||||||
|         return _pipepager(text, 'less', color) |  | ||||||
| 
 |  | ||||||
|     import tempfile |  | ||||||
|     fd, filename = tempfile.mkstemp() |  | ||||||
|     os.close(fd) |  | ||||||
|     try: |  | ||||||
|         if hasattr(os, 'system') and os.system('more "%s"' % filename) == 0: |  | ||||||
|             return _pipepager(text, 'more', color) |  | ||||||
|         return _nullpager(stdout, text, color) |  | ||||||
|     finally: |  | ||||||
|         os.unlink(filename) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def _pipepager(text, cmd, color): |  | ||||||
|     """Page through text by feeding it to another program.  Invoking a |  | ||||||
|     pager through this might support colors. |  | ||||||
|     """ |  | ||||||
|     import subprocess |  | ||||||
|     env = dict(os.environ) |  | ||||||
| 
 |  | ||||||
|     # If we're piping to less we might support colors under the |  | ||||||
|     # condition that |  | ||||||
|     cmd_detail = cmd.rsplit('/', 1)[-1].split() |  | ||||||
|     if color is None and cmd_detail[0] == 'less': |  | ||||||
|         less_flags = os.environ.get('LESS', '') + ' '.join(cmd_detail[1:]) |  | ||||||
|         if not less_flags: |  | ||||||
|             env['LESS'] = '-R' |  | ||||||
|             color = True |  | ||||||
|         elif 'r' in less_flags or 'R' in less_flags: |  | ||||||
|             color = True |  | ||||||
| 
 |  | ||||||
|     if not color: |  | ||||||
|         text = strip_ansi(text) |  | ||||||
| 
 |  | ||||||
|     c = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, |  | ||||||
|                          env=env) |  | ||||||
|     encoding = get_best_encoding(c.stdin) |  | ||||||
|     try: |  | ||||||
|         c.stdin.write(text.encode(encoding, 'replace')) |  | ||||||
|         c.stdin.close() |  | ||||||
|     except (IOError, KeyboardInterrupt): |  | ||||||
|         pass |  | ||||||
| 
 |  | ||||||
|     # Less doesn't respect ^C, but catches it for its own UI purposes (aborting |  | ||||||
|     # search or other commands inside less). |  | ||||||
|     # |  | ||||||
|     # That means when the user hits ^C, the parent process (click) terminates, |  | ||||||
|     # but less is still alive, paging the output and messing up the terminal. |  | ||||||
|     # |  | ||||||
|     # If the user wants to make the pager exit on ^C, they should set |  | ||||||
|     # `LESS='-K'`. It's not our decision to make. |  | ||||||
|     while True: |  | ||||||
|         try: |  | ||||||
|             c.wait() |  | ||||||
|         except KeyboardInterrupt: |  | ||||||
|             pass |  | ||||||
|         else: |  | ||||||
|             break |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def _tempfilepager(text, cmd, color): |  | ||||||
|     """Page through text by invoking a program on a temporary file.""" |  | ||||||
|     import tempfile |  | ||||||
|     filename = tempfile.mktemp() |  | ||||||
|     if not color: |  | ||||||
|         text = strip_ansi(text) |  | ||||||
|     encoding = get_best_encoding(sys.stdout) |  | ||||||
|     with open_stream(filename, 'wb')[0] as f: |  | ||||||
|         f.write(text.encode(encoding)) |  | ||||||
|     try: |  | ||||||
|         os.system(cmd + ' "' + filename + '"') |  | ||||||
|     finally: |  | ||||||
|         os.unlink(filename) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def _nullpager(stream, text, color): |  | ||||||
|     """Simply print unformatted text.  This is the ultimate fallback.""" |  | ||||||
|     if not color: |  | ||||||
|         text = strip_ansi(text) |  | ||||||
|     stream.write(text) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class Editor(object): |  | ||||||
| 
 |  | ||||||
|     def __init__(self, editor=None, env=None, require_save=True, |  | ||||||
|                  extension='.txt'): |  | ||||||
|         self.editor = editor |  | ||||||
|         self.env = env |  | ||||||
|         self.require_save = require_save |  | ||||||
|         self.extension = extension |  | ||||||
| 
 |  | ||||||
|     def get_editor(self): |  | ||||||
|         if self.editor is not None: |  | ||||||
|             return self.editor |  | ||||||
|         for key in 'VISUAL', 'EDITOR': |  | ||||||
|             rv = os.environ.get(key) |  | ||||||
|             if rv: |  | ||||||
|                 return rv |  | ||||||
|         if WIN: |  | ||||||
|             return 'notepad' |  | ||||||
|         for editor in 'vim', 'nano': |  | ||||||
|             if os.system('which %s >/dev/null 2>&1' % editor) == 0: |  | ||||||
|                 return editor |  | ||||||
|         return 'vi' |  | ||||||
| 
 |  | ||||||
|     def edit_file(self, filename): |  | ||||||
|         import subprocess |  | ||||||
|         editor = self.get_editor() |  | ||||||
|         if self.env: |  | ||||||
|             environ = os.environ.copy() |  | ||||||
|             environ.update(self.env) |  | ||||||
|         else: |  | ||||||
|             environ = None |  | ||||||
|         try: |  | ||||||
|             c = subprocess.Popen('%s "%s"' % (editor, filename), |  | ||||||
|                                  env=environ, shell=True) |  | ||||||
|             exit_code = c.wait() |  | ||||||
|             if exit_code != 0: |  | ||||||
|                 raise ClickException('%s: Editing failed!' % editor) |  | ||||||
|         except OSError as e: |  | ||||||
|             raise ClickException('%s: Editing failed: %s' % (editor, e)) |  | ||||||
| 
 |  | ||||||
|     def edit(self, text): |  | ||||||
|         import tempfile |  | ||||||
| 
 |  | ||||||
|         text = text or '' |  | ||||||
|         if text and not text.endswith('\n'): |  | ||||||
|             text += '\n' |  | ||||||
| 
 |  | ||||||
|         fd, name = tempfile.mkstemp(prefix='editor-', suffix=self.extension) |  | ||||||
|         try: |  | ||||||
|             if WIN: |  | ||||||
|                 encoding = 'utf-8-sig' |  | ||||||
|                 text = text.replace('\n', '\r\n') |  | ||||||
|             else: |  | ||||||
|                 encoding = 'utf-8' |  | ||||||
|             text = text.encode(encoding) |  | ||||||
| 
 |  | ||||||
|             f = os.fdopen(fd, 'wb') |  | ||||||
|             f.write(text) |  | ||||||
|             f.close() |  | ||||||
|             timestamp = os.path.getmtime(name) |  | ||||||
| 
 |  | ||||||
|             self.edit_file(name) |  | ||||||
| 
 |  | ||||||
|             if self.require_save \ |  | ||||||
|                and os.path.getmtime(name) == timestamp: |  | ||||||
|                 return None |  | ||||||
| 
 |  | ||||||
|             f = open(name, 'rb') |  | ||||||
|             try: |  | ||||||
|                 rv = f.read() |  | ||||||
|             finally: |  | ||||||
|                 f.close() |  | ||||||
|             return rv.decode('utf-8-sig').replace('\r\n', '\n') |  | ||||||
|         finally: |  | ||||||
|             os.unlink(name) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def open_url(url, wait=False, locate=False): |  | ||||||
|     import subprocess |  | ||||||
| 
 |  | ||||||
|     def _unquote_file(url): |  | ||||||
|         try: |  | ||||||
|             import urllib |  | ||||||
|         except ImportError: |  | ||||||
|             import urllib |  | ||||||
|         if url.startswith('file://'): |  | ||||||
|             url = urllib.unquote(url[7:]) |  | ||||||
|         return url |  | ||||||
| 
 |  | ||||||
|     if sys.platform == 'darwin': |  | ||||||
|         args = ['open'] |  | ||||||
|         if wait: |  | ||||||
|             args.append('-W') |  | ||||||
|         if locate: |  | ||||||
|             args.append('-R') |  | ||||||
|         args.append(_unquote_file(url)) |  | ||||||
|         null = open('/dev/null', 'w') |  | ||||||
|         try: |  | ||||||
|             return subprocess.Popen(args, stderr=null).wait() |  | ||||||
|         finally: |  | ||||||
|             null.close() |  | ||||||
|     elif WIN: |  | ||||||
|         if locate: |  | ||||||
|             url = _unquote_file(url) |  | ||||||
|             args = 'explorer /select,"%s"' % _unquote_file( |  | ||||||
|                 url.replace('"', '')) |  | ||||||
|         else: |  | ||||||
|             args = 'start %s "" "%s"' % ( |  | ||||||
|                 wait and '/WAIT' or '', url.replace('"', '')) |  | ||||||
|         return os.system(args) |  | ||||||
| 
 |  | ||||||
|     try: |  | ||||||
|         if locate: |  | ||||||
|             url = os.path.dirname(_unquote_file(url)) or '.' |  | ||||||
|         else: |  | ||||||
|             url = _unquote_file(url) |  | ||||||
|         c = subprocess.Popen(['xdg-open', url]) |  | ||||||
|         if wait: |  | ||||||
|             return c.wait() |  | ||||||
|         return 0 |  | ||||||
|     except OSError: |  | ||||||
|         if url.startswith(('http://', 'https://')) and not locate and not wait: |  | ||||||
|             import webbrowser |  | ||||||
|             webbrowser.open(url) |  | ||||||
|             return 0 |  | ||||||
|         return 1 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def _translate_ch_to_exc(ch): |  | ||||||
|     if ch == '\x03': |  | ||||||
|         raise KeyboardInterrupt() |  | ||||||
|     if ch == '\x04': |  | ||||||
|         raise EOFError() |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| if WIN: |  | ||||||
|     import msvcrt |  | ||||||
| 
 |  | ||||||
|     def getchar(echo): |  | ||||||
|         rv = msvcrt.getch() |  | ||||||
|         if echo: |  | ||||||
|             msvcrt.putchar(rv) |  | ||||||
|         _translate_ch_to_exc(rv) |  | ||||||
|         if PY2: |  | ||||||
|             enc = getattr(sys.stdin, 'encoding', None) |  | ||||||
|             if enc is not None: |  | ||||||
|                 rv = rv.decode(enc, 'replace') |  | ||||||
|             else: |  | ||||||
|                 rv = rv.decode('cp1252', 'replace') |  | ||||||
|         return rv |  | ||||||
| else: |  | ||||||
|     import tty |  | ||||||
|     import termios |  | ||||||
| 
 |  | ||||||
|     def getchar(echo): |  | ||||||
|         if not isatty(sys.stdin): |  | ||||||
|             f = open('/dev/tty') |  | ||||||
|             fd = f.fileno() |  | ||||||
|         else: |  | ||||||
|             fd = sys.stdin.fileno() |  | ||||||
|             f = None |  | ||||||
|         try: |  | ||||||
|             old_settings = termios.tcgetattr(fd) |  | ||||||
|             try: |  | ||||||
|                 tty.setraw(fd) |  | ||||||
|                 ch = os.read(fd, 32) |  | ||||||
|                 if echo and isatty(sys.stdout): |  | ||||||
|                     sys.stdout.write(ch) |  | ||||||
|             finally: |  | ||||||
|                 termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) |  | ||||||
|                 sys.stdout.flush() |  | ||||||
|                 if f is not None: |  | ||||||
|                     f.close() |  | ||||||
|         except termios.error: |  | ||||||
|             pass |  | ||||||
|         _translate_ch_to_exc(ch) |  | ||||||
|         return ch.decode(get_best_encoding(sys.stdin), 'replace') |  | ||||||
| @ -1,38 +0,0 @@ | |||||||
| import textwrap |  | ||||||
| from contextlib import contextmanager |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class TextWrapper(textwrap.TextWrapper): |  | ||||||
| 
 |  | ||||||
|     def _handle_long_word(self, reversed_chunks, cur_line, cur_len, width): |  | ||||||
|         space_left = max(width - cur_len, 1) |  | ||||||
| 
 |  | ||||||
|         if self.break_long_words: |  | ||||||
|             last = reversed_chunks[-1] |  | ||||||
|             cut = last[:space_left] |  | ||||||
|             res = last[space_left:] |  | ||||||
|             cur_line.append(cut) |  | ||||||
|             reversed_chunks[-1] = res |  | ||||||
|         elif not cur_line: |  | ||||||
|             cur_line.append(reversed_chunks.pop()) |  | ||||||
| 
 |  | ||||||
|     @contextmanager |  | ||||||
|     def extra_indent(self, indent): |  | ||||||
|         old_initial_indent = self.initial_indent |  | ||||||
|         old_subsequent_indent = self.subsequent_indent |  | ||||||
|         self.initial_indent += indent |  | ||||||
|         self.subsequent_indent += indent |  | ||||||
|         try: |  | ||||||
|             yield |  | ||||||
|         finally: |  | ||||||
|             self.initial_indent = old_initial_indent |  | ||||||
|             self.subsequent_indent = old_subsequent_indent |  | ||||||
| 
 |  | ||||||
|     def indent_only(self, text): |  | ||||||
|         rv = [] |  | ||||||
|         for idx, line in enumerate(text.splitlines()): |  | ||||||
|             indent = self.initial_indent |  | ||||||
|             if idx > 0: |  | ||||||
|                 indent = self.subsequent_indent |  | ||||||
|             rv.append(indent + line) |  | ||||||
|         return '\n'.join(rv) |  | ||||||
| @ -1,118 +0,0 @@ | |||||||
| import os |  | ||||||
| import sys |  | ||||||
| import codecs |  | ||||||
| 
 |  | ||||||
| from ._compat import PY2 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| # If someone wants to vendor click, we want to ensure the |  | ||||||
| # correct package is discovered.  Ideally we could use a |  | ||||||
| # relative import here but unfortunately Python does not |  | ||||||
| # support that. |  | ||||||
| click = sys.modules[__name__.rsplit('.', 1)[0]] |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def _find_unicode_literals_frame(): |  | ||||||
|     import __future__ |  | ||||||
|     frm = sys._getframe(1) |  | ||||||
|     idx = 1 |  | ||||||
|     while frm is not None: |  | ||||||
|         if frm.f_globals.get('__name__', '').startswith('click.'): |  | ||||||
|             frm = frm.f_back |  | ||||||
|             idx += 1 |  | ||||||
|         elif frm.f_code.co_flags & __future__.unicode_literals.compiler_flag: |  | ||||||
|             return idx |  | ||||||
|         else: |  | ||||||
|             break |  | ||||||
|     return 0 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def _check_for_unicode_literals(): |  | ||||||
|     if not __debug__: |  | ||||||
|         return |  | ||||||
|     if not PY2 or click.disable_unicode_literals_warning: |  | ||||||
|         return |  | ||||||
|     bad_frame = _find_unicode_literals_frame() |  | ||||||
|     if bad_frame <= 0: |  | ||||||
|         return |  | ||||||
|     from warnings import warn |  | ||||||
|     warn(Warning('Click detected the use of the unicode_literals ' |  | ||||||
|                  '__future__ import.  This is heavily discouraged ' |  | ||||||
|                  'because it can introduce subtle bugs in your ' |  | ||||||
|                  'code.  You should instead use explicit u"" literals ' |  | ||||||
|                  'for your unicode strings.  For more information see ' |  | ||||||
|                  'http://click.pocoo.org/python3/'), |  | ||||||
|          stacklevel=bad_frame) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def _verify_python3_env(): |  | ||||||
|     """Ensures that the environment is good for unicode on Python 3.""" |  | ||||||
|     if PY2: |  | ||||||
|         return |  | ||||||
|     try: |  | ||||||
|         import locale |  | ||||||
|         fs_enc = codecs.lookup(locale.getpreferredencoding()).name |  | ||||||
|     except Exception: |  | ||||||
|         fs_enc = 'ascii' |  | ||||||
|     if fs_enc != 'ascii': |  | ||||||
|         return |  | ||||||
| 
 |  | ||||||
|     extra = '' |  | ||||||
|     if os.name == 'posix': |  | ||||||
|         import subprocess |  | ||||||
|         rv = subprocess.Popen(['locale', '-a'], stdout=subprocess.PIPE, |  | ||||||
|                               stderr=subprocess.PIPE).communicate()[0] |  | ||||||
|         good_locales = set() |  | ||||||
|         has_c_utf8 = False |  | ||||||
| 
 |  | ||||||
|         # Make sure we're operating on text here. |  | ||||||
|         if isinstance(rv, bytes): |  | ||||||
|             rv = rv.decode('ascii', 'replace') |  | ||||||
| 
 |  | ||||||
|         for line in rv.splitlines(): |  | ||||||
|             locale = line.strip() |  | ||||||
|             if locale.lower().endswith(('.utf-8', '.utf8')): |  | ||||||
|                 good_locales.add(locale) |  | ||||||
|                 if locale.lower() in ('c.utf8', 'c.utf-8'): |  | ||||||
|                     has_c_utf8 = True |  | ||||||
| 
 |  | ||||||
|         extra += '\n\n' |  | ||||||
|         if not good_locales: |  | ||||||
|             extra += ( |  | ||||||
|                 'Additional information: on this system no suitable UTF-8\n' |  | ||||||
|                 'locales were discovered.  This most likely requires resolving\n' |  | ||||||
|                 'by reconfiguring the locale system.' |  | ||||||
|             ) |  | ||||||
|         elif has_c_utf8: |  | ||||||
|             extra += ( |  | ||||||
|                 'This system supports the C.UTF-8 locale which is recommended.\n' |  | ||||||
|                 'You might be able to resolve your issue by exporting the\n' |  | ||||||
|                 'following environment variables:\n\n' |  | ||||||
|                 '    export LC_ALL=C.UTF-8\n' |  | ||||||
|                 '    export LANG=C.UTF-8' |  | ||||||
|             ) |  | ||||||
|         else: |  | ||||||
|             extra += ( |  | ||||||
|                 'This system lists a couple of UTF-8 supporting locales that\n' |  | ||||||
|                 'you can pick from.  The following suitable locales where\n' |  | ||||||
|                 'discovered: %s' |  | ||||||
|             ) % ', '.join(sorted(good_locales)) |  | ||||||
| 
 |  | ||||||
|         bad_locale = None |  | ||||||
|         for locale in os.environ.get('LC_ALL'), os.environ.get('LANG'): |  | ||||||
|             if locale and locale.lower().endswith(('.utf-8', '.utf8')): |  | ||||||
|                 bad_locale = locale |  | ||||||
|             if locale is not None: |  | ||||||
|                 break |  | ||||||
|         if bad_locale is not None: |  | ||||||
|             extra += ( |  | ||||||
|                 '\n\nClick discovered that you exported a UTF-8 locale\n' |  | ||||||
|                 'but the locale system could not pick up from it because\n' |  | ||||||
|                 'it does not exist.  The exported locale is "%s" but it\n' |  | ||||||
|                 'is not supported' |  | ||||||
|             ) % bad_locale |  | ||||||
| 
 |  | ||||||
|     raise RuntimeError('Click will abort further execution because Python 3 ' |  | ||||||
|                        'was configured to use ASCII as encoding for the ' |  | ||||||
|                        'environment.  Consult http://click.pocoo.org/python3/' |  | ||||||
|                        'for mitigation steps.' + extra) |  | ||||||
| @ -1,273 +0,0 @@ | |||||||
| # -*- coding: utf-8 -*- |  | ||||||
| # This module is based on the excellent work by Adam Bartoš who |  | ||||||
| # provided a lot of what went into the implementation here in |  | ||||||
| # the discussion to issue1602 in the Python bug tracker. |  | ||||||
| # |  | ||||||
| # There are some general differences in regards to how this works |  | ||||||
| # compared to the original patches as we do not need to patch |  | ||||||
| # the entire interpreter but just work in our little world of |  | ||||||
| # echo and prmopt. |  | ||||||
| 
 |  | ||||||
| import io |  | ||||||
| import os |  | ||||||
| import sys |  | ||||||
| import zlib |  | ||||||
| import time |  | ||||||
| import ctypes |  | ||||||
| import msvcrt |  | ||||||
| from click._compat import _NonClosingTextIOWrapper, text_type, PY2 |  | ||||||
| from ctypes import byref, POINTER, c_int, c_char, c_char_p, \ |  | ||||||
|      c_void_p, py_object, c_ssize_t, c_ulong, windll, WINFUNCTYPE |  | ||||||
| try: |  | ||||||
|     from ctypes import pythonapi |  | ||||||
|     PyObject_GetBuffer = pythonapi.PyObject_GetBuffer |  | ||||||
|     PyBuffer_Release = pythonapi.PyBuffer_Release |  | ||||||
| except ImportError: |  | ||||||
|     pythonapi = None |  | ||||||
| from ctypes.wintypes import LPWSTR, LPCWSTR |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| c_ssize_p = POINTER(c_ssize_t) |  | ||||||
| 
 |  | ||||||
| kernel32 = windll.kernel32 |  | ||||||
| GetStdHandle = kernel32.GetStdHandle |  | ||||||
| ReadConsoleW = kernel32.ReadConsoleW |  | ||||||
| WriteConsoleW = kernel32.WriteConsoleW |  | ||||||
| GetLastError = kernel32.GetLastError |  | ||||||
| GetCommandLineW = WINFUNCTYPE(LPWSTR)( |  | ||||||
|     ('GetCommandLineW', windll.kernel32)) |  | ||||||
| CommandLineToArgvW = WINFUNCTYPE( |  | ||||||
|     POINTER(LPWSTR), LPCWSTR, POINTER(c_int))( |  | ||||||
|         ('CommandLineToArgvW', windll.shell32)) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| STDIN_HANDLE = GetStdHandle(-10) |  | ||||||
| STDOUT_HANDLE = GetStdHandle(-11) |  | ||||||
| STDERR_HANDLE = GetStdHandle(-12) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| PyBUF_SIMPLE = 0 |  | ||||||
| PyBUF_WRITABLE = 1 |  | ||||||
| 
 |  | ||||||
| ERROR_SUCCESS = 0 |  | ||||||
| ERROR_NOT_ENOUGH_MEMORY = 8 |  | ||||||
| ERROR_OPERATION_ABORTED = 995 |  | ||||||
| 
 |  | ||||||
| STDIN_FILENO = 0 |  | ||||||
| STDOUT_FILENO = 1 |  | ||||||
| STDERR_FILENO = 2 |  | ||||||
| 
 |  | ||||||
| EOF = b'\x1a' |  | ||||||
| MAX_BYTES_WRITTEN = 32767 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class Py_buffer(ctypes.Structure): |  | ||||||
|     _fields_ = [ |  | ||||||
|         ('buf', c_void_p), |  | ||||||
|         ('obj', py_object), |  | ||||||
|         ('len', c_ssize_t), |  | ||||||
|         ('itemsize', c_ssize_t), |  | ||||||
|         ('readonly', c_int), |  | ||||||
|         ('ndim', c_int), |  | ||||||
|         ('format', c_char_p), |  | ||||||
|         ('shape', c_ssize_p), |  | ||||||
|         ('strides', c_ssize_p), |  | ||||||
|         ('suboffsets', c_ssize_p), |  | ||||||
|         ('internal', c_void_p) |  | ||||||
|     ] |  | ||||||
| 
 |  | ||||||
|     if PY2: |  | ||||||
|         _fields_.insert(-1, ('smalltable', c_ssize_t * 2)) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| # On PyPy we cannot get buffers so our ability to operate here is |  | ||||||
| # serverly limited. |  | ||||||
| if pythonapi is None: |  | ||||||
|     get_buffer = None |  | ||||||
| else: |  | ||||||
|     def get_buffer(obj, writable=False): |  | ||||||
|         buf = Py_buffer() |  | ||||||
|         flags = PyBUF_WRITABLE if writable else PyBUF_SIMPLE |  | ||||||
|         PyObject_GetBuffer(py_object(obj), byref(buf), flags) |  | ||||||
|         try: |  | ||||||
|             buffer_type = c_char * buf.len |  | ||||||
|             return buffer_type.from_address(buf.buf) |  | ||||||
|         finally: |  | ||||||
|             PyBuffer_Release(byref(buf)) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class _WindowsConsoleRawIOBase(io.RawIOBase): |  | ||||||
| 
 |  | ||||||
|     def __init__(self, handle): |  | ||||||
|         self.handle = handle |  | ||||||
| 
 |  | ||||||
|     def isatty(self): |  | ||||||
|         io.RawIOBase.isatty(self) |  | ||||||
|         return True |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class _WindowsConsoleReader(_WindowsConsoleRawIOBase): |  | ||||||
| 
 |  | ||||||
|     def readable(self): |  | ||||||
|         return True |  | ||||||
| 
 |  | ||||||
|     def readinto(self, b): |  | ||||||
|         bytes_to_be_read = len(b) |  | ||||||
|         if not bytes_to_be_read: |  | ||||||
|             return 0 |  | ||||||
|         elif bytes_to_be_read % 2: |  | ||||||
|             raise ValueError('cannot read odd number of bytes from ' |  | ||||||
|                              'UTF-16-LE encoded console') |  | ||||||
| 
 |  | ||||||
|         buffer = get_buffer(b, writable=True) |  | ||||||
|         code_units_to_be_read = bytes_to_be_read // 2 |  | ||||||
|         code_units_read = c_ulong() |  | ||||||
| 
 |  | ||||||
|         rv = ReadConsoleW(self.handle, buffer, code_units_to_be_read, |  | ||||||
|                           byref(code_units_read), None) |  | ||||||
|         if GetLastError() == ERROR_OPERATION_ABORTED: |  | ||||||
|             # wait for KeyboardInterrupt |  | ||||||
|             time.sleep(0.1) |  | ||||||
|         if not rv: |  | ||||||
|             raise OSError('Windows error: %s' % GetLastError()) |  | ||||||
| 
 |  | ||||||
|         if buffer[0] == EOF: |  | ||||||
|             return 0 |  | ||||||
|         return 2 * code_units_read.value |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class _WindowsConsoleWriter(_WindowsConsoleRawIOBase): |  | ||||||
| 
 |  | ||||||
|     def writable(self): |  | ||||||
|         return True |  | ||||||
| 
 |  | ||||||
|     @staticmethod |  | ||||||
|     def _get_error_message(errno): |  | ||||||
|         if errno == ERROR_SUCCESS: |  | ||||||
|             return 'ERROR_SUCCESS' |  | ||||||
|         elif errno == ERROR_NOT_ENOUGH_MEMORY: |  | ||||||
|             return 'ERROR_NOT_ENOUGH_MEMORY' |  | ||||||
|         return 'Windows error %s' % errno |  | ||||||
| 
 |  | ||||||
|     def write(self, b): |  | ||||||
|         bytes_to_be_written = len(b) |  | ||||||
|         buf = get_buffer(b) |  | ||||||
|         code_units_to_be_written = min(bytes_to_be_written, |  | ||||||
|                                        MAX_BYTES_WRITTEN) // 2 |  | ||||||
|         code_units_written = c_ulong() |  | ||||||
| 
 |  | ||||||
|         WriteConsoleW(self.handle, buf, code_units_to_be_written, |  | ||||||
|                       byref(code_units_written), None) |  | ||||||
|         bytes_written = 2 * code_units_written.value |  | ||||||
| 
 |  | ||||||
|         if bytes_written == 0 and bytes_to_be_written > 0: |  | ||||||
|             raise OSError(self._get_error_message(GetLastError())) |  | ||||||
|         return bytes_written |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class ConsoleStream(object): |  | ||||||
| 
 |  | ||||||
|     def __init__(self, text_stream, byte_stream): |  | ||||||
|         self._text_stream = text_stream |  | ||||||
|         self.buffer = byte_stream |  | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def name(self): |  | ||||||
|         return self.buffer.name |  | ||||||
| 
 |  | ||||||
|     def write(self, x): |  | ||||||
|         if isinstance(x, text_type): |  | ||||||
|             return self._text_stream.write(x) |  | ||||||
|         try: |  | ||||||
|             self.flush() |  | ||||||
|         except Exception: |  | ||||||
|             pass |  | ||||||
|         return self.buffer.write(x) |  | ||||||
| 
 |  | ||||||
|     def writelines(self, lines): |  | ||||||
|         for line in lines: |  | ||||||
|             self.write(line) |  | ||||||
| 
 |  | ||||||
|     def __getattr__(self, name): |  | ||||||
|         return getattr(self._text_stream, name) |  | ||||||
| 
 |  | ||||||
|     def isatty(self): |  | ||||||
|         return self.buffer.isatty() |  | ||||||
| 
 |  | ||||||
|     def __repr__(self): |  | ||||||
|         return '<ConsoleStream name=%r encoding=%r>' % ( |  | ||||||
|             self.name, |  | ||||||
|             self.encoding, |  | ||||||
|         ) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def _get_text_stdin(buffer_stream): |  | ||||||
|     text_stream = _NonClosingTextIOWrapper( |  | ||||||
|         io.BufferedReader(_WindowsConsoleReader(STDIN_HANDLE)), |  | ||||||
|         'utf-16-le', 'strict', line_buffering=True) |  | ||||||
|     return ConsoleStream(text_stream, buffer_stream) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def _get_text_stdout(buffer_stream): |  | ||||||
|     text_stream = _NonClosingTextIOWrapper( |  | ||||||
|         _WindowsConsoleWriter(STDOUT_HANDLE), |  | ||||||
|         'utf-16-le', 'strict', line_buffering=True) |  | ||||||
|     return ConsoleStream(text_stream, buffer_stream) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def _get_text_stderr(buffer_stream): |  | ||||||
|     text_stream = _NonClosingTextIOWrapper( |  | ||||||
|         _WindowsConsoleWriter(STDERR_HANDLE), |  | ||||||
|         'utf-16-le', 'strict', line_buffering=True) |  | ||||||
|     return ConsoleStream(text_stream, buffer_stream) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| if PY2: |  | ||||||
|     def _hash_py_argv(): |  | ||||||
|         return zlib.crc32('\x00'.join(sys.argv[1:])) |  | ||||||
| 
 |  | ||||||
|     _initial_argv_hash = _hash_py_argv() |  | ||||||
| 
 |  | ||||||
|     def _get_windows_argv(): |  | ||||||
|         argc = c_int(0) |  | ||||||
|         argv_unicode = CommandLineToArgvW(GetCommandLineW(), byref(argc)) |  | ||||||
|         argv = [argv_unicode[i] for i in range(0, argc.value)] |  | ||||||
| 
 |  | ||||||
|         if not hasattr(sys, 'frozen'): |  | ||||||
|             argv = argv[1:] |  | ||||||
|             while len(argv) > 0: |  | ||||||
|                 arg = argv[0] |  | ||||||
|                 if not arg.startswith('-') or arg == '-': |  | ||||||
|                     break |  | ||||||
|                 argv = argv[1:] |  | ||||||
|                 if arg.startswith(('-c', '-m')): |  | ||||||
|                     break |  | ||||||
| 
 |  | ||||||
|         return argv[1:] |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| _stream_factories = { |  | ||||||
|     0: _get_text_stdin, |  | ||||||
|     1: _get_text_stdout, |  | ||||||
|     2: _get_text_stderr, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def _get_windows_console_stream(f, encoding, errors): |  | ||||||
|     if get_buffer is not None and \ |  | ||||||
|        encoding in ('utf-16-le', None) \ |  | ||||||
|        and errors in ('strict', None) and \ |  | ||||||
|        hasattr(f, 'isatty') and f.isatty(): |  | ||||||
|         func = _stream_factories.get(f.fileno()) |  | ||||||
|         if func is not None: |  | ||||||
|             if not PY2: |  | ||||||
|                 f = getattr(f, 'buffer') |  | ||||||
|                 if f is None: |  | ||||||
|                     return None |  | ||||||
|             else: |  | ||||||
|                 # If we are on Python 2 we need to set the stream that we |  | ||||||
|                 # deal with to binary mode as otherwise the exercise if a |  | ||||||
|                 # bit moot.  The same problems apply as for |  | ||||||
|                 # get_binary_stdin and friends from _compat. |  | ||||||
|                 msvcrt.setmode(f.fileno(), os.O_BINARY) |  | ||||||
|             return func(f) |  | ||||||
									
										
											File diff suppressed because it is too large
											Load Diff
										
									
								
							
						| @ -1,304 +0,0 @@ | |||||||
| import sys |  | ||||||
| import inspect |  | ||||||
| 
 |  | ||||||
| from functools import update_wrapper |  | ||||||
| 
 |  | ||||||
| from ._compat import iteritems |  | ||||||
| from ._unicodefun import _check_for_unicode_literals |  | ||||||
| from .utils import echo |  | ||||||
| from .globals import get_current_context |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def pass_context(f): |  | ||||||
|     """Marks a callback as wanting to receive the current context |  | ||||||
|     object as first argument. |  | ||||||
|     """ |  | ||||||
|     def new_func(*args, **kwargs): |  | ||||||
|         return f(get_current_context(), *args, **kwargs) |  | ||||||
|     return update_wrapper(new_func, f) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def pass_obj(f): |  | ||||||
|     """Similar to :func:`pass_context`, but only pass the object on the |  | ||||||
|     context onwards (:attr:`Context.obj`).  This is useful if that object |  | ||||||
|     represents the state of a nested system. |  | ||||||
|     """ |  | ||||||
|     def new_func(*args, **kwargs): |  | ||||||
|         return f(get_current_context().obj, *args, **kwargs) |  | ||||||
|     return update_wrapper(new_func, f) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def make_pass_decorator(object_type, ensure=False): |  | ||||||
|     """Given an object type this creates a decorator that will work |  | ||||||
|     similar to :func:`pass_obj` but instead of passing the object of the |  | ||||||
|     current context, it will find the innermost context of type |  | ||||||
|     :func:`object_type`. |  | ||||||
| 
 |  | ||||||
|     This generates a decorator that works roughly like this:: |  | ||||||
| 
 |  | ||||||
|         from functools import update_wrapper |  | ||||||
| 
 |  | ||||||
|         def decorator(f): |  | ||||||
|             @pass_context |  | ||||||
|             def new_func(ctx, *args, **kwargs): |  | ||||||
|                 obj = ctx.find_object(object_type) |  | ||||||
|                 return ctx.invoke(f, obj, *args, **kwargs) |  | ||||||
|             return update_wrapper(new_func, f) |  | ||||||
|         return decorator |  | ||||||
| 
 |  | ||||||
|     :param object_type: the type of the object to pass. |  | ||||||
|     :param ensure: if set to `True`, a new object will be created and |  | ||||||
|                    remembered on the context if it's not there yet. |  | ||||||
|     """ |  | ||||||
|     def decorator(f): |  | ||||||
|         def new_func(*args, **kwargs): |  | ||||||
|             ctx = get_current_context() |  | ||||||
|             if ensure: |  | ||||||
|                 obj = ctx.ensure_object(object_type) |  | ||||||
|             else: |  | ||||||
|                 obj = ctx.find_object(object_type) |  | ||||||
|             if obj is None: |  | ||||||
|                 raise RuntimeError('Managed to invoke callback without a ' |  | ||||||
|                                    'context object of type %r existing' |  | ||||||
|                                    % object_type.__name__) |  | ||||||
|             return ctx.invoke(f, obj, *args[1:], **kwargs) |  | ||||||
|         return update_wrapper(new_func, f) |  | ||||||
|     return decorator |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def _make_command(f, name, attrs, cls): |  | ||||||
|     if isinstance(f, Command): |  | ||||||
|         raise TypeError('Attempted to convert a callback into a ' |  | ||||||
|                         'command twice.') |  | ||||||
|     try: |  | ||||||
|         params = f.__click_params__ |  | ||||||
|         params.reverse() |  | ||||||
|         del f.__click_params__ |  | ||||||
|     except AttributeError: |  | ||||||
|         params = [] |  | ||||||
|     help = attrs.get('help') |  | ||||||
|     if help is None: |  | ||||||
|         help = inspect.getdoc(f) |  | ||||||
|         if isinstance(help, bytes): |  | ||||||
|             help = help.decode('utf-8') |  | ||||||
|     else: |  | ||||||
|         help = inspect.cleandoc(help) |  | ||||||
|     attrs['help'] = help |  | ||||||
|     _check_for_unicode_literals() |  | ||||||
|     return cls(name=name or f.__name__.lower(), |  | ||||||
|                callback=f, params=params, **attrs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def command(name=None, cls=None, **attrs): |  | ||||||
|     """Creates a new :class:`Command` and uses the decorated function as |  | ||||||
|     callback.  This will also automatically attach all decorated |  | ||||||
|     :func:`option`\s and :func:`argument`\s as parameters to the command. |  | ||||||
| 
 |  | ||||||
|     The name of the command defaults to the name of the function.  If you |  | ||||||
|     want to change that, you can pass the intended name as the first |  | ||||||
|     argument. |  | ||||||
| 
 |  | ||||||
|     All keyword arguments are forwarded to the underlying command class. |  | ||||||
| 
 |  | ||||||
|     Once decorated the function turns into a :class:`Command` instance |  | ||||||
|     that can be invoked as a command line utility or be attached to a |  | ||||||
|     command :class:`Group`. |  | ||||||
| 
 |  | ||||||
|     :param name: the name of the command.  This defaults to the function |  | ||||||
|                  name. |  | ||||||
|     :param cls: the command class to instantiate.  This defaults to |  | ||||||
|                 :class:`Command`. |  | ||||||
|     """ |  | ||||||
|     if cls is None: |  | ||||||
|         cls = Command |  | ||||||
|     def decorator(f): |  | ||||||
|         cmd = _make_command(f, name, attrs, cls) |  | ||||||
|         cmd.__doc__ = f.__doc__ |  | ||||||
|         return cmd |  | ||||||
|     return decorator |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def group(name=None, **attrs): |  | ||||||
|     """Creates a new :class:`Group` with a function as callback.  This |  | ||||||
|     works otherwise the same as :func:`command` just that the `cls` |  | ||||||
|     parameter is set to :class:`Group`. |  | ||||||
|     """ |  | ||||||
|     attrs.setdefault('cls', Group) |  | ||||||
|     return command(name, **attrs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def _param_memo(f, param): |  | ||||||
|     if isinstance(f, Command): |  | ||||||
|         f.params.append(param) |  | ||||||
|     else: |  | ||||||
|         if not hasattr(f, '__click_params__'): |  | ||||||
|             f.__click_params__ = [] |  | ||||||
|         f.__click_params__.append(param) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def argument(*param_decls, **attrs): |  | ||||||
|     """Attaches an argument to the command.  All positional arguments are |  | ||||||
|     passed as parameter declarations to :class:`Argument`; all keyword |  | ||||||
|     arguments are forwarded unchanged (except ``cls``). |  | ||||||
|     This is equivalent to creating an :class:`Argument` instance manually |  | ||||||
|     and attaching it to the :attr:`Command.params` list. |  | ||||||
| 
 |  | ||||||
|     :param cls: the argument class to instantiate.  This defaults to |  | ||||||
|                 :class:`Argument`. |  | ||||||
|     """ |  | ||||||
|     def decorator(f): |  | ||||||
|         ArgumentClass = attrs.pop('cls', Argument) |  | ||||||
|         _param_memo(f, ArgumentClass(param_decls, **attrs)) |  | ||||||
|         return f |  | ||||||
|     return decorator |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def option(*param_decls, **attrs): |  | ||||||
|     """Attaches an option to the command.  All positional arguments are |  | ||||||
|     passed as parameter declarations to :class:`Option`; all keyword |  | ||||||
|     arguments are forwarded unchanged (except ``cls``). |  | ||||||
|     This is equivalent to creating an :class:`Option` instance manually |  | ||||||
|     and attaching it to the :attr:`Command.params` list. |  | ||||||
| 
 |  | ||||||
|     :param cls: the option class to instantiate.  This defaults to |  | ||||||
|                 :class:`Option`. |  | ||||||
|     """ |  | ||||||
|     def decorator(f): |  | ||||||
|         if 'help' in attrs: |  | ||||||
|             attrs['help'] = inspect.cleandoc(attrs['help']) |  | ||||||
|         OptionClass = attrs.pop('cls', Option) |  | ||||||
|         _param_memo(f, OptionClass(param_decls, **attrs)) |  | ||||||
|         return f |  | ||||||
|     return decorator |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def confirmation_option(*param_decls, **attrs): |  | ||||||
|     """Shortcut for confirmation prompts that can be ignored by passing |  | ||||||
|     ``--yes`` as parameter. |  | ||||||
| 
 |  | ||||||
|     This is equivalent to decorating a function with :func:`option` with |  | ||||||
|     the following parameters:: |  | ||||||
| 
 |  | ||||||
|         def callback(ctx, param, value): |  | ||||||
|             if not value: |  | ||||||
|                 ctx.abort() |  | ||||||
| 
 |  | ||||||
|         @click.command() |  | ||||||
|         @click.option('--yes', is_flag=True, callback=callback, |  | ||||||
|                       expose_value=False, prompt='Do you want to continue?') |  | ||||||
|         def dropdb(): |  | ||||||
|             pass |  | ||||||
|     """ |  | ||||||
|     def decorator(f): |  | ||||||
|         def callback(ctx, param, value): |  | ||||||
|             if not value: |  | ||||||
|                 ctx.abort() |  | ||||||
|         attrs.setdefault('is_flag', True) |  | ||||||
|         attrs.setdefault('callback', callback) |  | ||||||
|         attrs.setdefault('expose_value', False) |  | ||||||
|         attrs.setdefault('prompt', 'Do you want to continue?') |  | ||||||
|         attrs.setdefault('help', 'Confirm the action without prompting.') |  | ||||||
|         return option(*(param_decls or ('--yes',)), **attrs)(f) |  | ||||||
|     return decorator |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def password_option(*param_decls, **attrs): |  | ||||||
|     """Shortcut for password prompts. |  | ||||||
| 
 |  | ||||||
|     This is equivalent to decorating a function with :func:`option` with |  | ||||||
|     the following parameters:: |  | ||||||
| 
 |  | ||||||
|         @click.command() |  | ||||||
|         @click.option('--password', prompt=True, confirmation_prompt=True, |  | ||||||
|                       hide_input=True) |  | ||||||
|         def changeadmin(password): |  | ||||||
|             pass |  | ||||||
|     """ |  | ||||||
|     def decorator(f): |  | ||||||
|         attrs.setdefault('prompt', True) |  | ||||||
|         attrs.setdefault('confirmation_prompt', True) |  | ||||||
|         attrs.setdefault('hide_input', True) |  | ||||||
|         return option(*(param_decls or ('--password',)), **attrs)(f) |  | ||||||
|     return decorator |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def version_option(version=None, *param_decls, **attrs): |  | ||||||
|     """Adds a ``--version`` option which immediately ends the program |  | ||||||
|     printing out the version number.  This is implemented as an eager |  | ||||||
|     option that prints the version and exits the program in the callback. |  | ||||||
| 
 |  | ||||||
|     :param version: the version number to show.  If not provided Click |  | ||||||
|                     attempts an auto discovery via setuptools. |  | ||||||
|     :param prog_name: the name of the program (defaults to autodetection) |  | ||||||
|     :param message: custom message to show instead of the default |  | ||||||
|                     (``'%(prog)s, version %(version)s'``) |  | ||||||
|     :param others: everything else is forwarded to :func:`option`. |  | ||||||
|     """ |  | ||||||
|     if version is None: |  | ||||||
|         module = sys._getframe(1).f_globals.get('__name__') |  | ||||||
|     def decorator(f): |  | ||||||
|         prog_name = attrs.pop('prog_name', None) |  | ||||||
|         message = attrs.pop('message', '%(prog)s, version %(version)s') |  | ||||||
| 
 |  | ||||||
|         def callback(ctx, param, value): |  | ||||||
|             if not value or ctx.resilient_parsing: |  | ||||||
|                 return |  | ||||||
|             prog = prog_name |  | ||||||
|             if prog is None: |  | ||||||
|                 prog = ctx.find_root().info_name |  | ||||||
|             ver = version |  | ||||||
|             if ver is None: |  | ||||||
|                 try: |  | ||||||
|                     import pkg_resources |  | ||||||
|                 except ImportError: |  | ||||||
|                     pass |  | ||||||
|                 else: |  | ||||||
|                     for dist in pkg_resources.working_set: |  | ||||||
|                         scripts = dist.get_entry_map().get('console_scripts') or {} |  | ||||||
|                         for script_name, entry_point in iteritems(scripts): |  | ||||||
|                             if entry_point.module_name == module: |  | ||||||
|                                 ver = dist.version |  | ||||||
|                                 break |  | ||||||
|                 if ver is None: |  | ||||||
|                     raise RuntimeError('Could not determine version') |  | ||||||
|             echo(message % { |  | ||||||
|                 'prog': prog, |  | ||||||
|                 'version': ver, |  | ||||||
|             }, color=ctx.color) |  | ||||||
|             ctx.exit() |  | ||||||
| 
 |  | ||||||
|         attrs.setdefault('is_flag', True) |  | ||||||
|         attrs.setdefault('expose_value', False) |  | ||||||
|         attrs.setdefault('is_eager', True) |  | ||||||
|         attrs.setdefault('help', 'Show the version and exit.') |  | ||||||
|         attrs['callback'] = callback |  | ||||||
|         return option(*(param_decls or ('--version',)), **attrs)(f) |  | ||||||
|     return decorator |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def help_option(*param_decls, **attrs): |  | ||||||
|     """Adds a ``--help`` option which immediately ends the program |  | ||||||
|     printing out the help page.  This is usually unnecessary to add as |  | ||||||
|     this is added by default to all commands unless suppressed. |  | ||||||
| 
 |  | ||||||
|     Like :func:`version_option`, this is implemented as eager option that |  | ||||||
|     prints in the callback and exits. |  | ||||||
| 
 |  | ||||||
|     All arguments are forwarded to :func:`option`. |  | ||||||
|     """ |  | ||||||
|     def decorator(f): |  | ||||||
|         def callback(ctx, param, value): |  | ||||||
|             if value and not ctx.resilient_parsing: |  | ||||||
|                 echo(ctx.get_help(), color=ctx.color) |  | ||||||
|                 ctx.exit() |  | ||||||
|         attrs.setdefault('is_flag', True) |  | ||||||
|         attrs.setdefault('expose_value', False) |  | ||||||
|         attrs.setdefault('help', 'Show this message and exit.') |  | ||||||
|         attrs.setdefault('is_eager', True) |  | ||||||
|         attrs['callback'] = callback |  | ||||||
|         return option(*(param_decls or ('--help',)), **attrs)(f) |  | ||||||
|     return decorator |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| # Circular dependencies between core and decorators |  | ||||||
| from .core import Command, Group, Argument, Option |  | ||||||
| @ -1,201 +0,0 @@ | |||||||
| from ._compat import PY2, filename_to_ui, get_text_stderr |  | ||||||
| from .utils import echo |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class ClickException(Exception): |  | ||||||
|     """An exception that Click can handle and show to the user.""" |  | ||||||
| 
 |  | ||||||
|     #: The exit code for this exception |  | ||||||
|     exit_code = 1 |  | ||||||
| 
 |  | ||||||
|     def __init__(self, message): |  | ||||||
|         if PY2: |  | ||||||
|             if message is not None: |  | ||||||
|                 message = message.encode('utf-8') |  | ||||||
|         Exception.__init__(self, message) |  | ||||||
|         self.message = message |  | ||||||
| 
 |  | ||||||
|     def format_message(self): |  | ||||||
|         return self.message |  | ||||||
| 
 |  | ||||||
|     def show(self, file=None): |  | ||||||
|         if file is None: |  | ||||||
|             file = get_text_stderr() |  | ||||||
|         echo('Error: %s' % self.format_message(), file=file) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class UsageError(ClickException): |  | ||||||
|     """An internal exception that signals a usage error.  This typically |  | ||||||
|     aborts any further handling. |  | ||||||
| 
 |  | ||||||
|     :param message: the error message to display. |  | ||||||
|     :param ctx: optionally the context that caused this error.  Click will |  | ||||||
|                 fill in the context automatically in some situations. |  | ||||||
|     """ |  | ||||||
|     exit_code = 2 |  | ||||||
| 
 |  | ||||||
|     def __init__(self, message, ctx=None): |  | ||||||
|         ClickException.__init__(self, message) |  | ||||||
|         self.ctx = ctx |  | ||||||
| 
 |  | ||||||
|     def show(self, file=None): |  | ||||||
|         if file is None: |  | ||||||
|             file = get_text_stderr() |  | ||||||
|         color = None |  | ||||||
|         if self.ctx is not None: |  | ||||||
|             color = self.ctx.color |  | ||||||
|             echo(self.ctx.get_usage() + '\n', file=file, color=color) |  | ||||||
|         echo('Error: %s' % self.format_message(), file=file, color=color) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class BadParameter(UsageError): |  | ||||||
|     """An exception that formats out a standardized error message for a |  | ||||||
|     bad parameter.  This is useful when thrown from a callback or type as |  | ||||||
|     Click will attach contextual information to it (for instance, which |  | ||||||
|     parameter it is). |  | ||||||
| 
 |  | ||||||
|     .. versionadded:: 2.0 |  | ||||||
| 
 |  | ||||||
|     :param param: the parameter object that caused this error.  This can |  | ||||||
|                   be left out, and Click will attach this info itself |  | ||||||
|                   if possible. |  | ||||||
|     :param param_hint: a string that shows up as parameter name.  This |  | ||||||
|                        can be used as alternative to `param` in cases |  | ||||||
|                        where custom validation should happen.  If it is |  | ||||||
|                        a string it's used as such, if it's a list then |  | ||||||
|                        each item is quoted and separated. |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     def __init__(self, message, ctx=None, param=None, |  | ||||||
|                  param_hint=None): |  | ||||||
|         UsageError.__init__(self, message, ctx) |  | ||||||
|         self.param = param |  | ||||||
|         self.param_hint = param_hint |  | ||||||
| 
 |  | ||||||
|     def format_message(self): |  | ||||||
|         if self.param_hint is not None: |  | ||||||
|             param_hint = self.param_hint |  | ||||||
|         elif self.param is not None: |  | ||||||
|             param_hint = self.param.opts or [self.param.human_readable_name] |  | ||||||
|         else: |  | ||||||
|             return 'Invalid value: %s' % self.message |  | ||||||
|         if isinstance(param_hint, (tuple, list)): |  | ||||||
|             param_hint = ' / '.join('"%s"' % x for x in param_hint) |  | ||||||
|         return 'Invalid value for %s: %s' % (param_hint, self.message) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class MissingParameter(BadParameter): |  | ||||||
|     """Raised if click required an option or argument but it was not |  | ||||||
|     provided when invoking the script. |  | ||||||
| 
 |  | ||||||
|     .. versionadded:: 4.0 |  | ||||||
| 
 |  | ||||||
|     :param param_type: a string that indicates the type of the parameter. |  | ||||||
|                        The default is to inherit the parameter type from |  | ||||||
|                        the given `param`.  Valid values are ``'parameter'``, |  | ||||||
|                        ``'option'`` or ``'argument'``. |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     def __init__(self, message=None, ctx=None, param=None, |  | ||||||
|                  param_hint=None, param_type=None): |  | ||||||
|         BadParameter.__init__(self, message, ctx, param, param_hint) |  | ||||||
|         self.param_type = param_type |  | ||||||
| 
 |  | ||||||
|     def format_message(self): |  | ||||||
|         if self.param_hint is not None: |  | ||||||
|             param_hint = self.param_hint |  | ||||||
|         elif self.param is not None: |  | ||||||
|             param_hint = self.param.opts or [self.param.human_readable_name] |  | ||||||
|         else: |  | ||||||
|             param_hint = None |  | ||||||
|         if isinstance(param_hint, (tuple, list)): |  | ||||||
|             param_hint = ' / '.join('"%s"' % x for x in param_hint) |  | ||||||
| 
 |  | ||||||
|         param_type = self.param_type |  | ||||||
|         if param_type is None and self.param is not None: |  | ||||||
|             param_type = self.param.param_type_name |  | ||||||
| 
 |  | ||||||
|         msg = self.message |  | ||||||
|         if self.param is not None: |  | ||||||
|             msg_extra = self.param.type.get_missing_message(self.param) |  | ||||||
|             if msg_extra: |  | ||||||
|                 if msg: |  | ||||||
|                     msg += '.  ' + msg_extra |  | ||||||
|                 else: |  | ||||||
|                     msg = msg_extra |  | ||||||
| 
 |  | ||||||
|         return 'Missing %s%s%s%s' % ( |  | ||||||
|             param_type, |  | ||||||
|             param_hint and ' %s' % param_hint or '', |  | ||||||
|             msg and '.  ' or '.', |  | ||||||
|             msg or '', |  | ||||||
|         ) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class NoSuchOption(UsageError): |  | ||||||
|     """Raised if click attempted to handle an option that does not |  | ||||||
|     exist. |  | ||||||
| 
 |  | ||||||
|     .. versionadded:: 4.0 |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     def __init__(self, option_name, message=None, possibilities=None, |  | ||||||
|                  ctx=None): |  | ||||||
|         if message is None: |  | ||||||
|             message = 'no such option: %s' % option_name |  | ||||||
|         UsageError.__init__(self, message, ctx) |  | ||||||
|         self.option_name = option_name |  | ||||||
|         self.possibilities = possibilities |  | ||||||
| 
 |  | ||||||
|     def format_message(self): |  | ||||||
|         bits = [self.message] |  | ||||||
|         if self.possibilities: |  | ||||||
|             if len(self.possibilities) == 1: |  | ||||||
|                 bits.append('Did you mean %s?' % self.possibilities[0]) |  | ||||||
|             else: |  | ||||||
|                 possibilities = sorted(self.possibilities) |  | ||||||
|                 bits.append('(Possible options: %s)' % ', '.join(possibilities)) |  | ||||||
|         return '  '.join(bits) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class BadOptionUsage(UsageError): |  | ||||||
|     """Raised if an option is generally supplied but the use of the option |  | ||||||
|     was incorrect.  This is for instance raised if the number of arguments |  | ||||||
|     for an option is not correct. |  | ||||||
| 
 |  | ||||||
|     .. versionadded:: 4.0 |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     def __init__(self, message, ctx=None): |  | ||||||
|         UsageError.__init__(self, message, ctx) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class BadArgumentUsage(UsageError): |  | ||||||
|     """Raised if an argument is generally supplied but the use of the argument |  | ||||||
|     was incorrect.  This is for instance raised if the number of values |  | ||||||
|     for an argument is not correct. |  | ||||||
| 
 |  | ||||||
|     .. versionadded:: 6.0 |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     def __init__(self, message, ctx=None): |  | ||||||
|         UsageError.__init__(self, message, ctx) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class FileError(ClickException): |  | ||||||
|     """Raised if a file cannot be opened.""" |  | ||||||
| 
 |  | ||||||
|     def __init__(self, filename, hint=None): |  | ||||||
|         ui_filename = filename_to_ui(filename) |  | ||||||
|         if hint is None: |  | ||||||
|             hint = 'unknown error' |  | ||||||
|         ClickException.__init__(self, hint) |  | ||||||
|         self.ui_filename = ui_filename |  | ||||||
|         self.filename = filename |  | ||||||
| 
 |  | ||||||
|     def format_message(self): |  | ||||||
|         return 'Could not open file %s: %s' % (self.ui_filename, self.message) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class Abort(RuntimeError): |  | ||||||
|     """An internal signalling exception that signals Click to abort.""" |  | ||||||
| @ -1,256 +0,0 @@ | |||||||
| from contextlib import contextmanager |  | ||||||
| from .termui import get_terminal_size |  | ||||||
| from .parser import split_opt |  | ||||||
| from ._compat import term_len |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| # Can force a width.  This is used by the test system |  | ||||||
| FORCED_WIDTH = None |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def measure_table(rows): |  | ||||||
|     widths = {} |  | ||||||
|     for row in rows: |  | ||||||
|         for idx, col in enumerate(row): |  | ||||||
|             widths[idx] = max(widths.get(idx, 0), term_len(col)) |  | ||||||
|     return tuple(y for x, y in sorted(widths.items())) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def iter_rows(rows, col_count): |  | ||||||
|     for row in rows: |  | ||||||
|         row = tuple(row) |  | ||||||
|         yield row + ('',) * (col_count - len(row)) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def wrap_text(text, width=78, initial_indent='', subsequent_indent='', |  | ||||||
|               preserve_paragraphs=False): |  | ||||||
|     """A helper function that intelligently wraps text.  By default, it |  | ||||||
|     assumes that it operates on a single paragraph of text but if the |  | ||||||
|     `preserve_paragraphs` parameter is provided it will intelligently |  | ||||||
|     handle paragraphs (defined by two empty lines). |  | ||||||
| 
 |  | ||||||
|     If paragraphs are handled, a paragraph can be prefixed with an empty |  | ||||||
|     line containing the ``\\b`` character (``\\x08``) to indicate that |  | ||||||
|     no rewrapping should happen in that block. |  | ||||||
| 
 |  | ||||||
|     :param text: the text that should be rewrapped. |  | ||||||
|     :param width: the maximum width for the text. |  | ||||||
|     :param initial_indent: the initial indent that should be placed on the |  | ||||||
|                            first line as a string. |  | ||||||
|     :param subsequent_indent: the indent string that should be placed on |  | ||||||
|                               each consecutive line. |  | ||||||
|     :param preserve_paragraphs: if this flag is set then the wrapping will |  | ||||||
|                                 intelligently handle paragraphs. |  | ||||||
|     """ |  | ||||||
|     from ._textwrap import TextWrapper |  | ||||||
|     text = text.expandtabs() |  | ||||||
|     wrapper = TextWrapper(width, initial_indent=initial_indent, |  | ||||||
|                           subsequent_indent=subsequent_indent, |  | ||||||
|                           replace_whitespace=False) |  | ||||||
|     if not preserve_paragraphs: |  | ||||||
|         return wrapper.fill(text) |  | ||||||
| 
 |  | ||||||
|     p = [] |  | ||||||
|     buf = [] |  | ||||||
|     indent = None |  | ||||||
| 
 |  | ||||||
|     def _flush_par(): |  | ||||||
|         if not buf: |  | ||||||
|             return |  | ||||||
|         if buf[0].strip() == '\b': |  | ||||||
|             p.append((indent or 0, True, '\n'.join(buf[1:]))) |  | ||||||
|         else: |  | ||||||
|             p.append((indent or 0, False, ' '.join(buf))) |  | ||||||
|         del buf[:] |  | ||||||
| 
 |  | ||||||
|     for line in text.splitlines(): |  | ||||||
|         if not line: |  | ||||||
|             _flush_par() |  | ||||||
|             indent = None |  | ||||||
|         else: |  | ||||||
|             if indent is None: |  | ||||||
|                 orig_len = term_len(line) |  | ||||||
|                 line = line.lstrip() |  | ||||||
|                 indent = orig_len - term_len(line) |  | ||||||
|             buf.append(line) |  | ||||||
|     _flush_par() |  | ||||||
| 
 |  | ||||||
|     rv = [] |  | ||||||
|     for indent, raw, text in p: |  | ||||||
|         with wrapper.extra_indent(' ' * indent): |  | ||||||
|             if raw: |  | ||||||
|                 rv.append(wrapper.indent_only(text)) |  | ||||||
|             else: |  | ||||||
|                 rv.append(wrapper.fill(text)) |  | ||||||
| 
 |  | ||||||
|     return '\n\n'.join(rv) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class HelpFormatter(object): |  | ||||||
|     """This class helps with formatting text-based help pages.  It's |  | ||||||
|     usually just needed for very special internal cases, but it's also |  | ||||||
|     exposed so that developers can write their own fancy outputs. |  | ||||||
| 
 |  | ||||||
|     At present, it always writes into memory. |  | ||||||
| 
 |  | ||||||
|     :param indent_increment: the additional increment for each level. |  | ||||||
|     :param width: the width for the text.  This defaults to the terminal |  | ||||||
|                   width clamped to a maximum of 78. |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     def __init__(self, indent_increment=2, width=None, max_width=None): |  | ||||||
|         self.indent_increment = indent_increment |  | ||||||
|         if max_width is None: |  | ||||||
|             max_width = 80 |  | ||||||
|         if width is None: |  | ||||||
|             width = FORCED_WIDTH |  | ||||||
|             if width is None: |  | ||||||
|                 width = max(min(get_terminal_size()[0], max_width) - 2, 50) |  | ||||||
|         self.width = width |  | ||||||
|         self.current_indent = 0 |  | ||||||
|         self.buffer = [] |  | ||||||
| 
 |  | ||||||
|     def write(self, string): |  | ||||||
|         """Writes a unicode string into the internal buffer.""" |  | ||||||
|         self.buffer.append(string) |  | ||||||
| 
 |  | ||||||
|     def indent(self): |  | ||||||
|         """Increases the indentation.""" |  | ||||||
|         self.current_indent += self.indent_increment |  | ||||||
| 
 |  | ||||||
|     def dedent(self): |  | ||||||
|         """Decreases the indentation.""" |  | ||||||
|         self.current_indent -= self.indent_increment |  | ||||||
| 
 |  | ||||||
|     def write_usage(self, prog, args='', prefix='Usage: '): |  | ||||||
|         """Writes a usage line into the buffer. |  | ||||||
| 
 |  | ||||||
|         :param prog: the program name. |  | ||||||
|         :param args: whitespace separated list of arguments. |  | ||||||
|         :param prefix: the prefix for the first line. |  | ||||||
|         """ |  | ||||||
|         usage_prefix = '%*s%s ' % (self.current_indent, prefix, prog) |  | ||||||
|         text_width = self.width - self.current_indent |  | ||||||
| 
 |  | ||||||
|         if text_width >= (term_len(usage_prefix) + 20): |  | ||||||
|             # The arguments will fit to the right of the prefix. |  | ||||||
|             indent = ' ' * term_len(usage_prefix) |  | ||||||
|             self.write(wrap_text(args, text_width, |  | ||||||
|                                  initial_indent=usage_prefix, |  | ||||||
|                                  subsequent_indent=indent)) |  | ||||||
|         else: |  | ||||||
|             # The prefix is too long, put the arguments on the next line. |  | ||||||
|             self.write(usage_prefix) |  | ||||||
|             self.write('\n') |  | ||||||
|             indent = ' ' * (max(self.current_indent, term_len(prefix)) + 4) |  | ||||||
|             self.write(wrap_text(args, text_width, |  | ||||||
|                                  initial_indent=indent, |  | ||||||
|                                  subsequent_indent=indent)) |  | ||||||
| 
 |  | ||||||
|         self.write('\n') |  | ||||||
| 
 |  | ||||||
|     def write_heading(self, heading): |  | ||||||
|         """Writes a heading into the buffer.""" |  | ||||||
|         self.write('%*s%s:\n' % (self.current_indent, '', heading)) |  | ||||||
| 
 |  | ||||||
|     def write_paragraph(self): |  | ||||||
|         """Writes a paragraph into the buffer.""" |  | ||||||
|         if self.buffer: |  | ||||||
|             self.write('\n') |  | ||||||
| 
 |  | ||||||
|     def write_text(self, text): |  | ||||||
|         """Writes re-indented text into the buffer.  This rewraps and |  | ||||||
|         preserves paragraphs. |  | ||||||
|         """ |  | ||||||
|         text_width = max(self.width - self.current_indent, 11) |  | ||||||
|         indent = ' ' * self.current_indent |  | ||||||
|         self.write(wrap_text(text, text_width, |  | ||||||
|                              initial_indent=indent, |  | ||||||
|                              subsequent_indent=indent, |  | ||||||
|                              preserve_paragraphs=True)) |  | ||||||
|         self.write('\n') |  | ||||||
| 
 |  | ||||||
|     def write_dl(self, rows, col_max=30, col_spacing=2): |  | ||||||
|         """Writes a definition list into the buffer.  This is how options |  | ||||||
|         and commands are usually formatted. |  | ||||||
| 
 |  | ||||||
|         :param rows: a list of two item tuples for the terms and values. |  | ||||||
|         :param col_max: the maximum width of the first column. |  | ||||||
|         :param col_spacing: the number of spaces between the first and |  | ||||||
|                             second column. |  | ||||||
|         """ |  | ||||||
|         rows = list(rows) |  | ||||||
|         widths = measure_table(rows) |  | ||||||
|         if len(widths) != 2: |  | ||||||
|             raise TypeError('Expected two columns for definition list') |  | ||||||
| 
 |  | ||||||
|         first_col = min(widths[0], col_max) + col_spacing |  | ||||||
| 
 |  | ||||||
|         for first, second in iter_rows(rows, len(widths)): |  | ||||||
|             self.write('%*s%s' % (self.current_indent, '', first)) |  | ||||||
|             if not second: |  | ||||||
|                 self.write('\n') |  | ||||||
|                 continue |  | ||||||
|             if term_len(first) <= first_col - col_spacing: |  | ||||||
|                 self.write(' ' * (first_col - term_len(first))) |  | ||||||
|             else: |  | ||||||
|                 self.write('\n') |  | ||||||
|                 self.write(' ' * (first_col + self.current_indent)) |  | ||||||
| 
 |  | ||||||
|             text_width = max(self.width - first_col - 2, 10) |  | ||||||
|             lines = iter(wrap_text(second, text_width).splitlines()) |  | ||||||
|             if lines: |  | ||||||
|                 self.write(next(lines) + '\n') |  | ||||||
|                 for line in lines: |  | ||||||
|                     self.write('%*s%s\n' % ( |  | ||||||
|                         first_col + self.current_indent, '', line)) |  | ||||||
|             else: |  | ||||||
|                 self.write('\n') |  | ||||||
| 
 |  | ||||||
|     @contextmanager |  | ||||||
|     def section(self, name): |  | ||||||
|         """Helpful context manager that writes a paragraph, a heading, |  | ||||||
|         and the indents. |  | ||||||
| 
 |  | ||||||
|         :param name: the section name that is written as heading. |  | ||||||
|         """ |  | ||||||
|         self.write_paragraph() |  | ||||||
|         self.write_heading(name) |  | ||||||
|         self.indent() |  | ||||||
|         try: |  | ||||||
|             yield |  | ||||||
|         finally: |  | ||||||
|             self.dedent() |  | ||||||
| 
 |  | ||||||
|     @contextmanager |  | ||||||
|     def indentation(self): |  | ||||||
|         """A context manager that increases the indentation.""" |  | ||||||
|         self.indent() |  | ||||||
|         try: |  | ||||||
|             yield |  | ||||||
|         finally: |  | ||||||
|             self.dedent() |  | ||||||
| 
 |  | ||||||
|     def getvalue(self): |  | ||||||
|         """Returns the buffer contents.""" |  | ||||||
|         return ''.join(self.buffer) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def join_options(options): |  | ||||||
|     """Given a list of option strings this joins them in the most appropriate |  | ||||||
|     way and returns them in the form ``(formatted_string, |  | ||||||
|     any_prefix_is_slash)`` where the second item in the tuple is a flag that |  | ||||||
|     indicates if any of the option prefixes was a slash. |  | ||||||
|     """ |  | ||||||
|     rv = [] |  | ||||||
|     any_prefix_is_slash = False |  | ||||||
|     for opt in options: |  | ||||||
|         prefix = split_opt(opt)[0] |  | ||||||
|         if prefix == '/': |  | ||||||
|             any_prefix_is_slash = True |  | ||||||
|         rv.append((len(prefix), opt)) |  | ||||||
| 
 |  | ||||||
|     rv.sort(key=lambda x: x[0]) |  | ||||||
| 
 |  | ||||||
|     rv = ', '.join(x[1] for x in rv) |  | ||||||
|     return rv, any_prefix_is_slash |  | ||||||
| @ -1,48 +0,0 @@ | |||||||
| from threading import local |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| _local = local() |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def get_current_context(silent=False): |  | ||||||
|     """Returns the current click context.  This can be used as a way to |  | ||||||
|     access the current context object from anywhere.  This is a more implicit |  | ||||||
|     alternative to the :func:`pass_context` decorator.  This function is |  | ||||||
|     primarily useful for helpers such as :func:`echo` which might be |  | ||||||
|     interested in changing it's behavior based on the current context. |  | ||||||
| 
 |  | ||||||
|     To push the current context, :meth:`Context.scope` can be used. |  | ||||||
| 
 |  | ||||||
|     .. versionadded:: 5.0 |  | ||||||
| 
 |  | ||||||
|     :param silent: is set to `True` the return value is `None` if no context |  | ||||||
|                    is available.  The default behavior is to raise a |  | ||||||
|                    :exc:`RuntimeError`. |  | ||||||
|     """ |  | ||||||
|     try: |  | ||||||
|         return getattr(_local, 'stack')[-1] |  | ||||||
|     except (AttributeError, IndexError): |  | ||||||
|         if not silent: |  | ||||||
|             raise RuntimeError('There is no active click context.') |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def push_context(ctx): |  | ||||||
|     """Pushes a new context to the current stack.""" |  | ||||||
|     _local.__dict__.setdefault('stack', []).append(ctx) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def pop_context(): |  | ||||||
|     """Removes the top level from the stack.""" |  | ||||||
|     _local.stack.pop() |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def resolve_color_default(color=None): |  | ||||||
|     """"Internal helper to get the default value of the color flag.  If a |  | ||||||
|     value is passed it's returned unchanged, otherwise it's looked up from |  | ||||||
|     the current context. |  | ||||||
|     """ |  | ||||||
|     if color is not None: |  | ||||||
|         return color |  | ||||||
|     ctx = get_current_context(silent=True) |  | ||||||
|     if ctx is not None: |  | ||||||
|         return ctx.color |  | ||||||
| @ -1,426 +0,0 @@ | |||||||
| # -*- coding: utf-8 -*- |  | ||||||
| """ |  | ||||||
|     click.parser |  | ||||||
|     ~~~~~~~~~~~~ |  | ||||||
| 
 |  | ||||||
|     This module started out as largely a copy paste from the stdlib's |  | ||||||
|     optparse module with the features removed that we do not need from |  | ||||||
|     optparse because we implement them in Click on a higher level (for |  | ||||||
|     instance type handling, help formatting and a lot more). |  | ||||||
| 
 |  | ||||||
|     The plan is to remove more and more from here over time. |  | ||||||
| 
 |  | ||||||
|     The reason this is a different module and not optparse from the stdlib |  | ||||||
|     is that there are differences in 2.x and 3.x about the error messages |  | ||||||
|     generated and optparse in the stdlib uses gettext for no good reason |  | ||||||
|     and might cause us issues. |  | ||||||
| """ |  | ||||||
| import re |  | ||||||
| from collections import deque |  | ||||||
| from .exceptions import UsageError, NoSuchOption, BadOptionUsage, \ |  | ||||||
|      BadArgumentUsage |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def _unpack_args(args, nargs_spec): |  | ||||||
|     """Given an iterable of arguments and an iterable of nargs specifications, |  | ||||||
|     it returns a tuple with all the unpacked arguments at the first index |  | ||||||
|     and all remaining arguments as the second. |  | ||||||
| 
 |  | ||||||
|     The nargs specification is the number of arguments that should be consumed |  | ||||||
|     or `-1` to indicate that this position should eat up all the remainders. |  | ||||||
| 
 |  | ||||||
|     Missing items are filled with `None`. |  | ||||||
|     """ |  | ||||||
|     args = deque(args) |  | ||||||
|     nargs_spec = deque(nargs_spec) |  | ||||||
|     rv = [] |  | ||||||
|     spos = None |  | ||||||
| 
 |  | ||||||
|     def _fetch(c): |  | ||||||
|         try: |  | ||||||
|             if spos is None: |  | ||||||
|                 return c.popleft() |  | ||||||
|             else: |  | ||||||
|                 return c.pop() |  | ||||||
|         except IndexError: |  | ||||||
|             return None |  | ||||||
| 
 |  | ||||||
|     while nargs_spec: |  | ||||||
|         nargs = _fetch(nargs_spec) |  | ||||||
|         if nargs == 1: |  | ||||||
|             rv.append(_fetch(args)) |  | ||||||
|         elif nargs > 1: |  | ||||||
|             x = [_fetch(args) for _ in range(nargs)] |  | ||||||
|             # If we're reversed, we're pulling in the arguments in reverse, |  | ||||||
|             # so we need to turn them around. |  | ||||||
|             if spos is not None: |  | ||||||
|                 x.reverse() |  | ||||||
|             rv.append(tuple(x)) |  | ||||||
|         elif nargs < 0: |  | ||||||
|             if spos is not None: |  | ||||||
|                 raise TypeError('Cannot have two nargs < 0') |  | ||||||
|             spos = len(rv) |  | ||||||
|             rv.append(None) |  | ||||||
| 
 |  | ||||||
|     # spos is the position of the wildcard (star).  If it's not `None`, |  | ||||||
|     # we fill it with the remainder. |  | ||||||
|     if spos is not None: |  | ||||||
|         rv[spos] = tuple(args) |  | ||||||
|         args = [] |  | ||||||
|         rv[spos + 1:] = reversed(rv[spos + 1:]) |  | ||||||
| 
 |  | ||||||
|     return tuple(rv), list(args) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def _error_opt_args(nargs, opt): |  | ||||||
|     if nargs == 1: |  | ||||||
|         raise BadOptionUsage('%s option requires an argument' % opt) |  | ||||||
|     raise BadOptionUsage('%s option requires %d arguments' % (opt, nargs)) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def split_opt(opt): |  | ||||||
|     first = opt[:1] |  | ||||||
|     if first.isalnum(): |  | ||||||
|         return '', opt |  | ||||||
|     if opt[1:2] == first: |  | ||||||
|         return opt[:2], opt[2:] |  | ||||||
|     return first, opt[1:] |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def normalize_opt(opt, ctx): |  | ||||||
|     if ctx is None or ctx.token_normalize_func is None: |  | ||||||
|         return opt |  | ||||||
|     prefix, opt = split_opt(opt) |  | ||||||
|     return prefix + ctx.token_normalize_func(opt) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def split_arg_string(string): |  | ||||||
|     """Given an argument string this attempts to split it into small parts.""" |  | ||||||
|     rv = [] |  | ||||||
|     for match in re.finditer(r"('([^'\\]*(?:\\.[^'\\]*)*)'" |  | ||||||
|                              r'|"([^"\\]*(?:\\.[^"\\]*)*)"' |  | ||||||
|                              r'|\S+)\s*', string, re.S): |  | ||||||
|         arg = match.group().strip() |  | ||||||
|         if arg[:1] == arg[-1:] and arg[:1] in '"\'': |  | ||||||
|             arg = arg[1:-1].encode('ascii', 'backslashreplace') \ |  | ||||||
|                 .decode('unicode-escape') |  | ||||||
|         try: |  | ||||||
|             arg = type(string)(arg) |  | ||||||
|         except UnicodeError: |  | ||||||
|             pass |  | ||||||
|         rv.append(arg) |  | ||||||
|     return rv |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class Option(object): |  | ||||||
| 
 |  | ||||||
|     def __init__(self, opts, dest, action=None, nargs=1, const=None, obj=None): |  | ||||||
|         self._short_opts = [] |  | ||||||
|         self._long_opts = [] |  | ||||||
|         self.prefixes = set() |  | ||||||
| 
 |  | ||||||
|         for opt in opts: |  | ||||||
|             prefix, value = split_opt(opt) |  | ||||||
|             if not prefix: |  | ||||||
|                 raise ValueError('Invalid start character for option (%s)' |  | ||||||
|                                  % opt) |  | ||||||
|             self.prefixes.add(prefix[0]) |  | ||||||
|             if len(prefix) == 1 and len(value) == 1: |  | ||||||
|                 self._short_opts.append(opt) |  | ||||||
|             else: |  | ||||||
|                 self._long_opts.append(opt) |  | ||||||
|                 self.prefixes.add(prefix) |  | ||||||
| 
 |  | ||||||
|         if action is None: |  | ||||||
|             action = 'store' |  | ||||||
| 
 |  | ||||||
|         self.dest = dest |  | ||||||
|         self.action = action |  | ||||||
|         self.nargs = nargs |  | ||||||
|         self.const = const |  | ||||||
|         self.obj = obj |  | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def takes_value(self): |  | ||||||
|         return self.action in ('store', 'append') |  | ||||||
| 
 |  | ||||||
|     def process(self, value, state): |  | ||||||
|         if self.action == 'store': |  | ||||||
|             state.opts[self.dest] = value |  | ||||||
|         elif self.action == 'store_const': |  | ||||||
|             state.opts[self.dest] = self.const |  | ||||||
|         elif self.action == 'append': |  | ||||||
|             state.opts.setdefault(self.dest, []).append(value) |  | ||||||
|         elif self.action == 'append_const': |  | ||||||
|             state.opts.setdefault(self.dest, []).append(self.const) |  | ||||||
|         elif self.action == 'count': |  | ||||||
|             state.opts[self.dest] = state.opts.get(self.dest, 0) + 1 |  | ||||||
|         else: |  | ||||||
|             raise ValueError('unknown action %r' % self.action) |  | ||||||
|         state.order.append(self.obj) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class Argument(object): |  | ||||||
| 
 |  | ||||||
|     def __init__(self, dest, nargs=1, obj=None): |  | ||||||
|         self.dest = dest |  | ||||||
|         self.nargs = nargs |  | ||||||
|         self.obj = obj |  | ||||||
| 
 |  | ||||||
|     def process(self, value, state): |  | ||||||
|         if self.nargs > 1: |  | ||||||
|             holes = sum(1 for x in value if x is None) |  | ||||||
|             if holes == len(value): |  | ||||||
|                 value = None |  | ||||||
|             elif holes != 0: |  | ||||||
|                 raise BadArgumentUsage('argument %s takes %d values' |  | ||||||
|                                        % (self.dest, self.nargs)) |  | ||||||
|         state.opts[self.dest] = value |  | ||||||
|         state.order.append(self.obj) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class ParsingState(object): |  | ||||||
| 
 |  | ||||||
|     def __init__(self, rargs): |  | ||||||
|         self.opts = {} |  | ||||||
|         self.largs = [] |  | ||||||
|         self.rargs = rargs |  | ||||||
|         self.order = [] |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class OptionParser(object): |  | ||||||
|     """The option parser is an internal class that is ultimately used to |  | ||||||
|     parse options and arguments.  It's modelled after optparse and brings |  | ||||||
|     a similar but vastly simplified API.  It should generally not be used |  | ||||||
|     directly as the high level Click classes wrap it for you. |  | ||||||
| 
 |  | ||||||
|     It's not nearly as extensible as optparse or argparse as it does not |  | ||||||
|     implement features that are implemented on a higher level (such as |  | ||||||
|     types or defaults). |  | ||||||
| 
 |  | ||||||
|     :param ctx: optionally the :class:`~click.Context` where this parser |  | ||||||
|                 should go with. |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     def __init__(self, ctx=None): |  | ||||||
|         #: The :class:`~click.Context` for this parser.  This might be |  | ||||||
|         #: `None` for some advanced use cases. |  | ||||||
|         self.ctx = ctx |  | ||||||
|         #: This controls how the parser deals with interspersed arguments. |  | ||||||
|         #: If this is set to `False`, the parser will stop on the first |  | ||||||
|         #: non-option.  Click uses this to implement nested subcommands |  | ||||||
|         #: safely. |  | ||||||
|         self.allow_interspersed_args = True |  | ||||||
|         #: This tells the parser how to deal with unknown options.  By |  | ||||||
|         #: default it will error out (which is sensible), but there is a |  | ||||||
|         #: second mode where it will ignore it and continue processing |  | ||||||
|         #: after shifting all the unknown options into the resulting args. |  | ||||||
|         self.ignore_unknown_options = False |  | ||||||
|         if ctx is not None: |  | ||||||
|             self.allow_interspersed_args = ctx.allow_interspersed_args |  | ||||||
|             self.ignore_unknown_options = ctx.ignore_unknown_options |  | ||||||
|         self._short_opt = {} |  | ||||||
|         self._long_opt = {} |  | ||||||
|         self._opt_prefixes = set(['-', '--']) |  | ||||||
|         self._args = [] |  | ||||||
| 
 |  | ||||||
|     def add_option(self, opts, dest, action=None, nargs=1, const=None, |  | ||||||
|                    obj=None): |  | ||||||
|         """Adds a new option named `dest` to the parser.  The destination |  | ||||||
|         is not inferred (unlike with optparse) and needs to be explicitly |  | ||||||
|         provided.  Action can be any of ``store``, ``store_const``, |  | ||||||
|         ``append``, ``appnd_const`` or ``count``. |  | ||||||
| 
 |  | ||||||
|         The `obj` can be used to identify the option in the order list |  | ||||||
|         that is returned from the parser. |  | ||||||
|         """ |  | ||||||
|         if obj is None: |  | ||||||
|             obj = dest |  | ||||||
|         opts = [normalize_opt(opt, self.ctx) for opt in opts] |  | ||||||
|         option = Option(opts, dest, action=action, nargs=nargs, |  | ||||||
|                         const=const, obj=obj) |  | ||||||
|         self._opt_prefixes.update(option.prefixes) |  | ||||||
|         for opt in option._short_opts: |  | ||||||
|             self._short_opt[opt] = option |  | ||||||
|         for opt in option._long_opts: |  | ||||||
|             self._long_opt[opt] = option |  | ||||||
| 
 |  | ||||||
|     def add_argument(self, dest, nargs=1, obj=None): |  | ||||||
|         """Adds a positional argument named `dest` to the parser. |  | ||||||
| 
 |  | ||||||
|         The `obj` can be used to identify the option in the order list |  | ||||||
|         that is returned from the parser. |  | ||||||
|         """ |  | ||||||
|         if obj is None: |  | ||||||
|             obj = dest |  | ||||||
|         self._args.append(Argument(dest=dest, nargs=nargs, obj=obj)) |  | ||||||
| 
 |  | ||||||
|     def parse_args(self, args): |  | ||||||
|         """Parses positional arguments and returns ``(values, args, order)`` |  | ||||||
|         for the parsed options and arguments as well as the leftover |  | ||||||
|         arguments if there are any.  The order is a list of objects as they |  | ||||||
|         appear on the command line.  If arguments appear multiple times they |  | ||||||
|         will be memorized multiple times as well. |  | ||||||
|         """ |  | ||||||
|         state = ParsingState(args) |  | ||||||
|         try: |  | ||||||
|             self._process_args_for_options(state) |  | ||||||
|             self._process_args_for_args(state) |  | ||||||
|         except UsageError: |  | ||||||
|             if self.ctx is None or not self.ctx.resilient_parsing: |  | ||||||
|                 raise |  | ||||||
|         return state.opts, state.largs, state.order |  | ||||||
| 
 |  | ||||||
|     def _process_args_for_args(self, state): |  | ||||||
|         pargs, args = _unpack_args(state.largs + state.rargs, |  | ||||||
|                                    [x.nargs for x in self._args]) |  | ||||||
| 
 |  | ||||||
|         for idx, arg in enumerate(self._args): |  | ||||||
|             arg.process(pargs[idx], state) |  | ||||||
| 
 |  | ||||||
|         state.largs = args |  | ||||||
|         state.rargs = [] |  | ||||||
| 
 |  | ||||||
|     def _process_args_for_options(self, state): |  | ||||||
|         while state.rargs: |  | ||||||
|             arg = state.rargs.pop(0) |  | ||||||
|             arglen = len(arg) |  | ||||||
|             # Double dashes always handled explicitly regardless of what |  | ||||||
|             # prefixes are valid. |  | ||||||
|             if arg == '--': |  | ||||||
|                 return |  | ||||||
|             elif arg[:1] in self._opt_prefixes and arglen > 1: |  | ||||||
|                 self._process_opts(arg, state) |  | ||||||
|             elif self.allow_interspersed_args: |  | ||||||
|                 state.largs.append(arg) |  | ||||||
|             else: |  | ||||||
|                 state.rargs.insert(0, arg) |  | ||||||
|                 return |  | ||||||
| 
 |  | ||||||
|         # Say this is the original argument list: |  | ||||||
|         # [arg0, arg1, ..., arg(i-1), arg(i), arg(i+1), ..., arg(N-1)] |  | ||||||
|         #                            ^ |  | ||||||
|         # (we are about to process arg(i)). |  | ||||||
|         # |  | ||||||
|         # Then rargs is [arg(i), ..., arg(N-1)] and largs is a *subset* of |  | ||||||
|         # [arg0, ..., arg(i-1)] (any options and their arguments will have |  | ||||||
|         # been removed from largs). |  | ||||||
|         # |  | ||||||
|         # The while loop will usually consume 1 or more arguments per pass. |  | ||||||
|         # If it consumes 1 (eg. arg is an option that takes no arguments), |  | ||||||
|         # then after _process_arg() is done the situation is: |  | ||||||
|         # |  | ||||||
|         #   largs = subset of [arg0, ..., arg(i)] |  | ||||||
|         #   rargs = [arg(i+1), ..., arg(N-1)] |  | ||||||
|         # |  | ||||||
|         # If allow_interspersed_args is false, largs will always be |  | ||||||
|         # *empty* -- still a subset of [arg0, ..., arg(i-1)], but |  | ||||||
|         # not a very interesting subset! |  | ||||||
| 
 |  | ||||||
|     def _match_long_opt(self, opt, explicit_value, state): |  | ||||||
|         if opt not in self._long_opt: |  | ||||||
|             possibilities = [word for word in self._long_opt |  | ||||||
|                              if word.startswith(opt)] |  | ||||||
|             raise NoSuchOption(opt, possibilities=possibilities) |  | ||||||
| 
 |  | ||||||
|         option = self._long_opt[opt] |  | ||||||
|         if option.takes_value: |  | ||||||
|             # At this point it's safe to modify rargs by injecting the |  | ||||||
|             # explicit value, because no exception is raised in this |  | ||||||
|             # branch.  This means that the inserted value will be fully |  | ||||||
|             # consumed. |  | ||||||
|             if explicit_value is not None: |  | ||||||
|                 state.rargs.insert(0, explicit_value) |  | ||||||
| 
 |  | ||||||
|             nargs = option.nargs |  | ||||||
|             if len(state.rargs) < nargs: |  | ||||||
|                 _error_opt_args(nargs, opt) |  | ||||||
|             elif nargs == 1: |  | ||||||
|                 value = state.rargs.pop(0) |  | ||||||
|             else: |  | ||||||
|                 value = tuple(state.rargs[:nargs]) |  | ||||||
|                 del state.rargs[:nargs] |  | ||||||
| 
 |  | ||||||
|         elif explicit_value is not None: |  | ||||||
|             raise BadOptionUsage('%s option does not take a value' % opt) |  | ||||||
| 
 |  | ||||||
|         else: |  | ||||||
|             value = None |  | ||||||
| 
 |  | ||||||
|         option.process(value, state) |  | ||||||
| 
 |  | ||||||
|     def _match_short_opt(self, arg, state): |  | ||||||
|         stop = False |  | ||||||
|         i = 1 |  | ||||||
|         prefix = arg[0] |  | ||||||
|         unknown_options = [] |  | ||||||
| 
 |  | ||||||
|         for ch in arg[1:]: |  | ||||||
|             opt = normalize_opt(prefix + ch, self.ctx) |  | ||||||
|             option = self._short_opt.get(opt) |  | ||||||
|             i += 1 |  | ||||||
| 
 |  | ||||||
|             if not option: |  | ||||||
|                 if self.ignore_unknown_options: |  | ||||||
|                     unknown_options.append(ch) |  | ||||||
|                     continue |  | ||||||
|                 raise NoSuchOption(opt) |  | ||||||
|             if option.takes_value: |  | ||||||
|                 # Any characters left in arg?  Pretend they're the |  | ||||||
|                 # next arg, and stop consuming characters of arg. |  | ||||||
|                 if i < len(arg): |  | ||||||
|                     state.rargs.insert(0, arg[i:]) |  | ||||||
|                     stop = True |  | ||||||
| 
 |  | ||||||
|                 nargs = option.nargs |  | ||||||
|                 if len(state.rargs) < nargs: |  | ||||||
|                     _error_opt_args(nargs, opt) |  | ||||||
|                 elif nargs == 1: |  | ||||||
|                     value = state.rargs.pop(0) |  | ||||||
|                 else: |  | ||||||
|                     value = tuple(state.rargs[:nargs]) |  | ||||||
|                     del state.rargs[:nargs] |  | ||||||
| 
 |  | ||||||
|             else: |  | ||||||
|                 value = None |  | ||||||
| 
 |  | ||||||
|             option.process(value, state) |  | ||||||
| 
 |  | ||||||
|             if stop: |  | ||||||
|                 break |  | ||||||
| 
 |  | ||||||
|         # If we got any unknown options we re-combinate the string of the |  | ||||||
|         # remaining options and re-attach the prefix, then report that |  | ||||||
|         # to the state as new larg.  This way there is basic combinatorics |  | ||||||
|         # that can be achieved while still ignoring unknown arguments. |  | ||||||
|         if self.ignore_unknown_options and unknown_options: |  | ||||||
|             state.largs.append(prefix + ''.join(unknown_options)) |  | ||||||
| 
 |  | ||||||
|     def _process_opts(self, arg, state): |  | ||||||
|         explicit_value = None |  | ||||||
|         # Long option handling happens in two parts.  The first part is |  | ||||||
|         # supporting explicitly attached values.  In any case, we will try |  | ||||||
|         # to long match the option first. |  | ||||||
|         if '=' in arg: |  | ||||||
|             long_opt, explicit_value = arg.split('=', 1) |  | ||||||
|         else: |  | ||||||
|             long_opt = arg |  | ||||||
|         norm_long_opt = normalize_opt(long_opt, self.ctx) |  | ||||||
| 
 |  | ||||||
|         # At this point we will match the (assumed) long option through |  | ||||||
|         # the long option matching code.  Note that this allows options |  | ||||||
|         # like "-foo" to be matched as long options. |  | ||||||
|         try: |  | ||||||
|             self._match_long_opt(norm_long_opt, explicit_value, state) |  | ||||||
|         except NoSuchOption: |  | ||||||
|             # At this point the long option matching failed, and we need |  | ||||||
|             # to try with short options.  However there is a special rule |  | ||||||
|             # which says, that if we have a two character options prefix |  | ||||||
|             # (applies to "--foo" for instance), we do not dispatch to the |  | ||||||
|             # short option code and will instead raise the no option |  | ||||||
|             # error. |  | ||||||
|             if arg[:2] not in self._opt_prefixes: |  | ||||||
|                 return self._match_short_opt(arg, state) |  | ||||||
|             if not self.ignore_unknown_options: |  | ||||||
|                 raise |  | ||||||
|             state.largs.append(arg) |  | ||||||
| @ -1,539 +0,0 @@ | |||||||
| import os |  | ||||||
| import sys |  | ||||||
| import struct |  | ||||||
| 
 |  | ||||||
| from ._compat import raw_input, text_type, string_types, \ |  | ||||||
|      isatty, strip_ansi, get_winterm_size, DEFAULT_COLUMNS, WIN |  | ||||||
| from .utils import echo |  | ||||||
| from .exceptions import Abort, UsageError |  | ||||||
| from .types import convert_type |  | ||||||
| from .globals import resolve_color_default |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| # The prompt functions to use.  The doc tools currently override these |  | ||||||
| # functions to customize how they work. |  | ||||||
| visible_prompt_func = raw_input |  | ||||||
| 
 |  | ||||||
| _ansi_colors = ('black', 'red', 'green', 'yellow', 'blue', 'magenta', |  | ||||||
|                 'cyan', 'white', 'reset') |  | ||||||
| _ansi_reset_all = '\033[0m' |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def hidden_prompt_func(prompt): |  | ||||||
|     import getpass |  | ||||||
|     return getpass.getpass(prompt) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def _build_prompt(text, suffix, show_default=False, default=None): |  | ||||||
|     prompt = text |  | ||||||
|     if default is not None and show_default: |  | ||||||
|         prompt = '%s [%s]' % (prompt, default) |  | ||||||
|     return prompt + suffix |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def prompt(text, default=None, hide_input=False, |  | ||||||
|            confirmation_prompt=False, type=None, |  | ||||||
|            value_proc=None, prompt_suffix=': ', |  | ||||||
|            show_default=True, err=False): |  | ||||||
|     """Prompts a user for input.  This is a convenience function that can |  | ||||||
|     be used to prompt a user for input later. |  | ||||||
| 
 |  | ||||||
|     If the user aborts the input by sending a interrupt signal, this |  | ||||||
|     function will catch it and raise a :exc:`Abort` exception. |  | ||||||
| 
 |  | ||||||
|     .. versionadded:: 6.0 |  | ||||||
|        Added unicode support for cmd.exe on Windows. |  | ||||||
| 
 |  | ||||||
|     .. versionadded:: 4.0 |  | ||||||
|        Added the `err` parameter. |  | ||||||
| 
 |  | ||||||
|     :param text: the text to show for the prompt. |  | ||||||
|     :param default: the default value to use if no input happens.  If this |  | ||||||
|                     is not given it will prompt until it's aborted. |  | ||||||
|     :param hide_input: if this is set to true then the input value will |  | ||||||
|                        be hidden. |  | ||||||
|     :param confirmation_prompt: asks for confirmation for the value. |  | ||||||
|     :param type: the type to use to check the value against. |  | ||||||
|     :param value_proc: if this parameter is provided it's a function that |  | ||||||
|                        is invoked instead of the type conversion to |  | ||||||
|                        convert a value. |  | ||||||
|     :param prompt_suffix: a suffix that should be added to the prompt. |  | ||||||
|     :param show_default: shows or hides the default value in the prompt. |  | ||||||
|     :param err: if set to true the file defaults to ``stderr`` instead of |  | ||||||
|                 ``stdout``, the same as with echo. |  | ||||||
|     """ |  | ||||||
|     result = None |  | ||||||
| 
 |  | ||||||
|     def prompt_func(text): |  | ||||||
|         f = hide_input and hidden_prompt_func or visible_prompt_func |  | ||||||
|         try: |  | ||||||
|             # Write the prompt separately so that we get nice |  | ||||||
|             # coloring through colorama on Windows |  | ||||||
|             echo(text, nl=False, err=err) |  | ||||||
|             return f('') |  | ||||||
|         except (KeyboardInterrupt, EOFError): |  | ||||||
|             # getpass doesn't print a newline if the user aborts input with ^C. |  | ||||||
|             # Allegedly this behavior is inherited from getpass(3). |  | ||||||
|             # A doc bug has been filed at https://bugs.python.org/issue24711 |  | ||||||
|             if hide_input: |  | ||||||
|                 echo(None, err=err) |  | ||||||
|             raise Abort() |  | ||||||
| 
 |  | ||||||
|     if value_proc is None: |  | ||||||
|         value_proc = convert_type(type, default) |  | ||||||
| 
 |  | ||||||
|     prompt = _build_prompt(text, prompt_suffix, show_default, default) |  | ||||||
| 
 |  | ||||||
|     while 1: |  | ||||||
|         while 1: |  | ||||||
|             value = prompt_func(prompt) |  | ||||||
|             if value: |  | ||||||
|                 break |  | ||||||
|             # If a default is set and used, then the confirmation |  | ||||||
|             # prompt is always skipped because that's the only thing |  | ||||||
|             # that really makes sense. |  | ||||||
|             elif default is not None: |  | ||||||
|                 return default |  | ||||||
|         try: |  | ||||||
|             result = value_proc(value) |  | ||||||
|         except UsageError as e: |  | ||||||
|             echo('Error: %s' % e.message, err=err) |  | ||||||
|             continue |  | ||||||
|         if not confirmation_prompt: |  | ||||||
|             return result |  | ||||||
|         while 1: |  | ||||||
|             value2 = prompt_func('Repeat for confirmation: ') |  | ||||||
|             if value2: |  | ||||||
|                 break |  | ||||||
|         if value == value2: |  | ||||||
|             return result |  | ||||||
|         echo('Error: the two entered values do not match', err=err) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def confirm(text, default=False, abort=False, prompt_suffix=': ', |  | ||||||
|             show_default=True, err=False): |  | ||||||
|     """Prompts for confirmation (yes/no question). |  | ||||||
| 
 |  | ||||||
|     If the user aborts the input by sending a interrupt signal this |  | ||||||
|     function will catch it and raise a :exc:`Abort` exception. |  | ||||||
| 
 |  | ||||||
|     .. versionadded:: 4.0 |  | ||||||
|        Added the `err` parameter. |  | ||||||
| 
 |  | ||||||
|     :param text: the question to ask. |  | ||||||
|     :param default: the default for the prompt. |  | ||||||
|     :param abort: if this is set to `True` a negative answer aborts the |  | ||||||
|                   exception by raising :exc:`Abort`. |  | ||||||
|     :param prompt_suffix: a suffix that should be added to the prompt. |  | ||||||
|     :param show_default: shows or hides the default value in the prompt. |  | ||||||
|     :param err: if set to true the file defaults to ``stderr`` instead of |  | ||||||
|                 ``stdout``, the same as with echo. |  | ||||||
|     """ |  | ||||||
|     prompt = _build_prompt(text, prompt_suffix, show_default, |  | ||||||
|                            default and 'Y/n' or 'y/N') |  | ||||||
|     while 1: |  | ||||||
|         try: |  | ||||||
|             # Write the prompt separately so that we get nice |  | ||||||
|             # coloring through colorama on Windows |  | ||||||
|             echo(prompt, nl=False, err=err) |  | ||||||
|             value = visible_prompt_func('').lower().strip() |  | ||||||
|         except (KeyboardInterrupt, EOFError): |  | ||||||
|             raise Abort() |  | ||||||
|         if value in ('y', 'yes'): |  | ||||||
|             rv = True |  | ||||||
|         elif value in ('n', 'no'): |  | ||||||
|             rv = False |  | ||||||
|         elif value == '': |  | ||||||
|             rv = default |  | ||||||
|         else: |  | ||||||
|             echo('Error: invalid input', err=err) |  | ||||||
|             continue |  | ||||||
|         break |  | ||||||
|     if abort and not rv: |  | ||||||
|         raise Abort() |  | ||||||
|     return rv |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def get_terminal_size(): |  | ||||||
|     """Returns the current size of the terminal as tuple in the form |  | ||||||
|     ``(width, height)`` in columns and rows. |  | ||||||
|     """ |  | ||||||
|     # If shutil has get_terminal_size() (Python 3.3 and later) use that |  | ||||||
|     if sys.version_info >= (3, 3): |  | ||||||
|         import shutil |  | ||||||
|         shutil_get_terminal_size = getattr(shutil, 'get_terminal_size', None) |  | ||||||
|         if shutil_get_terminal_size: |  | ||||||
|             sz = shutil_get_terminal_size() |  | ||||||
|             return sz.columns, sz.lines |  | ||||||
| 
 |  | ||||||
|     if get_winterm_size is not None: |  | ||||||
|         return get_winterm_size() |  | ||||||
| 
 |  | ||||||
|     def ioctl_gwinsz(fd): |  | ||||||
|         try: |  | ||||||
|             import fcntl |  | ||||||
|             import termios |  | ||||||
|             cr = struct.unpack( |  | ||||||
|                 'hh', fcntl.ioctl(fd, termios.TIOCGWINSZ, '1234')) |  | ||||||
|         except Exception: |  | ||||||
|             return |  | ||||||
|         return cr |  | ||||||
| 
 |  | ||||||
|     cr = ioctl_gwinsz(0) or ioctl_gwinsz(1) or ioctl_gwinsz(2) |  | ||||||
|     if not cr: |  | ||||||
|         try: |  | ||||||
|             fd = os.open(os.ctermid(), os.O_RDONLY) |  | ||||||
|             try: |  | ||||||
|                 cr = ioctl_gwinsz(fd) |  | ||||||
|             finally: |  | ||||||
|                 os.close(fd) |  | ||||||
|         except Exception: |  | ||||||
|             pass |  | ||||||
|     if not cr or not cr[0] or not cr[1]: |  | ||||||
|         cr = (os.environ.get('LINES', 25), |  | ||||||
|               os.environ.get('COLUMNS', DEFAULT_COLUMNS)) |  | ||||||
|     return int(cr[1]), int(cr[0]) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def echo_via_pager(text, color=None): |  | ||||||
|     """This function takes a text and shows it via an environment specific |  | ||||||
|     pager on stdout. |  | ||||||
| 
 |  | ||||||
|     .. versionchanged:: 3.0 |  | ||||||
|        Added the `color` flag. |  | ||||||
| 
 |  | ||||||
|     :param text: the text to page. |  | ||||||
|     :param color: controls if the pager supports ANSI colors or not.  The |  | ||||||
|                   default is autodetection. |  | ||||||
|     """ |  | ||||||
|     color = resolve_color_default(color) |  | ||||||
|     if not isinstance(text, string_types): |  | ||||||
|         text = text_type(text) |  | ||||||
|     from ._termui_impl import pager |  | ||||||
|     return pager(text + '\n', color) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def progressbar(iterable=None, length=None, label=None, show_eta=True, |  | ||||||
|                 show_percent=None, show_pos=False, |  | ||||||
|                 item_show_func=None, fill_char='#', empty_char='-', |  | ||||||
|                 bar_template='%(label)s  [%(bar)s]  %(info)s', |  | ||||||
|                 info_sep='  ', width=36, file=None, color=None): |  | ||||||
|     """This function creates an iterable context manager that can be used |  | ||||||
|     to iterate over something while showing a progress bar.  It will |  | ||||||
|     either iterate over the `iterable` or `length` items (that are counted |  | ||||||
|     up).  While iteration happens, this function will print a rendered |  | ||||||
|     progress bar to the given `file` (defaults to stdout) and will attempt |  | ||||||
|     to calculate remaining time and more.  By default, this progress bar |  | ||||||
|     will not be rendered if the file is not a terminal. |  | ||||||
| 
 |  | ||||||
|     The context manager creates the progress bar.  When the context |  | ||||||
|     manager is entered the progress bar is already displayed.  With every |  | ||||||
|     iteration over the progress bar, the iterable passed to the bar is |  | ||||||
|     advanced and the bar is updated.  When the context manager exits, |  | ||||||
|     a newline is printed and the progress bar is finalized on screen. |  | ||||||
| 
 |  | ||||||
|     No printing must happen or the progress bar will be unintentionally |  | ||||||
|     destroyed. |  | ||||||
| 
 |  | ||||||
|     Example usage:: |  | ||||||
| 
 |  | ||||||
|         with progressbar(items) as bar: |  | ||||||
|             for item in bar: |  | ||||||
|                 do_something_with(item) |  | ||||||
| 
 |  | ||||||
|     Alternatively, if no iterable is specified, one can manually update the |  | ||||||
|     progress bar through the `update()` method instead of directly |  | ||||||
|     iterating over the progress bar.  The update method accepts the number |  | ||||||
|     of steps to increment the bar with:: |  | ||||||
| 
 |  | ||||||
|         with progressbar(length=chunks.total_bytes) as bar: |  | ||||||
|             for chunk in chunks: |  | ||||||
|                 process_chunk(chunk) |  | ||||||
|                 bar.update(chunks.bytes) |  | ||||||
| 
 |  | ||||||
|     .. versionadded:: 2.0 |  | ||||||
| 
 |  | ||||||
|     .. versionadded:: 4.0 |  | ||||||
|        Added the `color` parameter.  Added a `update` method to the |  | ||||||
|        progressbar object. |  | ||||||
| 
 |  | ||||||
|     :param iterable: an iterable to iterate over.  If not provided the length |  | ||||||
|                      is required. |  | ||||||
|     :param length: the number of items to iterate over.  By default the |  | ||||||
|                    progressbar will attempt to ask the iterator about its |  | ||||||
|                    length, which might or might not work.  If an iterable is |  | ||||||
|                    also provided this parameter can be used to override the |  | ||||||
|                    length.  If an iterable is not provided the progress bar |  | ||||||
|                    will iterate over a range of that length. |  | ||||||
|     :param label: the label to show next to the progress bar. |  | ||||||
|     :param show_eta: enables or disables the estimated time display.  This is |  | ||||||
|                      automatically disabled if the length cannot be |  | ||||||
|                      determined. |  | ||||||
|     :param show_percent: enables or disables the percentage display.  The |  | ||||||
|                          default is `True` if the iterable has a length or |  | ||||||
|                          `False` if not. |  | ||||||
|     :param show_pos: enables or disables the absolute position display.  The |  | ||||||
|                      default is `False`. |  | ||||||
|     :param item_show_func: a function called with the current item which |  | ||||||
|                            can return a string to show the current item |  | ||||||
|                            next to the progress bar.  Note that the current |  | ||||||
|                            item can be `None`! |  | ||||||
|     :param fill_char: the character to use to show the filled part of the |  | ||||||
|                       progress bar. |  | ||||||
|     :param empty_char: the character to use to show the non-filled part of |  | ||||||
|                        the progress bar. |  | ||||||
|     :param bar_template: the format string to use as template for the bar. |  | ||||||
|                          The parameters in it are ``label`` for the label, |  | ||||||
|                          ``bar`` for the progress bar and ``info`` for the |  | ||||||
|                          info section. |  | ||||||
|     :param info_sep: the separator between multiple info items (eta etc.) |  | ||||||
|     :param width: the width of the progress bar in characters, 0 means full |  | ||||||
|                   terminal width |  | ||||||
|     :param file: the file to write to.  If this is not a terminal then |  | ||||||
|                  only the label is printed. |  | ||||||
|     :param color: controls if the terminal supports ANSI colors or not.  The |  | ||||||
|                   default is autodetection.  This is only needed if ANSI |  | ||||||
|                   codes are included anywhere in the progress bar output |  | ||||||
|                   which is not the case by default. |  | ||||||
|     """ |  | ||||||
|     from ._termui_impl import ProgressBar |  | ||||||
|     color = resolve_color_default(color) |  | ||||||
|     return ProgressBar(iterable=iterable, length=length, show_eta=show_eta, |  | ||||||
|                        show_percent=show_percent, show_pos=show_pos, |  | ||||||
|                        item_show_func=item_show_func, fill_char=fill_char, |  | ||||||
|                        empty_char=empty_char, bar_template=bar_template, |  | ||||||
|                        info_sep=info_sep, file=file, label=label, |  | ||||||
|                        width=width, color=color) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def clear(): |  | ||||||
|     """Clears the terminal screen.  This will have the effect of clearing |  | ||||||
|     the whole visible space of the terminal and moving the cursor to the |  | ||||||
|     top left.  This does not do anything if not connected to a terminal. |  | ||||||
| 
 |  | ||||||
|     .. versionadded:: 2.0 |  | ||||||
|     """ |  | ||||||
|     if not isatty(sys.stdout): |  | ||||||
|         return |  | ||||||
|     # If we're on Windows and we don't have colorama available, then we |  | ||||||
|     # clear the screen by shelling out.  Otherwise we can use an escape |  | ||||||
|     # sequence. |  | ||||||
|     if WIN: |  | ||||||
|         os.system('cls') |  | ||||||
|     else: |  | ||||||
|         sys.stdout.write('\033[2J\033[1;1H') |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def style(text, fg=None, bg=None, bold=None, dim=None, underline=None, |  | ||||||
|           blink=None, reverse=None, reset=True): |  | ||||||
|     """Styles a text with ANSI styles and returns the new string.  By |  | ||||||
|     default the styling is self contained which means that at the end |  | ||||||
|     of the string a reset code is issued.  This can be prevented by |  | ||||||
|     passing ``reset=False``. |  | ||||||
| 
 |  | ||||||
|     Examples:: |  | ||||||
| 
 |  | ||||||
|         click.echo(click.style('Hello World!', fg='green')) |  | ||||||
|         click.echo(click.style('ATTENTION!', blink=True)) |  | ||||||
|         click.echo(click.style('Some things', reverse=True, fg='cyan')) |  | ||||||
| 
 |  | ||||||
|     Supported color names: |  | ||||||
| 
 |  | ||||||
|     * ``black`` (might be a gray) |  | ||||||
|     * ``red`` |  | ||||||
|     * ``green`` |  | ||||||
|     * ``yellow`` (might be an orange) |  | ||||||
|     * ``blue`` |  | ||||||
|     * ``magenta`` |  | ||||||
|     * ``cyan`` |  | ||||||
|     * ``white`` (might be light gray) |  | ||||||
|     * ``reset`` (reset the color code only) |  | ||||||
| 
 |  | ||||||
|     .. versionadded:: 2.0 |  | ||||||
| 
 |  | ||||||
|     :param text: the string to style with ansi codes. |  | ||||||
|     :param fg: if provided this will become the foreground color. |  | ||||||
|     :param bg: if provided this will become the background color. |  | ||||||
|     :param bold: if provided this will enable or disable bold mode. |  | ||||||
|     :param dim: if provided this will enable or disable dim mode.  This is |  | ||||||
|                 badly supported. |  | ||||||
|     :param underline: if provided this will enable or disable underline. |  | ||||||
|     :param blink: if provided this will enable or disable blinking. |  | ||||||
|     :param reverse: if provided this will enable or disable inverse |  | ||||||
|                     rendering (foreground becomes background and the |  | ||||||
|                     other way round). |  | ||||||
|     :param reset: by default a reset-all code is added at the end of the |  | ||||||
|                   string which means that styles do not carry over.  This |  | ||||||
|                   can be disabled to compose styles. |  | ||||||
|     """ |  | ||||||
|     bits = [] |  | ||||||
|     if fg: |  | ||||||
|         try: |  | ||||||
|             bits.append('\033[%dm' % (_ansi_colors.index(fg) + 30)) |  | ||||||
|         except ValueError: |  | ||||||
|             raise TypeError('Unknown color %r' % fg) |  | ||||||
|     if bg: |  | ||||||
|         try: |  | ||||||
|             bits.append('\033[%dm' % (_ansi_colors.index(bg) + 40)) |  | ||||||
|         except ValueError: |  | ||||||
|             raise TypeError('Unknown color %r' % bg) |  | ||||||
|     if bold is not None: |  | ||||||
|         bits.append('\033[%dm' % (1 if bold else 22)) |  | ||||||
|     if dim is not None: |  | ||||||
|         bits.append('\033[%dm' % (2 if dim else 22)) |  | ||||||
|     if underline is not None: |  | ||||||
|         bits.append('\033[%dm' % (4 if underline else 24)) |  | ||||||
|     if blink is not None: |  | ||||||
|         bits.append('\033[%dm' % (5 if blink else 25)) |  | ||||||
|     if reverse is not None: |  | ||||||
|         bits.append('\033[%dm' % (7 if reverse else 27)) |  | ||||||
|     bits.append(text) |  | ||||||
|     if reset: |  | ||||||
|         bits.append(_ansi_reset_all) |  | ||||||
|     return ''.join(bits) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def unstyle(text): |  | ||||||
|     """Removes ANSI styling information from a string.  Usually it's not |  | ||||||
|     necessary to use this function as Click's echo function will |  | ||||||
|     automatically remove styling if necessary. |  | ||||||
| 
 |  | ||||||
|     .. versionadded:: 2.0 |  | ||||||
| 
 |  | ||||||
|     :param text: the text to remove style information from. |  | ||||||
|     """ |  | ||||||
|     return strip_ansi(text) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def secho(text, file=None, nl=True, err=False, color=None, **styles): |  | ||||||
|     """This function combines :func:`echo` and :func:`style` into one |  | ||||||
|     call.  As such the following two calls are the same:: |  | ||||||
| 
 |  | ||||||
|         click.secho('Hello World!', fg='green') |  | ||||||
|         click.echo(click.style('Hello World!', fg='green')) |  | ||||||
| 
 |  | ||||||
|     All keyword arguments are forwarded to the underlying functions |  | ||||||
|     depending on which one they go with. |  | ||||||
| 
 |  | ||||||
|     .. versionadded:: 2.0 |  | ||||||
|     """ |  | ||||||
|     return echo(style(text, **styles), file=file, nl=nl, err=err, color=color) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def edit(text=None, editor=None, env=None, require_save=True, |  | ||||||
|          extension='.txt', filename=None): |  | ||||||
|     r"""Edits the given text in the defined editor.  If an editor is given |  | ||||||
|     (should be the full path to the executable but the regular operating |  | ||||||
|     system search path is used for finding the executable) it overrides |  | ||||||
|     the detected editor.  Optionally, some environment variables can be |  | ||||||
|     used.  If the editor is closed without changes, `None` is returned.  In |  | ||||||
|     case a file is edited directly the return value is always `None` and |  | ||||||
|     `require_save` and `extension` are ignored. |  | ||||||
| 
 |  | ||||||
|     If the editor cannot be opened a :exc:`UsageError` is raised. |  | ||||||
| 
 |  | ||||||
|     Note for Windows: to simplify cross-platform usage, the newlines are |  | ||||||
|     automatically converted from POSIX to Windows and vice versa.  As such, |  | ||||||
|     the message here will have ``\n`` as newline markers. |  | ||||||
| 
 |  | ||||||
|     :param text: the text to edit. |  | ||||||
|     :param editor: optionally the editor to use.  Defaults to automatic |  | ||||||
|                    detection. |  | ||||||
|     :param env: environment variables to forward to the editor. |  | ||||||
|     :param require_save: if this is true, then not saving in the editor |  | ||||||
|                          will make the return value become `None`. |  | ||||||
|     :param extension: the extension to tell the editor about.  This defaults |  | ||||||
|                       to `.txt` but changing this might change syntax |  | ||||||
|                       highlighting. |  | ||||||
|     :param filename: if provided it will edit this file instead of the |  | ||||||
|                      provided text contents.  It will not use a temporary |  | ||||||
|                      file as an indirection in that case. |  | ||||||
|     """ |  | ||||||
|     from ._termui_impl import Editor |  | ||||||
|     editor = Editor(editor=editor, env=env, require_save=require_save, |  | ||||||
|                     extension=extension) |  | ||||||
|     if filename is None: |  | ||||||
|         return editor.edit(text) |  | ||||||
|     editor.edit_file(filename) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def launch(url, wait=False, locate=False): |  | ||||||
|     """This function launches the given URL (or filename) in the default |  | ||||||
|     viewer application for this file type.  If this is an executable, it |  | ||||||
|     might launch the executable in a new session.  The return value is |  | ||||||
|     the exit code of the launched application.  Usually, ``0`` indicates |  | ||||||
|     success. |  | ||||||
| 
 |  | ||||||
|     Examples:: |  | ||||||
| 
 |  | ||||||
|         click.launch('http://click.pocoo.org/') |  | ||||||
|         click.launch('/my/downloaded/file', locate=True) |  | ||||||
| 
 |  | ||||||
|     .. versionadded:: 2.0 |  | ||||||
| 
 |  | ||||||
|     :param url: URL or filename of the thing to launch. |  | ||||||
|     :param wait: waits for the program to stop. |  | ||||||
|     :param locate: if this is set to `True` then instead of launching the |  | ||||||
|                    application associated with the URL it will attempt to |  | ||||||
|                    launch a file manager with the file located.  This |  | ||||||
|                    might have weird effects if the URL does not point to |  | ||||||
|                    the filesystem. |  | ||||||
|     """ |  | ||||||
|     from ._termui_impl import open_url |  | ||||||
|     return open_url(url, wait=wait, locate=locate) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| # If this is provided, getchar() calls into this instead.  This is used |  | ||||||
| # for unittesting purposes. |  | ||||||
| _getchar = None |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def getchar(echo=False): |  | ||||||
|     """Fetches a single character from the terminal and returns it.  This |  | ||||||
|     will always return a unicode character and under certain rare |  | ||||||
|     circumstances this might return more than one character.  The |  | ||||||
|     situations which more than one character is returned is when for |  | ||||||
|     whatever reason multiple characters end up in the terminal buffer or |  | ||||||
|     standard input was not actually a terminal. |  | ||||||
| 
 |  | ||||||
|     Note that this will always read from the terminal, even if something |  | ||||||
|     is piped into the standard input. |  | ||||||
| 
 |  | ||||||
|     .. versionadded:: 2.0 |  | ||||||
| 
 |  | ||||||
|     :param echo: if set to `True`, the character read will also show up on |  | ||||||
|                  the terminal.  The default is to not show it. |  | ||||||
|     """ |  | ||||||
|     f = _getchar |  | ||||||
|     if f is None: |  | ||||||
|         from ._termui_impl import getchar as f |  | ||||||
|     return f(echo) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def pause(info='Press any key to continue ...', err=False): |  | ||||||
|     """This command stops execution and waits for the user to press any |  | ||||||
|     key to continue.  This is similar to the Windows batch "pause" |  | ||||||
|     command.  If the program is not run through a terminal, this command |  | ||||||
|     will instead do nothing. |  | ||||||
| 
 |  | ||||||
|     .. versionadded:: 2.0 |  | ||||||
| 
 |  | ||||||
|     .. versionadded:: 4.0 |  | ||||||
|        Added the `err` parameter. |  | ||||||
| 
 |  | ||||||
|     :param info: the info string to print before pausing. |  | ||||||
|     :param err: if set to message goes to ``stderr`` instead of |  | ||||||
|                 ``stdout``, the same as with echo. |  | ||||||
|     """ |  | ||||||
|     if not isatty(sys.stdin) or not isatty(sys.stdout): |  | ||||||
|         return |  | ||||||
|     try: |  | ||||||
|         if info: |  | ||||||
|             echo(info, nl=False, err=err) |  | ||||||
|         try: |  | ||||||
|             getchar() |  | ||||||
|         except (KeyboardInterrupt, EOFError): |  | ||||||
|             pass |  | ||||||
|     finally: |  | ||||||
|         if info: |  | ||||||
|             echo(err=err) |  | ||||||
| @ -1,322 +0,0 @@ | |||||||
| import os |  | ||||||
| import sys |  | ||||||
| import shutil |  | ||||||
| import tempfile |  | ||||||
| import contextlib |  | ||||||
| 
 |  | ||||||
| from ._compat import iteritems, PY2 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| # If someone wants to vendor click, we want to ensure the |  | ||||||
| # correct package is discovered.  Ideally we could use a |  | ||||||
| # relative import here but unfortunately Python does not |  | ||||||
| # support that. |  | ||||||
| clickpkg = sys.modules[__name__.rsplit('.', 1)[0]] |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| if PY2: |  | ||||||
|     from cStringIO import StringIO |  | ||||||
| else: |  | ||||||
|     import io |  | ||||||
|     from ._compat import _find_binary_reader |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class EchoingStdin(object): |  | ||||||
| 
 |  | ||||||
|     def __init__(self, input, output): |  | ||||||
|         self._input = input |  | ||||||
|         self._output = output |  | ||||||
| 
 |  | ||||||
|     def __getattr__(self, x): |  | ||||||
|         return getattr(self._input, x) |  | ||||||
| 
 |  | ||||||
|     def _echo(self, rv): |  | ||||||
|         self._output.write(rv) |  | ||||||
|         return rv |  | ||||||
| 
 |  | ||||||
|     def read(self, n=-1): |  | ||||||
|         return self._echo(self._input.read(n)) |  | ||||||
| 
 |  | ||||||
|     def readline(self, n=-1): |  | ||||||
|         return self._echo(self._input.readline(n)) |  | ||||||
| 
 |  | ||||||
|     def readlines(self): |  | ||||||
|         return [self._echo(x) for x in self._input.readlines()] |  | ||||||
| 
 |  | ||||||
|     def __iter__(self): |  | ||||||
|         return iter(self._echo(x) for x in self._input) |  | ||||||
| 
 |  | ||||||
|     def __repr__(self): |  | ||||||
|         return repr(self._input) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def make_input_stream(input, charset): |  | ||||||
|     # Is already an input stream. |  | ||||||
|     if hasattr(input, 'read'): |  | ||||||
|         if PY2: |  | ||||||
|             return input |  | ||||||
|         rv = _find_binary_reader(input) |  | ||||||
|         if rv is not None: |  | ||||||
|             return rv |  | ||||||
|         raise TypeError('Could not find binary reader for input stream.') |  | ||||||
| 
 |  | ||||||
|     if input is None: |  | ||||||
|         input = b'' |  | ||||||
|     elif not isinstance(input, bytes): |  | ||||||
|         input = input.encode(charset) |  | ||||||
|     if PY2: |  | ||||||
|         return StringIO(input) |  | ||||||
|     return io.BytesIO(input) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class Result(object): |  | ||||||
|     """Holds the captured result of an invoked CLI script.""" |  | ||||||
| 
 |  | ||||||
|     def __init__(self, runner, output_bytes, exit_code, exception, |  | ||||||
|                  exc_info=None): |  | ||||||
|         #: The runner that created the result |  | ||||||
|         self.runner = runner |  | ||||||
|         #: The output as bytes. |  | ||||||
|         self.output_bytes = output_bytes |  | ||||||
|         #: The exit code as integer. |  | ||||||
|         self.exit_code = exit_code |  | ||||||
|         #: The exception that happend if one did. |  | ||||||
|         self.exception = exception |  | ||||||
|         #: The traceback |  | ||||||
|         self.exc_info = exc_info |  | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def output(self): |  | ||||||
|         """The output as unicode string.""" |  | ||||||
|         return self.output_bytes.decode(self.runner.charset, 'replace') \ |  | ||||||
|             .replace('\r\n', '\n') |  | ||||||
| 
 |  | ||||||
|     def __repr__(self): |  | ||||||
|         return '<Result %s>' % ( |  | ||||||
|             self.exception and repr(self.exception) or 'okay', |  | ||||||
|         ) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class CliRunner(object): |  | ||||||
|     """The CLI runner provides functionality to invoke a Click command line |  | ||||||
|     script for unittesting purposes in a isolated environment.  This only |  | ||||||
|     works in single-threaded systems without any concurrency as it changes the |  | ||||||
|     global interpreter state. |  | ||||||
| 
 |  | ||||||
|     :param charset: the character set for the input and output data.  This is |  | ||||||
|                     UTF-8 by default and should not be changed currently as |  | ||||||
|                     the reporting to Click only works in Python 2 properly. |  | ||||||
|     :param env: a dictionary with environment variables for overriding. |  | ||||||
|     :param echo_stdin: if this is set to `True`, then reading from stdin writes |  | ||||||
|                        to stdout.  This is useful for showing examples in |  | ||||||
|                        some circumstances.  Note that regular prompts |  | ||||||
|                        will automatically echo the input. |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     def __init__(self, charset=None, env=None, echo_stdin=False): |  | ||||||
|         if charset is None: |  | ||||||
|             charset = 'utf-8' |  | ||||||
|         self.charset = charset |  | ||||||
|         self.env = env or {} |  | ||||||
|         self.echo_stdin = echo_stdin |  | ||||||
| 
 |  | ||||||
|     def get_default_prog_name(self, cli): |  | ||||||
|         """Given a command object it will return the default program name |  | ||||||
|         for it.  The default is the `name` attribute or ``"root"`` if not |  | ||||||
|         set. |  | ||||||
|         """ |  | ||||||
|         return cli.name or 'root' |  | ||||||
| 
 |  | ||||||
|     def make_env(self, overrides=None): |  | ||||||
|         """Returns the environment overrides for invoking a script.""" |  | ||||||
|         rv = dict(self.env) |  | ||||||
|         if overrides: |  | ||||||
|             rv.update(overrides) |  | ||||||
|         return rv |  | ||||||
| 
 |  | ||||||
|     @contextlib.contextmanager |  | ||||||
|     def isolation(self, input=None, env=None, color=False): |  | ||||||
|         """A context manager that sets up the isolation for invoking of a |  | ||||||
|         command line tool.  This sets up stdin with the given input data |  | ||||||
|         and `os.environ` with the overrides from the given dictionary. |  | ||||||
|         This also rebinds some internals in Click to be mocked (like the |  | ||||||
|         prompt functionality). |  | ||||||
| 
 |  | ||||||
|         This is automatically done in the :meth:`invoke` method. |  | ||||||
| 
 |  | ||||||
|         .. versionadded:: 4.0 |  | ||||||
|            The ``color`` parameter was added. |  | ||||||
| 
 |  | ||||||
|         :param input: the input stream to put into sys.stdin. |  | ||||||
|         :param env: the environment overrides as dictionary. |  | ||||||
|         :param color: whether the output should contain color codes. The |  | ||||||
|                       application can still override this explicitly. |  | ||||||
|         """ |  | ||||||
|         input = make_input_stream(input, self.charset) |  | ||||||
| 
 |  | ||||||
|         old_stdin = sys.stdin |  | ||||||
|         old_stdout = sys.stdout |  | ||||||
|         old_stderr = sys.stderr |  | ||||||
|         old_forced_width = clickpkg.formatting.FORCED_WIDTH |  | ||||||
|         clickpkg.formatting.FORCED_WIDTH = 80 |  | ||||||
| 
 |  | ||||||
|         env = self.make_env(env) |  | ||||||
| 
 |  | ||||||
|         if PY2: |  | ||||||
|             sys.stdout = sys.stderr = bytes_output = StringIO() |  | ||||||
|             if self.echo_stdin: |  | ||||||
|                 input = EchoingStdin(input, bytes_output) |  | ||||||
|         else: |  | ||||||
|             bytes_output = io.BytesIO() |  | ||||||
|             if self.echo_stdin: |  | ||||||
|                 input = EchoingStdin(input, bytes_output) |  | ||||||
|             input = io.TextIOWrapper(input, encoding=self.charset) |  | ||||||
|             sys.stdout = sys.stderr = io.TextIOWrapper( |  | ||||||
|                 bytes_output, encoding=self.charset) |  | ||||||
| 
 |  | ||||||
|         sys.stdin = input |  | ||||||
| 
 |  | ||||||
|         def visible_input(prompt=None): |  | ||||||
|             sys.stdout.write(prompt or '') |  | ||||||
|             val = input.readline().rstrip('\r\n') |  | ||||||
|             sys.stdout.write(val + '\n') |  | ||||||
|             sys.stdout.flush() |  | ||||||
|             return val |  | ||||||
| 
 |  | ||||||
|         def hidden_input(prompt=None): |  | ||||||
|             sys.stdout.write((prompt or '') + '\n') |  | ||||||
|             sys.stdout.flush() |  | ||||||
|             return input.readline().rstrip('\r\n') |  | ||||||
| 
 |  | ||||||
|         def _getchar(echo): |  | ||||||
|             char = sys.stdin.read(1) |  | ||||||
|             if echo: |  | ||||||
|                 sys.stdout.write(char) |  | ||||||
|                 sys.stdout.flush() |  | ||||||
|             return char |  | ||||||
| 
 |  | ||||||
|         default_color = color |  | ||||||
|         def should_strip_ansi(stream=None, color=None): |  | ||||||
|             if color is None: |  | ||||||
|                 return not default_color |  | ||||||
|             return not color |  | ||||||
| 
 |  | ||||||
|         old_visible_prompt_func = clickpkg.termui.visible_prompt_func |  | ||||||
|         old_hidden_prompt_func = clickpkg.termui.hidden_prompt_func |  | ||||||
|         old__getchar_func = clickpkg.termui._getchar |  | ||||||
|         old_should_strip_ansi = clickpkg.utils.should_strip_ansi |  | ||||||
|         clickpkg.termui.visible_prompt_func = visible_input |  | ||||||
|         clickpkg.termui.hidden_prompt_func = hidden_input |  | ||||||
|         clickpkg.termui._getchar = _getchar |  | ||||||
|         clickpkg.utils.should_strip_ansi = should_strip_ansi |  | ||||||
| 
 |  | ||||||
|         old_env = {} |  | ||||||
|         try: |  | ||||||
|             for key, value in iteritems(env): |  | ||||||
|                 old_env[key] = os.environ.get(key) |  | ||||||
|                 if value is None: |  | ||||||
|                     try: |  | ||||||
|                         del os.environ[key] |  | ||||||
|                     except Exception: |  | ||||||
|                         pass |  | ||||||
|                 else: |  | ||||||
|                     os.environ[key] = value |  | ||||||
|             yield bytes_output |  | ||||||
|         finally: |  | ||||||
|             for key, value in iteritems(old_env): |  | ||||||
|                 if value is None: |  | ||||||
|                     try: |  | ||||||
|                         del os.environ[key] |  | ||||||
|                     except Exception: |  | ||||||
|                         pass |  | ||||||
|                 else: |  | ||||||
|                     os.environ[key] = value |  | ||||||
|             sys.stdout = old_stdout |  | ||||||
|             sys.stderr = old_stderr |  | ||||||
|             sys.stdin = old_stdin |  | ||||||
|             clickpkg.termui.visible_prompt_func = old_visible_prompt_func |  | ||||||
|             clickpkg.termui.hidden_prompt_func = old_hidden_prompt_func |  | ||||||
|             clickpkg.termui._getchar = old__getchar_func |  | ||||||
|             clickpkg.utils.should_strip_ansi = old_should_strip_ansi |  | ||||||
|             clickpkg.formatting.FORCED_WIDTH = old_forced_width |  | ||||||
| 
 |  | ||||||
|     def invoke(self, cli, args=None, input=None, env=None, |  | ||||||
|                catch_exceptions=True, color=False, **extra): |  | ||||||
|         """Invokes a command in an isolated environment.  The arguments are |  | ||||||
|         forwarded directly to the command line script, the `extra` keyword |  | ||||||
|         arguments are passed to the :meth:`~clickpkg.Command.main` function of |  | ||||||
|         the command. |  | ||||||
| 
 |  | ||||||
|         This returns a :class:`Result` object. |  | ||||||
| 
 |  | ||||||
|         .. versionadded:: 3.0 |  | ||||||
|            The ``catch_exceptions`` parameter was added. |  | ||||||
| 
 |  | ||||||
|         .. versionchanged:: 3.0 |  | ||||||
|            The result object now has an `exc_info` attribute with the |  | ||||||
|            traceback if available. |  | ||||||
| 
 |  | ||||||
|         .. versionadded:: 4.0 |  | ||||||
|            The ``color`` parameter was added. |  | ||||||
| 
 |  | ||||||
|         :param cli: the command to invoke |  | ||||||
|         :param args: the arguments to invoke |  | ||||||
|         :param input: the input data for `sys.stdin`. |  | ||||||
|         :param env: the environment overrides. |  | ||||||
|         :param catch_exceptions: Whether to catch any other exceptions than |  | ||||||
|                                  ``SystemExit``. |  | ||||||
|         :param extra: the keyword arguments to pass to :meth:`main`. |  | ||||||
|         :param color: whether the output should contain color codes. The |  | ||||||
|                       application can still override this explicitly. |  | ||||||
|         """ |  | ||||||
|         exc_info = None |  | ||||||
|         with self.isolation(input=input, env=env, color=color) as out: |  | ||||||
|             exception = None |  | ||||||
|             exit_code = 0 |  | ||||||
| 
 |  | ||||||
|             try: |  | ||||||
|                 cli.main(args=args or (), |  | ||||||
|                          prog_name=self.get_default_prog_name(cli), **extra) |  | ||||||
|             except SystemExit as e: |  | ||||||
|                 if e.code != 0: |  | ||||||
|                     exception = e |  | ||||||
| 
 |  | ||||||
|                 exc_info = sys.exc_info() |  | ||||||
| 
 |  | ||||||
|                 exit_code = e.code |  | ||||||
|                 if not isinstance(exit_code, int): |  | ||||||
|                     sys.stdout.write(str(exit_code)) |  | ||||||
|                     sys.stdout.write('\n') |  | ||||||
|                     exit_code = 1 |  | ||||||
|             except Exception as e: |  | ||||||
|                 if not catch_exceptions: |  | ||||||
|                     raise |  | ||||||
|                 exception = e |  | ||||||
|                 exit_code = -1 |  | ||||||
|                 exc_info = sys.exc_info() |  | ||||||
|             finally: |  | ||||||
|                 sys.stdout.flush() |  | ||||||
|                 output = out.getvalue() |  | ||||||
| 
 |  | ||||||
|         return Result(runner=self, |  | ||||||
|                       output_bytes=output, |  | ||||||
|                       exit_code=exit_code, |  | ||||||
|                       exception=exception, |  | ||||||
|                       exc_info=exc_info) |  | ||||||
| 
 |  | ||||||
|     @contextlib.contextmanager |  | ||||||
|     def isolated_filesystem(self): |  | ||||||
|         """A context manager that creates a temporary folder and changes |  | ||||||
|         the current working directory to it for isolated filesystem tests. |  | ||||||
|         """ |  | ||||||
|         cwd = os.getcwd() |  | ||||||
|         t = tempfile.mkdtemp() |  | ||||||
|         os.chdir(t) |  | ||||||
|         try: |  | ||||||
|             yield t |  | ||||||
|         finally: |  | ||||||
|             os.chdir(cwd) |  | ||||||
|             try: |  | ||||||
|                 shutil.rmtree(t) |  | ||||||
|             except (OSError, IOError): |  | ||||||
|                 pass |  | ||||||
| @ -1,550 +0,0 @@ | |||||||
| import os |  | ||||||
| import stat |  | ||||||
| 
 |  | ||||||
| from ._compat import open_stream, text_type, filename_to_ui, \ |  | ||||||
|     get_filesystem_encoding, get_streerror, _get_argv_encoding, PY2 |  | ||||||
| from .exceptions import BadParameter |  | ||||||
| from .utils import safecall, LazyFile |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class ParamType(object): |  | ||||||
|     """Helper for converting values through types.  The following is |  | ||||||
|     necessary for a valid type: |  | ||||||
| 
 |  | ||||||
|     *   it needs a name |  | ||||||
|     *   it needs to pass through None unchanged |  | ||||||
|     *   it needs to convert from a string |  | ||||||
|     *   it needs to convert its result type through unchanged |  | ||||||
|         (eg: needs to be idempotent) |  | ||||||
|     *   it needs to be able to deal with param and context being `None`. |  | ||||||
|         This can be the case when the object is used with prompt |  | ||||||
|         inputs. |  | ||||||
|     """ |  | ||||||
|     is_composite = False |  | ||||||
| 
 |  | ||||||
|     #: the descriptive name of this type |  | ||||||
|     name = None |  | ||||||
| 
 |  | ||||||
|     #: if a list of this type is expected and the value is pulled from a |  | ||||||
|     #: string environment variable, this is what splits it up.  `None` |  | ||||||
|     #: means any whitespace.  For all parameters the general rule is that |  | ||||||
|     #: whitespace splits them up.  The exception are paths and files which |  | ||||||
|     #: are split by ``os.path.pathsep`` by default (":" on Unix and ";" on |  | ||||||
|     #: Windows). |  | ||||||
|     envvar_list_splitter = None |  | ||||||
| 
 |  | ||||||
|     def __call__(self, value, param=None, ctx=None): |  | ||||||
|         if value is not None: |  | ||||||
|             return self.convert(value, param, ctx) |  | ||||||
| 
 |  | ||||||
|     def get_metavar(self, param): |  | ||||||
|         """Returns the metavar default for this param if it provides one.""" |  | ||||||
| 
 |  | ||||||
|     def get_missing_message(self, param): |  | ||||||
|         """Optionally might return extra information about a missing |  | ||||||
|         parameter. |  | ||||||
| 
 |  | ||||||
|         .. versionadded:: 2.0 |  | ||||||
|         """ |  | ||||||
| 
 |  | ||||||
|     def convert(self, value, param, ctx): |  | ||||||
|         """Converts the value.  This is not invoked for values that are |  | ||||||
|         `None` (the missing value). |  | ||||||
|         """ |  | ||||||
|         return value |  | ||||||
| 
 |  | ||||||
|     def split_envvar_value(self, rv): |  | ||||||
|         """Given a value from an environment variable this splits it up |  | ||||||
|         into small chunks depending on the defined envvar list splitter. |  | ||||||
| 
 |  | ||||||
|         If the splitter is set to `None`, which means that whitespace splits, |  | ||||||
|         then leading and trailing whitespace is ignored.  Otherwise, leading |  | ||||||
|         and trailing splitters usually lead to empty items being included. |  | ||||||
|         """ |  | ||||||
|         return (rv or '').split(self.envvar_list_splitter) |  | ||||||
| 
 |  | ||||||
|     def fail(self, message, param=None, ctx=None): |  | ||||||
|         """Helper method to fail with an invalid value message.""" |  | ||||||
|         raise BadParameter(message, ctx=ctx, param=param) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class CompositeParamType(ParamType): |  | ||||||
|     is_composite = True |  | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def arity(self): |  | ||||||
|         raise NotImplementedError() |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class FuncParamType(ParamType): |  | ||||||
| 
 |  | ||||||
|     def __init__(self, func): |  | ||||||
|         self.name = func.__name__ |  | ||||||
|         self.func = func |  | ||||||
| 
 |  | ||||||
|     def convert(self, value, param, ctx): |  | ||||||
|         try: |  | ||||||
|             return self.func(value) |  | ||||||
|         except ValueError: |  | ||||||
|             try: |  | ||||||
|                 value = text_type(value) |  | ||||||
|             except UnicodeError: |  | ||||||
|                 value = str(value).decode('utf-8', 'replace') |  | ||||||
|             self.fail(value, param, ctx) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class UnprocessedParamType(ParamType): |  | ||||||
|     name = 'text' |  | ||||||
| 
 |  | ||||||
|     def convert(self, value, param, ctx): |  | ||||||
|         return value |  | ||||||
| 
 |  | ||||||
|     def __repr__(self): |  | ||||||
|         return 'UNPROCESSED' |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class StringParamType(ParamType): |  | ||||||
|     name = 'text' |  | ||||||
| 
 |  | ||||||
|     def convert(self, value, param, ctx): |  | ||||||
|         if isinstance(value, bytes): |  | ||||||
|             enc = _get_argv_encoding() |  | ||||||
|             try: |  | ||||||
|                 value = value.decode(enc) |  | ||||||
|             except UnicodeError: |  | ||||||
|                 fs_enc = get_filesystem_encoding() |  | ||||||
|                 if fs_enc != enc: |  | ||||||
|                     try: |  | ||||||
|                         value = value.decode(fs_enc) |  | ||||||
|                     except UnicodeError: |  | ||||||
|                         value = value.decode('utf-8', 'replace') |  | ||||||
|             return value |  | ||||||
|         return value |  | ||||||
| 
 |  | ||||||
|     def __repr__(self): |  | ||||||
|         return 'STRING' |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class Choice(ParamType): |  | ||||||
|     """The choice type allows a value to be checked against a fixed set of |  | ||||||
|     supported values.  All of these values have to be strings. |  | ||||||
| 
 |  | ||||||
|     See :ref:`choice-opts` for an example. |  | ||||||
|     """ |  | ||||||
|     name = 'choice' |  | ||||||
| 
 |  | ||||||
|     def __init__(self, choices): |  | ||||||
|         self.choices = choices |  | ||||||
| 
 |  | ||||||
|     def get_metavar(self, param): |  | ||||||
|         return '[%s]' % '|'.join(self.choices) |  | ||||||
| 
 |  | ||||||
|     def get_missing_message(self, param): |  | ||||||
|         return 'Choose from %s.' % ', '.join(self.choices) |  | ||||||
| 
 |  | ||||||
|     def convert(self, value, param, ctx): |  | ||||||
|         # Exact match |  | ||||||
|         if value in self.choices: |  | ||||||
|             return value |  | ||||||
| 
 |  | ||||||
|         # Match through normalization |  | ||||||
|         if ctx is not None and \ |  | ||||||
|            ctx.token_normalize_func is not None: |  | ||||||
|             value = ctx.token_normalize_func(value) |  | ||||||
|             for choice in self.choices: |  | ||||||
|                 if ctx.token_normalize_func(choice) == value: |  | ||||||
|                     return choice |  | ||||||
| 
 |  | ||||||
|         self.fail('invalid choice: %s. (choose from %s)' % |  | ||||||
|                   (value, ', '.join(self.choices)), param, ctx) |  | ||||||
| 
 |  | ||||||
|     def __repr__(self): |  | ||||||
|         return 'Choice(%r)' % list(self.choices) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class IntParamType(ParamType): |  | ||||||
|     name = 'integer' |  | ||||||
| 
 |  | ||||||
|     def convert(self, value, param, ctx): |  | ||||||
|         try: |  | ||||||
|             return int(value) |  | ||||||
|         except (ValueError, UnicodeError): |  | ||||||
|             self.fail('%s is not a valid integer' % value, param, ctx) |  | ||||||
| 
 |  | ||||||
|     def __repr__(self): |  | ||||||
|         return 'INT' |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class IntRange(IntParamType): |  | ||||||
|     """A parameter that works similar to :data:`click.INT` but restricts |  | ||||||
|     the value to fit into a range.  The default behavior is to fail if the |  | ||||||
|     value falls outside the range, but it can also be silently clamped |  | ||||||
|     between the two edges. |  | ||||||
| 
 |  | ||||||
|     See :ref:`ranges` for an example. |  | ||||||
|     """ |  | ||||||
|     name = 'integer range' |  | ||||||
| 
 |  | ||||||
|     def __init__(self, min=None, max=None, clamp=False): |  | ||||||
|         self.min = min |  | ||||||
|         self.max = max |  | ||||||
|         self.clamp = clamp |  | ||||||
| 
 |  | ||||||
|     def convert(self, value, param, ctx): |  | ||||||
|         rv = IntParamType.convert(self, value, param, ctx) |  | ||||||
|         if self.clamp: |  | ||||||
|             if self.min is not None and rv < self.min: |  | ||||||
|                 return self.min |  | ||||||
|             if self.max is not None and rv > self.max: |  | ||||||
|                 return self.max |  | ||||||
|         if self.min is not None and rv < self.min or \ |  | ||||||
|            self.max is not None and rv > self.max: |  | ||||||
|             if self.min is None: |  | ||||||
|                 self.fail('%s is bigger than the maximum valid value ' |  | ||||||
|                           '%s.' % (rv, self.max), param, ctx) |  | ||||||
|             elif self.max is None: |  | ||||||
|                 self.fail('%s is smaller than the minimum valid value ' |  | ||||||
|                           '%s.' % (rv, self.min), param, ctx) |  | ||||||
|             else: |  | ||||||
|                 self.fail('%s is not in the valid range of %s to %s.' |  | ||||||
|                           % (rv, self.min, self.max), param, ctx) |  | ||||||
|         return rv |  | ||||||
| 
 |  | ||||||
|     def __repr__(self): |  | ||||||
|         return 'IntRange(%r, %r)' % (self.min, self.max) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class BoolParamType(ParamType): |  | ||||||
|     name = 'boolean' |  | ||||||
| 
 |  | ||||||
|     def convert(self, value, param, ctx): |  | ||||||
|         if isinstance(value, bool): |  | ||||||
|             return bool(value) |  | ||||||
|         value = value.lower() |  | ||||||
|         if value in ('true', '1', 'yes', 'y'): |  | ||||||
|             return True |  | ||||||
|         elif value in ('false', '0', 'no', 'n'): |  | ||||||
|             return False |  | ||||||
|         self.fail('%s is not a valid boolean' % value, param, ctx) |  | ||||||
| 
 |  | ||||||
|     def __repr__(self): |  | ||||||
|         return 'BOOL' |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class FloatParamType(ParamType): |  | ||||||
|     name = 'float' |  | ||||||
| 
 |  | ||||||
|     def convert(self, value, param, ctx): |  | ||||||
|         try: |  | ||||||
|             return float(value) |  | ||||||
|         except (UnicodeError, ValueError): |  | ||||||
|             self.fail('%s is not a valid floating point value' % |  | ||||||
|                       value, param, ctx) |  | ||||||
| 
 |  | ||||||
|     def __repr__(self): |  | ||||||
|         return 'FLOAT' |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class UUIDParameterType(ParamType): |  | ||||||
|     name = 'uuid' |  | ||||||
| 
 |  | ||||||
|     def convert(self, value, param, ctx): |  | ||||||
|         import uuid |  | ||||||
|         try: |  | ||||||
|             if PY2 and isinstance(value, text_type): |  | ||||||
|                 value = value.encode('ascii') |  | ||||||
|             return uuid.UUID(value) |  | ||||||
|         except (UnicodeError, ValueError): |  | ||||||
|             self.fail('%s is not a valid UUID value' % value, param, ctx) |  | ||||||
| 
 |  | ||||||
|     def __repr__(self): |  | ||||||
|         return 'UUID' |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class File(ParamType): |  | ||||||
|     """Declares a parameter to be a file for reading or writing.  The file |  | ||||||
|     is automatically closed once the context tears down (after the command |  | ||||||
|     finished working). |  | ||||||
| 
 |  | ||||||
|     Files can be opened for reading or writing.  The special value ``-`` |  | ||||||
|     indicates stdin or stdout depending on the mode. |  | ||||||
| 
 |  | ||||||
|     By default, the file is opened for reading text data, but it can also be |  | ||||||
|     opened in binary mode or for writing.  The encoding parameter can be used |  | ||||||
|     to force a specific encoding. |  | ||||||
| 
 |  | ||||||
|     The `lazy` flag controls if the file should be opened immediately or |  | ||||||
|     upon first IO.  The default is to be non lazy for standard input and |  | ||||||
|     output streams as well as files opened for reading, lazy otherwise. |  | ||||||
| 
 |  | ||||||
|     Starting with Click 2.0, files can also be opened atomically in which |  | ||||||
|     case all writes go into a separate file in the same folder and upon |  | ||||||
|     completion the file will be moved over to the original location.  This |  | ||||||
|     is useful if a file regularly read by other users is modified. |  | ||||||
| 
 |  | ||||||
|     See :ref:`file-args` for more information. |  | ||||||
|     """ |  | ||||||
|     name = 'filename' |  | ||||||
|     envvar_list_splitter = os.path.pathsep |  | ||||||
| 
 |  | ||||||
|     def __init__(self, mode='r', encoding=None, errors='strict', lazy=None, |  | ||||||
|                  atomic=False): |  | ||||||
|         self.mode = mode |  | ||||||
|         self.encoding = encoding |  | ||||||
|         self.errors = errors |  | ||||||
|         self.lazy = lazy |  | ||||||
|         self.atomic = atomic |  | ||||||
| 
 |  | ||||||
|     def resolve_lazy_flag(self, value): |  | ||||||
|         if self.lazy is not None: |  | ||||||
|             return self.lazy |  | ||||||
|         if value == '-': |  | ||||||
|             return False |  | ||||||
|         elif 'w' in self.mode: |  | ||||||
|             return True |  | ||||||
|         return False |  | ||||||
| 
 |  | ||||||
|     def convert(self, value, param, ctx): |  | ||||||
|         try: |  | ||||||
|             if hasattr(value, 'read') or hasattr(value, 'write'): |  | ||||||
|                 return value |  | ||||||
| 
 |  | ||||||
|             lazy = self.resolve_lazy_flag(value) |  | ||||||
| 
 |  | ||||||
|             if lazy: |  | ||||||
|                 f = LazyFile(value, self.mode, self.encoding, self.errors, |  | ||||||
|                              atomic=self.atomic) |  | ||||||
|                 if ctx is not None: |  | ||||||
|                     ctx.call_on_close(f.close_intelligently) |  | ||||||
|                 return f |  | ||||||
| 
 |  | ||||||
|             f, should_close = open_stream(value, self.mode, |  | ||||||
|                                           self.encoding, self.errors, |  | ||||||
|                                           atomic=self.atomic) |  | ||||||
|             # If a context is provided, we automatically close the file |  | ||||||
|             # at the end of the context execution (or flush out).  If a |  | ||||||
|             # context does not exist, it's the caller's responsibility to |  | ||||||
|             # properly close the file.  This for instance happens when the |  | ||||||
|             # type is used with prompts. |  | ||||||
|             if ctx is not None: |  | ||||||
|                 if should_close: |  | ||||||
|                     ctx.call_on_close(safecall(f.close)) |  | ||||||
|                 else: |  | ||||||
|                     ctx.call_on_close(safecall(f.flush)) |  | ||||||
|             return f |  | ||||||
|         except (IOError, OSError) as e: |  | ||||||
|             self.fail('Could not open file: %s: %s' % ( |  | ||||||
|                 filename_to_ui(value), |  | ||||||
|                 get_streerror(e), |  | ||||||
|             ), param, ctx) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class Path(ParamType): |  | ||||||
|     """The path type is similar to the :class:`File` type but it performs |  | ||||||
|     different checks.  First of all, instead of returning an open file |  | ||||||
|     handle it returns just the filename.  Secondly, it can perform various |  | ||||||
|     basic checks about what the file or directory should be. |  | ||||||
| 
 |  | ||||||
|     .. versionchanged:: 6.0 |  | ||||||
|        `allow_dash` was added. |  | ||||||
| 
 |  | ||||||
|     :param exists: if set to true, the file or directory needs to exist for |  | ||||||
|                    this value to be valid.  If this is not required and a |  | ||||||
|                    file does indeed not exist, then all further checks are |  | ||||||
|                    silently skipped. |  | ||||||
|     :param file_okay: controls if a file is a possible value. |  | ||||||
|     :param dir_okay: controls if a directory is a possible value. |  | ||||||
|     :param writable: if true, a writable check is performed. |  | ||||||
|     :param readable: if true, a readable check is performed. |  | ||||||
|     :param resolve_path: if this is true, then the path is fully resolved |  | ||||||
|                          before the value is passed onwards.  This means |  | ||||||
|                          that it's absolute and symlinks are resolved. |  | ||||||
|     :param allow_dash: If this is set to `True`, a single dash to indicate |  | ||||||
|                        standard streams is permitted. |  | ||||||
|     :param type: optionally a string type that should be used to |  | ||||||
|                  represent the path.  The default is `None` which |  | ||||||
|                  means the return value will be either bytes or |  | ||||||
|                  unicode depending on what makes most sense given the |  | ||||||
|                  input data Click deals with. |  | ||||||
|     """ |  | ||||||
|     envvar_list_splitter = os.path.pathsep |  | ||||||
| 
 |  | ||||||
|     def __init__(self, exists=False, file_okay=True, dir_okay=True, |  | ||||||
|                  writable=False, readable=True, resolve_path=False, |  | ||||||
|                  allow_dash=False, path_type=None): |  | ||||||
|         self.exists = exists |  | ||||||
|         self.file_okay = file_okay |  | ||||||
|         self.dir_okay = dir_okay |  | ||||||
|         self.writable = writable |  | ||||||
|         self.readable = readable |  | ||||||
|         self.resolve_path = resolve_path |  | ||||||
|         self.allow_dash = allow_dash |  | ||||||
|         self.type = path_type |  | ||||||
| 
 |  | ||||||
|         if self.file_okay and not self.dir_okay: |  | ||||||
|             self.name = 'file' |  | ||||||
|             self.path_type = 'File' |  | ||||||
|         if self.dir_okay and not self.file_okay: |  | ||||||
|             self.name = 'directory' |  | ||||||
|             self.path_type = 'Directory' |  | ||||||
|         else: |  | ||||||
|             self.name = 'path' |  | ||||||
|             self.path_type = 'Path' |  | ||||||
| 
 |  | ||||||
|     def coerce_path_result(self, rv): |  | ||||||
|         if self.type is not None and not isinstance(rv, self.type): |  | ||||||
|             if self.type is text_type: |  | ||||||
|                 rv = rv.decode(get_filesystem_encoding()) |  | ||||||
|             else: |  | ||||||
|                 rv = rv.encode(get_filesystem_encoding()) |  | ||||||
|         return rv |  | ||||||
| 
 |  | ||||||
|     def convert(self, value, param, ctx): |  | ||||||
|         rv = value |  | ||||||
| 
 |  | ||||||
|         is_dash = self.file_okay and self.allow_dash and rv in (b'-', '-') |  | ||||||
| 
 |  | ||||||
|         if not is_dash: |  | ||||||
|             if self.resolve_path: |  | ||||||
|                 rv = os.path.realpath(rv) |  | ||||||
| 
 |  | ||||||
|             try: |  | ||||||
|                 st = os.stat(rv) |  | ||||||
|             except OSError: |  | ||||||
|                 if not self.exists: |  | ||||||
|                     return self.coerce_path_result(rv) |  | ||||||
|                 self.fail('%s "%s" does not exist.' % ( |  | ||||||
|                     self.path_type, |  | ||||||
|                     filename_to_ui(value) |  | ||||||
|                 ), param, ctx) |  | ||||||
| 
 |  | ||||||
|             if not self.file_okay and stat.S_ISREG(st.st_mode): |  | ||||||
|                 self.fail('%s "%s" is a file.' % ( |  | ||||||
|                     self.path_type, |  | ||||||
|                     filename_to_ui(value) |  | ||||||
|                 ), param, ctx) |  | ||||||
|             if not self.dir_okay and stat.S_ISDIR(st.st_mode): |  | ||||||
|                 self.fail('%s "%s" is a directory.' % ( |  | ||||||
|                     self.path_type, |  | ||||||
|                     filename_to_ui(value) |  | ||||||
|                 ), param, ctx) |  | ||||||
|             if self.writable and not os.access(value, os.W_OK): |  | ||||||
|                 self.fail('%s "%s" is not writable.' % ( |  | ||||||
|                     self.path_type, |  | ||||||
|                     filename_to_ui(value) |  | ||||||
|                 ), param, ctx) |  | ||||||
|             if self.readable and not os.access(value, os.R_OK): |  | ||||||
|                 self.fail('%s "%s" is not readable.' % ( |  | ||||||
|                     self.path_type, |  | ||||||
|                     filename_to_ui(value) |  | ||||||
|                 ), param, ctx) |  | ||||||
| 
 |  | ||||||
|         return self.coerce_path_result(rv) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class Tuple(CompositeParamType): |  | ||||||
|     """The default behavior of Click is to apply a type on a value directly. |  | ||||||
|     This works well in most cases, except for when `nargs` is set to a fixed |  | ||||||
|     count and different types should be used for different items.  In this |  | ||||||
|     case the :class:`Tuple` type can be used.  This type can only be used |  | ||||||
|     if `nargs` is set to a fixed number. |  | ||||||
| 
 |  | ||||||
|     For more information see :ref:`tuple-type`. |  | ||||||
| 
 |  | ||||||
|     This can be selected by using a Python tuple literal as a type. |  | ||||||
| 
 |  | ||||||
|     :param types: a list of types that should be used for the tuple items. |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     def __init__(self, types): |  | ||||||
|         self.types = [convert_type(ty) for ty in types] |  | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def name(self): |  | ||||||
|         return "<" + " ".join(ty.name for ty in self.types) + ">" |  | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def arity(self): |  | ||||||
|         return len(self.types) |  | ||||||
| 
 |  | ||||||
|     def convert(self, value, param, ctx): |  | ||||||
|         if len(value) != len(self.types): |  | ||||||
|             raise TypeError('It would appear that nargs is set to conflict ' |  | ||||||
|                             'with the composite type arity.') |  | ||||||
|         return tuple(ty(x, param, ctx) for ty, x in zip(self.types, value)) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def convert_type(ty, default=None): |  | ||||||
|     """Converts a callable or python ty into the most appropriate param |  | ||||||
|     ty. |  | ||||||
|     """ |  | ||||||
|     guessed_type = False |  | ||||||
|     if ty is None and default is not None: |  | ||||||
|         if isinstance(default, tuple): |  | ||||||
|             ty = tuple(map(type, default)) |  | ||||||
|         else: |  | ||||||
|             ty = type(default) |  | ||||||
|         guessed_type = True |  | ||||||
| 
 |  | ||||||
|     if isinstance(ty, tuple): |  | ||||||
|         return Tuple(ty) |  | ||||||
|     if isinstance(ty, ParamType): |  | ||||||
|         return ty |  | ||||||
|     if ty is text_type or ty is str or ty is None: |  | ||||||
|         return STRING |  | ||||||
|     if ty is int: |  | ||||||
|         return INT |  | ||||||
|     # Booleans are only okay if not guessed.  This is done because for |  | ||||||
|     # flags the default value is actually a bit of a lie in that it |  | ||||||
|     # indicates which of the flags is the one we want.  See get_default() |  | ||||||
|     # for more information. |  | ||||||
|     if ty is bool and not guessed_type: |  | ||||||
|         return BOOL |  | ||||||
|     if ty is float: |  | ||||||
|         return FLOAT |  | ||||||
|     if guessed_type: |  | ||||||
|         return STRING |  | ||||||
| 
 |  | ||||||
|     # Catch a common mistake |  | ||||||
|     if __debug__: |  | ||||||
|         try: |  | ||||||
|             if issubclass(ty, ParamType): |  | ||||||
|                 raise AssertionError('Attempted to use an uninstantiated ' |  | ||||||
|                                      'parameter type (%s).' % ty) |  | ||||||
|         except TypeError: |  | ||||||
|             pass |  | ||||||
|     return FuncParamType(ty) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| #: A dummy parameter type that just does nothing.  From a user's |  | ||||||
| #: perspective this appears to just be the same as `STRING` but internally |  | ||||||
| #: no string conversion takes place.  This is necessary to achieve the |  | ||||||
| #: same bytes/unicode behavior on Python 2/3 in situations where you want |  | ||||||
| #: to not convert argument types.  This is usually useful when working |  | ||||||
| #: with file paths as they can appear in bytes and unicode. |  | ||||||
| #: |  | ||||||
| #: For path related uses the :class:`Path` type is a better choice but |  | ||||||
| #: there are situations where an unprocessed type is useful which is why |  | ||||||
| #: it is is provided. |  | ||||||
| #: |  | ||||||
| #: .. versionadded:: 4.0 |  | ||||||
| UNPROCESSED = UnprocessedParamType() |  | ||||||
| 
 |  | ||||||
| #: A unicode string parameter type which is the implicit default.  This |  | ||||||
| #: can also be selected by using ``str`` as type. |  | ||||||
| STRING = StringParamType() |  | ||||||
| 
 |  | ||||||
| #: An integer parameter.  This can also be selected by using ``int`` as |  | ||||||
| #: type. |  | ||||||
| INT = IntParamType() |  | ||||||
| 
 |  | ||||||
| #: A floating point value parameter.  This can also be selected by using |  | ||||||
| #: ``float`` as type. |  | ||||||
| FLOAT = FloatParamType() |  | ||||||
| 
 |  | ||||||
| #: A boolean parameter.  This is the default for boolean flags.  This can |  | ||||||
| #: also be selected by using ``bool`` as a type. |  | ||||||
| BOOL = BoolParamType() |  | ||||||
| 
 |  | ||||||
| #: A UUID parameter. |  | ||||||
| UUID = UUIDParameterType() |  | ||||||
| @ -1,415 +0,0 @@ | |||||||
| import os |  | ||||||
| import sys |  | ||||||
| 
 |  | ||||||
| from .globals import resolve_color_default |  | ||||||
| 
 |  | ||||||
| from ._compat import text_type, open_stream, get_filesystem_encoding, \ |  | ||||||
|     get_streerror, string_types, PY2, binary_streams, text_streams, \ |  | ||||||
|     filename_to_ui, auto_wrap_for_ansi, strip_ansi, should_strip_ansi, \ |  | ||||||
|     _default_text_stdout, _default_text_stderr, is_bytes, WIN |  | ||||||
| 
 |  | ||||||
| if not PY2: |  | ||||||
|     from ._compat import _find_binary_writer |  | ||||||
| elif WIN: |  | ||||||
|     from ._winconsole import _get_windows_argv, \ |  | ||||||
|          _hash_py_argv, _initial_argv_hash |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| echo_native_types = string_types + (bytes, bytearray) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def _posixify(name): |  | ||||||
|     return '-'.join(name.split()).lower() |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def safecall(func): |  | ||||||
|     """Wraps a function so that it swallows exceptions.""" |  | ||||||
|     def wrapper(*args, **kwargs): |  | ||||||
|         try: |  | ||||||
|             return func(*args, **kwargs) |  | ||||||
|         except Exception: |  | ||||||
|             pass |  | ||||||
|     return wrapper |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def make_str(value): |  | ||||||
|     """Converts a value into a valid string.""" |  | ||||||
|     if isinstance(value, bytes): |  | ||||||
|         try: |  | ||||||
|             return value.decode(get_filesystem_encoding()) |  | ||||||
|         except UnicodeError: |  | ||||||
|             return value.decode('utf-8', 'replace') |  | ||||||
|     return text_type(value) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def make_default_short_help(help, max_length=45): |  | ||||||
|     words = help.split() |  | ||||||
|     total_length = 0 |  | ||||||
|     result = [] |  | ||||||
|     done = False |  | ||||||
| 
 |  | ||||||
|     for word in words: |  | ||||||
|         if word[-1:] == '.': |  | ||||||
|             done = True |  | ||||||
|         new_length = result and 1 + len(word) or len(word) |  | ||||||
|         if total_length + new_length > max_length: |  | ||||||
|             result.append('...') |  | ||||||
|             done = True |  | ||||||
|         else: |  | ||||||
|             if result: |  | ||||||
|                 result.append(' ') |  | ||||||
|             result.append(word) |  | ||||||
|         if done: |  | ||||||
|             break |  | ||||||
|         total_length += new_length |  | ||||||
| 
 |  | ||||||
|     return ''.join(result) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class LazyFile(object): |  | ||||||
|     """A lazy file works like a regular file but it does not fully open |  | ||||||
|     the file but it does perform some basic checks early to see if the |  | ||||||
|     filename parameter does make sense.  This is useful for safely opening |  | ||||||
|     files for writing. |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     def __init__(self, filename, mode='r', encoding=None, errors='strict', |  | ||||||
|                  atomic=False): |  | ||||||
|         self.name = filename |  | ||||||
|         self.mode = mode |  | ||||||
|         self.encoding = encoding |  | ||||||
|         self.errors = errors |  | ||||||
|         self.atomic = atomic |  | ||||||
| 
 |  | ||||||
|         if filename == '-': |  | ||||||
|             self._f, self.should_close = open_stream(filename, mode, |  | ||||||
|                                                      encoding, errors) |  | ||||||
|         else: |  | ||||||
|             if 'r' in mode: |  | ||||||
|                 # Open and close the file in case we're opening it for |  | ||||||
|                 # reading so that we can catch at least some errors in |  | ||||||
|                 # some cases early. |  | ||||||
|                 open(filename, mode).close() |  | ||||||
|             self._f = None |  | ||||||
|             self.should_close = True |  | ||||||
| 
 |  | ||||||
|     def __getattr__(self, name): |  | ||||||
|         return getattr(self.open(), name) |  | ||||||
| 
 |  | ||||||
|     def __repr__(self): |  | ||||||
|         if self._f is not None: |  | ||||||
|             return repr(self._f) |  | ||||||
|         return '<unopened file %r %s>' % (self.name, self.mode) |  | ||||||
| 
 |  | ||||||
|     def open(self): |  | ||||||
|         """Opens the file if it's not yet open.  This call might fail with |  | ||||||
|         a :exc:`FileError`.  Not handling this error will produce an error |  | ||||||
|         that Click shows. |  | ||||||
|         """ |  | ||||||
|         if self._f is not None: |  | ||||||
|             return self._f |  | ||||||
|         try: |  | ||||||
|             rv, self.should_close = open_stream(self.name, self.mode, |  | ||||||
|                                                 self.encoding, |  | ||||||
|                                                 self.errors, |  | ||||||
|                                                 atomic=self.atomic) |  | ||||||
|         except (IOError, OSError) as e: |  | ||||||
|             from .exceptions import FileError |  | ||||||
|             raise FileError(self.name, hint=get_streerror(e)) |  | ||||||
|         self._f = rv |  | ||||||
|         return rv |  | ||||||
| 
 |  | ||||||
|     def close(self): |  | ||||||
|         """Closes the underlying file, no matter what.""" |  | ||||||
|         if self._f is not None: |  | ||||||
|             self._f.close() |  | ||||||
| 
 |  | ||||||
|     def close_intelligently(self): |  | ||||||
|         """This function only closes the file if it was opened by the lazy |  | ||||||
|         file wrapper.  For instance this will never close stdin. |  | ||||||
|         """ |  | ||||||
|         if self.should_close: |  | ||||||
|             self.close() |  | ||||||
| 
 |  | ||||||
|     def __enter__(self): |  | ||||||
|         return self |  | ||||||
| 
 |  | ||||||
|     def __exit__(self, exc_type, exc_value, tb): |  | ||||||
|         self.close_intelligently() |  | ||||||
| 
 |  | ||||||
|     def __iter__(self): |  | ||||||
|         self.open() |  | ||||||
|         return iter(self._f) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class KeepOpenFile(object): |  | ||||||
| 
 |  | ||||||
|     def __init__(self, file): |  | ||||||
|         self._file = file |  | ||||||
| 
 |  | ||||||
|     def __getattr__(self, name): |  | ||||||
|         return getattr(self._file, name) |  | ||||||
| 
 |  | ||||||
|     def __enter__(self): |  | ||||||
|         return self |  | ||||||
| 
 |  | ||||||
|     def __exit__(self, exc_type, exc_value, tb): |  | ||||||
|         pass |  | ||||||
| 
 |  | ||||||
|     def __repr__(self): |  | ||||||
|         return repr(self._file) |  | ||||||
| 
 |  | ||||||
|     def __iter__(self): |  | ||||||
|         return iter(self._file) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def echo(message=None, file=None, nl=True, err=False, color=None): |  | ||||||
|     """Prints a message plus a newline to the given file or stdout.  On |  | ||||||
|     first sight, this looks like the print function, but it has improved |  | ||||||
|     support for handling Unicode and binary data that does not fail no |  | ||||||
|     matter how badly configured the system is. |  | ||||||
| 
 |  | ||||||
|     Primarily it means that you can print binary data as well as Unicode |  | ||||||
|     data on both 2.x and 3.x to the given file in the most appropriate way |  | ||||||
|     possible.  This is a very carefree function as in that it will try its |  | ||||||
|     best to not fail.  As of Click 6.0 this includes support for unicode |  | ||||||
|     output on the Windows console. |  | ||||||
| 
 |  | ||||||
|     In addition to that, if `colorama`_ is installed, the echo function will |  | ||||||
|     also support clever handling of ANSI codes.  Essentially it will then |  | ||||||
|     do the following: |  | ||||||
| 
 |  | ||||||
|     -   add transparent handling of ANSI color codes on Windows. |  | ||||||
|     -   hide ANSI codes automatically if the destination file is not a |  | ||||||
|         terminal. |  | ||||||
| 
 |  | ||||||
|     .. _colorama: http://pypi.python.org/pypi/colorama |  | ||||||
| 
 |  | ||||||
|     .. versionchanged:: 6.0 |  | ||||||
|        As of Click 6.0 the echo function will properly support unicode |  | ||||||
|        output on the windows console.  Not that click does not modify |  | ||||||
|        the interpreter in any way which means that `sys.stdout` or the |  | ||||||
|        print statement or function will still not provide unicode support. |  | ||||||
| 
 |  | ||||||
|     .. versionchanged:: 2.0 |  | ||||||
|        Starting with version 2.0 of Click, the echo function will work |  | ||||||
|        with colorama if it's installed. |  | ||||||
| 
 |  | ||||||
|     .. versionadded:: 3.0 |  | ||||||
|        The `err` parameter was added. |  | ||||||
| 
 |  | ||||||
|     .. versionchanged:: 4.0 |  | ||||||
|        Added the `color` flag. |  | ||||||
| 
 |  | ||||||
|     :param message: the message to print |  | ||||||
|     :param file: the file to write to (defaults to ``stdout``) |  | ||||||
|     :param err: if set to true the file defaults to ``stderr`` instead of |  | ||||||
|                 ``stdout``.  This is faster and easier than calling |  | ||||||
|                 :func:`get_text_stderr` yourself. |  | ||||||
|     :param nl: if set to `True` (the default) a newline is printed afterwards. |  | ||||||
|     :param color: controls if the terminal supports ANSI colors or not.  The |  | ||||||
|                   default is autodetection. |  | ||||||
|     """ |  | ||||||
|     if file is None: |  | ||||||
|         if err: |  | ||||||
|             file = _default_text_stderr() |  | ||||||
|         else: |  | ||||||
|             file = _default_text_stdout() |  | ||||||
| 
 |  | ||||||
|     # Convert non bytes/text into the native string type. |  | ||||||
|     if message is not None and not isinstance(message, echo_native_types): |  | ||||||
|         message = text_type(message) |  | ||||||
| 
 |  | ||||||
|     if nl: |  | ||||||
|         message = message or u'' |  | ||||||
|         if isinstance(message, text_type): |  | ||||||
|             message += u'\n' |  | ||||||
|         else: |  | ||||||
|             message += b'\n' |  | ||||||
| 
 |  | ||||||
|     # If there is a message, and we're in Python 3, and the value looks |  | ||||||
|     # like bytes, we manually need to find the binary stream and write the |  | ||||||
|     # message in there.  This is done separately so that most stream |  | ||||||
|     # types will work as you would expect.  Eg: you can write to StringIO |  | ||||||
|     # for other cases. |  | ||||||
|     if message and not PY2 and is_bytes(message): |  | ||||||
|         binary_file = _find_binary_writer(file) |  | ||||||
|         if binary_file is not None: |  | ||||||
|             file.flush() |  | ||||||
|             binary_file.write(message) |  | ||||||
|             binary_file.flush() |  | ||||||
|             return |  | ||||||
| 
 |  | ||||||
|     # ANSI-style support.  If there is no message or we are dealing with |  | ||||||
|     # bytes nothing is happening.  If we are connected to a file we want |  | ||||||
|     # to strip colors.  If we are on windows we either wrap the stream |  | ||||||
|     # to strip the color or we use the colorama support to translate the |  | ||||||
|     # ansi codes to API calls. |  | ||||||
|     if message and not is_bytes(message): |  | ||||||
|         color = resolve_color_default(color) |  | ||||||
|         if should_strip_ansi(file, color): |  | ||||||
|             message = strip_ansi(message) |  | ||||||
|         elif WIN: |  | ||||||
|             if auto_wrap_for_ansi is not None: |  | ||||||
|                 file = auto_wrap_for_ansi(file) |  | ||||||
|             elif not color: |  | ||||||
|                 message = strip_ansi(message) |  | ||||||
| 
 |  | ||||||
|     if message: |  | ||||||
|         file.write(message) |  | ||||||
|     file.flush() |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def get_binary_stream(name): |  | ||||||
|     """Returns a system stream for byte processing.  This essentially |  | ||||||
|     returns the stream from the sys module with the given name but it |  | ||||||
|     solves some compatibility issues between different Python versions. |  | ||||||
|     Primarily this function is necessary for getting binary streams on |  | ||||||
|     Python 3. |  | ||||||
| 
 |  | ||||||
|     :param name: the name of the stream to open.  Valid names are ``'stdin'``, |  | ||||||
|                  ``'stdout'`` and ``'stderr'`` |  | ||||||
|     """ |  | ||||||
|     opener = binary_streams.get(name) |  | ||||||
|     if opener is None: |  | ||||||
|         raise TypeError('Unknown standard stream %r' % name) |  | ||||||
|     return opener() |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def get_text_stream(name, encoding=None, errors='strict'): |  | ||||||
|     """Returns a system stream for text processing.  This usually returns |  | ||||||
|     a wrapped stream around a binary stream returned from |  | ||||||
|     :func:`get_binary_stream` but it also can take shortcuts on Python 3 |  | ||||||
|     for already correctly configured streams. |  | ||||||
| 
 |  | ||||||
|     :param name: the name of the stream to open.  Valid names are ``'stdin'``, |  | ||||||
|                  ``'stdout'`` and ``'stderr'`` |  | ||||||
|     :param encoding: overrides the detected default encoding. |  | ||||||
|     :param errors: overrides the default error mode. |  | ||||||
|     """ |  | ||||||
|     opener = text_streams.get(name) |  | ||||||
|     if opener is None: |  | ||||||
|         raise TypeError('Unknown standard stream %r' % name) |  | ||||||
|     return opener(encoding, errors) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def open_file(filename, mode='r', encoding=None, errors='strict', |  | ||||||
|               lazy=False, atomic=False): |  | ||||||
|     """This is similar to how the :class:`File` works but for manual |  | ||||||
|     usage.  Files are opened non lazy by default.  This can open regular |  | ||||||
|     files as well as stdin/stdout if ``'-'`` is passed. |  | ||||||
| 
 |  | ||||||
|     If stdin/stdout is returned the stream is wrapped so that the context |  | ||||||
|     manager will not close the stream accidentally.  This makes it possible |  | ||||||
|     to always use the function like this without having to worry to |  | ||||||
|     accidentally close a standard stream:: |  | ||||||
| 
 |  | ||||||
|         with open_file(filename) as f: |  | ||||||
|             ... |  | ||||||
| 
 |  | ||||||
|     .. versionadded:: 3.0 |  | ||||||
| 
 |  | ||||||
|     :param filename: the name of the file to open (or ``'-'`` for stdin/stdout). |  | ||||||
|     :param mode: the mode in which to open the file. |  | ||||||
|     :param encoding: the encoding to use. |  | ||||||
|     :param errors: the error handling for this file. |  | ||||||
|     :param lazy: can be flipped to true to open the file lazily. |  | ||||||
|     :param atomic: in atomic mode writes go into a temporary file and it's |  | ||||||
|                    moved on close. |  | ||||||
|     """ |  | ||||||
|     if lazy: |  | ||||||
|         return LazyFile(filename, mode, encoding, errors, atomic=atomic) |  | ||||||
|     f, should_close = open_stream(filename, mode, encoding, errors, |  | ||||||
|                                   atomic=atomic) |  | ||||||
|     if not should_close: |  | ||||||
|         f = KeepOpenFile(f) |  | ||||||
|     return f |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def get_os_args(): |  | ||||||
|     """This returns the argument part of sys.argv in the most appropriate |  | ||||||
|     form for processing.  What this means is that this return value is in |  | ||||||
|     a format that works for Click to process but does not necessarily |  | ||||||
|     correspond well to what's actually standard for the interpreter. |  | ||||||
| 
 |  | ||||||
|     On most environments the return value is ``sys.argv[:1]`` unchanged. |  | ||||||
|     However if you are on Windows and running Python 2 the return value |  | ||||||
|     will actually be a list of unicode strings instead because the |  | ||||||
|     default behavior on that platform otherwise will not be able to |  | ||||||
|     carry all possible values that sys.argv can have. |  | ||||||
| 
 |  | ||||||
|     .. versionadded:: 6.0 |  | ||||||
|     """ |  | ||||||
|     # We can only extract the unicode argv if sys.argv has not been |  | ||||||
|     # changed since the startup of the application. |  | ||||||
|     if PY2 and WIN and _initial_argv_hash == _hash_py_argv(): |  | ||||||
|         return _get_windows_argv() |  | ||||||
|     return sys.argv[1:] |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def format_filename(filename, shorten=False): |  | ||||||
|     """Formats a filename for user display.  The main purpose of this |  | ||||||
|     function is to ensure that the filename can be displayed at all.  This |  | ||||||
|     will decode the filename to unicode if necessary in a way that it will |  | ||||||
|     not fail.  Optionally, it can shorten the filename to not include the |  | ||||||
|     full path to the filename. |  | ||||||
| 
 |  | ||||||
|     :param filename: formats a filename for UI display.  This will also convert |  | ||||||
|                      the filename into unicode without failing. |  | ||||||
|     :param shorten: this optionally shortens the filename to strip of the |  | ||||||
|                     path that leads up to it. |  | ||||||
|     """ |  | ||||||
|     if shorten: |  | ||||||
|         filename = os.path.basename(filename) |  | ||||||
|     return filename_to_ui(filename) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def get_app_dir(app_name, roaming=True, force_posix=False): |  | ||||||
|     r"""Returns the config folder for the application.  The default behavior |  | ||||||
|     is to return whatever is most appropriate for the operating system. |  | ||||||
| 
 |  | ||||||
|     To give you an idea, for an app called ``"Foo Bar"``, something like |  | ||||||
|     the following folders could be returned: |  | ||||||
| 
 |  | ||||||
|     Mac OS X: |  | ||||||
|       ``~/Library/Application Support/Foo Bar`` |  | ||||||
|     Mac OS X (POSIX): |  | ||||||
|       ``~/.foo-bar`` |  | ||||||
|     Unix: |  | ||||||
|       ``~/.config/foo-bar`` |  | ||||||
|     Unix (POSIX): |  | ||||||
|       ``~/.foo-bar`` |  | ||||||
|     Win XP (roaming): |  | ||||||
|       ``C:\Documents and Settings\<user>\Local Settings\Application Data\Foo Bar`` |  | ||||||
|     Win XP (not roaming): |  | ||||||
|       ``C:\Documents and Settings\<user>\Application Data\Foo Bar`` |  | ||||||
|     Win 7 (roaming): |  | ||||||
|       ``C:\Users\<user>\AppData\Roaming\Foo Bar`` |  | ||||||
|     Win 7 (not roaming): |  | ||||||
|       ``C:\Users\<user>\AppData\Local\Foo Bar`` |  | ||||||
| 
 |  | ||||||
|     .. versionadded:: 2.0 |  | ||||||
| 
 |  | ||||||
|     :param app_name: the application name.  This should be properly capitalized |  | ||||||
|                      and can contain whitespace. |  | ||||||
|     :param roaming: controls if the folder should be roaming or not on Windows. |  | ||||||
|                     Has no affect otherwise. |  | ||||||
|     :param force_posix: if this is set to `True` then on any POSIX system the |  | ||||||
|                         folder will be stored in the home folder with a leading |  | ||||||
|                         dot instead of the XDG config home or darwin's |  | ||||||
|                         application support folder. |  | ||||||
|     """ |  | ||||||
|     if WIN: |  | ||||||
|         key = roaming and 'APPDATA' or 'LOCALAPPDATA' |  | ||||||
|         folder = os.environ.get(key) |  | ||||||
|         if folder is None: |  | ||||||
|             folder = os.path.expanduser('~') |  | ||||||
|         return os.path.join(folder, app_name) |  | ||||||
|     if force_posix: |  | ||||||
|         return os.path.join(os.path.expanduser('~/.' + _posixify(app_name))) |  | ||||||
|     if sys.platform == 'darwin': |  | ||||||
|         return os.path.join(os.path.expanduser( |  | ||||||
|             '~/Library/Application Support'), app_name) |  | ||||||
|     return os.path.join( |  | ||||||
|         os.environ.get('XDG_CONFIG_HOME', os.path.expanduser('~/.config')), |  | ||||||
|         _posixify(app_name)) |  | ||||||
| @ -1,49 +0,0 @@ | |||||||
| # -*- coding: utf-8 -*- |  | ||||||
| """ |  | ||||||
|     flask |  | ||||||
|     ~~~~~ |  | ||||||
| 
 |  | ||||||
|     A microframework based on Werkzeug.  It's extensively documented |  | ||||||
|     and follows best practice patterns. |  | ||||||
| 
 |  | ||||||
|     :copyright: © 2010 by the Pallets team. |  | ||||||
|     :license: BSD, see LICENSE for more details. |  | ||||||
| """ |  | ||||||
| 
 |  | ||||||
| __version__ = '1.0.2' |  | ||||||
| 
 |  | ||||||
| # 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 .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, before_render_template |  | ||||||
| 
 |  | ||||||
| # 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 |  | ||||||
| @ -1,14 +0,0 @@ | |||||||
| # -*- coding: utf-8 -*- |  | ||||||
| """ |  | ||||||
|     flask.__main__ |  | ||||||
|     ~~~~~~~~~~~~~~ |  | ||||||
| 
 |  | ||||||
|     Alias for flask.run for the command line. |  | ||||||
| 
 |  | ||||||
|     :copyright: © 2010 by the Pallets team. |  | ||||||
|     :license: BSD, see LICENSE for more details. |  | ||||||
| """ |  | ||||||
| 
 |  | ||||||
| if __name__ == '__main__': |  | ||||||
|     from .cli import main |  | ||||||
|     main(as_module=True) |  | ||||||
| @ -1,99 +0,0 @@ | |||||||
| # -*- 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: © 2010 by the Pallets team. |  | ||||||
|     :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 inspect import getfullargspec as getargspec |  | ||||||
|     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 inspect import getargspec |  | ||||||
|     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): |  | ||||||
|     """Create a base class with a metaclass.""" |  | ||||||
|     # 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. |  | ||||||
|     class metaclass(type): |  | ||||||
|         def __new__(cls, name, this_bases, d): |  | ||||||
|             return meta(name, bases, d) |  | ||||||
|     return type.__new__(metaclass, 'temporary_class', (), {}) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| # Certain versions of pypy have a bug where clearing the exception stack |  | ||||||
| # breaks the __exit__ function in a very peculiar way.  The second level of |  | ||||||
| # exception blocks is necessary because pypy seems to forget to check if an |  | ||||||
| # exception happened until the next bytecode instruction? |  | ||||||
| # |  | ||||||
| # Relevant PyPy bugfix commit: |  | ||||||
| # https://bitbucket.org/pypy/pypy/commits/77ecf91c635a287e88e60d8ddb0f4e9df4003301 |  | ||||||
| # According to ronan on #pypy IRC, it is released in PyPy2 2.3 and later |  | ||||||
| # versions. |  | ||||||
| # |  | ||||||
| # Ubuntu 14.04 has PyPy 2.2.1, which does exhibit this bug. |  | ||||||
| BROKEN_PYPY_CTXMGR_EXIT = False |  | ||||||
| if hasattr(sys, 'pypy_version_info'): |  | ||||||
|     class _Mgr(object): |  | ||||||
|         def __enter__(self): |  | ||||||
|             return self |  | ||||||
|         def __exit__(self, *args): |  | ||||||
|             if hasattr(sys, 'exc_clear'): |  | ||||||
|                 # Python 3 (PyPy3) doesn't have exc_clear |  | ||||||
|                 sys.exc_clear() |  | ||||||
|     try: |  | ||||||
|         try: |  | ||||||
|             with _Mgr(): |  | ||||||
|                 raise AssertionError() |  | ||||||
|         except: |  | ||||||
|             raise |  | ||||||
|     except TypeError: |  | ||||||
|         BROKEN_PYPY_CTXMGR_EXIT = True |  | ||||||
|     except AssertionError: |  | ||||||
|         pass |  | ||||||
									
										
											File diff suppressed because it is too large
											Load Diff
										
									
								
							
						| @ -1,448 +0,0 @@ | |||||||
| # -*- coding: utf-8 -*- |  | ||||||
| """ |  | ||||||
|     flask.blueprints |  | ||||||
|     ~~~~~~~~~~~~~~~~ |  | ||||||
| 
 |  | ||||||
|     Blueprints are the recommended way to implement larger or more |  | ||||||
|     pluggable applications in Flask 0.7 and later. |  | ||||||
| 
 |  | ||||||
|     :copyright: © 2010 by the Pallets team. |  | ||||||
|     :license: BSD, see LICENSE for more details. |  | ||||||
| """ |  | ||||||
| from functools import update_wrapper |  | ||||||
| from werkzeug.urls import url_join |  | ||||||
| 
 |  | ||||||
| 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 is not None: |  | ||||||
|             if rule: |  | ||||||
|                 rule = '/'.join(( |  | ||||||
|                     self.url_prefix.rstrip('/'), rule.lstrip('/'))) |  | ||||||
|             else: |  | ||||||
|                 rule = self.url_prefix |  | ||||||
|         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.blueprints.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 |  | ||||||
| 
 |  | ||||||
|     #: Blueprint local JSON decoder class to use. |  | ||||||
|     #: Set to ``None`` to use the app's :class:`~flask.app.Flask.json_encoder`. |  | ||||||
|     json_encoder = None |  | ||||||
|     #: Blueprint local JSON decoder class to use. |  | ||||||
|     #: Set to ``None`` to use the app's :class:`~flask.app.Flask.json_decoder`. |  | ||||||
|     json_decoder = None |  | ||||||
| 
 |  | ||||||
|     # TODO remove the next three attrs when Sphinx :inherited-members: works |  | ||||||
|     # https://github.com/sphinx-doc/sphinx/issues/741 |  | ||||||
| 
 |  | ||||||
|     #: The name of the package or module that this app belongs to. Do not |  | ||||||
|     #: change this once it is set by the constructor. |  | ||||||
|     import_name = None |  | ||||||
| 
 |  | ||||||
|     #: Location of the template files to be added to the template lookup. |  | ||||||
|     #: ``None`` if templates should not be added. |  | ||||||
|     template_folder = None |  | ||||||
| 
 |  | ||||||
|     #: Absolute path to the package on the filesystem. Used to look up |  | ||||||
|     #: resources contained in the package. |  | ||||||
|     root_path = None |  | ||||||
| 
 |  | ||||||
|     def __init__(self, name, import_name, static_folder=None, |  | ||||||
|                  static_url_path=None, template_folder=None, |  | ||||||
|                  url_prefix=None, subdomain=None, url_defaults=None, |  | ||||||
|                  root_path=None): |  | ||||||
|         _PackageBoundObject.__init__(self, import_name, template_folder, |  | ||||||
|                                      root_path=root_path) |  | ||||||
|         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 = [] |  | ||||||
|         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 all views |  | ||||||
|         and callbacks registered on the blueprint with the application. Creates |  | ||||||
|         a :class:`.BlueprintSetupState` and calls each :meth:`record` callback |  | ||||||
|         with it. |  | ||||||
| 
 |  | ||||||
|         :param app: The application this blueprint is being registered with. |  | ||||||
|         :param options: Keyword arguments forwarded from |  | ||||||
|             :meth:`~Flask.register_blueprint`. |  | ||||||
|         :param first_registration: Whether this is the first time this |  | ||||||
|             blueprint has been registered on the application. |  | ||||||
|         """ |  | ||||||
|         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 + '/<path:filename>', |  | ||||||
|                 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 endpoints should not contain dots" |  | ||||||
|         if view_func and hasattr(view_func, '__name__'): |  | ||||||
|             assert '.' not in view_func.__name__, "Blueprint view function name should not contain dots" |  | ||||||
|         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 |  | ||||||
| 
 |  | ||||||
|     def register_error_handler(self, code_or_exception, f): |  | ||||||
|         """Non-decorator version of the :meth:`errorhandler` error attach |  | ||||||
|         function, akin to the :meth:`~flask.Flask.register_error_handler` |  | ||||||
|         application-wide function of the :class:`~flask.Flask` object but |  | ||||||
|         for error handlers limited to this blueprint. |  | ||||||
| 
 |  | ||||||
|         .. versionadded:: 0.11 |  | ||||||
|         """ |  | ||||||
|         self.record_once(lambda s: s.app._register_error_handler( |  | ||||||
|             self.name, code_or_exception, f)) |  | ||||||
| @ -1,898 +0,0 @@ | |||||||
| # -*- coding: utf-8 -*- |  | ||||||
| """ |  | ||||||
|     flask.cli |  | ||||||
|     ~~~~~~~~~ |  | ||||||
| 
 |  | ||||||
|     A simple command line application to run flask apps. |  | ||||||
| 
 |  | ||||||
|     :copyright: © 2010 by the Pallets team. |  | ||||||
|     :license: BSD, see LICENSE for more details. |  | ||||||
| """ |  | ||||||
| 
 |  | ||||||
| from __future__ import print_function |  | ||||||
| 
 |  | ||||||
| import ast |  | ||||||
| import inspect |  | ||||||
| import os |  | ||||||
| import re |  | ||||||
| import ssl |  | ||||||
| import sys |  | ||||||
| import traceback |  | ||||||
| from functools import update_wrapper |  | ||||||
| from operator import attrgetter |  | ||||||
| from threading import Lock, Thread |  | ||||||
| 
 |  | ||||||
| import click |  | ||||||
| from werkzeug.utils import import_string |  | ||||||
| 
 |  | ||||||
| from . import __version__ |  | ||||||
| from ._compat import getargspec, iteritems, reraise, text_type |  | ||||||
| from .globals import current_app |  | ||||||
| from .helpers import get_debug_flag, get_env, get_load_dotenv |  | ||||||
| 
 |  | ||||||
| try: |  | ||||||
|     import dotenv |  | ||||||
| except ImportError: |  | ||||||
|     dotenv = None |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class NoAppException(click.UsageError): |  | ||||||
|     """Raised if an application cannot be found or loaded.""" |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def find_best_app(script_info, module): |  | ||||||
|     """Given a module instance this tries to find the best possible |  | ||||||
|     application in the module or raises an exception. |  | ||||||
|     """ |  | ||||||
|     from . import Flask |  | ||||||
| 
 |  | ||||||
|     # Search for the most common names first. |  | ||||||
|     for attr_name in ('app', 'application'): |  | ||||||
|         app = getattr(module, attr_name, None) |  | ||||||
| 
 |  | ||||||
|         if isinstance(app, Flask): |  | ||||||
|             return app |  | ||||||
| 
 |  | ||||||
|     # Otherwise find the only object that is a Flask instance. |  | ||||||
|     matches = [ |  | ||||||
|         v for k, v in iteritems(module.__dict__) if isinstance(v, Flask) |  | ||||||
|     ] |  | ||||||
| 
 |  | ||||||
|     if len(matches) == 1: |  | ||||||
|         return matches[0] |  | ||||||
|     elif len(matches) > 1: |  | ||||||
|         raise NoAppException( |  | ||||||
|             'Detected multiple Flask applications in module "{module}". Use ' |  | ||||||
|             '"FLASK_APP={module}:name" to specify the correct ' |  | ||||||
|             'one.'.format(module=module.__name__) |  | ||||||
|         ) |  | ||||||
| 
 |  | ||||||
|     # Search for app factory functions. |  | ||||||
|     for attr_name in ('create_app', 'make_app'): |  | ||||||
|         app_factory = getattr(module, attr_name, None) |  | ||||||
| 
 |  | ||||||
|         if inspect.isfunction(app_factory): |  | ||||||
|             try: |  | ||||||
|                 app = call_factory(script_info, app_factory) |  | ||||||
| 
 |  | ||||||
|                 if isinstance(app, Flask): |  | ||||||
|                     return app |  | ||||||
|             except TypeError: |  | ||||||
|                 if not _called_with_wrong_args(app_factory): |  | ||||||
|                     raise |  | ||||||
|                 raise NoAppException( |  | ||||||
|                     'Detected factory "{factory}" in module "{module}", but ' |  | ||||||
|                     'could not call it without arguments. Use ' |  | ||||||
|                     '"FLASK_APP=\'{module}:{factory}(args)\'" to specify ' |  | ||||||
|                     'arguments.'.format( |  | ||||||
|                         factory=attr_name, module=module.__name__ |  | ||||||
|                     ) |  | ||||||
|                 ) |  | ||||||
| 
 |  | ||||||
|     raise NoAppException( |  | ||||||
|         'Failed to find Flask application or factory in module "{module}". ' |  | ||||||
|         'Use "FLASK_APP={module}:name to specify one.'.format( |  | ||||||
|             module=module.__name__ |  | ||||||
|         ) |  | ||||||
|     ) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def call_factory(script_info, app_factory, arguments=()): |  | ||||||
|     """Takes an app factory, a ``script_info` object and  optionally a tuple |  | ||||||
|     of arguments. Checks for the existence of a script_info argument and calls |  | ||||||
|     the app_factory depending on that and the arguments provided. |  | ||||||
|     """ |  | ||||||
|     args_spec = getargspec(app_factory) |  | ||||||
|     arg_names = args_spec.args |  | ||||||
|     arg_defaults = args_spec.defaults |  | ||||||
| 
 |  | ||||||
|     if 'script_info' in arg_names: |  | ||||||
|         return app_factory(*arguments, script_info=script_info) |  | ||||||
|     elif arguments: |  | ||||||
|         return app_factory(*arguments) |  | ||||||
|     elif not arguments and len(arg_names) == 1 and arg_defaults is None: |  | ||||||
|         return app_factory(script_info) |  | ||||||
| 
 |  | ||||||
|     return app_factory() |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def _called_with_wrong_args(factory): |  | ||||||
|     """Check whether calling a function raised a ``TypeError`` because |  | ||||||
|     the call failed or because something in the factory raised the |  | ||||||
|     error. |  | ||||||
| 
 |  | ||||||
|     :param factory: the factory function that was called |  | ||||||
|     :return: true if the call failed |  | ||||||
|     """ |  | ||||||
|     tb = sys.exc_info()[2] |  | ||||||
| 
 |  | ||||||
|     try: |  | ||||||
|         while tb is not None: |  | ||||||
|             if tb.tb_frame.f_code is factory.__code__: |  | ||||||
|                 # in the factory, it was called successfully |  | ||||||
|                 return False |  | ||||||
| 
 |  | ||||||
|             tb = tb.tb_next |  | ||||||
| 
 |  | ||||||
|         # didn't reach the factory |  | ||||||
|         return True |  | ||||||
|     finally: |  | ||||||
|         del tb |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def find_app_by_string(script_info, module, app_name): |  | ||||||
|     """Checks if the given string is a variable name or a function. If it is a |  | ||||||
|     function, it checks for specified arguments and whether it takes a |  | ||||||
|     ``script_info`` argument and calls the function with the appropriate |  | ||||||
|     arguments. |  | ||||||
|     """ |  | ||||||
|     from flask import Flask |  | ||||||
|     match = re.match(r'^ *([^ ()]+) *(?:\((.*?) *,? *\))? *$', app_name) |  | ||||||
| 
 |  | ||||||
|     if not match: |  | ||||||
|         raise NoAppException( |  | ||||||
|             '"{name}" is not a valid variable name or function ' |  | ||||||
|             'expression.'.format(name=app_name) |  | ||||||
|         ) |  | ||||||
| 
 |  | ||||||
|     name, args = match.groups() |  | ||||||
| 
 |  | ||||||
|     try: |  | ||||||
|         attr = getattr(module, name) |  | ||||||
|     except AttributeError as e: |  | ||||||
|         raise NoAppException(e.args[0]) |  | ||||||
| 
 |  | ||||||
|     if inspect.isfunction(attr): |  | ||||||
|         if args: |  | ||||||
|             try: |  | ||||||
|                 args = ast.literal_eval('({args},)'.format(args=args)) |  | ||||||
|             except (ValueError, SyntaxError)as e: |  | ||||||
|                 raise NoAppException( |  | ||||||
|                     'Could not parse the arguments in ' |  | ||||||
|                     '"{app_name}".'.format(e=e, app_name=app_name) |  | ||||||
|                 ) |  | ||||||
|         else: |  | ||||||
|             args = () |  | ||||||
| 
 |  | ||||||
|         try: |  | ||||||
|             app = call_factory(script_info, attr, args) |  | ||||||
|         except TypeError as e: |  | ||||||
|             if not _called_with_wrong_args(attr): |  | ||||||
|                 raise |  | ||||||
| 
 |  | ||||||
|             raise NoAppException( |  | ||||||
|                 '{e}\nThe factory "{app_name}" in module "{module}" could not ' |  | ||||||
|                 'be called with the specified arguments.'.format( |  | ||||||
|                     e=e, app_name=app_name, module=module.__name__ |  | ||||||
|                 ) |  | ||||||
|             ) |  | ||||||
|     else: |  | ||||||
|         app = attr |  | ||||||
| 
 |  | ||||||
|     if isinstance(app, Flask): |  | ||||||
|         return app |  | ||||||
| 
 |  | ||||||
|     raise NoAppException( |  | ||||||
|         'A valid Flask application was not obtained from ' |  | ||||||
|         '"{module}:{app_name}".'.format( |  | ||||||
|             module=module.__name__, app_name=app_name |  | ||||||
|         ) |  | ||||||
|     ) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def prepare_import(path): |  | ||||||
|     """Given a filename this will try to calculate the python path, add it |  | ||||||
|     to the search path and return the actual module name that is expected. |  | ||||||
|     """ |  | ||||||
|     path = os.path.realpath(path) |  | ||||||
| 
 |  | ||||||
|     if os.path.splitext(path)[1] == '.py': |  | ||||||
|         path = os.path.splitext(path)[0] |  | ||||||
| 
 |  | ||||||
|     if os.path.basename(path) == '__init__': |  | ||||||
|         path = os.path.dirname(path) |  | ||||||
| 
 |  | ||||||
|     module_name = [] |  | ||||||
| 
 |  | ||||||
|     # move up until outside package structure (no __init__.py) |  | ||||||
|     while True: |  | ||||||
|         path, name = os.path.split(path) |  | ||||||
|         module_name.append(name) |  | ||||||
| 
 |  | ||||||
|         if not os.path.exists(os.path.join(path, '__init__.py')): |  | ||||||
|             break |  | ||||||
| 
 |  | ||||||
|     if sys.path[0] != path: |  | ||||||
|         sys.path.insert(0, path) |  | ||||||
| 
 |  | ||||||
|     return '.'.join(module_name[::-1]) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def locate_app(script_info, module_name, app_name, raise_if_not_found=True): |  | ||||||
|     __traceback_hide__ = True |  | ||||||
| 
 |  | ||||||
|     try: |  | ||||||
|         __import__(module_name) |  | ||||||
|     except ImportError: |  | ||||||
|         # Reraise the ImportError if it occurred within the imported module. |  | ||||||
|         # Determine this by checking whether the trace has a depth > 1. |  | ||||||
|         if sys.exc_info()[-1].tb_next: |  | ||||||
|             raise NoAppException( |  | ||||||
|                 'While importing "{name}", an ImportError was raised:' |  | ||||||
|                 '\n\n{tb}'.format(name=module_name, tb=traceback.format_exc()) |  | ||||||
|             ) |  | ||||||
|         elif raise_if_not_found: |  | ||||||
|             raise NoAppException( |  | ||||||
|                 'Could not import "{name}".'.format(name=module_name) |  | ||||||
|             ) |  | ||||||
|         else: |  | ||||||
|             return |  | ||||||
| 
 |  | ||||||
|     module = sys.modules[module_name] |  | ||||||
| 
 |  | ||||||
|     if app_name is None: |  | ||||||
|         return find_best_app(script_info, module) |  | ||||||
|     else: |  | ||||||
|         return find_app_by_string(script_info, module, app_name) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def get_version(ctx, param, value): |  | ||||||
|     if not value or ctx.resilient_parsing: |  | ||||||
|         return |  | ||||||
|     message = 'Flask %(version)s\nPython %(python_version)s' |  | ||||||
|     click.echo(message % { |  | ||||||
|         'version': __version__, |  | ||||||
|         'python_version': sys.version, |  | ||||||
|     }, color=ctx.color) |  | ||||||
|     ctx.exit() |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| version_option = click.Option( |  | ||||||
|     ['--version'], |  | ||||||
|     help='Show the flask version', |  | ||||||
|     expose_value=False, |  | ||||||
|     callback=get_version, |  | ||||||
|     is_flag=True, |  | ||||||
|     is_eager=True |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class DispatchingApp(object): |  | ||||||
|     """Special application that dispatches to a Flask application which |  | ||||||
|     is imported by name in a background thread.  If an error happens |  | ||||||
|     it is recorded and shown as part of the WSGI handling which in case |  | ||||||
|     of the Werkzeug debugger means that it shows up in the browser. |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     def __init__(self, loader, use_eager_loading=False): |  | ||||||
|         self.loader = loader |  | ||||||
|         self._app = None |  | ||||||
|         self._lock = Lock() |  | ||||||
|         self._bg_loading_exc_info = None |  | ||||||
|         if use_eager_loading: |  | ||||||
|             self._load_unlocked() |  | ||||||
|         else: |  | ||||||
|             self._load_in_background() |  | ||||||
| 
 |  | ||||||
|     def _load_in_background(self): |  | ||||||
|         def _load_app(): |  | ||||||
|             __traceback_hide__ = True |  | ||||||
|             with self._lock: |  | ||||||
|                 try: |  | ||||||
|                     self._load_unlocked() |  | ||||||
|                 except Exception: |  | ||||||
|                     self._bg_loading_exc_info = sys.exc_info() |  | ||||||
|         t = Thread(target=_load_app, args=()) |  | ||||||
|         t.start() |  | ||||||
| 
 |  | ||||||
|     def _flush_bg_loading_exception(self): |  | ||||||
|         __traceback_hide__ = True |  | ||||||
|         exc_info = self._bg_loading_exc_info |  | ||||||
|         if exc_info is not None: |  | ||||||
|             self._bg_loading_exc_info = None |  | ||||||
|             reraise(*exc_info) |  | ||||||
| 
 |  | ||||||
|     def _load_unlocked(self): |  | ||||||
|         __traceback_hide__ = True |  | ||||||
|         self._app = rv = self.loader() |  | ||||||
|         self._bg_loading_exc_info = None |  | ||||||
|         return rv |  | ||||||
| 
 |  | ||||||
|     def __call__(self, environ, start_response): |  | ||||||
|         __traceback_hide__ = True |  | ||||||
|         if self._app is not None: |  | ||||||
|             return self._app(environ, start_response) |  | ||||||
|         self._flush_bg_loading_exception() |  | ||||||
|         with self._lock: |  | ||||||
|             if self._app is not None: |  | ||||||
|                 rv = self._app |  | ||||||
|             else: |  | ||||||
|                 rv = self._load_unlocked() |  | ||||||
|             return rv(environ, start_response) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class ScriptInfo(object): |  | ||||||
|     """Help object to deal with Flask applications.  This is usually not |  | ||||||
|     necessary to interface with as it's used internally in the dispatching |  | ||||||
|     to click.  In future versions of Flask this object will most likely play |  | ||||||
|     a bigger role.  Typically it's created automatically by the |  | ||||||
|     :class:`FlaskGroup` but you can also manually create it and pass it |  | ||||||
|     onwards as click object. |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     def __init__(self, app_import_path=None, create_app=None): |  | ||||||
|         #: Optionally the import path for the Flask application. |  | ||||||
|         self.app_import_path = app_import_path or os.environ.get('FLASK_APP') |  | ||||||
|         #: Optionally a function that is passed the script info to create |  | ||||||
|         #: the instance of the application. |  | ||||||
|         self.create_app = create_app |  | ||||||
|         #: A dictionary with arbitrary data that can be associated with |  | ||||||
|         #: this script info. |  | ||||||
|         self.data = {} |  | ||||||
|         self._loaded_app = None |  | ||||||
| 
 |  | ||||||
|     def load_app(self): |  | ||||||
|         """Loads the Flask app (if not yet loaded) and returns it.  Calling |  | ||||||
|         this multiple times will just result in the already loaded app to |  | ||||||
|         be returned. |  | ||||||
|         """ |  | ||||||
|         __traceback_hide__ = True |  | ||||||
| 
 |  | ||||||
|         if self._loaded_app is not None: |  | ||||||
|             return self._loaded_app |  | ||||||
| 
 |  | ||||||
|         app = None |  | ||||||
| 
 |  | ||||||
|         if self.create_app is not None: |  | ||||||
|             app = call_factory(self, self.create_app) |  | ||||||
|         else: |  | ||||||
|             if self.app_import_path: |  | ||||||
|                 path, name = (self.app_import_path.split(':', 1) + [None])[:2] |  | ||||||
|                 import_name = prepare_import(path) |  | ||||||
|                 app = locate_app(self, import_name, name) |  | ||||||
|             else: |  | ||||||
|                 for path in ('wsgi.py', 'app.py'): |  | ||||||
|                     import_name = prepare_import(path) |  | ||||||
|                     app = locate_app(self, import_name, None, |  | ||||||
|                                      raise_if_not_found=False) |  | ||||||
| 
 |  | ||||||
|                     if app: |  | ||||||
|                         break |  | ||||||
| 
 |  | ||||||
|         if not app: |  | ||||||
|             raise NoAppException( |  | ||||||
|                 'Could not locate a Flask application. You did not provide ' |  | ||||||
|                 'the "FLASK_APP" environment variable, and a "wsgi.py" or ' |  | ||||||
|                 '"app.py" module was not found in the current directory.' |  | ||||||
|             ) |  | ||||||
| 
 |  | ||||||
|         debug = get_debug_flag() |  | ||||||
| 
 |  | ||||||
|         # Update the app's debug flag through the descriptor so that other |  | ||||||
|         # values repopulate as well. |  | ||||||
|         if debug is not None: |  | ||||||
|             app.debug = debug |  | ||||||
| 
 |  | ||||||
|         self._loaded_app = app |  | ||||||
|         return app |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| pass_script_info = click.make_pass_decorator(ScriptInfo, ensure=True) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def with_appcontext(f): |  | ||||||
|     """Wraps a callback so that it's guaranteed to be executed with the |  | ||||||
|     script's application context.  If callbacks are registered directly |  | ||||||
|     to the ``app.cli`` object then they are wrapped with this function |  | ||||||
|     by default unless it's disabled. |  | ||||||
|     """ |  | ||||||
|     @click.pass_context |  | ||||||
|     def decorator(__ctx, *args, **kwargs): |  | ||||||
|         with __ctx.ensure_object(ScriptInfo).load_app().app_context(): |  | ||||||
|             return __ctx.invoke(f, *args, **kwargs) |  | ||||||
|     return update_wrapper(decorator, f) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class AppGroup(click.Group): |  | ||||||
|     """This works similar to a regular click :class:`~click.Group` but it |  | ||||||
|     changes the behavior of the :meth:`command` decorator so that it |  | ||||||
|     automatically wraps the functions in :func:`with_appcontext`. |  | ||||||
| 
 |  | ||||||
|     Not to be confused with :class:`FlaskGroup`. |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     def command(self, *args, **kwargs): |  | ||||||
|         """This works exactly like the method of the same name on a regular |  | ||||||
|         :class:`click.Group` but it wraps callbacks in :func:`with_appcontext` |  | ||||||
|         unless it's disabled by passing ``with_appcontext=False``. |  | ||||||
|         """ |  | ||||||
|         wrap_for_ctx = kwargs.pop('with_appcontext', True) |  | ||||||
|         def decorator(f): |  | ||||||
|             if wrap_for_ctx: |  | ||||||
|                 f = with_appcontext(f) |  | ||||||
|             return click.Group.command(self, *args, **kwargs)(f) |  | ||||||
|         return decorator |  | ||||||
| 
 |  | ||||||
|     def group(self, *args, **kwargs): |  | ||||||
|         """This works exactly like the method of the same name on a regular |  | ||||||
|         :class:`click.Group` but it defaults the group class to |  | ||||||
|         :class:`AppGroup`. |  | ||||||
|         """ |  | ||||||
|         kwargs.setdefault('cls', AppGroup) |  | ||||||
|         return click.Group.group(self, *args, **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class FlaskGroup(AppGroup): |  | ||||||
|     """Special subclass of the :class:`AppGroup` group that supports |  | ||||||
|     loading more commands from the configured Flask app.  Normally a |  | ||||||
|     developer does not have to interface with this class but there are |  | ||||||
|     some very advanced use cases for which it makes sense to create an |  | ||||||
|     instance of this. |  | ||||||
| 
 |  | ||||||
|     For information as of why this is useful see :ref:`custom-scripts`. |  | ||||||
| 
 |  | ||||||
|     :param add_default_commands: if this is True then the default run and |  | ||||||
|         shell commands wil be added. |  | ||||||
|     :param add_version_option: adds the ``--version`` option. |  | ||||||
|     :param create_app: an optional callback that is passed the script info and |  | ||||||
|         returns the loaded app. |  | ||||||
|     :param load_dotenv: Load the nearest :file:`.env` and :file:`.flaskenv` |  | ||||||
|         files to set environment variables. Will also change the working |  | ||||||
|         directory to the directory containing the first file found. |  | ||||||
| 
 |  | ||||||
|     .. versionchanged:: 1.0 |  | ||||||
|         If installed, python-dotenv will be used to load environment variables |  | ||||||
|         from :file:`.env` and :file:`.flaskenv` files. |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     def __init__(self, add_default_commands=True, create_app=None, |  | ||||||
|                  add_version_option=True, load_dotenv=True, **extra): |  | ||||||
|         params = list(extra.pop('params', None) or ()) |  | ||||||
| 
 |  | ||||||
|         if add_version_option: |  | ||||||
|             params.append(version_option) |  | ||||||
| 
 |  | ||||||
|         AppGroup.__init__(self, params=params, **extra) |  | ||||||
|         self.create_app = create_app |  | ||||||
|         self.load_dotenv = load_dotenv |  | ||||||
| 
 |  | ||||||
|         if add_default_commands: |  | ||||||
|             self.add_command(run_command) |  | ||||||
|             self.add_command(shell_command) |  | ||||||
|             self.add_command(routes_command) |  | ||||||
| 
 |  | ||||||
|         self._loaded_plugin_commands = False |  | ||||||
| 
 |  | ||||||
|     def _load_plugin_commands(self): |  | ||||||
|         if self._loaded_plugin_commands: |  | ||||||
|             return |  | ||||||
|         try: |  | ||||||
|             import pkg_resources |  | ||||||
|         except ImportError: |  | ||||||
|             self._loaded_plugin_commands = True |  | ||||||
|             return |  | ||||||
| 
 |  | ||||||
|         for ep in pkg_resources.iter_entry_points('flask.commands'): |  | ||||||
|             self.add_command(ep.load(), ep.name) |  | ||||||
|         self._loaded_plugin_commands = True |  | ||||||
| 
 |  | ||||||
|     def get_command(self, ctx, name): |  | ||||||
|         self._load_plugin_commands() |  | ||||||
| 
 |  | ||||||
|         # We load built-in commands first as these should always be the |  | ||||||
|         # same no matter what the app does.  If the app does want to |  | ||||||
|         # override this it needs to make a custom instance of this group |  | ||||||
|         # and not attach the default commands. |  | ||||||
|         # |  | ||||||
|         # This also means that the script stays functional in case the |  | ||||||
|         # application completely fails. |  | ||||||
|         rv = AppGroup.get_command(self, ctx, name) |  | ||||||
|         if rv is not None: |  | ||||||
|             return rv |  | ||||||
| 
 |  | ||||||
|         info = ctx.ensure_object(ScriptInfo) |  | ||||||
|         try: |  | ||||||
|             rv = info.load_app().cli.get_command(ctx, name) |  | ||||||
|             if rv is not None: |  | ||||||
|                 return rv |  | ||||||
|         except NoAppException: |  | ||||||
|             pass |  | ||||||
| 
 |  | ||||||
|     def list_commands(self, ctx): |  | ||||||
|         self._load_plugin_commands() |  | ||||||
| 
 |  | ||||||
|         # The commands available is the list of both the application (if |  | ||||||
|         # available) plus the builtin commands. |  | ||||||
|         rv = set(click.Group.list_commands(self, ctx)) |  | ||||||
|         info = ctx.ensure_object(ScriptInfo) |  | ||||||
|         try: |  | ||||||
|             rv.update(info.load_app().cli.list_commands(ctx)) |  | ||||||
|         except Exception: |  | ||||||
|             # Here we intentionally swallow all exceptions as we don't |  | ||||||
|             # want the help page to break if the app does not exist. |  | ||||||
|             # If someone attempts to use the command we try to create |  | ||||||
|             # the app again and this will give us the error. |  | ||||||
|             # However, we will not do so silently because that would confuse |  | ||||||
|             # users. |  | ||||||
|             traceback.print_exc() |  | ||||||
|         return sorted(rv) |  | ||||||
| 
 |  | ||||||
|     def main(self, *args, **kwargs): |  | ||||||
|         # Set a global flag that indicates that we were invoked from the |  | ||||||
|         # command line interface. This is detected by Flask.run to make the |  | ||||||
|         # call into a no-op. This is necessary to avoid ugly errors when the |  | ||||||
|         # script that is loaded here also attempts to start a server. |  | ||||||
|         os.environ['FLASK_RUN_FROM_CLI'] = 'true' |  | ||||||
| 
 |  | ||||||
|         if get_load_dotenv(self.load_dotenv): |  | ||||||
|             load_dotenv() |  | ||||||
| 
 |  | ||||||
|         obj = kwargs.get('obj') |  | ||||||
| 
 |  | ||||||
|         if obj is None: |  | ||||||
|             obj = ScriptInfo(create_app=self.create_app) |  | ||||||
| 
 |  | ||||||
|         kwargs['obj'] = obj |  | ||||||
|         kwargs.setdefault('auto_envvar_prefix', 'FLASK') |  | ||||||
|         return super(FlaskGroup, self).main(*args, **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def _path_is_ancestor(path, other): |  | ||||||
|     """Take ``other`` and remove the length of ``path`` from it. Then join it |  | ||||||
|     to ``path``. If it is the original value, ``path`` is an ancestor of |  | ||||||
|     ``other``.""" |  | ||||||
|     return os.path.join(path, other[len(path):].lstrip(os.sep)) == other |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def load_dotenv(path=None): |  | ||||||
|     """Load "dotenv" files in order of precedence to set environment variables. |  | ||||||
| 
 |  | ||||||
|     If an env var is already set it is not overwritten, so earlier files in the |  | ||||||
|     list are preferred over later files. |  | ||||||
| 
 |  | ||||||
|     Changes the current working directory to the location of the first file |  | ||||||
|     found, with the assumption that it is in the top level project directory |  | ||||||
|     and will be where the Python path should import local packages from. |  | ||||||
| 
 |  | ||||||
|     This is a no-op if `python-dotenv`_ is not installed. |  | ||||||
| 
 |  | ||||||
|     .. _python-dotenv: https://github.com/theskumar/python-dotenv#readme |  | ||||||
| 
 |  | ||||||
|     :param path: Load the file at this location instead of searching. |  | ||||||
|     :return: ``True`` if a file was loaded. |  | ||||||
| 
 |  | ||||||
|     .. versionadded:: 1.0 |  | ||||||
|     """ |  | ||||||
|     if dotenv is None: |  | ||||||
|         if path or os.path.exists('.env') or os.path.exists('.flaskenv'): |  | ||||||
|             click.secho( |  | ||||||
|                 ' * Tip: There are .env files present.' |  | ||||||
|                 ' Do "pip install python-dotenv" to use them.', |  | ||||||
|                 fg='yellow') |  | ||||||
|         return |  | ||||||
| 
 |  | ||||||
|     if path is not None: |  | ||||||
|         return dotenv.load_dotenv(path) |  | ||||||
| 
 |  | ||||||
|     new_dir = None |  | ||||||
| 
 |  | ||||||
|     for name in ('.env', '.flaskenv'): |  | ||||||
|         path = dotenv.find_dotenv(name, usecwd=True) |  | ||||||
| 
 |  | ||||||
|         if not path: |  | ||||||
|             continue |  | ||||||
| 
 |  | ||||||
|         if new_dir is None: |  | ||||||
|             new_dir = os.path.dirname(path) |  | ||||||
| 
 |  | ||||||
|         dotenv.load_dotenv(path) |  | ||||||
| 
 |  | ||||||
|     if new_dir and os.getcwd() != new_dir: |  | ||||||
|         os.chdir(new_dir) |  | ||||||
| 
 |  | ||||||
|     return new_dir is not None  # at least one file was located and loaded |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def show_server_banner(env, debug, app_import_path, eager_loading): |  | ||||||
|     """Show extra startup messages the first time the server is run, |  | ||||||
|     ignoring the reloader. |  | ||||||
|     """ |  | ||||||
|     if os.environ.get('WERKZEUG_RUN_MAIN') == 'true': |  | ||||||
|         return |  | ||||||
| 
 |  | ||||||
|     if app_import_path is not None: |  | ||||||
|         message = ' * Serving Flask app "{0}"'.format(app_import_path) |  | ||||||
| 
 |  | ||||||
|         if not eager_loading: |  | ||||||
|             message += ' (lazy loading)' |  | ||||||
| 
 |  | ||||||
|         click.echo(message) |  | ||||||
| 
 |  | ||||||
|     click.echo(' * Environment: {0}'.format(env)) |  | ||||||
| 
 |  | ||||||
|     if env == 'production': |  | ||||||
|         click.secho( |  | ||||||
|             '   WARNING: Do not use the development server in a production' |  | ||||||
|             ' environment.', fg='red') |  | ||||||
|         click.secho('   Use a production WSGI server instead.', dim=True) |  | ||||||
| 
 |  | ||||||
|     if debug is not None: |  | ||||||
|         click.echo(' * Debug mode: {0}'.format('on' if debug else 'off')) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class CertParamType(click.ParamType): |  | ||||||
|     """Click option type for the ``--cert`` option. Allows either an |  | ||||||
|     existing file, the string ``'adhoc'``, or an import for a |  | ||||||
|     :class:`~ssl.SSLContext` object. |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     name = 'path' |  | ||||||
| 
 |  | ||||||
|     def __init__(self): |  | ||||||
|         self.path_type = click.Path( |  | ||||||
|             exists=True, dir_okay=False, resolve_path=True) |  | ||||||
| 
 |  | ||||||
|     def convert(self, value, param, ctx): |  | ||||||
|         try: |  | ||||||
|             return self.path_type(value, param, ctx) |  | ||||||
|         except click.BadParameter: |  | ||||||
|             value = click.STRING(value, param, ctx).lower() |  | ||||||
| 
 |  | ||||||
|             if value == 'adhoc': |  | ||||||
|                 try: |  | ||||||
|                     import OpenSSL |  | ||||||
|                 except ImportError: |  | ||||||
|                     raise click.BadParameter( |  | ||||||
|                         'Using ad-hoc certificates requires pyOpenSSL.', |  | ||||||
|                         ctx, param) |  | ||||||
| 
 |  | ||||||
|                 return value |  | ||||||
| 
 |  | ||||||
|             obj = import_string(value, silent=True) |  | ||||||
| 
 |  | ||||||
|             if sys.version_info < (2, 7): |  | ||||||
|                 if obj: |  | ||||||
|                     return obj |  | ||||||
|             else: |  | ||||||
|                 if isinstance(obj, ssl.SSLContext): |  | ||||||
|                     return obj |  | ||||||
| 
 |  | ||||||
|             raise |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def _validate_key(ctx, param, value): |  | ||||||
|     """The ``--key`` option must be specified when ``--cert`` is a file. |  | ||||||
|     Modifies the ``cert`` param to be a ``(cert, key)`` pair if needed. |  | ||||||
|     """ |  | ||||||
|     cert = ctx.params.get('cert') |  | ||||||
|     is_adhoc = cert == 'adhoc' |  | ||||||
| 
 |  | ||||||
|     if sys.version_info < (2, 7): |  | ||||||
|         is_context = cert and not isinstance(cert, (text_type, bytes)) |  | ||||||
|     else: |  | ||||||
|         is_context = isinstance(cert, ssl.SSLContext) |  | ||||||
| 
 |  | ||||||
|     if value is not None: |  | ||||||
|         if is_adhoc: |  | ||||||
|             raise click.BadParameter( |  | ||||||
|                 'When "--cert" is "adhoc", "--key" is not used.', |  | ||||||
|                 ctx, param) |  | ||||||
| 
 |  | ||||||
|         if is_context: |  | ||||||
|             raise click.BadParameter( |  | ||||||
|                 'When "--cert" is an SSLContext object, "--key is not used.', |  | ||||||
|                 ctx, param) |  | ||||||
| 
 |  | ||||||
|         if not cert: |  | ||||||
|             raise click.BadParameter( |  | ||||||
|                 '"--cert" must also be specified.', |  | ||||||
|                 ctx, param) |  | ||||||
| 
 |  | ||||||
|         ctx.params['cert'] = cert, value |  | ||||||
| 
 |  | ||||||
|     else: |  | ||||||
|         if cert and not (is_adhoc or is_context): |  | ||||||
|             raise click.BadParameter( |  | ||||||
|                 'Required when using "--cert".', |  | ||||||
|                 ctx, param) |  | ||||||
| 
 |  | ||||||
|     return value |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| @click.command('run', short_help='Runs a development server.') |  | ||||||
| @click.option('--host', '-h', default='127.0.0.1', |  | ||||||
|               help='The interface to bind to.') |  | ||||||
| @click.option('--port', '-p', default=5000, |  | ||||||
|               help='The port to bind to.') |  | ||||||
| @click.option('--cert', type=CertParamType(), |  | ||||||
|               help='Specify a certificate file to use HTTPS.') |  | ||||||
| @click.option('--key', |  | ||||||
|               type=click.Path(exists=True, dir_okay=False, resolve_path=True), |  | ||||||
|               callback=_validate_key, expose_value=False, |  | ||||||
|               help='The key file to use when specifying a certificate.') |  | ||||||
| @click.option('--reload/--no-reload', default=None, |  | ||||||
|               help='Enable or disable the reloader. By default the reloader ' |  | ||||||
|               'is active if debug is enabled.') |  | ||||||
| @click.option('--debugger/--no-debugger', default=None, |  | ||||||
|               help='Enable or disable the debugger. By default the debugger ' |  | ||||||
|               'is active if debug is enabled.') |  | ||||||
| @click.option('--eager-loading/--lazy-loader', default=None, |  | ||||||
|               help='Enable or disable eager loading. By default eager ' |  | ||||||
|               'loading is enabled if the reloader is disabled.') |  | ||||||
| @click.option('--with-threads/--without-threads', default=True, |  | ||||||
|               help='Enable or disable multithreading.') |  | ||||||
| @pass_script_info |  | ||||||
| def run_command(info, host, port, reload, debugger, eager_loading, |  | ||||||
|                 with_threads, cert): |  | ||||||
|     """Run a local development server. |  | ||||||
| 
 |  | ||||||
|     This server is for development purposes only. It does not provide |  | ||||||
|     the stability, security, or performance of production WSGI servers. |  | ||||||
| 
 |  | ||||||
|     The reloader and debugger are enabled by default if |  | ||||||
|     FLASK_ENV=development or FLASK_DEBUG=1. |  | ||||||
|     """ |  | ||||||
|     debug = get_debug_flag() |  | ||||||
| 
 |  | ||||||
|     if reload is None: |  | ||||||
|         reload = debug |  | ||||||
| 
 |  | ||||||
|     if debugger is None: |  | ||||||
|         debugger = debug |  | ||||||
| 
 |  | ||||||
|     if eager_loading is None: |  | ||||||
|         eager_loading = not reload |  | ||||||
| 
 |  | ||||||
|     show_server_banner(get_env(), debug, info.app_import_path, eager_loading) |  | ||||||
|     app = DispatchingApp(info.load_app, use_eager_loading=eager_loading) |  | ||||||
| 
 |  | ||||||
|     from werkzeug.serving import run_simple |  | ||||||
|     run_simple(host, port, app, use_reloader=reload, use_debugger=debugger, |  | ||||||
|                threaded=with_threads, ssl_context=cert) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| @click.command('shell', short_help='Runs a shell in the app context.') |  | ||||||
| @with_appcontext |  | ||||||
| def shell_command(): |  | ||||||
|     """Runs an interactive Python shell in the context of a given |  | ||||||
|     Flask application.  The application will populate the default |  | ||||||
|     namespace of this shell according to it's configuration. |  | ||||||
| 
 |  | ||||||
|     This is useful for executing small snippets of management code |  | ||||||
|     without having to manually configure the application. |  | ||||||
|     """ |  | ||||||
|     import code |  | ||||||
|     from flask.globals import _app_ctx_stack |  | ||||||
|     app = _app_ctx_stack.top.app |  | ||||||
|     banner = 'Python %s on %s\nApp: %s [%s]\nInstance: %s' % ( |  | ||||||
|         sys.version, |  | ||||||
|         sys.platform, |  | ||||||
|         app.import_name, |  | ||||||
|         app.env, |  | ||||||
|         app.instance_path, |  | ||||||
|     ) |  | ||||||
|     ctx = {} |  | ||||||
| 
 |  | ||||||
|     # Support the regular Python interpreter startup script if someone |  | ||||||
|     # is using it. |  | ||||||
|     startup = os.environ.get('PYTHONSTARTUP') |  | ||||||
|     if startup and os.path.isfile(startup): |  | ||||||
|         with open(startup, 'r') as f: |  | ||||||
|             eval(compile(f.read(), startup, 'exec'), ctx) |  | ||||||
| 
 |  | ||||||
|     ctx.update(app.make_shell_context()) |  | ||||||
| 
 |  | ||||||
|     code.interact(banner=banner, local=ctx) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| @click.command('routes', short_help='Show the routes for the app.') |  | ||||||
| @click.option( |  | ||||||
|     '--sort', '-s', |  | ||||||
|     type=click.Choice(('endpoint', 'methods', 'rule', 'match')), |  | ||||||
|     default='endpoint', |  | ||||||
|     help=( |  | ||||||
|         'Method to sort routes by. "match" is the order that Flask will match ' |  | ||||||
|         'routes when dispatching a request.' |  | ||||||
|     ) |  | ||||||
| ) |  | ||||||
| @click.option( |  | ||||||
|     '--all-methods', |  | ||||||
|     is_flag=True, |  | ||||||
|     help="Show HEAD and OPTIONS methods." |  | ||||||
| ) |  | ||||||
| @with_appcontext |  | ||||||
| def routes_command(sort, all_methods): |  | ||||||
|     """Show all registered routes with endpoints and methods.""" |  | ||||||
| 
 |  | ||||||
|     rules = list(current_app.url_map.iter_rules()) |  | ||||||
|     if not rules: |  | ||||||
|         click.echo('No routes were registered.') |  | ||||||
|         return |  | ||||||
| 
 |  | ||||||
|     ignored_methods = set(() if all_methods else ('HEAD', 'OPTIONS')) |  | ||||||
| 
 |  | ||||||
|     if sort in ('endpoint', 'rule'): |  | ||||||
|         rules = sorted(rules, key=attrgetter(sort)) |  | ||||||
|     elif sort == 'methods': |  | ||||||
|         rules = sorted(rules, key=lambda rule: sorted(rule.methods)) |  | ||||||
| 
 |  | ||||||
|     rule_methods = [ |  | ||||||
|         ', '.join(sorted(rule.methods - ignored_methods)) for rule in rules |  | ||||||
|     ] |  | ||||||
| 
 |  | ||||||
|     headers = ('Endpoint', 'Methods', 'Rule') |  | ||||||
|     widths = ( |  | ||||||
|         max(len(rule.endpoint) for rule in rules), |  | ||||||
|         max(len(methods) for methods in rule_methods), |  | ||||||
|         max(len(rule.rule) for rule in rules), |  | ||||||
|     ) |  | ||||||
|     widths = [max(len(h), w) for h, w in zip(headers, widths)] |  | ||||||
|     row = '{{0:<{0}}}  {{1:<{1}}}  {{2:<{2}}}'.format(*widths) |  | ||||||
| 
 |  | ||||||
|     click.echo(row.format(*headers).strip()) |  | ||||||
|     click.echo(row.format(*('-' * width for width in widths))) |  | ||||||
| 
 |  | ||||||
|     for rule, methods in zip(rules, rule_methods): |  | ||||||
|         click.echo(row.format(rule.endpoint, methods, rule.rule).rstrip()) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| cli = FlaskGroup(help="""\ |  | ||||||
| A general utility script for Flask applications. |  | ||||||
| 
 |  | ||||||
| Provides commands from Flask, extensions, and the application. Loads the |  | ||||||
| application defined in the FLASK_APP environment variable, or from a wsgi.py |  | ||||||
| file. Setting the FLASK_ENV environment variable to 'development' will enable |  | ||||||
| debug mode. |  | ||||||
| 
 |  | ||||||
| \b |  | ||||||
|   {prefix}{cmd} FLASK_APP=hello.py |  | ||||||
|   {prefix}{cmd} FLASK_ENV=development |  | ||||||
|   {prefix}flask run |  | ||||||
| """.format( |  | ||||||
|     cmd='export' if os.name == 'posix' else 'set', |  | ||||||
|     prefix='$ ' if os.name == 'posix' else '> ' |  | ||||||
| )) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def main(as_module=False): |  | ||||||
|     args = sys.argv[1:] |  | ||||||
| 
 |  | ||||||
|     if as_module: |  | ||||||
|         this_module = 'flask' |  | ||||||
| 
 |  | ||||||
|         if sys.version_info < (2, 7): |  | ||||||
|             this_module += '.cli' |  | ||||||
| 
 |  | ||||||
|         name = 'python -m ' + this_module |  | ||||||
| 
 |  | ||||||
|         # Python rewrites "python -m flask" to the path to the file in argv. |  | ||||||
|         # Restore the original command so that the reloader works. |  | ||||||
|         sys.argv = ['-m', this_module] + args |  | ||||||
|     else: |  | ||||||
|         name = None |  | ||||||
| 
 |  | ||||||
|     cli.main(args=args, prog_name=name) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| if __name__ == '__main__': |  | ||||||
|     main(as_module=True) |  | ||||||
| @ -1,265 +0,0 @@ | |||||||
| # -*- coding: utf-8 -*- |  | ||||||
| """ |  | ||||||
|     flask.config |  | ||||||
|     ~~~~~~~~~~~~ |  | ||||||
| 
 |  | ||||||
|     Implements the configuration related objects. |  | ||||||
| 
 |  | ||||||
|     :copyright: © 2010 by the Pallets team. |  | ||||||
|     :license: BSD, see LICENSE for more details. |  | ||||||
| """ |  | ||||||
| 
 |  | ||||||
| import os |  | ||||||
| import types |  | ||||||
| import errno |  | ||||||
| 
 |  | ||||||
| from werkzeug.utils import import_string |  | ||||||
| from ._compat import string_types, iteritems |  | ||||||
| from . import json |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 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 = types.ModuleType('config') |  | ||||||
|         d.__file__ = filename |  | ||||||
|         try: |  | ||||||
|             with open(filename, mode='rb') 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, errno.ENOTDIR |  | ||||||
|             ): |  | ||||||
|                 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. :meth:`from_object` |  | ||||||
|         loads only the uppercase attributes of the module/class. A ``dict`` |  | ||||||
|         object will not work with :meth:`from_object` because the keys of a |  | ||||||
|         ``dict`` are not attributes of the ``dict`` class. |  | ||||||
| 
 |  | ||||||
|         Example of module-based configuration:: |  | ||||||
| 
 |  | ||||||
|             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. |  | ||||||
| 
 |  | ||||||
|         See :ref:`config-dev-prod` for an example of class-based configuration |  | ||||||
|         using :meth:`from_object`. |  | ||||||
| 
 |  | ||||||
|         :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 from_json(self, filename, silent=False): |  | ||||||
|         """Updates the values in the config from a JSON file. This function |  | ||||||
|         behaves as if the JSON object was a dictionary and passed to the |  | ||||||
|         :meth:`from_mapping` function. |  | ||||||
| 
 |  | ||||||
|         :param filename: the filename of the JSON file.  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.11 |  | ||||||
|         """ |  | ||||||
|         filename = os.path.join(self.root_path, filename) |  | ||||||
| 
 |  | ||||||
|         try: |  | ||||||
|             with open(filename) as json_file: |  | ||||||
|                 obj = json.loads(json_file.read()) |  | ||||||
|         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 |  | ||||||
|         return self.from_mapping(obj) |  | ||||||
| 
 |  | ||||||
|     def from_mapping(self, *mapping, **kwargs): |  | ||||||
|         """Updates the config like :meth:`update` ignoring items with non-upper |  | ||||||
|         keys. |  | ||||||
| 
 |  | ||||||
|         .. versionadded:: 0.11 |  | ||||||
|         """ |  | ||||||
|         mappings = [] |  | ||||||
|         if len(mapping) == 1: |  | ||||||
|             if hasattr(mapping[0], 'items'): |  | ||||||
|                 mappings.append(mapping[0].items()) |  | ||||||
|             else: |  | ||||||
|                 mappings.append(mapping[0]) |  | ||||||
|         elif len(mapping) > 1: |  | ||||||
|             raise TypeError( |  | ||||||
|                 'expected at most 1 positional argument, got %d' % len(mapping) |  | ||||||
|             ) |  | ||||||
|         mappings.append(kwargs.items()) |  | ||||||
|         for mapping in mappings: |  | ||||||
|             for (key, value) in mapping: |  | ||||||
|                 if key.isupper(): |  | ||||||
|                     self[key] = value |  | ||||||
|         return True |  | ||||||
| 
 |  | ||||||
|     def get_namespace(self, namespace, lowercase=True, trim_namespace=True): |  | ||||||
|         """Returns a dictionary containing a subset of configuration options |  | ||||||
|         that match the specified namespace/prefix. Example usage:: |  | ||||||
| 
 |  | ||||||
|             app.config['IMAGE_STORE_TYPE'] = 'fs' |  | ||||||
|             app.config['IMAGE_STORE_PATH'] = '/var/app/images' |  | ||||||
|             app.config['IMAGE_STORE_BASE_URL'] = 'http://img.website.com' |  | ||||||
|             image_store_config = app.config.get_namespace('IMAGE_STORE_') |  | ||||||
| 
 |  | ||||||
|         The resulting dictionary `image_store_config` would look like:: |  | ||||||
| 
 |  | ||||||
|             { |  | ||||||
|                 'type': 'fs', |  | ||||||
|                 'path': '/var/app/images', |  | ||||||
|                 'base_url': 'http://img.website.com' |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|         This is often useful when configuration options map directly to |  | ||||||
|         keyword arguments in functions or class constructors. |  | ||||||
| 
 |  | ||||||
|         :param namespace: a configuration namespace |  | ||||||
|         :param lowercase: a flag indicating if the keys of the resulting |  | ||||||
|                           dictionary should be lowercase |  | ||||||
|         :param trim_namespace: a flag indicating if the keys of the resulting |  | ||||||
|                           dictionary should not include the namespace |  | ||||||
| 
 |  | ||||||
|         .. versionadded:: 0.11 |  | ||||||
|         """ |  | ||||||
|         rv = {} |  | ||||||
|         for k, v in iteritems(self): |  | ||||||
|             if not k.startswith(namespace): |  | ||||||
|                 continue |  | ||||||
|             if trim_namespace: |  | ||||||
|                 key = k[len(namespace):] |  | ||||||
|             else: |  | ||||||
|                 key = k |  | ||||||
|             if lowercase: |  | ||||||
|                 key = key.lower() |  | ||||||
|             rv[key] = v |  | ||||||
|         return rv |  | ||||||
| 
 |  | ||||||
|     def __repr__(self): |  | ||||||
|         return '<%s %s>' % (self.__class__.__name__, dict.__repr__(self)) |  | ||||||
| @ -1,457 +0,0 @@ | |||||||
| # -*- coding: utf-8 -*- |  | ||||||
| """ |  | ||||||
|     flask.ctx |  | ||||||
|     ~~~~~~~~~ |  | ||||||
| 
 |  | ||||||
|     Implements the objects required to keep the context. |  | ||||||
| 
 |  | ||||||
|     :copyright: © 2010 by the Pallets team. |  | ||||||
|     :license: BSD, see LICENSE for more details. |  | ||||||
| """ |  | ||||||
| 
 |  | ||||||
| import sys |  | ||||||
| from functools import update_wrapper |  | ||||||
| 
 |  | ||||||
| from werkzeug.exceptions import HTTPException |  | ||||||
| 
 |  | ||||||
| from .globals import _request_ctx_stack, _app_ctx_stack |  | ||||||
| from .signals import appcontext_pushed, appcontext_popped |  | ||||||
| from ._compat import BROKEN_PYPY_CTXMGR_EXIT, reraise |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| # a singleton sentinel value for parameter defaults |  | ||||||
| _sentinel = object() |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class _AppCtxGlobals(object): |  | ||||||
|     """A plain object. Used as a namespace for storing data during an |  | ||||||
|     application context. |  | ||||||
| 
 |  | ||||||
|     Creating an app context automatically creates this object, which is |  | ||||||
|     made available as the :data:`g` proxy. |  | ||||||
| 
 |  | ||||||
|     .. describe:: 'key' in g |  | ||||||
| 
 |  | ||||||
|         Check whether an attribute is present. |  | ||||||
| 
 |  | ||||||
|         .. versionadded:: 0.10 |  | ||||||
| 
 |  | ||||||
|     .. describe:: iter(g) |  | ||||||
| 
 |  | ||||||
|         Return an iterator over the attribute names. |  | ||||||
| 
 |  | ||||||
|         .. versionadded:: 0.10 |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     def get(self, name, default=None): |  | ||||||
|         """Get an attribute by name, or a default value. Like |  | ||||||
|         :meth:`dict.get`. |  | ||||||
| 
 |  | ||||||
|         :param name: Name of attribute to get. |  | ||||||
|         :param default: Value to return if the attribute is not present. |  | ||||||
| 
 |  | ||||||
|         .. versionadded:: 0.10 |  | ||||||
|         """ |  | ||||||
|         return self.__dict__.get(name, default) |  | ||||||
| 
 |  | ||||||
|     def pop(self, name, default=_sentinel): |  | ||||||
|         """Get and remove an attribute by name. Like :meth:`dict.pop`. |  | ||||||
| 
 |  | ||||||
|         :param name: Name of attribute to pop. |  | ||||||
|         :param default: Value to return if the attribute is not present, |  | ||||||
|             instead of raise a ``KeyError``. |  | ||||||
| 
 |  | ||||||
|         .. versionadded:: 0.11 |  | ||||||
|         """ |  | ||||||
|         if default is _sentinel: |  | ||||||
|             return self.__dict__.pop(name) |  | ||||||
|         else: |  | ||||||
|             return self.__dict__.pop(name, default) |  | ||||||
| 
 |  | ||||||
|     def setdefault(self, name, default=None): |  | ||||||
|         """Get the value of an attribute if it is present, otherwise |  | ||||||
|         set and return a default value. Like :meth:`dict.setdefault`. |  | ||||||
| 
 |  | ||||||
|         :param name: Name of attribute to get. |  | ||||||
|         :param: default: Value to set and return if the attribute is not |  | ||||||
|             present. |  | ||||||
| 
 |  | ||||||
|         .. versionadded:: 0.11 |  | ||||||
|         """ |  | ||||||
|         return self.__dict__.setdefault(name, default) |  | ||||||
| 
 |  | ||||||
|     def __contains__(self, item): |  | ||||||
|         return item in self.__dict__ |  | ||||||
| 
 |  | ||||||
|     def __iter__(self): |  | ||||||
|         return iter(self.__dict__) |  | ||||||
| 
 |  | ||||||
|     def __repr__(self): |  | ||||||
|         top = _app_ctx_stack.top |  | ||||||
|         if top is not None: |  | ||||||
|             return '<flask.g of %r>' % 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 |  | ||||||
|         if hasattr(sys, 'exc_clear'): |  | ||||||
|             sys.exc_clear() |  | ||||||
|         _app_ctx_stack.push(self) |  | ||||||
|         appcontext_pushed.send(self.app) |  | ||||||
| 
 |  | ||||||
|     def pop(self, exc=_sentinel): |  | ||||||
|         """Pops the app context.""" |  | ||||||
|         try: |  | ||||||
|             self._refcnt -= 1 |  | ||||||
|             if self._refcnt <= 0: |  | ||||||
|                 if exc is _sentinel: |  | ||||||
|                     exc = sys.exc_info()[1] |  | ||||||
|                 self.app.do_teardown_appcontext(exc) |  | ||||||
|         finally: |  | ||||||
|             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) |  | ||||||
| 
 |  | ||||||
|         if BROKEN_PYPY_CTXMGR_EXIT and exc_type is not None: |  | ||||||
|             reraise(exc_type, exc_value, tb) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 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() |  | ||||||
| 
 |  | ||||||
|     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 test suite 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) |  | ||||||
| 
 |  | ||||||
|         if hasattr(sys, 'exc_clear'): |  | ||||||
|             sys.exc_clear() |  | ||||||
| 
 |  | ||||||
|         _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. |  | ||||||
|         # Only open a new session if this is the first time the request was |  | ||||||
|         # pushed, otherwise stream_with_context loses the session. |  | ||||||
|         if self.session is None: |  | ||||||
|             session_interface = self.app.session_interface |  | ||||||
|             self.session = session_interface.open_session( |  | ||||||
|                 self.app, self.request |  | ||||||
|             ) |  | ||||||
| 
 |  | ||||||
|             if self.session is None: |  | ||||||
|                 self.session = session_interface.make_null_session(self.app) |  | ||||||
| 
 |  | ||||||
|     def pop(self, exc=_sentinel): |  | ||||||
|         """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() |  | ||||||
| 
 |  | ||||||
|         try: |  | ||||||
|             clear_request = False |  | ||||||
|             if not self._implicit_app_ctx_stack: |  | ||||||
|                 self.preserved = False |  | ||||||
|                 self._preserved_exc = None |  | ||||||
|                 if exc is _sentinel: |  | ||||||
|                     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 |  | ||||||
|         finally: |  | ||||||
|             rv = _request_ctx_stack.pop() |  | ||||||
| 
 |  | ||||||
|             # 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) |  | ||||||
| 
 |  | ||||||
|             assert rv is self, 'Popped wrong request context.  ' \ |  | ||||||
|                 '(%r instead of %r)' % (rv, self) |  | ||||||
| 
 |  | ||||||
|     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) |  | ||||||
| 
 |  | ||||||
|         if BROKEN_PYPY_CTXMGR_EXIT and exc_type is not None: |  | ||||||
|             reraise(exc_type, exc_value, tb) |  | ||||||
| 
 |  | ||||||
|     def __repr__(self): |  | ||||||
|         return '<%s \'%s\' [%s] of %s>' % ( |  | ||||||
|             self.__class__.__name__, |  | ||||||
|             self.request.url, |  | ||||||
|             self.request.method, |  | ||||||
|             self.app.name, |  | ||||||
|         ) |  | ||||||
| @ -1,168 +0,0 @@ | |||||||
| # -*- coding: utf-8 -*- |  | ||||||
| """ |  | ||||||
|     flask.debughelpers |  | ||||||
|     ~~~~~~~~~~~~~~~~~~ |  | ||||||
| 
 |  | ||||||
|     Various helpers to make the development experience better. |  | ||||||
| 
 |  | ||||||
|     :copyright: © 2010 by the Pallets team. |  | ||||||
|     :license: BSD, see LICENSE for more details. |  | ||||||
| """ |  | ||||||
| 
 |  | ||||||
| import os |  | ||||||
| from warnings import warn |  | ||||||
| 
 |  | ||||||
| from ._compat import implements_to_string, text_type |  | ||||||
| from .app import Flask |  | ||||||
| from .blueprints import Blueprint |  | ||||||
| from .globals import _request_ctx_stack |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class UnexpectedUnicodeError(AssertionError, UnicodeError): |  | ||||||
|     """Raised in places where we want some better error reporting for |  | ||||||
|     unexpected unicode or binary data. |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| @implements_to_string |  | ||||||
| class DebugFilesKeyError(KeyError, AssertionError): |  | ||||||
|     """Raised from request.files during debugging.  The idea is that it can |  | ||||||
|     provide a better error message than just a generic KeyError/BadRequest. |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     def __init__(self, request, key): |  | ||||||
|         form_matches = request.form.getlist(key) |  | ||||||
|         buf = ['You tried to access the file "%s" in the request.files ' |  | ||||||
|                'dictionary but it does not exist.  The mimetype for the request ' |  | ||||||
|                'is "%s" instead of "multipart/form-data" which means that no ' |  | ||||||
|                'file contents were transmitted.  To fix this error you should ' |  | ||||||
|                'provide enctype="multipart/form-data" in your form.' % |  | ||||||
|                (key, request.mimetype)] |  | ||||||
|         if form_matches: |  | ||||||
|             buf.append('\n\nThe browser instead transmitted some file names. ' |  | ||||||
|                        'This was submitted: %s' % ', '.join('"%s"' % x |  | ||||||
|                             for x in form_matches)) |  | ||||||
|         self.msg = ''.join(buf) |  | ||||||
| 
 |  | ||||||
|     def __str__(self): |  | ||||||
|         return self.msg |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class FormDataRoutingRedirect(AssertionError): |  | ||||||
|     """This exception is raised by Flask in debug mode if it detects a |  | ||||||
|     redirect caused by the routing system when the request method is not |  | ||||||
|     GET, HEAD or OPTIONS.  Reasoning: form data will be dropped. |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     def __init__(self, request): |  | ||||||
|         exc = request.routing_exception |  | ||||||
|         buf = ['A request was sent to this URL (%s) but a redirect was ' |  | ||||||
|                'issued automatically by the routing system to "%s".' |  | ||||||
|                % (request.url, exc.new_url)] |  | ||||||
| 
 |  | ||||||
|         # In case just a slash was appended we can be extra helpful |  | ||||||
|         if request.base_url + '/' == exc.new_url.split('?')[0]: |  | ||||||
|             buf.append('  The URL was defined with a trailing slash so ' |  | ||||||
|                        'Flask will automatically redirect to the URL ' |  | ||||||
|                        'with the trailing slash if it was accessed ' |  | ||||||
|                        'without one.') |  | ||||||
| 
 |  | ||||||
|         buf.append('  Make sure to directly send your %s-request to this URL ' |  | ||||||
|                    'since we can\'t make browsers or HTTP clients redirect ' |  | ||||||
|                    'with form data reliably or without user interaction.' % |  | ||||||
|                    request.method) |  | ||||||
|         buf.append('\n\nNote: this exception is only raised in debug mode') |  | ||||||
|         AssertionError.__init__(self, ''.join(buf).encode('utf-8')) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def attach_enctype_error_multidict(request): |  | ||||||
|     """Since Flask 0.8 we're monkeypatching the files object in case a |  | ||||||
|     request is detected that does not use multipart form data but the files |  | ||||||
|     object is accessed. |  | ||||||
|     """ |  | ||||||
|     oldcls = request.files.__class__ |  | ||||||
|     class newcls(oldcls): |  | ||||||
|         def __getitem__(self, key): |  | ||||||
|             try: |  | ||||||
|                 return oldcls.__getitem__(self, key) |  | ||||||
|             except KeyError: |  | ||||||
|                 if key not in request.form: |  | ||||||
|                     raise |  | ||||||
|                 raise DebugFilesKeyError(request, key) |  | ||||||
|     newcls.__name__ = oldcls.__name__ |  | ||||||
|     newcls.__module__ = oldcls.__module__ |  | ||||||
|     request.files.__class__ = newcls |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def _dump_loader_info(loader): |  | ||||||
|     yield 'class: %s.%s' % (type(loader).__module__, type(loader).__name__) |  | ||||||
|     for key, value in sorted(loader.__dict__.items()): |  | ||||||
|         if key.startswith('_'): |  | ||||||
|             continue |  | ||||||
|         if isinstance(value, (tuple, list)): |  | ||||||
|             if not all(isinstance(x, (str, text_type)) for x in value): |  | ||||||
|                 continue |  | ||||||
|             yield '%s:' % key |  | ||||||
|             for item in value: |  | ||||||
|                 yield '  - %s' % item |  | ||||||
|             continue |  | ||||||
|         elif not isinstance(value, (str, text_type, int, float, bool)): |  | ||||||
|             continue |  | ||||||
|         yield '%s: %r' % (key, value) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def explain_template_loading_attempts(app, template, attempts): |  | ||||||
|     """This should help developers understand what failed""" |  | ||||||
|     info = ['Locating template "%s":' % template] |  | ||||||
|     total_found = 0 |  | ||||||
|     blueprint = None |  | ||||||
|     reqctx = _request_ctx_stack.top |  | ||||||
|     if reqctx is not None and reqctx.request.blueprint is not None: |  | ||||||
|         blueprint = reqctx.request.blueprint |  | ||||||
| 
 |  | ||||||
|     for idx, (loader, srcobj, triple) in enumerate(attempts): |  | ||||||
|         if isinstance(srcobj, Flask): |  | ||||||
|             src_info = 'application "%s"' % srcobj.import_name |  | ||||||
|         elif isinstance(srcobj, Blueprint): |  | ||||||
|             src_info = 'blueprint "%s" (%s)' % (srcobj.name, |  | ||||||
|                                                 srcobj.import_name) |  | ||||||
|         else: |  | ||||||
|             src_info = repr(srcobj) |  | ||||||
| 
 |  | ||||||
|         info.append('% 5d: trying loader of %s' % ( |  | ||||||
|             idx + 1, src_info)) |  | ||||||
| 
 |  | ||||||
|         for line in _dump_loader_info(loader): |  | ||||||
|             info.append('       %s' % line) |  | ||||||
| 
 |  | ||||||
|         if triple is None: |  | ||||||
|             detail = 'no match' |  | ||||||
|         else: |  | ||||||
|             detail = 'found (%r)' % (triple[1] or '<string>') |  | ||||||
|             total_found += 1 |  | ||||||
|         info.append('       -> %s' % detail) |  | ||||||
| 
 |  | ||||||
|     seems_fishy = False |  | ||||||
|     if total_found == 0: |  | ||||||
|         info.append('Error: the template could not be found.') |  | ||||||
|         seems_fishy = True |  | ||||||
|     elif total_found > 1: |  | ||||||
|         info.append('Warning: multiple loaders returned a match for the template.') |  | ||||||
|         seems_fishy = True |  | ||||||
| 
 |  | ||||||
|     if blueprint is not None and seems_fishy: |  | ||||||
|         info.append('  The template was looked up from an endpoint that ' |  | ||||||
|                     'belongs to the blueprint "%s".' % blueprint) |  | ||||||
|         info.append('  Maybe you did not place a template in the right folder?') |  | ||||||
|         info.append('  See http://flask.pocoo.org/docs/blueprints/#templates') |  | ||||||
| 
 |  | ||||||
|     app.logger.info('\n'.join(info)) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def explain_ignored_app_run(): |  | ||||||
|     if os.environ.get('WERKZEUG_RUN_MAIN') != 'true': |  | ||||||
|         warn(Warning('Silently ignoring app.run() because the ' |  | ||||||
|                      'application is run from the flask command line ' |  | ||||||
|                      'executable.  Consider putting app.run() behind an ' |  | ||||||
|                      'if __name__ == "__main__" guard to silence this ' |  | ||||||
|                      'warning.'), stacklevel=3) |  | ||||||
| @ -1,61 +0,0 @@ | |||||||
| # -*- coding: utf-8 -*- |  | ||||||
| """ |  | ||||||
|     flask.globals |  | ||||||
|     ~~~~~~~~~~~~~ |  | ||||||
| 
 |  | ||||||
|     Defines all the global objects that are proxies to the current |  | ||||||
|     active context. |  | ||||||
| 
 |  | ||||||
|     :copyright: © 2010 by the Pallets team. |  | ||||||
|     :license: BSD, see LICENSE for more details. |  | ||||||
| """ |  | ||||||
| 
 |  | ||||||
| from functools import partial |  | ||||||
| from werkzeug.local import LocalStack, LocalProxy |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| _request_ctx_err_msg = '''\ |  | ||||||
| Working outside of request context. |  | ||||||
| 
 |  | ||||||
| This typically means that you attempted to use functionality that needed |  | ||||||
| an active HTTP request.  Consult the documentation on testing for |  | ||||||
| information about how to avoid this problem.\ |  | ||||||
| ''' |  | ||||||
| _app_ctx_err_msg = '''\ |  | ||||||
| Working outside of application context. |  | ||||||
| 
 |  | ||||||
| This typically means that you attempted to use functionality that needed |  | ||||||
| to interface with the current application object in some way. To solve |  | ||||||
| this, set up an application context with app.app_context().  See the |  | ||||||
| documentation for more information.\ |  | ||||||
| ''' |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def _lookup_req_object(name): |  | ||||||
|     top = _request_ctx_stack.top |  | ||||||
|     if top is None: |  | ||||||
|         raise RuntimeError(_request_ctx_err_msg) |  | ||||||
|     return getattr(top, name) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def _lookup_app_object(name): |  | ||||||
|     top = _app_ctx_stack.top |  | ||||||
|     if top is None: |  | ||||||
|         raise RuntimeError(_app_ctx_err_msg) |  | ||||||
|     return getattr(top, name) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def _find_app(): |  | ||||||
|     top = _app_ctx_stack.top |  | ||||||
|     if top is None: |  | ||||||
|         raise RuntimeError(_app_ctx_err_msg) |  | ||||||
|     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')) |  | ||||||
									
										
											File diff suppressed because it is too large
											Load Diff
										
									
								
							
						| @ -1,327 +0,0 @@ | |||||||
| # -*- coding: utf-8 -*- |  | ||||||
| """ |  | ||||||
| flask.json |  | ||||||
| ~~~~~~~~~~ |  | ||||||
| 
 |  | ||||||
| :copyright: © 2010 by the Pallets team. |  | ||||||
| :license: BSD, see LICENSE for more details. |  | ||||||
| """ |  | ||||||
| import codecs |  | ||||||
| import io |  | ||||||
| import uuid |  | ||||||
| from datetime import date, datetime |  | ||||||
| from flask.globals import current_app, request |  | ||||||
| from flask._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. |  | ||||||
| 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 :exc:`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.utctimetuple()) |  | ||||||
|         if isinstance(o, date): |  | ||||||
|             return http_date(o.timetuple()) |  | ||||||
|         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 decoder.  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: |  | ||||||
|         bp = current_app.blueprints.get(request.blueprint) if request else None |  | ||||||
|         kwargs.setdefault( |  | ||||||
|             'cls', |  | ||||||
|             bp.json_encoder if bp and bp.json_encoder |  | ||||||
|                 else 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: |  | ||||||
|         bp = current_app.blueprints.get(request.blueprint) if request else None |  | ||||||
|         kwargs.setdefault( |  | ||||||
|             'cls', |  | ||||||
|             bp.json_decoder if bp and bp.json_decoder |  | ||||||
|                 else current_app.json_decoder |  | ||||||
|         ) |  | ||||||
|     else: |  | ||||||
|         kwargs.setdefault('cls', JSONDecoder) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def detect_encoding(data): |  | ||||||
|     """Detect which UTF codec was used to encode the given bytes. |  | ||||||
| 
 |  | ||||||
|     The latest JSON standard (:rfc:`8259`) suggests that only UTF-8 is |  | ||||||
|     accepted. Older documents allowed 8, 16, or 32. 16 and 32 can be big |  | ||||||
|     or little endian. Some editors or libraries may prepend a BOM. |  | ||||||
| 
 |  | ||||||
|     :param data: Bytes in unknown UTF encoding. |  | ||||||
|     :return: UTF encoding name |  | ||||||
|     """ |  | ||||||
|     head = data[:4] |  | ||||||
| 
 |  | ||||||
|     if head[:3] == codecs.BOM_UTF8: |  | ||||||
|         return 'utf-8-sig' |  | ||||||
| 
 |  | ||||||
|     if b'\x00' not in head: |  | ||||||
|         return 'utf-8' |  | ||||||
| 
 |  | ||||||
|     if head in (codecs.BOM_UTF32_BE, codecs.BOM_UTF32_LE): |  | ||||||
|         return 'utf-32' |  | ||||||
| 
 |  | ||||||
|     if head[:2] in (codecs.BOM_UTF16_BE, codecs.BOM_UTF16_LE): |  | ||||||
|         return 'utf-16' |  | ||||||
| 
 |  | ||||||
|     if len(head) == 4: |  | ||||||
|         if head[:3] == b'\x00\x00\x00': |  | ||||||
|             return 'utf-32-be' |  | ||||||
| 
 |  | ||||||
|         if head[::2] == b'\x00\x00': |  | ||||||
|             return 'utf-16-be' |  | ||||||
| 
 |  | ||||||
|         if head[1:] == b'\x00\x00\x00': |  | ||||||
|             return 'utf-32-le' |  | ||||||
| 
 |  | ||||||
|         if head[1::2] == b'\x00\x00': |  | ||||||
|             return 'utf-16-le' |  | ||||||
| 
 |  | ||||||
|     if len(head) == 2: |  | ||||||
|         return 'utf-16-be' if head.startswith(b'\x00') else 'utf-16-le' |  | ||||||
| 
 |  | ||||||
|     return 'utf-8' |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 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 overridden 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): |  | ||||||
|         encoding = kwargs.pop('encoding', None) |  | ||||||
|         if encoding is None: |  | ||||||
|             encoding = detect_encoding(s) |  | ||||||
|         s = s.decode(encoding) |  | ||||||
|     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 ``<script>`` |  | ||||||
|     tags.  It accepts the same arguments and returns a JSON string.  Note that |  | ||||||
|     this is available in templates through the ``|tojson`` filter which will |  | ||||||
|     also mark the result as safe.  Due to how this function escapes certain |  | ||||||
|     characters this is safe even if used outside of ``<script>`` tags. |  | ||||||
| 
 |  | ||||||
|     The following characters are escaped in strings: |  | ||||||
| 
 |  | ||||||
|     -   ``<`` |  | ||||||
|     -   ``>`` |  | ||||||
|     -   ``&`` |  | ||||||
|     -   ``'`` |  | ||||||
| 
 |  | ||||||
|     This makes it safe to embed such strings in any place in HTML with the |  | ||||||
|     notable exception of double quoted attributes.  In that case single |  | ||||||
|     quote your attributes or HTML escape it in addition. |  | ||||||
| 
 |  | ||||||
|     .. versionchanged:: 0.10 |  | ||||||
|        This function's return value is now always safe for HTML usage, even |  | ||||||
|        if outside of script tags or if used in XHTML.  This rule does not |  | ||||||
|        hold true when using this function in HTML attributes that are double |  | ||||||
|        quoted.  Always single quote attributes if you use the ``|tojson`` |  | ||||||
|        filter.  Alternatively use ``|tojson|forceescape``. |  | ||||||
|     """ |  | ||||||
|     rv = dumps(obj, **kwargs) \ |  | ||||||
|         .replace(u'<', u'\\u003c') \ |  | ||||||
|         .replace(u'>', u'\\u003e') \ |  | ||||||
|         .replace(u'&', u'\\u0026') \ |  | ||||||
|         .replace(u"'", u'\\u0027') |  | ||||||
|     if not _slash_escape: |  | ||||||
|         rv = rv.replace('\\/', '/') |  | ||||||
|     return rv |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def htmlsafe_dump(obj, fp, **kwargs): |  | ||||||
|     """Like :func:`htmlsafe_dumps` but writes into a file object.""" |  | ||||||
|     fp.write(text_type(htmlsafe_dumps(obj, **kwargs))) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def jsonify(*args, **kwargs): |  | ||||||
|     """This function wraps :func:`dumps` to add a few enhancements that make |  | ||||||
|     life easier.  It turns the JSON output into a :class:`~flask.Response` |  | ||||||
|     object with the :mimetype:`application/json` mimetype.  For convenience, it |  | ||||||
|     also converts multiple arguments into an array or multiple keyword arguments |  | ||||||
|     into a dict.  This means that both ``jsonify(1,2,3)`` and |  | ||||||
|     ``jsonify([1,2,3])`` serialize to ``[1,2,3]``. |  | ||||||
| 
 |  | ||||||
|     For clarity, the JSON serialization behavior has the following differences |  | ||||||
|     from :func:`dumps`: |  | ||||||
| 
 |  | ||||||
|     1. Single argument: Passed straight through to :func:`dumps`. |  | ||||||
|     2. Multiple arguments: Converted to an array before being passed to |  | ||||||
|        :func:`dumps`. |  | ||||||
|     3. Multiple keyword arguments: Converted to a dict before being passed to |  | ||||||
|        :func:`dumps`. |  | ||||||
|     4. Both args and kwargs: Behavior undefined and will throw an exception. |  | ||||||
| 
 |  | ||||||
|     Example usage:: |  | ||||||
| 
 |  | ||||||
|         from flask import jsonify |  | ||||||
| 
 |  | ||||||
|         @app.route('/_get_current_user') |  | ||||||
|         def get_current_user(): |  | ||||||
|             return jsonify(username=g.user.username, |  | ||||||
|                            email=g.user.email, |  | ||||||
|                            id=g.user.id) |  | ||||||
| 
 |  | ||||||
|     This will send a JSON response like this to the browser:: |  | ||||||
| 
 |  | ||||||
|         { |  | ||||||
|             "username": "admin", |  | ||||||
|             "email": "admin@localhost", |  | ||||||
|             "id": 42 |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     .. versionchanged:: 0.11 |  | ||||||
|        Added support for serializing top-level arrays. This introduces a |  | ||||||
|        security risk in ancient browsers. See :ref:`json-security` for details. |  | ||||||
| 
 |  | ||||||
|     This function's response will be pretty printed if the |  | ||||||
|     ``JSONIFY_PRETTYPRINT_REGULAR`` config parameter is set to True or the |  | ||||||
|     Flask app is running in debug mode. Compressed (not pretty) formatting |  | ||||||
|     currently means no indents and no spaces after separators. |  | ||||||
| 
 |  | ||||||
|     .. versionadded:: 0.2 |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     indent = None |  | ||||||
|     separators = (',', ':') |  | ||||||
| 
 |  | ||||||
|     if current_app.config['JSONIFY_PRETTYPRINT_REGULAR'] or current_app.debug: |  | ||||||
|         indent = 2 |  | ||||||
|         separators = (', ', ': ') |  | ||||||
| 
 |  | ||||||
|     if args and kwargs: |  | ||||||
|         raise TypeError('jsonify() behavior undefined when passed both args and kwargs') |  | ||||||
|     elif len(args) == 1:  # single args are passed directly to dumps() |  | ||||||
|         data = args[0] |  | ||||||
|     else: |  | ||||||
|         data = args or kwargs |  | ||||||
| 
 |  | ||||||
|     return current_app.response_class( |  | ||||||
|         dumps(data, indent=indent, separators=separators) + '\n', |  | ||||||
|         mimetype=current_app.config['JSONIFY_MIMETYPE'] |  | ||||||
|     ) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def tojson_filter(obj, **kwargs): |  | ||||||
|     return Markup(htmlsafe_dumps(obj, **kwargs)) |  | ||||||
| @ -1,300 +0,0 @@ | |||||||
| # -*- coding: utf-8 -*- |  | ||||||
| """ |  | ||||||
| Tagged JSON |  | ||||||
| ~~~~~~~~~~~ |  | ||||||
| 
 |  | ||||||
| A compact representation for lossless serialization of non-standard JSON types. |  | ||||||
| :class:`~flask.sessions.SecureCookieSessionInterface` uses this to serialize |  | ||||||
| the session data, but it may be useful in other places. It can be extended to |  | ||||||
| support other types. |  | ||||||
| 
 |  | ||||||
| .. autoclass:: TaggedJSONSerializer |  | ||||||
|     :members: |  | ||||||
| 
 |  | ||||||
| .. autoclass:: JSONTag |  | ||||||
|     :members: |  | ||||||
| 
 |  | ||||||
| Let's seen an example that adds support for :class:`~collections.OrderedDict`. |  | ||||||
| Dicts don't have an order in Python or JSON, so to handle this we will dump |  | ||||||
| the items as a list of ``[key, value]`` pairs. Subclass :class:`JSONTag` and |  | ||||||
| give it the new key ``' od'`` to identify the type. The session serializer |  | ||||||
| processes dicts first, so insert the new tag at the front of the order since |  | ||||||
| ``OrderedDict`` must be processed before ``dict``. :: |  | ||||||
| 
 |  | ||||||
|     from flask.json.tag import JSONTag |  | ||||||
| 
 |  | ||||||
|     class TagOrderedDict(JSONTag): |  | ||||||
|         __slots__ = ('serializer',) |  | ||||||
|         key = ' od' |  | ||||||
| 
 |  | ||||||
|         def check(self, value): |  | ||||||
|             return isinstance(value, OrderedDict) |  | ||||||
| 
 |  | ||||||
|         def to_json(self, value): |  | ||||||
|             return [[k, self.serializer.tag(v)] for k, v in iteritems(value)] |  | ||||||
| 
 |  | ||||||
|         def to_python(self, value): |  | ||||||
|             return OrderedDict(value) |  | ||||||
| 
 |  | ||||||
|     app.session_interface.serializer.register(TagOrderedDict, index=0) |  | ||||||
| 
 |  | ||||||
| :copyright: © 2010 by the Pallets team. |  | ||||||
| :license: BSD, see LICENSE for more details. |  | ||||||
| """ |  | ||||||
| 
 |  | ||||||
| from base64 import b64decode, b64encode |  | ||||||
| from datetime import datetime |  | ||||||
| from uuid import UUID |  | ||||||
| 
 |  | ||||||
| from jinja2 import Markup |  | ||||||
| from werkzeug.http import http_date, parse_date |  | ||||||
| 
 |  | ||||||
| from flask._compat import iteritems, text_type |  | ||||||
| from flask.json import dumps, loads |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class JSONTag(object): |  | ||||||
|     """Base class for defining type tags for :class:`TaggedJSONSerializer`.""" |  | ||||||
| 
 |  | ||||||
|     __slots__ = ('serializer',) |  | ||||||
| 
 |  | ||||||
|     #: The tag to mark the serialized object with. If ``None``, this tag is |  | ||||||
|     #: only used as an intermediate step during tagging. |  | ||||||
|     key = None |  | ||||||
| 
 |  | ||||||
|     def __init__(self, serializer): |  | ||||||
|         """Create a tagger for the given serializer.""" |  | ||||||
|         self.serializer = serializer |  | ||||||
| 
 |  | ||||||
|     def check(self, value): |  | ||||||
|         """Check if the given value should be tagged by this tag.""" |  | ||||||
|         raise NotImplementedError |  | ||||||
| 
 |  | ||||||
|     def to_json(self, value): |  | ||||||
|         """Convert the Python object to an object that is a valid JSON type. |  | ||||||
|         The tag will be added later.""" |  | ||||||
|         raise NotImplementedError |  | ||||||
| 
 |  | ||||||
|     def to_python(self, value): |  | ||||||
|         """Convert the JSON representation back to the correct type. The tag |  | ||||||
|         will already be removed.""" |  | ||||||
|         raise NotImplementedError |  | ||||||
| 
 |  | ||||||
|     def tag(self, value): |  | ||||||
|         """Convert the value to a valid JSON type and add the tag structure |  | ||||||
|         around it.""" |  | ||||||
|         return {self.key: self.to_json(value)} |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class TagDict(JSONTag): |  | ||||||
|     """Tag for 1-item dicts whose only key matches a registered tag. |  | ||||||
| 
 |  | ||||||
|     Internally, the dict key is suffixed with `__`, and the suffix is removed |  | ||||||
|     when deserializing. |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     __slots__ = () |  | ||||||
|     key = ' di' |  | ||||||
| 
 |  | ||||||
|     def check(self, value): |  | ||||||
|         return ( |  | ||||||
|             isinstance(value, dict) |  | ||||||
|             and len(value) == 1 |  | ||||||
|             and next(iter(value)) in self.serializer.tags |  | ||||||
|         ) |  | ||||||
| 
 |  | ||||||
|     def to_json(self, value): |  | ||||||
|         key = next(iter(value)) |  | ||||||
|         return {key + '__': self.serializer.tag(value[key])} |  | ||||||
| 
 |  | ||||||
|     def to_python(self, value): |  | ||||||
|         key = next(iter(value)) |  | ||||||
|         return {key[:-2]: value[key]} |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class PassDict(JSONTag): |  | ||||||
|     __slots__ = () |  | ||||||
| 
 |  | ||||||
|     def check(self, value): |  | ||||||
|         return isinstance(value, dict) |  | ||||||
| 
 |  | ||||||
|     def to_json(self, value): |  | ||||||
|         # JSON objects may only have string keys, so don't bother tagging the |  | ||||||
|         # key here. |  | ||||||
|         return dict((k, self.serializer.tag(v)) for k, v in iteritems(value)) |  | ||||||
| 
 |  | ||||||
|     tag = to_json |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class TagTuple(JSONTag): |  | ||||||
|     __slots__ = () |  | ||||||
|     key = ' t' |  | ||||||
| 
 |  | ||||||
|     def check(self, value): |  | ||||||
|         return isinstance(value, tuple) |  | ||||||
| 
 |  | ||||||
|     def to_json(self, value): |  | ||||||
|         return [self.serializer.tag(item) for item in value] |  | ||||||
| 
 |  | ||||||
|     def to_python(self, value): |  | ||||||
|         return tuple(value) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class PassList(JSONTag): |  | ||||||
|     __slots__ = () |  | ||||||
| 
 |  | ||||||
|     def check(self, value): |  | ||||||
|         return isinstance(value, list) |  | ||||||
| 
 |  | ||||||
|     def to_json(self, value): |  | ||||||
|         return [self.serializer.tag(item) for item in value] |  | ||||||
| 
 |  | ||||||
|     tag = to_json |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class TagBytes(JSONTag): |  | ||||||
|     __slots__ = () |  | ||||||
|     key = ' b' |  | ||||||
| 
 |  | ||||||
|     def check(self, value): |  | ||||||
|         return isinstance(value, bytes) |  | ||||||
| 
 |  | ||||||
|     def to_json(self, value): |  | ||||||
|         return b64encode(value).decode('ascii') |  | ||||||
| 
 |  | ||||||
|     def to_python(self, value): |  | ||||||
|         return b64decode(value) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class TagMarkup(JSONTag): |  | ||||||
|     """Serialize anything matching the :class:`~flask.Markup` API by |  | ||||||
|     having a ``__html__`` method to the result of that method. Always |  | ||||||
|     deserializes to an instance of :class:`~flask.Markup`.""" |  | ||||||
| 
 |  | ||||||
|     __slots__ = () |  | ||||||
|     key = ' m' |  | ||||||
| 
 |  | ||||||
|     def check(self, value): |  | ||||||
|         return callable(getattr(value, '__html__', None)) |  | ||||||
| 
 |  | ||||||
|     def to_json(self, value): |  | ||||||
|         return text_type(value.__html__()) |  | ||||||
| 
 |  | ||||||
|     def to_python(self, value): |  | ||||||
|         return Markup(value) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class TagUUID(JSONTag): |  | ||||||
|     __slots__ = () |  | ||||||
|     key = ' u' |  | ||||||
| 
 |  | ||||||
|     def check(self, value): |  | ||||||
|         return isinstance(value, UUID) |  | ||||||
| 
 |  | ||||||
|     def to_json(self, value): |  | ||||||
|         return value.hex |  | ||||||
| 
 |  | ||||||
|     def to_python(self, value): |  | ||||||
|         return UUID(value) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class TagDateTime(JSONTag): |  | ||||||
|     __slots__ = () |  | ||||||
|     key = ' d' |  | ||||||
| 
 |  | ||||||
|     def check(self, value): |  | ||||||
|         return isinstance(value, datetime) |  | ||||||
| 
 |  | ||||||
|     def to_json(self, value): |  | ||||||
|         return http_date(value) |  | ||||||
| 
 |  | ||||||
|     def to_python(self, value): |  | ||||||
|         return parse_date(value) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class TaggedJSONSerializer(object): |  | ||||||
|     """Serializer that uses a tag system to compactly represent objects that |  | ||||||
|     are not JSON types. Passed as the intermediate serializer to |  | ||||||
|     :class:`itsdangerous.Serializer`. |  | ||||||
| 
 |  | ||||||
|     The following extra types are supported: |  | ||||||
| 
 |  | ||||||
|     * :class:`dict` |  | ||||||
|     * :class:`tuple` |  | ||||||
|     * :class:`bytes` |  | ||||||
|     * :class:`~flask.Markup` |  | ||||||
|     * :class:`~uuid.UUID` |  | ||||||
|     * :class:`~datetime.datetime` |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     __slots__ = ('tags', 'order') |  | ||||||
| 
 |  | ||||||
|     #: Tag classes to bind when creating the serializer. Other tags can be |  | ||||||
|     #: added later using :meth:`~register`. |  | ||||||
|     default_tags = [ |  | ||||||
|         TagDict, PassDict, TagTuple, PassList, TagBytes, TagMarkup, TagUUID, |  | ||||||
|         TagDateTime, |  | ||||||
|     ] |  | ||||||
| 
 |  | ||||||
|     def __init__(self): |  | ||||||
|         self.tags = {} |  | ||||||
|         self.order = [] |  | ||||||
| 
 |  | ||||||
|         for cls in self.default_tags: |  | ||||||
|             self.register(cls) |  | ||||||
| 
 |  | ||||||
|     def register(self, tag_class, force=False, index=None): |  | ||||||
|         """Register a new tag with this serializer. |  | ||||||
| 
 |  | ||||||
|         :param tag_class: tag class to register. Will be instantiated with this |  | ||||||
|             serializer instance. |  | ||||||
|         :param force: overwrite an existing tag. If false (default), a |  | ||||||
|             :exc:`KeyError` is raised. |  | ||||||
|         :param index: index to insert the new tag in the tag order. Useful when |  | ||||||
|             the new tag is a special case of an existing tag. If ``None`` |  | ||||||
|             (default), the tag is appended to the end of the order. |  | ||||||
| 
 |  | ||||||
|         :raise KeyError: if the tag key is already registered and ``force`` is |  | ||||||
|             not true. |  | ||||||
|         """ |  | ||||||
|         tag = tag_class(self) |  | ||||||
|         key = tag.key |  | ||||||
| 
 |  | ||||||
|         if key is not None: |  | ||||||
|             if not force and key in self.tags: |  | ||||||
|                 raise KeyError("Tag '{0}' is already registered.".format(key)) |  | ||||||
| 
 |  | ||||||
|             self.tags[key] = tag |  | ||||||
| 
 |  | ||||||
|         if index is None: |  | ||||||
|             self.order.append(tag) |  | ||||||
|         else: |  | ||||||
|             self.order.insert(index, tag) |  | ||||||
| 
 |  | ||||||
|     def tag(self, value): |  | ||||||
|         """Convert a value to a tagged representation if necessary.""" |  | ||||||
|         for tag in self.order: |  | ||||||
|             if tag.check(value): |  | ||||||
|                 return tag.tag(value) |  | ||||||
| 
 |  | ||||||
|         return value |  | ||||||
| 
 |  | ||||||
|     def untag(self, value): |  | ||||||
|         """Convert a tagged representation back to the original type.""" |  | ||||||
|         if len(value) != 1: |  | ||||||
|             return value |  | ||||||
| 
 |  | ||||||
|         key = next(iter(value)) |  | ||||||
| 
 |  | ||||||
|         if key not in self.tags: |  | ||||||
|             return value |  | ||||||
| 
 |  | ||||||
|         return self.tags[key].to_python(value[key]) |  | ||||||
| 
 |  | ||||||
|     def dumps(self, value): |  | ||||||
|         """Tag the value and dump it to a compact JSON string.""" |  | ||||||
|         return dumps(self.tag(value), separators=(',', ':')) |  | ||||||
| 
 |  | ||||||
|     def loads(self, value): |  | ||||||
|         """Load data from a JSON string and deserialized any tagged objects.""" |  | ||||||
|         return loads(value, object_hook=self.untag) |  | ||||||
| @ -1,78 +0,0 @@ | |||||||
| # -*- coding: utf-8 -*- |  | ||||||
| """ |  | ||||||
| flask.logging |  | ||||||
| ~~~~~~~~~~~~~ |  | ||||||
| 
 |  | ||||||
| :copyright: © 2010 by the Pallets team. |  | ||||||
| :license: BSD, see LICENSE for more details. |  | ||||||
| """ |  | ||||||
| 
 |  | ||||||
| from __future__ import absolute_import |  | ||||||
| 
 |  | ||||||
| import logging |  | ||||||
| import sys |  | ||||||
| 
 |  | ||||||
| from werkzeug.local import LocalProxy |  | ||||||
| 
 |  | ||||||
| from .globals import request |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| @LocalProxy |  | ||||||
| def wsgi_errors_stream(): |  | ||||||
|     """Find the most appropriate error stream for the application. If a request |  | ||||||
|     is active, log to ``wsgi.errors``, otherwise use ``sys.stderr``. |  | ||||||
| 
 |  | ||||||
|     If you configure your own :class:`logging.StreamHandler`, you may want to |  | ||||||
|     use this for the stream. If you are using file or dict configuration and |  | ||||||
|     can't import this directly, you can refer to it as |  | ||||||
|     ``ext://flask.logging.wsgi_errors_stream``. |  | ||||||
|     """ |  | ||||||
|     return request.environ['wsgi.errors'] if request else sys.stderr |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def has_level_handler(logger): |  | ||||||
|     """Check if there is a handler in the logging chain that will handle the |  | ||||||
|     given logger's :meth:`effective level <~logging.Logger.getEffectiveLevel>`. |  | ||||||
|     """ |  | ||||||
|     level = logger.getEffectiveLevel() |  | ||||||
|     current = logger |  | ||||||
| 
 |  | ||||||
|     while current: |  | ||||||
|         if any(handler.level <= level for handler in current.handlers): |  | ||||||
|             return True |  | ||||||
| 
 |  | ||||||
|         if not current.propagate: |  | ||||||
|             break |  | ||||||
| 
 |  | ||||||
|         current = current.parent |  | ||||||
| 
 |  | ||||||
|     return False |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| #: Log messages to :func:`~flask.logging.wsgi_errors_stream` with the format |  | ||||||
| #: ``[%(asctime)s] %(levelname)s in %(module)s: %(message)s``. |  | ||||||
| default_handler = logging.StreamHandler(wsgi_errors_stream) |  | ||||||
| default_handler.setFormatter(logging.Formatter( |  | ||||||
|     '[%(asctime)s] %(levelname)s in %(module)s: %(message)s' |  | ||||||
| )) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def create_logger(app): |  | ||||||
|     """Get the ``'flask.app'`` logger and configure it if needed. |  | ||||||
| 
 |  | ||||||
|     When :attr:`~flask.Flask.debug` is enabled, set the logger level to |  | ||||||
|     :data:`logging.DEBUG` if it is not set. |  | ||||||
| 
 |  | ||||||
|     If there is no handler for the logger's effective level, add a |  | ||||||
|     :class:`~logging.StreamHandler` for |  | ||||||
|     :func:`~flask.logging.wsgi_errors_stream` with a basic format. |  | ||||||
|     """ |  | ||||||
|     logger = logging.getLogger('flask.app') |  | ||||||
| 
 |  | ||||||
|     if app.debug and logger.level == logging.NOTSET: |  | ||||||
|         logger.setLevel(logging.DEBUG) |  | ||||||
| 
 |  | ||||||
|     if not has_level_handler(logger): |  | ||||||
|         logger.addHandler(default_handler) |  | ||||||
| 
 |  | ||||||
|     return logger |  | ||||||
| @ -1,385 +0,0 @@ | |||||||
| # -*- coding: utf-8 -*- |  | ||||||
| """ |  | ||||||
|     flask.sessions |  | ||||||
|     ~~~~~~~~~~~~~~ |  | ||||||
| 
 |  | ||||||
|     Implements cookie based sessions based on itsdangerous. |  | ||||||
| 
 |  | ||||||
|     :copyright: © 2010 by the Pallets team. |  | ||||||
|     :license: BSD, see LICENSE for more details. |  | ||||||
| """ |  | ||||||
| 
 |  | ||||||
| import hashlib |  | ||||||
| import warnings |  | ||||||
| from collections import MutableMapping |  | ||||||
| from datetime import datetime |  | ||||||
| 
 |  | ||||||
| from itsdangerous import BadSignature, URLSafeTimedSerializer |  | ||||||
| from werkzeug.datastructures import CallbackDict |  | ||||||
| 
 |  | ||||||
| from flask.helpers import is_ip, total_seconds |  | ||||||
| from flask.json.tag import TaggedJSONSerializer |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class SessionMixin(MutableMapping): |  | ||||||
|     """Expands a basic dictionary with session attributes.""" |  | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def permanent(self): |  | ||||||
|         """This reflects the ``'_permanent'`` key in the dict.""" |  | ||||||
|         return self.get('_permanent', False) |  | ||||||
| 
 |  | ||||||
|     @permanent.setter |  | ||||||
|     def permanent(self, value): |  | ||||||
|         self['_permanent'] = bool(value) |  | ||||||
| 
 |  | ||||||
|     #: Some implementations can detect whether a session is newly |  | ||||||
|     #: created, but that is not guaranteed. Use with caution. The mixin |  | ||||||
|     # default is hard-coded ``False``. |  | ||||||
|     new = False |  | ||||||
| 
 |  | ||||||
|     #: Some implementations can detect changes to the session and set |  | ||||||
|     #: this when that happens. The mixin default is hard coded to |  | ||||||
|     #: ``True``. |  | ||||||
|     modified = True |  | ||||||
| 
 |  | ||||||
|     #: Some implementations can detect when session data is read or |  | ||||||
|     #: written and set this when that happens. The mixin default is hard |  | ||||||
|     #: coded to ``True``. |  | ||||||
|     accessed = True |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class SecureCookieSession(CallbackDict, SessionMixin): |  | ||||||
|     """Base class for sessions based on signed cookies. |  | ||||||
| 
 |  | ||||||
|     This session backend will set the :attr:`modified` and |  | ||||||
|     :attr:`accessed` attributes. It cannot reliably track whether a |  | ||||||
|     session is new (vs. empty), so :attr:`new` remains hard coded to |  | ||||||
|     ``False``. |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     #: When data is changed, this is set to ``True``. Only the session |  | ||||||
|     #: dictionary itself is tracked; if the session contains mutable |  | ||||||
|     #: data (for example a nested dict) then this must be set to |  | ||||||
|     #: ``True`` manually when modifying that data. The session cookie |  | ||||||
|     #: will only be written to the response if this is ``True``. |  | ||||||
|     modified = False |  | ||||||
| 
 |  | ||||||
|     #: When data is read or written, this is set to ``True``. Used by |  | ||||||
|     # :class:`.SecureCookieSessionInterface` to add a ``Vary: Cookie`` |  | ||||||
|     #: header, which allows caching proxies to cache different pages for |  | ||||||
|     #: different users. |  | ||||||
|     accessed = False |  | ||||||
| 
 |  | ||||||
|     def __init__(self, initial=None): |  | ||||||
|         def on_update(self): |  | ||||||
|             self.modified = True |  | ||||||
|             self.accessed = True |  | ||||||
| 
 |  | ||||||
|         super(SecureCookieSession, self).__init__(initial, on_update) |  | ||||||
| 
 |  | ||||||
|     def __getitem__(self, key): |  | ||||||
|         self.accessed = True |  | ||||||
|         return super(SecureCookieSession, self).__getitem__(key) |  | ||||||
| 
 |  | ||||||
|     def get(self, key, default=None): |  | ||||||
|         self.accessed = True |  | ||||||
|         return super(SecureCookieSession, self).get(key, default) |  | ||||||
| 
 |  | ||||||
|     def setdefault(self, key, default=None): |  | ||||||
|         self.accessed = True |  | ||||||
|         return super(SecureCookieSession, self).setdefault(key, default) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class NullSession(SecureCookieSession): |  | ||||||
|     """Class used to generate nicer error messages if sessions are not |  | ||||||
|     available.  Will still allow read-only access to the empty session |  | ||||||
|     but fail on setting. |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     def _fail(self, *args, **kwargs): |  | ||||||
|         raise RuntimeError('The session is unavailable because no secret ' |  | ||||||
|                            'key was set.  Set the secret_key on the ' |  | ||||||
|                            'application to something unique and secret.') |  | ||||||
|     __setitem__ = __delitem__ = clear = pop = popitem = \ |  | ||||||
|         update = setdefault = _fail |  | ||||||
|     del _fail |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class SessionInterface(object): |  | ||||||
|     """The basic interface you have to implement in order to replace the |  | ||||||
|     default session interface which uses werkzeug's securecookie |  | ||||||
|     implementation.  The only methods you have to implement are |  | ||||||
|     :meth:`open_session` and :meth:`save_session`, the others have |  | ||||||
|     useful defaults which you don't need to change. |  | ||||||
| 
 |  | ||||||
|     The session object returned by the :meth:`open_session` method has to |  | ||||||
|     provide a dictionary like interface plus the properties and methods |  | ||||||
|     from the :class:`SessionMixin`.  We recommend just subclassing a dict |  | ||||||
|     and adding that mixin:: |  | ||||||
| 
 |  | ||||||
|         class Session(dict, SessionMixin): |  | ||||||
|             pass |  | ||||||
| 
 |  | ||||||
|     If :meth:`open_session` returns ``None`` Flask will call into |  | ||||||
|     :meth:`make_null_session` to create a session that acts as replacement |  | ||||||
|     if the session support cannot work because some requirement is not |  | ||||||
|     fulfilled.  The default :class:`NullSession` class that is created |  | ||||||
|     will complain that the secret key was not set. |  | ||||||
| 
 |  | ||||||
|     To replace the session interface on an application all you have to do |  | ||||||
|     is to assign :attr:`flask.Flask.session_interface`:: |  | ||||||
| 
 |  | ||||||
|         app = Flask(__name__) |  | ||||||
|         app.session_interface = MySessionInterface() |  | ||||||
| 
 |  | ||||||
|     .. versionadded:: 0.8 |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     #: :meth:`make_null_session` will look here for the class that should |  | ||||||
|     #: be created when a null session is requested.  Likewise the |  | ||||||
|     #: :meth:`is_null_session` method will perform a typecheck against |  | ||||||
|     #: this type. |  | ||||||
|     null_session_class = NullSession |  | ||||||
| 
 |  | ||||||
|     #: A flag that indicates if the session interface is pickle based. |  | ||||||
|     #: This can be used by Flask extensions to make a decision in regards |  | ||||||
|     #: to how to deal with the session object. |  | ||||||
|     #: |  | ||||||
|     #: .. versionadded:: 0.10 |  | ||||||
|     pickle_based = False |  | ||||||
| 
 |  | ||||||
|     def make_null_session(self, app): |  | ||||||
|         """Creates a null session which acts as a replacement object if the |  | ||||||
|         real session support could not be loaded due to a configuration |  | ||||||
|         error.  This mainly aids the user experience because the job of the |  | ||||||
|         null session is to still support lookup without complaining but |  | ||||||
|         modifications are answered with a helpful error message of what |  | ||||||
|         failed. |  | ||||||
| 
 |  | ||||||
|         This creates an instance of :attr:`null_session_class` by default. |  | ||||||
|         """ |  | ||||||
|         return self.null_session_class() |  | ||||||
| 
 |  | ||||||
|     def is_null_session(self, obj): |  | ||||||
|         """Checks if a given object is a null session.  Null sessions are |  | ||||||
|         not asked to be saved. |  | ||||||
| 
 |  | ||||||
|         This checks if the object is an instance of :attr:`null_session_class` |  | ||||||
|         by default. |  | ||||||
|         """ |  | ||||||
|         return isinstance(obj, self.null_session_class) |  | ||||||
| 
 |  | ||||||
|     def get_cookie_domain(self, app): |  | ||||||
|         """Returns the domain that should be set for the session cookie. |  | ||||||
| 
 |  | ||||||
|         Uses ``SESSION_COOKIE_DOMAIN`` if it is configured, otherwise |  | ||||||
|         falls back to detecting the domain based on ``SERVER_NAME``. |  | ||||||
| 
 |  | ||||||
|         Once detected (or if not set at all), ``SESSION_COOKIE_DOMAIN`` is |  | ||||||
|         updated to avoid re-running the logic. |  | ||||||
|         """ |  | ||||||
| 
 |  | ||||||
|         rv = app.config['SESSION_COOKIE_DOMAIN'] |  | ||||||
| 
 |  | ||||||
|         # set explicitly, or cached from SERVER_NAME detection |  | ||||||
|         # if False, return None |  | ||||||
|         if rv is not None: |  | ||||||
|             return rv if rv else None |  | ||||||
| 
 |  | ||||||
|         rv = app.config['SERVER_NAME'] |  | ||||||
| 
 |  | ||||||
|         # server name not set, cache False to return none next time |  | ||||||
|         if not rv: |  | ||||||
|             app.config['SESSION_COOKIE_DOMAIN'] = False |  | ||||||
|             return None |  | ||||||
| 
 |  | ||||||
|         # chop off the port which is usually not supported by browsers |  | ||||||
|         # remove any leading '.' since we'll add that later |  | ||||||
|         rv = rv.rsplit(':', 1)[0].lstrip('.') |  | ||||||
| 
 |  | ||||||
|         if '.' not in rv: |  | ||||||
|             # Chrome doesn't allow names without a '.' |  | ||||||
|             # this should only come up with localhost |  | ||||||
|             # hack around this by not setting the name, and show a warning |  | ||||||
|             warnings.warn( |  | ||||||
|                 '"{rv}" is not a valid cookie domain, it must contain a ".".' |  | ||||||
|                 ' Add an entry to your hosts file, for example' |  | ||||||
|                 ' "{rv}.localdomain", and use that instead.'.format(rv=rv) |  | ||||||
|             ) |  | ||||||
|             app.config['SESSION_COOKIE_DOMAIN'] = False |  | ||||||
|             return None |  | ||||||
| 
 |  | ||||||
|         ip = is_ip(rv) |  | ||||||
| 
 |  | ||||||
|         if ip: |  | ||||||
|             warnings.warn( |  | ||||||
|                 'The session cookie domain is an IP address. This may not work' |  | ||||||
|                 ' as intended in some browsers. Add an entry to your hosts' |  | ||||||
|                 ' file, for example "localhost.localdomain", and use that' |  | ||||||
|                 ' instead.' |  | ||||||
|             ) |  | ||||||
| 
 |  | ||||||
|         # if this is not an ip and app is mounted at the root, allow subdomain |  | ||||||
|         # matching by adding a '.' prefix |  | ||||||
|         if self.get_cookie_path(app) == '/' and not ip: |  | ||||||
|             rv = '.' + rv |  | ||||||
| 
 |  | ||||||
|         app.config['SESSION_COOKIE_DOMAIN'] = rv |  | ||||||
|         return rv |  | ||||||
| 
 |  | ||||||
|     def get_cookie_path(self, app): |  | ||||||
|         """Returns the path for which the cookie should be valid.  The |  | ||||||
|         default implementation uses the value from the ``SESSION_COOKIE_PATH`` |  | ||||||
|         config var if it's set, and falls back to ``APPLICATION_ROOT`` or |  | ||||||
|         uses ``/`` if it's ``None``. |  | ||||||
|         """ |  | ||||||
|         return app.config['SESSION_COOKIE_PATH'] \ |  | ||||||
|                or app.config['APPLICATION_ROOT'] |  | ||||||
| 
 |  | ||||||
|     def get_cookie_httponly(self, app): |  | ||||||
|         """Returns True if the session cookie should be httponly.  This |  | ||||||
|         currently just returns the value of the ``SESSION_COOKIE_HTTPONLY`` |  | ||||||
|         config var. |  | ||||||
|         """ |  | ||||||
|         return app.config['SESSION_COOKIE_HTTPONLY'] |  | ||||||
| 
 |  | ||||||
|     def get_cookie_secure(self, app): |  | ||||||
|         """Returns True if the cookie should be secure.  This currently |  | ||||||
|         just returns the value of the ``SESSION_COOKIE_SECURE`` setting. |  | ||||||
|         """ |  | ||||||
|         return app.config['SESSION_COOKIE_SECURE'] |  | ||||||
| 
 |  | ||||||
|     def get_cookie_samesite(self, app): |  | ||||||
|         """Return ``'Strict'`` or ``'Lax'`` if the cookie should use the |  | ||||||
|         ``SameSite`` attribute. This currently just returns the value of |  | ||||||
|         the :data:`SESSION_COOKIE_SAMESITE` setting. |  | ||||||
|         """ |  | ||||||
|         return app.config['SESSION_COOKIE_SAMESITE'] |  | ||||||
| 
 |  | ||||||
|     def get_expiration_time(self, app, session): |  | ||||||
|         """A helper method that returns an expiration date for the session |  | ||||||
|         or ``None`` if the session is linked to the browser session.  The |  | ||||||
|         default implementation returns now + the permanent session |  | ||||||
|         lifetime configured on the application. |  | ||||||
|         """ |  | ||||||
|         if session.permanent: |  | ||||||
|             return datetime.utcnow() + app.permanent_session_lifetime |  | ||||||
| 
 |  | ||||||
|     def should_set_cookie(self, app, session): |  | ||||||
|         """Used by session backends to determine if a ``Set-Cookie`` header |  | ||||||
|         should be set for this session cookie for this response. If the session |  | ||||||
|         has been modified, the cookie is set. If the session is permanent and |  | ||||||
|         the ``SESSION_REFRESH_EACH_REQUEST`` config is true, the cookie is |  | ||||||
|         always set. |  | ||||||
| 
 |  | ||||||
|         This check is usually skipped if the session was deleted. |  | ||||||
| 
 |  | ||||||
|         .. versionadded:: 0.11 |  | ||||||
|         """ |  | ||||||
| 
 |  | ||||||
|         return session.modified or ( |  | ||||||
|             session.permanent and app.config['SESSION_REFRESH_EACH_REQUEST'] |  | ||||||
|         ) |  | ||||||
| 
 |  | ||||||
|     def open_session(self, app, request): |  | ||||||
|         """This method has to be implemented and must either return ``None`` |  | ||||||
|         in case the loading failed because of a configuration error or an |  | ||||||
|         instance of a session object which implements a dictionary like |  | ||||||
|         interface + the methods and attributes on :class:`SessionMixin`. |  | ||||||
|         """ |  | ||||||
|         raise NotImplementedError() |  | ||||||
| 
 |  | ||||||
|     def save_session(self, app, session, response): |  | ||||||
|         """This is called for actual sessions returned by :meth:`open_session` |  | ||||||
|         at the end of the request.  This is still called during a request |  | ||||||
|         context so if you absolutely need access to the request you can do |  | ||||||
|         that. |  | ||||||
|         """ |  | ||||||
|         raise NotImplementedError() |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| session_json_serializer = TaggedJSONSerializer() |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class SecureCookieSessionInterface(SessionInterface): |  | ||||||
|     """The default session interface that stores sessions in signed cookies |  | ||||||
|     through the :mod:`itsdangerous` module. |  | ||||||
|     """ |  | ||||||
|     #: the salt that should be applied on top of the secret key for the |  | ||||||
|     #: signing of cookie based sessions. |  | ||||||
|     salt = 'cookie-session' |  | ||||||
|     #: the hash function to use for the signature.  The default is sha1 |  | ||||||
|     digest_method = staticmethod(hashlib.sha1) |  | ||||||
|     #: the name of the itsdangerous supported key derivation.  The default |  | ||||||
|     #: is hmac. |  | ||||||
|     key_derivation = 'hmac' |  | ||||||
|     #: A python serializer for the payload.  The default is a compact |  | ||||||
|     #: JSON derived serializer with support for some extra Python types |  | ||||||
|     #: such as datetime objects or tuples. |  | ||||||
|     serializer = session_json_serializer |  | ||||||
|     session_class = SecureCookieSession |  | ||||||
| 
 |  | ||||||
|     def get_signing_serializer(self, app): |  | ||||||
|         if not app.secret_key: |  | ||||||
|             return None |  | ||||||
|         signer_kwargs = dict( |  | ||||||
|             key_derivation=self.key_derivation, |  | ||||||
|             digest_method=self.digest_method |  | ||||||
|         ) |  | ||||||
|         return URLSafeTimedSerializer(app.secret_key, salt=self.salt, |  | ||||||
|                                       serializer=self.serializer, |  | ||||||
|                                       signer_kwargs=signer_kwargs) |  | ||||||
| 
 |  | ||||||
|     def open_session(self, app, request): |  | ||||||
|         s = self.get_signing_serializer(app) |  | ||||||
|         if s is None: |  | ||||||
|             return None |  | ||||||
|         val = request.cookies.get(app.session_cookie_name) |  | ||||||
|         if not val: |  | ||||||
|             return self.session_class() |  | ||||||
|         max_age = total_seconds(app.permanent_session_lifetime) |  | ||||||
|         try: |  | ||||||
|             data = s.loads(val, max_age=max_age) |  | ||||||
|             return self.session_class(data) |  | ||||||
|         except BadSignature: |  | ||||||
|             return self.session_class() |  | ||||||
| 
 |  | ||||||
|     def save_session(self, app, session, response): |  | ||||||
|         domain = self.get_cookie_domain(app) |  | ||||||
|         path = self.get_cookie_path(app) |  | ||||||
| 
 |  | ||||||
|         # If the session is modified to be empty, remove the cookie. |  | ||||||
|         # If the session is empty, return without setting the cookie. |  | ||||||
|         if not session: |  | ||||||
|             if session.modified: |  | ||||||
|                 response.delete_cookie( |  | ||||||
|                     app.session_cookie_name, |  | ||||||
|                     domain=domain, |  | ||||||
|                     path=path |  | ||||||
|                 ) |  | ||||||
| 
 |  | ||||||
|             return |  | ||||||
| 
 |  | ||||||
|         # Add a "Vary: Cookie" header if the session was accessed at all. |  | ||||||
|         if session.accessed: |  | ||||||
|             response.vary.add('Cookie') |  | ||||||
| 
 |  | ||||||
|         if not self.should_set_cookie(app, session): |  | ||||||
|             return |  | ||||||
| 
 |  | ||||||
|         httponly = self.get_cookie_httponly(app) |  | ||||||
|         secure = self.get_cookie_secure(app) |  | ||||||
|         samesite = self.get_cookie_samesite(app) |  | ||||||
|         expires = self.get_expiration_time(app, session) |  | ||||||
|         val = self.get_signing_serializer(app).dumps(dict(session)) |  | ||||||
|         response.set_cookie( |  | ||||||
|             app.session_cookie_name, |  | ||||||
|             val, |  | ||||||
|             expires=expires, |  | ||||||
|             httponly=httponly, |  | ||||||
|             domain=domain, |  | ||||||
|             path=path, |  | ||||||
|             secure=secure, |  | ||||||
|             samesite=samesite |  | ||||||
|         ) |  | ||||||
| @ -1,57 +0,0 @@ | |||||||
| # -*- coding: utf-8 -*- |  | ||||||
| """ |  | ||||||
|     flask.signals |  | ||||||
|     ~~~~~~~~~~~~~ |  | ||||||
| 
 |  | ||||||
|     Implements signals based on blinker if available, otherwise |  | ||||||
|     falls silently back to a noop. |  | ||||||
| 
 |  | ||||||
|     :copyright: © 2010 by the Pallets team. |  | ||||||
|     :license: BSD, see LICENSE for more details. |  | ||||||
| """ |  | ||||||
| 
 |  | ||||||
| signals_available = False |  | ||||||
| try: |  | ||||||
|     from blinker import Namespace |  | ||||||
|     signals_available = True |  | ||||||
| except ImportError: |  | ||||||
|     class Namespace(object): |  | ||||||
|         def signal(self, name, doc=None): |  | ||||||
|             return _FakeSignal(name, doc) |  | ||||||
| 
 |  | ||||||
|     class _FakeSignal(object): |  | ||||||
|         """If blinker is unavailable, create a fake class with the same |  | ||||||
|         interface that allows sending of signals but will fail with an |  | ||||||
|         error on anything else.  Instead of doing anything on send, it |  | ||||||
|         will just ignore the arguments and do nothing instead. |  | ||||||
|         """ |  | ||||||
| 
 |  | ||||||
|         def __init__(self, name, doc=None): |  | ||||||
|             self.name = name |  | ||||||
|             self.__doc__ = doc |  | ||||||
|         def _fail(self, *args, **kwargs): |  | ||||||
|             raise RuntimeError('signalling support is unavailable ' |  | ||||||
|                                'because the blinker library is ' |  | ||||||
|                                'not installed.') |  | ||||||
|         send = lambda *a, **kw: None |  | ||||||
|         connect = disconnect = has_receivers_for = receivers_for = \ |  | ||||||
|             temporarily_connected_to = connected_to = _fail |  | ||||||
|         del _fail |  | ||||||
| 
 |  | ||||||
| # The namespace for code signals.  If you are not Flask code, do |  | ||||||
| # not put signals in here.  Create your own namespace instead. |  | ||||||
| _signals = Namespace() |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| # Core signals.  For usage examples grep the source code or consult |  | ||||||
| # the API documentation in docs/api.rst as well as docs/signals.rst |  | ||||||
| template_rendered = _signals.signal('template-rendered') |  | ||||||
| before_render_template = _signals.signal('before-render-template') |  | ||||||
| request_started = _signals.signal('request-started') |  | ||||||
| request_finished = _signals.signal('request-finished') |  | ||||||
| request_tearing_down = _signals.signal('request-tearing-down') |  | ||||||
| got_request_exception = _signals.signal('got-request-exception') |  | ||||||
| appcontext_tearing_down = _signals.signal('appcontext-tearing-down') |  | ||||||
| appcontext_pushed = _signals.signal('appcontext-pushed') |  | ||||||
| appcontext_popped = _signals.signal('appcontext-popped') |  | ||||||
| message_flashed = _signals.signal('message-flashed') |  | ||||||
| @ -1,150 +0,0 @@ | |||||||
| # -*- coding: utf-8 -*- |  | ||||||
| """ |  | ||||||
|     flask.templating |  | ||||||
|     ~~~~~~~~~~~~~~~~ |  | ||||||
| 
 |  | ||||||
|     Implements the bridge to Jinja2. |  | ||||||
| 
 |  | ||||||
|     :copyright: © 2010 by the Pallets team. |  | ||||||
|     :license: BSD, see LICENSE for more details. |  | ||||||
| """ |  | ||||||
| 
 |  | ||||||
| from jinja2 import BaseLoader, Environment as BaseEnvironment, \ |  | ||||||
|      TemplateNotFound |  | ||||||
| 
 |  | ||||||
| from .globals import _request_ctx_stack, _app_ctx_stack |  | ||||||
| from .signals import template_rendered, before_render_template |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def _default_template_ctx_processor(): |  | ||||||
|     """Default template context processor.  Injects `request`, |  | ||||||
|     `session` and `g`. |  | ||||||
|     """ |  | ||||||
|     reqctx = _request_ctx_stack.top |  | ||||||
|     appctx = _app_ctx_stack.top |  | ||||||
|     rv = {} |  | ||||||
|     if appctx is not None: |  | ||||||
|         rv['g'] = appctx.g |  | ||||||
|     if reqctx is not None: |  | ||||||
|         rv['request'] = reqctx.request |  | ||||||
|         rv['session'] = reqctx.session |  | ||||||
|     return rv |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class Environment(BaseEnvironment): |  | ||||||
|     """Works like a regular Jinja2 environment but has some additional |  | ||||||
|     knowledge of how Flask's blueprint works so that it can prepend the |  | ||||||
|     name of the blueprint to referenced templates if necessary. |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     def __init__(self, app, **options): |  | ||||||
|         if 'loader' not in options: |  | ||||||
|             options['loader'] = app.create_global_jinja_loader() |  | ||||||
|         BaseEnvironment.__init__(self, **options) |  | ||||||
|         self.app = app |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class DispatchingJinjaLoader(BaseLoader): |  | ||||||
|     """A loader that looks for templates in the application and all |  | ||||||
|     the blueprint folders. |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     def __init__(self, app): |  | ||||||
|         self.app = app |  | ||||||
| 
 |  | ||||||
|     def get_source(self, environment, template): |  | ||||||
|         if self.app.config['EXPLAIN_TEMPLATE_LOADING']: |  | ||||||
|             return self._get_source_explained(environment, template) |  | ||||||
|         return self._get_source_fast(environment, template) |  | ||||||
| 
 |  | ||||||
|     def _get_source_explained(self, environment, template): |  | ||||||
|         attempts = [] |  | ||||||
|         trv = None |  | ||||||
| 
 |  | ||||||
|         for srcobj, loader in self._iter_loaders(template): |  | ||||||
|             try: |  | ||||||
|                 rv = loader.get_source(environment, template) |  | ||||||
|                 if trv is None: |  | ||||||
|                     trv = rv |  | ||||||
|             except TemplateNotFound: |  | ||||||
|                 rv = None |  | ||||||
|             attempts.append((loader, srcobj, rv)) |  | ||||||
| 
 |  | ||||||
|         from .debughelpers import explain_template_loading_attempts |  | ||||||
|         explain_template_loading_attempts(self.app, template, attempts) |  | ||||||
| 
 |  | ||||||
|         if trv is not None: |  | ||||||
|             return trv |  | ||||||
|         raise TemplateNotFound(template) |  | ||||||
| 
 |  | ||||||
|     def _get_source_fast(self, environment, template): |  | ||||||
|         for srcobj, loader in self._iter_loaders(template): |  | ||||||
|             try: |  | ||||||
|                 return loader.get_source(environment, template) |  | ||||||
|             except TemplateNotFound: |  | ||||||
|                 continue |  | ||||||
|         raise TemplateNotFound(template) |  | ||||||
| 
 |  | ||||||
|     def _iter_loaders(self, template): |  | ||||||
|         loader = self.app.jinja_loader |  | ||||||
|         if loader is not None: |  | ||||||
|             yield self.app, loader |  | ||||||
| 
 |  | ||||||
|         for blueprint in self.app.iter_blueprints(): |  | ||||||
|             loader = blueprint.jinja_loader |  | ||||||
|             if loader is not None: |  | ||||||
|                 yield blueprint, loader |  | ||||||
| 
 |  | ||||||
|     def list_templates(self): |  | ||||||
|         result = set() |  | ||||||
|         loader = self.app.jinja_loader |  | ||||||
|         if loader is not None: |  | ||||||
|             result.update(loader.list_templates()) |  | ||||||
| 
 |  | ||||||
|         for blueprint in self.app.iter_blueprints(): |  | ||||||
|             loader = blueprint.jinja_loader |  | ||||||
|             if loader is not None: |  | ||||||
|                 for template in loader.list_templates(): |  | ||||||
|                     result.add(template) |  | ||||||
| 
 |  | ||||||
|         return list(result) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def _render(template, context, app): |  | ||||||
|     """Renders the template and fires the signal""" |  | ||||||
| 
 |  | ||||||
|     before_render_template.send(app, template=template, context=context) |  | ||||||
|     rv = template.render(context) |  | ||||||
|     template_rendered.send(app, template=template, context=context) |  | ||||||
|     return rv |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def render_template(template_name_or_list, **context): |  | ||||||
|     """Renders a template from the template folder with the given |  | ||||||
|     context. |  | ||||||
| 
 |  | ||||||
|     :param template_name_or_list: the name of the template to be |  | ||||||
|                                   rendered, or an iterable with template names |  | ||||||
|                                   the first one existing will be rendered |  | ||||||
|     :param context: the variables that should be available in the |  | ||||||
|                     context of the template. |  | ||||||
|     """ |  | ||||||
|     ctx = _app_ctx_stack.top |  | ||||||
|     ctx.app.update_template_context(context) |  | ||||||
|     return _render(ctx.app.jinja_env.get_or_select_template(template_name_or_list), |  | ||||||
|                    context, ctx.app) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def render_template_string(source, **context): |  | ||||||
|     """Renders a template from the given template source string |  | ||||||
|     with the given context. Template variables will be autoescaped. |  | ||||||
| 
 |  | ||||||
|     :param source: the source code of the template to be |  | ||||||
|                    rendered |  | ||||||
|     :param context: the variables that should be available in the |  | ||||||
|                     context of the template. |  | ||||||
|     """ |  | ||||||
|     ctx = _app_ctx_stack.top |  | ||||||
|     ctx.app.update_template_context(context) |  | ||||||
|     return _render(ctx.app.jinja_env.from_string(source), |  | ||||||
|                    context, ctx.app) |  | ||||||
| @ -1,250 +0,0 @@ | |||||||
| # -*- coding: utf-8 -*- |  | ||||||
| """ |  | ||||||
|     flask.testing |  | ||||||
|     ~~~~~~~~~~~~~ |  | ||||||
| 
 |  | ||||||
|     Implements test support helpers.  This module is lazily imported |  | ||||||
|     and usually not used in production environments. |  | ||||||
| 
 |  | ||||||
|     :copyright: © 2010 by the Pallets team. |  | ||||||
|     :license: BSD, see LICENSE for more details. |  | ||||||
| """ |  | ||||||
| 
 |  | ||||||
| import werkzeug |  | ||||||
| from contextlib import contextmanager |  | ||||||
| 
 |  | ||||||
| from click.testing import CliRunner |  | ||||||
| from flask.cli import ScriptInfo |  | ||||||
| from werkzeug.test import Client, EnvironBuilder |  | ||||||
| from flask import _request_ctx_stack |  | ||||||
| from flask.json import dumps as json_dumps |  | ||||||
| from werkzeug.urls import url_parse |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def make_test_environ_builder( |  | ||||||
|     app, path='/', base_url=None, subdomain=None, url_scheme=None, |  | ||||||
|     *args, **kwargs |  | ||||||
| ): |  | ||||||
|     """Create a :class:`~werkzeug.test.EnvironBuilder`, taking some |  | ||||||
|     defaults from the application. |  | ||||||
| 
 |  | ||||||
|     :param app: The Flask application to configure the environment from. |  | ||||||
|     :param path: URL path being requested. |  | ||||||
|     :param base_url: Base URL where the app is being served, which |  | ||||||
|         ``path`` is relative to. If not given, built from |  | ||||||
|         :data:`PREFERRED_URL_SCHEME`, ``subdomain``, |  | ||||||
|         :data:`SERVER_NAME`, and :data:`APPLICATION_ROOT`. |  | ||||||
|     :param subdomain: Subdomain name to append to :data:`SERVER_NAME`. |  | ||||||
|     :param url_scheme: Scheme to use instead of |  | ||||||
|         :data:`PREFERRED_URL_SCHEME`. |  | ||||||
|     :param json: If given, this is serialized as JSON and passed as |  | ||||||
|         ``data``. Also defaults ``content_type`` to |  | ||||||
|         ``application/json``. |  | ||||||
|     :param args: other positional arguments passed to |  | ||||||
|         :class:`~werkzeug.test.EnvironBuilder`. |  | ||||||
|     :param kwargs: other keyword arguments passed to |  | ||||||
|         :class:`~werkzeug.test.EnvironBuilder`. |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     assert ( |  | ||||||
|         not (base_url or subdomain or url_scheme) |  | ||||||
|         or (base_url is not None) != bool(subdomain or url_scheme) |  | ||||||
|     ), 'Cannot pass "subdomain" or "url_scheme" with "base_url".' |  | ||||||
| 
 |  | ||||||
|     if base_url is None: |  | ||||||
|         http_host = app.config.get('SERVER_NAME') or 'localhost' |  | ||||||
|         app_root = app.config['APPLICATION_ROOT'] |  | ||||||
| 
 |  | ||||||
|         if subdomain: |  | ||||||
|             http_host = '{0}.{1}'.format(subdomain, http_host) |  | ||||||
| 
 |  | ||||||
|         if url_scheme is None: |  | ||||||
|             url_scheme = app.config['PREFERRED_URL_SCHEME'] |  | ||||||
| 
 |  | ||||||
|         url = url_parse(path) |  | ||||||
|         base_url = '{scheme}://{netloc}/{path}'.format( |  | ||||||
|             scheme=url.scheme or url_scheme, |  | ||||||
|             netloc=url.netloc or http_host, |  | ||||||
|             path=app_root.lstrip('/') |  | ||||||
|         ) |  | ||||||
|         path = url.path |  | ||||||
| 
 |  | ||||||
|         if url.query: |  | ||||||
|             sep = b'?' if isinstance(url.query, bytes) else '?' |  | ||||||
|             path += sep + url.query |  | ||||||
| 
 |  | ||||||
|     if 'json' in kwargs: |  | ||||||
|         assert 'data' not in kwargs, ( |  | ||||||
|             "Client cannot provide both 'json' and 'data'." |  | ||||||
|         ) |  | ||||||
| 
 |  | ||||||
|         # push a context so flask.json can use app's json attributes |  | ||||||
|         with app.app_context(): |  | ||||||
|             kwargs['data'] = json_dumps(kwargs.pop('json')) |  | ||||||
| 
 |  | ||||||
|         if 'content_type' not in kwargs: |  | ||||||
|             kwargs['content_type'] = 'application/json' |  | ||||||
| 
 |  | ||||||
|     return EnvironBuilder(path, base_url, *args, **kwargs) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class FlaskClient(Client): |  | ||||||
|     """Works like a regular Werkzeug test client but has some knowledge about |  | ||||||
|     how Flask works to defer the cleanup of the request context stack to the |  | ||||||
|     end of a ``with`` body when used in a ``with`` statement.  For general |  | ||||||
|     information about how to use this class refer to |  | ||||||
|     :class:`werkzeug.test.Client`. |  | ||||||
| 
 |  | ||||||
|     .. versionchanged:: 0.12 |  | ||||||
|        `app.test_client()` includes preset default environment, which can be |  | ||||||
|        set after instantiation of the `app.test_client()` object in |  | ||||||
|        `client.environ_base`. |  | ||||||
| 
 |  | ||||||
|     Basic usage is outlined in the :ref:`testing` chapter. |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     preserve_context = False |  | ||||||
| 
 |  | ||||||
|     def __init__(self, *args, **kwargs): |  | ||||||
|         super(FlaskClient, self).__init__(*args, **kwargs) |  | ||||||
|         self.environ_base = { |  | ||||||
|             "REMOTE_ADDR": "127.0.0.1", |  | ||||||
|             "HTTP_USER_AGENT": "werkzeug/" + werkzeug.__version__ |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|     @contextmanager |  | ||||||
|     def session_transaction(self, *args, **kwargs): |  | ||||||
|         """When used in combination with a ``with`` statement this opens a |  | ||||||
|         session transaction.  This can be used to modify the session that |  | ||||||
|         the test client uses.  Once the ``with`` block is left the session is |  | ||||||
|         stored back. |  | ||||||
| 
 |  | ||||||
|         :: |  | ||||||
| 
 |  | ||||||
|             with client.session_transaction() as session: |  | ||||||
|                 session['value'] = 42 |  | ||||||
| 
 |  | ||||||
|         Internally this is implemented by going through a temporary test |  | ||||||
|         request context and since session handling could depend on |  | ||||||
|         request variables this function accepts the same arguments as |  | ||||||
|         :meth:`~flask.Flask.test_request_context` which are directly |  | ||||||
|         passed through. |  | ||||||
|         """ |  | ||||||
|         if self.cookie_jar is None: |  | ||||||
|             raise RuntimeError('Session transactions only make sense ' |  | ||||||
|                                'with cookies enabled.') |  | ||||||
|         app = self.application |  | ||||||
|         environ_overrides = kwargs.setdefault('environ_overrides', {}) |  | ||||||
|         self.cookie_jar.inject_wsgi(environ_overrides) |  | ||||||
|         outer_reqctx = _request_ctx_stack.top |  | ||||||
|         with app.test_request_context(*args, **kwargs) as c: |  | ||||||
|             session_interface = app.session_interface |  | ||||||
|             sess = session_interface.open_session(app, c.request) |  | ||||||
|             if sess is None: |  | ||||||
|                 raise RuntimeError('Session backend did not open a session. ' |  | ||||||
|                                    'Check the configuration') |  | ||||||
| 
 |  | ||||||
|             # Since we have to open a new request context for the session |  | ||||||
|             # handling we want to make sure that we hide out own context |  | ||||||
|             # from the caller.  By pushing the original request context |  | ||||||
|             # (or None) on top of this and popping it we get exactly that |  | ||||||
|             # behavior.  It's important to not use the push and pop |  | ||||||
|             # methods of the actual request context object since that would |  | ||||||
|             # mean that cleanup handlers are called |  | ||||||
|             _request_ctx_stack.push(outer_reqctx) |  | ||||||
|             try: |  | ||||||
|                 yield sess |  | ||||||
|             finally: |  | ||||||
|                 _request_ctx_stack.pop() |  | ||||||
| 
 |  | ||||||
|             resp = app.response_class() |  | ||||||
|             if not session_interface.is_null_session(sess): |  | ||||||
|                 session_interface.save_session(app, sess, resp) |  | ||||||
|             headers = resp.get_wsgi_headers(c.request.environ) |  | ||||||
|             self.cookie_jar.extract_wsgi(c.request.environ, headers) |  | ||||||
| 
 |  | ||||||
|     def open(self, *args, **kwargs): |  | ||||||
|         as_tuple = kwargs.pop('as_tuple', False) |  | ||||||
|         buffered = kwargs.pop('buffered', False) |  | ||||||
|         follow_redirects = kwargs.pop('follow_redirects', False) |  | ||||||
| 
 |  | ||||||
|         if ( |  | ||||||
|             not kwargs and len(args) == 1 |  | ||||||
|             and isinstance(args[0], (EnvironBuilder, dict)) |  | ||||||
|         ): |  | ||||||
|             environ = self.environ_base.copy() |  | ||||||
| 
 |  | ||||||
|             if isinstance(args[0], EnvironBuilder): |  | ||||||
|                 environ.update(args[0].get_environ()) |  | ||||||
|             else: |  | ||||||
|                 environ.update(args[0]) |  | ||||||
| 
 |  | ||||||
|             environ['flask._preserve_context'] = self.preserve_context |  | ||||||
|         else: |  | ||||||
|             kwargs.setdefault('environ_overrides', {}) \ |  | ||||||
|                 ['flask._preserve_context'] = self.preserve_context |  | ||||||
|             kwargs.setdefault('environ_base', self.environ_base) |  | ||||||
|             builder = make_test_environ_builder( |  | ||||||
|                 self.application, *args, **kwargs |  | ||||||
|             ) |  | ||||||
| 
 |  | ||||||
|             try: |  | ||||||
|                 environ = builder.get_environ() |  | ||||||
|             finally: |  | ||||||
|                 builder.close() |  | ||||||
| 
 |  | ||||||
|         return Client.open( |  | ||||||
|             self, environ, |  | ||||||
|             as_tuple=as_tuple, |  | ||||||
|             buffered=buffered, |  | ||||||
|             follow_redirects=follow_redirects |  | ||||||
|         ) |  | ||||||
| 
 |  | ||||||
|     def __enter__(self): |  | ||||||
|         if self.preserve_context: |  | ||||||
|             raise RuntimeError('Cannot nest client invocations') |  | ||||||
|         self.preserve_context = True |  | ||||||
|         return self |  | ||||||
| 
 |  | ||||||
|     def __exit__(self, exc_type, exc_value, tb): |  | ||||||
|         self.preserve_context = False |  | ||||||
| 
 |  | ||||||
|         # on exit we want to clean up earlier.  Normally the request context |  | ||||||
|         # stays preserved until the next request in the same thread comes |  | ||||||
|         # in.  See RequestGlobals.push() for the general behavior. |  | ||||||
|         top = _request_ctx_stack.top |  | ||||||
|         if top is not None and top.preserved: |  | ||||||
|             top.pop() |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class FlaskCliRunner(CliRunner): |  | ||||||
|     """A :class:`~click.testing.CliRunner` for testing a Flask app's |  | ||||||
|     CLI commands. Typically created using |  | ||||||
|     :meth:`~flask.Flask.test_cli_runner`. See :ref:`testing-cli`. |  | ||||||
|     """ |  | ||||||
|     def __init__(self, app, **kwargs): |  | ||||||
|         self.app = app |  | ||||||
|         super(FlaskCliRunner, self).__init__(**kwargs) |  | ||||||
| 
 |  | ||||||
|     def invoke(self, cli=None, args=None, **kwargs): |  | ||||||
|         """Invokes a CLI command in an isolated environment. See |  | ||||||
|         :meth:`CliRunner.invoke <click.testing.CliRunner.invoke>` for |  | ||||||
|         full method documentation. See :ref:`testing-cli` for examples. |  | ||||||
| 
 |  | ||||||
|         If the ``obj`` argument is not given, passes an instance of |  | ||||||
|         :class:`~flask.cli.ScriptInfo` that knows how to load the Flask |  | ||||||
|         app being tested. |  | ||||||
| 
 |  | ||||||
|         :param cli: Command object to invoke. Default is the app's |  | ||||||
|             :attr:`~flask.app.Flask.cli` group. |  | ||||||
|         :param args: List of strings to invoke the command with. |  | ||||||
| 
 |  | ||||||
|         :return: a :class:`~click.testing.Result` object. |  | ||||||
|         """ |  | ||||||
|         if cli is None: |  | ||||||
|             cli = self.app.cli |  | ||||||
| 
 |  | ||||||
|         if 'obj' not in kwargs: |  | ||||||
|             kwargs['obj'] = ScriptInfo(create_app=lambda: self.app) |  | ||||||
| 
 |  | ||||||
|         return super(FlaskCliRunner, self).invoke(cli, args, **kwargs) |  | ||||||
| @ -1,158 +0,0 @@ | |||||||
| # -*- coding: utf-8 -*- |  | ||||||
| """ |  | ||||||
|     flask.views |  | ||||||
|     ~~~~~~~~~~~ |  | ||||||
| 
 |  | ||||||
|     This module provides class-based views inspired by the ones in Django. |  | ||||||
| 
 |  | ||||||
|     :copyright: © 2010 by the Pallets team. |  | ||||||
|     :license: BSD, see LICENSE for more details. |  | ||||||
| """ |  | ||||||
| 
 |  | ||||||
| from .globals import request |  | ||||||
| from ._compat import with_metaclass |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| http_method_funcs = frozenset(['get', 'post', 'head', 'options', |  | ||||||
|                                'delete', 'put', 'trace', 'patch']) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class View(object): |  | ||||||
|     """Alternative way to use view functions.  A subclass has to implement |  | ||||||
|     :meth:`dispatch_request` which is called with the view arguments from |  | ||||||
|     the URL routing system.  If :attr:`methods` is provided the methods |  | ||||||
|     do not have to be passed to the :meth:`~flask.Flask.add_url_rule` |  | ||||||
|     method explicitly:: |  | ||||||
| 
 |  | ||||||
|         class MyView(View): |  | ||||||
|             methods = ['GET'] |  | ||||||
| 
 |  | ||||||
|             def dispatch_request(self, name): |  | ||||||
|                 return 'Hello %s!' % name |  | ||||||
| 
 |  | ||||||
|         app.add_url_rule('/hello/<name>', view_func=MyView.as_view('myview')) |  | ||||||
| 
 |  | ||||||
|     When you want to decorate a pluggable view you will have to either do that |  | ||||||
|     when the view function is created (by wrapping the return value of |  | ||||||
|     :meth:`as_view`) or you can use the :attr:`decorators` attribute:: |  | ||||||
| 
 |  | ||||||
|         class SecretView(View): |  | ||||||
|             methods = ['GET'] |  | ||||||
|             decorators = [superuser_required] |  | ||||||
| 
 |  | ||||||
|             def dispatch_request(self): |  | ||||||
|                 ... |  | ||||||
| 
 |  | ||||||
|     The decorators stored in the decorators list are applied one after another |  | ||||||
|     when the view function is created.  Note that you can *not* use the class |  | ||||||
|     based decorators since those would decorate the view class and not the |  | ||||||
|     generated view function! |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     #: A list of methods this view can handle. |  | ||||||
|     methods = None |  | ||||||
| 
 |  | ||||||
|     #: Setting this disables or force-enables the automatic options handling. |  | ||||||
|     provide_automatic_options = None |  | ||||||
| 
 |  | ||||||
|     #: The canonical way to decorate class-based views is to decorate the |  | ||||||
|     #: return value of as_view().  However since this moves parts of the |  | ||||||
|     #: logic from the class declaration to the place where it's hooked |  | ||||||
|     #: into the routing system. |  | ||||||
|     #: |  | ||||||
|     #: You can place one or more decorators in this list and whenever the |  | ||||||
|     #: view function is created the result is automatically decorated. |  | ||||||
|     #: |  | ||||||
|     #: .. versionadded:: 0.8 |  | ||||||
|     decorators = () |  | ||||||
| 
 |  | ||||||
|     def dispatch_request(self): |  | ||||||
|         """Subclasses have to override this method to implement the |  | ||||||
|         actual view function code.  This method is called with all |  | ||||||
|         the arguments from the URL rule. |  | ||||||
|         """ |  | ||||||
|         raise NotImplementedError() |  | ||||||
| 
 |  | ||||||
|     @classmethod |  | ||||||
|     def as_view(cls, name, *class_args, **class_kwargs): |  | ||||||
|         """Converts the class into an actual view function that can be used |  | ||||||
|         with the routing system.  Internally this generates a function on the |  | ||||||
|         fly which will instantiate the :class:`View` on each request and call |  | ||||||
|         the :meth:`dispatch_request` method on it. |  | ||||||
| 
 |  | ||||||
|         The arguments passed to :meth:`as_view` are forwarded to the |  | ||||||
|         constructor of the class. |  | ||||||
|         """ |  | ||||||
|         def view(*args, **kwargs): |  | ||||||
|             self = view.view_class(*class_args, **class_kwargs) |  | ||||||
|             return self.dispatch_request(*args, **kwargs) |  | ||||||
| 
 |  | ||||||
|         if cls.decorators: |  | ||||||
|             view.__name__ = name |  | ||||||
|             view.__module__ = cls.__module__ |  | ||||||
|             for decorator in cls.decorators: |  | ||||||
|                 view = decorator(view) |  | ||||||
| 
 |  | ||||||
|         # We attach the view class to the view function for two reasons: |  | ||||||
|         # first of all it allows us to easily figure out what class-based |  | ||||||
|         # view this thing came from, secondly it's also used for instantiating |  | ||||||
|         # the view class so you can actually replace it with something else |  | ||||||
|         # for testing purposes and debugging. |  | ||||||
|         view.view_class = cls |  | ||||||
|         view.__name__ = name |  | ||||||
|         view.__doc__ = cls.__doc__ |  | ||||||
|         view.__module__ = cls.__module__ |  | ||||||
|         view.methods = cls.methods |  | ||||||
|         view.provide_automatic_options = cls.provide_automatic_options |  | ||||||
|         return view |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class MethodViewType(type): |  | ||||||
|     """Metaclass for :class:`MethodView` that determines what methods the view |  | ||||||
|     defines. |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     def __init__(cls, name, bases, d): |  | ||||||
|         super(MethodViewType, cls).__init__(name, bases, d) |  | ||||||
| 
 |  | ||||||
|         if 'methods' not in d: |  | ||||||
|             methods = set() |  | ||||||
| 
 |  | ||||||
|             for key in http_method_funcs: |  | ||||||
|                 if hasattr(cls, key): |  | ||||||
|                     methods.add(key.upper()) |  | ||||||
| 
 |  | ||||||
|             # If we have no method at all in there we don't want to add a |  | ||||||
|             # method list. This is for instance the case for the base class |  | ||||||
|             # or another subclass of a base method view that does not introduce |  | ||||||
|             # new methods. |  | ||||||
|             if methods: |  | ||||||
|                 cls.methods = methods |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class MethodView(with_metaclass(MethodViewType, View)): |  | ||||||
|     """A class-based view that dispatches request methods to the corresponding |  | ||||||
|     class methods. For example, if you implement a ``get`` method, it will be |  | ||||||
|     used to handle ``GET`` requests. :: |  | ||||||
| 
 |  | ||||||
|         class CounterAPI(MethodView): |  | ||||||
|             def get(self): |  | ||||||
|                 return session.get('counter', 0) |  | ||||||
| 
 |  | ||||||
|             def post(self): |  | ||||||
|                 session['counter'] = session.get('counter', 0) + 1 |  | ||||||
|                 return 'OK' |  | ||||||
| 
 |  | ||||||
|         app.add_url_rule('/counter', view_func=CounterAPI.as_view('counter')) |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     def dispatch_request(self, *args, **kwargs): |  | ||||||
|         meth = getattr(self, request.method.lower(), None) |  | ||||||
| 
 |  | ||||||
|         # If the request method is HEAD and we don't have a handler for it |  | ||||||
|         # retry with GET. |  | ||||||
|         if meth is None and request.method == 'HEAD': |  | ||||||
|             meth = getattr(self, 'get', None) |  | ||||||
| 
 |  | ||||||
|         assert meth is not None, 'Unimplemented method %r' % request.method |  | ||||||
|         return meth(*args, **kwargs) |  | ||||||
| @ -1,216 +0,0 @@ | |||||||
| # -*- coding: utf-8 -*- |  | ||||||
| """ |  | ||||||
|     flask.wrappers |  | ||||||
|     ~~~~~~~~~~~~~~ |  | ||||||
| 
 |  | ||||||
|     Implements the WSGI wrappers (request and response). |  | ||||||
| 
 |  | ||||||
|     :copyright: © 2010 by the Pallets team. |  | ||||||
|     :license: BSD, see LICENSE for more details. |  | ||||||
| """ |  | ||||||
| 
 |  | ||||||
| from werkzeug.exceptions import BadRequest |  | ||||||
| from werkzeug.wrappers import Request as RequestBase, Response as ResponseBase |  | ||||||
| 
 |  | ||||||
| from flask import json |  | ||||||
| from flask.globals import current_app |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class JSONMixin(object): |  | ||||||
|     """Common mixin for both request and response objects to provide JSON |  | ||||||
|     parsing capabilities. |  | ||||||
| 
 |  | ||||||
|     .. versionadded:: 1.0 |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     _cached_json = (Ellipsis, Ellipsis) |  | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def is_json(self): |  | ||||||
|         """Check if the mimetype indicates JSON data, either |  | ||||||
|         :mimetype:`application/json` or :mimetype:`application/*+json`. |  | ||||||
| 
 |  | ||||||
|         .. versionadded:: 0.11 |  | ||||||
|         """ |  | ||||||
|         mt = self.mimetype |  | ||||||
|         return ( |  | ||||||
|             mt == 'application/json' |  | ||||||
|             or (mt.startswith('application/')) and mt.endswith('+json') |  | ||||||
|         ) |  | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def json(self): |  | ||||||
|         """This will contain the parsed JSON data if the mimetype indicates |  | ||||||
|         JSON (:mimetype:`application/json`, see :meth:`is_json`), otherwise it |  | ||||||
|         will be ``None``. |  | ||||||
|         """ |  | ||||||
|         return self.get_json() |  | ||||||
| 
 |  | ||||||
|     def _get_data_for_json(self, cache): |  | ||||||
|         return self.get_data(cache=cache) |  | ||||||
| 
 |  | ||||||
|     def get_json(self, force=False, silent=False, cache=True): |  | ||||||
|         """Parse and return the data as JSON. If the mimetype does not |  | ||||||
|         indicate JSON (:mimetype:`application/json`, see |  | ||||||
|         :meth:`is_json`), this returns ``None`` unless ``force`` is |  | ||||||
|         true. If parsing fails, :meth:`on_json_loading_failed` is called |  | ||||||
|         and its return value is used as the return value. |  | ||||||
| 
 |  | ||||||
|         :param force: Ignore the mimetype and always try to parse JSON. |  | ||||||
|         :param silent: Silence parsing errors and return ``None`` |  | ||||||
|             instead. |  | ||||||
|         :param cache: Store the parsed JSON to return for subsequent |  | ||||||
|             calls. |  | ||||||
|         """ |  | ||||||
|         if cache and self._cached_json[silent] is not Ellipsis: |  | ||||||
|             return self._cached_json[silent] |  | ||||||
| 
 |  | ||||||
|         if not (force or self.is_json): |  | ||||||
|             return None |  | ||||||
| 
 |  | ||||||
|         data = self._get_data_for_json(cache=cache) |  | ||||||
| 
 |  | ||||||
|         try: |  | ||||||
|             rv = json.loads(data) |  | ||||||
|         except ValueError as e: |  | ||||||
|             if silent: |  | ||||||
|                 rv = None |  | ||||||
|                 if cache: |  | ||||||
|                     normal_rv, _ = self._cached_json |  | ||||||
|                     self._cached_json = (normal_rv, rv) |  | ||||||
|             else: |  | ||||||
|                 rv = self.on_json_loading_failed(e) |  | ||||||
|                 if cache: |  | ||||||
|                     _, silent_rv = self._cached_json |  | ||||||
|                     self._cached_json = (rv, silent_rv) |  | ||||||
|         else: |  | ||||||
|             if cache: |  | ||||||
|                 self._cached_json = (rv, rv) |  | ||||||
| 
 |  | ||||||
|         return rv |  | ||||||
| 
 |  | ||||||
|     def on_json_loading_failed(self, e): |  | ||||||
|         """Called if :meth:`get_json` parsing fails and isn't silenced. If |  | ||||||
|         this method returns a value, it is used as the return value for |  | ||||||
|         :meth:`get_json`. The default implementation raises a |  | ||||||
|         :class:`BadRequest` exception. |  | ||||||
| 
 |  | ||||||
|         .. versionchanged:: 0.10 |  | ||||||
|            Raise a :exc:`BadRequest` error instead of returning an error |  | ||||||
|            message as JSON. If you want that behavior you can add it by |  | ||||||
|            subclassing. |  | ||||||
| 
 |  | ||||||
|         .. versionadded:: 0.8 |  | ||||||
|         """ |  | ||||||
|         if current_app is not None and current_app.debug: |  | ||||||
|             raise BadRequest('Failed to decode JSON object: {0}'.format(e)) |  | ||||||
| 
 |  | ||||||
|         raise BadRequest() |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class Request(RequestBase, JSONMixin): |  | ||||||
|     """The request object used by default in Flask.  Remembers the |  | ||||||
|     matched endpoint and view arguments. |  | ||||||
| 
 |  | ||||||
|     It is what ends up as :class:`~flask.request`.  If you want to replace |  | ||||||
|     the request object used you can subclass this and set |  | ||||||
|     :attr:`~flask.Flask.request_class` to your subclass. |  | ||||||
| 
 |  | ||||||
|     The request object is a :class:`~werkzeug.wrappers.Request` subclass and |  | ||||||
|     provides all of the attributes Werkzeug defines plus a few Flask |  | ||||||
|     specific ones. |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     #: The internal URL rule that matched the request.  This can be |  | ||||||
|     #: useful to inspect which methods are allowed for the URL from |  | ||||||
|     #: a before/after handler (``request.url_rule.methods``) etc. |  | ||||||
|     #: Though if the request's method was invalid for the URL rule, |  | ||||||
|     #: the valid list is available in ``routing_exception.valid_methods`` |  | ||||||
|     #: instead (an attribute of the Werkzeug exception :exc:`~werkzeug.exceptions.MethodNotAllowed`) |  | ||||||
|     #: because the request was never internally bound. |  | ||||||
|     #: |  | ||||||
|     #: .. versionadded:: 0.6 |  | ||||||
|     url_rule = None |  | ||||||
| 
 |  | ||||||
|     #: A dict of view arguments that matched the request.  If an exception |  | ||||||
|     #: happened when matching, this will be ``None``. |  | ||||||
|     view_args = None |  | ||||||
| 
 |  | ||||||
|     #: If matching the URL failed, this is the exception that will be |  | ||||||
|     #: raised / was raised as part of the request handling.  This is |  | ||||||
|     #: usually a :exc:`~werkzeug.exceptions.NotFound` exception or |  | ||||||
|     #: something similar. |  | ||||||
|     routing_exception = None |  | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def max_content_length(self): |  | ||||||
|         """Read-only view of the ``MAX_CONTENT_LENGTH`` config key.""" |  | ||||||
|         if current_app: |  | ||||||
|             return current_app.config['MAX_CONTENT_LENGTH'] |  | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def endpoint(self): |  | ||||||
|         """The endpoint that matched the request.  This in combination with |  | ||||||
|         :attr:`view_args` can be used to reconstruct the same or a |  | ||||||
|         modified URL.  If an exception happened when matching, this will |  | ||||||
|         be ``None``. |  | ||||||
|         """ |  | ||||||
|         if self.url_rule is not None: |  | ||||||
|             return self.url_rule.endpoint |  | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def blueprint(self): |  | ||||||
|         """The name of the current blueprint""" |  | ||||||
|         if self.url_rule and '.' in self.url_rule.endpoint: |  | ||||||
|             return self.url_rule.endpoint.rsplit('.', 1)[0] |  | ||||||
| 
 |  | ||||||
|     def _load_form_data(self): |  | ||||||
|         RequestBase._load_form_data(self) |  | ||||||
| 
 |  | ||||||
|         # In debug mode we're replacing the files multidict with an ad-hoc |  | ||||||
|         # subclass that raises a different error for key errors. |  | ||||||
|         if ( |  | ||||||
|             current_app |  | ||||||
|             and current_app.debug |  | ||||||
|             and self.mimetype != 'multipart/form-data' |  | ||||||
|             and not self.files |  | ||||||
|         ): |  | ||||||
|             from .debughelpers import attach_enctype_error_multidict |  | ||||||
|             attach_enctype_error_multidict(self) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class Response(ResponseBase, JSONMixin): |  | ||||||
|     """The response object that is used by default in Flask.  Works like the |  | ||||||
|     response object from Werkzeug but is set to have an HTML mimetype by |  | ||||||
|     default.  Quite often you don't have to create this object yourself because |  | ||||||
|     :meth:`~flask.Flask.make_response` will take care of that for you. |  | ||||||
| 
 |  | ||||||
|     If you want to replace the response object used you can subclass this and |  | ||||||
|     set :attr:`~flask.Flask.response_class` to your subclass. |  | ||||||
| 
 |  | ||||||
|     .. versionchanged:: 1.0 |  | ||||||
|         JSON support is added to the response, like the request. This is useful |  | ||||||
|         when testing to get the test client response data as JSON. |  | ||||||
| 
 |  | ||||||
|     .. versionchanged:: 1.0 |  | ||||||
| 
 |  | ||||||
|         Added :attr:`max_cookie_size`. |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     default_mimetype = 'text/html' |  | ||||||
| 
 |  | ||||||
|     def _get_data_for_json(self, cache): |  | ||||||
|         return self.get_data() |  | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def max_cookie_size(self): |  | ||||||
|         """Read-only view of the :data:`MAX_COOKIE_SIZE` config key. |  | ||||||
| 
 |  | ||||||
|         See :attr:`~werkzeug.wrappers.BaseResponse.max_cookie_size` in |  | ||||||
|         Werkzeug's docs. |  | ||||||
|         """ |  | ||||||
|         if current_app: |  | ||||||
|             return current_app.config['MAX_COOKIE_SIZE'] |  | ||||||
| 
 |  | ||||||
|         # return Werkzeug's default when not in an app context |  | ||||||
|         return super(Response, self).max_cookie_size |  | ||||||
| @ -1 +0,0 @@ | |||||||
| pip |  | ||||||
| @ -1,23 +0,0 @@ | |||||||
| 2009-2018 (c) Benoît Chesneau <benoitc@e-engura.org> |  | ||||||
| 2009-2015 (c) Paul J. Davis <paul.joseph.davis@gmail.com> |  | ||||||
| 
 |  | ||||||
| Permission is hereby granted, free of charge, to any person |  | ||||||
| obtaining a copy of this software and associated documentation |  | ||||||
| files (the "Software"), to deal in the Software without |  | ||||||
| restriction, including without limitation the rights to use, |  | ||||||
| copy, modify, merge, publish, distribute, sublicense, and/or sell |  | ||||||
| copies of the Software, and to permit persons to whom the |  | ||||||
| Software is furnished to do so, subject to the following |  | ||||||
| conditions: |  | ||||||
| 
 |  | ||||||
| The above copyright notice and this permission notice shall be |  | ||||||
| included in all copies or substantial portions of the Software. |  | ||||||
| 
 |  | ||||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |  | ||||||
| EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES |  | ||||||
| OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |  | ||||||
| NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |  | ||||||
| HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |  | ||||||
| WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |  | ||||||
| FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |  | ||||||
| OTHER DEALINGS IN THE SOFTWARE. |  | ||||||
| @ -1,111 +0,0 @@ | |||||||
| Metadata-Version: 2.1 |  | ||||||
| Name: gunicorn |  | ||||||
| Version: 19.8.1 |  | ||||||
| Summary: WSGI HTTP Server for UNIX |  | ||||||
| Home-page: http://gunicorn.org |  | ||||||
| Author: Benoit Chesneau |  | ||||||
| Author-email: benoitc@e-engura.com |  | ||||||
| License: MIT |  | ||||||
| Platform: UNKNOWN |  | ||||||
| Classifier: Development Status :: 4 - Beta |  | ||||||
| Classifier: Environment :: Other Environment |  | ||||||
| Classifier: Intended Audience :: Developers |  | ||||||
| Classifier: License :: OSI Approved :: MIT License |  | ||||||
| Classifier: Operating System :: MacOS :: MacOS X |  | ||||||
| Classifier: Operating System :: POSIX |  | ||||||
| Classifier: Programming Language :: Python |  | ||||||
| Classifier: Programming Language :: Python :: 2 |  | ||||||
| Classifier: Programming Language :: Python :: 2.6 |  | ||||||
| Classifier: Programming Language :: Python :: 2.7 |  | ||||||
| Classifier: Programming Language :: Python :: 3 |  | ||||||
| Classifier: Programming Language :: Python :: 3.2 |  | ||||||
| Classifier: Programming Language :: Python :: 3.3 |  | ||||||
| Classifier: Programming Language :: Python :: 3.4 |  | ||||||
| Classifier: Programming Language :: Python :: 3.5 |  | ||||||
| Classifier: Programming Language :: Python :: 3.6 |  | ||||||
| Classifier: Topic :: Internet |  | ||||||
| Classifier: Topic :: Utilities |  | ||||||
| Classifier: Topic :: Software Development :: Libraries :: Python Modules |  | ||||||
| Classifier: Topic :: Internet :: WWW/HTTP |  | ||||||
| Classifier: Topic :: Internet :: WWW/HTTP :: WSGI |  | ||||||
| Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Server |  | ||||||
| Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content |  | ||||||
| Requires-Python: >=2.6, !=3.0.*, !=3.1.* |  | ||||||
| Provides-Extra: gevent |  | ||||||
| Provides-Extra: tornado |  | ||||||
| Provides-Extra: eventlet |  | ||||||
| Provides-Extra: gthread |  | ||||||
| Provides-Extra: eventlet |  | ||||||
| Requires-Dist: eventlet (>=0.9.7); extra == 'eventlet' |  | ||||||
| Provides-Extra: gevent |  | ||||||
| Requires-Dist: gevent (>=0.13); extra == 'gevent' |  | ||||||
| Provides-Extra: gthread |  | ||||||
| Provides-Extra: tornado |  | ||||||
| Requires-Dist: tornado (>=0.2); extra == 'tornado' |  | ||||||
| 
 |  | ||||||
| Gunicorn |  | ||||||
| -------- |  | ||||||
| 
 |  | ||||||
| .. image:: https://img.shields.io/pypi/v/gunicorn.svg?style=flat |  | ||||||
|     :alt: PyPI version |  | ||||||
|     :target: https://pypi.python.org/pypi/gunicorn |  | ||||||
| 
 |  | ||||||
| .. image:: https://img.shields.io/pypi/pyversions/gunicorn.svg |  | ||||||
|     :alt: Supported Python versions |  | ||||||
|     :target: https://pypi.python.org/pypi/gunicorn |  | ||||||
| 
 |  | ||||||
| .. image:: https://travis-ci.org/benoitc/gunicorn.svg?branch=master |  | ||||||
|     :alt: Build Status |  | ||||||
|     :target: https://travis-ci.org/benoitc/gunicorn |  | ||||||
| 
 |  | ||||||
| Gunicorn 'Green Unicorn' is a Python WSGI HTTP Server for UNIX. It's a pre-fork |  | ||||||
| worker model ported from Ruby's Unicorn_ project. The Gunicorn server is broadly |  | ||||||
| compatible with various web frameworks, simply implemented, light on server |  | ||||||
| resource usage, and fairly speedy. |  | ||||||
| 
 |  | ||||||
| Feel free to join us in `#gunicorn`_ on Freenode_. |  | ||||||
| 
 |  | ||||||
| Documentation |  | ||||||
| ------------- |  | ||||||
| 
 |  | ||||||
| The documentation is hosted at http://docs.gunicorn.org. |  | ||||||
| 
 |  | ||||||
| Installation |  | ||||||
| ------------ |  | ||||||
| 
 |  | ||||||
| Gunicorn requires **Python 2.x >= 2.6** or **Python 3.x >= 3.2**. |  | ||||||
| 
 |  | ||||||
| Install from PyPI:: |  | ||||||
| 
 |  | ||||||
|     $ pip install gunicorn |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| Usage |  | ||||||
| ----- |  | ||||||
| 
 |  | ||||||
| Basic usage:: |  | ||||||
| 
 |  | ||||||
|     $ gunicorn [OPTIONS] APP_MODULE |  | ||||||
| 
 |  | ||||||
| Where ``APP_MODULE`` is of the pattern ``$(MODULE_NAME):$(VARIABLE_NAME)``. The |  | ||||||
| module name can be a full dotted path. The variable name refers to a WSGI |  | ||||||
| callable that should be found in the specified module. |  | ||||||
| 
 |  | ||||||
| Example with test app:: |  | ||||||
| 
 |  | ||||||
|     $ cd examples |  | ||||||
|     $ gunicorn --workers=2 test:app |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| License |  | ||||||
| ------- |  | ||||||
| 
 |  | ||||||
| Gunicorn is released under the MIT License. See the LICENSE_ file for more |  | ||||||
| details. |  | ||||||
| 
 |  | ||||||
| .. _Unicorn: https://bogomips.org/unicorn/ |  | ||||||
| .. _`#gunicorn`: https://webchat.freenode.net/?channels=gunicorn |  | ||||||
| .. _Freenode: https://freenode.net/ |  | ||||||
| .. _LICENSE: https://github.com/benoitc/gunicorn/blob/master/LICENSE |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| @ -1,88 +0,0 @@ | |||||||
| gunicorn/__init__.py,sha256=Y1BlVaRVNjIKXqSzcqTNHo9dq2eG6kgPx5jWJ3h5GRE,255 |  | ||||||
| gunicorn/_compat.py,sha256=5cXb6vMfVzInDq-AHNyZfsK-UG5NetDn62nPfqylHSU,9355 |  | ||||||
| gunicorn/arbiter.py,sha256=AbJNSFnTmx9Qd-vZAqEH3y5fz8ydPmyli_BERNIwdyE,20158 |  | ||||||
| gunicorn/argparse_compat.py,sha256=gsHDGwo4BSJWHdiaEXy0Emr96NKC0LDYmK5nB7PE8Qc,87791 |  | ||||||
| gunicorn/config.py,sha256=HDoWZ0JyoPzl2WW6hlDatDevvhfah4oS_j7tOq8Pa7E,53417 |  | ||||||
| gunicorn/debug.py,sha256=UUw-eteLEm_OQ98D6K3XtDjx4Dya2H35zdiu8z7F7uc,2289 |  | ||||||
| gunicorn/errors.py,sha256=JlDBjag90gMiRwLHG3xzEJzDOntSl1iM32R277-U6j0,919 |  | ||||||
| gunicorn/glogging.py,sha256=PMdoe6hdBQWKGlnP4lXdBph6b1ygD0kknxkDsmNIVSU,15554 |  | ||||||
| gunicorn/pidfile.py,sha256=_69tsfF1aHklrMrJe2sHERovMduRByVTv99my7yQ874,2357 |  | ||||||
| gunicorn/reloader.py,sha256=fh4J7w_DxWaFuFd3G4RyOgDFs1C1lrd0w7jOXItSu5g,3791 |  | ||||||
| gunicorn/selectors.py,sha256=14_UESrpE3AQKXWKeeAUG9vBTzJ0yTYDGtEo6xOtlDY,18997 |  | ||||||
| gunicorn/six.py,sha256=6N-6RCENPfBtMpN5UmgDfDKmJebbbuPu_Dk3Zf8ngww,27344 |  | ||||||
| gunicorn/sock.py,sha256=gX2FsdsOGMCtSHbDXn7lsiYYYRc3roQklIJLip1oZQo,6019 |  | ||||||
| gunicorn/systemd.py,sha256=ffhv17cdv-hDeFAJi1eAVtJskkVciV6cQU75Q2oplqg,1362 |  | ||||||
| gunicorn/util.py,sha256=Ns_a8Pf7MkaEi0KbV3GsP9aVQ2a_S45EjSE6Iyg2tYU,16229 |  | ||||||
| gunicorn/app/__init__.py,sha256=GuqstqdkizeV4HRbd8aGMBn0Q8IDOyRU1wMMNqNe5GY,127 |  | ||||||
| gunicorn/app/base.py,sha256=LKxyziLMPNlK3qm6dPMieELBqfLfmwBFnn9SB-KBogE,6652 |  | ||||||
| gunicorn/app/pasterapp.py,sha256=AGzZnUpcpw8O8KrizxTgdJBZ4lQdrHgsV0gdx7FVTs8,6046 |  | ||||||
| gunicorn/app/wsgiapp.py,sha256=ny71qjegQHl_bGMjNfq_aemPrmGEpH2bMRIdph6bj4Q,1870 |  | ||||||
| gunicorn/http/__init__.py,sha256=b4TF3x5F0VYOPTOeNYwRGR1EYHBaPMhZRMoNeuD5-n0,277 |  | ||||||
| gunicorn/http/_sendfile.py,sha256=Eqd-s3HlvLuyfGjqaH_Jk72cAtEV8hQv5tb1M1AqcBU,2217 |  | ||||||
| gunicorn/http/body.py,sha256=MmlZpj_6oRPj3oPVSMQZr0X3KH6ikntxDnVcLgfekZs,7345 |  | ||||||
| gunicorn/http/errors.py,sha256=sNjF2lm4m2qyZ9l95_U33FRxPXpxXzjnZyYqWS-hxd4,2850 |  | ||||||
| gunicorn/http/message.py,sha256=G5po0upwbrTyIggb_IEAItIjSi_aDoWYLPQ62o8pOI4,12257 |  | ||||||
| gunicorn/http/parser.py,sha256=IRMvp0veP4wL8Z4vgNV72CPydCNPdNNIy9u-DlDvvSo,1294 |  | ||||||
| gunicorn/http/unreader.py,sha256=s4kDW5euiJPsDuHzCqFXUtHCApqIxpShb9dtAyjJw9Y,2019 |  | ||||||
| gunicorn/http/wsgi.py,sha256=_5zYFl5HGKrPpEMrEnsLyPreOJcTgaYzsEBuJkEOmko,12852 |  | ||||||
| gunicorn/instrument/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 |  | ||||||
| gunicorn/instrument/statsd.py,sha256=5xueDuTZMFtmS8ayGT4sU_OyB9qkEv4Agk-eJwAmhJM,4434 |  | ||||||
| gunicorn/workers/__init__.py,sha256=Z57G1WjnZDCG52C8PgiXF4mKRKqlv81b2GHkhOJiO6A,774 |  | ||||||
| gunicorn/workers/_gaiohttp.py,sha256=CFKiyLNqWqemhDvDovb-JqMRTMNz50gZUwwOpIjrpHw,5071 |  | ||||||
| gunicorn/workers/async.py,sha256=54VkS3S_wrFD7v3jInhFfkeBhaPnV5UN-cu-i5MoXkc,5575 |  | ||||||
| gunicorn/workers/base.py,sha256=eYdcy2EPlydcjyi2CpgeU0tqlJpz3_kt-RbGhoamvQ8,9126 |  | ||||||
| gunicorn/workers/gaiohttp.py,sha256=3rhXky6APkhI0D9nwXlogLo_Jd9v98CiEuCy9inzCU4,823 |  | ||||||
| gunicorn/workers/geventlet.py,sha256=L7N2bizKQw8VXb02teu1_wYVG5hwt9SSaQn7J0kSKyI,4253 |  | ||||||
| gunicorn/workers/ggevent.py,sha256=hzx2kOZP13yVBz-EBthoTgjalOeRKfoUk5XchmRKzDM,7407 |  | ||||||
| gunicorn/workers/gthread.py,sha256=HIoWuylHZfH1wlSh4eZ8wxo1kQ5abvdUaFfKfIsgQvI,12009 |  | ||||||
| gunicorn/workers/gtornado.py,sha256=LtBWnEX7MNpeGX-YmlBoV1_OOhjkdytFmt1pzOlRPZk,5044 |  | ||||||
| gunicorn/workers/sync.py,sha256=_vd1JATNLG4MgJppNJG5KWBIzLGYqRzhEAQVz9H11LI,7153 |  | ||||||
| gunicorn/workers/workertmp.py,sha256=6QINPBrriLvezgkC_hclOOeXLi_owMt_SOA5KPEIN-A,1459 |  | ||||||
| gunicorn-19.8.1.dist-info/LICENSE.txt,sha256=eJ_hG5Lhyr-890S1_MOSyb1cZ5hgOk6J-SW2M3mE0d8,1136 |  | ||||||
| gunicorn-19.8.1.dist-info/METADATA,sha256=w9Od3TWYwIXsx_CAyLy5OZ1h5v9C_T0_mhK9psl1x5Q,3388 |  | ||||||
| gunicorn-19.8.1.dist-info/RECORD,, |  | ||||||
| gunicorn-19.8.1.dist-info/WHEEL,sha256=J3CsTk7Mf2JNUyhImI-mjX-fmI4oDjyiXgWT4qgZiCE,110 |  | ||||||
| gunicorn-19.8.1.dist-info/entry_points.txt,sha256=XeFINKRdSUKwJwaVSolO24PuV_YeO71IMF-rOra5JO8,184 |  | ||||||
| gunicorn-19.8.1.dist-info/top_level.txt,sha256=cdMaa2yhxb8do-WioY9qRHUCfwf55YztjwQCncaInoE,9 |  | ||||||
| ../../../bin/gunicorn,sha256=3n02jiI_1KSuGRVnArdMBsMwXwNk9qYNxest7n5NCtA,226 |  | ||||||
| ../../../bin/gunicorn_paster,sha256=VpfTHNYpEn2RVEjyLdmq1-_lArYY2joHAgAlGrbIjeg,228 |  | ||||||
| gunicorn-19.8.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 |  | ||||||
| gunicorn/debug.pyc,, |  | ||||||
| gunicorn/workers/sync.pyc,, |  | ||||||
| gunicorn/http/wsgi.pyc,, |  | ||||||
| gunicorn/workers/async.pyc,, |  | ||||||
| gunicorn/workers/workertmp.pyc,, |  | ||||||
| gunicorn/http/message.pyc,, |  | ||||||
| gunicorn/instrument/__init__.pyc,, |  | ||||||
| gunicorn/http/unreader.pyc,, |  | ||||||
| gunicorn/app/__init__.pyc,, |  | ||||||
| gunicorn/systemd.pyc,, |  | ||||||
| gunicorn/config.pyc,, |  | ||||||
| gunicorn/workers/base.pyc,, |  | ||||||
| gunicorn/app/wsgiapp.pyc,, |  | ||||||
| gunicorn/workers/gaiohttp.pyc,, |  | ||||||
| gunicorn/app/base.pyc,, |  | ||||||
| gunicorn/arbiter.pyc,, |  | ||||||
| gunicorn/workers/ggevent.pyc,, |  | ||||||
| gunicorn/http/errors.pyc,, |  | ||||||
| gunicorn/workers/gtornado.pyc,, |  | ||||||
| gunicorn/six.pyc,, |  | ||||||
| gunicorn/http/__init__.pyc,, |  | ||||||
| gunicorn/pidfile.pyc,, |  | ||||||
| gunicorn/workers/gthread.pyc,, |  | ||||||
| gunicorn/_compat.pyc,, |  | ||||||
| gunicorn/errors.pyc,, |  | ||||||
| gunicorn/http/body.pyc,, |  | ||||||
| gunicorn/instrument/statsd.pyc,, |  | ||||||
| gunicorn/__init__.pyc,, |  | ||||||
| gunicorn/http/parser.pyc,, |  | ||||||
| gunicorn/selectors.pyc,, |  | ||||||
| gunicorn/sock.pyc,, |  | ||||||
| gunicorn/reloader.pyc,, |  | ||||||
| gunicorn/workers/__init__.pyc,, |  | ||||||
| gunicorn/argparse_compat.pyc,, |  | ||||||
| gunicorn/glogging.pyc,, |  | ||||||
| gunicorn/http/_sendfile.pyc,, |  | ||||||
| gunicorn/workers/geventlet.pyc,, |  | ||||||
| gunicorn/util.pyc,, |  | ||||||
| gunicorn/app/pasterapp.pyc,, |  | ||||||
Some files were not shown because too many files have changed in this diff Show More
					Loading…
					
					
				
		Reference in new issue