فهرست منبع

- Fixed a bug introduced in 3.0a7 where parsing a string of key/value
pairs failed on Python 2.3 due to use of regular expression syntax
introduced in Python 2.4.

Mike Naberezny 15 سال پیش
والد
کامیت
b1d2fb8aad
3فایلهای تغییر یافته به همراه32 افزوده شده و 20 حذف شده
  1. 4 0
      CHANGES.txt
  2. 11 19
      src/supervisor/datatypes.py
  3. 17 1
      src/supervisor/tests/test_datatypes.py

+ 4 - 0
CHANGES.txt

@@ -9,6 +9,10 @@ Next Release
   - Fixed a bug introduced in 3.0a7 where setup.py would not detect the
     Python version correctly.  Patch by Daniele Paolella.
 
+  - Fixed a bug introduced in 3.0a7 where parsing a string of key/value
+    pairs failed on Python 2.3 due to use of regular expression syntax
+    introduced in Python 2.4.
+
   - Removed the test suite for the ``memmon`` console script, which was 
     moved to the Superlance package in 3.0a7.
 

+ 11 - 19
src/supervisor/datatypes.py

@@ -16,6 +16,7 @@ import os
 import re
 import sys
 import socket
+import shlex
 from supervisor.loggers import getLevelNumByDescription
 
 # I dont know why we bother, this doesn't run on Windows, but just
@@ -79,30 +80,21 @@ def list_of_exitcodes(arg):
     except:
         raise ValueError("not a valid list of exit codes: " + repr(arg))
 
-# Regular expression to match key=value, key='value' or key="value" strings
-# Quoted values can allow commas, unquoted will not
-DICT_OF_KVP_REGEXP = re.compile(r"[ \t]*(?P<key>\w+)[ \t]*=[ \t]"
-                                r"*(?P<quote>['\"])?"
-                                r"(?P<value>.*?)(?(quote)['\"])[,$]")
-
 def dict_of_key_value_pairs(arg):
     """ parse KEY=val,KEY2=val2 into {'KEY':'val', 'KEY2':'val2'}
         Quotes can be used to allow commas in the value
     """
-    D = {}
-
-    if len(arg):
-        # Work-around non-greedy value match won't let the regexp parse
-        # the last key=value pair if value is not quoted
-        if arg[-1] != ',':
-            arg += ','
-
-        for key, quote, value in DICT_OF_KVP_REGEXP.findall(arg):
-            D[key] = value.strip()
-
-        if D == {}:
-            raise ValueError("not a list of key/value pairs: " + repr(arg))
+    tokens = list(shlex.shlex(arg))
+    tokens_len = len(tokens)
 
+    D = {}
+    i = 0
+    while i in range(0, tokens_len):   
+        k_eq_v = tokens[i:i+3]
+        if len(k_eq_v) != 3:
+            raise ValueError, "Unexpected end of key/value pairs"
+        D[k_eq_v[0]] = k_eq_v[2].strip('\'"')
+        i += 4
     return D
 
 class Automatic:

+ 17 - 1
src/supervisor/tests/test_datatypes.py

@@ -100,6 +100,11 @@ class DatatypesTest(unittest.TestCase):
         expected = {'foo': 'bar', 'baz': 'qux'}
         self.assertEqual(actual, expected)
 
+    def test_dict_of_key_value_pairs_returns_dict_even_if_newlines(self):
+        actual = datatypes.dict_of_key_value_pairs('foo\n=\nbar\n,\nbaz\n=\nqux')
+        expected = {'foo': 'bar', 'baz': 'qux'}
+        self.assertEqual(actual, expected)
+
     def test_dict_of_key_value_pairs_handles_commas_inside_apostrophes(self):
         actual = datatypes.dict_of_key_value_pairs("foo='bar,baz',baz='q,ux'")
         expected = {'foo': 'bar,baz', 'baz': 'q,ux'}
@@ -110,9 +115,20 @@ class DatatypesTest(unittest.TestCase):
         expected = {'foo': 'bar,baz', 'baz': 'q,ux'}
         self.assertEqual(actual, expected)
 
-    def test_dict_of_key_value_pairs_raises_value_error_on_weird_input(self):
+    def test_dict_of_key_value_pairs_allows_trailing_comma(self):
+        actual = datatypes.dict_of_key_value_pairs('foo=bar,')
+        expected = {'foo': 'bar'}
+        self.assertEqual(actual, expected)
+
+    def test_dict_of_key_value_pairs_raises_value_error_on_too_short(self):
         self.assertRaises(ValueError, 
                           datatypes.dict_of_key_value_pairs, 'foo')
+        self.assertRaises(ValueError, 
+                          datatypes.dict_of_key_value_pairs, 'foo=')
+        self.assertRaises(ValueError, 
+                          datatypes.dict_of_key_value_pairs, 'foo=bar,baz')
+        self.assertRaises(ValueError, 
+                          datatypes.dict_of_key_value_pairs, 'foo=bar,baz=')
 
     def test_logfile_name_returns_none_for_none_values(self):
         for thing in datatypes.LOGFILE_NONES: