Do the monkey patch instead

This commit is contained in:
Alex Gaynor 2017-03-26 11:17:02 -04:00
parent ca19d0d572
commit ef7db41728
6 changed files with 49 additions and 52 deletions

View File

@ -51,7 +51,7 @@ logger = logging.getLogger(__name__)
warnings.filterwarnings("ignore", category=InsecureRequestWarning)
def autocomplete(stdout):
def autocomplete():
"""Command and option completion for the main option parser (and options)
and its subcommands (and options).
@ -75,7 +75,7 @@ def autocomplete(stdout):
except IndexError:
subcommand_name = None
parser = create_main_parser(stdout=stdout)
parser = create_main_parser()
# subcommand options
if subcommand_name:
# special case: 'help' subcommand has no options
@ -124,14 +124,13 @@ def autocomplete(stdout):
sys.exit(1)
def create_main_parser(stdout):
def create_main_parser():
parser_kw = {
'usage': '\n%prog <command> [options]',
'add_help_option': False,
'formatter': UpdatingDefaultsHelpFormatter(),
'name': 'global',
'prog': get_prog(),
'stdout': stdout,
}
parser = ConfigOptionParser(**parser_kw)
@ -155,8 +154,8 @@ def create_main_parser(stdout):
return parser
def parseopts(args, stdout):
parser = create_main_parser(stdout=stdout)
def parseopts(args):
parser = create_main_parser()
# Note: parser calls disable_interspersed_args(), so the result of this
# call is to split the initial args into the general options before the
@ -169,8 +168,8 @@ def parseopts(args, stdout):
# --version
if general_options.version:
stdout.write(parser.version)
stdout.write(os.linesep)
sys.stdout.write(parser.version)
sys.stdout.write(os.linesep)
sys.exit()
# pip || pip help -> print_help()
@ -206,26 +205,20 @@ def check_isolated(args):
return isolated
def main(args=None, stdin=None, stdout=None, stderr=None):
def main(args=None):
if args is None:
args = sys.argv[1:]
if stdin is None:
stdin = sys.stdin
if stdout is None:
stdout = sys.stdout
if stderr is None:
stderr = sys.stderr
# Configure our deprecation warnings to be sent through loggers
deprecation.install_warning_logger()
autocomplete(stdout=stdout)
autocomplete()
try:
cmd_name, cmd_args = parseopts(args, stdout=stdout)
cmd_name, cmd_args = parseopts(args)
except PipError as exc:
stderr.write("ERROR: %s" % exc)
stderr.write(os.linesep)
sys.stderr.write("ERROR: %s" % exc)
sys.stderr.write(os.linesep)
sys.exit(1)
# Needed for locale.getpreferredencoding(False) to work
@ -235,9 +228,7 @@ def main(args=None, stdin=None, stdout=None, stderr=None):
except locale.Error as e:
# setlocale can apparently crash if locale are uninitialized
logger.debug("Ignoring error %s when setting locale", e)
command = commands_dict[cmd_name](
isolated=check_isolated(cmd_args), stdout=stdout
)
command = commands_dict[cmd_name](isolated=check_isolated(cmd_args))
return command.main(cmd_args)

View File

@ -38,7 +38,7 @@ class Command(object):
hidden = False
log_streams = ("ext://sys.stdout", "ext://sys.stderr")
def __init__(self, isolated=False, stdout=None):
def __init__(self, isolated=False):
parser_kw = {
'usage': self.usage,
'prog': '%s %s' % (get_prog(), self.name),
@ -47,7 +47,6 @@ class Command(object):
'name': self.name,
'description': self.__doc__,
'isolated': isolated,
'stdout': stdout,
}
self.parser = ConfigOptionParser(**parser_kw)

View File

@ -130,7 +130,6 @@ class ConfigOptionParser(CustomOptionParser):
def __init__(self, *args, **kwargs):
self.name = kwargs.pop('name')
self.stdout = kwargs.pop('stdout')
isolated = kwargs.pop("isolated", False)
self.config = Configuration(isolated)
@ -209,9 +208,6 @@ class ConfigOptionParser(CustomOptionParser):
defaults[option.dest] = option.check_value(opt_str, default)
return optparse.Values(defaults)
def print_help(self):
return CustomOptionParser.print_help(self, file=self.stdout)
def error(self, msg):
self.print_usage(sys.stderr)
self.exit(2, "%s\n" % msg)

View File

@ -29,7 +29,7 @@ class HelpCommand(Command):
raise CommandError(' - '.join(msg))
command = commands_dict[cmd_name](stdout=self.parser.stdout)
command = commands_dict[cmd_name]()
command.parser.print_help()
return SUCCESS

View File

@ -186,3 +186,32 @@ def script(tmpdir, virtualenv):
@pytest.fixture
def data(tmpdir):
return TestData.copy(tmpdir.join("data"))
class InMemoryPipResult(object):
def __init__(self, returncode, stdout):
self.returncode = returncode
self.stdout = stdout
class InMemoryPip(object):
def pip(self, *args):
import io
import sys
import pip
orig_stdout = sys.stdout
sys.stdout = stdout = io.BytesIO()
try:
returncode = pip.main(list(args))
except SystemExit as e:
returncode = e.code or 0
finally:
sys.stdout = orig_stdout
return InMemoryPipResult(returncode, stdout.getvalue())
@pytest.fixture
def in_memory_pip():
return InMemoryPip()

View File

@ -65,30 +65,12 @@ def test_help_command_should_exit_status_error_when_cmd_does_not_exist(script):
assert result.returncode == ERROR
class InMemoryPipResult(object):
def __init__(self, returncode, stdout):
self.returncode = returncode
self.stdout = stdout
def in_memory_pip(*args):
import io
import pip
stdout = io.BytesIO()
try:
returncode = pip.main(list(args), stdout=stdout)
except SystemExit as e:
returncode = e.code or 0
return InMemoryPipResult(returncode, stdout.getvalue())
def test_help_commands_equally_functional():
def test_help_commands_equally_functional(in_memory_pip):
"""
Test if `pip help` and 'pip --help' behave the same way.
"""
results = list(map(in_memory_pip, ('help', '--help')))
results.append(in_memory_pip())
results = list(map(in_memory_pip.pip, ('help', '--help')))
results.append(in_memory_pip.pip())
out = map(lambda x: x.stdout, results)
ret = map(lambda x: x.returncode, results)
@ -103,6 +85,6 @@ def test_help_commands_equally_functional():
continue
assert (
in_memory_pip('help', name).stdout ==
in_memory_pip(name, '--help').stdout != ""
in_memory_pip.pip('help', name).stdout ==
in_memory_pip.pip(name, '--help').stdout != ""
)