8000 gh-92728: Restore re.template, but deprecate it (GH-93161) · python/cpython@74b205b · GitHub
[go: up one dir, main page]

Skip to content

Commit 74b205b

Browse files
gh-92728: Restore re.template, but deprecate it (GH-93161)
Revert "bpo-47211: Remove function re.template() and flag re.TEMPLATE (GH-32300)" This reverts commit b09184b. (cherry picked from commit 16a7e4a) Co-authored-by: Miro Hrončok <miro@hroncok.cz>
1 parent 7a5f190 commit 74b205b

File tree

10 files changed

+65
-5
lines changed

10 files changed

+65
-5
lines changed

Doc/whatsnew/3.11.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1273,6 +1273,11 @@ Deprecated
12731273
is now deprecated. Support will be removed in Python 3.13. (Contributed by
12741274
Jingchen Ye in :gh:`90224`.)
12751275

1276+
* The :func:`re.template` function and the corresponding :const:`re.TEMPLATE`
1277+
and :const:`re.T` flags are deprecated, as they were undocumented and
1278+
lacked an obvious purpose. They will be removed in Python 3.13.
1279+
(Contributed by Serhiy Storchaka and Miro Hrončok in :gh:`92728`.)
1280+
12761281

12771282
Pending Removal in Python 3.12
12781283
==============================

Lib/re/__init__.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@
129129
# public symbols
130130
__all__ = [
131131
"match", "fullmatch", "search", "sub", "subn", "split",
132-
"findall", "finditer", "compile", "purge", "escape",
132+
"findall", "finditer", "compile", "purge", "template", "escape",
133133
"error", "Pattern", "Match", "A", "I", "L", "M", "S", "X", "U",
134134
"ASCII", "IGNORECASE", "LOCALE", "MULTILINE", "DOTALL", "VERBOSE",
135135
"UNICODE", "NOFLAG", "RegexFlag",
@@ -148,6 +148,8 @@ class RegexFlag:
148148
MULTILINE = M = _compiler.SRE_FLAG_MULTILINE # make anchors look for newline
149149
DOTALL = S = _compiler.SRE_FLAG_DOTALL # make dot match newline
150150
VERBOSE = X = _compiler.SRE_FLAG_VERBOSE # ignore whitespace and comments
151+
# sre extensions (experimental, don't rely on these)
152+
TEMPLATE = T = _compiler.SRE_FLAG_TEMPLATE # unknown purpose, deprecated
151153
DEBUG = _compiler.SRE_FLAG_DEBUG # dump pattern after compilation
152154
__str__ = object.__str__
153155
_numeric_repr_ = hex
@@ -229,6 +231,18 @@ def purge():
229231
_cache.clear()
230232
_compile_repl.cache_clear()
231233

234+
def template(pattern, flags=0):
235+
"Compile a template pattern, returning a Pattern object, deprecated"
236+
import warnings
237+
warnings.warn("The re.template() function is deprecated "
238+
"as it is an undocumented function "
239+
"without an obvious purpose. "
240+
"Use re.compile() instead.",
241+
DeprecationWarning)
242+
with warnings.catch_warnings():
243+
warnings.simplefilter("ignore", DeprecationWarning) # warn just once
244+
return _compile(pattern, flags|T)
245+
232246
# SPECIAL_CHARS
233247
# closing ')', '}' and ']'
234248
# '-' (a range in character set)
@@ -270,6 +284,13 @@ def _compile(pattern, flags):
270284
return pattern
271285
if not _compiler.isstring(pattern):
272286
raise TypeError("first argument must be string or compiled pattern")
287+
if flags & T:
288+
import warnings
289+
warnings.warn("The re.TEMPLATE/re.T flag is deprecated "
290+
"as it is an undocumented flag "
291+
"without an obvious purpose. "
292+
"Don't use it.",
293+
DeprecationWarning)
273294
p = _compiler.compile(pattern, flags)
274295
if not (flags & DEBUG):
275296
if len(_cache) >= _MAXCACHE:

Lib/re/_compiler.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@ def _compile(data, pattern, flags):
108108
else:
109109
emit(ANY)
110110
elif op in REPEATING_CODES:
111+
if flags & SRE_FLAG_TEMPLATE:
112+
raise error("internal: unsupported template operator %r" % (op,))
111113
if _simple(av[2]):
112114
emit(REPEATING_CODES[op][2])
113115
skip = _len(code); emit(0)

Lib/re/_constants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ def _makecodes(*names):
204204
}
205205

206206
# flags
207+
SRE_FLAG_TEMPLATE = 1 # template mode (unknown purpose, deprecated)
207208
SRE_FLAG_IGNORECASE = 2 # case insensitive
208209
SRE_FLAG_LOCALE = 4 # honour system locale
209210
SRE_FLAG_MULTILINE = 8 # treat target as multiline string

Lib/re/_parser.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,12 @@
6161
"x": SRE_FLAG_VERBOSE,
6262
# extensions
6363
"a": SRE_FLAG_ASCII,
64+
"t": SRE_FLAG_TEMPLATE,
6465
"u": SRE_FLAG_UNICODE,
6566
}
6667

