From e50fe4c9eb279632caf9a5084706c5988f9049f6 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 6 Mar 2014 12:24:29 +0200 Subject: [PATCH] Issue #20283: RE pattern methods now accept the string keyword parameters as documented. The pattern and source keyword parameters are left as deprecated aliases. --- Lib/test/test_re.py | 13 ++++++ Misc/NEWS | 4 ++ Modules/_sre.c | 97 +++++++++++++++++++++++++++++++++++++-------- 3 files changed, 98 insertions(+), 16 deletions(-) diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py index fe71c8477e..d7692883a1 100644 --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -933,6 +933,19 @@ class ReTests(unittest.TestCase): self.assertEqual(out.getvalue().splitlines(), ['literal 102', 'literal 111', 'literal 111']) + def test_keyword_parameters(self): + # Issue #20283: Accepting the string keyword parameter. + pat = re.compile(r'(ab)') + self.assertEqual( + pat.match(string='abracadabra', pos=7, endpos=10).span(), (7, 9)) + self.assertEqual( + pat.search(string='abracadabra', pos=3, endpos=10).span(), (7, 9)) + self.assertEqual( + pat.findall(string='abracadabra', pos=3, endpos=10), ['ab']) + self.assertEqual( + pat.split(string='abracadabra', maxsplit=1), + ['', 'ab', 'racadabra']) + def run_re_tests(): from test.re_tests import tests, SUCCEED, FAIL, SYNTAX_ERROR diff --git a/Misc/NEWS b/Misc/NEWS index f5439fcc00..635c33b571 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -40,6 +40,10 @@ Core and Builtins Library ------- +- Issue #20283: RE pattern methods now accept the string keyword parameters + as documented. The pattern and source keyword parameters are left as + deprecated aliases. + - Issue #15618: Make turtle.py compatible with 'from __future__ import unicode_literals'. Initial patch by Juancarlo Añez. diff --git a/Modules/_sre.c b/Modules/_sre.c index bf802a686a..d88c13f3fe 100644 --- a/Modules/_sre.c +++ b/Modules/_sre.c @@ -1875,18 +1875,62 @@ pattern_dealloc(PatternObject* self) PyObject_DEL(self); } +static int +check_args_size(const char *name, PyObject* args, PyObject* kw, int n) +{ + Py_ssize_t m = PyTuple_GET_SIZE(args) + (kw ? PyDict_Size(kw) : 0); + if (m <= n) + return 1; + PyErr_Format(PyExc_TypeError, + "%s() takes at most %d positional arguments (%zd given)", + name, n, m); + return 0; +} + +static PyObject* +fix_string_param(PyObject *string, PyObject *string2, const char *oldname) +{ + if (string2 != NULL) { + char buf[100]; + if (string != NULL) { + PyErr_Format(PyExc_TypeError, + "Argument given by name ('%s') and position (1)", + oldname); + return NULL; + } + sprintf(buf, "The '%s' keyword parameter name is deprecated. " + "Use 'string' instead.", oldname); + if (PyErr_Warn(PyExc_DeprecationWarning, buf) < 0) + return NULL; + return string2; + } + if (string == NULL) { + PyErr_SetString(PyExc_TypeError, + "Required argument 'string' (pos 1) not found"); + return NULL; + } + return string; +} + static PyObject* pattern_match(PatternObject* self, PyObject* args, PyObject* kw) { SRE_STATE state; int status; - PyObject* string; + PyObject *string = NULL, *string2 = NULL; Py_ssize_t start = 0; Py_ssize_t end = PY_SSIZE_T_MAX; - static char* kwlist[] = { "pattern", "pos", "endpos", NULL }; - if (!PyArg_ParseTupleAndKeywords(args, kw, "O|nn:match", kwlist, - &string, &start, &end)) + static char* kwlist[] = { "string", "pos", "endpos", "pattern", NULL }; + if (!check_args_size("match", args, kw, 3)) + return NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kw, "|OnnO:match", kwlist, + &string, &start, &end, &string2)) + return NULL; + + string = fix_string_param(string, string2, "pattern"); + if (!string) return NULL; string = state_init(&state, self, string, start, end); @@ -1920,12 +1964,19 @@ pattern_search(PatternObject* self, PyObject* args, PyObject* kw) SRE_STATE state; int status; - PyObject* string; + PyObject *string = NULL, *string2 = NULL; Py_ssize_t start = 0; Py_ssize_t end = PY_SSIZE_T_MAX; - static char* kwlist[] = { "pattern", "pos", "endpos", NULL }; - if (!PyArg_ParseTupleAndKeywords(args, kw, "O|nn:search", kwlist, - &string, &start, &end)) + static char* kwlist[] = { "string", "pos", "endpos", "pattern", NULL }; + if (!check_args_size("search", args, kw, 3)) + return NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kw, "|OnnO:search", kwlist, + &string, &start, &end, &string2)) + return NULL; + + string = fix_string_param(string, string2, "pattern"); + if (!string) return NULL; string = state_init(&state, self, string, start, end); @@ -2055,12 +2106,19 @@ pattern_findall(PatternObject* self, PyObject* args, PyObject* kw) int status; Py_ssize_t i, b, e; - PyObject* string; + PyObject *string = NULL, *string2 = NULL; Py_ssize_t start = 0; Py_ssize_t end = PY_SSIZE_T_MAX; - static char* kwlist[] = { "source", "pos", "endpos", NULL }; - if (!PyArg_ParseTupleAndKeywords(args, kw, "O|nn:findall", kwlist, - &string, &start, &end)) + static char* kwlist[] = { "string", "pos", "endpos", "source", NULL }; + if (!check_args_size("findall", args, kw, 3)) + return NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kw, "|OnnO:findall", kwlist, + &string, &start, &end, &string2)) + return NULL; + + string = fix_string_param(string, string2, "source"); + if (!string) return NULL; string = state_init(&state, self, string, start, end); @@ -2185,11 +2243,18 @@ pattern_split(PatternObject* self, PyObject* args, PyObject* kw) Py_ssize_t i; void* last; - PyObject* string; + PyObject *string = NULL, *string2 = NULL; Py_ssize_t maxsplit = 0; - static char* kwlist[] = { "source", "maxsplit", NULL }; - if (!PyArg_ParseTupleAndKeywords(args, kw, "O|n:split", kwlist, - &string, &maxsplit)) + static char* kwlist[] = { "string", "maxsplit", "source", NULL }; + if (!check_args_size("split", args, kw, 2)) + return NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kw, "|OnO:split", kwlist, + &string, &maxsplit, &string2)) + return NULL; + + string = fix_string_param(string, string2, "source"); + if (!string) return NULL; string = state_init(&state, self, string, 0, PY_SSIZE_T_MAX); -- 2.50.1