Added virtual environment and directory structure
parent
249c5e9343
commit
7cb99cd04f
24
config.py
24
config.py
|
@ -1,6 +1,30 @@
|
||||||
# App configuration
|
# App configuration
|
||||||
DEBUG = False
|
DEBUG = False
|
||||||
|
|
||||||
|
# Define the application directory
|
||||||
|
import os
|
||||||
|
BASE_DIR = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
|
||||||
|
# Define the database - we are working with
|
||||||
|
# SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(BASE_DIR, 'app.db')
|
||||||
|
# DATABASE_CONNECT_OPTIONS = {}
|
||||||
|
|
||||||
|
# Application threads. A common general assumption is
|
||||||
|
# using 2 per available processor cores - to handle
|
||||||
|
# incoming requests using one and performing background
|
||||||
|
# operations using the other.
|
||||||
|
THREADS_PER_PAGE = 2
|
||||||
|
|
||||||
|
# Enable protection agains *Cross-site Request Forgery (CSRF)*
|
||||||
|
CSRF_ENABLED = True
|
||||||
|
|
||||||
|
# Use a secure, unique and absolutely secret key for
|
||||||
|
# signing the data.
|
||||||
|
CSRF_SESSION_KEY = "secret"
|
||||||
|
|
||||||
|
# Secret key for signing cookies
|
||||||
|
SECRET_KEY = "secret"
|
||||||
|
|
||||||
# MQTT configuration
|
# MQTT configuration
|
||||||
MQTT_BROKER_URL = 'mybroker.com'
|
MQTT_BROKER_URL = 'mybroker.com'
|
||||||
MQTT_BROKER_PORT = 1883
|
MQTT_BROKER_PORT = 1883
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/Python
|
|
@ -0,0 +1 @@
|
||||||
|
/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/include/python3.6m
|
|
@ -0,0 +1 @@
|
||||||
|
/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/__future__.py
|
|
@ -0,0 +1 @@
|
||||||
|
/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/_bootlocale.py
|
|
@ -0,0 +1 @@
|
||||||
|
/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/_collections_abc.py
|
|
@ -0,0 +1 @@
|
||||||
|
/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/_dummy_thread.py
|
|
@ -0,0 +1 @@
|
||||||
|
/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/_weakrefset.py
|
|
@ -0,0 +1 @@
|
||||||
|
/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/abc.py
|
|
@ -0,0 +1 @@
|
||||||
|
/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/base64.py
|
|
@ -0,0 +1 @@
|
||||||
|
/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/bisect.py
|
|
@ -0,0 +1 @@
|
||||||
|
/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/codecs.py
|
|
@ -0,0 +1 @@
|
||||||
|
/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/collections
|
|
@ -0,0 +1 @@
|
||||||
|
/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/config-3.6m-darwin
|
|
@ -0,0 +1 @@
|
||||||
|
/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/copy.py
|
|
@ -0,0 +1 @@
|
||||||
|
/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/copyreg.py
|
|
@ -0,0 +1,101 @@
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import warnings
|
||||||
|
import imp
|
||||||
|
import opcode # opcode is not a virtualenv module, so we can use it to find the stdlib
|
||||||
|
# Important! To work on pypy, this must be a module that resides in the
|
||||||
|
# lib-python/modified-x.y.z directory
|
||||||
|
|
||||||
|
dirname = os.path.dirname
|
||||||
|
|
||||||
|
distutils_path = os.path.join(os.path.dirname(opcode.__file__), 'distutils')
|
||||||
|
if os.path.normpath(distutils_path) == os.path.dirname(os.path.normpath(__file__)):
|
||||||
|
warnings.warn(
|
||||||
|
"The virtualenv distutils package at %s appears to be in the same location as the system distutils?")
|
||||||
|
else:
|
||||||
|
__path__.insert(0, distutils_path)
|
||||||
|
real_distutils = imp.load_module("_virtualenv_distutils", None, distutils_path, ('', '', imp.PKG_DIRECTORY))
|
||||||
|
# Copy the relevant attributes
|
||||||
|
try:
|
||||||
|
__revision__ = real_distutils.__revision__
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
__version__ = real_distutils.__version__
|
||||||
|
|
||||||
|
from distutils import dist, sysconfig
|
||||||
|
|
||||||
|
try:
|
||||||
|
basestring
|
||||||
|
except NameError:
|
||||||
|
basestring = str
|
||||||
|
|
||||||
|
## patch build_ext (distutils doesn't know how to get the libs directory
|
||||||
|
## path on windows - it hardcodes the paths around the patched sys.prefix)
|
||||||
|
|
||||||
|
if sys.platform == 'win32':
|
||||||
|
from distutils.command.build_ext import build_ext as old_build_ext
|
||||||
|
class build_ext(old_build_ext):
|
||||||
|
def finalize_options (self):
|
||||||
|
if self.library_dirs is None:
|
||||||
|
self.library_dirs = []
|
||||||
|
elif isinstance(self.library_dirs, basestring):
|
||||||
|
self.library_dirs = self.library_dirs.split(os.pathsep)
|
||||||
|
|
||||||
|
self.library_dirs.insert(0, os.path.join(sys.real_prefix, "Libs"))
|
||||||
|
old_build_ext.finalize_options(self)
|
||||||
|
|
||||||
|
from distutils.command import build_ext as build_ext_module
|
||||||
|
build_ext_module.build_ext = build_ext
|
||||||
|
|
||||||
|
## distutils.dist patches:
|
||||||
|
|
||||||
|
old_find_config_files = dist.Distribution.find_config_files
|
||||||
|
def find_config_files(self):
|
||||||
|
found = old_find_config_files(self)
|
||||||
|
system_distutils = os.path.join(distutils_path, 'distutils.cfg')
|
||||||
|
#if os.path.exists(system_distutils):
|
||||||
|
# found.insert(0, system_distutils)
|
||||||
|
# What to call the per-user config file
|
||||||
|
if os.name == 'posix':
|
||||||
|
user_filename = ".pydistutils.cfg"
|
||||||
|
else:
|
||||||
|
user_filename = "pydistutils.cfg"
|
||||||
|
user_filename = os.path.join(sys.prefix, user_filename)
|
||||||
|
if os.path.isfile(user_filename):
|
||||||
|
for item in list(found):
|
||||||
|
if item.endswith('pydistutils.cfg'):
|
||||||
|
found.remove(item)
|
||||||
|
found.append(user_filename)
|
||||||
|
return found
|
||||||
|
dist.Distribution.find_config_files = find_config_files
|
||||||
|
|
||||||
|
## distutils.sysconfig patches:
|
||||||
|
|
||||||
|
old_get_python_inc = sysconfig.get_python_inc
|
||||||
|
def sysconfig_get_python_inc(plat_specific=0, prefix=None):
|
||||||
|
if prefix is None:
|
||||||
|
prefix = sys.real_prefix
|
||||||
|
return old_get_python_inc(plat_specific, prefix)
|
||||||
|
sysconfig_get_python_inc.__doc__ = old_get_python_inc.__doc__
|
||||||
|
sysconfig.get_python_inc = sysconfig_get_python_inc
|
||||||
|
|
||||||
|
old_get_python_lib = sysconfig.get_python_lib
|
||||||
|
def sysconfig_get_python_lib(plat_specific=0, standard_lib=0, prefix=None):
|
||||||
|
if standard_lib and prefix is None:
|
||||||
|
prefix = sys.real_prefix
|
||||||
|
return old_get_python_lib(plat_specific, standard_lib, prefix)
|
||||||
|
sysconfig_get_python_lib.__doc__ = old_get_python_lib.__doc__
|
||||||
|
sysconfig.get_python_lib = sysconfig_get_python_lib
|
||||||
|
|
||||||
|
old_get_config_vars = sysconfig.get_config_vars
|
||||||
|
def sysconfig_get_config_vars(*args):
|
||||||
|
real_vars = old_get_config_vars(*args)
|
||||||
|
if sys.platform == 'win32':
|
||||||
|
lib_dir = os.path.join(sys.real_prefix, "libs")
|
||||||
|
if isinstance(real_vars, dict) and 'LIBDIR' not in real_vars:
|
||||||
|
real_vars['LIBDIR'] = lib_dir # asked for all
|
||||||
|
elif isinstance(real_vars, list) and 'LIBDIR' in args:
|
||||||
|
real_vars = real_vars + [lib_dir] # asked for list
|
||||||
|
return real_vars
|
||||||
|
sysconfig_get_config_vars.__doc__ = old_get_config_vars.__doc__
|
||||||
|
sysconfig.get_config_vars = sysconfig_get_config_vars
|
|
@ -0,0 +1,6 @@
|
||||||
|
# This is a config file local to this virtualenv installation
|
||||||
|
# You may include options that will be used by all distutils commands,
|
||||||
|
# and by easy_install. For instance:
|
||||||
|
#
|
||||||
|
# [easy_install]
|
||||||
|
# find_links = http://mylocalsite
|
|
@ -0,0 +1 @@
|
||||||
|
/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/encodings
|
|
@ -0,0 +1 @@
|
||||||
|
/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/enum.py
|
|
@ -0,0 +1 @@
|
||||||
|
/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/fnmatch.py
|
|
@ -0,0 +1 @@
|
||||||
|
/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/functools.py
|
|
@ -0,0 +1 @@
|
||||||
|
/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/genericpath.py
|
|
@ -0,0 +1 @@
|
||||||
|
/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/hashlib.py
|
|
@ -0,0 +1 @@
|
||||||
|
/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/heapq.py
|
|
@ -0,0 +1 @@
|
||||||
|
/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/hmac.py
|
|
@ -0,0 +1 @@
|
||||||
|
/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/imp.py
|
|
@ -0,0 +1 @@
|
||||||
|
/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/importlib
|
|
@ -0,0 +1 @@
|
||||||
|
/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/io.py
|
|
@ -0,0 +1 @@
|
||||||
|
/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/keyword.py
|
|
@ -0,0 +1 @@
|
||||||
|
/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/lib-dynload
|
|
@ -0,0 +1 @@
|
||||||
|
/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/linecache.py
|
|
@ -0,0 +1 @@
|
||||||
|
/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/locale.py
|
|
@ -0,0 +1 @@
|
||||||
|
/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/ntpath.py
|
|
@ -0,0 +1 @@
|
||||||
|
/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/operator.py
|
|
@ -0,0 +1 @@
|
||||||
|
/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6
|
|
@ -0,0 +1 @@
|
||||||
|
/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/os.py
|
|
@ -0,0 +1 @@
|
||||||
|
/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/posixpath.py
|
|
@ -0,0 +1 @@
|
||||||
|
/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/random.py
|
|
@ -0,0 +1 @@
|
||||||
|
/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/re.py
|
|
@ -0,0 +1 @@
|
||||||
|
/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/reprlib.py
|
|
@ -0,0 +1 @@
|
||||||
|
/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/rlcompleter.py
|
|
@ -0,0 +1 @@
|
||||||
|
/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/shutil.py
|
|
@ -0,0 +1,46 @@
|
||||||
|
Flask
|
||||||
|
-----
|
||||||
|
|
||||||
|
Flask is a microframework for Python based on Werkzeug, Jinja 2 and good
|
||||||
|
intentions. And before you ask: It's BSD licensed!
|
||||||
|
|
||||||
|
Flask is Fun
|
||||||
|
````````````
|
||||||
|
|
||||||
|
Save in a hello.py:
|
||||||
|
|
||||||
|
.. code:: python
|
||||||
|
|
||||||
|
from flask import Flask
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
@app.route("/")
|
||||||
|
def hello():
|
||||||
|
return "Hello World!"
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app.run()
|
||||||
|
|
||||||
|
And Easy to Setup
|
||||||
|
`````````````````
|
||||||
|
|
||||||
|
And run it:
|
||||||
|
|
||||||
|
.. code:: bash
|
||||||
|
|
||||||
|
$ pip install Flask
|
||||||
|
$ python hello.py
|
||||||
|
* Running on http://localhost:5000/
|
||||||
|
|
||||||
|
Ready for production? `Read this first <http://flask.pocoo.org/docs/deploying/>`.
|
||||||
|
|
||||||
|
Links
|
||||||
|
`````
|
||||||
|
|
||||||
|
* `website <http://flask.pocoo.org/>`_
|
||||||
|
* `documentation <http://flask.pocoo.org/docs/>`_
|
||||||
|
* `development version
|
||||||
|
<http://github.com/pallets/flask/zipball/master#egg=Flask-dev>`_
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
pip
|
|
@ -0,0 +1,33 @@
|
||||||
|
Copyright (c) 2015 by Armin Ronacher and contributors. See AUTHORS
|
||||||
|
for more details.
|
||||||
|
|
||||||
|
Some rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms of the software as well
|
||||||
|
as documentation, 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 AND DOCUMENTATION 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 AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||||
|
DAMAGE.
|
|
@ -0,0 +1,75 @@
|
||||||
|
Metadata-Version: 2.0
|
||||||
|
Name: Flask
|
||||||
|
Version: 0.12.2
|
||||||
|
Summary: A microframework based on Werkzeug, Jinja2 and good intentions
|
||||||
|
Home-page: http://github.com/pallets/flask/
|
||||||
|
Author: Armin Ronacher
|
||||||
|
Author-email: armin.ronacher@active-4.com
|
||||||
|
License: BSD
|
||||||
|
Platform: any
|
||||||
|
Classifier: Development Status :: 4 - Beta
|
||||||
|
Classifier: Environment :: Web Environment
|
||||||
|
Classifier: Intended Audience :: Developers
|
||||||
|
Classifier: License :: OSI Approved :: BSD License
|
||||||
|
Classifier: Operating System :: OS Independent
|
||||||
|
Classifier: Programming Language :: Python
|
||||||
|
Classifier: Programming Language :: Python :: 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
|
||||||
|
Requires-Dist: Jinja2 (>=2.4)
|
||||||
|
Requires-Dist: Werkzeug (>=0.7)
|
||||||
|
Requires-Dist: click (>=2.0)
|
||||||
|
Requires-Dist: itsdangerous (>=0.21)
|
||||||
|
|
||||||
|
Flask
|
||||||
|
-----
|
||||||
|
|
||||||
|
Flask is a microframework for Python based on Werkzeug, Jinja 2 and good
|
||||||
|
intentions. And before you ask: It's BSD licensed!
|
||||||
|
|
||||||
|
Flask is Fun
|
||||||
|
````````````
|
||||||
|
|
||||||
|
Save in a hello.py:
|
||||||
|
|
||||||
|
.. code:: python
|
||||||
|
|
||||||
|
from flask import Flask
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
@app.route("/")
|
||||||
|
def hello():
|
||||||
|
return "Hello World!"
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app.run()
|
||||||
|
|
||||||
|
And Easy to Setup
|
||||||
|
`````````````````
|
||||||
|
|
||||||
|
And run it:
|
||||||
|
|
||||||
|
.. code:: bash
|
||||||
|
|
||||||
|
$ pip install Flask
|
||||||
|
$ python hello.py
|
||||||
|
* Running on http://localhost:5000/
|
||||||
|
|
||||||
|
Ready for production? `Read this first <http://flask.pocoo.org/docs/deploying/>`.
|
||||||
|
|
||||||
|
Links
|
||||||
|
`````
|
||||||
|
|
||||||
|
* `website <http://flask.pocoo.org/>`_
|
||||||
|
* `documentation <http://flask.pocoo.org/docs/>`_
|
||||||
|
* `development version
|
||||||
|
<http://github.com/pallets/flask/zipball/master#egg=Flask-dev>`_
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
Flask-0.12.2.dist-info/DESCRIPTION.rst,sha256=DmJm8IBlBjl3wkm0Ly23jYvWbvK_mCuE5oUseYCijbI,810
|
||||||
|
Flask-0.12.2.dist-info/LICENSE.txt,sha256=hLgKluMRHSnxG-L0EmrqjmKgG5cHlff6pIh3rCNINeI,1582
|
||||||
|
Flask-0.12.2.dist-info/METADATA,sha256=OgSkJQ_kmrz4qEkS-OzYtL75uZmXAThymkOcGR4kXRQ,1948
|
||||||
|
Flask-0.12.2.dist-info/RECORD,,
|
||||||
|
Flask-0.12.2.dist-info/WHEEL,sha256=o2k-Qa-RMNIJmUdIc7KU6VWR_ErNRbWNlxDIpl7lm34,110
|
||||||
|
Flask-0.12.2.dist-info/entry_points.txt,sha256=jzk2Wy2h30uEcqqzd4CVnlzsMXB-vaD5GXjuPMXmTmI,60
|
||||||
|
Flask-0.12.2.dist-info/metadata.json,sha256=By8kZ1vY9lLEAGnRiWNBhudqKvLPo0HkZVXTYECyPKk,1389
|
||||||
|
Flask-0.12.2.dist-info/top_level.txt,sha256=dvi65F6AeGWVU0TBpYiC04yM60-FX1gJFkK31IKQr5c,6
|
||||||
|
flask/__init__.py,sha256=sHdK1v6WRbVmCN0fEv990EE7rOT2UlamQkSof2d0Dt0,1673
|
||||||
|
flask/__main__.py,sha256=cldbNi5zpjE68XzIWI8uYHNWwBHHVJmwtlXWk6P4CO4,291
|
||||||
|
flask/_compat.py,sha256=VlfjUuLjufsTHJIjr_ZsnnOesSbAXIslBBgRe5tfOok,2802
|
||||||
|
flask/app.py,sha256=6DPjtb5jUJWgL5fXksG5boA49EB3l-k9pWyftitbNNk,83169
|
||||||
|
flask/blueprints.py,sha256=6HVasMcPcaq7tk36kCrgX4bnhTkky4G5WIWCyyJL8HY,16872
|
||||||
|
flask/cli.py,sha256=2NXEdCOu5-4ymklxX4Lf6bjb-89I4VHYeP6xScR3i8E,18328
|
||||||
|
flask/config.py,sha256=Ym5Jenyu6zAZ1fdVLeKekY9-EsKmq8183qnRgauwCMY,9905
|
||||||
|
flask/ctx.py,sha256=UPA0YwoIlHP0txOGanC9lQLSGv6eCqV5Fmw2cVJRmgQ,14739
|
||||||
|
flask/debughelpers.py,sha256=z-uQavKIymOZl0WQDLXsnacA00ERIlCx3S3Tnb_OYsE,6024
|
||||||
|
flask/exthook.py,sha256=SvXs5jwpcOjogwJ7SNquiWTxowoN1-MHFoqAejWnk2o,5762
|
||||||
|
flask/globals.py,sha256=I3m_4RssLhWW1R11zuEI8oFryHUHX3NQwjMkGXOZzg8,1645
|
||||||
|
flask/helpers.py,sha256=KrsQ2Yo3lOVHvBTgQCLvpubgmTOpQdTTyiCOOYlwDuQ,38452
|
||||||
|
flask/json.py,sha256=1zPM-NPLiWoOfGd0P14FxnEkeKtjtUZxMC9pyYyDBYI,9183
|
||||||
|
flask/logging.py,sha256=UG-77jPkRClk9w1B-_ArjjXPuj9AmZz9mG0IRGvptW0,2751
|
||||||
|
flask/sessions.py,sha256=QBKXVYKJ-HKbx9m6Yb5yan_EPq84a5yevVLgAzNKFQY,14394
|
||||||
|
flask/signals.py,sha256=MfZk5qTRj_R_O3aGYlTEnx2g3SvlZncz8Ii73eKK59g,2209
|
||||||
|
flask/templating.py,sha256=u7FbN6j56H_q6CrdJJyJ6gZtqaMa0vh1_GP12gEHRQQ,4912
|
||||||
|
flask/testing.py,sha256=II8EO_NjOT1LvL8Hh_SdIFL_BdlwVPcB9yot5pbltxE,5630
|
||||||
|
flask/views.py,sha256=6OPv7gwu3h14JhqpeeMRWwrxoGHsUr4_nOGSyTRAxAI,5630
|
||||||
|
flask/wrappers.py,sha256=1S_5mmuA1Tlx7D9lXV6xMblrg-PdAauNWahe-henMEE,7612
|
||||||
|
flask/ext/__init__.py,sha256=UEezCApsG4ZJWqwUnX9YmWcNN4OVENgph_9L05n0eOM,842
|
||||||
|
../../../bin/flask,sha256=1ow220Ff1jdiAk6Kq--IP8c1BYJdNqtYXFLTS5ul3yA,266
|
||||||
|
Flask-0.12.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||||
|
flask/ext/__pycache__/__init__.cpython-36.pyc,,
|
||||||
|
flask/__pycache__/blueprints.cpython-36.pyc,,
|
||||||
|
flask/__pycache__/logging.cpython-36.pyc,,
|
||||||
|
flask/__pycache__/sessions.cpython-36.pyc,,
|
||||||
|
flask/__pycache__/templating.cpython-36.pyc,,
|
||||||
|
flask/__pycache__/cli.cpython-36.pyc,,
|
||||||
|
flask/__pycache__/config.cpython-36.pyc,,
|
||||||
|
flask/__pycache__/signals.cpython-36.pyc,,
|
||||||
|
flask/__pycache__/testing.cpython-36.pyc,,
|
||||||
|
flask/__pycache__/views.cpython-36.pyc,,
|
||||||
|
flask/__pycache__/ctx.cpython-36.pyc,,
|
||||||
|
flask/__pycache__/app.cpython-36.pyc,,
|
||||||
|
flask/__pycache__/exthook.cpython-36.pyc,,
|
||||||
|
flask/__pycache__/__main__.cpython-36.pyc,,
|
||||||
|
flask/__pycache__/_compat.cpython-36.pyc,,
|
||||||
|
flask/__pycache__/helpers.cpython-36.pyc,,
|
||||||
|
flask/__pycache__/wrappers.cpython-36.pyc,,
|
||||||
|
flask/__pycache__/__init__.cpython-36.pyc,,
|
||||||
|
flask/__pycache__/debughelpers.cpython-36.pyc,,
|
||||||
|
flask/__pycache__/globals.cpython-36.pyc,,
|
||||||
|
flask/__pycache__/json.cpython-36.pyc,,
|
|
@ -0,0 +1,6 @@
|
||||||
|
Wheel-Version: 1.0
|
||||||
|
Generator: bdist_wheel (0.29.0)
|
||||||
|
Root-Is-Purelib: true
|
||||||
|
Tag: py2-none-any
|
||||||
|
Tag: py3-none-any
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
[console_scripts]
|
||||||
|
flask=flask.cli:main
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
{"classifiers": ["Development Status :: 4 - Beta", "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"], "extensions": {"python.commands": {"wrap_console": {"flask": "flask.cli:main"}}, "python.details": {"contacts": [{"email": "armin.ronacher@active-4.com", "name": "Armin Ronacher", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst", "license": "LICENSE.txt"}, "project_urls": {"Home": "http://github.com/pallets/flask/"}}, "python.exports": {"console_scripts": {"flask": "flask.cli:main"}}}, "extras": [], "generator": "bdist_wheel (0.29.0)", "license": "BSD", "metadata_version": "2.0", "name": "Flask", "platform": "any", "run_requires": [{"requires": ["Jinja2 (>=2.4)", "Werkzeug (>=0.7)", "click (>=2.0)", "itsdangerous (>=0.21)"]}], "summary": "A microframework based on Werkzeug, Jinja2 and good intentions", "version": "0.12.2"}
|
|
@ -0,0 +1 @@
|
||||||
|
flask
|
|
@ -0,0 +1,173 @@
|
||||||
|
# Flask-MQTT
|
||||||
|
|
||||||
|
Flask Extension for the [MQTT protocol][1]. Basically it is a thin wrapper
|
||||||
|
around [paho-mqtt][0] and aimes to simplify MQTT integration in Flask. MQTT is a
|
||||||
|
machine-to-machine "Internet of Things" protocol and was designed for extremely
|
||||||
|
lightweight publish/subscribe messaging transport.
|
||||||
|
|
||||||
|
[![Documentation Status](https://readthedocs.org/projects/flask-mqtt/badge/?version=latest)](http://flask-mqtt.readthedocs.io/en/latest/?badge=latest) [![PyPI version](https://badge.fury.io/py/Flask-MQTT.svg)](https://badge.fury.io/py/Flask-MQTT) [![Travis CI](https://travis-ci.org/stlehmann/Flask-MQTT.svg?branch=master)](https://travis-ci.org/stlehmann/Flask-MQTT.svg?branch=master)
|
||||||
|
|
||||||
|
Find the documentation on [http://flask-mqtt.readthedocs.io][2].
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
* configuration via Flask config variables
|
||||||
|
* auto-connect on start of your web application
|
||||||
|
* publish and subscribe messages
|
||||||
|
* use callbacks for certain topics
|
||||||
|
* use one callback for all subscribed topics
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Simply install the package as usual via pip:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ pip install flask-mqtt
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Basic Setup
|
||||||
|
|
||||||
|
```python
|
||||||
|
from flask import Flask
|
||||||
|
from flask_mqtt import Mqtt
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
app.config['MQTT_BROKER_URL'] = 'mybroker.com'
|
||||||
|
app.config['MQTT_BROKER_PORT'] = 1883
|
||||||
|
app.config['MQTT_USERNAME'] = 'user'
|
||||||
|
app.config['MQTT_PASSWORD'] = 'secret'
|
||||||
|
app.config['MQTT_REFRESH_TIME'] = 1.0 # refresh time in seconds
|
||||||
|
mqtt = Mqtt(app)
|
||||||
|
|
||||||
|
@app.route('/')
|
||||||
|
def index():
|
||||||
|
return render_template('index.html')
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Subscribe to a topic
|
||||||
|
|
||||||
|
To subscribe to a topic simply use `mqtt.subscribe()`. To make sure the
|
||||||
|
subscription gets handled correctly on startup place the subscription inside
|
||||||
|
an `on_connect()` callback function.
|
||||||
|
|
||||||
|
```python
|
||||||
|
@mqtt.on_connect()
|
||||||
|
def handle_connect(client, userdata, flags, rc):
|
||||||
|
mqtt.subscribe('home/mytopic')
|
||||||
|
```
|
||||||
|
|
||||||
|
To handle the subscribed messages you can define a handling function by
|
||||||
|
decorating it with `@mqtt.on_message()`.
|
||||||
|
|
||||||
|
```python
|
||||||
|
@mqtt.on_message()
|
||||||
|
def handle_mqtt_message(client, userdata, message):
|
||||||
|
data = dict(
|
||||||
|
topic=message.topic,
|
||||||
|
payload=message.payload.decode()
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
To unsubscribe do:
|
||||||
|
|
||||||
|
```python
|
||||||
|
mqtt.unsubscribe('home/mytopic')
|
||||||
|
```
|
||||||
|
|
||||||
|
Or if you want to unsubscribe all topics use `unsubscribe_all()`.
|
||||||
|
|
||||||
|
```python
|
||||||
|
mqtt.unsubscribe_all()
|
||||||
|
```
|
||||||
|
|
||||||
|
### Publish
|
||||||
|
|
||||||
|
To publish a message you can use the `publish()` method.
|
||||||
|
|
||||||
|
```python
|
||||||
|
mqtt.publish('home/mytopic', 'this is my message')
|
||||||
|
```
|
||||||
|
|
||||||
|
### Small publish/subscribe MQTT client
|
||||||
|
|
||||||
|
```python
|
||||||
|
"""
|
||||||
|
|
||||||
|
A small Test application to show how to use Flask-MQTT.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import eventlet
|
||||||
|
import json
|
||||||
|
from flask import Flask, render_template
|
||||||
|
from flask_mqtt import Mqtt
|
||||||
|
from flask_socketio import SocketIO
|
||||||
|
from flask_bootstrap import Bootstrap
|
||||||
|
|
||||||
|
eventlet.monkey_patch()
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
app.config['SECRET'] = 'my secret key'
|
||||||
|
app.config['TEMPLATES_AUTO_RELOAD'] = True
|
||||||
|
app.config['MQTT_BROKER_URL'] = 'broker.hivemq.com'
|
||||||
|
app.config['MQTT_BROKER_PORT'] = 1883
|
||||||
|
app.config['MQTT_USERNAME'] = ''
|
||||||
|
app.config['MQTT_PASSWORD'] = ''
|
||||||
|
app.config['MQTT_KEEPALIVE'] = 5
|
||||||
|
app.config['MQTT_TLS_ENABLED'] = False
|
||||||
|
|
||||||
|
# Parameters for SSL enabled
|
||||||
|
# app.config['MQTT_BROKER_PORT'] = 8883
|
||||||
|
# app.config['MQTT_TLS_ENABLED'] = True
|
||||||
|
# app.config['MQTT_TLS_INSECURE'] = True
|
||||||
|
# app.config['MQTT_TLS_CA_CERTS'] = 'ca.crt'
|
||||||
|
|
||||||
|
mqtt = Mqtt(app)
|
||||||
|
socketio = SocketIO(app)
|
||||||
|
bootstrap = Bootstrap(app)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/')
|
||||||
|
def index():
|
||||||
|
return render_template('index.html')
|
||||||
|
|
||||||
|
|
||||||
|
@socketio.on('publish')
|
||||||
|
def handle_publish(json_str):
|
||||||
|
data = json.loads(json_str)
|
||||||
|
mqtt.publish(data['topic'], data['message'])
|
||||||
|
|
||||||
|
|
||||||
|
@socketio.on('subscribe')
|
||||||
|
def handle_subscribe(json_str):
|
||||||
|
data = json.loads(json_str)
|
||||||
|
mqtt.subscribe(data['topic'])
|
||||||
|
|
||||||
|
|
||||||
|
@mqtt.on_message()
|
||||||
|
def handle_mqtt_message(client, userdata, message):
|
||||||
|
data = dict(
|
||||||
|
topic=message.topic,
|
||||||
|
payload=message.payload.decode()
|
||||||
|
)
|
||||||
|
socketio.emit('mqtt_message', data=data)
|
||||||
|
|
||||||
|
|
||||||
|
@mqtt.on_log()
|
||||||
|
def handle_logging(client, userdata, level, buf):
|
||||||
|
print(level, buf)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
socketio.run(app, host='0.0.0.0', port=5000, use_reloader=True, debug=True)
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
[0]: https://github.com/eclipse/paho.mqtt.python
|
||||||
|
[1]: http://mqtt.org/
|
||||||
|
[2]: http://flask-mqtt.readthedocs.io/en/latest/
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
pip
|
|
@ -0,0 +1,194 @@
|
||||||
|
Metadata-Version: 2.0
|
||||||
|
Name: Flask-MQTT
|
||||||
|
Version: 1.0.3
|
||||||
|
Summary: Flask extension for the MQTT protocol
|
||||||
|
Home-page: https://github.com/MrLeeh/Flask-MQTT
|
||||||
|
Author: Stefan Lehmann
|
||||||
|
Author-email: stefan.st.lehmann@gmail.com
|
||||||
|
License: MIT
|
||||||
|
Platform: any
|
||||||
|
Classifier: Development Status :: 5 - Production/Stable
|
||||||
|
Classifier: Environment :: Web Environment
|
||||||
|
Classifier: Intended Audience :: Developers
|
||||||
|
Classifier: License :: OSI Approved :: MIT License
|
||||||
|
Classifier: Programming Language :: Python
|
||||||
|
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
|
||||||
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
||||||
|
Description-Content-Type: text/markdown
|
||||||
|
Requires-Dist: Flask
|
||||||
|
Requires-Dist: typing
|
||||||
|
Requires-Dist: paho-mqtt
|
||||||
|
|
||||||
|
# Flask-MQTT
|
||||||
|
|
||||||
|
Flask Extension for the [MQTT protocol][1]. Basically it is a thin wrapper
|
||||||
|
around [paho-mqtt][0] and aimes to simplify MQTT integration in Flask. MQTT is a
|
||||||
|
machine-to-machine "Internet of Things" protocol and was designed for extremely
|
||||||
|
lightweight publish/subscribe messaging transport.
|
||||||
|
|
||||||
|
[![Documentation Status](https://readthedocs.org/projects/flask-mqtt/badge/?version=latest)](http://flask-mqtt.readthedocs.io/en/latest/?badge=latest) [![PyPI version](https://badge.fury.io/py/Flask-MQTT.svg)](https://badge.fury.io/py/Flask-MQTT) [![Travis CI](https://travis-ci.org/stlehmann/Flask-MQTT.svg?branch=master)](https://travis-ci.org/stlehmann/Flask-MQTT.svg?branch=master)
|
||||||
|
|
||||||
|
Find the documentation on [http://flask-mqtt.readthedocs.io][2].
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
* configuration via Flask config variables
|
||||||
|
* auto-connect on start of your web application
|
||||||
|
* publish and subscribe messages
|
||||||
|
* use callbacks for certain topics
|
||||||
|
* use one callback for all subscribed topics
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Simply install the package as usual via pip:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ pip install flask-mqtt
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Basic Setup
|
||||||
|
|
||||||
|
```python
|
||||||
|
from flask import Flask
|
||||||
|
from flask_mqtt import Mqtt
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
app.config['MQTT_BROKER_URL'] = 'mybroker.com'
|
||||||
|
app.config['MQTT_BROKER_PORT'] = 1883
|
||||||
|
app.config['MQTT_USERNAME'] = 'user'
|
||||||
|
app.config['MQTT_PASSWORD'] = 'secret'
|
||||||
|
app.config['MQTT_REFRESH_TIME'] = 1.0 # refresh time in seconds
|
||||||
|
mqtt = Mqtt(app)
|
||||||
|
|
||||||
|
@app.route('/')
|
||||||
|
def index():
|
||||||
|
return render_template('index.html')
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Subscribe to a topic
|
||||||
|
|
||||||
|
To subscribe to a topic simply use `mqtt.subscribe()`. To make sure the
|
||||||
|
subscription gets handled correctly on startup place the subscription inside
|
||||||
|
an `on_connect()` callback function.
|
||||||
|
|
||||||
|
```python
|
||||||
|
@mqtt.on_connect()
|
||||||
|
def handle_connect(client, userdata, flags, rc):
|
||||||
|
mqtt.subscribe('home/mytopic')
|
||||||
|
```
|
||||||
|
|
||||||
|
To handle the subscribed messages you can define a handling function by
|
||||||
|
decorating it with `@mqtt.on_message()`.
|
||||||
|
|
||||||
|
```python
|
||||||
|
@mqtt.on_message()
|
||||||
|
def handle_mqtt_message(client, userdata, message):
|
||||||
|
data = dict(
|
||||||
|
topic=message.topic,
|
||||||
|
payload=message.payload.decode()
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
To unsubscribe do:
|
||||||
|
|
||||||
|
```python
|
||||||
|
mqtt.unsubscribe('home/mytopic')
|
||||||
|
```
|
||||||
|
|
||||||
|
Or if you want to unsubscribe all topics use `unsubscribe_all()`.
|
||||||
|
|
||||||
|
```python
|
||||||
|
mqtt.unsubscribe_all()
|
||||||
|
```
|
||||||
|
|
||||||
|
### Publish
|
||||||
|
|
||||||
|
To publish a message you can use the `publish()` method.
|
||||||
|
|
||||||
|
```python
|
||||||
|
mqtt.publish('home/mytopic', 'this is my message')
|
||||||
|
```
|
||||||
|
|
||||||
|
### Small publish/subscribe MQTT client
|
||||||
|
|
||||||
|
```python
|
||||||
|
"""
|
||||||
|
|
||||||
|
A small Test application to show how to use Flask-MQTT.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import eventlet
|
||||||
|
import json
|
||||||
|
from flask import Flask, render_template
|
||||||
|
from flask_mqtt import Mqtt
|
||||||
|
from flask_socketio import SocketIO
|
||||||
|
from flask_bootstrap import Bootstrap
|
||||||
|
|
||||||
|
eventlet.monkey_patch()
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
app.config['SECRET'] = 'my secret key'
|
||||||
|
app.config['TEMPLATES_AUTO_RELOAD'] = True
|
||||||
|
app.config['MQTT_BROKER_URL'] = 'broker.hivemq.com'
|
||||||
|
app.config['MQTT_BROKER_PORT'] = 1883
|
||||||
|
app.config['MQTT_USERNAME'] = ''
|
||||||
|
app.config['MQTT_PASSWORD'] = ''
|
||||||
|
app.config['MQTT_KEEPALIVE'] = 5
|
||||||
|
app.config['MQTT_TLS_ENABLED'] = False
|
||||||
|
|
||||||
|
# Parameters for SSL enabled
|
||||||
|
# app.config['MQTT_BROKER_PORT'] = 8883
|
||||||
|
# app.config['MQTT_TLS_ENABLED'] = True
|
||||||
|
# app.config['MQTT_TLS_INSECURE'] = True
|
||||||
|
# app.config['MQTT_TLS_CA_CERTS'] = 'ca.crt'
|
||||||
|
|
||||||
|
mqtt = Mqtt(app)
|
||||||
|
socketio = SocketIO(app)
|
||||||
|
bootstrap = Bootstrap(app)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/')
|
||||||
|
def index():
|
||||||
|
return render_template('index.html')
|
||||||
|
|
||||||
|
|
||||||
|
@socketio.on('publish')
|
||||||
|
def handle_publish(json_str):
|
||||||
|
data = json.loads(json_str)
|
||||||
|
mqtt.publish(data['topic'], data['message'])
|
||||||
|
|
||||||
|
|
||||||
|
@socketio.on('subscribe')
|
||||||
|
def handle_subscribe(json_str):
|
||||||
|
data = json.loads(json_str)
|
||||||
|
mqtt.subscribe(data['topic'])
|
||||||
|
|
||||||
|
|
||||||
|
@mqtt.on_message()
|
||||||
|
def handle_mqtt_message(client, userdata, message):
|
||||||
|
data = dict(
|
||||||
|
topic=message.topic,
|
||||||
|
payload=message.payload.decode()
|
||||||
|
)
|
||||||
|
socketio.emit('mqtt_message', data=data)
|
||||||
|
|
||||||
|
|
||||||
|
@mqtt.on_log()
|
||||||
|
def handle_logging(client, userdata, level, buf):
|
||||||
|
print(level, buf)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
socketio.run(app, host='0.0.0.0', port=5000, use_reloader=True, debug=True)
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
[0]: https://github.com/eclipse/paho.mqtt.python
|
||||||
|
[1]: http://mqtt.org/
|
||||||
|
[2]: http://flask-mqtt.readthedocs.io/en/latest/
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
Flask_MQTT-1.0.3.dist-info/DESCRIPTION.rst,sha256=scdzeVK9SyGF_ZYEjSy07Lvbkx3VKOH5KwRt8oNRx7s,4225
|
||||||
|
Flask_MQTT-1.0.3.dist-info/METADATA,sha256=Sz1g2z9KQFIaAlv4kh2ga0sCeX2GbQb2PAnlyYcKt94,4946
|
||||||
|
Flask_MQTT-1.0.3.dist-info/RECORD,,
|
||||||
|
Flask_MQTT-1.0.3.dist-info/WHEEL,sha256=0mO7-aKM6K9CHeURc5NDYZyLWH5lmR-r4TtPinHxz7Y,93
|
||||||
|
Flask_MQTT-1.0.3.dist-info/metadata.json,sha256=8k4mdFdGj0w-NXl0Q3hK4CX4B0fiqDu-GzTakg9HlQc,901
|
||||||
|
Flask_MQTT-1.0.3.dist-info/top_level.txt,sha256=rDSXoP_WPnaqCmGIyZOn1ieidQ63URSSX4KvlN3HzL8,11
|
||||||
|
flask_mqtt/__init__.py,sha256=SAbjc3stsoQIxpD8IfS__mqSNxgZNhtBo2W4Xn7A2Bg,13391
|
||||||
|
Flask_MQTT-1.0.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||||
|
flask_mqtt/__pycache__/__init__.cpython-36.pyc,,
|
|
@ -0,0 +1,5 @@
|
||||||
|
Wheel-Version: 1.0
|
||||||
|
Generator: bdist_wheel (0.30.0)
|
||||||
|
Root-Is-Purelib: true
|
||||||
|
Tag: cp36-none-any
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
{"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Software Development :: Libraries :: Python Modules"], "description_content_type": "text/markdown", "extensions": {"python.details": {"contacts": [{"email": "stefan.st.lehmann@gmail.com", "name": "Stefan Lehmann", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "https://github.com/MrLeeh/Flask-MQTT"}}}, "extras": [], "generator": "bdist_wheel (0.30.0)", "license": "MIT", "metadata_version": "2.0", "name": "Flask-MQTT", "platform": "any", "run_requires": [{"requires": ["Flask", "paho-mqtt", "typing"]}], "summary": "Flask extension for the MQTT protocol", "version": "1.0.3"}
|
|
@ -0,0 +1 @@
|
||||||
|
flask_mqtt
|
|
@ -0,0 +1,37 @@
|
||||||
|
|
||||||
|
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/
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
pip
|
|
@ -0,0 +1,31 @@
|
||||||
|
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.
|
|
@ -0,0 +1,68 @@
|
||||||
|
Metadata-Version: 2.0
|
||||||
|
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-Content-Type: UNKNOWN
|
||||||
|
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
|
||||||
|
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: 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/
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
Jinja2-2.10.dist-info/DESCRIPTION.rst,sha256=b5ckFDoM7vVtz_mAsJD4OPteFKCqE7beu353g4COoYI,978
|
||||||
|
Jinja2-2.10.dist-info/LICENSE.txt,sha256=JvzUNv3Io51EiWrAPm8d_SXjhJnEjyDYvB3Tvwqqils,1554
|
||||||
|
Jinja2-2.10.dist-info/METADATA,sha256=18EgU8zR6-av-0-5y_gXebzK4GnBB_76lALUsl-6QHM,2258
|
||||||
|
Jinja2-2.10.dist-info/RECORD,,
|
||||||
|
Jinja2-2.10.dist-info/WHEEL,sha256=kdsN-5OJAZIiHN-iO4Rhl82KyS0bDWf4uBwMbkNafr8,110
|
||||||
|
Jinja2-2.10.dist-info/entry_points.txt,sha256=NdzVcOrqyNyKDxD09aERj__3bFx2paZhizFDsKmVhiA,72
|
||||||
|
Jinja2-2.10.dist-info/metadata.json,sha256=NPUJ9TMBxVQAv_kTJzvU8HwmP-4XZvbK9mz6_4YUVl4,1473
|
||||||
|
Jinja2-2.10.dist-info/top_level.txt,sha256=PkeVWtLb3-CqjWi1fO29OCbj55EhX_chhKrCdrVe_zs,7
|
||||||
|
jinja2/__init__.py,sha256=xJHjaMoy51_KXn1wf0cysH6tUUifUxZCwSOfcJGEYZw,2614
|
||||||
|
jinja2/_compat.py,sha256=xP60CE5Qr8FTYcDE1f54tbZLKGvMwYml4-8T7Q4KG9k,2596
|
||||||
|
jinja2/_identifier.py,sha256=W1QBSY-iJsyt6oR_nKSuNNCzV95vLIOYgUNPUI1d5gU,1726
|
||||||
|
jinja2/asyncfilters.py,sha256=cTDPvrS8Hp_IkwsZ1m9af_lr5nHysw7uTa5gV0NmZVE,4144
|
||||||
|
jinja2/asyncsupport.py,sha256=UErQ3YlTLaSjFb94P4MVn08-aVD9jJxty2JVfMRb-1M,7878
|
||||||
|
jinja2/bccache.py,sha256=nQldx0ZRYANMyfvOihRoYFKSlUdd5vJkS7BjxNwlOZM,12794
|
||||||
|
jinja2/compiler.py,sha256=BqC5U6JxObSRhblyT_a6Tp5GtEU5z3US1a4jLQaxxgo,65386
|
||||||
|
jinja2/constants.py,sha256=uwwV8ZUhHhacAuz5PTwckfsbqBaqM7aKfyJL7kGX5YQ,1626
|
||||||
|
jinja2/debug.py,sha256=WTVeUFGUa4v6ReCsYv-iVPa3pkNB75OinJt3PfxNdXs,12045
|
||||||
|
jinja2/defaults.py,sha256=Em-95hmsJxIenDCZFB1YSvf9CNhe9rBmytN3yUrBcWA,1400
|
||||||
|
jinja2/environment.py,sha256=VnkAkqw8JbjZct4tAyHlpBrka2vqB-Z58RAP-32P1ZY,50849
|
||||||
|
jinja2/exceptions.py,sha256=_Rj-NVi98Q6AiEjYQOsP8dEIdu5AlmRHzcSNOPdWix4,4428
|
||||||
|
jinja2/ext.py,sha256=atMQydEC86tN1zUsdQiHw5L5cF62nDbqGue25Yiu3N4,24500
|
||||||
|
jinja2/filters.py,sha256=yOAJk0MsH-_gEC0i0U6NweVQhbtYaC-uE8xswHFLF4w,36528
|
||||||
|
jinja2/idtracking.py,sha256=2GbDSzIvGArEBGLkovLkqEfmYxmWsEf8c3QZwM4uNsw,9197
|
||||||
|
jinja2/lexer.py,sha256=ySEPoXd1g7wRjsuw23uimS6nkGN5aqrYwcOKxCaVMBQ,28559
|
||||||
|
jinja2/loaders.py,sha256=xiTuURKAEObyym0nU8PCIXu_Qp8fn0AJ5oIADUUm-5Q,17382
|
||||||
|
jinja2/meta.py,sha256=fmKHxkmZYAOm9QyWWy8EMd6eefAIh234rkBMW2X4ZR8,4340
|
||||||
|
jinja2/nativetypes.py,sha256=_sJhS8f-8Q0QMIC0dm1YEdLyxEyoO-kch8qOL5xUDfE,7308
|
||||||
|
jinja2/nodes.py,sha256=L10L_nQDfubLhO3XjpF9qz46FSh2clL-3e49ogVlMmA,30853
|
||||||
|
jinja2/optimizer.py,sha256=MsdlFACJ0FRdPtjmCAdt7JQ9SGrXFaDNUaslsWQaG3M,1722
|
||||||
|
jinja2/parser.py,sha256=lPzTEbcpTRBLw8ii6OYyExHeAhaZLMA05Hpv4ll3ULk,35875
|
||||||
|
jinja2/runtime.py,sha256=DHdD38Pq8gj7uWQC5usJyWFoNWL317A9AvXOW_CLB34,27755
|
||||||
|
jinja2/sandbox.py,sha256=TVyZHlNqqTzsv9fv2NvJNmSdWRHTguhyMHdxjWms32U,16708
|
||||||
|
jinja2/tests.py,sha256=iJQLwbapZr-EKquTG_fVOVdwHUUKf3SX9eNkjQDF8oU,4237
|
||||||
|
jinja2/utils.py,sha256=q24VupGZotQ-uOyrJxCaXtDWhZC1RgsQG7kcdmjck2Q,20629
|
||||||
|
jinja2/visitor.py,sha256=JD1H1cANA29JcntFfN5fPyqQxB4bI4wC00BzZa-XHks,3316
|
||||||
|
Jinja2-2.10.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||||
|
jinja2/__pycache__/lexer.cpython-36.pyc,,
|
||||||
|
jinja2/__pycache__/sandbox.cpython-36.pyc,,
|
||||||
|
jinja2/__pycache__/debug.cpython-36.pyc,,
|
||||||
|
jinja2/__pycache__/constants.cpython-36.pyc,,
|
||||||
|
jinja2/__pycache__/idtracking.cpython-36.pyc,,
|
||||||
|
jinja2/__pycache__/parser.cpython-36.pyc,,
|
||||||
|
jinja2/__pycache__/exceptions.cpython-36.pyc,,
|
||||||
|
jinja2/__pycache__/ext.cpython-36.pyc,,
|
||||||
|
jinja2/__pycache__/meta.cpython-36.pyc,,
|
||||||
|
jinja2/__pycache__/environment.cpython-36.pyc,,
|
||||||
|
jinja2/__pycache__/loaders.cpython-36.pyc,,
|
||||||
|
jinja2/__pycache__/asyncsupport.cpython-36.pyc,,
|
||||||
|
jinja2/__pycache__/asyncfilters.cpython-36.pyc,,
|
||||||
|
jinja2/__pycache__/tests.cpython-36.pyc,,
|
||||||
|
jinja2/__pycache__/optimizer.cpython-36.pyc,,
|
||||||
|
jinja2/__pycache__/compiler.cpython-36.pyc,,
|
||||||
|
jinja2/__pycache__/bccache.cpython-36.pyc,,
|
||||||
|
jinja2/__pycache__/_identifier.cpython-36.pyc,,
|
||||||
|
jinja2/__pycache__/_compat.cpython-36.pyc,,
|
||||||
|
jinja2/__pycache__/defaults.cpython-36.pyc,,
|
||||||
|
jinja2/__pycache__/utils.cpython-36.pyc,,
|
||||||
|
jinja2/__pycache__/nodes.cpython-36.pyc,,
|
||||||
|
jinja2/__pycache__/filters.cpython-36.pyc,,
|
||||||
|
jinja2/__pycache__/runtime.cpython-36.pyc,,
|
||||||
|
jinja2/__pycache__/__init__.cpython-36.pyc,,
|
||||||
|
jinja2/__pycache__/nativetypes.cpython-36.pyc,,
|
||||||
|
jinja2/__pycache__/visitor.cpython-36.pyc,,
|
|
@ -0,0 +1,6 @@
|
||||||
|
Wheel-Version: 1.0
|
||||||
|
Generator: bdist_wheel (0.30.0)
|
||||||
|
Root-Is-Purelib: true
|
||||||
|
Tag: py2-none-any
|
||||||
|
Tag: py3-none-any
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
[babel.extractors]
|
||||||
|
jinja2 = jinja2.ext:babel_extract[i18n]
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
{"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", "Programming Language :: Python :: 3.6", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Text Processing :: Markup :: HTML"], "description_content_type": "UNKNOWN", "extensions": {"python.details": {"contacts": [{"email": "armin.ronacher@active-4.com", "name": "Armin Ronacher", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst", "license": "LICENSE.txt"}, "project_urls": {"Home": "http://jinja.pocoo.org/"}}, "python.exports": {"babel.extractors": {"jinja2": "jinja2.ext:babel_extract [i18n]"}}}, "extras": ["i18n"], "generator": "bdist_wheel (0.30.0)", "license": "BSD", "metadata_version": "2.0", "name": "Jinja2", "run_requires": [{"extra": "i18n", "requires": ["Babel (>=0.8)"]}, {"requires": ["MarkupSafe (>=0.23)"]}], "summary": "A small but fast and easy to use stand-alone template engine written in pure python.", "version": "2.10"}
|
|
@ -0,0 +1 @@
|
||||||
|
jinja2
|
|
@ -0,0 +1,115 @@
|
||||||
|
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.
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
pip
|
|
@ -0,0 +1,33 @@
|
||||||
|
Copyright (c) 2010 by Armin Ronacher and contributors. See AUTHORS
|
||||||
|
for more details.
|
||||||
|
|
||||||
|
Some rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms of the software as well
|
||||||
|
as documentation, 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 AND DOCUMENTATION 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 AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||||
|
DAMAGE.
|
|
@ -0,0 +1,135 @@
|
||||||
|
Metadata-Version: 2.0
|
||||||
|
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
|
||||||
|
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
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
MarkupSafe-1.0.dist-info/DESCRIPTION.rst,sha256=3B3J0YLzzmJQVaWQ_XlVMhGeHA_DvBqysABvul_5fko,3397
|
||||||
|
MarkupSafe-1.0.dist-info/LICENSE.txt,sha256=C76IIo_WPSDsCX9k5Y1aCkZRI64TkUChjUBsYLSIJLU,1582
|
||||||
|
MarkupSafe-1.0.dist-info/METADATA,sha256=EUwvRzJbtRP3hBMc8Z2TDT44TBDeZdIurbGzIc7FOkg,4182
|
||||||
|
MarkupSafe-1.0.dist-info/RECORD,,
|
||||||
|
MarkupSafe-1.0.dist-info/WHEEL,sha256=t7v9jPyHKppZusl3DelaV4cYxaKjc-YJ3uQtEMT8OaQ,111
|
||||||
|
MarkupSafe-1.0.dist-info/metadata.json,sha256=LPb3W7qq-SH_u1SFzjXQqT8sCGpE-b4NmYAxMcw91e8,924
|
||||||
|
MarkupSafe-1.0.dist-info/top_level.txt,sha256=qy0Plje5IJuvsCBjejJyhDCjEAdcDLK_2agVcex8Z6U,11
|
||||||
|
markupsafe/__init__.py,sha256=xtkRdxhzJzgp65wUo1D4DjnazxHU88pPldaAuDekBeY,10697
|
||||||
|
markupsafe/_compat.py,sha256=r1HE0CpcAZeb-AiTV9wITR91PeLHn0CzZ_XHkYoozpI,565
|
||||||
|
markupsafe/_constants.py,sha256=U_xybFQsyXKCgHSfranJnFzo-z9nn9fuBeSk243sE5Q,4795
|
||||||
|
markupsafe/_native.py,sha256=E2Un1ysOf-w45d18YCj8UelT5UP7Vt__IuFPYJ7YRIs,1187
|
||||||
|
markupsafe/_speedups.c,sha256=B6Mf6Fn33WqkagfwY7q5ZBSm_vJoHDYxDB0Jp_DP7Jw,5936
|
||||||
|
markupsafe/_speedups.cpython-36m-darwin.so,sha256=0vozF8REMN0zriSHLpbLrkp0dAJ38SLFAb13MDfUyaQ,10600
|
||||||
|
MarkupSafe-1.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||||
|
markupsafe/__pycache__/_native.cpython-36.pyc,,
|
||||||
|
markupsafe/__pycache__/_constants.cpython-36.pyc,,
|
||||||
|
markupsafe/__pycache__/_compat.cpython-36.pyc,,
|
||||||
|
markupsafe/__pycache__/__init__.cpython-36.pyc,,
|
|
@ -0,0 +1,5 @@
|
||||||
|
Wheel-Version: 1.0
|
||||||
|
Generator: bdist_wheel (0.30.0)
|
||||||
|
Root-Is-Purelib: false
|
||||||
|
Tag: cp36-cp36m-macosx_10_13_x86_64
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
{"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Text Processing :: Markup :: HTML"], "extensions": {"python.details": {"contacts": [{"email": "armin.ronacher@active-4.com", "name": "Armin Ronacher", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst", "license": "LICENSE.txt"}, "project_urls": {"Home": "http://github.com/pallets/markupsafe"}}}, "generator": "bdist_wheel (0.30.0)", "license": "BSD", "metadata_version": "2.0", "name": "MarkupSafe", "summary": "Implements a XML/HTML/XHTML Markup safe string for Python", "version": "1.0"}
|
|
@ -0,0 +1 @@
|
||||||
|
markupsafe
|
|
@ -0,0 +1,80 @@
|
||||||
|
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/
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
pip
|
|
@ -0,0 +1,31 @@
|
||||||
|
Copyright © 2007 by the Pallets team.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
* Neither the name of the copyright holder nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE AND DOCUMENTATION 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 HOLDER 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 AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
SUCH DAMAGE.
|
|
@ -0,0 +1,116 @@
|
||||||
|
Metadata-Version: 2.0
|
||||||
|
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-Content-Type: UNKNOWN
|
||||||
|
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
|
||||||
|
Provides-Extra: dev
|
||||||
|
Requires-Dist: coverage; extra == 'dev'
|
||||||
|
Requires-Dist: pytest; extra == 'dev'
|
||||||
|
Requires-Dist: sphinx; extra == 'dev'
|
||||||
|
Requires-Dist: tox; extra == 'dev'
|
||||||
|
Provides-Extra: termcolor
|
||||||
|
Requires-Dist: termcolor; extra == 'termcolor'
|
||||||
|
Provides-Extra: watchdog
|
||||||
|
Requires-Dist: watchdog; extra == 'watchdog'
|
||||||
|
|
||||||
|
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/
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
Werkzeug-0.14.1.dist-info/DESCRIPTION.rst,sha256=rOCN36jwsWtWsTpqPG96z7FMilB5qI1CIARSKRuUmz8,2452
|
||||||
|
Werkzeug-0.14.1.dist-info/LICENSE.txt,sha256=xndz_dD4m269AF9l_Xbl5V3tM1N3C1LoZC2PEPxWO-8,1534
|
||||||
|
Werkzeug-0.14.1.dist-info/METADATA,sha256=FbfadrPdJNUWAxMOKxGUtHe5R3IDSBKYYmAz3FvI3uY,3872
|
||||||
|
Werkzeug-0.14.1.dist-info/RECORD,,
|
||||||
|
Werkzeug-0.14.1.dist-info/WHEEL,sha256=GrqQvamwgBV4nLoJe0vhYRSWzWsx7xjlt74FT0SWYfE,110
|
||||||
|
Werkzeug-0.14.1.dist-info/metadata.json,sha256=4489UTt6HBp2NQil95-pBkjU4Je93SMHvMxZ_rjOpqA,1452
|
||||||
|
Werkzeug-0.14.1.dist-info/top_level.txt,sha256=QRyj2VjwJoQkrwjwFIOlB8Xg3r9un0NtqVHQF-15xaw,9
|
||||||
|
werkzeug/__init__.py,sha256=NR0d4n_-U9BLVKlOISean3zUt2vBwhvK-AZE6M0sC0k,6842
|
||||||
|
werkzeug/_compat.py,sha256=8c4U9o6A_TR9nKCcTbpZNxpqCXcXDVIbFawwKM2s92c,6311
|
||||||
|
werkzeug/_internal.py,sha256=GhEyGMlsSz_tYjsDWO9TG35VN7304MM8gjKDrXLEdVc,13873
|
||||||
|
werkzeug/_reloader.py,sha256=AyPphcOHPbu6qzW0UbrVvTDJdre5WgpxbhIJN_TqzUc,9264
|
||||||
|
werkzeug/datastructures.py,sha256=3IgNKNqrz-ZjmAG7y3YgEYK-enDiMT_b652PsypWcYg,90080
|
||||||
|
werkzeug/exceptions.py,sha256=3wp95Hqj9FqV8MdikV99JRcHse_fSMn27V8tgP5Hw2c,20505
|
||||||
|
werkzeug/filesystem.py,sha256=hHWeWo_gqLMzTRfYt8-7n2wWcWUNTnDyudQDLOBEICE,2175
|
||||||
|
werkzeug/formparser.py,sha256=mUuCwjzjb8_E4RzrAT2AioLuZSYpqR1KXTK6LScRYzA,21722
|
||||||
|
werkzeug/http.py,sha256=RQg4MJuhRv2isNRiEh__Phh09ebpfT3Kuu_GfrZ54_c,40079
|
||||||
|
werkzeug/local.py,sha256=QdQhWV5L8p1Y1CJ1CDStwxaUs24SuN5aebHwjVD08C8,14553
|
||||||
|
werkzeug/posixemulation.py,sha256=xEF2Bxc-vUCPkiu4IbfWVd3LW7DROYAT-ExW6THqyzw,3519
|
||||||
|
werkzeug/routing.py,sha256=2JVtdSgxKGeANy4Z_FP-dKESvKtkYGCZ1J2fARCLGCY,67214
|
||||||
|
werkzeug/script.py,sha256=DwaVDcXdaOTffdNvlBdLitxWXjKaRVT32VbhDtljFPY,11365
|
||||||
|
werkzeug/security.py,sha256=0m107exslz4QJLWQCpfQJ04z3re4eGHVggRvrQVAdWc,9193
|
||||||
|
werkzeug/serving.py,sha256=A0flnIJHufdn2QJ9oeuHfrXwP3LzP8fn3rNW6hbxKUg,31926
|
||||||
|
werkzeug/test.py,sha256=XmECSmnpASiYQTct4oMiWr0LT5jHWCtKqnpYKZd2ui8,36100
|
||||||
|
werkzeug/testapp.py,sha256=3HQRW1sHZKXuAjCvFMet4KXtQG3loYTFnvn6LWt-4zI,9396
|
||||||
|
werkzeug/urls.py,sha256=dUeLg2IeTm0WLmSvFeD4hBZWGdOs-uHudR5-t8n9zPo,36771
|
||||||
|
werkzeug/useragents.py,sha256=BhYMf4cBTHyN4U0WsQedePIocmNlH_34C-UwqSThGCc,5865
|
||||||
|
werkzeug/utils.py,sha256=BrY1j0DHQ8RTb0K1StIobKuMJhN9SQQkWEARbrh2qpk,22972
|
||||||
|
werkzeug/websocket.py,sha256=PpSeDxXD_0UsPAa5hQhQNM6mxibeUgn8lA8eRqiS0vM,11344
|
||||||
|
werkzeug/wrappers.py,sha256=kbyL_aFjxELwPgMwfNCYjKu-CR6kNkh-oO8wv3GXbk8,84511
|
||||||
|
werkzeug/wsgi.py,sha256=1Nob-aeChWQf7MsiicO8RZt6J90iRzEcik44ev9Qu8s,49347
|
||||||
|
werkzeug/contrib/__init__.py,sha256=f7PfttZhbrImqpr5Ezre8CXgwvcGUJK7zWNpO34WWrw,623
|
||||||
|
werkzeug/contrib/atom.py,sha256=qqfJcfIn2RYY-3hO3Oz0aLq9YuNubcPQ_KZcNsDwVJo,15575
|
||||||
|
werkzeug/contrib/cache.py,sha256=xBImHNj09BmX_7kC5NUCx8f_l4L8_O7zi0jCL21UZKE,32163
|
||||||
|
werkzeug/contrib/fixers.py,sha256=gR06T-w71ur-tHQ_31kP_4jpOncPJ4Wc1dOqTvYusr8,10179
|
||||||
|
werkzeug/contrib/iterio.py,sha256=RlqDvGhz0RneTpzE8dVc-yWCUv4nkPl1jEc_EDp2fH0,10814
|
||||||
|
werkzeug/contrib/jsrouting.py,sha256=QTmgeDoKXvNK02KzXgx9lr3cAH6fAzpwF5bBdPNvJPs,8564
|
||||||
|
werkzeug/contrib/limiter.py,sha256=iS8-ahPZ-JLRnmfIBzxpm7O_s3lPsiDMVWv7llAIDCI,1334
|
||||||
|
werkzeug/contrib/lint.py,sha256=Mj9NeUN7s4zIUWeQOAVjrmtZIcl3Mm2yDe9BSIr9YGE,12558
|
||||||
|
werkzeug/contrib/profiler.py,sha256=ISwCWvwVyGpDLRBRpLjo_qUWma6GXYBrTAco4PEQSHY,5151
|
||||||
|
werkzeug/contrib/securecookie.py,sha256=uWMyHDHY3lkeBRiCSayGqWkAIy4a7xAbSE_Hln9ecqc,12196
|
||||||
|
werkzeug/contrib/sessions.py,sha256=39LVNvLbm5JWpbxM79WC2l87MJFbqeISARjwYbkJatw,12577
|
||||||
|
werkzeug/contrib/testtools.py,sha256=G9xN-qeihJlhExrIZMCahvQOIDxdL9NiX874jiiHFMs,2453
|
||||||
|
werkzeug/contrib/wrappers.py,sha256=v7OYlz7wQtDlS9fey75UiRZ1IkUWqCpzbhsLy4k14Hw,10398
|
||||||
|
werkzeug/debug/__init__.py,sha256=uSn9BqCZ5E3ySgpoZtundpROGsn-uYvZtSFiTfAX24M,17452
|
||||||
|
werkzeug/debug/console.py,sha256=n3-dsKk1TsjnN-u4ZgmuWCU_HO0qw5IA7ttjhyyMM6I,5607
|
||||||
|
werkzeug/debug/repr.py,sha256=bKqstDYGfECpeLerd48s_hxuqK4b6UWnjMu3d_DHO8I,9340
|
||||||
|
werkzeug/debug/tbtools.py,sha256=rBudXCmkVdAKIcdhxANxgf09g6kQjJWW9_5bjSpr4OY,18451
|
||||||
|
werkzeug/debug/shared/FONT_LICENSE,sha256=LwAVEI1oYnvXiNMT9SnCH_TaLCxCpeHziDrMg0gPkAI,4673
|
||||||
|
werkzeug/debug/shared/console.png,sha256=bxax6RXXlvOij_KeqvSNX0ojJf83YbnZ7my-3Gx9w2A,507
|
||||||
|
werkzeug/debug/shared/debugger.js,sha256=PKPVYuyO4SX1hkqLOwCLvmIEO5154WatFYaXE-zIfKI,6264
|
||||||
|
werkzeug/debug/shared/jquery.js,sha256=7LkWEzqTdpEfELxcZZlS6wAx5Ff13zZ83lYO2_ujj7g,95957
|
||||||
|
werkzeug/debug/shared/less.png,sha256=-4-kNRaXJSONVLahrQKUxMwXGm9R4OnZ9SxDGpHlIR4,191
|
||||||
|
werkzeug/debug/shared/more.png,sha256=GngN7CioHQoV58rH6ojnkYi8c_qED2Aka5FO5UXrReY,200
|
||||||
|
werkzeug/debug/shared/source.png,sha256=RoGcBTE4CyCB85GBuDGTFlAnUqxwTBiIfDqW15EpnUQ,818
|
||||||
|
werkzeug/debug/shared/style.css,sha256=IEO0PC2pWmh2aEyGCaN--txuWsRCliuhlbEhPDFwh0A,6270
|
||||||
|
werkzeug/debug/shared/ubuntu.ttf,sha256=1eaHFyepmy4FyDvjLVzpITrGEBu_CZYY94jE0nED1c0,70220
|
||||||
|
Werkzeug-0.14.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||||
|
werkzeug/__pycache__/posixemulation.cpython-36.pyc,,
|
||||||
|
werkzeug/__pycache__/exceptions.cpython-36.pyc,,
|
||||||
|
werkzeug/__pycache__/websocket.cpython-36.pyc,,
|
||||||
|
werkzeug/__pycache__/datastructures.cpython-36.pyc,,
|
||||||
|
werkzeug/__pycache__/filesystem.cpython-36.pyc,,
|
||||||
|
werkzeug/__pycache__/useragents.cpython-36.pyc,,
|
||||||
|
werkzeug/__pycache__/serving.cpython-36.pyc,,
|
||||||
|
werkzeug/__pycache__/testapp.cpython-36.pyc,,
|
||||||
|
werkzeug/__pycache__/_compat.cpython-36.pyc,,
|
||||||
|
werkzeug/__pycache__/script.cpython-36.pyc,,
|
||||||
|
werkzeug/__pycache__/security.cpython-36.pyc,,
|
||||||
|
werkzeug/__pycache__/_internal.cpython-36.pyc,,
|
||||||
|
werkzeug/__pycache__/routing.cpython-36.pyc,,
|
||||||
|
werkzeug/__pycache__/_reloader.cpython-36.pyc,,
|
||||||
|
werkzeug/__pycache__/local.cpython-36.pyc,,
|
||||||
|
werkzeug/__pycache__/http.cpython-36.pyc,,
|
||||||
|
werkzeug/__pycache__/utils.cpython-36.pyc,,
|
||||||
|
werkzeug/__pycache__/wsgi.cpython-36.pyc,,
|
||||||
|
werkzeug/__pycache__/formparser.cpython-36.pyc,,
|
||||||
|
werkzeug/__pycache__/wrappers.cpython-36.pyc,,
|
||||||
|
werkzeug/__pycache__/__init__.cpython-36.pyc,,
|
||||||
|
werkzeug/__pycache__/test.cpython-36.pyc,,
|
||||||
|
werkzeug/__pycache__/urls.cpython-36.pyc,,
|
||||||
|
werkzeug/contrib/__pycache__/sessions.cpython-36.pyc,,
|
||||||
|
werkzeug/contrib/__pycache__/lint.cpython-36.pyc,,
|
||||||
|
werkzeug/contrib/__pycache__/jsrouting.cpython-36.pyc,,
|
||||||
|
werkzeug/contrib/__pycache__/iterio.cpython-36.pyc,,
|
||||||
|
werkzeug/contrib/__pycache__/testtools.cpython-36.pyc,,
|
||||||
|
werkzeug/contrib/__pycache__/securecookie.cpython-36.pyc,,
|
||||||
|
werkzeug/contrib/__pycache__/fixers.cpython-36.pyc,,
|
||||||
|
werkzeug/contrib/__pycache__/profiler.cpython-36.pyc,,
|
||||||
|
werkzeug/contrib/__pycache__/cache.cpython-36.pyc,,
|
||||||
|
werkzeug/contrib/__pycache__/limiter.cpython-36.pyc,,
|
||||||
|
werkzeug/contrib/__pycache__/wrappers.cpython-36.pyc,,
|
||||||
|
werkzeug/contrib/__pycache__/__init__.cpython-36.pyc,,
|
||||||
|
werkzeug/contrib/__pycache__/atom.cpython-36.pyc,,
|
||||||
|
werkzeug/debug/__pycache__/repr.cpython-36.pyc,,
|
||||||
|
werkzeug/debug/__pycache__/console.cpython-36.pyc,,
|
||||||
|
werkzeug/debug/__pycache__/tbtools.cpython-36.pyc,,
|
||||||
|
werkzeug/debug/__pycache__/__init__.cpython-36.pyc,,
|
|
@ -0,0 +1,6 @@
|
||||||
|
Wheel-Version: 1.0
|
||||||
|
Generator: bdist_wheel (0.26.0)
|
||||||
|
Root-Is-Purelib: true
|
||||||
|
Tag: py2-none-any
|
||||||
|
Tag: py3-none-any
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
{"generator": "bdist_wheel (0.26.0)", "summary": "The comprehensive WSGI web application library.", "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", "Programming Language :: Python :: 3.6", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Software Development :: Libraries :: Python Modules"], "description_content_type": "UNKNOWN", "extensions": {"python.details": {"project_urls": {"Home": "https://www.palletsprojects.org/p/werkzeug/"}, "contacts": [{"email": "armin.ronacher@active-4.com", "name": "Armin Ronacher", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst", "license": "LICENSE.txt"}}}, "license": "BSD", "metadata_version": "2.0", "name": "Werkzeug", "platform": "any", "extras": ["dev", "termcolor", "watchdog"], "run_requires": [{"requires": ["coverage", "pytest", "sphinx", "tox"], "extra": "dev"}, {"requires": ["termcolor"], "extra": "termcolor"}, {"requires": ["watchdog"], "extra": "watchdog"}], "version": "0.14.1"}
|
|
@ -0,0 +1 @@
|
||||||
|
werkzeug
|
|
@ -0,0 +1,3 @@
|
||||||
|
UNKNOWN
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
pip
|
|
@ -0,0 +1,16 @@
|
||||||
|
Metadata-Version: 2.0
|
||||||
|
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
|
||||||
|
Platform: UNKNOWN
|
||||||
|
Classifier: License :: OSI Approved :: BSD License
|
||||||
|
Classifier: Programming Language :: Python
|
||||||
|
Classifier: Programming Language :: Python :: 3
|
||||||
|
|
||||||
|
UNKNOWN
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
click/__init__.py,sha256=k8R00cFKWI8dhDVKQeLBlAdNh1CxerMEDRiGnr32gdw,2858
|
||||||
|
click/_bashcomplete.py,sha256=82rMiibtEurdwBq60NHXVCBuGXJHDpblFO9o2YxJDF0,2423
|
||||||
|
click/_compat.py,sha256=j59MpzxYGE-fTGj0A5sg8UI8GhHod1XMojiCA0jvbL0,21011
|
||||||
|
click/_termui_impl.py,sha256=Ol1JJhvBRw3l8j1WIU0tOWjQtxxmwGE44lFDbzDqzoA,16395
|
||||||
|
click/_textwrap.py,sha256=gwS4m7bdQiJnzaDG8osFcRb-5vn4t4l2qSCy-5csCEc,1198
|
||||||
|
click/_unicodefun.py,sha256=A3UOzJw6lEZyol2SBg3fNXgweTutaOzkJ61OB7vik3Y,4204
|
||||||
|
click/_winconsole.py,sha256=MzG46DEYPoRyx4SO7EIhFuFZHESgooAfJLIukbB6p5c,7790
|
||||||
|
click/core.py,sha256=M0nJ6Kkye7XZXYG7HCbkJWSfy14WHV6bQmGLACrOhKw,70254
|
||||||
|
click/decorators.py,sha256=y7CX2needh8iRWafj-QS_hGQFsN24eyXAhx5Y2ATwas,10941
|
||||||
|
click/exceptions.py,sha256=rOa0pP3PbSy0_AAPOW9irBEM8AJ3BySN-4z2VUwFVo4,6788
|
||||||
|
click/formatting.py,sha256=eh-cypTUAhpI3HD-K4ZpR3vCiURIO62xXvKkR3tNUTM,8889
|
||||||
|
click/globals.py,sha256=PAgnKvGxq4YuEIldw3lgYOGBLYwsyxnm1IByBX3BFXo,1515
|
||||||
|
click/parser.py,sha256=i01xgYuIA6AwQWEXjshwHSwnTR3gUep4FxJIfyW4ta4,15510
|
||||||
|
click/termui.py,sha256=Bp99MSWQtyoWe1_7HggDmA77n--3KLxu7NsZMFMaCUo,21008
|
||||||
|
click/testing.py,sha256=kJ9mjtJgwNAlkgKcFf9-ISxufmaPDbbuOHVC9WIvKdY,11002
|
||||||
|
click/types.py,sha256=ZGb2lmFs5Vwd9loTRIMbGcqhPVOql8mGoBhWBRT6V4E,18864
|
||||||
|
click/utils.py,sha256=1jalPlkUU28JReTEQeeSFtbJd-SirYWBNfjtELBKzT4,14916
|
||||||
|
click-6.7.dist-info/DESCRIPTION.rst,sha256=OCTuuN6LcWulhHS3d5rfjdsQtW22n7HENFRh6jC6ego,10
|
||||||
|
click-6.7.dist-info/METADATA,sha256=l6lAyogIUXiHKUK_rWguef-EMcvO5C6bXzFCNCcblbQ,424
|
||||||
|
click-6.7.dist-info/RECORD,,
|
||||||
|
click-6.7.dist-info/WHEEL,sha256=5wvfB7GvgZAbKBSE9uX9Zbi6LCL-_KgezgHblXhCRnM,113
|
||||||
|
click-6.7.dist-info/metadata.json,sha256=qg0uO6amNHkIkOxnmWX7Xa_DNQMQ62Q6drivuP9Gh1c,571
|
||||||
|
click-6.7.dist-info/top_level.txt,sha256=J1ZQogalYS4pphY_lPECoNMfw0HzTSrZglC4Yfwo4xA,6
|
||||||
|
click-6.7.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||||
|
click/__pycache__/parser.cpython-36.pyc,,
|
||||||
|
click/__pycache__/exceptions.cpython-36.pyc,,
|
||||||
|
click/__pycache__/formatting.cpython-36.pyc,,
|
||||||
|
click/__pycache__/testing.cpython-36.pyc,,
|
||||||
|
click/__pycache__/types.cpython-36.pyc,,
|
||||||
|
click/__pycache__/_bashcomplete.cpython-36.pyc,,
|
||||||
|
click/__pycache__/_compat.cpython-36.pyc,,
|
||||||
|
click/__pycache__/_winconsole.cpython-36.pyc,,
|
||||||
|
click/__pycache__/_unicodefun.cpython-36.pyc,,
|
||||||
|
click/__pycache__/utils.cpython-36.pyc,,
|
||||||
|
click/__pycache__/_textwrap.cpython-36.pyc,,
|
||||||
|
click/__pycache__/core.cpython-36.pyc,,
|
||||||
|
click/__pycache__/termui.cpython-36.pyc,,
|
||||||
|
click/__pycache__/__init__.cpython-36.pyc,,
|
||||||
|
click/__pycache__/globals.cpython-36.pyc,,
|
||||||
|
click/__pycache__/decorators.cpython-36.pyc,,
|
||||||
|
click/__pycache__/_termui_impl.cpython-36.pyc,,
|
|
@ -0,0 +1,6 @@
|
||||||
|
Wheel-Version: 1.0
|
||||||
|
Generator: bdist_wheel (0.30.0.a0)
|
||||||
|
Root-Is-Purelib: true
|
||||||
|
Tag: py2-none-any
|
||||||
|
Tag: py3-none-any
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
{"classifiers": ["License :: OSI Approved :: BSD License", "Programming Language :: Python", "Programming Language :: Python :: 3"], "extensions": {"python.details": {"contacts": [{"email": "armin.ronacher@active-4.com", "name": "Armin Ronacher", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "http://github.com/mitsuhiko/click"}}}, "generator": "bdist_wheel (0.30.0.a0)", "metadata_version": "2.0", "name": "click", "summary": "A simple wrapper around optparse for powerful command line utilities.", "version": "6.7"}
|
|
@ -0,0 +1 @@
|
||||||
|
click
|
|
@ -0,0 +1,98 @@
|
||||||
|
# -*- 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'
|
|
@ -0,0 +1,83 @@
|
||||||
|
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
|
|
@ -0,0 +1,648 @@
|
||||||
|
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,
|
||||||
|
}
|
|
@ -0,0 +1,547 @@
|
||||||
|
"""
|
||||||
|
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')
|
|
@ -0,0 +1,38 @@
|
||||||
|
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)
|
|
@ -0,0 +1,118 @@
|
||||||
|
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)
|
|
@ -0,0 +1,273 @@
|
||||||
|
# -*- 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)
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue