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