Skip to content

Commit fdbd011

Browse files
bpo-10076: Compiled regular expression and match objects now are copyable. (#1000)
1 parent cd85d0b commit fdbd011

File tree

5 files changed

+41
-164
lines changed

5 files changed

+41
-164
lines changed

Doc/library/re.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -970,6 +970,11 @@ attributes:
970970
The pattern string from which the RE object was compiled.
971971

972972

973+
.. versionchanged:: 3.7
974+
Added support of :func:`copy.copy` and :func:`copy.deepcopy`. Compiled
975+
regular expression objects are considered atomic.
976+
977+
973978
.. _match-objects:
974979

975980
Match Objects
@@ -1171,6 +1176,11 @@ Match objects support the following methods and attributes:
11711176
The string passed to :meth:`~regex.match` or :meth:`~regex.search`.
11721177

11731178

1179+
.. versionchanged:: 3.7
1180+
Added support of :func:`copy.copy` and :func:`copy.deepcopy`. Match objects
1181+
are considered atomic.
1182+
1183+
11741184
.. _re-examples:
11751185

11761186
Regular Expression Examples

Lib/test/test_re.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -971,6 +971,15 @@ def test_pickling(self):
971971
# current pickle expects the _compile() reconstructor in re module
972972
from re import _compile
973973

974+
def test_copying(self):
975+
import copy
976+
p = re.compile(r'(?P<int>\d+)(?:\.(?P<frac>\d*))?')
977+
self.assertIs(copy.copy(p), p)
978+
self.assertIs(copy.deepcopy(p), p)
979+
m = p.match('12.34')
980+
self.assertIs(copy.copy(m), m)
981+
self.assertIs(copy.deepcopy(m), m)
982+
974983
def test_constants(self):
975984
self.assertEqual(re.I, re.IGNORECASE)
976985
self.assertEqual(re.L, re.LOCALE)

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,9 @@ Extension Modules
313313
Library
314314
-------
315315

316+
- bpo-10076: Compiled regular expression and match objects in the re module
317+
now support copy.copy() and copy.deepcopy() (they are considered atomic).
318+
316319
- bpo-30068: _io._IOBase.readlines will check if it's closed first when
317320
hint is present.
318321

Modules/_sre.c

Lines changed: 14 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,6 @@ static const char copyright[] =
5959
/* defining this one enables tracing */
6060
#undef VERBOSE
6161

62-
/* -------------------------------------------------------------------- */
63-
/* optional features */
64-
65-
/* enables copy/deepcopy handling (work in progress) */
66-
#undef USE_BUILTIN_COPY
67-
6862
/* -------------------------------------------------------------------- */
6963

7064
#if defined(_MSC_VER)
@@ -695,28 +689,6 @@ call(const char* module, const char* function, PyObject* args)
695689
return result;
696690
}
697691

698-
#ifdef USE_BUILTIN_COPY
699-
static int
700-
deepcopy(PyObject** object, PyObject* memo)
701-
{
702-
PyObject* copy;
703-
704-
if (!*object)
705-
return 1;
706-
707-
copy = call(
708-
"copy", "deepcopy",
709-
PyTuple_Pack(2, *object, memo)
710-
);
711-
if (!copy)
712-
return 0;
713-
714-
Py_SETREF(*object, copy);
715-
716-
return 1; /* success */
717-
}
718-
#endif
719-
720692
/*[clinic input]
721693
_sre.SRE_Pattern.findall
722694
@@ -1229,60 +1201,24 @@ static PyObject *
12291201
_sre_SRE_Pattern___copy___impl(PatternObject *self)
12301202
/*[clinic end generated code: output=85dedc2db1bd8694 input=a730a59d863bc9f5]*/
12311203
{
1232-
#ifdef USE_BUILTIN_COPY
1233-
PatternObject* copy;
1234-
int offset;
1235-
1236-
copy = PyObject_NEW_VAR(PatternObject, &Pattern_Type, self->codesize);
1237-
if (!copy)
1238-
return NULL;
1239-
1240-
offset = offsetof(PatternObject, groups);
1241-
1242-
Py_XINCREF(self->groupindex);
1243-
Py_XINCREF(self->indexgroup);
1244-
Py_XINCREF(self->pattern);
1245-
1246-
memcpy((char*) copy + offset, (char*) self + offset,
1247-
sizeof(PatternObject) + self->codesize * sizeof(SRE_CODE) - offset);
1248-
copy->weakreflist = NULL;
1249-
1250-
return (PyObject*) copy;
1251-
#else
1252-
PyErr_SetString(PyExc_TypeError, "cannot copy this pattern object");
1253-
return NULL;
1254-
#endif
1204+
Py_INCREF(self);
1205+
return (PyObject *)self;
12551206
}
12561207

