/usr/lib/python2.7/dist-packages/qcli/option_parsing.py is in python-qcli 0.1.0-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 | #!/usr/bin/env python
""" Utilities for parsing command line options and arguments
This code was derived from PyCogent (www.pycogent.org) and QIIME
(www.qiime.org), where it was initally developed. It has been ported
to qcli to support accessing this functionality without those
dependencies.
"""
from copy import copy
import types
import sys
from optparse import (OptionParser, OptionGroup, Option,
OptionValueError, OptionError)
from os import popen, remove, makedirs, getenv
from os.path import join, abspath, exists, isdir, isfile, split
from glob import glob
__author__ = "Greg Caporaso, Gavin Huttley, Rob Knight, Daniel McDonald"
__copyright__ = "Copyright 2013, The BiPy Project"
__credits__ = ["Greg Caporaso",
"Daniel McDonald",
"Gavin Huttley",
"Rob Knight",
"Jose Antonio Navas Molina"]
__license__ = "GPL"
__version__ = "0.1.0"
__maintainer__ = "Greg Caporaso"
__email__ = "gregcaporaso@gmail.com"
## Definition of CogentOption option type, a subclass of Option that
## contains specific types for filepaths and directory paths. This
## will be particularly useful for graphical interfaces that make
## use of the script_info dictionary as they can then distinguish
## paths from ordinary strings
def check_existing_filepath(option, opt, value):
if not exists(value):
raise OptionValueError(
"option %s: file does not exist: %r" % (opt, value))
elif not isfile(value):
raise OptionValueError(
"option %s: not a regular file (can't be a directory!): %r" % (opt, value))
else:
return value
def check_existing_filepaths(option, opt, value):
paths = []
for v in value.split(','):
fps = glob(v)
if len(fps) == 0:
raise OptionValueError(
"No filepaths match pattern/name '%s'. "
"All patterns must be matched at least once." % v)
else:
paths.extend(fps)
values = []
for v in paths:
check_existing_filepath(option,opt,v)
values.append(v)
return values
def check_existing_dirpath(option, opt, value):
if not exists(value):
raise OptionValueError(
"option %s: directory does not exist: %r" % (opt, value))
elif not isdir(value):
raise OptionValueError(
"option %s: not a directory (can't be a file!): %r" % (opt, value))
else:
return value
def check_new_filepath(option, opt, value):
return value
def check_new_dirpath(option, opt, value):
return value
def check_existing_path(option, opt, value):
if not exists(value):
raise OptionValueError(
"option %s: path does not exist: %r" % (opt, value))
return value
def check_new_path(option, opt, value):
return value
def check_multiple_choice(option, opt, value):
#split_char = ';' if ';' in value else ','
values = value.split(option.split_char)
for v in values:
if v not in option.mchoices:
choices = ",".join(map(repr, option.mchoices))
raise OptionValueError(
"option %s: invalid choice: %r (choose from %s)"
% (opt, v, choices))
return values
def check_blast_db(option, opt, value):
db_dir, db_name = split(abspath(value))
if not exists(db_dir):
raise OptionValueError(
"option %s: path does not exists: %r" % (opt, db_dir))
elif not isdir(db_dir):
raise OptionValueError(
"option %s: not a directory: %r" % (opt, db_dir))
return value
class QcliOption(Option):
ATTRS = Option.ATTRS + ['mchoices','split_char']
TYPES = Option.TYPES + ("existing_path",
"new_path",
"existing_filepath",
"existing_filepaths",
"new_filepath",
"existing_dirpath",
"new_dirpath",
"multiple_choice",
"blast_db")
TYPE_CHECKER = copy(Option.TYPE_CHECKER)
# for cases where the user specifies an existing file or directory
# as input, but it can be either a dir or a file
TYPE_CHECKER["existing_path"] = check_existing_path
# for cases where the user specifies a new file or directory
# as output, but it can be either a dir or a file
TYPE_CHECKER["new_path"] = check_new_path
# for cases where the user passes a single existing file
TYPE_CHECKER["existing_filepath"] = check_existing_filepath
# for cases where the user passes one or more existing files
# as a comma-separated list - paths are returned as a list
TYPE_CHECKER["existing_filepaths"] = check_existing_filepaths
# for cases where the user is passing a new path to be
# create (e.g., an output file)
TYPE_CHECKER["new_filepath"] = check_new_filepath
# for cases where the user is passing an existing directory
# (e.g., containing a set of input files)
TYPE_CHECKER["existing_dirpath"] = check_existing_dirpath
# for cases where the user is passing a new directory to be
# create (e.g., an output dir which will contain many result files)
TYPE_CHECKER["new_dirpath"] = check_new_dirpath
# for cases where the user is passing one or more values
# as comma- or semicolon-separated list
# choices are returned as a list
TYPE_CHECKER["multiple_choice"] = check_multiple_choice
# for cases where the user is passing a blast database option
# blast_db is returned as a string
TYPE_CHECKER["blast_db"] = check_blast_db
def _check_multiple_choice(self):
if self.type == "multiple_choice":
if self.mchoices is None:
raise OptionError(
"must supply a list of mchoices for type '%s'" % self.type, self)
elif type(self.mchoices) not in (types.TupleType, types.ListType):
raise OptionError(
"choices must be a list of strings ('%s' supplied)"
% str(type(self.mchoices)).split("'")[1], self)
if self.split_char is None:
self.split_char = ','
elif self.mchoices is not None:
raise OptionError(
"must not supply mchoices for type %r" % self.type, self)
CHECK_METHODS = Option.CHECK_METHODS + [_check_multiple_choice]
# When this code was in PyCogent, the option object was called
# CogentOption, so leaving that name in place for backward compatibility.
make_option = CogentOption = QcliOption
## End definition of new option type
def build_usage_lines(required_options,
script_description,
script_usage,
optional_input_line,
required_input_line):
""" Build the usage string from components
"""
line1 = 'usage: %prog [options] ' + '{%s}' %\
' '.join(['%s %s' % (str(ro),ro.dest.upper())\
for ro in required_options])
usage_examples = []
for title, description, command in script_usage:
title = title.strip(':').strip()
description = description.strip(':').strip()
command = command.strip()
if title:
usage_examples.append('%s: %s\n %s' %\
(title,description,command))
else:
usage_examples.append('%s\n %s' % (description,command))
usage_examples = '\n\n'.join(usage_examples)
lines = (line1,
'', # Blank line
optional_input_line,
required_input_line,
'', # Blank line
script_description,
'', # Blank line
'Example usage: ',\
'Print help message and exit',
' %prog -h\n',
usage_examples)
return '\n'.join(lines)
def set_parameter(key,kwargs,default=None):
try:
return kwargs[key]
except KeyError:
return default
def set_required_parameter(key,kwargs):
try:
return kwargs[key]
except KeyError:
raise KeyError,\
"parse_command_line_parameters requires value for %s" % key
def parse_command_line_parameters(**kwargs):
""" Constructs the OptionParser object and parses command line arguments
parse_command_line_parameters takes a dict of objects via kwargs which
it uses to build command line interfaces according to standards
developed in the Knight Lab, and enforced in QIIME. The currently
supported options are listed below with their default values. If no
default is provided, the option is required.
script_description
script_usage = [("","","")]
version
required_options=None
optional_options=None
suppress_verbose=False
disallow_positional_arguments=True
help_on_no_arguments=True
optional_input_line = '[] indicates optional input (order unimportant)'
required_input_line = '{} indicates required input (order unimportant)'
These values can either be passed directly, as:
parse_command_line_parameters(script_description="My script",\
script_usage=[('Print help','%prog -h','')],\
version=1.0)
or they can be passed via a pre-constructed dict, as:
d = {'script_description':"My script",\
'script_usage':[('Print help','%prog -h','')],\
'version':1.0}
parse_command_line_parameters(**d)
"""
# Get the options, or defaults if none were provided.
script_description = set_required_parameter('script_description',kwargs)
version = set_required_parameter('version',kwargs)
script_usage = set_parameter('script_usage',kwargs,[("","","")])
required_options = set_parameter('required_options',kwargs,[])
optional_options = set_parameter('optional_options',kwargs,[])
suppress_verbose = set_parameter('suppress_verbose',kwargs,False)
disallow_positional_arguments =\
set_parameter('disallow_positional_arguments',kwargs,True)
help_on_no_arguments = set_parameter('help_on_no_arguments',kwargs,True)
optional_input_line = set_parameter('optional_input_line',kwargs,\
'[] indicates optional input (order unimportant)')
required_input_line = set_parameter('required_input_line',kwargs,\
'{} indicates required input (order unimportant)')
# command_line_text will usually be nothing, but can be passed for
# testing purposes
command_line_args = set_parameter('command_line_args',kwargs,None)
# Build the usage and version strings
usage = build_usage_lines(required_options,script_description,script_usage,\
optional_input_line,required_input_line)
version = 'Version: %prog ' + version
# Instantiate the command line parser object
parser = OptionParser(usage=usage, version=version)
parser.exit = set_parameter('exit_func',kwargs,parser.exit)
# If no arguments were provided, print the help string (unless the
# caller specified not to)
if help_on_no_arguments and (not command_line_args) and len(sys.argv) == 1:
parser.print_usage()
return parser.exit(-1)
# Process the required options
if required_options:
# Define an option group so all required options are
# grouped together, and under a common header
required = OptionGroup(parser, "REQUIRED options",
"The following options must be provided under all circumstances.")
for ro in required_options:
# if the option doesn't already end with [REQUIRED],
# add it.
if not ro.help.strip().endswith('[REQUIRED]'):
ro.help += ' [REQUIRED]'
required.add_option(ro)
parser.add_option_group(required)
# Add a verbose parameter (if the caller didn't specify not to)
if not suppress_verbose:
parser.add_option('-v','--verbose',action='store_true',\
dest='verbose',help='Print information during execution '+\
'-- useful for debugging [default: %default]',default=False)
# Add the optional options
map(parser.add_option,optional_options)
# Parse the command line
# command_line_text will None except in test cases, in which
# case sys.argv[1:] will be parsed
opts,args = parser.parse_args(command_line_args)
# If positional arguments are not allowed, and any were provided,
# raise an error.
if disallow_positional_arguments and len(args) != 0:
parser.error("Positional argument detected: %s\n" % str(args[0]) +\
" Be sure all parameters are identified by their option name.\n" +\
" (e.g.: include the '-i' in '-i INPUT_DIR')")
# Test that all required options were provided.
if required_options:
required_option_ids = [o.dest for o in required.option_list]
for required_option_id in required_option_ids:
if getattr(opts,required_option_id) == None:
return parser.error('Required option --%s omitted.' \
% required_option_id)
# Return the parser, the options, and the arguments. The parser is returned
# so users have access to any additional functionality they may want at
# this stage -- most commonly, it will be used for doing custom tests of
# parameter values.
return parser, opts, args
|