diff --git a/Lib/test/string_tests.py b/Lib/test/string_tests.py --- a/Lib/test/string_tests.py +++ b/Lib/test/string_tests.py @@ -145,6 +145,12 @@ self.assertEqual(rem, 0, '%s != 0 for %s' % (rem, i)) self.assertEqual(r1, r2, '%s != %s for %s' % (r1, r2, i)) + # test None arguments (issue 11828) + self.checkequal(1, 'hello', 'count', 'o', -1, None) + self.checkequal(1, 'hello', 'count', 'l', -2, None) + self.checkequal(2, 'hello', 'count', 'l', None) + self.checkequal(0, 'hello', 'count', 'x', None, None) + def test_find(self): self.checkequal(0, 'abcdefghiabc', 'find', 'abc') self.checkequal(9, 'abcdefghiabc', 'find', 'abc', 1) @@ -940,6 +946,12 @@ self.checkraises(TypeError, 'hello', 'startswith', (42,)) + # test None arguments (issue 11828) + self.checkequal(True, 'hello', 'startswith', 'o', -1, None) + self.checkequal(True, 'hello', 'startswith', 'l', -2, None) + self.checkequal(True, 'hello', 'startswith', 'h', None) + self.checkequal(False, 'hello', 'startswith', 'x', None, None) + def test_endswith(self): self.checkequal(True, 'hello', 'endswith', 'lo') self.checkequal(False, 'hello', 'endswith', 'he') @@ -989,6 +1001,12 @@ self.checkraises(TypeError, 'hello', 'endswith', (42,)) + # test None arguments (issue 11828) + self.checkequal(True, 'hello', 'endswith', 'o', -1, None) + self.checkequal(True, 'hello', 'endswith', 'lo', -2, None) + self.checkequal(True, 'hello', 'endswith', 'o', None) + self.checkequal(False, 'hello', 'endswith', 'x', None, None) + def test___contains__(self): self.checkequal(True, '', '__contains__', '') self.checkequal(True, 'abc', '__contains__', '') diff --git a/Objects/stringlib/find.h b/Objects/stringlib/find.h --- a/Objects/stringlib/find.h +++ b/Objects/stringlib/find.h @@ -97,8 +97,8 @@ /* This function is a helper for the "find" family (find, rfind, index, -rindex) of unicodeobject.c file, because they all have the same -behaviour for the arguments. +rindex, count, startswith, endswith) of unicodeobject.c file, because +they all have the same behaviour for the arguments. It does not touch the variables received until it knows everything is ok. @@ -111,7 +111,8 @@ Py_LOCAL_INLINE(int) _ParseTupleFinds (PyObject *args, PyObject **substring, - Py_ssize_t *start, Py_ssize_t *end) { + Py_ssize_t *start, Py_ssize_t *end, + int convert_first_argument_to_unicode) { PyObject *tmp_substring; Py_ssize_t tmp_start = 0; Py_ssize_t tmp_end = PY_SSIZE_T_MAX; @@ -131,9 +132,12 @@ if (!_PyEval_SliceIndex(obj_end, &tmp_end)) return 0; - tmp_substring = PyUnicode_FromObject(tmp_substring); - if (!tmp_substring) - return 0; + if (convert_first_argument_to_unicode) + { + tmp_substring = PyUnicode_FromObject(tmp_substring); + if (!tmp_substring) + return 0; + } *start = tmp_start; *end = tmp_end; diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -7515,13 +7515,7 @@ Py_ssize_t end = PY_SSIZE_T_MAX; PyObject *result; - if (!PyArg_ParseTuple(args, "O|O&O&:count", &substring, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) - return NULL; - - substring = (PyUnicodeObject *)PyUnicode_FromObject( - (PyObject *)substring); - if (substring == NULL) + if (!_ParseTupleFinds(args, (PyObject **)&substring, &start, &end, 1)) return NULL; ADJUST_INDICES(start, end, self->length); @@ -7663,7 +7657,7 @@ Py_ssize_t end; Py_ssize_t result; - if (!_ParseTupleFinds(args, &substring, &start, &end)) + if (!_ParseTupleFinds(args, &substring, &start, &end, 1)) return NULL; result = stringlib_find_slice( @@ -7724,7 +7718,7 @@ Py_ssize_t start; Py_ssize_t end; - if (!_ParseTupleFinds(args, &substring, &start, &end)) + if (!_ParseTupleFinds(args, &substring, &start, &end, 1)) return NULL; result = stringlib_find_slice( @@ -8588,7 +8582,7 @@ Py_ssize_t end; Py_ssize_t result; - if (!_ParseTupleFinds(args, &substring, &start, &end)) + if (!_ParseTupleFinds(args, &substring, &start, &end, 1)) return NULL; result = stringlib_rfind_slice( @@ -8615,7 +8609,7 @@ Py_ssize_t end; Py_ssize_t result; - if (!_ParseTupleFinds(args, &substring, &start, &end)) + if (!_ParseTupleFinds(args, &substring, &start, &end, 1)) return NULL; result = stringlib_rfind_slice( @@ -9083,9 +9077,9 @@ Py_ssize_t end = PY_SSIZE_T_MAX; int result; - if (!PyArg_ParseTuple(args, "O|O&O&:startswith", &subobj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) - return NULL; + if (!_ParseTupleFinds(args, &subobj, &start, &end, 0)) + return NULL; + if (PyTuple_Check(subobj)) { Py_ssize_t i; for (i = 0; i < PyTuple_GET_SIZE(subobj); i++) { @@ -9129,9 +9123,9 @@ Py_ssize_t end = PY_SSIZE_T_MAX; int result; - if (!PyArg_ParseTuple(args, "O|O&O&:endswith", &subobj, - _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) - return NULL; + if (!_ParseTupleFinds(args, &subobj, &start, &end, 0)) + return NULL; + if (PyTuple_Check(subobj)) { Py_ssize_t i; for (i = 0; i < PyTuple_GET_SIZE(subobj); i++) {