12571208
/*[clinic input]
12581209
_sre.SRE_Pattern.__deepcopy__
12591210
12601211
memo: object
1212+
/
12611213
12621214
[clinic start generated code]*/
12631215

12641216
static PyObject *
1265-
_sre_SRE_Pattern___deepcopy___impl(PatternObject *self, PyObject *memo)
1266-
/*[clinic end generated code: output=75efe69bd12c5d7d input=3959719482c07f70]*/
1217+
_sre_SRE_Pattern___deepcopy__(PatternObject *self, PyObject *memo)
1218+
/*[clinic end generated code: output=2ad25679c1f1204a input=a465b1602f997bed]*/
12671219
{
1268-
#ifdef USE_BUILTIN_COPY
1269-
PatternObject* copy;
1270-
1271-
copy = (PatternObject*) pattern_copy(self);
1272-
if (!copy)
1273-
return NULL;
1274-
1275-
if (!deepcopy(&copy->groupindex, memo) ||
1276-
!deepcopy(&copy->indexgroup, memo) ||
1277-
!deepcopy(&copy->pattern, memo)) {
1278-
Py_DECREF(copy);
1279-
return NULL;
1280-
}
1281-
1282-
#else
1283-
PyErr_SetString(PyExc_TypeError, "cannot deepcopy this pattern object");
1284-
return NULL;
1285-
#endif
1220+
Py_INCREF(self);
1221+
return (PyObject *)self;
12861222
}
12871223

12881224
static PyObject *
@@ -2298,63 +2234,24 @@ static PyObject *
22982234
_sre_SRE_Match___copy___impl(MatchObject *self)
22992235
/*[clinic end generated code: output=a779c5fc8b5b4eb4 input=3bb4d30b6baddb5b]*/
23002236
{
2301-
#ifdef USE_BUILTIN_COPY
2302-
MatchObject* copy;
2303-
Py_ssize_t slots, offset;
2304-
2305-
slots = 2 * (self->pattern->groups+1);
2306-
2307-
copy = PyObject_NEW_VAR(MatchObject, &Match_Type, slots);
2308-
if (!copy)
2309-
return NULL;
2310-
2311-
/* this value a constant, but any compiler should be able to
2312-
figure that out all by itself */
2313-
offset = offsetof(MatchObject, string);
2314-
2315-
Py_XINCREF(self->pattern);
2316-
Py_XINCREF(self->string);
2317-
Py_XINCREF(self->regs);
2318-
2319-
memcpy((char*) copy + offset, (char*) self + offset,
2320-
sizeof(MatchObject) + slots * sizeof(Py_ssize_t) - offset);
2321-
2322-
return (PyObject*) copy;
2323-
#else
2324-
PyErr_SetString(PyExc_TypeError, "cannot copy this match object");
2325-
return NULL;
2326-
#endif
2237+
Py_INCREF(self);
2238+
return (PyObject *)self;
23272239
}
23282240

23292241
/*[clinic input]
23302242
_sre.SRE_Match.__deepcopy__
23312243
23322244
memo: object
2245+
/
23332246
23342247
[clinic start generated code]*/
23352248

23362249
static PyObject *
2337-
_sre_SRE_Match___deepcopy___impl(MatchObject *self, PyObject *memo)
2338-
/*[clinic end generated code: output=2b657578eb03f4a3 input=b65b72489eac64cc]*/
2250+
_sre_SRE_Match___deepcopy__(MatchObject *self, PyObject *memo)
2251+
/*[clinic end generated code: output=ba7cb46d655e4ee2 input=779d12a31c2c325e]*/
23392252
{
2340-
#ifdef USE_BUILTIN_COPY
2341-
MatchObject* copy;
2342-
2343-
copy = (MatchObject*) match_copy(self);
2344-
if (!copy)
2345-
return NULL;
2346-
2347-
if (!deepcopy((PyObject**) &copy->pattern, memo) ||
2348-
!deepcopy(&copy->string, memo) ||
2349-
!deepcopy(&copy->regs, memo)) {
2350-
Py_DECREF(copy);
2351-
return NULL;
2352-
}
2353-
2354-
#else
2355-
PyErr_SetString(PyExc_TypeError, "cannot deepcopy this match object");
2356-
return NULL;
2357-
#endif
2253+
Py_INCREF(self);
2254+
return (PyObject *)self;
23582255
}
23592256

