858 changed files with 52 additions and 217564 deletions
@ -1,78 +0,0 @@ |
|||
# This file must be used with "source bin/activate" *from bash* |
|||
# you cannot run it directly |
|||
|
|||
deactivate () { |
|||
unset -f pydoc >/dev/null 2>&1 |
|||
|
|||
# reset old environment variables |
|||
# ! [ -z ${VAR+_} ] returns true if VAR is declared at all |
|||
if ! [ -z "${_OLD_VIRTUAL_PATH+_}" ] ; then |
|||
PATH="$_OLD_VIRTUAL_PATH" |
|||
export PATH |
|||
unset _OLD_VIRTUAL_PATH |
|||
fi |
|||
if ! [ -z "${_OLD_VIRTUAL_PYTHONHOME+_}" ] ; then |
|||
PYTHONHOME="$_OLD_VIRTUAL_PYTHONHOME" |
|||
export PYTHONHOME |
|||
unset _OLD_VIRTUAL_PYTHONHOME |
|||
fi |
|||
|
|||
# This should detect bash and zsh, which have a hash command that must |
|||
# be called to get it to forget past commands. Without forgetting |
|||
# past commands the $PATH changes we made may not be respected |
|||
if [ -n "${BASH-}" ] || [ -n "${ZSH_VERSION-}" ] ; then |
|||
hash -r 2>/dev/null |
|||
fi |
|||
|
|||
if ! [ -z "${_OLD_VIRTUAL_PS1+_}" ] ; then |
|||
PS1="$_OLD_VIRTUAL_PS1" |
|||
export PS1 |
|||
unset _OLD_VIRTUAL_PS1 |
|||
fi |
|||
|
|||
unset VIRTUAL_ENV |
|||
if [ ! "${1-}" = "nondestructive" ] ; then |
|||
# Self destruct! |
|||
unset -f deactivate |
|||
fi |
|||
} |
|||
|
|||
# unset irrelevant variables |
|||
deactivate nondestructive |
|||
|
|||
VIRTUAL_ENV="/home/wes/MGOAL/venv" |
|||
export VIRTUAL_ENV |
|||
|
|||
_OLD_VIRTUAL_PATH="$PATH" |
|||
PATH="$VIRTUAL_ENV/bin:$PATH" |
|||
export PATH |
|||
|
|||
# unset PYTHONHOME if set |
|||
if ! [ -z "${PYTHONHOME+_}" ] ; then |
|||
_OLD_VIRTUAL_PYTHONHOME="$PYTHONHOME" |
|||
unset PYTHONHOME |
|||
fi |
|||
|
|||
if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT-}" ] ; then |
|||
_OLD_VIRTUAL_PS1="$PS1" |
|||
if [ "x" != x ] ; then |
|||
PS1="$PS1" |
|||
else |
|||
PS1="(`basename \"$VIRTUAL_ENV\"`) $PS1" |
|||
fi |
|||
export PS1 |
|||
fi |
|||
|
|||
# Make sure to unalias pydoc if it's already there |
|||
alias pydoc 2>/dev/null >/dev/null && unalias pydoc |
|||
|
|||
pydoc () { |
|||
python -m pydoc "$@" |
|||
} |
|||
|
|||
# This should detect bash and zsh, which have a hash command that must |
|||
# be called to get it to forget past commands. Without forgetting |
|||
# past commands the $PATH changes we made may not be respected |
|||
if [ -n "${BASH-}" ] || [ -n "${ZSH_VERSION-}" ] ; then |
|||
hash -r 2>/dev/null |
|||
fi |
@ -1,36 +0,0 @@ |
|||
# This file must be used with "source bin/activate.csh" *from csh*. |
|||
# You cannot run it directly. |
|||
# Created by Davide Di Blasi <davidedb@gmail.com>. |
|||
|
|||
alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; test "\!:*" != "nondestructive" && unalias deactivate && unalias pydoc' |
|||
|
|||
# Unset irrelevant variables. |
|||
deactivate nondestructive |
|||
|
|||
setenv VIRTUAL_ENV "/home/wes/MGOAL/venv" |
|||
|
|||
set _OLD_VIRTUAL_PATH="$PATH" |
|||
setenv PATH "$VIRTUAL_ENV/bin:$PATH" |
|||
|
|||
|
|||
|
|||
if ("" != "") then |
|||
set env_name = "" |
|||
else |
|||
set env_name = `basename "$VIRTUAL_ENV"` |
|||
endif |
|||
|
|||
# Could be in a non-interactive environment, |
|||
# in which case, $prompt is undefined and we wouldn't |
|||
# care about the prompt anyway. |
|||
if ( $?prompt ) then |
|||
set _OLD_VIRTUAL_PROMPT="$prompt" |
|||
set prompt = "[$env_name] $prompt" |
|||
endif |
|||
|
|||
unset env_name |
|||
|
|||
alias pydoc python -m pydoc |
|||
|
|||
rehash |
|||
|
@ -1,76 +0,0 @@ |
|||
# This file must be used using `. bin/activate.fish` *within a running fish ( http://fishshell.com ) session*. |
|||
# Do not run it directly. |
|||
|
|||
function deactivate -d 'Exit virtualenv mode and return to the normal environment.' |
|||
# reset old environment variables |
|||
if test -n "$_OLD_VIRTUAL_PATH" |
|||
set -gx PATH $_OLD_VIRTUAL_PATH |
|||
set -e _OLD_VIRTUAL_PATH |
|||
end |
|||
|
|||
if test -n "$_OLD_VIRTUAL_PYTHONHOME" |
|||
set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME |
|||
set -e _OLD_VIRTUAL_PYTHONHOME |
|||
end |
|||
|
|||
if test -n "$_OLD_FISH_PROMPT_OVERRIDE" |
|||
# Set an empty local `$fish_function_path` to allow the removal of `fish_prompt` using `functions -e`. |
|||
set -l fish_function_path |
|||
|
|||
# Erase virtualenv's `fish_prompt` and restore the original. |
|||
functions -e fish_prompt |
|||
functions -c _old_fish_prompt fish_prompt |
|||
functions -e _old_fish_prompt |
|||
set -e _OLD_FISH_PROMPT_OVERRIDE |
|||
end |
|||
|
|||
set -e VIRTUAL_ENV |
|||
|
|||
if test "$argv[1]" != 'nondestructive' |
|||
# Self-destruct! |
|||
functions -e pydoc |
|||
functions -e deactivate |
|||
end |
|||
end |
|||
|
|||
# Unset irrelevant variables. |
|||
deactivate nondestructive |
|||
|
|||
set -gx VIRTUAL_ENV "/home/wes/MGOAL/venv" |
|||
|
|||
set -gx _OLD_VIRTUAL_PATH $PATH |
|||
set -gx PATH "$VIRTUAL_ENV/bin" $PATH |
|||
|
|||
# Unset `$PYTHONHOME` if set. |
|||
if set -q PYTHONHOME |
|||
set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME |
|||
set -e PYTHONHOME |
|||
end |
|||
|
|||
function pydoc |
|||
python -m pydoc $argv |
|||
end |
|||
|
|||
if test -z "$VIRTUAL_ENV_DISABLE_PROMPT" |
|||
# Copy the current `fish_prompt` function as `_old_fish_prompt`. |
|||
functions -c fish_prompt _old_fish_prompt |
|||
|
|||
function fish_prompt |
|||
# Save the current $status, for fish_prompts that display it. |
|||
set -l old_status $status |
|||
|
|||
# Prompt override provided? |
|||
# If not, just prepend the environment name. |
|||
if test -n "" |
|||
printf '%s%s' "" (set_color normal) |
|||
else |
|||
printf '%s(%s) ' (set_color normal) (basename "$VIRTUAL_ENV") |
|||
end |
|||
|
|||
# Restore the original $status |
|||
echo "exit $old_status" | source |
|||
_old_fish_prompt |
|||
end |
|||
|
|||
set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV" |
|||
end |
@ -1,34 +0,0 @@ |
|||
"""By using execfile(this_file, dict(__file__=this_file)) you will |
|||
activate this virtualenv environment. |
|||
|
|||
This can be used when you must use an existing Python interpreter, not |
|||
the virtualenv bin/python |
|||
""" |
|||
|
|||
try: |
|||
__file__ |
|||
except NameError: |
|||
raise AssertionError( |
|||
"You must run this like execfile('path/to/activate_this.py', dict(__file__='path/to/activate_this.py'))") |
|||
import sys |
|||
import os |
|||
|
|||
old_os_path = os.environ.get('PATH', '') |
|||
os.environ['PATH'] = os.path.dirname(os.path.abspath(__file__)) + os.pathsep + old_os_path |
|||
base = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) |
|||
if sys.platform == 'win32': |
|||
site_packages = os.path.join(base, 'Lib', 'site-packages') |
|||
else: |
|||
site_packages = os.path.join(base, 'lib', 'python%s' % sys.version[:3], 'site-packages') |
|||
prev_sys_path = list(sys.path) |
|||
import site |
|||
site.addsitedir(site_packages) |
|||
sys.real_prefix = sys.prefix |
|||
sys.prefix = base |
|||
# Move the added items to the front of the path: |
|||
new_sys_path = [] |
|||
for item in list(sys.path): |
|||
if item not in prev_sys_path: |
|||
new_sys_path.append(item) |
|||
sys.path.remove(item) |
|||
sys.path[:0] = new_sys_path |
@ -1,11 +0,0 @@ |
|||
#!/home/wes/MGOAL/venv/bin/python2 |
|||
|
|||
# -*- coding: utf-8 -*- |
|||
import re |
|||
import sys |
|||
|
|||
from setuptools.command.easy_install import main |
|||
|
|||
if __name__ == '__main__': |
|||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) |
|||
sys.exit(main()) |
@ -1,11 +0,0 @@ |
|||
#!/home/wes/MGOAL/venv/bin/python2 |
|||
|
|||
# -*- coding: utf-8 -*- |
|||
import re |
|||
import sys |
|||
|
|||
from setuptools.command.easy_install import main |
|||
|
|||
if __name__ == '__main__': |
|||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) |
|||
sys.exit(main()) |
@ -1,11 +0,0 @@ |
|||
#!/home/wes/MGOAL/venv/bin/python2 |
|||
|
|||
# -*- coding: utf-8 -*- |
|||
import re |
|||
import sys |
|||
|
|||
from flask.cli import main |
|||
|
|||
if __name__ == '__main__': |
|||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) |
|||
sys.exit(main()) |
@ -1,11 +0,0 @@ |
|||
#!/home/wes/MGOAL/venv/bin/python2 |
|||
|
|||
# -*- coding: utf-8 -*- |
|||
import re |
|||
import sys |
|||
|
|||
from pip import main |
|||
|
|||
if __name__ == '__main__': |
|||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) |
|||
sys.exit(main()) |
@ -1,11 +0,0 @@ |
|||
#!/home/wes/MGOAL/venv/bin/python2 |
|||
|
|||
# -*- coding: utf-8 -*- |
|||
import re |
|||
import sys |
|||
|
|||
from pip import main |
|||
|
|||
if __name__ == '__main__': |
|||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) |
|||
sys.exit(main()) |
@ -1,11 +0,0 @@ |
|||
#!/home/wes/MGOAL/venv/bin/python2 |
|||
|
|||
# -*- coding: utf-8 -*- |
|||
import re |
|||
import sys |
|||
|
|||
from pip import main |
|||
|
|||
if __name__ == '__main__': |
|||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) |
|||
sys.exit(main()) |
@ -1 +0,0 @@ |
|||
python2 |
@ -1,78 +0,0 @@ |
|||
#!/home/wes/MGOAL/venv/bin/python |
|||
|
|||
import sys |
|||
import getopt |
|||
import sysconfig |
|||
|
|||
valid_opts = ['prefix', 'exec-prefix', 'includes', 'libs', 'cflags', |
|||
'ldflags', 'help'] |
|||
|
|||
if sys.version_info >= (3, 2): |
|||
valid_opts.insert(-1, 'extension-suffix') |
|||
valid_opts.append('abiflags') |
|||
if sys.version_info >= (3, 3): |
|||
valid_opts.append('configdir') |
|||
|
|||
|
|||
def exit_with_usage(code=1): |
|||
sys.stderr.write("Usage: {0} [{1}]\n".format( |
|||
sys.argv[0], '|'.join('--'+opt for opt in valid_opts))) |
|||
sys.exit(code) |
|||
|
|||
try: |
|||
opts, args = getopt.getopt(sys.argv[1:], '', valid_opts) |
|||
except getopt.error: |
|||
exit_with_usage() |
|||
|
|||
if not opts: |
|||
exit_with_usage() |
|||
|
|||
pyver = sysconfig.get_config_var('VERSION') |
|||
getvar = sysconfig.get_config_var |
|||
|
|||
opt_flags = [flag for (flag, val) in opts] |
|||
|
|||
if '--help' in opt_flags: |
|||
exit_with_usage(code=0) |
|||
|
|||
for opt in opt_flags: |
|||
if opt == '--prefix': |
|||
print(sysconfig.get_config_var('prefix')) |
|||
|
|||
elif opt == '--exec-prefix': |
|||
print(sysconfig.get_config_var('exec_prefix')) |
|||
|
|||
elif opt in ('--includes', '--cflags'): |
|||
flags = ['-I' + sysconfig.get_path('include'), |
|||
'-I' + sysconfig.get_path('platinclude')] |
|||
if opt == '--cflags': |
|||
flags.extend(getvar('CFLAGS').split()) |
|||
print(' '.join(flags)) |
|||
|
|||
elif opt in ('--libs', '--ldflags'): |
|||
abiflags = getattr(sys, 'abiflags', '') |
|||
libs = ['-lpython' + pyver + abiflags] |
|||
libs += getvar('LIBS').split() |
|||
libs += getvar('SYSLIBS').split() |
|||
# add the prefix/lib/pythonX.Y/config dir, but only if there is no |
|||
# shared library in prefix/lib/. |
|||
if opt == '--ldflags': |
|||
if not getvar('Py_ENABLE_SHARED'): |
|||
libs.insert(0, '-L' + getvar('LIBPL')) |
|||
if not getvar('PYTHONFRAMEWORK'): |
|||
libs.extend(getvar('LINKFORSHARED').split()) |
|||
print(' '.join(libs)) |
|||
|
|||
elif opt == '--extension-suffix': |
|||
ext_suffix = sysconfig.get_config_var('EXT_SUFFIX') |
|||
if ext_suffix is None: |
|||
ext_suffix = sysconfig.get_config_var('SO') |
|||
print(ext_suffix) |
|||
|
|||
elif opt == '--abiflags': |
|||
if not getattr(sys, 'abiflags', None): |
|||
exit_with_usage() |
|||
print(sys.abiflags) |
|||
|
|||
elif opt == '--configdir': |
|||
print(sysconfig.get_config_var('LIBPL')) |
Binary file not shown.
@ -1 +0,0 @@ |
|||
python2 |
@ -1,11 +0,0 @@ |
|||
#!/home/wes/MGOAL/venv/bin/python2 |
|||
|
|||
# -*- coding: utf-8 -*- |
|||
import re |
|||
import sys |
|||
|
|||
from wheel.tool import main |
|||
|
|||
if __name__ == '__main__': |
|||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) |
|||
sys.exit(main()) |
@ -1 +0,0 @@ |
|||
/usr/include/python2.7 |
@ -1 +0,0 @@ |
|||
/usr/lib/python2.7/UserDict.py |
@ -1 +0,0 @@ |
|||
/usr/lib/python2.7/_abcoll.py |
@ -1 +0,0 @@ |
|||
/usr/lib/python2.7/_weakrefset.py |
@ -1 +0,0 @@ |
|||
/usr/lib/python2.7/abc.py |
@ -1 +0,0 @@ |
|||
/usr/lib/python2.7/codecs.py |
@ -1 +0,0 @@ |
|||
/usr/lib/python2.7/config |
@ -1 +0,0 @@ |
|||
/usr/lib/python2.7/copy_reg.py |
@ -1,101 +0,0 @@ |
|||
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 |
@ -1,6 +0,0 @@ |
|||
# 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 |
@ -1 +0,0 @@ |
|||
/usr/lib/python2.7/encodings |
@ -1 +0,0 @@ |
|||
/usr/lib/python2.7/fnmatch.py |
@ -1 +0,0 @@ |
|||
/usr/lib/python2.7/genericpath.py |
@ -1 +0,0 @@ |
|||
/usr/lib/python2.7/lib-dynload |
@ -1 +0,0 @@ |
|||
/usr/lib/python2.7/linecache.py |
@ -1 +0,0 @@ |
|||
/usr/lib/python2.7/locale.py |
@ -1 +0,0 @@ |
|||
/usr/lib/python2.7/ntpath.py |
@ -1 +0,0 @@ |
|||
/usr |
@ -1 +0,0 @@ |
|||
/usr/lib/python2.7/os.py |
@ -1 +0,0 @@ |
|||
/usr/lib/python2.7/posixpath.py |
@ -1 +0,0 @@ |
|||
/usr/lib/python2.7/re.py |
@ -1,44 +0,0 @@ |
|||
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/ |
|||
|
|||
Links |
|||
````` |
|||
|
|||
* `website <http://flask.pocoo.org/>`_ |
|||
* `documentation <http://flask.pocoo.org/docs/>`_ |
|||
* `development version |
|||
<http://github.com/pallets/flask/zipball/master#egg=Flask-dev>`_ |
|||
|
|||
|
|||
|
@ -1 +0,0 @@ |
|||
pip |
@ -1,73 +0,0 @@ |
|||
Metadata-Version: 2.0 |
|||
Name: Flask |
|||
Version: 0.11.1 |
|||
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/ |
|||
|
|||
Links |
|||
````` |
|||
|
|||
* `website <http://flask.pocoo.org/>`_ |
|||
* `documentation <http://flask.pocoo.org/docs/>`_ |
|||
* `development version |
|||
<http://github.com/pallets/flask/zipball/master#egg=Flask-dev>`_ |
|||
|
|||
|
|||
|
@ -1,51 +0,0 @@ |
|||
Flask-0.11.1.dist-info/DESCRIPTION.rst,sha256=d3yS7Rb_P-vHUNF_euyueS52NGfpmuqg-C4FVuyGL1w,726 |
|||
Flask-0.11.1.dist-info/METADATA,sha256=JYsqnubNfoj5zUbNv3Ip0Oim6ubPsjTRmdgDj0vsQOQ,1864 |
|||
Flask-0.11.1.dist-info/RECORD,, |
|||
Flask-0.11.1.dist-info/WHEEL,sha256=o2k-Qa-RMNIJmUdIc7KU6VWR_ErNRbWNlxDIpl7lm34,110 |
|||
Flask-0.11.1.dist-info/entry_points.txt,sha256=jzk2Wy2h30uEcqqzd4CVnlzsMXB-vaD5GXjuPMXmTmI,60 |
|||
Flask-0.11.1.dist-info/metadata.json,sha256=mZ1xu9uLOritQIZ0KTAMKnzcA1PHcyFP6e7pgi2Uh64,1363 |
|||
Flask-0.11.1.dist-info/top_level.txt,sha256=dvi65F6AeGWVU0TBpYiC04yM60-FX1gJFkK31IKQr5c,6 |
|||
flask/__init__.py,sha256=nPn1VVakZyNaD7j1f3k8I4y81ch8U_aKTUhGWE0mcTY,1673 |
|||
flask/__main__.py,sha256=cldbNi5zpjE68XzIWI8uYHNWwBHHVJmwtlXWk6P4CO4,291 |
|||
flask/_compat.py,sha256=vtZmNzjdZ5slXhSrjOVIX52C_FIY03xipZjJdrWUv1o,2490 |
|||
flask/app.py,sha256=Fmtl5tQjFcz-x6jSFpRDX7AmLSu-qPP4jvpx2G7d2EE,83370 |
|||
flask/blueprints.py,sha256=6HVasMcPcaq7tk36kCrgX4bnhTkky4G5WIWCyyJL8HY,16872 |
|||
flask/cli.py,sha256=mUcrLCj_e_GjTxM5YOF4f_qCB3kPphTFwDHPuStrL4s,16941 |
|||
flask/config.py,sha256=94IXmQjOxy4L-EsW5R5cljc9uzzCdYNFVwZjg4uJ2Xg,9602 |
|||
flask/ctx.py,sha256=UPA0YwoIlHP0txOGanC9lQLSGv6eCqV5Fmw2cVJRmgQ,14739 |
|||
flask/debughelpers.py,sha256=z-uQavKIymOZl0WQDLXsnacA00ERIlCx3S3Tnb_OYsE,6024 |
|||
flask/exthook.py,sha256=BHC5mNVqvmMpktMxTckJKiw2wyWiKQkV8eiiK1ZXTSQ,5748 |
|||
flask/globals.py,sha256=I3m_4RssLhWW1R11zuEI8oFryHUHX3NQwjMkGXOZzg8,1645 |
|||
flask/helpers.py,sha256=VTVl7C1GRyp3y-SkX1fYGJhG-TlzfAWphglayGR6Zog,37384 |
|||
flask/json.py,sha256=Dht7yQuPBpp0YH3gETBJDo5hdeSSzHCVEEOxnSslgpg,9261 |
|||
flask/logging.py,sha256=NwB0-gTqg2htzI88_BxWcmiMWVKb0NgY2RgZTzEZQmA,2683 |
|||
flask/sessions.py,sha256=iZBE63y-1SA8PmpIIngYrjJZvc3ZY3wDZt0Q2DTFrdc,14333 |
|||
flask/signals.py,sha256=ufhmyiteedO7_nOOcsMheQwGpjPkEP93dh_I7lZlu_c,2209 |
|||
flask/templating.py,sha256=u7FbN6j56H_q6CrdJJyJ6gZtqaMa0vh1_GP12gEHRQQ,4912 |
|||
flask/testing.py,sha256=t8dNl0b8Qq8A9dUXgYp1HmLOq-FGa90gTr-gLh9WTgA,5101 |
|||
flask/views.py,sha256=1QCDSf2w9cmrrKPAmresZiBbvYsDbPnEr1-KmBkQFGY,5632 |
|||
flask/wrappers.py,sha256=avZTGHogskE_pJ1iHhULhXFPkaYoeha6vT20JskH_fc,7538 |
|||
flask/ext/__init__.py,sha256=UEezCApsG4ZJWqwUnX9YmWcNN4OVENgph_9L05n0eOM,842 |
|||
../../../bin/flask,sha256=TCnOAaDSCS_Yn-mcXLKUOrE9i1L2r4Ukgzy0gHRnUgU,227 |
|||
Flask-0.11.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 |
|||
flask/config.pyc,, |
|||
flask/testing.pyc,, |
|||
flask/wrappers.pyc,, |
|||
flask/views.pyc,, |
|||
flask/logging.pyc,, |
|||
flask/json.pyc,, |
|||
flask/helpers.pyc,, |
|||
flask/__main__.pyc,, |
|||
flask/blueprints.pyc,, |
|||
flask/signals.pyc,, |
|||
flask/exthook.pyc,, |
|||
flask/__init__.pyc,, |
|||
flask/debughelpers.pyc,, |
|||
flask/templating.pyc,, |
|||
flask/ctx.pyc,, |
|||
flask/cli.pyc,, |
|||
flask/_compat.pyc,, |
|||
flask/app.pyc,, |
|||
flask/globals.pyc,, |
|||
flask/ext/__init__.pyc,, |
|||
flask/sessions.pyc,, |
@ -1,6 +0,0 @@ |
|||
Wheel-Version: 1.0 |
|||
Generator: bdist_wheel (0.29.0) |
|||
Root-Is-Purelib: true |
|||
Tag: py2-none-any |
|||
Tag: py3-none-any |
|||
|
@ -1,4 +0,0 @@ |
|||
|
|||
[console_scripts] |
|||
flask=flask.cli:main |
|||
|
@ -1 +0,0 @@ |
|||
{"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"}, "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.11.1"} |
@ -1 +0,0 @@ |
|||
flask |
@ -1,36 +0,0 @@ |
|||
Jinja2 |
|||
~~~~~~ |
|||
|
|||
Jinja2 is a template engine written in pure Python. It provides a |
|||
`Django`_ inspired non-XML syntax but supports inline expressions and |
|||
an optional `sandboxed`_ environment. |
|||
|
|||
Nutshell |
|||
-------- |
|||
|
|||
Here a small example of a Jinja template:: |
|||
|
|||
{% extends 'base.html' %} |
|||
{% block title %}Memberlist{% endblock %} |
|||
{% block content %} |
|||
<ul> |
|||
{% for user in users %} |
|||
<li><a href="{{ user.url }}">{{ user.username }}</a></li> |
|||
{% endfor %} |
|||
</ul> |
|||
{% endblock %} |
|||
|
|||
Philosophy |
|||
---------- |
|||
|
|||
Application logic is for the controller but don't try to make the life |
|||
for the template designer too hard by giving him too few functionality. |
|||
|
|||
For more informations visit the new `Jinja2 webpage`_ and `documentation`_. |
|||
|
|||
.. _sandboxed: http://en.wikipedia.org/wiki/Sandbox_(computer_security) |
|||
.. _Django: http://www.djangoproject.com/ |
|||
.. _Jinja2 webpage: http://jinja.pocoo.org/ |
|||
.. _documentation: http://jinja.pocoo.org/2/documentation/ |
|||
|
|||
|
@ -1 +0,0 @@ |
|||
pip |
@ -1,63 +0,0 @@ |
|||
Metadata-Version: 2.0 |
|||
Name: Jinja2 |
|||
Version: 2.8 |
|||
Summary: A small but fast and easy to use stand-alone template engine written in pure python. |
|||
Home-page: http://jinja.pocoo.org/ |
|||
Author: Armin Ronacher |
|||
Author-email: armin.ronacher@active-4.com |
|||
License: BSD |
|||
Platform: UNKNOWN |
|||
Classifier: Development Status :: 5 - Production/Stable |
|||
Classifier: Environment :: Web Environment |
|||
Classifier: Intended Audience :: Developers |
|||
Classifier: License :: OSI Approved :: BSD License |
|||
Classifier: Operating System :: OS Independent |
|||
Classifier: Programming Language :: Python |
|||
Classifier: Programming Language :: Python :: 2 |
|||
Classifier: Programming Language :: Python :: 2.6 |
|||
Classifier: Programming Language :: Python :: 2.7 |
|||
Classifier: Programming Language :: Python :: 3 |
|||
Classifier: Programming Language :: Python :: 3.3 |
|||
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content |
|||
Classifier: Topic :: Software Development :: Libraries :: Python Modules |
|||
Classifier: Topic :: Text Processing :: Markup :: HTML |
|||
Requires-Dist: MarkupSafe |
|||
Provides-Extra: i18n |
|||
Requires-Dist: Babel (>=0.8); extra == 'i18n' |
|||
|
|||
Jinja2 |
|||
~~~~~~ |
|||
|
|||
Jinja2 is a template engine written in pure Python. It provides a |
|||
`Django`_ inspired non-XML syntax but supports inline expressions and |
|||
an optional `sandboxed`_ environment. |
|||
|
|||
Nutshell |
|||
-------- |
|||
|
|||
Here a small example of a Jinja template:: |
|||
|
|||
{% extends 'base.html' %} |
|||
{% block title %}Memberlist{% endblock %} |
|||
{% block content %} |
|||
<ul> |
|||
{% for user in users %} |
|||
<li><a href="{{ user.url }}">{{ user.username }}</a></li> |
|||
{% endfor %} |
|||
</ul> |
|||
{% endblock %} |
|||
|
|||
Philosophy |
|||
---------- |
|||
|
|||
Application logic is for the controller but don't try to make the life |
|||
for the template designer too hard by giving him too few functionality. |
|||
|
|||
For more informations visit the new `Jinja2 webpage`_ and `documentation`_. |
|||
|
|||
.. _sandboxed: http://en.wikipedia.org/wiki/Sandbox_(computer_security) |
|||
.. _Django: http://www.djangoproject.com/ |
|||
.. _Jinja2 webpage: http://jinja.pocoo.org/ |
|||
.. _documentation: http://jinja.pocoo.org/2/documentation/ |
|||
|
|||
|
@ -1,54 +0,0 @@ |
|||
jinja2/__init__.py,sha256=c59bnaAFo63I7lYUZlO2UKHj8LPG3JACKnCrwWgvjGY,2326 |
|||
jinja2/_compat.py,sha256=O4FnYOMi4HRBfoCKkX137tt3sR6HvpnQNcwqg8ARYog,3109 |
|||
jinja2/_stringdefs.py,sha256=SFObWX5vSMeGNc_aSO3_B2EEmScCstFWtjS4K0YFBXk,404291 |
|||
jinja2/bccache.py,sha256=EMN9fsvOpwK3DfxQ9F1lmWoxU2Qlo6AnNhPXTsMrw84,12793 |
|||
jinja2/compiler.py,sha256=nQmoS6HpGwgDIC8UXkSdjPYiAjbVqZ-Gf4odO-SAR6E,63846 |
|||
jinja2/constants.py,sha256=DCr-oKC2xQO-fkOQO3kXRJW7rEYgmcsMRNpPnM66YSU,1626 |
|||
jinja2/debug.py,sha256=GEGHM8vFsNFF-kGc0_fwyj1ftMtuyaH4r0nyG-XA9Z8,11553 |
|||
jinja2/defaults.py,sha256=eLMOE7JC52QwZBu5Gz4TPZqzoJy9IgV5EynL_pW7MUw,1057 |
|||
jinja2/environment.py,sha256=jzJmujSFtxb1HvITO4TdUCOOA-hSZx0gHrxeDZ2VE-M,48120 |
|||
jinja2/exceptions.py,sha256=Q9yZOUif-lhVj5BRw0ELjfBvEdBsB7xZobgOvC2qGy4,4428 |
|||
jinja2/ext.py,sha256=X-1zCiut1cuxIteKPkJr3jb6odlVE1jciO8RnrMniPE,25072 |
|||
jinja2/filters.py,sha256=R4x2flPfyzIjrtItzpGpK4LzBvx-NOlEXH9wD-ZBWtU,30115 |
|||
jinja2/lexer.py,sha256=QyiQwAQVEE2YREZJLcA04F3yqv0XOwBbSlWaFW4xJ20,28425 |
|||
jinja2/loaders.py,sha256=BgDCvmiB0gH_zPMf-6TMemqtJdrck3IyJ8g0kWUvFa0,17380 |
|||
jinja2/meta.py,sha256=cxAOtMuSWWSQX2H8zhYsAtjNwRcNB8Zvs06Y-JlWnbk,4198 |
|||
jinja2/nodes.py,sha256=YN6hfFa0WlfToG2r-Q-yhUkAUp0O9l8KulK53mOAVUo,28954 |
|||
jinja2/optimizer.py,sha256=bNNKbo5SC5FBUm9dvP-I3GkiXZYBYIER7_g9hK77ZVI,2302 |
|||
jinja2/parser.py,sha256=pjLfkZDg2IKJKt_ixNosV-RzwAja5GWYuVeBQumIRns,35442 |
|||
jinja2/runtime.py,sha256=Ct36Q9-gVmKer45syS4j3thQ15T_DnLDh6CqvTcnPwQ,22530 |
|||
jinja2/sandbox.py,sha256=qgH4CoBsF5NwGj0krqsCOw8sg2mXmfpZKnvmZEE-da4,13327 |
|||
jinja2/tests.py,sha256=znB0L_k6wdKp_lQJvxboXwUXDy1HhFe5SSA888tHt_w,4131 |
|||
jinja2/utils.py,sha256=pjbOhQJ5NYexu2MbjA66nBibudUkYcQRZbxvbYE0tFk,16560 |
|||
jinja2/visitor.py,sha256=3hEAYD26xS_JiJBf4RfcqYPpiuR6efOH8Hh6om59eU8,3316 |
|||
Jinja2-2.8.dist-info/DESCRIPTION.rst,sha256=CXIS1UnPSk5_lZBS6Lb8ko-3lqGfjsiUwNBLXCTj2lc,975 |
|||
Jinja2-2.8.dist-info/entry_points.txt,sha256=NdzVcOrqyNyKDxD09aERj__3bFx2paZhizFDsKmVhiA,72 |
|||
Jinja2-2.8.dist-info/METADATA,sha256=Vio5F8qaEVcGzaCV1rl8tIWEKsHUFSSSAfL0u9oMmGk,2061 |
|||
Jinja2-2.8.dist-info/metadata.json,sha256=4TsqsSBwGwy0C2xF_uRZHYsRn2W5Lv4NUMBjTnXPldM,1275 |
|||
Jinja2-2.8.dist-info/RECORD,, |
|||
Jinja2-2.8.dist-info/top_level.txt,sha256=PkeVWtLb3-CqjWi1fO29OCbj55EhX_chhKrCdrVe_zs,7 |
|||
Jinja2-2.8.dist-info/WHEEL,sha256=AvR0WeTpDaxT645bl5FQxUK6NPsTls2ttpcGJg3j1Xg,110 |
|||
Jinja2-2.8.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 |
|||
jinja2/_compat.pyc,, |
|||
jinja2/defaults.pyc,, |
|||
jinja2/sandbox.pyc,, |
|||
jinja2/_stringdefs.pyc,, |
|||
jinja2/environment.pyc,, |
|||
jinja2/bccache.pyc,, |
|||
jinja2/runtime.pyc,, |
|||
jinja2/utils.pyc,, |
|||
jinja2/parser.pyc,, |
|||
jinja2/debug.pyc,, |
|||
jinja2/visitor.pyc,, |
|||
jinja2/ext.pyc,, |
|||
jinja2/lexer.pyc,, |
|||
jinja2/nodes.pyc,, |
|||
jinja2/meta.pyc,, |
|||
jinja2/compiler.pyc,, |
|||
jinja2/exceptions.pyc,, |
|||
jinja2/__init__.pyc,, |
|||
jinja2/optimizer.pyc,, |
|||
jinja2/constants.pyc,, |
|||
jinja2/tests.pyc,, |
|||
jinja2/loaders.pyc,, |
|||
jinja2/filters.pyc,, |
@ -1,6 +0,0 @@ |
|||
Wheel-Version: 1.0 |
|||
Generator: bdist_wheel (0.24.0) |
|||
Root-Is-Purelib: true |
|||
Tag: py2-none-any |
|||
Tag: py3-none-any |
|||
|
@ -1,4 +0,0 @@ |
|||
|
|||
[babel.extractors] |
|||
jinja2 = jinja2.ext:babel_extract[i18n] |
|||
|
@ -1 +0,0 @@ |
|||
{"license": "BSD", "name": "Jinja2", "metadata_version": "2.0", "generator": "bdist_wheel (0.24.0)", "summary": "A small but fast and easy to use stand-alone template engine written in pure python.", "run_requires": [{"requires": ["Babel (>=0.8)"], "extra": "i18n"}, {"requires": ["MarkupSafe"]}], "version": "2.8", "extensions": {"python.details": {"project_urls": {"Home": "http://jinja.pocoo.org/"}, "document_names": {"description": "DESCRIPTION.rst"}, "contacts": [{"role": "author", "email": "armin.ronacher@active-4.com", "name": "Armin Ronacher"}]}, "python.exports": {"babel.extractors": {"jinja2": "jinja2.ext:babel_extract [i18n]"}}}, "classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Text Processing :: Markup :: HTML"], "extras": ["i18n"]} |
@ -1 +0,0 @@ |
|||
jinja2 |
@ -1,101 +0,0 @@ |
|||
MarkupSafe |
|||
========== |
|||
|
|||
Implements a unicode subclass that supports HTML strings: |
|||
|
|||
>>> 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). |
|||
|
|||
>>> from markupsafe import soft_unicode |
|||
>>> soft_unicode(42) |
|||
u'42' |
|||
>>> soft_unicode(Markup('foo')) |
|||
Markup(u'foo') |
|||
|
|||
HTML Representations |
|||
-------------------- |
|||
|
|||
Objects can customize their HTML markup equivalent by overriding |
|||
the `__html__` function: |
|||
|
|||
>>> class Foo(object): |
|||
... def __html__(self): |
|||
... return '<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:: |
|||
|
|||
from markupsafe import Markup, escape_silent as escape |
|||
|
|||
class SilentMarkup(Markup): |
|||
__slots__ = () |
|||
|
|||
@classmethod |
|||
def escape(cls, s): |
|||
return cls(escape(s)) |
|||
|
|||
New-Style String Formatting |
|||
--------------------------- |
|||
|
|||
Starting with MarkupSafe 0.21 new style string formats from Python 2.6 and |
|||
3.x are now fully supported. Previously the escape behavior of those |
|||
functions was spotty at best. The new implementations operates under the |
|||
following algorithm: |
|||
|
|||
1. if an object has an ``__html_format__`` method it is called as |
|||
replacement for ``__format__`` with the format specifier. It either |
|||
has to return a string or markup object. |
|||
2. if an object has an ``__html__`` method it is called. |
|||
3. otherwise the default format system of Python kicks in and the result |
|||
is HTML escaped. |
|||
|
|||
Here is how you can implement your own formatting:: |
|||
|
|||
class User(object): |
|||
|
|||
def __init__(self, id, username): |
|||
self.id = id |
|||
self.username = username |
|||
|
|||
def __html_format__(self, format_spec): |
|||
if format_spec == 'link': |
|||
return Markup('<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: |
|||
|
|||
>>> 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>') |
|||
|
|||
|
@ -1 +0,0 @@ |
|||
pip |
@ -1,121 +0,0 @@ |
|||
Metadata-Version: 2.0 |
|||
Name: MarkupSafe |
|||
Version: 0.23 |
|||
Summary: Implements a XML/HTML/XHTML Markup safe string for Python |
|||
Home-page: http://github.com/mitsuhiko/markupsafe |
|||
Author: Armin Ronacher |
|||
Author-email: armin.ronacher@active-4.com |
|||
License: BSD |
|||
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: |
|||
|
|||
>>> 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). |
|||
|
|||
>>> from markupsafe import soft_unicode |
|||
>>> soft_unicode(42) |
|||
u'42' |
|||
>>> soft_unicode(Markup('foo')) |
|||
Markup(u'foo') |
|||
|
|||
HTML Representations |
|||
-------------------- |
|||
|
|||
Objects can customize their HTML markup equivalent by overriding |
|||
the `__html__` function: |
|||
|
|||
>>> class Foo(object): |
|||
... def __html__(self): |
|||
... return '<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:: |
|||
|
|||
from markupsafe import Markup, escape_silent as escape |
|||
|
|||
class SilentMarkup(Markup): |
|||
__slots__ = () |
|||
|
|||
@classmethod |
|||
def escape(cls, s): |
|||
return cls(escape(s)) |
|||
|
|||
New-Style String Formatting |
|||
--------------------------- |
|||
|
|||
Starting with MarkupSafe 0.21 new style string formats from Python 2.6 and |
|||
3.x are now fully supported. Previously the escape behavior of those |
|||
functions was spotty at best. The new implementations operates under the |
|||
following algorithm: |
|||
|
|||
1. if an object has an ``__html_format__`` method it is called as |
|||
replacement for ``__format__`` with the format specifier. It either |
|||
has to return a string or markup object. |
|||
2. if an object has an ``__html__`` method it is called. |
|||
3. otherwise the default format system of Python kicks in and the result |
|||
is HTML escaped. |
|||
|
|||
Here is how you can implement your own formatting:: |
|||
|
|||
class User(object): |
|||
|
|||
def __init__(self, id, username): |
|||
self.id = id |
|||
self.username = username |
|||
|
|||
def __html_format__(self, format_spec): |
|||
if format_spec == 'link': |
|||
return Markup('<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: |
|||
|
|||
>>> 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>') |
|||
|
|||
|
@ -1,19 +0,0 @@ |
|||
MarkupSafe-0.23.dist-info/DESCRIPTION.rst,sha256=VnEbwPneiOkqh-nzxb0DUiGlcVGHuaDQjsNBLi-yNYw,3091 |
|||
MarkupSafe-0.23.dist-info/METADATA,sha256=g-KikeSr9J7vagkJoCt0ViT2ORy9O4NYV7XtRu1Pni8,3879 |
|||
MarkupSafe-0.23.dist-info/RECORD,, |
|||
MarkupSafe-0.23.dist-info/WHEEL,sha256=LgENoDL_AkiRWbJ7HCJLnTXVvHl9ZtXZ7UZmjmcCeN0,105 |
|||
MarkupSafe-0.23.dist-info/metadata.json,sha256=y9yFyMJYU3UIRc5KfHIY6A3Z6nvJ2lXva5-7Ts2lsvY,901 |
|||
MarkupSafe-0.23.dist-info/top_level.txt,sha256=qy0Plje5IJuvsCBjejJyhDCjEAdcDLK_2agVcex8Z6U,11 |
|||
markupsafe/__init__.py,sha256=zFQpANILi3mCCALiPd6ZJdlW6ibu_hTKzikMXKXVtaM,10338 |
|||
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=gZwPEM_0zcbAzJjPuPYXk97R67QR1uUGtDvOPsvirCA,5939 |
|||
markupsafe/_speedups.so,sha256=fQbdBe1y1gzgoPajRdqAcU39EvIJQ_j_ZrgO3v2zIQk,13344 |
|||
markupsafe/tests.py,sha256=RLI4eYI0ICNZwkoN638VHXf_fDu4d_jnvbGr22j58Ng,6107 |
|||
MarkupSafe-0.23.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 |
|||
markupsafe/_constants.pyc,, |
|||
markupsafe/__init__.pyc,, |
|||
markupsafe/_native.pyc,, |
|||
markupsafe/_compat.pyc,, |
|||
markupsafe/tests.pyc,, |
@ -1,5 +0,0 @@ |
|||
Wheel-Version: 1.0 |
|||
Generator: bdist_wheel (0.29.0) |
|||
Root-Is-Purelib: false |
|||
Tag: cp27-cp27mu-linux_x86_64 |
|||
|
@ -1 +0,0 @@ |
|||
{"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"}, "project_urls": {"Home": "http://github.com/mitsuhiko/markupsafe"}}}, "generator": "bdist_wheel (0.29.0)", "license": "BSD", "metadata_version": "2.0", "name": "MarkupSafe", "summary": "Implements a XML/HTML/XHTML Markup safe string for Python", "version": "0.23"} |
@ -1 +0,0 @@ |
|||
markupsafe |
@ -1,54 +0,0 @@ |
|||
Werkzeug |
|||
======== |
|||
|
|||
Werkzeug started as simple collection of various utilities for WSGI |
|||
applications and has become one of the most advanced WSGI utility |
|||
modules. It includes a powerful debugger, full featured request and |
|||
response objects, HTTP utilities to handle entity tags, cache control |
|||
headers, HTTP dates, cookie handling, file uploads, a powerful URL |
|||
routing system and a bunch of community contributed addon modules. |
|||
|
|||
Werkzeug is unicode aware and doesn't enforce a specific template |
|||
engine, database adapter or anything else. It doesn't even enforce |
|||
a specific way of handling requests and leaves all that up to the |
|||
developer. It's most useful for end user applications which should work |
|||
on as many server environments as possible (such as blogs, wikis, |
|||
bulletin boards, etc.). |
|||
|
|||
Details and example applications are available on the |
|||
`Werkzeug website <http://werkzeug.pocoo.org/>`_. |
|||
|
|||
|
|||
Features |
|||
-------- |
|||
|
|||
- unicode awareness |
|||
|
|||
- request and response objects |
|||
|
|||
- various utility functions for dealing with HTTP headers such as |
|||
`Accept` and `Cache-Control` headers. |
|||
|
|||
- thread local objects with proper cleanup at request end |
|||
|
|||
- an interactive debugger |
|||
|
|||
- A simple WSGI server with support for threading and forking |
|||
with an automatic reloader. |
|||
|
|||
- a flexible URL routing system with REST support. |
|||
|
|||
- fully WSGI compatible |
|||
|
|||
|
|||
Development Version |
|||
------------------- |
|||
|
|||
The Werkzeug development version can be installed by cloning the git |
|||
repository from `github`_:: |
|||
|
|||
git clone git@github.com:mitsuhiko/werkzeug.git |
|||
|
|||
.. _github: http://github.com/mitsuhiko/werkzeug |
|||
|
|||
|
@ -1 +0,0 @@ |
|||
pip |
@ -1,79 +0,0 @@ |
|||
Metadata-Version: 2.0 |
|||
Name: Werkzeug |
|||
Version: 0.11.10 |
|||
Summary: The Swiss Army knife of Python web development |
|||
Home-page: http://werkzeug.pocoo.org/ |
|||
Author: Armin Ronacher |
|||
Author-email: armin.ronacher@active-4.com |
|||
License: BSD |
|||
Platform: any |
|||
Classifier: Development Status :: 5 - Production/Stable |
|||
Classifier: Environment :: Web Environment |
|||
Classifier: Intended Audience :: Developers |
|||
Classifier: License :: OSI Approved :: BSD License |
|||
Classifier: Operating System :: OS Independent |
|||
Classifier: Programming Language :: Python |
|||
Classifier: Programming Language :: Python :: 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 |
|||
|
|||
Werkzeug |
|||
======== |
|||
|
|||
Werkzeug started as simple collection of various utilities for WSGI |
|||
applications and has become one of the most advanced WSGI utility |
|||
modules. It includes a powerful debugger, full featured request and |
|||
response objects, HTTP utilities to handle entity tags, cache control |
|||
headers, HTTP dates, cookie handling, file uploads, a powerful URL |
|||
routing system and a bunch of community contributed addon modules. |
|||
|
|||
Werkzeug is unicode aware and doesn't enforce a specific template |
|||
engine, database adapter or anything else. It doesn't even enforce |
|||
a specific way of handling requests and leaves all that up to the |
|||
developer. It's most useful for end user applications which should work |
|||
on as many server environments as possible (such as blogs, wikis, |
|||
bulletin boards, etc.). |
|||
|
|||
Details and example applications are available on the |
|||
`Werkzeug website <http://werkzeug.pocoo.org/>`_. |
|||
|
|||
|
|||
Features |
|||
-------- |
|||
|
|||
- unicode awareness |
|||
|
|||
- request and response objects |
|||
|
|||
- various utility functions for dealing with HTTP headers such as |
|||
`Accept` and `Cache-Control` headers. |
|||
|
|||
- thread local objects with proper cleanup at request end |
|||
|
|||
- an interactive debugger |
|||
|
|||
- A simple WSGI server with support for threading and forking |
|||
with an automatic reloader. |
|||
|
|||
- a flexible URL routing system with REST support. |
|||
|
|||
- fully WSGI compatible |
|||
|
|||
|
|||
Development Version |
|||
------------------- |
|||
|
|||
The Werkzeug development version can be installed by cloning the git |
|||
repository from `github`_:: |
|||
|
|||
git clone git@github.com:mitsuhiko/werkzeug.git |
|||
|
|||
.. _github: http://github.com/mitsuhiko/werkzeug |
|||
|
|||
|
@ -1,94 +0,0 @@ |
|||
Werkzeug-0.11.10.dist-info/DESCRIPTION.rst,sha256=5sTwZ_Sj5aeEN8mlcOdNJ_ng40HiGazGmILLyTMX8o0,1595 |
|||
Werkzeug-0.11.10.dist-info/METADATA,sha256=vweH07PHdEwMIeOU7fvKXKi_6zY5e6d_dfVCgqT--Aw,2600 |
|||
Werkzeug-0.11.10.dist-info/RECORD,, |
|||
Werkzeug-0.11.10.dist-info/WHEEL,sha256=GrqQvamwgBV4nLoJe0vhYRSWzWsx7xjlt74FT0SWYfE,110 |
|||
Werkzeug-0.11.10.dist-info/metadata.json,sha256=PC5ATsCVx4EUlD8uEGHEhx-aTnCr9GA8vfWXT3CLwQw,1096 |
|||
Werkzeug-0.11.10.dist-info/top_level.txt,sha256=QRyj2VjwJoQkrwjwFIOlB8Xg3r9un0NtqVHQF-15xaw,9 |
|||
werkzeug/__init__.py,sha256=BDx17HnxLmB4L8OSE0Bkj3DjDTO6xLu6_nNck8QiRaw,6920 |
|||
werkzeug/_compat.py,sha256=8c4U9o6A_TR9nKCcTbpZNxpqCXcXDVIbFawwKM2s92c,6311 |
|||
werkzeug/_internal.py,sha256=IEScSoFtQ8KqFH_2ubdfscNAdQ2RIysyVupI5BR9W2U,13709 |
|||
werkzeug/_reloader.py,sha256=YQykMSQW7AlojJQ7qOlgNaXw5_CNjf9yzxplwzVdL7Q,8336 |
|||
werkzeug/datastructures.py,sha256=5CLVMLROGMoB0dSdQ7aBabma6IC_vxIx77VnMoFFVyc,87447 |
|||
werkzeug/exceptions.py,sha256=c-3fKHItsPvC52X_NwBNLcmGXR30h0WP5ynPSwCqPiw,18733 |
|||
werkzeug/filesystem.py,sha256=hHWeWo_gqLMzTRfYt8-7n2wWcWUNTnDyudQDLOBEICE,2175 |
|||
werkzeug/formparser.py,sha256=90D5Urp8Ghrzw32kAs090G0nXPYlU73NeAzPlQFMVrY,21296 |
|||
werkzeug/http.py,sha256=sqNaMmLBvi16cPoVRiBviwnVOb1bAQ1lGTrvfCdaQrY,35264 |
|||
werkzeug/local.py,sha256=4Q5gwHQJhfhZFqTR8iQDs2VHohpR1OEsP4YTwn7rt7w,14275 |
|||
werkzeug/posixemulation.py,sha256=xEF2Bxc-vUCPkiu4IbfWVd3LW7DROYAT-ExW6THqyzw,3519 |
|||
werkzeug/routing.py,sha256=TqiZD5HkwdLBnKBUjC5PlytzXmpczQC5dz54VfQzMOw,66350 |
|||
werkzeug/script.py,sha256=DwaVDcXdaOTffdNvlBdLitxWXjKaRVT32VbhDtljFPY,11365 |
|||
werkzeug/security.py,sha256=tuVc22OqoHV5K-TrYJmynCJJa12aUt9BQ3wR_vEPQ34,8971 |
|||
werkzeug/serving.py,sha256=uRUqXuA-Dw2MRA-d232cK_034-taldoj66fEFrtin7k,27736 |
|||
werkzeug/test.py,sha256=nan0aDi3g5hyUzWCtaN3XL9HrbIsNNNgMNjwpfM6qMc,34152 |
|||
werkzeug/testapp.py,sha256=3HQRW1sHZKXuAjCvFMet4KXtQG3loYTFnvn6LWt-4zI,9396 |
|||
werkzeug/urls.py,sha256=fSbI4Gb29_p02Zk21VAZQRN1QdOVY9CNTgpb2rbajNQ,36710 |
|||
werkzeug/useragents.py,sha256=uqpgPcJ5BfcCVh9nPIIl2r3duIrIuENmrbRqbAMmPDk,5418 |
|||
werkzeug/utils.py,sha256=lkybtv_mq35zV1qhelvEcILTzrMUwZ9yon6E8XwapJE,22972 |
|||
werkzeug/wrappers.py,sha256=lKYevpKD1-quk9Cop7bsFxt1eWJxU3h33HCnOI_YzSU,77011 |
|||
werkzeug/wsgi.py,sha256=S8R3pBGPlBK67s-d6Wa93nhzG27WjfcHs_ZBGIAQCxM,39573 |
|||
werkzeug/contrib/__init__.py,sha256=f7PfttZhbrImqpr5Ezre8CXgwvcGUJK7zWNpO34WWrw,623 |
|||
werkzeug/contrib/atom.py,sha256=rvijBrphjMzVObfuCR6ddu6aLwI_SiNiudu64OSTh4Q,15588 |
|||
werkzeug/contrib/cache.py,sha256=4W2WCT9Hw6HEU8yME9GuU4Xf8e50r2K84ASMxhLb6tY,27983 |
|||
werkzeug/contrib/fixers.py,sha256=MtN_YmENxoTsGvXGGERmtbQ62LaeFc5I2d1YifXNENA,10183 |
|||
werkzeug/contrib/iterio.py,sha256=pTX36rYCKO_9IEoB5sIN5cFSYszI9zdx6YhquWovcPY,10814 |
|||
werkzeug/contrib/jsrouting.py,sha256=QTmgeDoKXvNK02KzXgx9lr3cAH6fAzpwF5bBdPNvJPs,8564 |
|||
werkzeug/contrib/limiter.py,sha256=iS8-ahPZ-JLRnmfIBzxpm7O_s3lPsiDMVWv7llAIDCI,1334 |
|||
werkzeug/contrib/lint.py,sha256=XDKYx0ELn9k18xRn4SiAsCgltCuN4yLjzxnCN8tG_eM,12490 |
|||
werkzeug/contrib/profiler.py,sha256=ISwCWvwVyGpDLRBRpLjo_qUWma6GXYBrTAco4PEQSHY,5151 |
|||
werkzeug/contrib/securecookie.py,sha256=X-Ao_0NRDveW6K1Fhe4U42hHWBW8esCpA3VcBDpzWIk,12206 |
|||
werkzeug/contrib/sessions.py,sha256=uAPcnyxaxEla-bUA13gKc3KK4mwSagdzbCZzyKl3PeE,12577 |
|||
werkzeug/contrib/testtools.py,sha256=G9xN-qeihJlhExrIZMCahvQOIDxdL9NiX874jiiHFMs,2453 |
|||
werkzeug/contrib/wrappers.py,sha256=Uv5FRO5OqKwOsNgkW2-FRcw0vUDe3uiaivjPNYWNfAk,10337 |
|||
werkzeug/debug/__init__.py,sha256=qQT5YnOv9Eov9Jt5eLtP6MOqwpmo-tORJ6HcQmmnvro,17271 |
|||
werkzeug/debug/console.py,sha256=B7uAu9Rk60siDnGlEt-A_q1ZR4zCtmxx5itg3X-BOxo,5599 |
|||
werkzeug/debug/repr.py,sha256=NaoB89aHb0vuvdSWels-GWdeGDZp76uE4uSNZPX1jAM,9354 |
|||
werkzeug/debug/tbtools.py,sha256=L5P5TkGEHc_Bc5duNosP6D4CNe7ieTo1oiPX8nKQdek,18402 |
|||
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=PEMBoNuD6fUaNou8Km_ZvVmFcIA3z3k3jSEMWLW-cA0,6187 |
|||
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=7x1s8olZO1XHalqD4M9MWn9vRqQkA635S9_6zRoe220,6231 |
|||
werkzeug/debug/shared/ubuntu.ttf,sha256=1eaHFyepmy4FyDvjLVzpITrGEBu_CZYY94jE0nED1c0,70220 |
|||
Werkzeug-0.11.10.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 |
|||
werkzeug/_reloader.pyc,, |
|||
werkzeug/filesystem.pyc,, |
|||
werkzeug/contrib/testtools.pyc,, |
|||
werkzeug/formparser.pyc,, |
|||
werkzeug/_compat.pyc,, |
|||
werkzeug/posixemulation.pyc,, |
|||
werkzeug/wsgi.pyc,, |
|||
werkzeug/serving.pyc,, |
|||
werkzeug/contrib/__init__.pyc,, |
|||
werkzeug/contrib/iterio.pyc,, |
|||
werkzeug/test.pyc,, |
|||
werkzeug/__init__.pyc,, |
|||
werkzeug/contrib/limiter.pyc,, |
|||
werkzeug/debug/tbtools.pyc,, |
|||
werkzeug/contrib/sessions.pyc,, |
|||
werkzeug/contrib/securecookie.pyc,, |
|||
werkzeug/local.pyc,, |
|||
werkzeug/utils.pyc,, |
|||
werkzeug/_internal.pyc,, |
|||
werkzeug/security.pyc,, |
|||
werkzeug/contrib/cache.pyc,, |
|||
werkzeug/script.pyc,, |
|||
werkzeug/routing.pyc,, |
|||
werkzeug/wrappers.pyc,, |
|||
werkzeug/contrib/jsrouting.pyc,, |
|||
werkzeug/contrib/fixers.pyc,, |
|||
werkzeug/contrib/profiler.pyc,, |
|||
werkzeug/debug/console.pyc,, |
|||
werkzeug/debug/__init__.pyc,, |
|||
werkzeug/datastructures.pyc,, |
|||
werkzeug/http.pyc,, |
|||
werkzeug/urls.pyc,, |
|||
werkzeug/contrib/lint.pyc,, |
|||
werkzeug/contrib/wrappers.pyc,, |
|||
werkzeug/exceptions.pyc,, |
|||
werkzeug/contrib/atom.pyc,, |
|||
werkzeug/testapp.pyc,, |
|||
werkzeug/debug/repr.pyc,, |
|||
werkzeug/useragents.pyc,, |
@ -1,6 +0,0 @@ |
|||
Wheel-Version: 1.0 |
|||
Generator: bdist_wheel (0.26.0) |
|||
Root-Is-Purelib: true |
|||
Tag: py2-none-any |
|||
Tag: py3-none-any |
|||
|
@ -1 +0,0 @@ |
|||
{"generator": "bdist_wheel (0.26.0)", "summary": "The Swiss Army knife of Python web development", "classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Software Development :: Libraries :: Python Modules"], "extensions": {"python.details": {"project_urls": {"Home": "http://werkzeug.pocoo.org/"}, "contacts": [{"email": "armin.ronacher@active-4.com", "name": "Armin Ronacher", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}}}, "license": "BSD", "metadata_version": "2.0", "name": "Werkzeug", "platform": "any", "version": "0.11.10"} |
@ -1 +0,0 @@ |
|||
werkzeug |
@ -1,3 +0,0 @@ |
|||
UNKNOWN |
|||
|
|||
|
@ -1 +0,0 @@ |
|||
pip |
@ -1,16 +0,0 @@ |
|||
Metadata-Version: 2.0 |
|||
Name: click |
|||
Version: 6.6 |
|||
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 |
|||
|
|||
|
@ -1,41 +0,0 @@ |
|||
click/__init__.py,sha256=-BDiJ4G3FXy1nn7Lt9UTIYdKb7SZTHnTm9yv2WQbHm0,2858 |
|||
click/_bashcomplete.py,sha256=J8L3TvE23YVicEf5LQdiN5pCS3aAquP8D8897Jp_PvE,2423 |
|||
click/_compat.py,sha256=xP-n7Tkuof1I6aEzcR6A88vusa-Lu6gpkPxnO-KY0pA,20706 |
|||
click/_termui_impl.py,sha256=BbBPaw2nDEmNYgjBl_JlxUOSAzFexO0jL3z0OY-Z6BM,16377 |
|||
click/_textwrap.py,sha256=gwS4m7bdQiJnzaDG8osFcRb-5vn4t4l2qSCy-5csCEc,1198 |
|||
click/_unicodefun.py,sha256=vK1_Y_d29nxYhE7_QF8y8-DLjG_fYDhiT-LlcmiHVeE,4265 |
|||
click/_winconsole.py,sha256=MzG46DEYPoRyx4SO7EIhFuFZHESgooAfJLIukbB6p5c,7790 |
|||
click/core.py,sha256=PFAK6hjAiM8fcXxdHNwaDKINSoHYCYfLV8n9TdodYS4,70085 |
|||
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=LjWcVtxA5vMdWx5ev7KSjU4vcTlxZiSDrP7tOV1nCxk,11004 |
|||
click/types.py,sha256=ZGb2lmFs5Vwd9loTRIMbGcqhPVOql8mGoBhWBRT6V4E,18864 |
|||
click/utils.py,sha256=1jalPlkUU28JReTEQeeSFtbJd-SirYWBNfjtELBKzT4,14916 |
|||
click-6.6.dist-info/DESCRIPTION.rst,sha256=OCTuuN6LcWulhHS3d5rfjdsQtW22n7HENFRh6jC6ego,10 |
|||
click-6.6.dist-info/METADATA,sha256=gYQxaGWBuXfQy0NGVARhka10cSm9b_6XF6WeD7k3_Rg,424 |
|||
click-6.6.dist-info/RECORD,, |
|||
click-6.6.dist-info/WHEEL,sha256=o2k-Qa-RMNIJmUdIc7KU6VWR_ErNRbWNlxDIpl7lm34,110 |
|||
click-6.6.dist-info/metadata.json,sha256=6QQvh7-Y7ZLMEiYZVIYzVKGeKPmzdxcgSIioWfhp9DE,568 |
|||
click-6.6.dist-info/top_level.txt,sha256=J1ZQogalYS4pphY_lPECoNMfw0HzTSrZglC4Yfwo4xA,6 |
|||
click-6.6.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 |
|||
click/_unicodefun.pyc,, |
|||
click/_compat.pyc,, |
|||
click/_termui_impl.pyc,, |
|||
click/_textwrap.pyc,, |
|||
click/formatting.pyc,, |
|||
click/exceptions.pyc,, |
|||
click/decorators.pyc,, |
|||
click/parser.pyc,, |
|||
click/testing.pyc,, |
|||
click/utils.pyc,, |
|||
click/_bashcomplete.pyc,, |
|||
click/types.pyc,, |
|||
click/termui.pyc,, |
|||
click/core.pyc,, |
|||
click/_winconsole.pyc,, |
|||
click/__init__.pyc,, |
|||
click/globals.pyc,, |
@ -1,6 +0,0 @@ |
|||
Wheel-Version: 1.0 |
|||
Generator: bdist_wheel (0.29.0) |
|||
Root-Is-Purelib: true |
|||
Tag: py2-none-any |
|||
Tag: py3-none-any |
|||
|
@ -1 +0,0 @@ |
|||
{"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.29.0)", "metadata_version": "2.0", "name": "click", "summary": "A simple wrapper around optparse for powerful command line utilities.", "version": "6.6"} |
@ -1 +0,0 @@ |
|||
click |
@ -1,98 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
""" |
|||
click |
|||
~~~~~ |
|||
|
|||
Click is a simple Python module that wraps the stdlib's optparse to make |
|||
writing command line scripts fun. Unlike other modules, it's based around |
|||
a simple API that does not come with too much magic and is composable. |
|||
|
|||
In case optparse ever gets removed from the stdlib, it will be shipped by |
|||
this module. |
|||
|
|||
:copyright: (c) 2014 by Armin Ronacher. |
|||
:license: BSD, see LICENSE for more details. |
|||
""" |
|||
|
|||
# Core classes |
|||
from .core import Context, BaseCommand, Command, MultiCommand, Group, \ |
|||
CommandCollection, Parameter, Option, Argument |
|||
|
|||
# Globals |
|||
from .globals import get_current_context |
|||
|
|||
# Decorators |
|||
from .decorators import pass_context, pass_obj, make_pass_decorator, \ |
|||
command, group, argument, option, confirmation_option, \ |
|||
password_option, version_option, help_option |
|||
|
|||
# Types |
|||
from .types import ParamType, File, Path, Choice, IntRange, Tuple, \ |
|||
STRING, INT, FLOAT, BOOL, UUID, UNPROCESSED |
|||
|
|||
# Utilities |
|||
from .utils import echo, get_binary_stream, get_text_stream, open_file, \ |
|||
format_filename, get_app_dir, get_os_args |
|||
|
|||
# Terminal functions |
|||
from .termui import prompt, confirm, get_terminal_size, echo_via_pager, \ |
|||
progressbar, clear, style, unstyle, secho, edit, launch, getchar, \ |
|||
pause |
|||
|
|||
# Exceptions |
|||
from .exceptions import ClickException, UsageError, BadParameter, \ |
|||
FileError, Abort, NoSuchOption, BadOptionUsage, BadArgumentUsage, \ |
|||
MissingParameter |
|||
|
|||
# Formatting |
|||
from .formatting import HelpFormatter, wrap_text |
|||
|
|||
# Parsing |
|||
from .parser import OptionParser |
|||
|
|||
|
|||
__all__ = [ |
|||
# Core classes |
|||
'Context', 'BaseCommand', 'Command', 'MultiCommand', 'Group', |
|||
'CommandCollection', 'Parameter', 'Option', 'Argument', |
|||
|
|||
# Globals |
|||
'get_current_context', |
|||
|
|||
# Decorators |
|||
'pass_context', 'pass_obj', 'make_pass_decorator', 'command', 'group', |
|||
'argument', 'option', 'confirmation_option', 'password_option', |
|||
'version_option', 'help_option', |
|||
|
|||
# Types |
|||
'ParamType', 'File', 'Path', 'Choice', 'IntRange', 'Tuple', 'STRING', |
|||
'INT', 'FLOAT', 'BOOL', 'UUID', 'UNPROCESSED', |
|||
|
|||
# Utilities |
|||
'echo', 'get_binary_stream', 'get_text_stream', 'open_file', |
|||
'format_filename', 'get_app_dir', 'get_os_args', |
|||
|
|||
# Terminal functions |
|||
'prompt', 'confirm', 'get_terminal_size', 'echo_via_pager', |
|||
'progressbar', 'clear', 'style', 'unstyle', 'secho', 'edit', 'launch', |
|||
'getchar', 'pause', |
|||
|
|||
# Exceptions |
|||
'ClickException', 'UsageError', 'BadParameter', 'FileError', |
|||
'Abort', 'NoSuchOption', 'BadOptionUsage', 'BadArgumentUsage', |
|||
'MissingParameter', |
|||
|
|||
# Formatting |
|||
'HelpFormatter', 'wrap_text', |
|||
|
|||
# Parsing |
|||
'OptionParser', |
|||
] |
|||
|
|||
|
|||
# Controls if click should emit the warning about the use of unicode |
|||
# literals. |
|||
disable_unicode_literals_warning = False |
|||
|
|||
|
|||
__version__ = '6.6' |
@ -1,83 +0,0 @@ |
|||
import os |
|||
import re |
|||
from .utils import echo |
|||
from .parser import split_arg_string |
|||
from .core import MultiCommand, Option |
|||
|
|||
|
|||
COMPLETION_SCRIPT = ''' |
|||
%(complete_func)s() { |
|||
COMPREPLY=( $( env COMP_WORDS="${COMP_WORDS[*]}" \\ |
|||
COMP_CWORD=$COMP_CWORD \\ |
|||
%(autocomplete_var)s=complete $1 ) ) |
|||
return 0 |
|||
} |
|||
|
|||
complete -F %(complete_func)s -o default %(script_names)s |
|||
''' |
|||
|
|||
_invalid_ident_char_re = re.compile(r'[^a-zA-Z0-9_]') |
|||
|
|||
|
|||
def get_completion_script(prog_name, complete_var): |
|||
cf_name = _invalid_ident_char_re.sub('', prog_name.replace('-', '_')) |
|||
return (COMPLETION_SCRIPT % { |
|||
'complete_func': '_%s_completion' % cf_name, |
|||
'script_names': prog_name, |
|||
'autocomplete_var': complete_var, |
|||
}).strip() + ';' |
|||
|
|||
|
|||
def resolve_ctx(cli, prog_name, args): |
|||
ctx = cli.make_context(prog_name, args, resilient_parsing=True) |
|||
while ctx.args + ctx.protected_args and isinstance(ctx.command, MultiCommand): |
|||
a = ctx.args + ctx.protected_args |
|||
cmd = ctx.command.get_command(ctx, a[0]) |
|||
if cmd is None: |
|||
return None |
|||
ctx = cmd.make_context(a[0], a[1:], parent=ctx, resilient_parsing=True) |
|||
return ctx |
|||
|
|||
|
|||
def get_choices(cli, prog_name, args, incomplete): |
|||
ctx = resolve_ctx(cli, prog_name, args) |
|||
if ctx is None: |
|||
return |
|||
|
|||
choices = [] |
|||
if incomplete and not incomplete[:1].isalnum(): |
|||
for param in ctx.command.params: |
|||
if not isinstance(param, Option): |
|||
continue |
|||
choices.extend(param.opts) |
|||
choices.extend(param.secondary_opts) |
|||
elif isinstance(ctx.command, MultiCommand): |
|||
choices.extend(ctx.command.list_commands(ctx)) |
|||
|
|||
for item in choices: |
|||
if item.startswith(incomplete): |
|||
yield item |
|||
|
|||
|
|||
def do_complete(cli, prog_name): |
|||
cwords = split_arg_string(os.environ['COMP_WORDS']) |
|||
cword = int(os.environ['COMP_CWORD']) |
|||
args = cwords[1:cword] |
|||
try: |
|||
incomplete = cwords[cword] |
|||
except IndexError: |
|||
incomplete = '' |
|||
|
|||
for item in get_choices(cli, prog_name, args, incomplete): |
|||
echo(item) |
|||
|
|||
return True |
|||
|
|||
|
|||
def bashcomplete(cli, prog_name, complete_var, complete_instr): |
|||
if complete_instr == 'source': |
|||
echo(get_completion_script(prog_name, complete_var)) |
|||
return True |
|||
elif complete_instr == 'complete': |
|||
return do_complete(cli, prog_name) |
|||
return False |
@ -1,642 +0,0 @@ |
|||
import re |
|||
import io |
|||
import os |
|||
import sys |
|||
import codecs |
|||
from weakref import WeakKeyDictionary |
|||
|
|||
|
|||
PY2 = sys.version_info[0] == 2 |
|||
WIN = sys.platform.startswith('win') |
|||
DEFAULT_COLUMNS = 80 |
|||
|
|||
|
|||
_ansi_re = re.compile('\033\[((?:\d|;)*)([a-zA-Z])') |
|||
|
|||
|
|||
def get_filesystem_encoding(): |
|||
return sys.getfilesystemencoding() or sys.getdefaultencoding() |
|||
|
|||
|
|||
def _make_text_stream(stream, encoding, errors): |
|||
if encoding is None: |
|||
encoding = get_best_encoding(stream) |
|||
if errors is None: |
|||
errors = 'replace' |
|||
return _NonClosingTextIOWrapper(stream, encoding, errors, |
|||
line_buffering=True) |
|||
|
|||
|
|||
def is_ascii_encoding(encoding): |
|||
"""Checks if a given encoding is ascii.""" |
|||
try: |
|||
return codecs.lookup(encoding).name == 'ascii' |
|||
except LookupError: |
|||
return False |
|||
|
|||
|
|||
def get_best_encoding(stream): |
|||
"""Returns the default stream encoding if not found.""" |
|||
rv = getattr(stream, 'encoding', None) or sys.getdefaultencoding() |
|||
if is_ascii_encoding(rv): |
|||
return 'utf-8' |
|||
return rv |
|||
|
|||
|
|||
class _NonClosingTextIOWrapper(io.TextIOWrapper): |
|||
|
|||
def __init__(self, stream, encoding, errors, **extra): |
|||
self._stream = stream = _FixupStream(stream) |
|||
io.TextIOWrapper.__init__(self, stream, encoding, errors, **extra) |
|||
|
|||
# The io module is a place where the Python 3 text behavior |
|||
# was forced upon Python 2, so we need to unbreak |
|||
# it to look like Python 2. |
|||
if PY2: |
|||
def write(self, x): |
|||
if isinstance(x, str) or is_bytes(x): |
|||
try: |
|||
self.flush() |
|||
except Exception: |
|||
pass |
|||
return self.buffer.write(str(x)) |
|||
return io.TextIOWrapper.write(self, x) |
|||
|
|||
def writelines(self, lines): |
|||
for line in lines: |
|||
self.write(line) |
|||
|
|||
def __del__(self): |
|||
try: |
|||
self.detach() |
|||
except Exception: |
|||
pass |
|||
|
|||
def isatty(self): |
|||
# https://bitbucket.org/pypy/pypy/issue/1803 |
|||
return self._stream.isatty() |
|||
|
|||
|
|||
class _FixupStream(object): |
|||
"""The new io interface needs more from streams than streams |
|||
traditionally implement. As such, this fix-up code is necessary in |
|||
some circumstances. |
|||
""" |
|||
|
|||
def __init__(self, stream): |
|||
self._stream = stream |
|||
|
|||
def __getattr__(self, name): |
|||
return getattr(self._stream, name) |
|||
|
|||
def read1(self, size): |
|||
f = getattr(self._stream, 'read1', None) |
|||
if f is not None: |
|||
return f(size) |
|||
# We only dispatch to readline instead of read in Python 2 as we |
|||
# do not want cause problems with the different implementation |
|||
# of line buffering. |
|||
if PY2: |
|||
return self._stream.readline(size) |
|||
return self._stream.read(size) |
|||
|
|||
def readable(self): |
|||
x = getattr(self._stream, 'readable', None) |
|||
if x is not None: |
|||
return x() |
|||
try: |
|||
self._stream.read(0) |
|||
except Exception: |
|||
return False |
|||
return True |
|||
|
|||
def writable(self): |
|||
x = getattr(self._stream, 'writable', None) |
|||
if x is not None: |
|||
return x() |
|||
try: |
|||
self._stream.write('') |
|||
except Exception: |
|||
try: |
|||
self._stream.write(b'') |
|||
except Exception: |
|||
return False |
|||
return True |
|||
|
|||
def seekable(self): |
|||
x = getattr(self._stream, 'seekable', None) |
|||
if x is not None: |
|||
return x() |
|||
try: |
|||
self._stream.seek(self._stream.tell()) |
|||
except Exception: |
|||
return False |
|||
return True |
|||
|
|||
|
|||
if PY2: |
|||
text_type = unicode |
|||
bytes = str |
|||
raw_input = raw_input |
|||
string_types = (str, unicode) |
|||
iteritems = lambda x: x.iteritems() |
|||
range_type = xrange |
|||
|
|||
def is_bytes(x): |
|||
return isinstance(x, (buffer, bytearray)) |
|||
|
|||
_identifier_re = re.compile(r'^[a-zA-Z_][a-zA-Z0-9_]*$') |
|||
|
|||
# For Windows, we need to force stdout/stdin/stderr to binary if it's |
|||
# fetched for that. This obviously is not the most correct way to do |
|||
# it as it changes global state. Unfortunately, there does not seem to |
|||
# be a clear better way to do it as just reopening the file in binary |
|||
# mode does not change anything. |
|||
# |
|||
# An option would be to do what Python 3 does and to open the file as |
|||
# binary only, patch it back to the system, and then use a wrapper |
|||
# stream that converts newlines. It's not quite clear what's the |
|||
# correct option here. |
|||
# |
|||
# This code also lives in _winconsole for the fallback to the console |
|||
# emulation stream. |
|||
if WIN: |
|||
import msvcrt |
|||
def set_binary_mode(f): |
|||
try: |
|||
fileno = f.fileno() |
|||
except Exception: |
|||
pass |
|||
else: |
|||
msvcrt.setmode(fileno, os.O_BINARY) |
|||
return f |
|||
else: |
|||
set_binary_mode = lambda x: x |
|||
|
|||
def isidentifier(x): |
|||
return _identifier_re.search(x) is not None |
|||
|
|||
def get_binary_stdin(): |
|||
return set_binary_mode(sys.stdin) |
|||
|
|||
def get_binary_stdout(): |
|||
return set_binary_mode(sys.stdout) |
|||
|
|||
def get_binary_stderr(): |
|||
return set_binary_mode(sys.stderr) |
|||
|
|||
def get_text_stdin(encoding=None, errors=None): |
|||
rv = _get_windows_console_stream(sys.stdin, encoding, errors) |
|||
if rv is not None: |
|||
return rv |
|||
return _make_text_stream(sys.stdin, encoding, errors) |
|||
|
|||
def get_text_stdout(encoding=None, errors=None): |
|||
rv = _get_windows_console_stream(sys.stdout, encoding, errors) |
|||
if rv is not None: |
|||
return rv |
|||
return _make_text_stream(sys.stdout, encoding, errors) |
|||
|
|||
def get_text_stderr(encoding=None, errors=None): |
|||
rv = _get_windows_console_stream(sys.stderr, encoding, errors) |
|||
if rv is not None: |
|||
return rv |
|||
return _make_text_stream(sys.stderr, encoding, errors) |
|||
|
|||
def filename_to_ui(value): |
|||
if isinstance(value, bytes): |
|||
value = value.decode(get_filesystem_encoding(), 'replace') |
|||
return value |
|||
else: |
|||
import io |
|||
text_type = str |
|||
raw_input = input |
|||
string_types = (str,) |
|||
range_type = range |
|||
isidentifier = lambda x: x.isidentifier() |
|||
iteritems = lambda x: iter(x.items()) |
|||
|
|||
def is_bytes(x): |
|||
return isinstance(x, (bytes, memoryview, bytearray)) |
|||
|
|||
def _is_binary_reader(stream, default=False): |
|||
try: |
|||
return isinstance(stream.read(0), bytes) |
|||
except Exception: |
|||
return default |
|||
# This happens in some cases where the stream was already |
|||
# closed. In this case, we assume the default. |
|||
|
|||
def _is_binary_writer(stream, default=False): |
|||
try: |
|||
stream.write(b'') |
|||
except Exception: |
|||
try: |
|||
stream.write('') |
|||
return False |
|||
except Exception: |
|||
pass |
|||
return default |
|||
return True |
|||
|
|||
def _find_binary_reader(stream): |
|||
# We need to figure out if the given stream is already binary. |
|||
# This can happen because the official docs recommend detaching |
|||
# the streams to get binary streams. Some code might do this, so |
|||
# we need to deal with this case explicitly. |
|||
if _is_binary_reader(stream, False): |
|||
return stream |
|||
|
|||
buf = getattr(stream, 'buffer', None) |
|||
|
|||
# Same situation here; this time we assume that the buffer is |
|||
# actually binary in case it's closed. |
|||
if buf is not None and _is_binary_reader(buf, True): |
|||
return buf |
|||
|
|||
def _find_binary_writer(stream): |
|||
# We need to figure out if the given stream is already binary. |
|||
# This can happen because the official docs recommend detatching |
|||
# the streams to get binary streams. Some code might do this, so |
|||
# we need to deal with this case explicitly. |
|||
if _is_binary_writer(stream, False): |
|||
return stream |
|||
|
|||
buf = getattr(stream, 'buffer', None) |
|||
|
|||
# Same situation here; this time we assume that the buffer is |
|||
# actually binary in case it's closed. |
|||
if buf is not None and _is_binary_writer(buf, True): |
|||
return buf |
|||
|
|||
def _stream_is_misconfigured(stream): |
|||
"""A stream is misconfigured if its encoding is ASCII.""" |
|||
# If the stream does not have an encoding set, we assume it's set |
|||
# to ASCII. This appears to happen in certain unittest |
|||
# environments. It's not quite clear what the correct behavior is |
|||
# but this at least will force Click to recover somehow. |
|||
return is_ascii_encoding(getattr(stream, 'encoding', None) or 'ascii') |
|||
|
|||
def _is_compatible_text_stream(stream, encoding, errors): |
|||
stream_encoding = getattr(stream, 'encoding', None) |
|||
stream_errors = getattr(stream, 'errors', None) |
|||
|
|||
# Perfect match. |
|||
if stream_encoding == encoding and stream_errors == errors: |
|||
return True |
|||
|
|||
# Otherwise, it's only a compatible stream if we did not ask for |
|||
# an encoding. |
|||
if encoding is None: |
|||
return stream_encoding is not None |
|||
|
|||
return False |
|||
|
|||
def _force_correct_text_reader(text_reader, encoding, errors): |
|||
if _is_binary_reader(text_reader, False): |
|||
binary_reader = text_reader |
|||
else: |
|||
# If there is no target encoding set, we need to verify that the |
|||
# reader is not actually misconfigured. |
|||
if encoding is None and not _stream_is_misconfigured(text_reader): |
|||
return text_reader |
|||
|
|||
if _is_compatible_text_stream(text_reader, encoding, errors): |
|||
return text_reader |
|||
|
|||
# If the reader has no encoding, we try to find the underlying |
|||
# binary reader for it. If that fails because the environment is |
|||
# misconfigured, we silently go with the same reader because this |
|||
# is too common to happen. In that case, mojibake is better than |
|||
# exceptions. |
|||
binary_reader = _find_binary_reader(text_reader) |
|||
if binary_reader is None: |
|||
return text_reader |
|||
|
|||
# At this point, we default the errors to replace instead of strict |
|||
# because nobody handles those errors anyways and at this point |
|||
# we're so fundamentally fucked that nothing can repair it. |
|||
if errors is None: |
|||
errors = 'replace' |
|||
return _make_text_stream(binary_reader, encoding, errors) |
|||
|
|||
def _force_correct_text_writer(text_writer, encoding, errors): |
|||
if _is_binary_writer(text_writer, False): |
|||
binary_writer = text_writer |
|||
else: |
|||
# If there is no target encoding set, we need to verify that the |
|||
# writer is not actually misconfigured. |
|||
if encoding is None and not _stream_is_misconfigured(text_writer): |
|||
return text_writer |
|||
|
|||
if _is_compatible_text_stream(text_writer, encoding, errors): |
|||
return text_writer |
|||
|
|||
# If the writer has no encoding, we try to find the underlying |
|||
# binary writer for it. If that fails because the environment is |
|||
# misconfigured, we silently go with the same writer because this |
|||
# is too common to happen. In that case, mojibake is better than |
|||
# exceptions. |
|||
binary_writer = _find_binary_writer(text_writer) |
|||
if binary_writer is None: |
|||
return text_writer |
|||
|
|||
# At this point, we default the errors to replace instead of strict |
|||
# because nobody handles those errors anyways and at this point |
|||
# we're so fundamentally fucked that nothing can repair it. |
|||
if errors is None: |
|||
errors = 'replace' |
|||
return _make_text_stream(binary_writer, encoding, errors) |
|||
|
|||
def get_binary_stdin(): |
|||
reader = _find_binary_reader(sys.stdin) |
|||
if reader is None: |
|||
raise RuntimeError('Was not able to determine binary ' |
|||
'stream for sys.stdin.') |
|||
return reader |
|||
|
|||
def get_binary_stdout(): |
|||
writer = _find_binary_writer(sys.stdout) |
|||
if writer is None: |
|||
raise RuntimeError('Was not able to determine binary ' |
|||
'stream for sys.stdout.') |
|||
return writer |
|||
|
|||
def get_binary_stderr(): |
|||
writer = _find_binary_writer(sys.stderr) |
|||
if writer is None: |
|||
raise RuntimeError('Was not able to determine binary ' |
|||
'stream for sys.stderr.') |
|||
return writer |
|||
|
|||
def get_text_stdin(encoding=None, errors=None): |
|||
rv = _get_windows_console_stream(sys.stdin, encoding, errors) |
|||
if rv is not None: |
|||
return rv |
|||
return _force_correct_text_reader(sys.stdin, encoding, errors) |
|||
|
|||
def get_text_stdout(encoding=None, errors=None): |
|||
rv = _get_windows_console_stream(sys.stdout, encoding, errors) |
|||
if rv is not None: |
|||
return rv |
|||
return _force_correct_text_writer(sys.stdout, encoding, errors) |
|||
|
|||
def get_text_stderr(encoding=None, errors=None): |
|||
rv = _get_windows_console_stream(sys.stderr, encoding, errors) |
|||
if rv is not None: |
|||
return rv |
|||
return _force_correct_text_writer(sys.stderr, encoding, errors) |
|||
|
|||
def filename_to_ui(value): |
|||
if isinstance(value, bytes): |
|||
value = value.decode(get_filesystem_encoding(), 'replace') |
|||
else: |
|||
value = value.encode('utf-8', 'surrogateescape') \ |
|||
.decode('utf-8', 'replace') |
|||
return value |
|||
|
|||
|
|||
def get_streerror(e, default=None): |
|||
if hasattr(e, 'strerror'): |
|||
msg = e.strerror |
|||
else: |
|||
if default is not None: |
|||
msg = default |
|||
else: |
|||
msg = str(e) |
|||
if isinstance(msg, bytes): |
|||
msg = msg.decode('utf-8', 'replace') |
|||
return msg |
|||
|
|||
|
|||
def open_stream(filename, mode='r', encoding=None, errors='strict', |
|||
atomic=False): |
|||
# Standard streams first. These are simple because they don't need |
|||
# special handling for the atomic flag. It's entirely ignored. |
|||
if filename == '-': |
|||
if 'w' in mode: |
|||
if 'b' in mode: |
|||
return get_binary_stdout(), False |
|||
return get_text_stdout(encoding=encoding, errors=errors), False |
|||
if 'b' in mode: |
|||
return get_binary_stdin(), False |
|||
return get_text_stdin(encoding=encoding, errors=errors), False |
|||
|
|||
# Non-atomic writes directly go out through the regular open functions. |
|||
if not atomic: |
|||
if encoding is None: |
|||
return open(filename, mode), True |
|||
return io.open(filename, mode, encoding=encoding, errors=errors), True |
|||
|
|||
# Some usability stuff for atomic writes |
|||
if 'a' in mode: |
|||
raise ValueError( |
|||
'Appending to an existing file is not supported, because that ' |
|||
'would involve an expensive `copy`-operation to a temporary ' |
|||
'file. Open the file in normal `w`-mode and copy explicitly ' |
|||
'if that\'s what you\'re after.' |
|||
) |
|||
if 'x' in mode: |
|||
raise ValueError('Use the `overwrite`-parameter instead.') |
|||
if 'w' not in mode: |
|||
raise ValueError('Atomic writes only make sense with `w`-mode.') |
|||
|
|||
# Atomic writes are more complicated. They work by opening a file |
|||
# as a proxy in the same folder and then using the fdopen |
|||
# functionality to wrap it in a Python file. Then we wrap it in an |
|||
# atomic file that moves the file over on close. |
|||
import tempfile |
|||
fd, tmp_filename = tempfile.mkstemp(dir=os.path.dirname(filename), |
|||
prefix='.__atomic-write') |
|||
|
|||
if encoding is not None: |
|||
f = io.open(fd, mode, encoding=encoding, errors=errors) |
|||
else: |
|||
f = os.fdopen(fd, mode) |
|||
|
|||
return _AtomicFile(f, tmp_filename, filename), True |
|||
|
|||
|
|||
# Used in a destructor call, needs extra protection from interpreter cleanup. |
|||
if hasattr(os, 'replace'): |
|||
_replace = os.replace |
|||
_can_replace = True |
|||
else: |
|||
_replace = os.rename |
|||
_can_replace = not WIN |
|||
|
|||
|
|||
class _AtomicFile(object): |
|||
|
|||
def __init__(self, f, tmp_filename, real_filename): |
|||
self._f = f |
|||
self._tmp_filename = tmp_filename |
|||
self._real_filename = real_filename |
|||
self.closed = False |
|||
|
|||
@property |
|||
def name(self): |
|||
return self._real_filename |
|||
|
|||
def close(self, delete=False): |
|||
if self.closed: |
|||
return |
|||
self._f.close() |
|||
if not _can_replace: |
|||
try: |
|||
os.remove(self._real_filename) |
|||
except OSError: |
|||
pass |
|||
_replace(self._tmp_filename, self._real_filename) |
|||
self.closed = True |
|||
|
|||
def __getattr__(self, name): |
|||
return getattr(self._f, name) |
|||
|
|||
def __enter__(self): |
|||
return self |
|||
|
|||
def __exit__(self, exc_type, exc_value, tb): |
|||
self.close(delete=exc_type is not None) |
|||
|
|||
def __repr__(self): |
|||
return repr(self._f) |
|||
|
|||
|
|||
auto_wrap_for_ansi = None |
|||
colorama = None |
|||
get_winterm_size = None |
|||
|
|||
|
|||
def strip_ansi(value): |
|||
return _ansi_re.sub('', value) |
|||
|
|||
|
|||
def should_strip_ansi(stream=None, color=None): |
|||
if color is None: |
|||
if stream is None: |
|||
stream = sys.stdin |
|||
return not isatty(stream) |
|||
return not color |
|||
|
|||
|
|||
# If we're on Windows, we provide transparent integration through |
|||
# colorama. This will make ANSI colors through the echo function |
|||
# work automatically. |
|||
if WIN: |
|||
# Windows has a smaller terminal |
|||
DEFAULT_COLUMNS = 79 |
|||
|
|||
from ._winconsole import _get_windows_console_stream |
|||
|
|||
def _get_argv_encoding(): |
|||
import locale |
|||
return locale.getpreferredencoding() |
|||
|
|||
if PY2: |
|||
def raw_input(prompt=''): |
|||
sys.stderr.flush() |
|||
if prompt: |
|||
stdout = _default_text_stdout() |
|||
stdout.write(prompt) |
|||
stdin = _default_text_stdin() |
|||
return stdin.readline().rstrip('\r\n') |
|||
|
|||
try: |
|||
import colorama |
|||
except ImportError: |
|||
pass |
|||
else: |
|||
_ansi_stream_wrappers = WeakKeyDictionary() |
|||
|
|||
def auto_wrap_for_ansi(stream, color=None): |
|||
"""This function wraps a stream so that calls through colorama |
|||
are issued to the win32 console API to recolor on demand. It |
|||
also ensures to reset the colors if a write call is interrupted |
|||
to not destroy the console afterwards. |
|||
""" |
|||
try: |
|||
cached = _ansi_stream_wrappers.get(stream) |
|||
except Exception: |
|||
cached = None |
|||
if cached is not None: |
|||
return cached |
|||
strip = should_strip_ansi(stream, color) |
|||
ansi_wrapper = colorama.AnsiToWin32(stream, strip=strip) |
|||
rv = ansi_wrapper.stream |
|||
_write = rv.write |
|||
|
|||
def _safe_write(s): |
|||
try: |
|||
return _write(s) |
|||
except: |
|||
ansi_wrapper.reset_all() |
|||
raise |
|||
|
|||
rv.write = _safe_write |
|||
try: |
|||
_ansi_stream_wrappers[stream] = rv |
|||
except Exception: |
|||
pass |
|||
return rv |
|||
|
|||
def get_winterm_size(): |
|||
win = colorama.win32.GetConsoleScreenBufferInfo( |
|||
colorama.win32.STDOUT).srWindow |
|||
return win.Right - win.Left, win.Bottom - win.Top |
|||
else: |
|||
def _get_argv_encoding(): |
|||
return getattr(sys.stdin, 'encoding', None) or get_filesystem_encoding() |
|||
|
|||
_get_windows_console_stream = lambda *x: None |
|||
|
|||
|
|||
def term_len(x): |
|||
return len(strip_ansi(x)) |
|||
|
|||
|
|||
def isatty(stream): |
|||
try: |
|||
return stream.isatty() |
|||
except Exception: |
|||
return False |
|||
|
|||
|
|||
def _make_cached_stream_func(src_func, wrapper_func): |
|||
cache = WeakKeyDictionary() |
|||
def func(): |
|||
stream = src_func() |
|||
try: |
|||
rv = cache.get(stream) |
|||
except Exception: |
|||
rv = None |
|||
if rv is not None: |
|||
return rv |
|||
rv = wrapper_func() |
|||
try: |
|||
cache[stream] = rv |
|||
except Exception: |
|||
pass |
|||
return rv |
|||
return func |
|||
|
|||
|
|||
_default_text_stdin = _make_cached_stream_func( |
|||
lambda: sys.stdin, get_text_stdin) |
|||
_default_text_stdout = _make_cached_stream_func( |
|||
lambda: sys.stdout, get_text_stdout) |
|||
_default_text_stderr = _make_cached_stream_func( |
|||
lambda: sys.stderr, get_text_stderr) |
|||
|
|||
|
|||
binary_streams = { |
|||
'stdin': get_binary_stdin, |
|||
'stdout': get_binary_stdout, |
|||
'stderr': get_binary_stderr, |
|||
} |
|||
|
|||
text_streams = { |
|||
'stdin': get_text_stdin, |
|||
'stdout': get_text_stdout, |
|||
'stderr': get_text_stderr, |
|||
} |
@ -1,547 +0,0 @@ |
|||
""" |
|||
click._termui_impl |
|||
~~~~~~~~~~~~~~~~~~ |
|||
|
|||
This module contains implementations for the termui module. To keep the |
|||
import time of Click down, some infrequently used functionality is placed |
|||
in this module and only imported as needed. |
|||
|
|||
:copyright: (c) 2014 by Armin Ronacher. |
|||
:license: BSD, see LICENSE for more details. |
|||
""" |
|||
import os |
|||
import sys |
|||
import time |
|||
import math |
|||
from ._compat import _default_text_stdout, range_type, PY2, isatty, \ |
|||
open_stream, strip_ansi, term_len, get_best_encoding, WIN |
|||
from .utils import echo |
|||
from .exceptions import ClickException |
|||
|
|||
|
|||
if os.name == 'nt': |
|||
BEFORE_BAR = '\r' |
|||
AFTER_BAR = '\n' |
|||
else: |
|||
BEFORE_BAR = '\r\033[?25l' |
|||
AFTER_BAR = '\033[?25h\n' |
|||
|
|||
|
|||
def _length_hint(obj): |
|||
"""Returns the length hint of an object.""" |
|||
try: |
|||
return len(obj) |
|||
except TypeError: |
|||
try: |
|||
get_hint = type(obj).__length_hint__ |
|||
except AttributeError: |
|||
return None |
|||
try: |
|||
hint = get_hint(obj) |
|||
except TypeError: |
|||
return None |
|||
if hint is NotImplemented or \ |
|||
not isinstance(hint, (int, long)) or \ |
|||
hint < 0: |
|||
return None |
|||
return hint |
|||
|
|||
|
|||
class ProgressBar(object): |
|||
|
|||
def __init__(self, iterable, length=None, fill_char='#', empty_char=' ', |
|||
bar_template='%(bar)s', info_sep=' ', show_eta=True, |
|||
show_percent=None, show_pos=False, item_show_func=None, |
|||
label=None, file=None, color=None, width=30): |
|||
self.fill_char = fill_char |
|||
self.empty_char = empty_char |
|||
self.bar_template = bar_template |
|||
self.info_sep = info_sep |
|||
self.show_eta = show_eta |
|||
self.show_percent = show_percent |
|||
self.show_pos = show_pos |
|||
self.item_show_func = item_show_func |
|||
self.label = label or '' |
|||
if file is None: |
|||
file = _default_text_stdout() |
|||
self.file = file |
|||
self.color = color |
|||
self.width = width |
|||
self.autowidth = width == 0 |
|||
|
|||
if length is None: |
|||
length = _length_hint(iterable) |
|||
if iterable is None: |
|||
if length is None: |
|||
raise TypeError('iterable or length is required') |
|||
iterable = range_type(length) |
|||
self.iter = iter(iterable) |
|||
self.length = length |
|||
self.length_known = length is not None |
|||
self.pos = 0 |
|||
self.avg = [] |
|||
self.start = self.last_eta = time.time() |
|||
self.eta_known = False |
|||
self.finished = False |
|||
self.max_width = None |
|||
self.entered = False |
|||
self.current_item = None |
|||
self.is_hidden = not isatty(self.file) |
|||
self._last_line = None |
|||
|
|||
def __enter__(self): |
|||
self.entered = True |
|||
self.render_progress() |
|||
return self |
|||
|
|||
def __exit__(self, exc_type, exc_value, tb): |
|||
self.render_finish() |
|||
|
|||
def __iter__(self): |
|||
if not self.entered: |
|||
raise RuntimeError('You need to use progress bars in a with block.') |
|||
self.render_progress() |
|||
return self |
|||
|
|||
def render_finish(self): |
|||
if self.is_hidden: |
|||
return |
|||
self.file.write(AFTER_BAR) |
|||
self.file.flush() |
|||
|
|||
@property |
|||
def pct(self): |
|||
if self.finished: |
|||
return 1.0 |
|||
return min(self.pos / (float(self.length) or 1), 1.0) |
|||
|
|||
@property |
|||
def time_per_iteration(self): |
|||
if not self.avg: |
|||
return 0.0 |
|||
return sum(self.avg) / float(len(self.avg)) |
|||
|
|||
@property |
|||
def eta(self): |
|||
if self.length_known and not self.finished: |
|||
return self.time_per_iteration * (self.length - self.pos) |
|||
return 0.0 |
|||
|
|||
def format_eta(self): |
|||
if self.eta_known: |
|||
t = self.eta + 1 |
|||
seconds = t % 60 |
|||
t /= 60 |
|||
minutes = t % 60 |
|||
t /= 60 |
|||
hours = t % 24 |
|||
t /= 24 |
|||
if t > 0: |
|||
days = t |
|||
return '%dd %02d:%02d:%02d' % (days, hours, minutes, seconds) |
|||
else: |
|||
return '%02d:%02d:%02d' % (hours, minutes, seconds) |
|||
return '' |
|||
|
|||
def format_pos(self): |
|||
pos = str(self.pos) |
|||
if self.length_known: |
|||
pos += '/%s' % self.length |
|||
return pos |
|||
|
|||
def format_pct(self): |
|||
return ('% 4d%%' % int(self.pct * 100))[1:] |
|||
|
|||
def format_progress_line(self): |
|||
show_percent = self.show_percent |
|||
|
|||
info_bits = [] |
|||
if self.length_known: |
|||
bar_length = int(self.pct * self.width) |
|||
bar = self.fill_char * bar_length |
|||
bar += self.empty_char * (self.width - bar_length) |
|||
if show_percent is None: |
|||
show_percent = not self.show_pos |
|||
else: |
|||
if self.finished: |
|||
bar = self.fill_char * self.width |
|||
else: |
|||
bar = list(self.empty_char * (self.width or 1)) |
|||
if self.time_per_iteration != 0: |
|||
bar[int((math.cos(self.pos * self.time_per_iteration) |
|||
/ 2.0 + 0.5) * self.width)] = self.fill_char |
|||
bar = ''.join(bar) |
|||
|
|||
if self.show_pos: |
|||
info_bits.append(self.format_pos()) |
|||
if show_percent: |
|||
info_bits.append(self.format_pct()) |
|||
if self.show_eta and self.eta_known and not self.finished: |
|||
info_bits.append(self.format_eta()) |
|||
if self.item_show_func is not None: |
|||
item_info = self.item_show_func(self.current_item) |
|||
if item_info is not None: |
|||
info_bits.append(item_info) |
|||
|
|||
return (self.bar_template % { |
|||
'label': self.label, |
|||
'bar': bar, |
|||
'info': self.info_sep.join(info_bits) |
|||
}).rstrip() |
|||
|
|||
def render_progress(self): |
|||
from .termui import get_terminal_size |
|||
nl = False |
|||
|
|||
if self.is_hidden: |
|||
buf = [self.label] |
|||
nl = True |
|||
else: |
|||
buf = [] |
|||
# Update width in case the terminal has been resized |
|||
if self.autowidth: |
|||
old_width = self.width |
|||
self.width = 0 |
|||
clutter_length = term_len(self.format_progress_line()) |
|||
new_width = max(0, get_terminal_size()[0] - clutter_length) |
|||
if new_width < old_width: |
|||
buf.append(BEFORE_BAR) |
|||
buf.append(' ' * self.max_width) |
|||
self.max_width = new_width |
|||
self.width = new_width |
|||
|
|||
clear_width = self.width |
|||
if self.max_width is not None: |
|||
clear_width = self.max_width |
|||
|
|||
buf.append(BEFORE_BAR) |
|||
line = self.format_progress_line() |
|||
line_len = term_len(line) |
|||
if self.max_width is None or self.max_width < line_len: |
|||
self.max_width = line_len |
|||
buf.append(line) |
|||
|
|||
buf.append(' ' * (clear_width - line_len)) |
|||
line = ''.join(buf) |
|||
|
|||
# Render the line only if it changed. |
|||
if line != self._last_line: |
|||
self._last_line = line |
|||
echo(line, file=self.file, color=self.color, nl=nl) |
|||
self.file.flush() |
|||
|
|||
def make_step(self, n_steps): |
|||
self.pos += n_steps |
|||
if self.length_known and self.pos >= self.length: |
|||
self.finished = True |
|||
|
|||
if (time.time() - self.last_eta) < 1.0: |
|||
return |
|||
|
|||
self.last_eta = time.time() |
|||
self.avg = self.avg[-6:] + [-(self.start - time.time()) / (self.pos)] |
|||
|
|||
self.eta_known = self.length_known |
|||
|
|||
def update(self, n_steps): |
|||
self.make_step(n_steps) |
|||
self.render_progress() |
|||
|
|||
def finish(self): |
|||
self.eta_known = 0 |
|||
self.current_item = None |
|||
self.finished = True |
|||
|
|||
def next(self): |
|||
if self.is_hidden: |
|||
return next(self.iter) |
|||
try: |
|||
rv = next(self.iter) |
|||
self.current_item = rv |
|||
except StopIteration: |
|||
self.finish() |
|||
self.render_progress() |
|||
raise StopIteration() |
|||
else: |
|||
self.update(1) |
|||
return rv |
|||
|
|||
if not PY2: |
|||
__next__ = next |
|||
del next |
|||
|
|||
|
|||
def pager(text, color=None): |
|||
"""Decide what method to use for paging through text.""" |
|||
stdout = _default_text_stdout() |
|||
if not isatty(sys.stdin) or not isatty(stdout): |
|||
return _nullpager(stdout, text, color) |
|||
pager_cmd = (os.environ.get('PAGER', None) or '').strip() |
|||
if pager_cmd: |
|||
if WIN: |
|||
return _tempfilepager(text, pager_cmd, color) |
|||
return _pipepager(text, pager_cmd, color) |
|||
if os.environ.get('TERM') in ('dumb', 'emacs'): |
|||
return _nullpager(stdout, text, color) |
|||
if WIN or sys.platform.startswith('os2'): |
|||
return _tempfilepager(text, 'more <', color) |
|||
if hasattr(os, 'system') and os.system('(less) 2>/dev/null') == 0: |
|||
return _pipepager(text, 'less', color) |
|||
|
|||
import tempfile |
|||
fd, filename = tempfile.mkstemp() |
|||
os.close(fd) |
|||
try: |
|||
if hasattr(os, 'system') and os.system('more "%s"' % filename) == 0: |
|||
return _pipepager(text, 'more', color) |
|||
return _nullpager(stdout, text, color) |
|||
finally: |
|||
os.unlink(filename) |
|||
|
|||
|
|||
def _pipepager(text, cmd, color): |
|||
"""Page through text by feeding it to another program. Invoking a |
|||
pager through this might support colors. |
|||
""" |
|||
import subprocess |
|||
env = dict(os.environ) |
|||
|
|||
# If we're piping to less we might support colors under the |
|||
# condition that |
|||
cmd_detail = cmd.rsplit('/', 1)[-1].split() |
|||
if color is None and cmd_detail[0] == 'less': |
|||
less_flags = os.environ.get('LESS', '') + ' '.join(cmd_detail[1:]) |
|||
if not less_flags: |
|||
env['LESS'] = '-R' |
|||
color = True |
|||
elif 'r' in less_flags or 'R' in less_flags: |
|||
color = True |
|||
|
|||
if not color: |
|||
text = strip_ansi(text) |
|||
|
|||
c = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, |
|||
env=env) |
|||
encoding = get_best_encoding(c.stdin) |
|||
try: |
|||
c.stdin.write(text.encode(encoding, 'replace')) |
|||
c.stdin.close() |
|||
except (IOError, KeyboardInterrupt): |
|||
pass |
|||
|
|||
# Less doesn't respect ^C, but catches it for its own UI purposes (aborting |
|||
# search or other commands inside less). |
|||
# |
|||
# That means when the user hits ^C, the parent process (click) terminates, |
|||
# but less is still alive, paging the output and messing up the terminal. |
|||
# |
|||
# If the user wants to make the pager exit on ^C, they should set |
|||
# `LESS='-K'`. It's not our decision to make. |
|||
while True: |
|||
try: |
|||
c.wait() |
|||
except KeyboardInterrupt: |
|||
pass |
|||
else: |
|||
break |
|||
|
|||
|
|||
def _tempfilepager(text, cmd, color): |
|||
"""Page through text by invoking a program on a temporary file.""" |
|||
import tempfile |
|||
filename = tempfile.mktemp() |
|||
if not color: |
|||
text = strip_ansi(text) |
|||
encoding = get_best_encoding(sys.stdout) |
|||
with open_stream(filename, 'wb')[0] as f: |
|||
f.write(text.encode(encoding)) |
|||
try: |
|||
os.system(cmd + ' "' + filename + '"') |
|||
finally: |
|||
os.unlink(filename) |
|||
|
|||
|
|||
def _nullpager(stream, text, color): |
|||
"""Simply print unformatted text. This is the ultimate fallback.""" |
|||
if not color: |
|||
text = strip_ansi(text) |
|||
stream.write(text) |
|||
|
|||
|
|||
class Editor(object): |
|||
|
|||
def __init__(self, editor=None, env=None, require_save=True, |
|||
extension='.txt'): |
|||
self.editor = editor |
|||
self.env = env |
|||
self.require_save = require_save |
|||
self.extension = extension |
|||
|
|||
def get_editor(self): |
|||
if self.editor is not None: |
|||
return self.editor |
|||
for key in 'VISUAL', 'EDITOR': |
|||
rv = os.environ.get(key) |
|||
if rv: |
|||
return rv |
|||
if WIN: |
|||
return 'notepad' |
|||
for editor in 'vim', 'nano': |
|||
if os.system('which %s >/dev/null 2>&1' % editor) == 0: |
|||
return editor |
|||
return 'vi' |
|||
|
|||
def edit_file(self, filename): |
|||
import subprocess |
|||
editor = self.get_editor() |
|||
if self.env: |
|||
environ = os.environ.copy() |
|||
environ.update(self.env) |
|||
else: |
|||
environ = None |
|||
try: |
|||
c = subprocess.Popen('%s "%s"' % (editor, filename), |
|||
env=environ, shell=True) |
|||
exit_code = c.wait() |
|||
if exit_code != 0: |
|||
raise ClickException('%s: Editing failed!' % editor) |
|||
except OSError as e: |
|||
raise ClickException('%s: Editing failed: %s' % (editor, e)) |
|||
|
|||
def edit(self, text): |
|||
import tempfile |
|||
|
|||
text = text or '' |
|||
if text and not text.endswith('\n'): |
|||
text += '\n' |
|||
|
|||
fd, name = tempfile.mkstemp(prefix='editor-', suffix=self.extension) |
|||
try: |
|||
if WIN: |
|||
encoding = 'utf-8-sig' |
|||
text = text.replace('\n', '\r\n') |
|||
else: |
|||
encoding = 'utf-8' |
|||
text = text.encode(encoding) |
|||
|
|||
f = os.fdopen(fd, 'wb') |
|||
f.write(text) |
|||
f.close() |
|||
timestamp = os.path.getmtime(name) |
|||
|
|||
self.edit_file(name) |
|||
|
|||
if self.require_save \ |
|||
and os.path.getmtime(name) == timestamp: |
|||
return None |
|||
|
|||
f = open(name, 'rb') |
|||
try: |
|||
rv = f.read() |
|||
finally: |
|||
f.close() |
|||
return rv.decode('utf-8-sig').replace('\r\n', '\n') |
|||
finally: |
|||
os.unlink(name) |
|||
|
|||
|
|||
def open_url(url, wait=False, locate=False): |
|||
import subprocess |
|||
|
|||
def _unquote_file(url): |
|||
try: |
|||
import urllib |
|||
except ImportError: |
|||
import urllib |
|||
if url.startswith('file://'): |
|||
url = urllib.unquote(url[7:]) |
|||
return url |
|||
|
|||
if sys.platform == 'darwin': |
|||
args = ['open'] |
|||
if wait: |
|||
args.append('-W') |
|||
if locate: |
|||
args.append('-R') |
|||
args.append(_unquote_file(url)) |
|||
null = open('/dev/null', 'w') |
|||
try: |
|||
return subprocess.Popen(args, stderr=null).wait() |
|||
finally: |
|||
null.close() |
|||
elif WIN: |
|||
if locate: |
|||
url = _unquote_file(url) |
|||
args = 'explorer /select,"%s"' % _unquote_file( |
|||
url.replace('"', '')) |
|||
else: |
|||
args = 'start %s "" "%s"' % ( |
|||
wait and '/WAIT' or '', url.replace('"', '')) |
|||
return os.system(args) |
|||
|
|||
try: |
|||
if locate: |
|||
url = os.path.dirname(_unquote_file(url)) or '.' |
|||
else: |
|||
url = _unquote_file(url) |
|||
c = subprocess.Popen(['xdg-open', url]) |
|||
if wait: |
|||
return c.wait() |
|||
return 0 |
|||
except OSError: |
|||
if url.startswith(('http://', 'https://')) and not locate and not wait: |
|||
import webbrowser |
|||
webbrowser.open(url) |
|||
return 0 |
|||
return 1 |
|||
|
|||
|
|||
def _translate_ch_to_exc(ch): |
|||
if ch == '\x03': |
|||
raise KeyboardInterrupt() |
|||
if ch == '\x04': |
|||
raise EOFError() |
|||
|
|||
|
|||
if WIN: |
|||
import msvcrt |
|||
|
|||
def getchar(echo): |
|||
rv = msvcrt.getch() |
|||
if echo: |
|||
msvcrt.putchar(rv) |
|||
_translate_ch_to_exc(rv) |
|||
if PY2: |
|||
enc = getattr(sys.stdin, 'encoding', None) |
|||
if enc is not None: |
|||
rv = rv.decode(enc, 'replace') |
|||
else: |
|||
rv = rv.decode('cp1252', 'replace') |
|||
return rv |
|||
else: |
|||
import tty |
|||
import termios |
|||
|
|||
def getchar(echo): |
|||
if not isatty(sys.stdin): |
|||
f = open('/dev/tty') |
|||
fd = f.fileno() |
|||
else: |
|||
fd = sys.stdin.fileno() |
|||
f = None |
|||
try: |
|||
old_settings = termios.tcgetattr(fd) |
|||
try: |
|||
tty.setraw(fd) |
|||
ch = os.read(fd, 32) |
|||
if echo and isatty(sys.stdout): |
|||
sys.stdout.write(ch) |
|||
finally: |
|||
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) |
|||
sys.stdout.flush() |
|||
if f is not None: |
|||
f.close() |
|||
except termios.error: |
|||
pass |
|||
_translate_ch_to_exc(ch) |
|||
return ch.decode(get_best_encoding(sys.stdin), 'replace') |
@ -1,38 +0,0 @@ |
|||
import textwrap |
|||
from contextlib import contextmanager |
|||
|
|||
|
|||
class TextWrapper(textwrap.TextWrapper): |
|||
|
|||
def _handle_long_word(self, reversed_chunks, cur_line, cur_len, width): |
|||
space_left = max(width - cur_len, 1) |
|||
|
|||
if self.break_long_words: |
|||
last = reversed_chunks[-1] |
|||
cut = last[:space_left] |
|||
res = last[space_left:] |
|||
cur_line.append(cut) |
|||
reversed_chunks[-1] = res |
|||
elif not cur_line: |
|||
cur_line.append(reversed_chunks.pop()) |
|||
|
|||
@contextmanager |
|||
def extra_indent(self, indent): |
|||
old_initial_indent = self.initial_indent |
|||
old_subsequent_indent = self.subsequent_indent |
|||
self.initial_indent += indent |
|||
self.subsequent_indent += indent |
|||
try: |
|||
yield |
|||
finally: |
|||
self.initial_indent = old_initial_indent |
|||
self.subsequent_indent = old_subsequent_indent |
|||
|
|||
def indent_only(self, text): |
|||
rv = [] |
|||
for idx, line in enumerate(text.splitlines()): |
|||
indent = self.initial_indent |
|||
if idx > 0: |
|||
indent = self.subsequent_indent |
|||
rv.append(indent + line) |
|||
return '\n'.join(rv) |
@ -1,119 +0,0 @@ |
|||
import os |
|||
import sys |
|||
import codecs |
|||
|
|||
from ._compat import PY2 |
|||
|
|||
|
|||
# If someone wants to vendor click, we want to ensure the |
|||
# correct package is discovered. Ideally we could use a |
|||
# relative import here but unfortunately Python does not |
|||
# support that. |
|||
click = sys.modules[__name__.rsplit('.', 1)[0]] |
|||
|
|||
|
|||
def _find_unicode_literals_frame(): |
|||
import __future__ |
|||
frm = sys._getframe(1) |
|||
idx = 1 |
|||
while frm is not None: |
|||
if frm.f_globals.get('__name__', '').startswith('click.'): |
|||
frm = frm.f_back |
|||
idx += 1 |
|||
elif frm.f_code.co_flags & __future__.unicode_literals.compiler_flag: |
|||
return idx |
|||
else: |
|||
break |
|||
return 0 |
|||
|
|||
|
|||
def _check_for_unicode_literals(): |
|||
if not __debug__: |
|||
return |
|||
if not PY2 or click.disable_unicode_literals_warning: |
|||
return |
|||
bad_frame = _find_unicode_literals_frame() |
|||
if bad_frame <= 0: |
|||
return |
|||
from warnings import warn |
|||
warn(Warning('Click detected the use of the unicode_literals ' |
|||
'__future__ import. This is heavily discouraged ' |
|||
'because it can introduce subtle bugs in your ' |
|||
'code. You should instead use explicit u"" literals ' |
|||
'for your unicode strings. For more information see ' |
|||
'http://click.pocoo.org/python3/'), |
|||
stacklevel=bad_frame) |
|||
|
|||
|
|||
def _verify_python3_env(): |
|||
"""Ensures that the environment is good for unicode on Python 3.""" |
|||
if PY2: |
|||
return |
|||
try: |
|||
import locale |
|||
fs_enc = codecs.lookup(locale.getpreferredencoding()).name |
|||
except Exception: |
|||
fs_enc = 'ascii' |
|||
if fs_enc != 'ascii': |
|||
return |
|||
|
|||
extra = '' |
|||
if os.name == 'posix': |
|||
import subprocess |
|||
rv = subprocess.Popen(['locale', '-a'], stdout=subprocess.PIPE, |
|||
stderr=subprocess.PIPE).communicate()[0] |
|||
good_locales = set() |
|||
has_c_utf8 = False |
|||
|
|||
# Make sure we're operating on text here. |
|||
if isinstance(rv, bytes): |
|||
rv = rv.decode('ascii', 'replace') |
|||
|
|||
for line in rv.splitlines(): |
|||
locale = line.strip() |
|||
if locale.lower().endswith(('.utf-8', '.utf8')): |
|||
good_locales.add(locale) |
|||
if locale.lower() in ('c.utf8', 'c.utf-8'): |
|||
has_c_utf8 = True |
|||
|
|||
extra += '\n\n' |
|||
if not good_locales: |
|||
extra += ( |
|||
'Additional information: on this system no suitable UTF-8\n' |
|||
'locales were discovered. This most likely requires resolving\n' |
|||
'by reconfiguring the locale system.' |
|||
) |
|||
elif has_c_utf8: |
|||
extra += ( |
|||
'This system supports the C.UTF-8 locale which is recommended.\n' |
|||
'You might be able to resolve your issue by exporting the\n' |
|||
'following environment variables:\n\n' |
|||
' export LC_ALL=C.UTF-8\n' |
|||
' export LANG=C.UTF-8' |
|||
) |
|||
else: |
|||
extra += ( |
|||
'This system lists a couple of UTF-8 supporting locales that\n' |
|||
'you can pick from. The following suitable locales where\n' |
|||
'discovered: %s' |
|||
) % ', '.join(sorted(good_locales)) |
|||
|
|||
bad_locale = None |
|||
for locale in os.environ.get('LC_ALL'), os.environ.get('LANG'): |
|||
if locale and locale.lower().endswith(('.utf-8', '.utf8')): |
|||
bad_locale = locale |
|||
if locale is not None: |
|||
break |
|||
if bad_locale is not None: |
|||
extra += ( |
|||
'\n\nClick discovered that you exported a UTF-8 locale\n' |
|||
'but the locale system could not pick up from it because\n' |
|||
'it does not exist. The exported locale is "%s" but it\n' |
|||
'is not supported' |
|||
) % bad_locale |
|||
|
|||
raise RuntimeError('Click will abort further execution because Python 3 ' |
|||
'was configured to use ASCII as encoding for the ' |
|||
'environment. Either run this under Python 2 or ' |
|||
'consult http://click.pocoo.org/python3/ for ' |
|||
'mitigation steps.' + extra) |
@ -1,273 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# This module is based on the excellent work by Adam Bartoš who |
|||
# provided a lot of what went into the implementation here in |
|||
# the discussion to issue1602 in the Python bug tracker. |
|||
# |
|||
# There are some general differences in regards to how this works |
|||
# compared to the original patches as we do not need to patch |
|||
# the entire interpreter but just work in our little world of |
|||
# echo and prmopt. |
|||
|
|||
import io |
|||
import os |
|||
import sys |
|||
import zlib |
|||
import time |
|||
import ctypes |
|||
import msvcrt |
|||
from click._compat import _NonClosingTextIOWrapper, text_type, PY2 |
|||
from ctypes import byref, POINTER, c_int, c_char, c_char_p, \ |
|||
c_void_p, py_object, c_ssize_t, c_ulong, windll, WINFUNCTYPE |
|||
try: |
|||
from ctypes import pythonapi |
|||
PyObject_GetBuffer = pythonapi.PyObject_GetBuffer |
|||
PyBuffer_Release = pythonapi.PyBuffer_Release |
|||
except ImportError: |
|||
pythonapi = None |
|||
from ctypes.wintypes import LPWSTR, LPCWSTR |
|||
|
|||
|
|||
c_ssize_p = POINTER(c_ssize_t) |
|||
|
|||
kernel32 = windll.kernel32 |
|||
GetStdHandle = kernel32.GetStdHandle |
|||
ReadConsoleW = kernel32.ReadConsoleW |
|||
WriteConsoleW = kernel32.WriteConsoleW |
|||
GetLastError = kernel32.GetLastError |
|||
GetCommandLineW = WINFUNCTYPE(LPWSTR)( |
|||
('GetCommandLineW', windll.kernel32)) |
|||
CommandLineToArgvW = WINFUNCTYPE( |
|||
POINTER(LPWSTR), LPCWSTR, POINTER(c_int))( |
|||
('CommandLineToArgvW', windll.shell32)) |
|||
|
|||
|
|||
STDIN_HANDLE = GetStdHandle(-10) |
|||
STDOUT_HANDLE = GetStdHandle(-11) |
|||
STDERR_HANDLE = GetStdHandle(-12) |
|||
|
|||
|
|||
PyBUF_SIMPLE = 0 |
|||
PyBUF_WRITABLE = 1 |
|||
|
|||
ERROR_SUCCESS = 0 |
|||
ERROR_NOT_ENOUGH_MEMORY = 8 |
|||
ERROR_OPERATION_ABORTED = 995 |
|||
|
|||
STDIN_FILENO = 0 |
|||
STDOUT_FILENO = 1 |
|||
STDERR_FILENO = 2 |
|||
|
|||
EOF = b'\x1a' |
|||
MAX_BYTES_WRITTEN = 32767 |
|||
|
|||
|
|||
class Py_buffer(ctypes.Structure): |
|||
_fields_ = [ |
|||
('buf', c_void_p), |
|||
('obj', py_object), |
|||
('len', c_ssize_t), |
|||
('itemsize', c_ssize_t), |
|||
('readonly', c_int), |
|||
('ndim', c_int), |
|||
('format', c_char_p), |
|||
('shape', c_ssize_p), |
|||
('strides', c_ssize_p), |
|||
('suboffsets', c_ssize_p), |
|||
('internal', c_void_p) |
|||
] |
|||
|
|||
if PY2: |
|||
_fields_.insert(-1, ('smalltable', c_ssize_t * 2)) |
|||
|
|||
|
|||
# On PyPy we cannot get buffers so our ability to operate here is |
|||
# serverly limited. |
|||
if pythonapi is None: |
|||
get_buffer = None |
|||
else: |
|||
def get_buffer(obj, writable=False): |
|||
buf = Py_buffer() |
|||
flags = PyBUF_WRITABLE if writable else PyBUF_SIMPLE |
|||
PyObject_GetBuffer(py_object(obj), byref(buf), flags) |
|||
try: |
|||
buffer_type = c_char * buf.len |
|||
return buffer_type.from_address(buf.buf) |
|||
finally: |
|||
PyBuffer_Release(byref(buf)) |
|||
|
|||
|
|||
class _WindowsConsoleRawIOBase(io.RawIOBase): |
|||
|
|||
def __init__(self, handle): |
|||
self.handle = handle |
|||
|
|||
def isatty(self): |
|||
io.RawIOBase.isatty(self) |
|||
return True |
|||
|
|||
|
|||
class _WindowsConsoleReader(_WindowsConsoleRawIOBase): |
|||
|
|||
def readable(self): |
|||
return True |
|||
|
|||
def readinto(self, b): |
|||
bytes_to_be_read = len(b) |
|||
if not bytes_to_be_read: |
|||
return 0 |
|||
elif bytes_to_be_read % 2: |
|||
raise ValueError('cannot read odd number of bytes from ' |
|||
'UTF-16-LE encoded console') |
|||
|
|||
buffer = get_buffer(b, writable=True) |
|||
code_units_to_be_read = bytes_to_be_read // 2 |
|||
code_units_read = c_ulong() |
|||
|
|||
rv = ReadConsoleW(self.handle, buffer, code_units_to_be_read, |
|||
byref(code_units_read), None) |
|||
if GetLastError() == ERROR_OPERATION_ABORTED: |
|||
# wait for KeyboardInterrupt |
|||
time.sleep(0.1) |
|||
if not rv: |
|||
raise OSError('Windows error: %s' % GetLastError()) |
|||
|
|||
if buffer[0] == EOF: |
|||
return 0 |
|||
return 2 * code_units_read.value |
|||
|
|||
|
|||
class _WindowsConsoleWriter(_WindowsConsoleRawIOBase): |
|||
|
|||
def writable(self): |
|||
return True |
|||
|
|||
@staticmethod |
|||
def _get_error_message(errno): |
|||
if errno == ERROR_SUCCESS: |
|||
return 'ERROR_SUCCESS' |
|||
elif errno == ERROR_NOT_ENOUGH_MEMORY: |
|||
return 'ERROR_NOT_ENOUGH_MEMORY' |
|||
return 'Windows error %s' % errno |
|||
|
|||
def write(self, b): |
|||
bytes_to_be_written = len(b) |
|||
buf = get_buffer(b) |
|||
code_units_to_be_written = min(bytes_to_be_written, |
|||
MAX_BYTES_WRITTEN) // 2 |
|||
code_units_written = c_ulong() |
|||
|
|||
WriteConsoleW(self.handle, buf, code_units_to_be_written, |
|||
byref(code_units_written), None) |
|||
bytes_written = 2 * code_units_written.value |
|||
|
|||
if bytes_written == 0 and bytes_to_be_written > 0: |
|||
raise OSError(self._get_error_message(GetLastError())) |
|||
return bytes_written |
|||
|
|||
|
|||
class ConsoleStream(object): |
|||
|
|||
def __init__(self, text_stream, byte_stream): |
|||
self._text_stream = text_stream |
|||
self.buffer = byte_stream |
|||
|
|||
@property |
|||
def name(self): |
|||
return self.buffer.name |
|||
|
|||
def write(self, x): |
|||
if isinstance(x, text_type): |
|||
return self._text_stream.write(x) |
|||
try: |
|||
self.flush() |
|||
except Exception: |
|||
pass |
|||
return self.buffer.write(x) |
|||
|
|||
def writelines(self, lines): |
|||
for line in lines: |
|||
self.write(line) |
|||
|
|||
def __getattr__(self, name): |
|||
return getattr(self._text_stream, name) |
|||
|
|||
def isatty(self): |
|||
return self.buffer.isatty() |
|||
|
|||
def __repr__(self): |
|||
return '<ConsoleStream name=%r encoding=%r>' % ( |
|||
self.name, |
|||
self.encoding, |
|||
) |
|||
|
|||
|
|||
def _get_text_stdin(buffer_stream): |
|||
text_stream = _NonClosingTextIOWrapper( |
|||
io.BufferedReader(_WindowsConsoleReader(STDIN_HANDLE)), |
|||
'utf-16-le', 'strict', line_buffering=True) |
|||
return ConsoleStream(text_stream, buffer_stream) |
|||
|
|||
|
|||
def _get_text_stdout(buffer_stream): |
|||
text_stream = _NonClosingTextIOWrapper( |
|||
_WindowsConsoleWriter(STDOUT_HANDLE), |
|||
'utf-16-le', 'strict', line_buffering=True) |
|||
return ConsoleStream(text_stream, buffer_stream) |
|||
|
|||
|
|||
def _get_text_stderr(buffer_stream): |
|||
text_stream = _NonClosingTextIOWrapper( |
|||
_WindowsConsoleWriter(STDERR_HANDLE), |
|||
'utf-16-le', 'strict', line_buffering=True) |
|||
return ConsoleStream(text_stream, buffer_stream) |
|||
|
|||
|
|||
if PY2: |
|||
def _hash_py_argv(): |
|||
return zlib.crc32('\x00'.join(sys.argv[1:])) |
|||
|
|||
_initial_argv_hash = _hash_py_argv() |
|||
|
|||
def _get_windows_argv(): |
|||
argc = c_int(0) |
|||
argv_unicode = CommandLineToArgvW(GetCommandLineW(), byref(argc)) |
|||
argv = [argv_unicode[i] for i in range(0, argc.value)] |
|||
|
|||
if not hasattr(sys, 'frozen'): |
|||
argv = argv[1:] |
|||
while len(argv) > 0: |
|||
arg = argv[0] |
|||
if not arg.startswith('-') or arg == '-': |
|||
break |
|||
argv = argv[1:] |
|||
if arg.startswith(('-c', '-m')): |
|||
break |
|||
|
|||
return argv[1:] |
|||
|
|||
|
|||
_stream_factories = { |
|||
0: _get_text_stdin, |
|||
1: _get_text_stdout, |
|||
2: _get_text_stderr, |
|||
} |
|||
|
|||
|
|||
def _get_windows_console_stream(f, encoding, errors): |
|||
if get_buffer is not None and \ |
|||
encoding in ('utf-16-le', None) \ |
|||
and errors in ('strict', None) and \ |
|||
hasattr(f, 'isatty') and f.isatty(): |
|||
func = _stream_factories.get(f.fileno()) |
|||
if func is not None: |
|||
if not PY2: |
|||
f = getattr(f, 'buffer') |
|||
if f is None: |
|||
return None |
|||
else: |
|||
# If we are on Python 2 we need to set the stream that we |
|||
# deal with to binary mode as otherwise the exercise if a |
|||
# bit moot. The same problems apply as for |
|||
# get_binary_stdin and friends from _compat. |
|||
msvcrt.setmode(f.fileno(), os.O_BINARY) |
|||
return func(f) |
File diff suppressed because it is too large
@ -1,304 +0,0 @@ |
|||
import sys |
|||
import inspect |
|||
|
|||
from functools import update_wrapper |
|||
|
|||
from ._compat import iteritems |
|||
from ._unicodefun import _check_for_unicode_literals |
|||
from .utils import echo |
|||
from .globals import get_current_context |
|||
|
|||
|
|||
def pass_context(f): |
|||
"""Marks a callback as wanting to receive the current context |
|||
object as first argument. |
|||
""" |
|||
def new_func(*args, **kwargs): |
|||
return f(get_current_context(), *args, **kwargs) |
|||
return update_wrapper(new_func, f) |
|||
|
|||
|
|||
def pass_obj(f): |
|||
"""Similar to :func:`pass_context`, but only pass the object on the |
|||
context onwards (:attr:`Context.obj`). This is useful if that object |
|||
represents the state of a nested system. |
|||
""" |
|||
def new_func(*args, **kwargs): |
|||
return f(get_current_context().obj, *args, **kwargs) |
|||
return update_wrapper(new_func, f) |
|||
|
|||
|
|||
def make_pass_decorator(object_type, ensure=False): |
|||
"""Given an object type this creates a decorator that will work |
|||
similar to :func:`pass_obj` but instead of passing the object of the |
|||
current context, it will find the innermost context of type |
|||
:func:`object_type`. |
|||
|
|||
This generates a decorator that works roughly like this:: |
|||
|
|||
from functools import update_wrapper |
|||
|
|||
def decorator(f): |
|||
@pass_context |
|||
def new_func(ctx, *args, **kwargs): |
|||
obj = ctx.find_object(object_type) |
|||
return ctx.invoke(f, obj, *args, **kwargs) |
|||
return update_wrapper(new_func, f) |
|||
return decorator |
|||
|
|||
:param object_type: the type of the object to pass. |
|||
:param ensure: if set to `True`, a new object will be created and |
|||
remembered on the context if it's not there yet. |
|||
""" |
|||
def decorator(f): |
|||
def new_func(*args, **kwargs): |
|||
ctx = get_current_context() |
|||
if ensure: |
|||
obj = ctx.ensure_object(object_type) |
|||
else: |
|||
obj = ctx.find_object(object_type) |
|||
if obj is None: |
|||
raise RuntimeError('Managed to invoke callback without a ' |
|||
'context object of type %r existing' |
|||
% object_type.__name__) |
|||
return ctx.invoke(f, obj, *args[1:], **kwargs) |
|||
return update_wrapper(new_func, f) |
|||
return decorator |
|||
|
|||
|
|||
def _make_command(f, name, attrs, cls): |
|||
if isinstance(f, Command): |
|||
raise TypeError('Attempted to convert a callback into a ' |
|||
'command twice.') |
|||
try: |
|||
params = f.__click_params__ |
|||
params.reverse() |
|||
del f.__click_params__ |
|||
except AttributeError: |
|||
params = [] |
|||
help = attrs.get('help') |
|||
if help is None: |
|||
help = inspect.getdoc(f) |
|||
if isinstance(help, bytes): |
|||
help = help.decode('utf-8') |
|||
else: |
|||
help = inspect.cleandoc(help) |
|||
attrs['help'] = help |
|||
_check_for_unicode_literals() |
|||
return cls(name=name or f.__name__.lower(), |
|||
callback=f, params=params, **attrs) |
|||
|
|||
|
|||
def command(name=None, cls=None, **attrs): |
|||
"""Creates a new :class:`Command` and uses the decorated function as |
|||
callback. This will also automatically attach all decorated |
|||
:func:`option`\s and :func:`argument`\s as parameters to the command. |
|||
|
|||
The name of the command defaults to the name of the function. If you |
|||
want to change that, you can pass the intended name as the first |
|||
argument. |
|||
|
|||
All keyword arguments are forwarded to the underlying command class. |
|||
|
|||
Once decorated the function turns into a :class:`Command` instance |
|||
that can be invoked as a command line utility or be attached to a |
|||
command :class:`Group`. |
|||
|
|||
:param name: the name of the command. This defaults to the function |
|||
name. |
|||
:param cls: the command class to instantiate. This defaults to |
|||
:class:`Command`. |
|||
""" |
|||
if cls is None: |
|||
cls = Command |
|||
def decorator(f): |
|||
cmd = _make_command(f, name, attrs, cls) |
|||
cmd.__doc__ = f.__doc__ |
|||
return cmd |
|||
return decorator |
|||
|
|||
|
|||
def group(name=None, **attrs): |
|||
"""Creates a new :class:`Group` with a function as callback. This |
|||
works otherwise the same as :func:`command` just that the `cls` |
|||
parameter is set to :class:`Group`. |
|||
""" |
|||
attrs.setdefault('cls', Group) |
|||
return command(name, **attrs) |
|||
|
|||
|
|||
def _param_memo(f, param): |
|||
if isinstance(f, Command): |
|||
f.params.append(param) |
|||
else: |
|||
if not hasattr(f, '__click_params__'): |
|||
f.__click_params__ = [] |
|||
f.__click_params__.append(param) |
|||
|
|||
|
|||
def argument(*param_decls, **attrs): |
|||
"""Attaches an argument to the command. All positional arguments are |
|||
passed as parameter declarations to :class:`Argument`; all keyword |
|||
arguments are forwarded unchanged (except ``cls``). |
|||
This is equivalent to creating an :class:`Argument` instance manually |
|||
and attaching it to the :attr:`Command.params` list. |
|||
|
|||
:param cls: the argument class to instantiate. This defaults to |
|||
:class:`Argument`. |
|||
""" |
|||
def decorator(f): |
|||
ArgumentClass = attrs.pop('cls', Argument) |
|||
_param_memo(f, ArgumentClass(param_decls, **attrs)) |
|||
return f |
|||
return decorator |
|||
|
|||
|
|||
def option(*param_decls, **attrs): |
|||
"""Attaches an option to the command. All positional arguments are |
|||
passed as parameter declarations to :class:`Option`; all keyword |
|||
arguments are forwarded unchanged (except ``cls``). |
|||
This is equivalent to creating an :class:`Option` instance manually |
|||
and attaching it to the :attr:`Command.params` list. |
|||
|
|||
:param cls: the option class to instantiate. This defaults to |
|||
:class:`Option`. |
|||
""" |
|||
def decorator(f): |
|||
if 'help' in attrs: |
|||
attrs['help'] = inspect.cleandoc(attrs['help']) |
|||
OptionClass = attrs.pop('cls', Option) |
|||
_param_memo(f, OptionClass(param_decls, **attrs)) |
|||
return f |
|||
return decorator |
|||
|
|||
|
|||
def confirmation_option(*param_decls, **attrs): |
|||
"""Shortcut for confirmation prompts that can be ignored by passing |
|||
``--yes`` as parameter. |
|||
|
|||
This is equivalent to decorating a function with :func:`option` with |
|||
the following parameters:: |
|||
|
|||
def callback(ctx, param, value): |
|||
if not value: |
|||
ctx.abort() |
|||
|
|||
@click.command() |
|||
@click.option('--yes', is_flag=True, callback=callback, |
|||
expose_value=False, prompt='Do you want to continue?') |
|||
def dropdb(): |
|||
pass |
|||
""" |
|||
def decorator(f): |
|||
def callback(ctx, param, value): |
|||
if not value: |
|||
ctx.abort() |
|||
attrs.setdefault('is_flag', True) |
|||
attrs.setdefault('callback', callback) |
|||
attrs.setdefault('expose_value', False) |
|||
attrs.setdefault('prompt', 'Do you want to continue?') |
|||
attrs.setdefault('help', 'Confirm the action without prompting.') |
|||
return option(*(param_decls or ('--yes',)), **attrs)(f) |
|||
return decorator |
|||
|
|||
|
|||
def password_option(*param_decls, **attrs): |
|||
"""Shortcut for password prompts. |
|||
|
|||
This is equivalent to decorating a function with :func:`option` with |
|||
the following parameters:: |
|||
|
|||
@click.command() |
|||
@click.option('--password', prompt=True, confirmation_prompt=True, |
|||
hide_input=True) |
|||
def changeadmin(password): |
|||
pass |
|||
""" |
|||
def decorator(f): |
|||
attrs.setdefault('prompt', True) |
|||
attrs.setdefault('confirmation_prompt', True) |
|||
attrs.setdefault('hide_input', True) |
|||
return option(*(param_decls or ('--password',)), **attrs)(f) |
|||
return decorator |
|||
|
|||
|
|||
def version_option(version=None, *param_decls, **attrs): |
|||
"""Adds a ``--version`` option which immediately ends the program |
|||
printing out the version number. This is implemented as an eager |
|||
option that prints the version and exits the program in the callback. |
|||
|
|||
:param version: the version number to show. If not provided Click |
|||
attempts an auto discovery via setuptools. |
|||
:param prog_name: the name of the program (defaults to autodetection) |
|||
:param message: custom message to show instead of the default |
|||
(``'%(prog)s, version %(version)s'``) |
|||
:param others: everything else is forwarded to :func:`option`. |
|||
""" |
|||
if version is None: |
|||
module = sys._getframe(1).f_globals.get('__name__') |
|||
def decorator(f): |
|||
prog_name = attrs.pop('prog_name', None) |
|||
message = attrs.pop('message', '%(prog)s, version %(version)s') |
|||
|
|||
def callback(ctx, param, value): |
|||
if not value or ctx.resilient_parsing: |
|||
return |
|||
prog = prog_name |
|||
if prog is None: |
|||
prog = ctx.find_root().info_name |
|||
ver = version |
|||
if ver is None: |
|||
try: |
|||
import pkg_resources |
|||
except ImportError: |
|||
pass |
|||
else: |
|||
for dist in pkg_resources.working_set: |
|||
scripts = dist.get_entry_map().get('console_scripts') or {} |
|||
for script_name, entry_point in iteritems(scripts): |
|||
if entry_point.module_name == module: |
|||
ver = dist.version |
|||
break |
|||
if ver is None: |
|||
raise RuntimeError('Could not determine version') |
|||
echo(message % { |
|||
'prog': prog, |
|||
'version': ver, |
|||
}, color=ctx.color) |
|||
ctx.exit() |
|||
|
|||
attrs.setdefault('is_flag', True) |
|||
attrs.setdefault('expose_value', False) |
|||
attrs.setdefault('is_eager', True) |
|||
attrs.setdefault('help', 'Show the version and exit.') |
|||
attrs['callback'] = callback |
|||
return option(*(param_decls or ('--version',)), **attrs)(f) |
|||
return decorator |
|||
|
|||
|
|||
def help_option(*param_decls, **attrs): |
|||
"""Adds a ``--help`` option which immediately ends the program |
|||
printing out the help page. This is usually unnecessary to add as |
|||
this is added by default to all commands unless suppressed. |
|||
|
|||
Like :func:`version_option`, this is implemented as eager option that |
|||
prints in the callback and exits. |
|||
|
|||
All arguments are forwarded to :func:`option`. |
|||
""" |
|||
def decorator(f): |
|||
def callback(ctx, param, value): |
|||
if value and not ctx.resilient_parsing: |
|||
echo(ctx.get_help(), color=ctx.color) |
|||
ctx.exit() |
|||
attrs.setdefault('is_flag', True) |
|||
attrs.setdefault('expose_value', False) |
|||
attrs.setdefault('help', 'Show this message and exit.') |
|||
attrs.setdefault('is_eager', True) |
|||
attrs['callback'] = callback |
|||
return option(*(param_decls or ('--help',)), **attrs)(f) |
|||
return decorator |
|||
|
|||
|
|||
# Circular dependencies between core and decorators |
|||
from .core import Command, Group, Argument, Option |
@ -1,201 +0,0 @@ |
|||
from ._compat import PY2, filename_to_ui, get_text_stderr |
|||
from .utils import echo |
|||
|
|||
|
|||
class ClickException(Exception): |
|||
"""An exception that Click can handle and show to the user.""" |
|||
|
|||
#: The exit code for this exception |
|||
exit_code = 1 |
|||
|
|||
def __init__(self, message): |
|||
if PY2: |
|||
if message is not None: |
|||
message = message.encode('utf-8') |
|||
Exception.__init__(self, message) |
|||
self.message = message |
|||
|
|||
def format_message(self): |
|||
return self.message |
|||
|
|||
def show(self, file=None): |
|||
if file is None: |
|||
file = get_text_stderr() |
|||
echo('Error: %s' % self.format_message(), file=file) |
|||
|
|||
|
|||
class UsageError(ClickException): |
|||
"""An internal exception that signals a usage error. This typically |
|||
aborts any further handling. |
|||
|
|||
:param message: the error message to display. |
|||
:param ctx: optionally the context that caused this error. Click will |
|||
fill in the context automatically in some situations. |
|||
""" |
|||
exit_code = 2 |
|||
|
|||
def __init__(self, message, ctx=None): |
|||
ClickException.__init__(self, message) |
|||
self.ctx = ctx |
|||
|
|||
def show(self, file=None): |
|||
if file is None: |
|||
file = get_text_stderr() |
|||
color = None |
|||
if self.ctx is not None: |
|||
color = self.ctx.color |
|||
echo(self.ctx.get_usage() + '\n', file=file, color=color) |
|||
echo('Error: %s' % self.format_message(), file=file, color=color) |
|||
|
|||
|
|||
class BadParameter(UsageError): |
|||
"""An exception that formats out a standardized error message for a |
|||
bad parameter. This is useful when thrown from a callback or type as |
|||
Click will attach contextual information to it (for instance, which |
|||
parameter it is). |
|||
|
|||
.. versionadded:: 2.0 |
|||
|
|||
:param param: the parameter object that caused this error. This can |
|||
be left out, and Click will attach this info itself |
|||
if possible. |
|||
:param param_hint: a string that shows up as parameter name. This |
|||
can be used as alternative to `param` in cases |
|||
where custom validation should happen. If it is |
|||
a string it's used as such, if it's a list then |
|||
each item is quoted and separated. |
|||
""" |
|||
|
|||
def __init__(self, message, ctx=None, param=None, |
|||
param_hint=None): |
|||
UsageError.__init__(self, message, ctx) |
|||
self.param = param |
|||
self.param_hint = param_hint |
|||
|
|||
def format_message(self): |
|||
if self.param_hint is not None: |
|||
param_hint = self.param_hint |
|||
elif self.param is not None: |
|||
param_hint = self.param.opts or [self.param.human_readable_name] |
|||
else: |
|||
return 'Invalid value: %s' % self.message |
|||
if isinstance(param_hint, (tuple, list)): |
|||
param_hint = ' / '.join('"%s"' % x for x in param_hint) |
|||
return 'Invalid value for %s: %s' % (param_hint, self.message) |
|||
|
|||
|
|||
class MissingParameter(BadParameter): |
|||
"""Raised if click required an option or argument but it was not |
|||
provided when invoking the script. |
|||
|
|||
.. versionadded:: 4.0 |
|||
|
|||
:param param_type: a string that indicates the type of the parameter. |
|||
The default is to inherit the parameter type from |
|||
the given `param`. Valid values are ``'parameter'``, |
|||
``'option'`` or ``'argument'``. |
|||
""" |
|||
|
|||
def __init__(self, message=None, ctx=None, param=None, |
|||
param_hint=None, param_type=None): |
|||
BadParameter.__init__(self, message, ctx, param, param_hint) |
|||
self.param_type = param_type |
|||
|
|||
def format_message(self): |
|||
if self.param_hint is not None: |
|||
param_hint = self.param_hint |
|||
elif self.param is not None: |
|||
param_hint = self.param.opts or [self.param.human_readable_name] |
|||
else: |
|||
param_hint = None |
|||
if isinstance(param_hint, (tuple, list)): |
|||
param_hint = ' / '.join('"%s"' % x for x in param_hint) |
|||
|
|||
param_type = self.param_type |
|||
if param_type is None and self.param is not None: |
|||
param_type = self.param.param_type_name |
|||
|
|||
msg = self.message |
|||
if self.param is not None: |
|||
msg_extra = self.param.type.get_missing_message(self.param) |
|||
if msg_extra: |
|||
if msg: |
|||
msg += '. ' + msg_extra |
|||
else: |
|||
msg = msg_extra |
|||
|
|||
return 'Missing %s%s%s%s' % ( |
|||
param_type, |
|||
param_hint and ' %s' % param_hint or '', |
|||
msg and '. ' or '.', |
|||
msg or '', |
|||
) |
|||
|
|||
|
|||
class NoSuchOption(UsageError): |
|||
"""Raised if click attempted to handle an option that does not |
|||
exist. |
|||
|
|||
.. versionadded:: 4.0 |
|||
""" |
|||
|
|||
def __init__(self, option_name, message=None, possibilities=None, |
|||
ctx=None): |
|||
if message is None: |
|||
message = 'no such option: %s' % option_name |
|||
UsageError.__init__(self, message, ctx) |
|||
self.option_name = option_name |
|||
self.possibilities = possibilities |
|||
|
|||
def format_message(self): |
|||
bits = [self.message] |
|||
if self.possibilities: |
|||
if len(self.possibilities) == 1: |
|||
bits.append('Did you mean %s?' % self.possibilities[0]) |
|||
else: |
|||
possibilities = sorted(self.possibilities) |
|||
bits.append('(Possible options: %s)' % ', '.join(possibilities)) |
|||
return ' '.join(bits) |
|||
|
|||
|
|||
class BadOptionUsage(UsageError): |
|||
"""Raised if an option is generally supplied but the use of the option |
|||
was incorrect. This is for instance raised if the number of arguments |
|||
for an option is not correct. |
|||
|
|||
.. versionadded:: 4.0 |
|||
""" |
|||
|
|||
def __init__(self, message, ctx=None): |
|||
UsageError.__init__(self, message, ctx) |
|||
|
|||
|
|||
class BadArgumentUsage(UsageError): |
|||
"""Raised if an argument is generally supplied but the use of the argument |
|||
was incorrect. This is for instance raised if the number of values |
|||
for an argument is not correct. |
|||
|
|||
.. versionadded:: 6.0 |
|||
""" |
|||
|
|||
def __init__(self, message, ctx=None): |
|||
UsageError.__init__(self, message, ctx) |
|||
|
|||
|
|||
class FileError(ClickException): |
|||
"""Raised if a file cannot be opened.""" |
|||
|
|||
def __init__(self, filename, hint=None): |
|||
ui_filename = filename_to_ui(filename) |
|||
if hint is None: |
|||
hint = 'unknown error' |
|||
ClickException.__init__(self, hint) |
|||
self.ui_filename = ui_filename |
|||
self.filename = filename |
|||
|
|||
def format_message(self): |
|||
return 'Could not open file %s: %s' % (self.ui_filename, self.message) |
|||
|
|||
|
|||
class Abort(RuntimeError): |
|||
"""An internal signalling exception that signals Click to abort.""" |
@ -1,256 +0,0 @@ |
|||
from contextlib import contextmanager |
|||
from .termui import get_terminal_size |
|||
from .parser import split_opt |
|||
from ._compat import term_len |
|||
|
|||
|
|||
# Can force a width. This is used by the test system |
|||
FORCED_WIDTH = None |
|||
|
|||
|
|||
def measure_table(rows): |
|||
widths = {} |
|||
for row in rows: |
|||
for idx, col in enumerate(row): |
|||
widths[idx] = max(widths.get(idx, 0), term_len(col)) |
|||
return tuple(y for x, y in sorted(widths.items())) |
|||
|
|||
|
|||
def iter_rows(rows, col_count): |
|||
for row in rows: |
|||
row = tuple(row) |
|||
yield row + ('',) * (col_count - len(row)) |
|||
|
|||
|
|||
def wrap_text(text, width=78, initial_indent='', subsequent_indent='', |
|||
preserve_paragraphs=False): |
|||
"""A helper function that intelligently wraps text. By default, it |
|||
assumes that it operates on a single paragraph of text but if the |
|||
`preserve_paragraphs` parameter is provided it will intelligently |
|||
handle paragraphs (defined by two empty lines). |
|||
|
|||
If paragraphs are handled, a paragraph can be prefixed with an empty |
|||
line containing the ``\\b`` character (``\\x08``) to indicate that |
|||
no rewrapping should happen in that block. |
|||
|
|||
:param text: the text that should be rewrapped. |
|||
:param width: the maximum width for the text. |
|||
:param initial_indent: the initial indent that should be placed on the |
|||
first line as a string. |
|||
:param subsequent_indent: the indent string that should be placed on |
|||
each consecutive line. |
|||
:param preserve_paragraphs: if this flag is set then the wrapping will |
|||
intelligently handle paragraphs. |
|||
""" |
|||
from ._textwrap import TextWrapper |
|||
text = text.expandtabs() |
|||
wrapper = TextWrapper(width, initial_indent=initial_indent, |
|||
subsequent_indent=subsequent_indent, |
|||
replace_whitespace=False) |
|||
if not preserve_paragraphs: |
|||
return wrapper.fill(text) |
|||
|
|||
p = [] |
|||
buf = [] |
|||
indent = None |
|||
|
|||
def _flush_par(): |
|||
if not buf: |
|||
return |
|||
if buf[0].strip() == '\b': |
|||
p.append((indent or 0, True, '\n'.join(buf[1:]))) |
|||
else: |
|||
p.append((indent or 0, False, ' '.join(buf))) |
|||
del buf[:] |
|||
|
|||
for line in text.splitlines(): |
|||
if not line: |
|||
_flush_par() |
|||
indent = None |
|||
else: |
|||
if indent is None: |
|||
orig_len = term_len(line) |
|||
line = line.lstrip() |
|||
indent = orig_len - term_len(line) |
|||
buf.append(line) |
|||
_flush_par() |
|||
|
|||
rv = [] |
|||
for indent, raw, text in p: |
|||
with wrapper.extra_indent(' ' * indent): |
|||
if raw: |
|||
rv.append(wrapper.indent_only(text)) |
|||
else: |
|||
rv.append(wrapper.fill(text)) |
|||
|
|||
return '\n\n'.join(rv) |
|||
|
|||
|
|||
class HelpFormatter(object): |
|||
"""This class helps with formatting text-based help pages. It's |
|||
usually just needed for very special internal cases, but it's also |
|||
exposed so that developers can write their own fancy outputs. |
|||
|
|||
At present, it always writes into memory. |
|||
|
|||
:param indent_increment: the additional increment for each level. |
|||
:param width: the width for the text. This defaults to the terminal |
|||
width clamped to a maximum of 78. |
|||
""" |
|||
|
|||
def __init__(self, indent_increment=2, width=None, max_width=None): |
|||
self.indent_increment = indent_increment |
|||
if max_width is None: |
|||
max_width = 80 |
|||
if width is None: |
|||
width = FORCED_WIDTH |
|||
if width is None: |
|||
width = max(min(get_terminal_size()[0], max_width) - 2, 50) |
|||
self.width = width |
|||
self.current_indent = 0 |
|||
self.buffer = [] |
|||
|
|||
def write(self, string): |
|||
"""Writes a unicode string into the internal buffer.""" |
|||
self.buffer.append(string) |
|||
|
|||
def indent(self): |
|||
"""Increases the indentation.""" |
|||
self.current_indent += self.indent_increment |
|||
|
|||
def dedent(self): |
|||
"""Decreases the indentation.""" |
|||
self.current_indent -= self.indent_increment |
|||
|
|||
def write_usage(self, prog, args='', prefix='Usage: '): |
|||
"""Writes a usage line into the buffer. |
|||
|
|||
:param prog: the program name. |
|||
:param args: whitespace separated list of arguments. |
|||
:param prefix: the prefix for the first line. |
|||
""" |
|||
usage_prefix = '%*s%s ' % (self.current_indent, prefix, prog) |
|||
text_width = self.width - self.current_indent |
|||
|
|||
if text_width >= (term_len(usage_prefix) + 20): |
|||
# The arguments will fit to the right of the prefix. |
|||
indent = ' ' * term_len(usage_prefix) |
|||
self.write(wrap_text(args, text_width, |
|||
initial_indent=usage_prefix, |
|||
subsequent_indent=indent)) |
|||
else: |
|||
# The prefix is too long, put the arguments on the next line. |
|||
self.write(usage_prefix) |
|||
self.write('\n') |
|||
indent = ' ' * (max(self.current_indent, term_len(prefix)) + 4) |
|||
self.write(wrap_text(args, text_width, |
|||
initial_indent=indent, |
|||
subsequent_indent=indent)) |
|||
|
|||
self.write('\n') |
|||
|
|||
def write_heading(self, heading): |
|||
"""Writes a heading into the buffer.""" |
|||
self.write('%*s%s:\n' % (self.current_indent, '', heading)) |
|||
|
|||
def write_paragraph(self): |
|||
"""Writes a paragraph into the buffer.""" |
|||
if self.buffer: |
|||
self.write('\n') |
|||
|
|||
def write_text(self, text): |
|||
"""Writes re-indented text into the buffer. This rewraps and |
|||
preserves paragraphs. |
|||
""" |
|||
text_width = max(self.width - self.current_indent, 11) |
|||
indent = ' ' * self.current_indent |
|||
self.write(wrap_text(text, text_width, |
|||
initial_indent=indent, |
|||
subsequent_indent=indent, |
|||
preserve_paragraphs=True)) |
|||
self.write('\n') |
|||
|
|||
def write_dl(self, rows, col_max=30, col_spacing=2): |
|||
"""Writes a definition list into the buffer. This is how options |
|||
and commands are usually formatted. |
|||
|
|||
:param rows: a list of two item tuples for the terms and values. |
|||
:param col_max: the maximum width of the first column. |
|||
:param col_spacing: the number of spaces between the first and |
|||
second column. |
|||
""" |
|||
rows = list(rows) |
|||
widths = measure_table(rows) |
|||
if len(widths) != 2: |
|||
raise TypeError('Expected two columns for definition list') |
|||
|
|||
first_col = min(widths[0], col_max) + col_spacing |
|||
|
|||
for first, second in iter_rows(rows, len(widths)): |
|||
self.write('%*s%s' % (self.current_indent, '', first)) |
|||
if not second: |
|||
self.write('\n') |
|||
continue |
|||
if term_len(first) <= first_col - col_spacing: |
|||
self.write(' ' * (first_col - term_len(first))) |
|||
else: |
|||
self.write('\n') |
|||
self.write(' ' * (first_col + self.current_indent)) |
|||
|
|||
text_width = max(self.width - first_col - 2, 10) |
|||
lines = iter(wrap_text(second, text_width).splitlines()) |
|||
if lines: |
|||
self.write(next(lines) + '\n') |
|||
for line in lines: |
|||
self.write('%*s%s\n' % ( |
|||
first_col + self.current_indent, '', line)) |
|||
else: |
|||
self.write('\n') |
|||
|
|||
@contextmanager |
|||
def section(self, name): |
|||
"""Helpful context manager that writes a paragraph, a heading, |
|||
and the indents. |
|||
|
|||
:param name: the section name that is written as heading. |
|||
""" |
|||
self.write_paragraph() |
|||
self.write_heading(name) |
|||
self.indent() |
|||
try: |
|||
yield |
|||
finally: |
|||
self.dedent() |
|||
|
|||
@contextmanager |
|||
def indentation(self): |
|||
"""A context manager that increases the indentation.""" |
|||
self.indent() |
|||
try: |
|||
yield |
|||
finally: |
|||
self.dedent() |
|||
|
|||
def getvalue(self): |
|||
"""Returns the buffer contents.""" |
|||
return ''.join(self.buffer) |
|||
|
|||
|
|||
def join_options(options): |
|||
"""Given a list of option strings this joins them in the most appropriate |
|||
way and returns them in the form ``(formatted_string, |
|||
any_prefix_is_slash)`` where the second item in the tuple is a flag that |
|||
indicates if any of the option prefixes was a slash. |
|||
""" |
|||
rv = [] |
|||
any_prefix_is_slash = False |
|||
for opt in options: |
|||
prefix = split_opt(opt)[0] |
|||
if prefix == '/': |
|||
any_prefix_is_slash = True |
|||
rv.append((len(prefix), opt)) |
|||
|
|||
rv.sort(key=lambda x: x[0]) |
|||
|
|||
rv = ', '.join(x[1] for x in rv) |
|||
return rv, any_prefix_is_slash |
@ -1,48 +0,0 @@ |
|||
from threading import local |
|||
|
|||
|
|||
_local = local() |
|||
|
|||
|
|||
def get_current_context(silent=False): |
|||
"""Returns the current click context. This can be used as a way to |
|||
access the current context object from anywhere. This is a more implicit |
|||
alternative to the :func:`pass_context` decorator. This function is |
|||
primarily useful for helpers such as :func:`echo` which might be |
|||
interested in changing it's behavior based on the current context. |
|||
|
|||
To push the current context, :meth:`Context.scope` can be used. |
|||
|
|||
.. versionadded:: 5.0 |
|||
|
|||
:param silent: is set to `True` the return value is `None` if no context |
|||
is available. The default behavior is to raise a |
|||
:exc:`RuntimeError`. |
|||
""" |
|||
try: |
|||
return getattr(_local, 'stack')[-1] |
|||
except (AttributeError, IndexError): |
|||
if not silent: |
|||
raise RuntimeError('There is no active click context.') |
|||
|
|||
|
|||
def push_context(ctx): |
|||
"""Pushes a new context to the current stack.""" |
|||
_local.__dict__.setdefault('stack', []).append(ctx) |
|||
|
|||
|
|||
def pop_context(): |
|||
"""Removes the top level from the stack.""" |
|||
_local.stack.pop() |
|||
|
|||
|
|||
def resolve_color_default(color=None): |
|||
""""Internal helper to get the default value of the color flag. If a |
|||
value is passed it's returned unchanged, otherwise it's looked up from |
|||
the current context. |
|||
""" |
|||
if color is not None: |
|||
return color |
|||
ctx = get_current_context(silent=True) |
|||
if ctx is not None: |
|||
return ctx.color |
@ -1,426 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
""" |
|||
click.parser |
|||
~~~~~~~~~~~~ |
|||
|
|||
This module started out as largely a copy paste from the stdlib's |
|||
optparse module with the features removed that we do not need from |
|||
optparse because we implement them in Click on a higher level (for |
|||
instance type handling, help formatting and a lot more). |
|||
|
|||
The plan is to remove more and more from here over time. |
|||
|
|||
The reason this is a different module and not optparse from the stdlib |
|||
is that there are differences in 2.x and 3.x about the error messages |
|||
generated and optparse in the stdlib uses gettext for no good reason |
|||
and might cause us issues. |
|||
""" |
|||
import re |
|||
from collections import deque |
|||
from .exceptions import UsageError, NoSuchOption, BadOptionUsage, \ |
|||
BadArgumentUsage |
|||
|
|||
|
|||
def _unpack_args(args, nargs_spec): |
|||
"""Given an iterable of arguments and an iterable of nargs specifications, |
|||
it returns a tuple with all the unpacked arguments at the first index |
|||
and all remaining arguments as the second. |
|||
|
|||
The nargs specification is the number of arguments that should be consumed |
|||
or `-1` to indicate that this position should eat up all the remainders. |
|||
|
|||
Missing items are filled with `None`. |
|||
""" |
|||
args = deque(args) |
|||
nargs_spec = deque(nargs_spec) |
|||
rv = [] |
|||
spos = None |
|||
|
|||
def _fetch(c): |
|||
try: |
|||
if spos is None: |
|||
return c.popleft() |
|||
else: |
|||
return c.pop() |
|||
except IndexError: |
|||
return None |
|||
|
|||
while nargs_spec: |
|||
nargs = _fetch(nargs_spec) |
|||
if nargs == 1: |
|||
rv.append(_fetch(args)) |
|||
elif nargs > 1: |
|||
x = [_fetch(args) for _ in range(nargs)] |
|||
# If we're reversed, we're pulling in the arguments in reverse, |
|||
# so we need to turn them around. |
|||
if spos is not None: |
|||
x.reverse() |
|||
rv.append(tuple(x)) |
|||
elif nargs < 0: |
|||
if spos is not None: |
|||
raise TypeError('Cannot have two nargs < 0') |
|||
spos = len(rv) |
|||
rv.append(None) |
|||
|
|||
# spos is the position of the wildcard (star). If it's not `None`, |
|||
# we fill it with the remainder. |
|||
if spos is not None: |
|||
rv[spos] = tuple(args) |
|||
args = [] |
|||
rv[spos + 1:] = reversed(rv[spos + 1:]) |
|||
|
|||
return tuple(rv), list(args) |
|||
|
|||
|
|||
def _error_opt_args(nargs, opt): |
|||
if nargs == 1: |
|||
raise BadOptionUsage('%s option requires an argument' % opt) |
|||
raise BadOptionUsage('%s option requires %d arguments' % (opt, nargs)) |
|||
|
|||
|
|||
def split_opt(opt): |
|||
first = opt[:1] |
|||
if first.isalnum(): |
|||
return '', opt |
|||
if opt[1:2] == first: |
|||
return opt[:2], opt[2:] |
|||
return first, opt[1:] |
|||
|
|||
|
|||
def normalize_opt(opt, ctx): |
|||
if ctx is None or ctx.token_normalize_func is None: |
|||
return opt |
|||
prefix, opt = split_opt(opt) |
|||
return prefix + ctx.token_normalize_func(opt) |
|||
|
|||
|
|||
def split_arg_string(string): |
|||
"""Given an argument string this attempts to split it into small parts.""" |
|||
rv = [] |
|||
for match in re.finditer(r"('([^'\\]*(?:\\.[^'\\]*)*)'" |
|||
r'|"([^"\\]*(?:\\.[^"\\]*)*)"' |
|||
r'|\S+)\s*', string, re.S): |
|||
arg = match.group().strip() |
|||
if arg[:1] == arg[-1:] and arg[:1] in '"\'': |
|||
arg = arg[1:-1].encode('ascii', 'backslashreplace') \ |
|||
.decode('unicode-escape') |
|||
try: |
|||
arg = type(string)(arg) |
|||
except UnicodeError: |
|||
pass |
|||
rv.append(arg) |
|||
return rv |
|||
|
|||
|
|||
class Option(object): |
|||
|
|||
def __init__(self, opts, dest, action=None, nargs=1, const=None, obj=None): |
|||
self._short_opts = [] |
|||
self._long_opts = [] |
|||
self.prefixes = set() |
|||
|
|||
for opt in opts: |
|||
prefix, value = split_opt(opt) |
|||
if not prefix: |
|||
raise ValueError('Invalid start character for option (%s)' |
|||
% opt) |
|||
self.prefixes.add(prefix[0]) |
|||
if len(prefix) == 1 and len(value) == 1: |
|||
self._short_opts.append(opt) |
|||
else: |
|||
self._long_opts.append(opt) |
|||
self.prefixes.add(prefix) |
|||
|
|||
if action is None: |
|||
action = 'store' |
|||
|
|||
self.dest = dest |
|||
self.action = action |
|||
self.nargs = nargs |
|||
self.const = const |
|||
self.obj = obj |
|||
|
|||
@property |
|||
def takes_value(self): |
|||
return self.action in ('store', 'append') |
|||
|
|||
def process(self, value, state): |
|||
if self.action == 'store': |
|||
state.opts[self.dest] = value |
|||
elif self.action == 'store_const': |
|||
state.opts[self.dest] = self.const |
|||
elif self.action == 'append': |
|||
state.opts.setdefault(self.dest, []).append(value) |
|||
elif self.action == 'append_const': |
|||
state.opts.setdefault(self.dest, []).append(self.const) |
|||
elif self.action == 'count': |
|||
state.opts[self.dest] = state.opts.get(self.dest, 0) + 1 |
|||
else: |
|||
raise ValueError('unknown action %r' % self.action) |
|||
state.order.append(self.obj) |
|||
|
|||
|
|||
class Argument(object): |
|||
|
|||
def __init__(self, dest, nargs=1, obj=None): |
|||
self.dest = dest |
|||
self.nargs = nargs |
|||
self.obj = obj |
|||
|
|||
def process(self, value, state): |
|||
if self.nargs > 1: |
|||
holes = sum(1 for x in value if x is None) |
|||
if holes == len(value): |
|||
value = None |
|||
elif holes != 0: |
|||
raise BadArgumentUsage('argument %s takes %d values' |
|||
% (self.dest, self.nargs)) |
|||
state.opts[self.dest] = value |
|||
state.order.append(self.obj) |
|||
|
|||
|
|||
class ParsingState(object): |
|||
|
|||
def __init__(self, rargs): |
|||
self.opts = {} |
|||
self.largs = [] |
|||
self.rargs = rargs |
|||
self.order = [] |
|||
|
|||
|
|||
class OptionParser(object): |
|||
"""The option parser is an internal class that is ultimately used to |
|||
parse options and arguments. It's modelled after optparse and brings |
|||
a similar but vastly simplified API. It should generally not be used |
|||
directly as the high level Click classes wrap it for you. |
|||
|
|||
It's not nearly as extensible as optparse or argparse as it does not |
|||
implement features that are implemented on a higher level (such as |
|||
types or defaults). |
|||
|
|||
:param ctx: optionally the :class:`~click.Context` where this parser |
|||
should go with. |
|||
""" |
|||
|
|||
def __init__(self, ctx=None): |
|||
#: The :class:`~click.Context` for this parser. This might be |
|||
#: `None` for some advanced use cases. |
|||
self.ctx = ctx |
|||
#: This controls how the parser deals with interspersed arguments. |
|||
#: If this is set to `False`, the parser will stop on the first |
|||
#: non-option. Click uses this to implement nested subcommands |
|||
#: safely. |
|||
self.allow_interspersed_args = True |
|||
#: This tells the parser how to deal with unknown options. By |
|||
#: default it will error out (which is sensible), but there is a |
|||
#: second mode where it will ignore it and continue processing |
|||
#: after shifting all the unknown options into the resulting args. |
|||
self.ignore_unknown_options = False |
|||
if ctx is not None: |
|||
self.allow_interspersed_args = ctx.allow_interspersed_args |
|||
self.ignore_unknown_options = ctx.ignore_unknown_options |
|||
self._short_opt = {} |
|||
self._long_opt = {} |
|||
self._opt_prefixes = set(['-', '--']) |
|||
self._args = [] |
|||
|
|||
def add_option(self, opts, dest, action=None, nargs=1, const=None, |
|||
obj=None): |
|||
"""Adds a new option named `dest` to the parser. The destination |
|||
is not inferred (unlike with optparse) and needs to be explicitly |
|||
provided. Action can be any of ``store``, ``store_const``, |
|||
``append``, ``appnd_const`` or ``count``. |
|||
|
|||
The `obj` can be used to identify the option in the order list |
|||
that is returned from the parser. |
|||
""" |
|||
if obj is None: |
|||
obj = dest |
|||
opts = [normalize_opt(opt, self.ctx) for opt in opts] |
|||
option = Option(opts, dest, action=action, nargs=nargs, |
|||
const=const, obj=obj) |
|||
self._opt_prefixes.update(option.prefixes) |
|||
for opt in option._short_opts: |
|||
self._short_opt[opt] = option |
|||
for opt in option._long_opts: |
|||
self._long_opt[opt] = option |
|||
|
|||
def add_argument(self, dest, nargs=1, obj=None): |
|||
"""Adds a positional argument named `dest` to the parser. |
|||
|
|||
The `obj` can be used to identify the option in the order list |
|||
that is returned from the parser. |
|||
""" |
|||
if obj is None: |
|||
obj = dest |
|||
self._args.append(Argument(dest=dest, nargs=nargs, obj=obj)) |
|||
|
|||
def parse_args(self, args): |
|||
"""Parses positional arguments and returns ``(values, args, order)`` |
|||
for the parsed options and arguments as well as the leftover |
|||
arguments if there are any. The order is a list of objects as they |
|||
appear on the command line. If arguments appear multiple times they |
|||
will be memorized multiple times as well. |
|||
""" |
|||
state = ParsingState(args) |
|||
try: |
|||
self._process_args_for_options(state) |
|||
self._process_args_for_args(state) |
|||
except UsageError: |
|||
if self.ctx is None or not self.ctx.resilient_parsing: |
|||
raise |
|||
return state.opts, state.largs, state.order |
|||
|
|||
def _process_args_for_args(self, state): |
|||
pargs, args = _unpack_args(state.largs + state.rargs, |
|||
[x.nargs for x in self._args]) |
|||
|
|||
for idx, arg in enumerate(self._args): |
|||
arg.process(pargs[idx], state) |
|||
|
|||
state.largs = args |
|||
state.rargs = [] |
|||
|
|||
def _process_args_for_options(self, state): |
|||
while state.rargs: |
|||
arg = state.rargs.pop(0) |
|||
arglen = len(arg) |
|||
# Double dashes always handled explicitly regardless of what |
|||
# prefixes are valid. |
|||
if arg == '--': |
|||
return |
|||
elif arg[:1] in self._opt_prefixes and arglen > 1: |
|||
self._process_opts(arg, state) |
|||
elif self.allow_interspersed_args: |
|||
state.largs.append(arg) |
|||
else: |
|||
state.rargs.insert(0, arg) |
|||
return |
|||
|
|||
# Say this is the original argument list: |
|||
# [arg0, arg1, ..., arg(i-1), arg(i), arg(i+1), ..., arg(N-1)] |
|||
# ^ |
|||
# (we are about to process arg(i)). |
|||
# |
|||
# Then rargs is [arg(i), ..., arg(N-1)] and largs is a *subset* of |
|||
# [arg0, ..., arg(i-1)] (any options and their arguments will have |
|||
# been removed from largs). |
|||
# |
|||
# The while loop will usually consume 1 or more arguments per pass. |
|||
# If it consumes 1 (eg. arg is an option that takes no arguments), |
|||
# then after _process_arg() is done the situation is: |
|||
# |
|||
# largs = subset of [arg0, ..., arg(i)] |
|||
# rargs = [arg(i+1), ..., arg(N-1)] |
|||
# |
|||
# If allow_interspersed_args is false, largs will always be |
|||
# *empty* -- still a subset of [arg0, ..., arg(i-1)], but |
|||
# not a very interesting subset! |
|||
|
|||
def _match_long_opt(self, opt, explicit_value, state): |
|||
if opt not in self._long_opt: |
|||
possibilities = [word for word in self._long_opt |
|||
if word.startswith(opt)] |
|||
raise NoSuchOption(opt, possibilities=possibilities) |
|||
|
|||
option = self._long_opt[opt] |
|||
if option.takes_value: |
|||
# At this point it's safe to modify rargs by injecting the |
|||
# explicit value, because no exception is raised in this |
|||
# branch. This means that the inserted value will be fully |
|||
# consumed. |
|||
if explicit_value is not None: |
|||
state.rargs.insert(0, explicit_value) |
|||
|
|||
nargs = option.nargs |
|||
if len(state.rargs) < nargs: |
|||
_error_opt_args(nargs, opt) |
|||
elif nargs == 1: |
|||
value = state.rargs.pop(0) |
|||
else: |
|||
value = tuple(state.rargs[:nargs]) |
|||
del state.rargs[:nargs] |
|||
|
|||
elif explicit_value is not None: |
|||
raise BadOptionUsage('%s option does not take a value' % opt) |
|||
|
|||
else: |
|||
value = None |
|||
|
|||
option.process(value, state) |
|||
|
|||
def _match_short_opt(self, arg, state): |
|||
stop = False |
|||
i = 1 |
|||
prefix = arg[0] |
|||
unknown_options = [] |
|||
|
|||
for ch in arg[1:]: |
|||
opt = normalize_opt(prefix + ch, self.ctx) |
|||
option = self._short_opt.get(opt) |
|||
i += 1 |
|||
|
|||
if not option: |
|||
if self.ignore_unknown_options: |
|||
unknown_options.append(ch) |
|||
continue |
|||
raise NoSuchOption(opt) |
|||
if option.takes_value: |
|||
# Any characters left in arg? Pretend they're the |
|||
# next arg, and stop consuming characters of arg. |
|||
if i < len(arg): |
|||
state.rargs.insert(0, arg[i:]) |
|||
stop = True |
|||
|
|||
nargs = option.nargs |
|||
if len(state.rargs) < nargs: |
|||
_error_opt_args(nargs, opt) |
|||
elif nargs == 1: |
|||
value = state.rargs.pop(0) |
|||
else: |
|||
value = tuple(state.rargs[:nargs]) |
|||
del state.rargs[:nargs] |
|||
|
|||
else: |
|||
value = None |
|||
|
|||
option.process(value, state) |
|||
|
|||
if stop: |
|||
break |
|||
|
|||
# If we got any unknown options we re-combinate the string of the |
|||
# remaining options and re-attach the prefix, then report that |
|||
# to the state as new larg. This way there is basic combinatorics |
|||
# that can be achieved while still ignoring unknown arguments. |
|||
if self.ignore_unknown_options and unknown_options: |
|||
state.largs.append(prefix + ''.join(unknown_options)) |
|||
|
|||
def _process_opts(self, arg, state): |
|||
explicit_value = None |
|||
# Long option handling happens in two parts. The first part is |
|||
# supporting explicitly attached values. In any case, we will try |
|||
# to long match the option first. |
|||
if '=' in arg: |
|||
long_opt, explicit_value = arg.split('=', 1) |
|||
else: |
|||
long_opt = arg |
|||
norm_long_opt = normalize_opt(long_opt, self.ctx) |
|||
|
|||
# At this point we will match the (assumed) long option through |
|||
# the long option matching code. Note that this allows options |
|||
# like "-foo" to be matched as long options. |
|||
try: |
|||
self._match_long_opt(norm_long_opt, explicit_value, state) |
|||
except NoSuchOption: |
|||
# At this point the long option matching failed, and we need |
|||
# to try with short options. However there is a special rule |
|||
# which says, that if we have a two character options prefix |
|||
# (applies to "--foo" for instance), we do not dispatch to the |
|||
# short option code and will instead raise the no option |
|||
# error. |
|||
if arg[:2] not in self._opt_prefixes: |
|||
return self._match_short_opt(arg, state) |
|||
if not self.ignore_unknown_options: |
|||
raise |
|||
state.largs.append(arg) |
@ -1,539 +0,0 @@ |
|||
import os |
|||
import sys |
|||
import struct |
|||
|
|||
from ._compat import raw_input, text_type, string_types, \ |
|||
isatty, strip_ansi, get_winterm_size, DEFAULT_COLUMNS, WIN |
|||
from .utils import echo |
|||
from .exceptions import Abort, UsageError |
|||
from .types import convert_type |
|||
from .globals import resolve_color_default |
|||
|
|||
|
|||
# The prompt functions to use. The doc tools currently override these |
|||
# functions to customize how they work. |
|||
visible_prompt_func = raw_input |
|||
|
|||
_ansi_colors = ('black', 'red', 'green', 'yellow', 'blue', 'magenta', |
|||
'cyan', 'white', 'reset') |
|||
_ansi_reset_all = '\033[0m' |
|||
|
|||
|
|||
def hidden_prompt_func(prompt): |
|||
import getpass |
|||
return getpass.getpass(prompt) |
|||
|
|||
|
|||
def _build_prompt(text, suffix, show_default=False, default=None): |
|||
prompt = text |
|||
if default is not None and show_default: |
|||
prompt = '%s [%s]' % (prompt, default) |
|||
return prompt + suffix |
|||
|
|||
|
|||
def prompt(text, default=None, hide_input=False, |
|||
confirmation_prompt=False, type=None, |
|||
value_proc=None, prompt_suffix=': ', |
|||
show_default=True, err=False): |
|||
"""Prompts a user for input. This is a convenience function that can |
|||
be used to prompt a user for input later. |
|||
|
|||
If the user aborts the input by sending a interrupt signal, this |
|||
function will catch it and raise a :exc:`Abort` exception. |
|||
|
|||
.. versionadded:: 6.0 |
|||
Added unicode support for cmd.exe on Windows. |
|||
|
|||
.. versionadded:: 4.0 |
|||
Added the `err` parameter. |
|||
|
|||
:param text: the text to show for the prompt. |
|||
:param default: the default value to use if no input happens. If this |
|||
is not given it will prompt until it's aborted. |
|||
:param hide_input: if this is set to true then the input value will |
|||
be hidden. |
|||
:param confirmation_prompt: asks for confirmation for the value. |
|||
:param type: the type to use to check the value against. |
|||
:param value_proc: if this parameter is provided it's a function that |
|||
is invoked instead of the type conversion to |
|||
convert a value. |
|||
:param prompt_suffix: a suffix that should be added to the prompt. |
|||
:param show_default: shows or hides the default value in the prompt. |
|||
:param err: if set to true the file defaults to ``stderr`` instead of |
|||
``stdout``, the same as with echo. |
|||
""" |
|||
result = None |
|||
|
|||
def prompt_func(text): |
|||
f = hide_input and hidden_prompt_func or visible_prompt_func |
|||
try: |
|||
# Write the prompt separately so that we get nice |
|||
# coloring through colorama on Windows |
|||
echo(text, nl=False, err=err) |
|||
return f('') |
|||
except (KeyboardInterrupt, EOFError): |
|||
# getpass doesn't print a newline if the user aborts input with ^C. |
|||
# Allegedly this behavior is inherited from getpass(3). |
|||
# A doc bug has been filed at https://bugs.python.org/issue24711 |
|||
if hide_input: |
|||
echo(None, err=err) |
|||
raise Abort() |
|||
|
|||
if value_proc is None: |
|||
value_proc = convert_type(type, default) |
|||
|
|||
prompt = _build_prompt(text, prompt_suffix, show_default, default) |
|||
|
|||
while 1: |
|||
while 1: |
|||
value = prompt_func(prompt) |
|||
if value: |
|||
break |
|||
# If a default is set and used, then the confirmation |
|||
# prompt is always skipped because that's the only thing |
|||
# that really makes sense. |
|||
elif default is not None: |
|||
return default |
|||
try: |
|||
result = value_proc(value) |
|||
except UsageError as e: |
|||
echo('Error: %s' % e.message, err=err) |
|||
continue |
|||
if not confirmation_prompt: |
|||
return result |
|||
while 1: |
|||
value2 = prompt_func('Repeat for confirmation: ') |
|||
if value2: |
|||
break |
|||
if value == value2: |
|||
return result |
|||
echo('Error: the two entered values do not match', err=err) |
|||
|
|||
|
|||
def confirm(text, default=False, abort=False, prompt_suffix=': ', |
|||
show_default=True, err=False): |
|||
"""Prompts for confirmation (yes/no question). |
|||
|
|||
If the user aborts the input by sending a interrupt signal this |
|||
function will catch it and raise a :exc:`Abort` exception. |
|||
|
|||
.. versionadded:: 4.0 |
|||
Added the `err` parameter. |
|||
|
|||
:param text: the question to ask. |
|||
:param default: the default for the prompt. |
|||
:param abort: if this is set to `True` a negative answer aborts the |
|||
exception by raising :exc:`Abort`. |
|||
:param prompt_suffix: a suffix that should be added to the prompt. |
|||
:param show_default: shows or hides the default value in the prompt. |
|||
:param err: if set to true the file defaults to ``stderr`` instead of |
|||
``stdout``, the same as with echo. |
|||
""" |
|||
prompt = _build_prompt(text, prompt_suffix, show_default, |
|||
default and 'Y/n' or 'y/N') |
|||
while 1: |
|||
try: |
|||
# Write the prompt separately so that we get nice |
|||
# coloring through colorama on Windows |
|||
echo(prompt, nl=False, err=err) |
|||
value = visible_prompt_func('').lower().strip() |
|||
except (KeyboardInterrupt, EOFError): |
|||
raise Abort() |
|||
if value in ('y', 'yes'): |
|||
rv = True |
|||
elif value in ('n', 'no'): |
|||
rv = False |
|||
elif value == '': |
|||
rv = default |
|||
else: |
|||
echo('Error: invalid input', err=err) |
|||
continue |
|||
break |
|||
if abort and not rv: |
|||
raise Abort() |
|||
return rv |
|||
|
|||
|
|||
def get_terminal_size(): |
|||
"""Returns the current size of the terminal as tuple in the form |
|||
``(width, height)`` in columns and rows. |
|||
""" |
|||
# If shutil has get_terminal_size() (Python 3.3 and later) use that |
|||
if sys.version_info >= (3, 3): |
|||
import shutil |
|||
shutil_get_terminal_size = getattr(shutil, 'get_terminal_size', None) |
|||
if shutil_get_terminal_size: |
|||
sz = shutil_get_terminal_size() |
|||
return sz.columns, sz.lines |
|||
|
|||
if get_winterm_size is not None: |
|||
return get_winterm_size() |
|||
|
|||
def ioctl_gwinsz(fd): |
|||
try: |
|||
import fcntl |
|||
import termios |
|||
cr = struct.unpack( |
|||
'hh', fcntl.ioctl(fd, termios.TIOCGWINSZ, '1234')) |
|||
except Exception: |
|||
return |
|||
return cr |
|||
|
|||
cr = ioctl_gwinsz(0) or ioctl_gwinsz(1) or ioctl_gwinsz(2) |
|||
if not cr: |
|||
try: |
|||
fd = os.open(os.ctermid(), os.O_RDONLY) |
|||
try: |
|||
cr = ioctl_gwinsz(fd) |
|||
finally: |
|||
os.close(fd) |
|||
except Exception: |
|||
pass |
|||
if not cr or not cr[0] or not cr[1]: |
|||
cr = (os.environ.get('LINES', 25), |
|||
os.environ.get('COLUMNS', DEFAULT_COLUMNS)) |
|||
return int(cr[1]), int(cr[0]) |
|||
|
|||
|
|||
def echo_via_pager(text, color=None): |
|||
"""This function takes a text and shows it via an environment specific |
|||
pager on stdout. |
|||
|
|||
.. versionchanged:: 3.0 |
|||
Added the `color` flag. |
|||
|
|||
:param text: the text to page. |
|||
:param color: controls if the pager supports ANSI colors or not. The |
|||
default is autodetection. |
|||
""" |
|||
color = resolve_color_default(color) |
|||
if not isinstance(text, string_types): |
|||
text = text_type(text) |
|||
from ._termui_impl import pager |
|||
return pager(text + '\n', color) |
|||
|
|||
|
|||
def progressbar(iterable=None, length=None, label=None, show_eta=True, |
|||
show_percent=None, show_pos=False, |
|||
item_show_func=None, fill_char='#', empty_char='-', |
|||
bar_template='%(label)s [%(bar)s] %(info)s', |
|||
info_sep=' ', width=36, file=None, color=None): |
|||
"""This function creates an iterable context manager that can be used |
|||
to iterate over something while showing a progress bar. It will |
|||
either iterate over the `iterable` or `length` items (that are counted |
|||
up). While iteration happens, this function will print a rendered |
|||
progress bar to the given `file` (defaults to stdout) and will attempt |
|||
to calculate remaining time and more. By default, this progress bar |
|||
will not be rendered if the file is not a terminal. |
|||
|
|||
The context manager creates the progress bar. When the context |
|||
manager is entered the progress bar is already displayed. With every |
|||
iteration over the progress bar, the iterable passed to the bar is |
|||
advanced and the bar is updated. When the context manager exits, |
|||
a newline is printed and the progress bar is finalized on screen. |
|||
|
|||
No printing must happen or the progress bar will be unintentionally |
|||
destroyed. |
|||
|
|||
Example usage:: |
|||
|
|||
with progressbar(items) as bar: |
|||
for item in bar: |
|||
do_something_with(item) |
|||
|
|||
Alternatively, if no iterable is specified, one can manually update the |
|||
progress bar through the `update()` method instead of directly |
|||
iterating over the progress bar. The update method accepts the number |
|||
of steps to increment the bar with:: |
|||
|
|||
with progressbar(length=chunks.total_bytes) as bar: |
|||
for chunk in chunks: |
|||
process_chunk(chunk) |
|||
bar.update(chunks.bytes) |
|||
|
|||
.. versionadded:: 2.0 |
|||
|
|||
.. versionadded:: 4.0 |
|||
Added the `color` parameter. Added a `update` method to the |
|||
progressbar object. |
|||
|
|||
:param iterable: an iterable to iterate over. If not provided the length |
|||
is required. |
|||
:param length: the number of items to iterate over. By default the |
|||
progressbar will attempt to ask the iterator about its |
|||
length, which might or might not work. If an iterable is |
|||
also provided this parameter can be used to override the |
|||
length. If an iterable is not provided the progress bar |
|||
will iterate over a range of that length. |
|||
:param label: the label to show next to the progress bar. |
|||
:param show_eta: enables or disables the estimated time display. This is |
|||
automatically disabled if the length cannot be |
|||
determined. |
|||
:param show_percent: enables or disables the percentage display. The |
|||
default is `True` if the iterable has a length or |
|||
`False` if not. |
|||
:param show_pos: enables or disables the absolute position display. The |
|||
default is `False`. |
|||
:param item_show_func: a function called with the current item which |
|||
can return a string to show the current item |
|||
next to the progress bar. Note that the current |
|||
item can be `None`! |
|||
:param fill_char: the character to use to show the filled part of the |
|||
progress bar. |
|||
:param empty_char: the character to use to show the non-filled part of |
|||
the progress bar. |
|||
:param bar_template: the format string to use as template for the bar. |
|||
The parameters in it are ``label`` for the label, |
|||
``bar`` for the progress bar and ``info`` for the |
|||
info section. |
|||
:param info_sep: the separator between multiple info items (eta etc.) |
|||
:param width: the width of the progress bar in characters, 0 means full |
|||
terminal width |
|||
:param file: the file to write to. If this is not a terminal then |
|||
only the label is printed. |
|||
:param color: controls if the terminal supports ANSI colors or not. The |
|||
default is autodetection. This is only needed if ANSI |
|||
codes are included anywhere in the progress bar output |
|||
which is not the case by default. |
|||
""" |
|||
from ._termui_impl import ProgressBar |
|||
color = resolve_color_default(color) |
|||
return ProgressBar(iterable=iterable, length=length, show_eta=show_eta, |
|||
show_percent=show_percent, show_pos=show_pos, |
|||
item_show_func=item_show_func, fill_char=fill_char, |
|||
empty_char=empty_char, bar_template=bar_template, |
|||
info_sep=info_sep, file=file, label=label, |
|||
width=width, color=color) |
|||
|
|||
|
|||
def clear(): |
|||
"""Clears the terminal screen. This will have the effect of clearing |
|||
the whole visible space of the terminal and moving the cursor to the |
|||
top left. This does not do anything if not connected to a terminal. |
|||
|
|||
.. versionadded:: 2.0 |
|||
""" |
|||
if not isatty(sys.stdout): |
|||
return |
|||
# If we're on Windows and we don't have colorama available, then we |
|||
# clear the screen by shelling out. Otherwise we can use an escape |
|||
# sequence. |
|||
if WIN: |
|||
os.system('cls') |
|||
else: |
|||
sys.stdout.write('\033[2J\033[1;1H') |
|||
|
|||
|
|||
def style(text, fg=None, bg=None, bold=None, dim=None, underline=None, |
|||
blink=None, reverse=None, reset=True): |
|||
"""Styles a text with ANSI styles and returns the new string. By |
|||
default the styling is self contained which means that at the end |
|||
of the string a reset code is issued. This can be prevented by |
|||
passing ``reset=False``. |
|||
|
|||
Examples:: |
|||
|
|||
click.echo(click.style('Hello World!', fg='green')) |
|||
click.echo(click.style('ATTENTION!', blink=True)) |
|||
click.echo(click.style('Some things', reverse=True, fg='cyan')) |
|||
|
|||
Supported color names: |
|||
|
|||
* ``black`` (might be a gray) |
|||
* ``red`` |
|||
* ``green`` |
|||
* ``yellow`` (might be an orange) |
|||
* ``blue`` |
|||
* ``magenta`` |
|||
* ``cyan`` |
|||
* ``white`` (might be light gray) |
|||
* ``reset`` (reset the color code only) |
|||
|
|||
.. versionadded:: 2.0 |
|||
|
|||
:param text: the string to style with ansi codes. |
|||
:param fg: if provided this will become the foreground color. |
|||
:param bg: if provided this will become the background color. |
|||
:param bold: if provided this will enable or disable bold mode. |
|||
:param dim: if provided this will enable or disable dim mode. This is |
|||
badly supported. |
|||
:param underline: if provided this will enable or disable underline. |
|||
:param blink: if provided this will enable or disable blinking. |
|||
:param reverse: if provided this will enable or disable inverse |
|||
rendering (foreground becomes background and the |
|||
other way round). |
|||
:param reset: by default a reset-all code is added at the end of the |
|||
string which means that styles do not carry over. This |
|||
can be disabled to compose styles. |
|||
""" |
|||
bits = [] |
|||
if fg: |
|||
try: |
|||
bits.append('\033[%dm' % (_ansi_colors.index(fg) + 30)) |
|||
except ValueError: |
|||
raise TypeError('Unknown color %r' % fg) |
|||
if bg: |
|||
try: |
|||
bits.append('\033[%dm' % (_ansi_colors.index(bg) + 40)) |
|||
except ValueError: |
|||
raise TypeError('Unknown color %r' % bg) |
|||
if bold is not None: |
|||
bits.append('\033[%dm' % (1 if bold else 22)) |
|||
if dim is not None: |
|||
bits.append('\033[%dm' % (2 if dim else 22)) |
|||
if underline is not None: |
|||
bits.append('\033[%dm' % (4 if underline else 24)) |
|||
if blink is not None: |
|||
bits.append('\033[%dm' % (5 if blink else 25)) |
|||
if reverse is not None: |
|||
bits.append('\033[%dm' % (7 if reverse else 27)) |
|||
bits.append(text) |
|||
if reset: |
|||
bits.append(_ansi_reset_all) |
|||
return ''.join(bits) |
|||
|
|||
|
|||
def unstyle(text): |
|||
"""Removes ANSI styling information from a string. Usually it's not |
|||
necessary to use this function as Click's echo function will |
|||
automatically remove styling if necessary. |
|||
|
|||
.. versionadded:: 2.0 |
|||
|
|||
:param text: the text to remove style information from. |
|||
""" |
|||
return strip_ansi(text) |
|||
|
|||
|
|||
def secho(text, file=None, nl=True, err=False, color=None, **styles): |
|||
"""This function combines :func:`echo` and :func:`style` into one |
|||
call. As such the following two calls are the same:: |
|||
|
|||
click.secho('Hello World!', fg='green') |
|||
click.echo(click.style('Hello World!', fg='green')) |
|||
|
|||
All keyword arguments are forwarded to the underlying functions |
|||
depending on which one they go with. |
|||
|
|||
.. versionadded:: 2.0 |
|||
""" |
|||
return echo(style(text, **styles), file=file, nl=nl, err=err, color=color) |
|||
|
|||
|
|||
def edit(text=None, editor=None, env=None, require_save=True, |
|||
extension='.txt', filename=None): |
|||
r"""Edits the given text in the defined editor. If an editor is given |
|||
(should be the full path to the executable but the regular operating |
|||
system search path is used for finding the executable) it overrides |
|||
the detected editor. Optionally, some environment variables can be |
|||
used. If the editor is closed without changes, `None` is returned. In |
|||
case a file is edited directly the return value is always `None` and |
|||
`require_save` and `extension` are ignored. |
|||
|
|||
If the editor cannot be opened a :exc:`UsageError` is raised. |
|||
|
|||
Note for Windows: to simplify cross-platform usage, the newlines are |
|||
automatically converted from POSIX to Windows and vice versa. As such, |
|||
the message here will have ``\n`` as newline markers. |
|||
|
|||
:param text: the text to edit. |
|||
:param editor: optionally the editor to use. Defaults to automatic |
|||
detection. |
|||
:param env: environment variables to forward to the editor. |
|||
:param require_save: if this is true, then not saving in the editor |
|||
will make the return value become `None`. |
|||
:param extension: the extension to tell the editor about. This defaults |
|||
to `.txt` but changing this might change syntax |
|||
highlighting. |
|||
:param filename: if provided it will edit this file instead of the |
|||
provided text contents. It will not use a temporary |
|||
file as an indirection in that case. |
|||
""" |
|||
from ._termui_impl import Editor |
|||
editor = Editor(editor=editor, env=env, require_save=require_save, |
|||
extension=extension) |
|||
if filename is None: |
|||
return editor.edit(text) |
|||
editor.edit_file(filename) |
|||
|
|||
|
|||
def launch(url, wait=False, locate=False): |
|||
"""This function launches the given URL (or filename) in the default |
|||
viewer application for this file type. If this is an executable, it |
|||
might launch the executable in a new session. The return value is |
|||
the exit code of the launched application. Usually, ``0`` indicates |
|||
success. |
|||
|
|||
Examples:: |
|||
|
|||
click.launch('http://click.pocoo.org/') |
|||
click.launch('/my/downloaded/file', locate=True) |
|||
|
|||
.. versionadded:: 2.0 |
|||
|
|||
:param url: URL or filename of the thing to launch. |
|||
:param wait: waits for the program to stop. |
|||
:param locate: if this is set to `True` then instead of launching the |
|||
application associated with the URL it will attempt to |
|||
launch a file manager with the file located. This |
|||
might have weird effects if the URL does not point to |
|||
the filesystem. |
|||
""" |
|||
from ._termui_impl import open_url |
|||
return open_url(url, wait=wait, locate=locate) |
|||
|
|||
|
|||
# If this is provided, getchar() calls into this instead. This is used |
|||
# for unittesting purposes. |
|||
_getchar = None |
|||
|
|||
|
|||
def getchar(echo=False): |
|||
"""Fetches a single character from the terminal and returns it. This |
|||
will always return a unicode character and under certain rare |
|||
circumstances this might return more than one character. The |
|||
situations which more than one character is returned is when for |
|||
whatever reason multiple characters end up in the terminal buffer or |
|||
standard input was not actually a terminal. |
|||
|
|||
Note that this will always read from the terminal, even if something |
|||
is piped into the standard input. |
|||
|
|||
.. versionadded:: 2.0 |
|||
|
|||
:param echo: if set to `True`, the character read will also show up on |
|||
the terminal. The default is to not show it. |
|||
""" |
|||
f = _getchar |
|||
if f is None: |
|||
from ._termui_impl import getchar as f |
|||
return f(echo) |
|||
|
|||
|
|||
def pause(info='Press any key to continue ...', err=False): |
|||
"""This command stops execution and waits for the user to press any |
|||
key to continue. This is similar to the Windows batch "pause" |
|||
command. If the program is not run through a terminal, this command |
|||
will instead do nothing. |
|||
|
|||
.. versionadded:: 2.0 |
|||
|
|||
.. versionadded:: 4.0 |
|||
Added the `err` parameter. |
|||
|
|||
:param info: the info string to print before pausing. |
|||
:param err: if set to message goes to ``stderr`` instead of |
|||
``stdout``, the same as with echo. |
|||
""" |
|||
if not isatty(sys.stdin) or not isatty(sys.stdout): |
|||
return |
|||
try: |
|||
if info: |
|||
echo(info, nl=False, err=err) |
|||
try: |
|||
getchar() |
|||
except (KeyboardInterrupt, EOFError): |
|||
pass |
|||
finally: |
|||
if info: |
|||
echo(err=err) |
@ -1,322 +0,0 @@ |
|||
import os |
|||
import sys |
|||
import shutil |
|||
import tempfile |
|||
import contextlib |
|||
|
|||
from ._compat import iteritems, PY2 |
|||
|
|||
|
|||
# If someone wants to vendor click, we want to ensure the |
|||
# correct package is discovered. Ideally we could use a |
|||
# relative import here but unfortunately Python does not |
|||
# support that. |
|||
clickpkg = sys.modules[__name__.rsplit('.', 1)[0]] |
|||
|
|||
|
|||
if PY2: |
|||
from cStringIO import StringIO |
|||
else: |
|||
import io |
|||
from ._compat import _find_binary_reader |
|||
|
|||
|
|||
class EchoingStdin(object): |
|||
|
|||
def __init__(self, input, output): |
|||
self._input = input |
|||
self._output = output |
|||
|
|||
def __getattr__(self, x): |
|||
return getattr(self._input, x) |
|||
|
|||
def _echo(self, rv): |
|||
self._output.write(rv) |
|||
return rv |
|||
|
|||
def read(self, n=-1): |
|||
return self._echo(self._input.read(n)) |
|||
|
|||
def readline(self, n=-1): |
|||
return self._echo(self._input.readline(n)) |
|||
|
|||
def readlines(self): |
|||
return [self._echo(x) for x in self._input.readlines()] |
|||
|
|||
def __iter__(self): |
|||
return iter(self._echo(x) for x in self._input) |
|||
|
|||
def __repr__(self): |
|||
return repr(self._input) |
|||
|
|||
|
|||
def make_input_stream(input, charset): |
|||
# Is already an input stream. |
|||
if hasattr(input, 'read'): |
|||
if PY2: |
|||
return input |
|||
rv = _find_binary_reader(input) |
|||
if rv is not None: |
|||
return rv |
|||
raise TypeError('Could not find binary reader for input stream.') |
|||
|
|||
if input is None: |
|||
input = b'' |
|||
elif not isinstance(input, bytes): |
|||
input = input.encode(charset) |
|||
if PY2: |
|||
return StringIO(input) |
|||
return io.BytesIO(input) |
|||
|
|||
|
|||
class Result(object): |
|||
"""Holds the captured result of an invoked CLI script.""" |
|||
|
|||
def __init__(self, runner, output_bytes, exit_code, exception, |
|||
exc_info=None): |
|||
#: The runner that created the result |
|||
self.runner = runner |
|||
#: The output as bytes. |
|||
self.output_bytes = output_bytes |
|||
#: The exit code as integer. |
|||
self.exit_code = exit_code |
|||
#: The exception that happend if one did. |
|||
self.exception = exception |
|||
#: The traceback |
|||
self.exc_info = exc_info |
|||
|
|||
@property |
|||
def output(self): |
|||
"""The output as unicode string.""" |
|||
return self.output_bytes.decode(self.runner.charset, 'replace') \ |
|||
.replace('\r\n', '\n') |
|||
|
|||
def __repr__(self): |
|||
return '<Result %s>' % ( |
|||
self.exception and repr(self.exception) or 'okay', |
|||
) |
|||
|
|||
|
|||
class CliRunner(object): |
|||
"""The CLI runner provides functionality to invoke a Click command line |
|||
script for unittesting purposes in a isolated environment. This only |
|||
works in single-threaded systems without any concurrency as it changes the |
|||
global interpreter state. |
|||
|
|||
:param charset: the character set for the input and output data. This is |
|||
UTF-8 by default and should not be changed currently as |
|||
the reporting to Click only works in Python 2 properly. |
|||
:param env: a dictionary with environment variables for overriding. |
|||
:param echo_stdin: if this is set to `True`, then reading from stdin writes |
|||
to stdout. This is useful for showing examples in |
|||
some circumstances. Note that regular prompts |
|||
will automatically echo the input. |
|||
""" |
|||
|
|||
def __init__(self, charset=None, env=None, echo_stdin=False): |
|||
if charset is None: |
|||
charset = 'utf-8' |
|||
self.charset = charset |
|||
self.env = env or {} |
|||
self.echo_stdin = echo_stdin |
|||
|
|||
def get_default_prog_name(self, cli): |
|||
"""Given a command object it will return the default program name |
|||
for it. The default is the `name` attribute or ``"root"`` if not |
|||
set. |
|||
""" |
|||
return cli.name or 'root' |
|||
|
|||
def make_env(self, overrides=None): |
|||
"""Returns the environment overrides for invoking a script.""" |
|||
rv = dict(self.env) |
|||
if overrides: |
|||
rv.update(overrides) |
|||
return rv |
|||
|
|||
@contextlib.contextmanager |
|||
def isolation(self, input=None, env=None, color=False): |
|||
"""A context manager that sets up the isolation for invoking of a |
|||
command line tool. This sets up stdin with the given input data |
|||
and `os.environ` with the overrides from the given dictionary. |
|||
This also rebinds some internals in Click to be mocked (like the |
|||
prompt functionality). |
|||
|
|||
This is automatically done in the :meth:`invoke` method. |
|||
|
|||
.. versionadded:: 4.0 |
|||
The ``color`` parameter was added. |
|||
|
|||
:param input: the input stream to put into sys.stdin. |
|||
:param env: the environment overrides as dictionary. |
|||
:param color: whether the output should contain color codes. The |
|||
application can still override this explicitly. |
|||
""" |
|||
input = make_input_stream(input, self.charset) |
|||
|
|||
old_stdin = sys.stdin |
|||
old_stdout = sys.stdout |
|||
old_stderr = sys.stderr |
|||
old_forced_width = clickpkg.formatting.FORCED_WIDTH |
|||
clickpkg.formatting.FORCED_WIDTH = 80 |
|||
|
|||
env = self.make_env(env) |
|||
|
|||
if PY2: |
|||
sys.stdout = sys.stderr = bytes_output = StringIO() |
|||
if self.echo_stdin: |
|||
input = EchoingStdin(input, bytes_output) |
|||
else: |
|||
bytes_output = io.BytesIO() |
|||
if self.echo_stdin: |
|||
input = EchoingStdin(input, bytes_output) |
|||
input = io.TextIOWrapper(input, encoding=self.charset) |
|||
sys.stdout = sys.stderr = io.TextIOWrapper( |
|||
bytes_output, encoding=self.charset) |
|||
|
|||
sys.stdin = input |
|||
|
|||
def visible_input(prompt=None): |
|||
sys.stdout.write(prompt or '') |
|||
val = input.readline().rstrip('\r\n') |
|||
sys.stdout.write(val + '\n') |
|||
sys.stdout.flush() |
|||
return val |
|||
|
|||
def hidden_input(prompt=None): |
|||
sys.stdout.write((prompt or '') + '\n') |
|||
sys.stdout.flush() |
|||
return input.readline().rstrip('\r\n') |
|||
|
|||
def _getchar(echo): |
|||
char = sys.stdin.read(1) |
|||
if echo: |
|||
sys.stdout.write(char) |
|||
sys.stdout.flush() |
|||
return char |
|||
|
|||
default_color = color |
|||
def should_strip_ansi(stream=None, color=None): |
|||
if color is None: |
|||
return not default_color |
|||
return not color |
|||
|
|||
old_visible_prompt_func = clickpkg.termui.visible_prompt_func |
|||
old_hidden_prompt_func = clickpkg.termui.hidden_prompt_func |
|||
old__getchar_func = clickpkg.termui._getchar |
|||
old_should_strip_ansi = clickpkg.utils.should_strip_ansi |
|||
clickpkg.termui.visible_prompt_func = visible_input |
|||
clickpkg.termui.hidden_prompt_func = hidden_input |
|||
clickpkg.termui._getchar = _getchar |
|||
clickpkg.utils.should_strip_ansi = should_strip_ansi |
|||
|
|||
old_env = {} |
|||
try: |
|||
for key, value in iteritems(env): |
|||
old_env[key] = os.environ.get(value) |
|||
if value is None: |
|||
try: |
|||
del os.environ[key] |
|||
except Exception: |
|||
pass |
|||
else: |
|||
os.environ[key] = value |
|||
yield bytes_output |
|||
finally: |
|||
for key, value in iteritems(old_env): |
|||
if value is None: |
|||
try: |
|||
del os.environ[key] |
|||
except Exception: |
|||
pass |
|||
else: |
|||
os.environ[key] = value |
|||
sys.stdout = old_stdout |
|||
sys.stderr = old_stderr |
|||
sys.stdin = old_stdin |
|||
clickpkg.termui.visible_prompt_func = old_visible_prompt_func |
|||
clickpkg.termui.hidden_prompt_func = old_hidden_prompt_func |
|||
clickpkg.termui._getchar = old__getchar_func |
|||
clickpkg.utils.should_strip_ansi = old_should_strip_ansi |
|||
clickpkg.formatting.FORCED_WIDTH = old_forced_width |
|||
|
|||
def invoke(self, cli, args=None, input=None, env=None, |
|||
catch_exceptions=True, color=False, **extra): |
|||
"""Invokes a command in an isolated environment. The arguments are |
|||
forwarded directly to the command line script, the `extra` keyword |
|||
arguments are passed to the :meth:`~clickpkg.Command.main` function of |
|||
the command. |
|||
|
|||
This returns a :class:`Result` object. |
|||
|
|||
.. versionadded:: 3.0 |
|||
The ``catch_exceptions`` parameter was added. |
|||
|
|||
.. versionchanged:: 3.0 |
|||
The result object now has an `exc_info` attribute with the |
|||
traceback if available. |
|||
|
|||
.. versionadded:: 4.0 |
|||
The ``color`` parameter was added. |
|||
|
|||
:param cli: the command to invoke |
|||
:param args: the arguments to invoke |
|||
:param input: the input data for `sys.stdin`. |
|||
:param env: the environment overrides. |
|||
:param catch_exceptions: Whether to catch any other exceptions than |
|||
``SystemExit``. |
|||
:param extra: the keyword arguments to pass to :meth:`main`. |
|||
:param color: whether the output should contain color codes. The |
|||
application can still override this explicitly. |
|||
""" |
|||
exc_info = None |
|||
with self.isolation(input=input, env=env, color=color) as out: |
|||
exception = None |
|||
exit_code = 0 |
|||
|
|||
try: |
|||
cli.main(args=args or (), |
|||
prog_name=self.get_default_prog_name(cli), **extra) |
|||
except SystemExit as e: |
|||
if e.code != 0: |
|||
exception = e |
|||
|
|||
exc_info = sys.exc_info() |
|||
|
|||
exit_code = e.code |
|||
if not isinstance(exit_code, int): |
|||
sys.stdout.write(str(exit_code)) |
|||
sys.stdout.write('\n') |
|||
exit_code = 1 |
|||
except Exception as e: |
|||
if not catch_exceptions: |
|||
raise |
|||
exception = e |
|||
exit_code = -1 |
|||
exc_info = sys.exc_info() |
|||
finally: |
|||
sys.stdout.flush() |
|||
output = out.getvalue() |
|||
|
|||
return Result(runner=self, |
|||
output_bytes=output, |
|||
exit_code=exit_code, |
|||
exception=exception, |
|||
exc_info=exc_info) |
|||
|
|||
@contextlib.contextmanager |
|||
def isolated_filesystem(self): |
|||
"""A context manager that creates a temporary folder and changes |
|||
the current working directory to it for isolated filesystem tests. |
|||
""" |
|||
cwd = os.getcwd() |
|||
t = tempfile.mkdtemp() |
|||
os.chdir(t) |
|||
try: |
|||
yield t |
|||
finally: |
|||
os.chdir(cwd) |
|||
try: |
|||
shutil.rmtree(t) |
|||
except (OSError, IOError): |
|||
pass |
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue