141 lines
5 KiB
Python
141 lines
5 KiB
Python
|
import os
|
||
|
import sys
|
||
|
|
||
|
PY3 = sys.version_info[0] == 3
|
||
|
OLD_PY2 = sys.version_info[:2] < (2, 7)
|
||
|
|
||
|
if PY3: # pragma: no cover
|
||
|
input_str = 'builtins.input'
|
||
|
iteritems = lambda d: iter(d.items())
|
||
|
from unittest.mock import patch
|
||
|
from io import StringIO
|
||
|
|
||
|
def read_response(prompt=''):
|
||
|
"""
|
||
|
Prompt the user for a response.
|
||
|
|
||
|
Prints the given prompt (which should be a Unicode string),
|
||
|
and returns the text entered by the user as a Unicode string.
|
||
|
|
||
|
:param prompt: A Unicode string that is presented to the user.
|
||
|
"""
|
||
|
# The Python 3 input function does exactly what we want
|
||
|
return input(prompt)
|
||
|
|
||
|
else: # pragma: no cover
|
||
|
from __builtin__ import raw_input
|
||
|
input = raw_input
|
||
|
input_str = '__builtin__.raw_input'
|
||
|
iteritems = lambda d: d.iteritems()
|
||
|
from mock import patch
|
||
|
from cStringIO import StringIO
|
||
|
|
||
|
def read_response(prompt=''):
|
||
|
"""
|
||
|
Prompt the user for a response.
|
||
|
|
||
|
Prints the given prompt (which should be a Unicode string),
|
||
|
and returns the text entered by the user as a Unicode string.
|
||
|
|
||
|
:param prompt: A Unicode string that is presented to the user.
|
||
|
"""
|
||
|
# For Python 2, raw_input takes a byte string argument for the prompt.
|
||
|
# This must be encoded using the encoding used by sys.stdout.
|
||
|
# The result is a byte string encoding using sys.stdin.encoding.
|
||
|
# However, if the program is not being run interactively, sys.stdout
|
||
|
# and sys.stdin may not have encoding attributes.
|
||
|
# In that case we don't print a prompt (stdin/out isn't interactive,
|
||
|
# so prompting is pointless), and we assume the returned data is
|
||
|
# encoded using sys.getdefaultencoding(). This may not be right,
|
||
|
# but it's likely the best we can do.
|
||
|
# Isn't Python 2 encoding support wonderful? :-)
|
||
|
if sys.stdout.encoding:
|
||
|
prompt = prompt.encode(sys.stdout.encoding)
|
||
|
else:
|
||
|
prompt = ''
|
||
|
enc = sys.stdin.encoding or sys.getdefaultencoding()
|
||
|
return raw_input(prompt).decode(enc)
|
||
|
|
||
|
|
||
|
if PY3: # Forced testing
|
||
|
|
||
|
from shutil import which
|
||
|
|
||
|
else: # Forced testing
|
||
|
|
||
|
def is_exe(program):
|
||
|
"""
|
||
|
Returns whether or not a file is an executable.
|
||
|
"""
|
||
|
return os.path.isfile(program) and os.access(program, os.X_OK)
|
||
|
|
||
|
def which(cmd, mode=os.F_OK | os.X_OK, path=None):
|
||
|
"""Given a command, mode, and a PATH string, return the path which
|
||
|
conforms to the given mode on the PATH, or None if there is no such
|
||
|
file.
|
||
|
`mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result
|
||
|
of os.environ.get("PATH"), or can be overridden with a custom search
|
||
|
path.
|
||
|
|
||
|
Note: This function was backported from the Python 3 source code.
|
||
|
"""
|
||
|
# Check that a given file can be accessed with the correct mode.
|
||
|
# Additionally check that `file` is not a directory, as on Windows
|
||
|
# directories pass the os.access check.
|
||
|
def _access_check(fn, mode):
|
||
|
return (os.path.exists(fn) and os.access(fn, mode)
|
||
|
and not os.path.isdir(fn))
|
||
|
|
||
|
# If we're given a path with a directory part, look it up directly
|
||
|
# rather than referring to PATH directories. This includes checking
|
||
|
# relative to the current directory, e.g. ./script
|
||
|
if os.path.dirname(cmd):
|
||
|
if _access_check(cmd, mode):
|
||
|
return cmd
|
||
|
return None
|
||
|
|
||
|
if path is None:
|
||
|
path = os.environ.get("PATH", os.defpath)
|
||
|
if not path:
|
||
|
return None
|
||
|
path = path.split(os.pathsep)
|
||
|
|
||
|
if sys.platform == "win32":
|
||
|
# The current directory takes precedence on Windows.
|
||
|
if os.curdir not in path:
|
||
|
path.insert(0, os.curdir)
|
||
|
|
||
|
# PATHEXT is necessary to check on Windows.
|
||
|
pathext = os.environ.get("PATHEXT", "").split(os.pathsep)
|
||
|
# See if the given file matches any of the expected path
|
||
|
# extensions. This will allow us to short circuit when given
|
||
|
# "python.exe". If it does match, only test that one, otherwise we
|
||
|
# have to try others.
|
||
|
if any(cmd.lower().endswith(ext.lower()) for ext in pathext):
|
||
|
files = [cmd]
|
||
|
else:
|
||
|
files = [cmd + ext for ext in pathext]
|
||
|
else:
|
||
|
# On other platforms you don't have things like PATHEXT to tell you
|
||
|
# what file suffixes are executable, so just pass on cmd as-is.
|
||
|
files = [cmd]
|
||
|
|
||
|
seen = set()
|
||
|
for dir in path:
|
||
|
normdir = os.path.normcase(dir)
|
||
|
if normdir not in seen:
|
||
|
seen.add(normdir)
|
||
|
for thefile in files:
|
||
|
name = os.path.join(dir, thefile)
|
||
|
if _access_check(name, mode):
|
||
|
return name
|
||
|
return None
|
||
|
|
||
|
|
||
|
def is_string(obj):
|
||
|
"""Determine if an object is a string."""
|
||
|
return isinstance(obj, str if PY3 else basestring)
|
||
|
|
||
|
|
||
|
_hush_pyflakes = (patch, StringIO, which)
|