bpo-10076: Compiled regular expression and match objects now are copyable. (#1000)
This commit is contained in:
parent
cd85d0b90b
commit
fdbd01151d
|
@ -970,6 +970,11 @@ attributes:
|
|||
The pattern string from which the RE object was compiled.
|
||||
|
||||
|
||||
.. versionchanged:: 3.7
|
||||
Added support of :func:`copy.copy` and :func:`copy.deepcopy`. Compiled
|
||||
regular expression objects are considered atomic.
|
||||
|
||||
|
||||
.. _match-objects:
|
||||
|
||||
Match Objects
|
||||
|
@ -1171,6 +1176,11 @@ Match objects support the following methods and attributes:
|
|||
The string passed to :meth:`~regex.match` or :meth:`~regex.search`.
|
||||
|
||||
|
||||
.. versionchanged:: 3.7
|
||||
Added support of :func:`copy.copy` and :func:`copy.deepcopy`. Match objects
|
||||
are considered atomic.
|
||||
|
||||
|
||||
.. _re-examples:
|
||||
|
||||
Regular Expression Examples
|
||||
|
|
|
@ -971,6 +971,15 @@ class ReTests(unittest.TestCase):
|
|||
# current pickle expects the _compile() reconstructor in re module
|
||||
from re import _compile
|
||||
|
||||
def test_copying(self):
|
||||
import copy
|
||||
p = re.compile(r'(?P<int>\d+)(?:\.(?P<frac>\d*))?')
|
||||
self.assertIs(copy.copy(p), p)
|
||||
self.assertIs(copy.deepcopy(p), p)
|
||||
m = p.match('12.34')
|
||||
self.assertIs(copy.copy(m), m)
|
||||
self.assertIs(copy.deepcopy(m), m)
|
||||
|
||||
def test_constants(self):
|
||||
self.assertEqual(re.I, re.IGNORECASE)
|
||||
self.assertEqual(re.L, re.LOCALE)
|
||||
|
|
|
@ -313,6 +313,9 @@ Extension Modules
|
|||
Library
|
||||
-------
|
||||
|
||||
- bpo-10076: Compiled regular expression and match objects in the re module
|
||||
now support copy.copy() and copy.deepcopy() (they are considered atomic).
|
||||
|
||||
- bpo-30068: _io._IOBase.readlines will check if it's closed first when
|
||||
hint is present.
|
||||
|
||||
|
|
131
Modules/_sre.c
131
Modules/_sre.c
|
@ -59,12 +59,6 @@ static const char copyright[] =
|
|||
/* defining this one enables tracing */
|
||||
#undef VERBOSE
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* optional features */
|
||||
|
||||
/* enables copy/deepcopy handling (work in progress) */
|
||||
#undef USE_BUILTIN_COPY
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
|
@ -695,28 +689,6 @@ call(const char* module, const char* function, PyObject* args)
|
|||
return result;
|
||||
}
|
||||
|
||||
#ifdef USE_BUILTIN_COPY
|
||||
static int
|
||||
deepcopy(PyObject** object, PyObject* memo)
|
||||
{
|
||||
PyObject* copy;
|
||||
|
||||
if (!*object)
|
||||
return 1;
|
||||
|
||||
copy = call(
|
||||
"copy", "deepcopy",
|
||||
PyTuple_Pack(2, *object, memo)
|
||||
);
|
||||
if (!copy)
|
||||
return 0;
|
||||
|
||||
Py_SETREF(*object, copy);
|
||||
|
||||
return 1; /* success */
|
||||
}
|
||||
#endif
|
||||
|
||||
/*[clinic input]
|
||||
_sre.SRE_Pattern.findall
|
||||
|
||||
|
@ -1229,60 +1201,24 @@ static PyObject *
|
|||
_sre_SRE_Pattern___copy___impl(PatternObject *self)
|
||||
/*[clinic end generated code: output=85dedc2db1bd8694 input=a730a59d863bc9f5]*/
|
||||
{
|
||||
#ifdef USE_BUILTIN_COPY
|
||||
PatternObject* copy;
|
||||
int offset;
|
||||
|
||||
copy = PyObject_NEW_VAR(PatternObject, &Pattern_Type, self->codesize);
|
||||
if (!copy)
|
||||
return NULL;
|
||||
|
||||
offset = offsetof(PatternObject, groups);
|
||||
|
||||
Py_XINCREF(self->groupindex);
|
||||
Py_XINCREF(self->indexgroup);
|
||||
Py_XINCREF(self->pattern);
|
||||
|
||||
memcpy((char*) copy + offset, (char*) self + offset,
|
||||
sizeof(PatternObject) + self->codesize * sizeof(SRE_CODE) - offset);
|
||||
copy->weakreflist = NULL;
|
||||
|
||||
return (PyObject*) copy;
|
||||
#else
|
||||
PyErr_SetString(PyExc_TypeError, "cannot copy this pattern object");
|
||||
return NULL;
|
||||
#endif
|
||||
Py_INCREF(self);
|
||||
return (PyObject *)self;
|
||||
}
|
||||
|
||||
/*[clinic input]
|
||||
_sre.SRE_Pattern.__deepcopy__
|
||||
|
||||
memo: object
|
||||
/
|
||||
|
||||
[clinic start generated code]*/
|
||||
|
||||
static PyObject *
|
||||
_sre_SRE_Pattern___deepcopy___impl(PatternObject *self, PyObject *memo)
|
||||
/*[clinic end generated code: output=75efe69bd12c5d7d input=3959719482c07f70]*/
|
||||
_sre_SRE_Pattern___deepcopy__(PatternObject *self, PyObject *memo)
|
||||
/*[clinic end generated code: output=2ad25679c1f1204a input=a465b1602f997bed]*/
|
||||
{
|
||||
#ifdef USE_BUILTIN_COPY
|
||||
PatternObject* copy;
|
||||
|
||||
copy = (PatternObject*) pattern_copy(self);
|
||||
if (!copy)
|
||||
return NULL;
|
||||
|
||||
if (!deepcopy(©->groupindex, memo) ||
|
||||
!deepcopy(©->indexgroup, memo) ||
|
||||
!deepcopy(©->pattern, memo)) {
|
||||
Py_DECREF(copy);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#else
|
||||
PyErr_SetString(PyExc_TypeError, "cannot deepcopy this pattern object");
|
||||
return NULL;
|
||||
#endif
|
||||
Py_INCREF(self);
|
||||
return (PyObject *)self;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
|
@ -2298,63 +2234,24 @@ static PyObject *
|
|||
_sre_SRE_Match___copy___impl(MatchObject *self)
|
||||
/*[clinic end generated code: output=a779c5fc8b5b4eb4 input=3bb4d30b6baddb5b]*/
|
||||
{
|
||||
#ifdef USE_BUILTIN_COPY
|
||||
MatchObject* copy;
|
||||
Py_ssize_t slots, offset;
|
||||
|
||||
slots = 2 * (self->pattern->groups+1);
|
||||
|
||||
copy = PyObject_NEW_VAR(MatchObject, &Match_Type, slots);
|
||||
if (!copy)
|
||||
return NULL;
|
||||
|
||||
/* this value a constant, but any compiler should be able to
|
||||
figure that out all by itself */
|
||||
offset = offsetof(MatchObject, string);
|
||||
|
||||
Py_XINCREF(self->pattern);
|
||||
Py_XINCREF(self->string);
|
||||
Py_XINCREF(self->regs);
|
||||
|
||||
memcpy((char*) copy + offset, (char*) self + offset,
|
||||
sizeof(MatchObject) + slots * sizeof(Py_ssize_t) - offset);
|
||||
|
||||
return (PyObject*) copy;
|
||||
#else
|
||||
PyErr_SetString(PyExc_TypeError, "cannot copy this match object");
|
||||
return NULL;
|
||||
#endif
|
||||
Py_INCREF(self);
|
||||
return (PyObject *)self;
|
||||
}
|
||||
|
||||
/*[clinic input]
|
||||
_sre.SRE_Match.__deepcopy__
|
||||
|
||||
memo: object
|
||||
/
|
||||
|
||||
[clinic start generated code]*/
|
||||
|
||||
static PyObject *
|
||||
_sre_SRE_Match___deepcopy___impl(MatchObject *self, PyObject *memo)
|
||||
/*[clinic end generated code: output=2b657578eb03f4a3 input=b65b72489eac64cc]*/
|
||||
_sre_SRE_Match___deepcopy__(MatchObject *self, PyObject *memo)
|
||||
/*[clinic end generated code: output=ba7cb46d655e4ee2 input=779d12a31c2c325e]*/
|
||||
{
|
||||
#ifdef USE_BUILTIN_COPY
|
||||
MatchObject* copy;
|
||||
|
||||
copy = (MatchObject*) match_copy(self);
|
||||
if (!copy)
|
||||
return NULL;
|
||||
|
||||
if (!deepcopy((PyObject**) ©->pattern, memo) ||
|
||||
!deepcopy(©->string, memo) ||
|
||||
!deepcopy(©->regs, memo)) {
|
||||
Py_DECREF(copy);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#else
|
||||
PyErr_SetString(PyExc_TypeError, "cannot deepcopy this match object");
|
||||
return NULL;
|
||||
#endif
|
||||
Py_INCREF(self);
|
||||
return (PyObject *)self;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(match_doc,
|
||||
|
|
|
@ -383,33 +383,12 @@ _sre_SRE_Pattern___copy__(PatternObject *self, PyObject *Py_UNUSED(ignored))
|
|||
}
|
||||
|
||||
PyDoc_STRVAR(_sre_SRE_Pattern___deepcopy____doc__,
|
||||
"__deepcopy__($self, /, memo)\n"
|
||||
"__deepcopy__($self, memo, /)\n"
|
||||
"--\n"
|
||||
"\n");
|
||||
|
||||
#define _SRE_SRE_PATTERN___DEEPCOPY___METHODDEF \
|
||||
{"__deepcopy__", (PyCFunction)_sre_SRE_Pattern___deepcopy__, METH_FASTCALL, _sre_SRE_Pattern___deepcopy____doc__},
|
||||
|
||||
static PyObject *
|
||||
_sre_SRE_Pattern___deepcopy___impl(PatternObject *self, PyObject *memo);
|
||||
|
||||
static PyObject *
|
||||
_sre_SRE_Pattern___deepcopy__(PatternObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
static const char * const _keywords[] = {"memo", NULL};
|
||||
static _PyArg_Parser _parser = {"O:__deepcopy__", _keywords, 0};
|
||||
PyObject *memo;
|
||||
|
||||
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
|
||||
&memo)) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = _sre_SRE_Pattern___deepcopy___impl(self, memo);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
{"__deepcopy__", (PyCFunction)_sre_SRE_Pattern___deepcopy__, METH_O, _sre_SRE_Pattern___deepcopy____doc__},
|
||||
|
||||
PyDoc_STRVAR(_sre_compile__doc__,
|
||||
"compile($module, /, pattern, flags, code, groups, groupindex,\n"
|
||||
|
@ -671,33 +650,12 @@ _sre_SRE_Match___copy__(MatchObject *self, PyObject *Py_UNUSED(ignored))
|
|||
}
|
||||
|
||||
PyDoc_STRVAR(_sre_SRE_Match___deepcopy____doc__,
|
||||
"__deepcopy__($self, /, memo)\n"
|
||||
"__deepcopy__($self, memo, /)\n"
|
||||
"--\n"
|
||||
"\n");
|
||||
|
||||
#define _SRE_SRE_MATCH___DEEPCOPY___METHODDEF \
|
||||
{"__deepcopy__", (PyCFunction)_sre_SRE_Match___deepcopy__, METH_FASTCALL, _sre_SRE_Match___deepcopy____doc__},
|
||||
|
||||
static PyObject *
|
||||
_sre_SRE_Match___deepcopy___impl(MatchObject *self, PyObject *memo);
|
||||
|
||||
static PyObject *
|
||||
_sre_SRE_Match___deepcopy__(MatchObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
static const char * const _keywords[] = {"memo", NULL};
|
||||
static _PyArg_Parser _parser = {"O:__deepcopy__", _keywords, 0};
|
||||
PyObject *memo;
|
||||
|
||||
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
|
||||
&memo)) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = _sre_SRE_Match___deepcopy___impl(self, memo);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
{"__deepcopy__", (PyCFunction)_sre_SRE_Match___deepcopy__, METH_O, _sre_SRE_Match___deepcopy____doc__},
|
||||
|
||||
PyDoc_STRVAR(_sre_SRE_Scanner_match__doc__,
|
||||
"match($self, /)\n"
|
||||
|
@ -732,4 +690,4 @@ _sre_SRE_Scanner_search(ScannerObject *self, PyObject *Py_UNUSED(ignored))
|
|||
{
|
||||
return _sre_SRE_Scanner_search_impl(self);
|
||||
}
|
||||
/*[clinic end generated code: output=5df18da8e2dc762c input=a9049054013a1b77]*/
|
||||
/*[clinic end generated code: output=e6dab3ba8864da9e input=a9049054013a1b77]*/
|
||||
|
|
Loading…
Reference in New Issue