gh-103384: Generalize the regex pattern BaseConfigurator.INDEX_PATTERN to allow spaces and non-alphanumeric characters in keys. (GH-103391)

Co-authored-by: Vinay Sajip <vinay_sajip@yahoo.co.uk>
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
Co-authored-by: Erlend E. Aasland <erlend@python.org>
This commit is contained in:
Peeyush Aggarwal 2023-08-25 13:45:26 +05:30 committed by GitHub
parent 135098743a
commit 8d4052075e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 51 additions and 3 deletions

View file

@ -685,7 +685,8 @@ resolve to ``'dev_team@domain.tld'`` and the string
``'support_team@domain.tld'``. The ``subject`` value could be accessed
using either ``'cfg://handlers.email.subject'`` or, equivalently,
``'cfg://handlers.email[subject]'``. The latter form only needs to be
used if the key contains spaces or non-alphanumeric characters. If an
used if the key contains spaces or non-alphanumeric characters. Please note
that the characters ``[`` and ``]`` are not allowed in the keys. If an
index value consists only of decimal digits, access will be attempted
using the corresponding integer value, falling back to the string
value if needed.

View file

@ -378,7 +378,7 @@ class BaseConfigurator(object):
WORD_PATTERN = re.compile(r'^\s*(\w+)\s*')
DOT_PATTERN = re.compile(r'^\.\s*(\w+)\s*')
INDEX_PATTERN = re.compile(r'^\[\s*(\w+)\s*\]\s*')
INDEX_PATTERN = re.compile(r'^\[([^\[\]]*)\]\s*')
DIGIT_PATTERN = re.compile(r'^\d+$')
value_converters = {

View file

@ -3662,7 +3662,28 @@ def test_baseconfig(self):
d = {
'atuple': (1, 2, 3),
'alist': ['a', 'b', 'c'],
'adict': {'d': 'e', 'f': 3 },
'adict': {
'd': 'e', 'f': 3 ,
'alpha numeric 1 with spaces' : 5,
'aplha numeric 1 %( - © ©ß¯' : 9,
'alpha numeric ] 1 with spaces' : 15,
'aplha ]] numeric 1 %( - © ©ß¯]' : 19,
' aplha [ numeric 1 %( - © ©ß¯] ' : 11,
' aplha ' : 32,
'' : 10,
'nest4' : {
'd': 'e', 'f': 3 ,
'alpha numeric 1 with spaces' : 5,
'aplha numeric 1 %( - © ©ß¯' : 9,
'' : 10,
'somelist' : ('g', ('h', 'i'), 'j'),
'somedict' : {
'a' : 1,
'a with 1 and space' : 3,
'a with ( and space' : 4,
}
}
},
'nest1': ('g', ('h', 'i'), 'j'),
'nest2': ['k', ['l', 'm'], 'n'],
'nest3': ['o', 'cfg://alist', 'p'],
@ -3674,11 +3695,36 @@ def test_baseconfig(self):
self.assertEqual(bc.convert('cfg://nest2[1][1]'), 'm')
self.assertEqual(bc.convert('cfg://adict.d'), 'e')
self.assertEqual(bc.convert('cfg://adict[f]'), 3)
self.assertEqual(bc.convert('cfg://adict[alpha numeric 1 with spaces]'), 5)
self.assertEqual(bc.convert('cfg://adict[aplha numeric 1 %( - © ©ß¯]'), 9)
self.assertEqual(bc.convert('cfg://adict[]'), 10)
self.assertEqual(bc.convert('cfg://adict.nest4.d'), 'e')
self.assertEqual(bc.convert('cfg://adict.nest4[d]'), 'e')
self.assertEqual(bc.convert('cfg://adict[nest4].d'), 'e')
self.assertEqual(bc.convert('cfg://adict[nest4][f]'), 3)
self.assertEqual(bc.convert('cfg://adict[nest4][alpha numeric 1 with spaces]'), 5)
self.assertEqual(bc.convert('cfg://adict[nest4][aplha numeric 1 %( - © ©ß¯]'), 9)
self.assertEqual(bc.convert('cfg://adict[nest4][]'), 10)
self.assertEqual(bc.convert('cfg://adict[nest4][somelist][0]'), 'g')
self.assertEqual(bc.convert('cfg://adict[nest4][somelist][1][0]'), 'h')
self.assertEqual(bc.convert('cfg://adict[nest4][somelist][1][1]'), 'i')
self.assertEqual(bc.convert('cfg://adict[nest4][somelist][2]'), 'j')
self.assertEqual(bc.convert('cfg://adict[nest4].somedict.a'), 1)
self.assertEqual(bc.convert('cfg://adict[nest4].somedict[a]'), 1)
self.assertEqual(bc.convert('cfg://adict[nest4].somedict[a with 1 and space]'), 3)
self.assertEqual(bc.convert('cfg://adict[nest4].somedict[a with ( and space]'), 4)
self.assertEqual(bc.convert('cfg://adict.nest4.somelist[1][1]'), 'i')
self.assertEqual(bc.convert('cfg://adict.nest4.somelist[2]'), 'j')
self.assertEqual(bc.convert('cfg://adict.nest4.somedict.a'), 1)
self.assertEqual(bc.convert('cfg://adict.nest4.somedict[a]'), 1)
v = bc.convert('cfg://nest3')
self.assertEqual(v.pop(1), ['a', 'b', 'c'])
self.assertRaises(KeyError, bc.convert, 'cfg://nosuch')
self.assertRaises(ValueError, bc.convert, 'cfg://!')
self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]')
self.assertRaises(KeyError, bc.convert, 'cfg://adict[alpha numeric ] 1 with spaces]')
self.assertRaises(ValueError, bc.convert, 'cfg://adict[ aplha ]] numeric 1 %( - © ©ß¯] ]')
self.assertRaises(ValueError, bc.convert, 'cfg://adict[ aplha [ numeric 1 %( - © ©ß¯] ]')
def test_namedtuple(self):
# see bpo-39142

View file

@ -0,0 +1 @@
Generalize the regex pattern ``BaseConfigurator.INDEX_PATTERN`` to allow spaces and non-alphanumeric characters in keys.