mirror of
https://github.com/python/cpython.git
synced 2025-10-09 16:34:44 +00:00
bpo-47066: Convert a warning about flags not at the start of the regular expression into error (GH-31994)
This commit is contained in:
parent
cb7874f49d
commit
92a6abf72e
5 changed files with 25 additions and 65 deletions
|
@ -299,6 +299,9 @@ The special characters are:
|
||||||
:func:`re.compile` function. Flags should be used first in the
|
:func:`re.compile` function. Flags should be used first in the
|
||||||
expression string.
|
expression string.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.11
|
||||||
|
This construction can only be used at the start of the expression.
|
||||||
|
|
||||||
.. index:: single: (?:; in regular expressions
|
.. index:: single: (?:; in regular expressions
|
||||||
|
|
||||||
``(?:...)``
|
``(?:...)``
|
||||||
|
|
|
@ -688,6 +688,11 @@ Changes in the Python API
|
||||||
if no locale is specified.
|
if no locale is specified.
|
||||||
(Contributed by Victor Stinner in :issue:`46659`.)
|
(Contributed by Victor Stinner in :issue:`46659`.)
|
||||||
|
|
||||||
|
* Global inline flags (e.g. ``(?i)``) can now only be used at the start of
|
||||||
|
the regular expressions. Using them not at the start of expression was
|
||||||
|
deprecated since Python 3.6.
|
||||||
|
(Contributed by Serhiy Storchaka in :issue:`47066`.)
|
||||||
|
|
||||||
|
|
||||||
Build Changes
|
Build Changes
|
||||||
=============
|
=============
|
||||||
|
|
|
@ -805,16 +805,9 @@ def _parse(source, state, verbose, nested, first=False):
|
||||||
flags = _parse_flags(source, state, char)
|
flags = _parse_flags(source, state, char)
|
||||||
if flags is None: # global flags
|
if flags is None: # global flags
|
||||||
if not first or subpattern:
|
if not first or subpattern:
|
||||||
import warnings
|
raise source.error('global flags not at the start '
|
||||||
warnings.warn(
|
'of the expression',
|
||||||
'Flags not at the start of the expression %r%s'
|
source.tell() - start)
|
||||||
' but at position %d' % (
|
|
||||||
source.string[:20], # truncate long regexes
|
|
||||||
' (truncated)' if len(source.string) > 20 else '',
|
|
||||||
start,
|
|
||||||
),
|
|
||||||
DeprecationWarning, stacklevel=nested + 6
|
|
||||||
)
|
|
||||||
if (state.flags & SRE_FLAG_VERBOSE) and not verbose:
|
if (state.flags & SRE_FLAG_VERBOSE) and not verbose:
|
||||||
raise Verbose
|
raise Verbose
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -1439,66 +1439,22 @@ class ReTests(unittest.TestCase):
|
||||||
self.assertTrue(re.match('(?x) (?i) ' + upper_char, lower_char))
|
self.assertTrue(re.match('(?x) (?i) ' + upper_char, lower_char))
|
||||||
self.assertTrue(re.match(' (?x) (?i) ' + upper_char, lower_char, re.X))
|
self.assertTrue(re.match(' (?x) (?i) ' + upper_char, lower_char, re.X))
|
||||||
|
|
||||||
p = upper_char + '(?i)'
|
msg = "global flags not at the start of the expression"
|
||||||
with self.assertWarns(DeprecationWarning) as warns:
|
self.checkPatternError(upper_char + '(?i)', msg, 1)
|
||||||
self.assertTrue(re.match(p, lower_char))
|
|
||||||
self.assertEqual(
|
|
||||||
str(warns.warnings[0].message),
|
|
||||||
'Flags not at the start of the expression %r'
|
|
||||||
' but at position 1' % p
|
|
||||||
)
|
|
||||||
self.assertEqual(warns.warnings[0].filename, __file__)
|
|
||||||
|
|
||||||
p = upper_char + '(?i)%s' % ('.?' * 100)
|
|
||||||
with self.assertWarns(DeprecationWarning) as warns:
|
|
||||||
self.assertTrue(re.match(p, lower_char))
|
|
||||||
self.assertEqual(
|
|
||||||
str(warns.warnings[0].message),
|
|
||||||
'Flags not at the start of the expression %r (truncated)'
|
|
||||||
' but at position 1' % p[:20]
|
|
||||||
)
|
|
||||||
self.assertEqual(warns.warnings[0].filename, __file__)
|
|
||||||
|
|
||||||
# bpo-30605: Compiling a bytes instance regex was throwing a BytesWarning
|
# bpo-30605: Compiling a bytes instance regex was throwing a BytesWarning
|
||||||
with warnings.catch_warnings():
|
with warnings.catch_warnings():
|
||||||
warnings.simplefilter('error', BytesWarning)
|
warnings.simplefilter('error', BytesWarning)
|
||||||
p = b'A(?i)'
|
self.checkPatternError(b'A(?i)', msg, 1)
|
||||||
with self.assertWarns(DeprecationWarning) as warns:
|
|
||||||
self.assertTrue(re.match(p, b'a'))
|
|
||||||
self.assertEqual(
|
|
||||||
str(warns.warnings[0].message),
|
|
||||||
'Flags not at the start of the expression %r'
|
|
||||||
' but at position 1' % p
|
|
||||||
)
|
|
||||||
self.assertEqual(warns.warnings[0].filename, __file__)
|
|
||||||
|
|
||||||
with self.assertWarns(DeprecationWarning):
|
self.checkPatternError('(?s).(?i)' + upper_char, msg, 5)
|
||||||
self.assertTrue(re.match('(?s).(?i)' + upper_char, '\n' + lower_char))
|
self.checkPatternError('(?i) ' + upper_char + ' (?x)', msg, 7)
|
||||||
with self.assertWarns(DeprecationWarning):
|
self.checkPatternError(' (?x) (?i) ' + upper_char, msg, 1)
|
||||||
self.assertTrue(re.match('(?i) ' + upper_char + ' (?x)', lower_char))
|
self.checkPatternError('^(?i)' + upper_char, msg, 1)
|
||||||
with self.assertWarns(DeprecationWarning):
|
self.checkPatternError('$|(?i)' + upper_char, msg, 2)
|
||||||
self.assertTrue(re.match(' (?x) (?i) ' + upper_char, lower_char))
|
self.checkPatternError('(?:(?i)' + upper_char + ')', msg, 3)
|
||||||
with self.assertWarns(DeprecationWarning):
|
self.checkPatternError('(^)?(?(1)(?i)' + upper_char + ')', msg, 9)
|
||||||
self.assertTrue(re.match('^(?i)' + upper_char, lower_char))
|
self.checkPatternError('($)?(?(1)|(?i)' + upper_char + ')', msg, 10)
|
||||||
with self.assertWarns(DeprecationWarning):
|
|
||||||
self.assertTrue(re.match('$|(?i)' + upper_char, lower_char))
|
|
||||||
with self.assertWarns(DeprecationWarning) as warns:
|
|
||||||
self.assertTrue(re.match('(?:(?i)' + upper_char + ')', lower_char))
|
|
||||||
self.assertRegex(str(warns.warnings[0].message),
|
|
||||||
'Flags not at the start')
|
|
||||||
self.assertEqual(warns.warnings[0].filename, __file__)
|
|
||||||
with self.assertWarns(DeprecationWarning) as warns:
|
|
||||||
self.assertTrue(re.fullmatch('(^)?(?(1)(?i)' + upper_char + ')',
|
|
||||||
lower_char))
|
|
||||||
self.assertRegex(str(warns.warnings[0].message),
|
|
||||||
'Flags not at the start')
|
|
||||||
self.assertEqual(warns.warnings[0].filename, __file__)
|
|
||||||
with self.assertWarns(DeprecationWarning) as warns:
|
|
||||||
self.assertTrue(re.fullmatch('($)?(?(1)|(?i)' + upper_char + ')',
|
|
||||||
lower_char))
|
|
||||||
self.assertRegex(str(warns.warnings[0].message),
|
|
||||||
'Flags not at the start')
|
|
||||||
self.assertEqual(warns.warnings[0].filename, __file__)
|
|
||||||
|
|
||||||
|
|
||||||
def test_dollar_matches_twice(self):
|
def test_dollar_matches_twice(self):
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
Global inline flags (e.g. ``(?i)``) can now only be used at the start of the
|
||||||
|
regular expressions. Using them not at the start of expression was
|
||||||
|
deprecated since Python 3.6.
|
Loading…
Add table
Add a link
Reference in a new issue