Skip to content

option parsing fixes #1202

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Sep 17, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions docs/pipext.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
from docutils.statemachine import ViewList
from textwrap import dedent
from pip import commands
from pip.baseparser import create_main_parser, standard_options
from pip import cmdoptions
from pip.util import get_prog

Expand Down Expand Up @@ -79,19 +78,19 @@ def run(self):

class PipGeneralOptions(PipOptions):
def process_options(self):
self._format_options(standard_options)
self._format_options([o.make() for o in cmdoptions.general_group['options']])


class PipIndexOptions(PipOptions):
def process_options(self):
self._format_options(cmdoptions.index_group['options'])
self._format_options([o.make() for o in cmdoptions.index_group['options']])


class PipCommandOptions(PipOptions):
required_arguments = 1

def process_options(self):
cmd = commands[self.arguments[0]](create_main_parser())
cmd = commands[self.arguments[0]]()
self._format_options(cmd.parser.option_groups[0].option_list, cmd_name=cmd.name)


Expand Down
79 changes: 55 additions & 24 deletions pip/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@
import sys
import re

from pip import cmdoptions
from pip.exceptions import InstallationError, CommandError, PipError
from pip.log import logger
from pip.util import get_installed_distributions, get_prog
from pip.vcs import git, mercurial, subversion, bazaar # noqa
from pip.baseparser import create_main_parser
from pip.commands import commands, get_similar_commands, get_summaries

from pip.baseparser import (ConfigOptionParser, UpdatingDefaultsHelpFormatter,
version)
from pip.commands import commands, get_summaries, get_similar_commands

# The version as used in the setup.py and the docs conf.py
__version__ = "1.5.dev1"
Expand Down Expand Up @@ -60,7 +61,7 @@ def autocomplete():
print(dist)
sys.exit(1)

subcommand = commands[subcommand_name](parser)
subcommand = commands[subcommand_name]()
options += [(opt.get_opt_string(), opt.nargs)
for opt in subcommand.parser.option_list_all
if opt.help != optparse.SUPPRESS_HELP]
Expand Down Expand Up @@ -90,45 +91,75 @@ def autocomplete():
sys.exit(1)


def parseopts(args):
parser = create_main_parser()
def create_main_parser():
parser_kw = {
'usage': '\n%prog <command> [options]',
'add_help_option': False,
'formatter': UpdatingDefaultsHelpFormatter(),
'name': 'global',
'prog': get_prog(),
}

parser = ConfigOptionParser(**parser_kw)
parser.disable_interspersed_args()

# having a default version action just causes trouble
parser.version = version

# add the general options
gen_opts = cmdoptions.make_option_group(cmdoptions.general_group, parser)
parser.add_option_group(gen_opts)

parser.main = True # so the help formatter knows

# create command listing
# create command listing for description
command_summaries = get_summaries()

description = [''] + ['%-27s %s' % (i, j) for i, j in command_summaries]
parser.description = '\n'.join(description)

options, args = parser.parse_args(args)
return parser


def parseopts(args):
parser = create_main_parser()

if options.version:
# Note: parser calls disable_interspersed_args(), so the result of this call
# is to split the initial args into the general options before the
# subcommand and everything else.
# For example:
# args: ['--timeout=5', 'install', '--user', 'INITools']
# general_options: ['--timeout==5']
# args_else: ['install', '--user', 'INITools']
general_options, args_else = parser.parse_args(args)

# --version
if general_options.version:
sys.stdout.write(parser.version)
sys.stdout.write(os.linesep)
sys.exit()

# pip || pip help || pip --help -> print_help()
if not args or (args[0] == 'help' and len(args) == 1):
# pip || pip help -> print_help()
if not args_else or (args_else[0] == 'help' and len(args_else) == 1):
parser.print_help()
sys.exit()

if not args:
msg = ('You must give a command '
'(use "pip --help" to see a list of commands)')
raise CommandError(msg)
# the subcommand name
cmd_name = args_else[0].lower()

command = args[0].lower()
#all the args without the subcommand
cmd_args = args[:]
cmd_args.remove(args_else[0].lower())

if command not in commands:
guess = get_similar_commands(command)
if cmd_name not in commands:
guess = get_similar_commands(cmd_name)

msg = ['unknown command "%s"' % command]
msg = ['unknown command "%s"' % cmd_name]
if guess:
msg.append('maybe you meant "%s"' % guess)

raise CommandError(' - '.join(msg))

return command, options, args, parser
return cmd_name, cmd_args


def main(initial_args=None):
Expand All @@ -138,15 +169,15 @@ def main(initial_args=None):
autocomplete()

try:
cmd_name, options, args, parser = parseopts(initial_args)
cmd_name, cmd_args = parseopts(initial_args)
except PipError:
e = sys.exc_info()[1]
sys.stderr.write("ERROR: %s" % e)
sys.stderr.write(os.linesep)
sys.exit(1)

command = commands[cmd_name](parser) # see baseparser.Command
return command.main(args[1:], options)
command = commands[cmd_name]()
return command.main(cmd_args)


def bootstrap():
Expand Down
51 changes: 13 additions & 38 deletions pip/basecommand.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import time
import optparse

from pip import cmdoptions
from pip.log import logger
from pip.download import urlopen
from pip.exceptions import (BadCommand, InstallationError, UninstallationError,
Expand All @@ -31,7 +32,7 @@ class Command(object):
usage = None
hidden = False

def __init__(self, main_parser):
def __init__(self):
parser_kw = {
'usage': self.usage,
'prog': '%s %s' % (get_prog(), self.name),
Expand All @@ -40,53 +41,27 @@ def __init__(self, main_parser):
'name': self.name,
'description': self.__doc__,
}
self.main_parser = main_parser

self.parser = ConfigOptionParser(**parser_kw)

# Commands should add options to this option group
optgroup_name = '%s Options' % self.name.capitalize()
self.cmd_opts = optparse.OptionGroup(self.parser, optgroup_name)

# Re-add all options and option groups.
for group in main_parser.option_groups:
self._copy_option_group(self.parser, group)

# Copies all general options from the main parser.
self._copy_options(self.parser, main_parser.option_list)

def _copy_options(self, parser, options):
"""Populate an option parser or group with options."""
for option in options:
if not option.dest:
continue
parser.add_option(option)

def _copy_option_group(self, parser, group):
"""Copy option group (including options) to another parser."""
new_group = optparse.OptionGroup(parser, group.title)
self._copy_options(new_group, group.option_list)

parser.add_option_group(new_group)

def merge_options(self, initial_options, options):
# Make sure we have all global options carried over
attrs = ['log', 'proxy', 'require_venv',
'log_explicit_levels', 'log_file',
'timeout', 'default_vcs',
'skip_requirements_regex',
'no_input', 'exists_action',
'cert']
for attr in attrs:
setattr(options, attr, getattr(initial_options, attr) or getattr(options, attr))
options.quiet += initial_options.quiet
options.verbose += initial_options.verbose
# Add the general options
gen_opts = cmdoptions.make_option_group(cmdoptions.general_group, self.parser)
self.parser.add_option_group(gen_opts)


def setup_logging(self):
pass

def main(self, args, initial_options):
options, args = self.parser.parse_args(args)
self.merge_options(initial_options, options)
def parse_args(self, args):
# factored out for testability
return self.parser.parse_args(args)

def main(self, args):
options, args = self.parse_args(args)

level = 1 # Notify
level += options.verbose
Expand Down
Loading