Skip to content

Commit 92a6abf

Browse files
bpo-47066: Convert a warning about flags not at the start of the regular expression into error (GH-31994)
1 parent cb7874f commit 92a6abf

File tree

5 files changed

+26
-66
lines changed

5 files changed

+26
-66
lines changed

Doc/library/re.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,9 @@ The special characters are:
299299
:func:`re.compile` function. Flags should be used first in the
300300
expression string.
301301

302+
.. versionchanged:: 3.11
303+
This construction can only be used at the start of the expression.
304+
302305
.. index:: single: (?:; in regular expressions
303306

304307
``(?:...)``

Doc/whatsnew/3.11.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,11 @@ Changes in the Python API
688688
if no locale is specified.
689689
(Contributed by Victor Stinner in :issue:`46659`.)
690690

691+
* Global inline flags (e.g. ``(?i)``) can now only be used at the start of
692+
the regular expressions. Using them not at the start of expression was
693+
deprecated since Python 3.6.
694+
(Contributed by Serhiy Storchaka in :issue:`47066`.)
695+
691696

692697
Build Changes
693698
=============

Lib/sre_parse.py

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -805,16 +805,9 @@ def _parse(source, state, verbose, nested, first=False):
805805
flags = _parse_flags(source, state, char)
806806
if flags is None: # global flags
807807
if not first or subpattern:
808-
import warnings
809-
warnings.warn(
810-
'Flags not at the start of the expression %r%s'
811-
' but at position %d' % (
812-
source.string[:20], # truncate long regexes
813-
' (truncated)' if len(source.string) > 20 else '',
814-
start,
815-
),
816-
DeprecationWarning, stacklevel=nested + 6
817-
)
808+
raise source.error('global flags not at the start '
809+
'of the expression',
810+
source.tell() - start)
818811
if (state.flags & SRE_FLAG_VERBOSE) and not verbose:
819812
raise Verbose
820813
continue

Lib/test/test_re.py

Lines changed: 12 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1439,66 +1439,22 @@ def test_inline_flags(self):
14391439
self.assertTrue(re.match('(?x) (?i) ' + upper_char, lower_char))
14401440
self.assertTrue(re.match(' (?x) (?i) ' + upper_char, lower_char, re.X))
14411441

1442-
p = upper_char + '(?i)'
1443-
with self.assertWarns(DeprecationWarning) as warns:
1444-
self.assertTrue(re.match(p, lower_char))
1445-
self.assertEqual(
1446-
str(warns.warnings[0].message),
1447-
'Flags not at the start of the expression %r'
1448-
' but at position 1' % p
1449-
)
1450-
self.assertEqual(warns.warnings[0].filename, __file__)
1451-
1452-
p = upper_char + '(?i)%s' % ('.?' * 100)
1453-
with self.assertWarns(DeprecationWarning) as warns:
1454-
self.assertTrue(re.match(p, lower_char))
1455-
self.assertEqual(
1456-
str(warns.warnings[0].message),
1457-
'Flags not at the start of the expression %r (truncated)'
1458-
' but at position 1' % p[:20]
1459-
)
1460-
self.assertEqual(warns.warnings[0].filename, __file__)
1442+
msg = "global flags not at the start of the expression"
1443+
self.checkPatternError(upper_char + '(?i)', msg, 1)
14611444

14621445
# bpo-30605: Compiling a bytes instance regex was throwing a BytesWarning
14631446
with warnings.catch_warnings():
14641447
warnings.simplefilter('error', BytesWarning)
1465-
p = b'A(?i)'
1466-
with self.assertWarns(DeprecationWarning) as warns:
1467-
self.assertTrue(re.match(p, b'a'))
1468-
self.assertEqual(
1469-
str(warns.warnings[0].message),
1470-
'Flags not at the start of the expression %r'
1471-
' but at position 1' % p
1472-
)
1473-
self.assertEqual(warns.warnings[0].filename, __file__)
1474-
1475-
with self.assertWarns(DeprecationWarning):
1476-
self.assertTrue(re.match('(?s).(?i)' + upper_char, '\n' + lower_char))
1477-
with self.assertWarns(DeprecationWarning):
1478-
self.assertTrue(re.match('(?i) ' + upper_char + ' (?x)', lower_char))
1479-
with self.assertWarns(DeprecationWarning):
1480-
self.assertTrue(re.match(' (?x) (?i) ' + upper_char, lower_char))
1481-
with self.assertWarns(DeprecationWarning):
1482-
self.assertTrue(re.match('^(?i)' + upper_char, lower_char))
1483-
with self.assertWarns(DeprecationWarning):
1484-
self.assertTrue(re.match('$|(?i)' + upper_char, lower_char))
1485-
with self.assertWarns(DeprecationWarning) as warns:
1486-
self.assertTrue(re.match('(?:(?i)' + upper_char + ')', lower_char))
1487-
self.assertRegex(str(warns.warnings[0].message),
1488-
'Flags not at the start')
1489-
self.assertEqual(warns.warnings[0].filename, __file__)
1490-
with self.assertWarns(DeprecationWarning) as warns:
1491-
self.assertTrue(re.fullmatch('(^)?(?(1)(?i)' + upper_char + ')',
1492-
lower_char))
1493-
self.assertRegex(str(warns.warnings[0].message),
1494-
'Flags not at the start')
1495-
self.assertEqual(warns.warnings[0].filename, __file__)
1496-
with self.assertWarns(DeprecationWarning) as warns:
1497-
self.assertTrue(re.fullmatch('($)?(?(1)|(?i)' + upper_char + ')',
1498-
lower_char))
1499-
self.assertRegex(str(warns.warnings[0].message),
1500-
'Flags not at the start')
1501-
self.assertEqual(warns.warnings[0].filename, __file__)
1448+
self.checkPatternError(b'A(?i)', msg, 1)
1449+
1450+
self.checkPatternError('(?s).(?i)' + upper_char, msg, 5)
1451+
self.checkPatternError('(?i) ' + upper_char + ' (?x)', msg, 7)
1452+
self.checkPatternError(' (?x) (?i) ' + upper_char, msg, 1)
1453+
self.checkPatternError('^(?i)' + upper_char, msg, 1)
1454+
self.checkPatternError('$|(?i)' + upper_char, msg, 2)
1455+
self.checkPatternError('(?:(?i)' + upper_char + ')', msg, 3)
1456+
self.checkPatternError('(^)?(?(1)(?i)' + upper_char + ')', msg, 9)
1457+
self.checkPatternError('($)?(?(1)|(?i)' + upper_char + ')', msg, 10)
15021458

15031459

15041460
def test_dollar_matches_twice(self):
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Global inline flags (e.g. ``(?i)``) can now only be used at the start of the
2+
regular expressions. Using them not at the start of expression was
3+
deprecated since Python 3.6.

0 commit comments

Comments
 (0)