5 new revisions:
Revision: 4326e4d0b8f1
Author: Pekka Klärck
Date: Mon Jan 30 06:41:57 2012
Log: ArgParser: 1) require options to be indented by at least one
space (ma...
http://code.google.com/p/robotframework/source/detail?r=4326e4d0b8f1
Revision: aa03bac5d7fd
Author: Pekka Klärck
Date: Mon Jan 30 07:32:52 2012
Log: ArgumentParser: Automatically consider --help, --version,
--pythonpath...
http://code.google.com/p/robotframework/source/detail?r=aa03bac5d7fd
Revision: 30b35797508e
Author: Pekka Klärck
Date: Mon Jan 30 08:28:51 2012
Log: ArgumentParser: allow passing name and default value for version
http://code.google.com/p/robotframework/source/detail?r=30b35797508e
Revision: 3bf7cb2e0793
Author: Pekka Klärck
Date: Mon Jan 30 08:54:41 2012
Log: initial skeleton for a generic command line app
http://code.google.com/p/robotframework/source/detail?r=3bf7cb2e0793
Revision: cf32c5f024bc
Author: Pekka Klärck
Date: Mon Jan 30 08:55:24 2012
Log: Automated merge with https://robotframework.googlecode.com/hg/
http://code.google.com/p/robotframework/source/detail?r=cf32c5f024bc
==============================================================================
Revision: 4326e4d0b8f1
Author: Pekka Klärck
Date: Mon Jan 30 06:41:57 2012
Log: ArgParser: 1) require options to be indented by at least one
space (max is still four), 2) test cleanup
http://code.google.com/p/robotframework/source/detail?r=4326e4d0b8f1
Modified:
/src/robot/utils/argumentparser.py
/utest/utils/test_argumentparser.py
=======================================
--- /src/robot/utils/argumentparser.py Sun Jan 29 12:57:25 2012
+++ /src/robot/utils/argumentparser.py Mon Jan 30 06:41:57 2012
@@ -39,7 +39,7 @@
class ArgumentParser:
_opt_line_re = re.compile('''
- ^\s{,4} # max 4 spaces in the beginning of the line
+ ^\s{1,4} # 1-4 spaces in the beginning of the line
((-\S\s)*) # all possible short options incl. spaces (group 1)
--(\S{2,}) # required long option (group 3)
(\s\S+)? # optional value (group 4)
=======================================
--- /utest/utils/test_argumentparser.py Tue Feb 1 06:01:38 2011
+++ /utest/utils/test_argumentparser.py Mon Jan 30 06:41:57 2012
@@ -55,26 +55,28 @@
assert_equals(self.ap._short_opts, 'd:r:E:v:N:h?')
def test_long_options(self):
- expected = [ 'reportdir=', 'reportfile=', 'escape=', 'variable=',
- 'name=', 'help', 'version' ]
+ expected = ['reportdir=', 'reportfile=', 'escape=', 'variable=',
+ 'name=', 'help', 'version']
assert_equals(self.ap._long_opts, expected)
def test_multi_options(self):
- assert_equals(self.ap._multi_opts, ['escape','variable'])
+ assert_equals(self.ap._multi_opts, ['escape', 'variable'])
def test_toggle_options(self):
- assert_equals(self.ap._toggle_opts, ['help','version'])
-
- def test_options_over_4_spaces_from_left_are_ignored(self):
- assert_equals(ArgumentParser('''Name
+ assert_equals(self.ap._toggle_opts, ['help', 'version'])
+
+ def test_options_must_be_indented_by_1_to_four_spaces(self):
+ ap = ArgumentParser('''Name
1234567890
---opt1
+--notin this option is not indented at all and thus ignored
+ --opt1
--opt2 This option is 4 spaces from left -> included
-o --opt3 argument It doesn't matter how far the option gets.
--notopt This option is 5 spaces from left -> not included
-i --ignored
--not-in-either
- ''')._long_opts, ['opt1', 'opt2', 'opt3='])
+ --included back in four space indentation''')
+ assert_equals(ap._long_opts, ['opt1', 'opt2', 'opt3=', 'included'])
def test_case_insensitive_long_options(self):
ap = ArgumentParser(' -f --foo\n -B --BAR\n')
@@ -82,10 +84,10 @@
assert_equals(ap._long_opts, ['foo','bar'])
def test_same_option_multiple_times(self):
- for my_usage in [ ' --foo\n --foo\n',
+ for my_usage in [' --foo\n --foo\n',
' --foo\n -f --Foo\n',
' -x --foo xxx\n -y --Foo yyy\n',
- ' -f --foo\n -f --bar\n' ]:
+ ' -f --foo\n -f --bar\n']:
assert_raises(FrameworkError, ArgumentParser, my_usage)
ap = ArgumentParser(' -f --foo\n -F --bar\n')
assert_equals(ap._short_opts, 'fF')
@@ -103,37 +105,32 @@
def test_single_options(self):
inargs = '-d reports --reportfile report.html -? arg'.split()
- exp_opts = {'reportdir':'reports', 'reportfile':'report.html',
- 'variable':[], 'name':None, 'escape' : [],
- 'help':True, 'version':False }
- exp_args = [ 'arg' ]
opts, args = self.ap.parse_args(inargs)
- assert_equals(opts, exp_opts)
- assert_equals(args, exp_args)
+ assert_equals(opts,
{'reportdir':'reports', 'reportfile':'report.html',
+ 'variable':[], 'name':None, 'escape' : [],
+ 'help':True, 'version':False})
def test_multi_options(self):
inargs = '-v a:1 -v b:2 --name my_name --variable c:3 arg'.split()
- exp_opts = {'variable':['a:1','b:2','c:3'], 'name':'my_name',
- 'reportdir':None, 'reportfile':None, 'escape' : [],
- 'help':False, 'version':False }
- exp_args = [ 'arg' ]
opts, args = self.ap.parse_args(inargs)
- assert_equals(opts, exp_opts)
- assert_equals(args, exp_args)
+ assert_equals(opts,
{'variable':['a:1','b:2','c:3'], 'name':'my_name',
+ 'reportdir':None, 'reportfile':None, 'escape' :
[],
+ 'help':False, 'version':False})
+ assert_equals(args, ['arg'])
def test_toggle_options(self):
- for inargs, exp in [ ('arg', False),
- ('--help arg', True),
- ('--help --name whatever -h arg', False),
- ('-? -h --help arg', True) ]:
+ for inargs, exp in [('arg', False),
+ ('--help arg', True),
+ ('--help --name whatever -h arg', False),
+ ('-? -h --help arg', True)]:
opts, args = self.ap.parse_args(inargs.split())
assert_equals(opts['help'], exp)
assert_equals(args, ['arg'])
def test_single_option_multiple_times(self):
- for inargs in [ '--name Foo -N Bar arg',
- '-N Zap --name Foo --name Bar arg',
- '-N 1 -N 2 -N 3 -h --variable foo -N 4 --name Bar
arg' ]:
+ for inargs in ['--name Foo -N Bar arg',
+ '-N Zap --name Foo --name Bar arg',
+ '-N 1 -N 2 -N 3 -h --variable foo -N 4 --name Bar
arg']:
opts, args = self.ap.parse_args(inargs.split())
assert_equals(opts['name'], 'Bar')
assert_equals(args, ['arg'])
@@ -149,21 +146,12 @@
assert_equals(opts['escape'], ['X:y', 'ZZ'])
assert_equals(args, [])
- def test_non_ascii_chars(self):
- ap = ArgumentParser(USAGE2)
- inargs = '-x foo=bar --variable a=1,2,3 arg1 arg2'.split()
- exp_opts = {'var-able':'foo=bar', 'variable':'a=1,2,3', '42':
False}
- exp_args = ['arg1', 'arg2']
- opts, args = ap.parse_args(inargs)
- assert_equals(opts, exp_opts)
- assert_equals(args, exp_args)
-
def test_check_args_with_correct_args(self):
- for args in [ ('hello',), ('hello world',) ]:
- self.ap.parse_args(args, check_args=True)
+ for arg in ['hello', 'hello world']:
+ self.ap.parse_args([arg], check_args=True)
def test_check_args_with_wrong_number_of_args(self):
- for args in [ (), ('arg1','arg2','arg3') ]:
+ for args in [(), ('arg1', 'arg2', 'arg3')]:
assert_raises(DataError, self.ap._check_args, args)
def test_check_variable_number_of_args(self):
@@ -189,7 +177,6 @@
assert_raises(FrameworkError, ArgumentParser('test').parse_args,
[], check_args=True)
-
def test_unescape_options(self):
cli = '--escape quot:Q -E space:SP -E lt:LT -E gt:GT ' \
+ '-N QQQLTmySPfineSPnameGTQQQ sourceSPwithSPspaces'
@@ -200,16 +187,16 @@
def test_split_pythonpath(self):
ap = ArgumentParser('ignored')
- data = [ (['path'], ['path']),
- (['path1','path2'], ['path1','path2']),
- (['path1:path2'], ['path1','path2']),
- (['p1:p2:p3','p4','.'], ['p1','p2','p3','p4','.']) ]
+ data = [(['path'], ['path']),
+ (['path1','path2'], ['path1','path2']),
+ (['path1:path2'], ['path1','path2']),
+ (['p1:p2:p3','p4','.'], ['p1','p2','p3','p4','.'])]
if os.sep == '\\':
- data += [ (['c:\\path'], ['c:\\path']),
- (['c:\\path','d:\\path'], ['c:\\path','d:\\path']),
- (['c:\\path:d:\\path'], ['c:\\path','d:\\path']),
- (['c:/path:x:yy:d:\\path','c','.','x:/xxx'],
-
['c:\\path', 'x', 'yy', 'd:\\path', 'c', '.', 'x:\\xxx']) ]
+ data += [(['c:\\path'], ['c:\\path']),
+ (['c:\\path','d:\\path'], ['c:\\path','d:\\path']),
+ (['c:\\path:d:\\path'], ['c:\\path','d:\\path']),
+ (['c:/path:x:yy:d:\\path','c','.','x:/xxx'],
+
['c:\\path', 'x', 'yy', 'd:\\path', 'c', '.', 'x:\\xxx'])]
for inp, exp in data:
assert_equals(ap._split_pythonpath(inp), exp)
==============================================================================
Revision: aa03bac5d7fd
Author: Pekka Klärck
Date: Mon Jan 30 07:32:52 2012
Log: ArgumentParser: Automatically consider --help, --version,
--pythonpath, --escape, and --argumentfile special when they are used. This
considerably eases configuring ap.parse_args().
http://code.google.com/p/robotframework/source/detail?r=aa03bac5d7fd
Modified:
/src/robot/__init__.py
/src/robot/tidy.py
/src/robot/utils/argumentparser.py
/utest/utils/test_argumentparser.py
=======================================
--- /src/robot/__init__.py Sun Jan 29 13:32:23 2012
+++ /src/robot/__init__.py Mon Jan 30 07:32:52 2012
@@ -17,7 +17,7 @@
if 'pythonpathsetter' not in sys.modules:
from robot import pythonpathsetter
if sys.platform.startswith('java'):
- from robot import jythonworkarounds
+ from robot import jythonworkarounds
from robot.conf import RobotSettings, RebotSettings
from robot.errors import (DataError, Information, INFO_PRINTED, DATA_ERROR,
STOPPED_BY_USER, FRAMEWORK_ERROR)
@@ -34,17 +34,16 @@
def run_from_cli(args, usage):
LOGGER.info(get_full_version('Robot Framework'))
- return _run_or_rebot_from_cli(run, args, usage,
pythonpath='pythonpath')
+ return _run_or_rebot_from_cli(run, args, usage)
def rebot_from_cli(args, usage):
LOGGER.info(get_full_version('Rebot'))
return _run_or_rebot_from_cli(rebot, args, usage)
-def _run_or_rebot_from_cli(method, cliargs, usage, **argparser_config):
+def _run_or_rebot_from_cli(method, cliargs, usage):
LOGGER.register_file_logger()
try:
- options, datasources = _parse_arguments(cliargs, usage,
- **argparser_config)
+ options, datasources = _parse_arguments(cliargs, usage)
except Information, msg:
print utils.encode_output(unicode(msg))
return INFO_PRINTED
@@ -54,11 +53,9 @@
LOGGER.info('Data sources: %s' % utils.seq2str(datasources))
return method(*datasources, **options)
-def _parse_arguments(cliargs, usage, **argparser_config):
+def _parse_arguments(cliargs, usage):
ap = utils.ArgumentParser(usage, get_full_version())
- return ap.parse_args(cliargs, argfile='argumentfile',
unescape='escape',
- help='help', version='version', check_args=True,
- **argparser_config)
+ return ap.parse_args(cliargs, check_args=True)
def _execute(method, datasources, options):
try:
=======================================
--- /src/robot/tidy.py Sun Jan 29 12:49:51 2012
+++ /src/robot/tidy.py Mon Jan 30 07:32:52 2012
@@ -160,7 +160,7 @@
return tidy.file(inputs[0])
def _parse_args(self, args):
- options, sources = self._parser.parse_args(args, help='help')
+ options, sources = self._parser.parse_args(args)
if options['inplace'] and options['recursive']:
raise DataError('--recursive and --inplace can not be used
together.')
if not options['inplace'] and len(sources) > 1:
=======================================
--- /src/robot/utils/argumentparser.py Mon Jan 30 06:41:57 2012
+++ /src/robot/utils/argumentparser.py Mon Jan 30 07:32:52 2012
@@ -73,8 +73,7 @@
self._expected_args = ()
self._parse_usage(usage)
- def parse_args(self, args_list, unescape=None, argfile=None,
pythonpath=None,
- help=None, version=None, check_args=False):
+ def parse_args(self, args_list, check_args=False):
"""Parse given arguments and return options and positional
arguments.
Arguments must be given as a list and are typically sys.argv[1:].
@@ -89,54 +88,47 @@
Positional arguments are returned as a list in the order they are
given.
- 'unescape' option can be used to automatically unescape problematic
- characters given in an escaped format. Given value must be the
name of
- the long option used for escaping. Typically usage is having
- '--escape name:value *' in usage doc and
specifying 'enescape="escape"'
- when calling this method.
-
- 'argfile' can be used to automatically read arguments from
specified
- file. Given value must be the name of the long option used for
giving
- the argument file. Typical usage is '--argumentfile path *' in
usage doc
- and calling this method with 'argfile="argumentfile"'.
If 'argfile' is
- used, it can always be given multiple times and thus it is
recommended
- to use '*' to denote that. Special value 'stdin' can be used to
read
- arguments from stdin instead of a file.
-
- 'pythonpath' can be used to specify option(s) containing extra
paths to
- be added into 'sys.path'. Value can be either a string containing
the
- name of the long option used for this purpose or a list containing
- all such long options (i.e. the latter format allows aliases).
-
- 'help' and 'version' make it possible to automatically generate
help
- and version messages. Version is generated based on the tool name
- and version -- see __init__ for information how to set them. Help
- contains the whole usage given to __init__. Possible <VERSION> text
- in the usage is replaced with the given version. Possible
<--ESCAPES-->
- is replaced with available escapes so that they are wrapped to
multiple
- lines but take the same amount of horizontal space as
<---ESCAPES--->.
- The numer of hyphens can be used to contrl the horizontal space.
Both
- help and version are wrapped to Information exception.
-
If 'check_args' is True, this method will automatically check that
correct number of arguments, as parsed from the usage line, are
given.
If the last argument in the usage line ends with the character 's',
the maximum number of arguments is infinite.
Possible errors in processing arguments are reported using
DataError.
+
+ Some options have a special meaning and are handled automatically
+ if defined in the usage and given from the command line:
+
+ --escape option can be used to automatically unescape problematic
+ characters given in an escaped format.
+
+ --argumentfile can be used to automatically read arguments from
+ a specified file. When --argumentfile is used, the parser always
+ allows using it multiple times. Adding '*' to denote that is thus
+ recommend. A special value 'stdin' can be used to read arguments
from
+ stdin instead of a file.
+
+ --pythonpath can be used to add extra path(s) to sys.path.
+
+ --help and --version automatically generate help and version
messages.
+ Version is generated based on the tool name and version -- see
__init__
+ for information how to set them. Help contains the whole usage
given to
+ __init__. Possible <VERSION> text in the usage is replaced with the
+ given version. Possible <--ESCAPES--> is replaced with available
+ escapes so that they are wrapped to multiple lines but take the
same
+ amount of horizontal space as <---ESCAPES--->. Both help and
version
+ are wrapped to Information exception.
"""
args_list = [decode_from_file_system(a) for a in args_list]
- if argfile:
- args_list = self._add_args_from_file(args_list, argfile)
+ args_list = self._process_possible_argfile(args_list)
opts, args = self._parse_args(args_list)
- if unescape:
- opts, args = self._unescape_opts_and_args(opts, args, unescape)
- if help and opts[help]:
+ if opts.get('escape'):
+ opts, args = self._unescape_opts_and_args(opts, args)
+ if opts.get('help'):
self._raise_help()
- if version and opts[version]:
+ if opts.get('version'):
self._raise_version()
- if pythonpath:
- sys.path = self._get_pythonpath(opts[pythonpath]) + sys.path
+ if opts.get('pythonpath'):
+ sys.path = self._get_pythonpath(opts['pythonpath']) + sys.path
if check_args:
self._check_args(args)
return opts, args
@@ -172,21 +164,21 @@
exptxt = "at least %d argument%s" % (minargs, minend)
raise DataError("Expected %s, got %d." % (exptxt, len(args)))
- def _unescape_opts_and_args(self, opts, args, escape_opt):
+ def _unescape_opts_and_args(self, opts, args):
try:
- escape_strings = opts[escape_opt]
+ escape_strings = opts['escape']
except KeyError:
- raise FrameworkError("No escape option '%s' in given options")
+ raise FrameworkError("No 'escape' in options")
escapes = self._get_escapes(escape_strings)
for name, value in opts.items():
- if name != escape_opt:
+ if name != 'escape':
opts[name] = self._unescape(value, escapes)
return opts, [self._unescape(arg, escapes) for arg in args]
- def _add_args_from_file(self, args, argfile_opt):
- argfile_opts = ['--'+argfile_opt]
+ def _process_possible_argfile(self, args):
+ argfile_opts = ['--argumentfile']
for sopt, lopt in self._short_to_long.items():
- if lopt == argfile_opt:
+ if lopt == 'argumentfile':
argfile_opts.append('-'+sopt)
while True:
try:
=======================================
--- /utest/utils/test_argumentparser.py Mon Jan 30 06:41:57 2012
+++ /utest/utils/test_argumentparser.py Mon Jan 30 07:32:52 2012
@@ -22,6 +22,7 @@
nothing after value and next nothing after option name
-v --variable name:value *
-N --name name
+ -t -T --toggle Something
-h -? --help
--version Explanation
@@ -43,6 +44,7 @@
-v --variable name=value
-x --var-able name=v1,v2 Explanation
-3 --42
+ --help
"""
@@ -52,18 +54,18 @@
self.ap = ArgumentParser(USAGE)
def test_short_options(self):
- assert_equals(self.ap._short_opts, 'd:r:E:v:N:h?')
+ assert_equals(self.ap._short_opts, 'd:r:E:v:N:tTh?')
def test_long_options(self):
expected = ['reportdir=', 'reportfile=', 'escape=', 'variable=',
- 'name=', 'help', 'version']
+ 'name=', 'toggle', 'help', 'version']
assert_equals(self.ap._long_opts, expected)
def test_multi_options(self):
assert_equals(self.ap._multi_opts, ['escape', 'variable'])
def test_toggle_options(self):
- assert_equals(self.ap._toggle_opts, ['help', 'version'])
+ assert_equals(self.ap._toggle_opts, ['toggle', 'help', 'version'])
def test_options_must_be_indented_by_1_to_four_spaces(self):
ap = ArgumentParser('''Name
@@ -101,49 +103,49 @@
def test_missing_argument_file_throws_data_error(self):
inargs = '--argumentfile
missing_argument_file_that_really_is_not_there.txt'.split()
- self.assertRaises(DataError, self.ap.parse_args, inargs,
argfile='argumentfile')
+ self.assertRaises(DataError, self.ap.parse_args, inargs)
def test_single_options(self):
- inargs = '-d reports --reportfile report.html -? arg'.split()
+ inargs = '-d reports --reportfile report.html -T arg'.split()
opts, args = self.ap.parse_args(inargs)
assert_equals(opts,
{'reportdir':'reports', 'reportfile':'report.html',
- 'variable':[], 'name':None, 'escape' : [],
- 'help':True, 'version':False})
+ 'variable':[], 'name':None, 'escape':[],
+ 'toggle':True, 'help':False, 'version':False})
def test_multi_options(self):
inargs = '-v a:1 -v b:2 --name my_name --variable c:3 arg'.split()
opts, args = self.ap.parse_args(inargs)
assert_equals(opts,
{'variable':['a:1','b:2','c:3'], 'name':'my_name',
- 'reportdir':None, 'reportfile':None, 'escape' :
[],
- 'help':False, 'version':False})
+ 'reportdir':None, 'reportfile':None, 'escape':[],
+ 'toggle':False, 'help':False, 'version':False})
assert_equals(args, ['arg'])
def test_toggle_options(self):
for inargs, exp in [('arg', False),
- ('--help arg', True),
- ('--help --name whatever -h arg', False),
- ('-? -h --help arg', True)]:
+ ('--toggle arg', True),
+ ('--toggle --name whatever -t arg', False),
+ ('-t -T --toggle arg', True)]:
opts, args = self.ap.parse_args(inargs.split())
- assert_equals(opts['help'], exp)
+ assert_equals(opts['toggle'], exp)
assert_equals(args, ['arg'])
def test_single_option_multiple_times(self):
for inargs in ['--name Foo -N Bar arg',
'-N Zap --name Foo --name Bar arg',
- '-N 1 -N 2 -N 3 -h --variable foo -N 4 --name Bar
arg']:
+ '-N 1 -N 2 -N 3 -t --variable foo -N 4 --name Bar
arg']:
opts, args = self.ap.parse_args(inargs.split())
assert_equals(opts['name'], 'Bar')
assert_equals(args, ['arg'])
def test_case_insensitive_long_options(self):
- opts, args = self.ap.parse_args('--EsCape X:y --HELP arg'.split())
- assert_equals(opts['escape'], ['X:y'])
- assert_equals(opts['help'], True)
+ opts, args = self.ap.parse_args('--VarIable X:y --TOGGLE
arg'.split())
+ assert_equals(opts['variable'], ['X:y'])
+ assert_equals(opts['toggle'], True)
assert_equals(args, ['arg'])
def test_case_insensitive_long_options_with_equal_sign(self):
- opts, args = self.ap.parse_args('--EsCape=X:y --escAPE=ZZ'.split())
- assert_equals(opts['escape'], ['X:y', 'ZZ'])
+ opts, args = self.ap.parse_args('--VariAble=X:y
--VARIABLE=ZzZ'.split())
+ assert_equals(opts['variable'], ['X:y', 'ZzZ'])
assert_equals(args, [])
def test_check_args_with_correct_args(self):
@@ -180,7 +182,7 @@
def test_unescape_options(self):
cli = '--escape quot:Q -E space:SP -E lt:LT -E gt:GT ' \
+ '-N QQQLTmySPfineSPnameGTQQQ sourceSPwithSPspaces'
- opts, args = self.ap.parse_args(cli.split(), unescape='escape');
+ opts, args = self.ap.parse_args(cli.split())
assert_equals(opts['name'], '"""<my fine name>"""')
assert_equals(opts['escape'],
['quot:Q','space:SP','lt:LT','gt:GT'])
assert_equals(args, ['source with spaces'])
@@ -230,7 +232,7 @@
def test_print_help(self):
assert_raises_with_msg(Information, USAGE2,
- self.ap2.parse_args, ['--42'], help='42')
+ self.ap2.parse_args, ['--help'])
def test_name_is_got_from_first_line_of_the_usage(self):
assert_equals(self.ap._name, 'Example Tool')
@@ -238,21 +240,22 @@
def test_print_version(self):
assert_raises_with_msg(Information, 'Example Tool 1.0 alpha',
- self.ap.parse_args, ['--version'],
version='version')
+ self.ap.parse_args, ['--version'])
def test_print_version_when_version_not_set(self):
- assert_raises(FrameworkError, self.ap2.parse_args, ['--42', '-x
a'], version='42')
+ ap = ArgumentParser(' --version')
+ assert_raises(FrameworkError, ap.parse_args, ['--version'])
def test_version_is_replaced_in_help(self):
assert_raises_with_msg(Information,
USAGE.replace('<VERSION>', '1.0 alpha'),
- self.ap.parse_args, ['--help'], help='help')
+ self.ap.parse_args, ['--help'])
def test_escapes_are_replaced_in_help(self):
usage = """Name
--escape x:y blaa
blaa .............................................. end
<-----------------------ESCAPES---------------------------->
-- next line --
- --he"""
+ --help"""
expected = """Name
--escape x:y blaa
blaa .............................................. end
Available escapes: amp (&), apos ('), at (@), bslash
(\),
@@ -261,9 +264,9 @@
()), percent (%), pipe (|), quest (?), quot ("), semic
(;),
slash (/), space ( ), square1 ([), square2 (]), star (*)
-- next line --
- --he"""
+ --help"""
assert_raises_with_msg(Information, expected,
- ArgumentParser(usage).parse_args, ['--he'],
help='he')
+ ArgumentParser(usage).parse_args,
['--help'])
if __name__ == "__main__":
==============================================================================
Revision: 30b35797508e
Author: Pekka Klärck
Date: Mon Jan 30 08:28:51 2012
Log: ArgumentParser: allow passing name and default value for version
http://code.google.com/p/robotframework/source/detail?r=30b35797508e
Modified:
/src/robot/utils/argumentparser.py
/utest/utils/test_argumentparser.py
=======================================
--- /src/robot/utils/argumentparser.py Mon Jan 30 07:32:52 2012
+++ /src/robot/utils/argumentparser.py Mon Jan 30 08:28:51 2012
@@ -23,6 +23,7 @@
import textwrap
from robot.errors import DataError, Information, FrameworkError
+from robot.version import get_full_version
from misc import plural_or_not
from encoding import decode_output, decode_from_file_system
@@ -52,7 +53,7 @@
\s*$
''', re.VERBOSE | re.IGNORECASE)
- def __init__(self, usage, version=None, arg_limits=None):
+ def __init__(self, usage, name=None, version=None, arg_limits=None):
"""Available options and tool name are read from the usage.
Tool name is got from the first row of the usage. It is either the
@@ -60,9 +61,9 @@
"""
if not usage:
raise FrameworkError('Usage cannot be empty')
+ self.name = name or usage.splitlines()[0].split(' -- ')[0].strip()
+ self.version = version or get_full_version()
self._usage = usage
- self._name = usage.splitlines()[0].split(' -- ')[0].strip()
- self._version = version
self._arg_limits = arg_limits
self._short_opts = ''
self._long_opts = []
@@ -367,8 +368,8 @@
def _raise_help(self):
msg = self._usage
- if self._version:
- msg = msg.replace('<VERSION>', self._version)
+ if self.version:
+ msg = msg.replace('<VERSION>', self.version)
def replace_escapes(res):
escapes = 'Available escapes: ' + self._get_available_escapes()
lines = textwrap.wrap(escapes, width=len(res.group(2)))
@@ -378,9 +379,7 @@
raise Information(msg)
def _raise_version(self):
- if not self._version:
- raise FrameworkError('Version not set')
- raise Information('%s %s' % (self._name, self._version))
+ raise Information('%s %s' % (self.name, self.version))
def _raise_option_multiple_times_in_usage(self, opt):
raise FrameworkError("Option '%s' multiple times in usage" % opt)
=======================================
--- /utest/utils/test_argumentparser.py Mon Jan 30 07:32:52 2012
+++ /utest/utils/test_argumentparser.py Mon Jan 30 08:28:51 2012
@@ -4,6 +4,7 @@
from robot.utils.argumentparser import ArgumentParser
from robot.utils.asserts import *
from robot.errors import Information, DataError, FrameworkError
+from robot.version import get_full_version
USAGE = """Example Tool -- Stuff before hyphens is considered name
@@ -235,16 +236,22 @@
self.ap2.parse_args, ['--help'])
def test_name_is_got_from_first_line_of_the_usage(self):
- assert_equals(self.ap._name, 'Example Tool')
- assert_equals(self.ap2._name, 'Just Name Here')
+ assert_equals(self.ap.name, 'Example Tool')
+ assert_equals(self.ap2.name, 'Just Name Here')
+
+ def test_name_and_version_can_be_given(self):
+ ap = ArgumentParser(USAGE, name='Kakkonen', version='2')
+ assert_equals(ap.name, 'Kakkonen')
+ assert_equals(ap.version, '2')
def test_print_version(self):
assert_raises_with_msg(Information, 'Example Tool 1.0 alpha',
self.ap.parse_args, ['--version'])
def test_print_version_when_version_not_set(self):
- ap = ArgumentParser(' --version')
- assert_raises(FrameworkError, ap.parse_args, ['--version'])
+ ap = ArgumentParser(' --version', name='Kekkonen')
+ msg = assert_raises(Information, ap.parse_args, ['--version'])
+ assert_equals(unicode(msg), 'Kekkonen %s' % get_full_version())
def test_version_is_replaced_in_help(self):
assert_raises_with_msg(Information,
USAGE.replace('<VERSION>', '1.0 alpha'),
==============================================================================
Revision: 3bf7cb2e0793
Author: Pekka Klärck
Date: Mon Jan 30 08:54:41 2012
Log: initial skeleton for a generic command line app
http://code.google.com/p/robotframework/source/detail?r=3bf7cb2e0793
Added:
/src/robot/cliapp.py
=======================================
--- /dev/null
+++ /src/robot/cliapp.py Mon Jan 30 08:54:41 2012
@@ -0,0 +1,79 @@
+# Copyright 2008-2011 Nokia Siemens Networks Oyj
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+from robot.output import LOGGER
+from robot import utils
+from robot.errors import (INFO_PRINTED, DATA_ERROR, STOPPED_BY_USER,
+ FRAMEWORK_ERROR, Information, DataError)
+
+
+class CommandLineApplication(object):
+
+ def __init__(self, usage, name=None, version=None, arg_limits=None):
+ self._ap = utils.ArgumentParser(usage, name, version, arg_limits)
+ LOGGER.register_file_logger()
+ LOGGER.info('%s %s' % (self.name, self.version))
+
+ @property
+ def name(self):
+ return self._ap.name
+
+ @property
+ def version(self):
+ return self._ap.version
+
+ def parse_arguments(self, cli_args, check_args=True):
+ try:
+ options, arguments = self._ap.parse_args(cli_args, check_args)
+ except Information, msg:
+ self._report_info_and_exit(unicode(msg))
+ except DataError, err:
+ self._report_error_and_exit(unicode(err), help=True)
+ else:
+ LOGGER.info('Arguments: %s' % utils.seq2str(arguments))
+ return options, arguments
+
+ def execute(self, method, options, arguments):
+ try:
+ rc = method(*arguments, **options)
+ except DataError, err:
+ self._report_error_and_exit(unicode(err), help=True)
+ except (KeyboardInterrupt, SystemExit):
+ self._report_error_and_exit('Execution stopped by user.',
+ rc=STOPPED_BY_USER)
+ except:
+ error, details = utils.get_error_details()
+ self._report_error_and_exit('Unexpected error: %s' % error,
+ details, rc=FRAMEWORK_ERROR)
+ else:
+ return rc
+
+ def _report_info_and_exit(self, msg):
+ print utils.encode_output(unicode(msg))
+ self.exit(INFO_PRINTED)
+
+ def _report_error_and_exit(self, message, details=None, help=False,
+ rc=DATA_ERROR):
+ if help:
+ message += '\n\nTry --help for usage information.'
+ if details:
+ message += '\n' + details
+ LOGGER.error(message)
+ self.exit(rc)
+
+ def exit(self, rc):
+ LOGGER.close()
+ sys.exit(rc)
==============================================================================
Revision: cf32c5f024bc
Author: Pekka Klärck
Date: Mon Jan 30 08:55:24 2012
Log: Automated merge with https://robotframework.googlecode.com/hg/
http://code.google.com/p/robotframework/source/detail?r=cf32c5f024bc