]> granicus.if.org Git - python/commitdiff
bpo-10076: Compiled regular expression and match objects now are copyable. (#1000)
authorSerhiy Storchaka <storchaka@gmail.com>
Sun, 16 Apr 2017 07:16:03 +0000 (10:16 +0300)
committerGitHub <noreply@github.com>
Sun, 16 Apr 2017 07:16:03 +0000 (10:16 +0300)
Doc/library/re.rst
Lib/test/test_re.py
Misc/NEWS
Modules/_sre.c
Modules/clinic/_sre.c.h

index ce90ec7e01a2e8996e6ae788e66fa1b672a8b0c4..0fa7196148dee0fb8c88e643e256be6d0551e657 100644 (file)
@@ -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
index b3b29f847e619ea2112942101d04cbe36716bd63..da5c953ced0cd9000f96e7751b65e3e03868ed7f 100644 (file)
@@ -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)
index 5981b3a1c795bc084824fd11443cdaca4bbdd263..512592e81bec4104502c5bb9f4c9635f51cacfb3 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -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.
 
index ef8295a4a5a4e774b207671240346e44fe837a00..84e2f933db3462f6adff6416e1d62cc42bb1ab4f 100644 (file)
@@ -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(&copy->groupindex, memo) ||
-        !deepcopy(&copy->indexgroup, memo) ||
-        !deepcopy(&copy->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**) &copy->pattern, memo) ||
-        !deepcopy(&copy->string, memo) ||
-        !deepcopy(&copy->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,
index fcb23e891919ccd34f48d76a027b7b88d6194800..5278323f31725dbf84fef29c5ac02663b1eb7ef8 100644 (file)
@@ -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]*/