6768
TYPE_FLAGS = SRE_FLAG_ASCII | SRE_FLAG_LOCALE | SRE_FLAG_UNICODE
68-
GLOBAL_FLAGS = SRE_FLAG_DEBUG
69+
GLOBAL_FLAGS = SRE_FLAG_DEBUG | SRE_FLAG_TEMPLATE
6970

7071
class State:
7172
# keeps track of state for parsing

Lib/test/test_re.py

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2417,6 +2417,30 @@ def test_bug_gh91616(self):
24172417
self.assertTrue(re.fullmatch(r'(?s:(?>.*?\.).*)\Z', "a.txt")) # reproducer
24182418
self.assertTrue(re.fullmatch(r'(?s:(?=(?P<g0>.*?\.))(?P=g0).*)\Z', "a.txt"))
24192419

2420+
def test_template_function_and_flag_is_deprecated(self):
2421+
with self.assertWarns(DeprecationWarning) as cm:
2422+
template_re1 = re.template(r'a')
2423+
self.assertIn('re.template()', str(cm.warning))
2424+
self.assertIn('is deprecated', str(cm.warning))
2425+
self.assertIn('function', str(cm.warning))
2426+
self.assertNotIn('flag', str(cm.warning))
2427+
2428+
with self.assertWarns(DeprecationWarning) as cm:
2429+
# we deliberately use more flags here to test that that still
2430+
# triggers the warning
2431+
# if paranoid, we could test multiple different combinations,
2432+
# but it's probably not worth it
2433+
template_re2 = re.compile(r'a', flags=re.TEMPLATE|re.UNICODE)
2434+
self.assertIn('re.TEMPLATE', str(cm.warning))
2435+
self.assertIn('is deprecated', str(cm.warning))
2436+
self.assertIn('flag', str(cm.warning))
2437+
self.assertNotIn('function', str(cm.warning))
2438+
2439+
# while deprecated, is should still function
2440+
self.assertEqual(template_re1, template_re2)
2441+
self.assertTrue(template_re1.match('ahoy'))
2442+
self.assertFalse(template_re1.match('nope'))
2443+
24202444

24212445
def get_debug_out(pat):
24222446
with captured_stdout() as out:
@@ -2611,11 +2635,11 @@ def test_flags_repr(self):
26112635
"re.IGNORECASE|re.DOTALL|re.VERBOSE|0x100000")
26122636
self.assertEqual(
26132637
repr(~re.I),
2614-
"re.ASCII|re.LOCALE|re.UNICODE|re.MULTILINE|re.DOTALL|re.VERBOSE|re.DEBUG|0x1")
2638+
"re.ASCII|re.LOCALE|re.UNICODE|re.MULTILINE|re.DOTALL|re.VERBOSE|re.TEMPLATE|re.DEBUG")
26152639
self.assertEqual(repr(~(re.I|re.S|re.X)),
2616-
"re.ASCII|re.LOCALE|re.UNICODE|re.MULTILINE|re.DEBUG|0x1")
2640+
"re.ASCII|re.LOCALE|re.UNICODE|re.MULTILINE|re.TEMPLATE|re.DEBUG")
26172641
self.assertEqual(repr(~(re.I|re.S|re.X|(1<<20))),
2618-
"re.ASCII|re.LOCALE|re.UNICODE|re.MULTILINE|re.DEBUG|0xffe01")
2642+
"re.ASCII|re.LOCALE|re.UNICODE|re.MULTILINE|re.TEMPLATE|re.DEBUG|0xffe00")
26192643

26202644

26212645
class ImplementationTest(unittest.TestCase):

Misc/NEWS.d/3.11.0b1.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1373,6 +1373,7 @@ Suppress expression chaining for more :mod:`re` parsing errors.
13731373
13741374
Remove undocumented and never working function ``re.template()`` and flag
13751375
``re.TEMPLATE``.
1376+
This was later reverted in 3.11.0b2 and deprecated instead.
13761377

13771378
..
13781379
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
The :func:`re.template` function and the corresponding :const:`re.TEMPLATE`
2+
and :const:`re.T` flags are restored after they were removed in 3.11.0b1,
3+
but they are now deprecated, so they might be removed from Python 3.13.

Modules/_sre/sre.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1323,6 +1323,7 @@ pattern_repr(PatternObject *obj)
13231323
const char *name;
13241324
int value;
13251325
} flag_names[] = {
1326+
{"re.TEMPLATE", SRE_FLAG_TEMPLATE},
13261327
{"re.IGNORECASE", SRE_FLAG_IGNORECASE},
13271328
{"re.LOCALE", SRE_FLAG_LOCALE},
13281329
{"re.MULTILINE", SRE_FLAG_MULTILINE},

Modules/_sre/sre_constants.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@
8585
#define SRE_CATEGORY_UNI_NOT_WORD 15
8686
#define SRE_CATEGORY_UNI_LINEBREAK 16
8787
#define SRE_CATEGORY_UNI_NOT_LINEBREAK 17
88+
#define SRE_FLAG_TEMPLATE 1
8889
#define SRE_FLAG_IGNORECASE 2
8990
#define SRE_FLAG_LOCALE 4
9091
#define SRE_FLAG_MULTILINE 8

0 commit comments

Comments
 (0)
0