Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
pythongh-90716: bugfixes and more tests for _pylong.
Browse files Browse the repository at this point in the history
* Properly decref on _pylong import error.
* Improve the error message on _pylong TypeError.
* Tie the return value comments together.

These are minor followups to issues not caught among the reviewers on
python#96673.
gpshead committed Nov 3, 2022
1 parent 0faa0ba commit d0de40f
Showing 2 changed files with 36 additions and 3 deletions.
31 changes: 31 additions & 0 deletions Lib/test/test_int.py
Original file line number Diff line number Diff line change
@@ -2,10 +2,13 @@
import time

import unittest
from unittest import mock
from test import support
from test.test_grammar import (VALID_UNDERSCORE_LITERALS,
INVALID_UNDERSCORE_LITERALS)

import _pylong

L = [
('0', 0),
('1', 1),
@@ -841,6 +844,34 @@ def test_pylong_str_to_int(self):
with self.assertRaises(ValueError) as err:
int('_' + s)

@mock.patch.object(_pylong, "int_to_decimal_string")
def test_pylong_misbehavior_error_path_to_str(
self, mock_int_to_str):
with support.adjust_int_max_str_digits(20_000):
big_value = int('7'*19_999)
mock_int_to_str.return_value = None # not a str
with self.assertRaises(TypeError) as ctx:
str(big_value)
self.assertIn('non-string', str(ctx.exception))
mock_int_to_str.side_effect = RuntimeError("testABC")
with self.assertRaises(RuntimeError):
str(big_value)

@mock.patch.object(_pylong, "int_from_string")
def test_pylong_misbehavior_error_path_from_str(
self, mock_int_from_str):
big_value = '7'*19_999
with support.adjust_int_max_str_digits(20_000):
mock_int_from_str.return_value = b'not an int'
with self.assertRaises(TypeError) as ctx:
int(big_value)
self.assertIn('_pylong.int_from_string', str(ctx.exception))

mock_int_from_str.side_effect = RuntimeError("test123")
with self.assertRaises(RuntimeError):
int(big_value)



if __name__ == "__main__":
unittest.main()
8 changes: 5 additions & 3 deletions Objects/longobject.c
Original file line number Diff line number Diff line change
@@ -2362,6 +2362,7 @@ pylong_int_from_string(const char *start, const char *end, PyLongObject **res)
}
PyObject *s = PyUnicode_FromStringAndSize(start, end-start);
if (s == NULL) {
Py_DECREF(mod);
goto error;
}
PyObject *result = PyObject_CallMethod(mod, "int_from_string", "O", s);
@@ -2371,14 +2372,14 @@ pylong_int_from_string(const char *start, const char *end, PyLongObject **res)
goto error;
}
if (!PyLong_Check(result)) {
PyErr_SetString(PyExc_TypeError, "an integer is required");
PyErr_SetString(PyExc_TypeError, "_pylong.int_from_string did not return an int");
goto error;
}
*res = (PyLongObject *)result;
return 0;
error:
*res = NULL;
return 0;
return 0; // See the long_from_string_base() API comment.
}
#endif /* WITH_PYLONG_MODULE */

@@ -2617,7 +2618,8 @@ long_from_non_binary_base(const char *start, const char *end, Py_ssize_t digits,
* Return values:
*
* - Returns -1 on syntax error (exception needs to be set, *res is untouched)
* - Returns 0 and sets *res to NULL for MemoryError/OverflowError.
* - Returns 0 and sets *res to NULL for MemoryError, OverflowError, or
* _pylong.int_from_string() errors.
* - Returns 0 and sets *res to an unsigned, unnormalized PyLong (success!).
*
* Afterwards *str is set to point to the first non-digit (which may be *str!).

0 comments on commit d0de40f

Please sign in to comment.