23602257
PyDoc_STRVAR(match_doc,

Modules/clinic/_sre.c.h

Lines changed: 5 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -383,33 +383,12 @@ _sre_SRE_Pattern___copy__(PatternObject *self, PyObject *Py_UNUSED(ignored))
383383
}
384384

385385
PyDoc_STRVAR(_sre_SRE_Pattern___deepcopy____doc__,
386-
"__deepcopy__($self, /, memo)\n"
386+
"__deepcopy__($self, memo, /)\n"
387387
"--\n"
388388
"\n");
389389

390390
#define _SRE_SRE_PATTERN___DEEPCOPY___METHODDEF \
391-
{"__deepcopy__", (PyCFunction)_sre_SRE_Pattern___deepcopy__, METH_FASTCALL, _sre_SRE_Pattern___deepcopy____doc__},
392-
393-
static PyObject *
394-
_sre_SRE_Pattern___deepcopy___impl(PatternObject *self, PyObject *memo);
395-
396-
static PyObject *
397-
_sre_SRE_Pattern___deepcopy__(PatternObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
398-
{
399-
PyObject *return_value = NULL;
400-
static const char * const _keywords[] = {"memo", NULL};
401-
static _PyArg_Parser _parser = {"O:__deepcopy__", _keywords, 0};
402-
PyObject *memo;
403-
404-
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
405-
&memo)) {
406-
goto exit;
407-
}
408-
return_value = _sre_SRE_Pattern___deepcopy___impl(self, memo);
409-
410-
exit:
411-
return return_value;
412-
}
391+
{"__deepcopy__", (PyCFunction)_sre_SRE_Pattern___deepcopy__, METH_O, _sre_SRE_Pattern___deepcopy____doc__},
413392

414393
PyDoc_STRVAR(_sre_compile__doc__,
415394
"compile($module, /, pattern, flags, code, groups, groupindex,\n"
@@ -671,33 +650,12 @@ _sre_SRE_Match___copy__(MatchObject *self, PyObject *Py_UNUSED(ignored))
671650
}
672651

673652
PyDoc_STRVAR(_sre_SRE_Match___deepcopy____doc__,
674-
"__deepcopy__($self, /, memo)\n"
653+
"__deepcopy__($self, memo, /)\n"
675654
"--\n"
676655
"\n");
677656

678657
#define _SRE_SRE_MATCH___DEEPCOPY___METHODDEF \
679-
{"__deepcopy__", (PyCFunction)_sre_SRE_Match___deepcopy__, METH_FASTCALL, _sre_SRE_Match___deepcopy____doc__},
680-
681-
static PyObject *
682-
_sre_SRE_Match___deepcopy___impl(MatchObject *self, PyObject *memo);
683-
684-
static PyObject *
685-
_sre_SRE_Match___deepcopy__(MatchObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
686-
{
687-
PyObject *return_value = NULL;
688-
static const char * const _keywords[] = {"memo", NULL};
689-
static _PyArg_Parser _parser = {"O:__deepcopy__", _keywords, 0};
690-
PyObject *memo;
691-
692-
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
693-
&memo)) {
694-
goto exit;
695-
}
696-
return_value = _sre_SRE_Match___deepcopy___impl(self, memo);
697-
698-
exit:
699-
return return_value;
700-
}
658+
{"__deepcopy__", (PyCFunction)_sre_SRE_Match___deepcopy__, METH_O, _sre_SRE_Match___deepcopy____doc__},
701659

702660
PyDoc_STRVAR(_sre_SRE_Scanner_match__doc__,
703661
"match($self, /)\n"
@@ -732,4 +690,4 @@ _sre_SRE_Scanner_search(ScannerObject *self, PyObject *Py_UNUSED(ignored))
732690
{
733691
return _sre_SRE_Scanner_search_impl(self);
734692
}
735-
/*[clinic end generated code: output=5df18da8e2dc762c input=a9049054013a1b77]*/
693+
/*[clinic end generated code: output=e6dab3ba8864da9e input=a9049054013a1b77]*/

0 commit comments

Comments
 (0)