Author: laukpe
Date: Tue Nov 25 18:01:47 2008
New Revision: 1122

Modified:
   trunk/src/robot/utils/argumentparser.py
   trunk/utest/utils/test_argumentparser.py

Log:
1) Ignore options over 4 spaces from the beginning of line (no need to escape/unescape them anymore), 2) Allow also numbers (and pretty much everything else) as short opts, 3) Cleanup

Modified: trunk/src/robot/utils/argumentparser.py
==============================================================================
--- trunk/src/robot/utils/argumentparser.py     (original)
+++ trunk/src/robot/utils/argumentparser.py     Tue Nov 25 18:01:47 2008
@@ -38,25 +38,19 @@

 class ArgumentParser:

-    _short_opt_chars = '-?a-zA-Z'
-    _long_opt_chars = _short_opt_chars + '_0-9'
-    _value_chars = _long_opt_chars + '\.,=:|/<>*+!$@'
-
     _opt_line_re = re.compile('''
-    ^([%s ]*?)        # possible short options incl. spaces (group 1)
-    --([%s]{2,})      # required long option (group 2)
- ([%s ]*?) # possible value and/or '*' telling that option is allowed
-                      # multiple times (group 3)
-    (\s{2,}.*)?$      # rest of the option line
-    ''' % (_short_opt_chars, _long_opt_chars, _value_chars), re.VERBOSE)
+    ^\s{,4}       # max 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)
+ (\s\*)? # optional '*' telling option allowed multiple times (group 5)
+    ''', re.VERBOSE)

     _usage_line_re = re.compile('''
-    ^usage:           #
-    .*                #
-    \[options\]       #
-    \s+               #
-    (.*)              # arguments (group 1)
-    \s*$              #
+    ^usage:.*
+    \[options\]\s+
+    (.*)          # arguments (group 1)
+    \s*$
     ''', re.VERBOSE | re.IGNORECASE)

     def __init__(self, usage, version=None):
@@ -277,33 +271,29 @@

     def _parse_usage(self, usage):
         for line in usage.splitlines():
-            line = line.strip()
-            if line.startswith('-') and self._opt_line_re.match(line):
-                self._parse_opt_line(line)
-            elif self._usage_line_re.match(line):
-                self._parse_usage_line(line)
-
-    def _parse_usage_line(self, line):
-        res = self._usage_line_re.match(line)
-        self._expected_args = res.group(1).split()
+            res = self._opt_line_re.match(line)
+            if res:
+                self._parse_opt_line(res)
+                continue
+            res = self._usage_line_re.match(line)
+            if res:
+                self._expected_args = res.group(1).split()

-    def _parse_opt_line(self, line):
-        res = self._opt_line_re.match(line)
-        long_opt = res.group(2).lower()
+    def _parse_opt_line(self, res):
+        long_opt = res.group(3).lower()
         if long_opt in self._names:
             self._raise_option_multiple_times_in_usage('--' + long_opt)
         self._names.append(long_opt)
-        short_opts = self._parse_short_opts(res.group(1))
+        short_opts = [ opt[1] for opt in res.group(1).split() ]
         for sopt in short_opts:
             if self._short_to_long.has_key(sopt):
                 self._raise_option_multiple_times_in_usage('-' + sopt)
             self._short_to_long[sopt] = long_opt
-        _takes_value, _is_multi = self._process_value(res.group(3))
         # options allowed multiple times
-        if _is_multi:
+        if res.group(5):
             self._multi_opts.append(long_opt)
         # options with arguments
-        if _takes_value:
+        if res.group(4):
             long_opt += '='
             short_opts = [ sopt + ':' for sopt in short_opts ]
         else:
@@ -311,29 +301,6 @@
         self._long_opts.append(long_opt)
         self._short_opts += (''.join(short_opts))

-    def _process_value(self, valstr):
-        if valstr is None or valstr == '':
-            return False, False
-        tokens = valstr.split()
-        if len(tokens) == 1:
-            if tokens[0] == '*':
-                return False, True
-            else:
-                return True, False
-        if len(tokens) == 2:
-            if tokens[1] == '*':
-                return True, True
-        raise FrameworkError("Invalid option value '%s'" % valstr)
-
-    def _parse_short_opts(self, optstr):
-        if optstr is None: return []
-        return [ self._parse_short_opt(opt) for opt in optstr.split() ]
-
-    def _parse_short_opt(self, opt):
-        if len(opt) != 2 and opt[0] != '-':
-            raise FrameworkError("Invalid short option '%s'" % opt)
-        return opt[1]
-
     def _get_pythonpath(self, paths):
         if not is_list(paths):
             paths = [paths]

Modified: trunk/utest/utils/test_argumentparser.py
==============================================================================
--- trunk/utest/utils/test_argumentparser.py    (original)
+++ trunk/utest/utils/test_argumentparser.py    Tue Nov 25 18:01:47 2008
@@ -13,8 +13,8 @@
 Version: <VERSION>

 Options:
-  -d  --reportdir dir        Explanation
-  -r  --reportfile file      This explanation continues ............... 78
+  -d --reportdir dir        Explanation
+  -r --reportfile file      This explanation continues ............... 78
        ........... to multiple lines.
        Next line is totally empty.

@@ -29,7 +29,9 @@
   --z  No long option here either
   this line doesn't start with a '-' so not an --optionline
   -\\-option     escaped 1
-  -o -\\-option  escaped 2
+  -o -\\-option  escaped 2
+          --ignored  options cannot be this far
+          --ignored

 * denotes options that can be set multiple times
 """
@@ -38,9 +40,9 @@
 usage:  robot.py [options] arg1 arg2

 options:
-  -v     --variable name=value
-  -x     --var-able name=v1,v2   Explanation
-  --42
+  -v --variable name=value
+  -x --var-able name=v1,v2   Explanation
+  -3 --42
 """


@@ -62,6 +64,17 @@

     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
+1234567890
+--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='])

     def test_case_insensitive_long_options(self):
         ap = ArgumentParser(' -f --foo\n -B --BAR\n')

Reply via email to