From c5f9c26a90915d61fb666f68df711a2c94cceff9 Mon Sep 17 00:00:00 2001 From: ynir3 Date: Wed, 13 Aug 2025 13:05:19 +0100 Subject: [PATCH 1/5] . --- Lib/test/test_exceptions.py | 17 ++++++ Objects/exceptions.c | 112 ++++++++++++++++++++++-------------- 2 files changed, 86 insertions(+), 43 deletions(-) diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 59f77f91d85e5c..980fa0e8a17e40 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -20,6 +20,7 @@ from test.support.os_helper import TESTFN, unlink from test.support.warnings_helper import check_warnings from test import support +import timeit try: import _testcapi @@ -2002,6 +2003,22 @@ def blech(self): # Note: name suggestion tests live in `test_traceback`. +class ImportErrorBenchmark(unittest.TestCase): + def test_benchmark(self): + # Create a big ImportError for testing + missing_name = "some_missing_module" + path_hint = "/this/is/a/fake/path/that/is/quite/long/and/descriptive" + exc = ImportError(f"Cannot import {missing_name}", name=missing_name, path=path_hint) + + # Define the code to benchmark + stmt = "repr(ImportError('Cannot import some_missing_module', name='some_missing_module', path='/this/is/a/fake/path/that/is/quite/long/and/descriptive'))" + + # Run benchmark + iterations = 1_000_000 # Adjust for desired accuracy + total_time = timeit.timeit(stmt, number=iterations) + avg_time = total_time / iterations + + print(f"Total time for creating ImportError: {total_time:.10f} seconds") class ImportErrorTests(unittest.TestCase): diff --git a/Objects/exceptions.c b/Objects/exceptions.c index c41a8a0b37037f..a573ae7176cda7 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -1868,54 +1868,80 @@ static PyObject * ImportError_repr(PyObject *self) { int hasargs = PyTuple_GET_SIZE(((PyBaseExceptionObject *)self)->args) != 0; - PyImportErrorObject *exc = PyImportErrorObject_CAST(self); - PyUnicodeWriter *writer = PyUnicodeWriter_Create(0); - if (writer == NULL) { - goto error; - } PyObject *r = BaseException_repr(self); - if (r == NULL) { - goto error; - } - if (PyUnicodeWriter_WriteSubstring( - writer, r, 0, PyUnicode_GET_LENGTH(r) - 1) < 0) - { - Py_XDECREF(r); - goto error; - } - Py_XDECREF(r); - if (exc->name) { - if (hasargs) { - if (PyUnicodeWriter_WriteASCII(writer, ", ", 2) < 0) { - goto error; - } - } - if (PyUnicodeWriter_Format(writer, "name=%R", exc->name) < 0) { - goto error; + PyImportErrorObject *exc = PyImportErrorObject_CAST(self); + + if (r && (exc->name || exc->path)) { + /* remove ')' */ + Py_SETREF(r, PyUnicode_Substring(r, 0, PyUnicode_GET_LENGTH(r) - 1)); + if (r && exc->name) { + Py_SETREF(r, PyUnicode_FromFormat("%U%sname=%R", + r, hasargs ? ", " : "", exc->name)); + hasargs = 1; } - hasargs = 1; - } - if (exc->path) { - if (hasargs) { - if (PyUnicodeWriter_WriteASCII(writer, ", ", 2) < 0) { - goto error; - } + if (r && exc->path) { + Py_SETREF(r, PyUnicode_FromFormat("%U%spath=%R", + r, hasargs ? ", " : "", exc->path)); } - if (PyUnicodeWriter_Format(writer, "path=%R", exc->path) < 0) { - goto error; + if (r) { + Py_SETREF(r, PyUnicode_FromFormat("%U)", r)); } } - - if (PyUnicodeWriter_WriteChar(writer, ')') < 0) { - goto error; - } - - return PyUnicodeWriter_Finish(writer); - -error: - PyUnicodeWriter_Discard(writer); - return NULL; -} + return r; +} + +// static PyObject * +// ImportError_repr(PyObject *self) +// { +// int hasargs = PyTuple_GET_SIZE(((PyBaseExceptionObject *)self)->args) != 0; +// PyImportErrorObject *exc = PyImportErrorObject_CAST(self); +// PyUnicodeWriter *writer = PyUnicodeWriter_Create(0); +// if (writer == NULL) { +// goto error; +// } +// PyObject *r = BaseException_repr(self); +// if (r == NULL) { +// goto error; +// } +// if (PyUnicodeWriter_WriteSubstring( +// writer, r, 0, PyUnicode_GET_LENGTH(r) - 1) < 0) +// { +// Py_XDECREF(r); +// goto error; +// } +// Py_XDECREF(r); +// if (exc->name) { +// if (hasargs) { +// if (PyUnicodeWriter_WriteASCII(writer, ", ", 2) < 0) { +// goto error; +// } +// } +// if (PyUnicodeWriter_Format(writer, "name=%R", exc->name) < 0) { +// goto error; +// } +// hasargs = 1; +// } +// if (exc->path) { +// if (hasargs) { +// if (PyUnicodeWriter_WriteASCII(writer, ", ", 2) < 0) { +// goto error; +// } +// } +// if (PyUnicodeWriter_Format(writer, "path=%R", exc->path) < 0) { +// goto error; +// } +// } + +// if (PyUnicodeWriter_WriteChar(writer, ')') < 0) { +// goto error; +// } + +// return PyUnicodeWriter_Finish(writer); + +// error: +// PyUnicodeWriter_Discard(writer); +// return NULL; +// } static PyMemberDef ImportError_members[] = { {"msg", _Py_T_OBJECT, offsetof(PyImportErrorObject, msg), 0, From 8e623d3732a899057e061075295b72374f6561a9 Mon Sep 17 00:00:00 2001 From: ynir3 Date: Wed, 13 Aug 2025 13:15:17 +0100 Subject: [PATCH 2/5] small cleanup --- Lib/test/test_exceptions.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 980fa0e8a17e40..1381579d21712c 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -2008,7 +2008,6 @@ def test_benchmark(self): # Create a big ImportError for testing missing_name = "some_missing_module" path_hint = "/this/is/a/fake/path/that/is/quite/long/and/descriptive" - exc = ImportError(f"Cannot import {missing_name}", name=missing_name, path=path_hint) # Define the code to benchmark stmt = "repr(ImportError('Cannot import some_missing_module', name='some_missing_module', path='/this/is/a/fake/path/that/is/quite/long/and/descriptive'))" @@ -2016,7 +2015,6 @@ def test_benchmark(self): # Run benchmark iterations = 1_000_000 # Adjust for desired accuracy total_time = timeit.timeit(stmt, number=iterations) - avg_time = total_time / iterations print(f"Total time for creating ImportError: {total_time:.10f} seconds") From 876c8b4968e4be6f9d298a6b717bae4354c0ec5b Mon Sep 17 00:00:00 2001 From: ynir3 Date: Wed, 13 Aug 2025 13:15:30 +0100 Subject: [PATCH 3/5] small cleanup --- Lib/test/test_exceptions.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 1381579d21712c..5ba986eca85925 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -2005,10 +2005,6 @@ def blech(self): class ImportErrorBenchmark(unittest.TestCase): def test_benchmark(self): - # Create a big ImportError for testing - missing_name = "some_missing_module" - path_hint = "/this/is/a/fake/path/that/is/quite/long/and/descriptive" - # Define the code to benchmark stmt = "repr(ImportError('Cannot import some_missing_module', name='some_missing_module', path='/this/is/a/fake/path/that/is/quite/long/and/descriptive'))" From 08c689ec5b2e762b076d2c709ca2eaa650b959be Mon Sep 17 00:00:00 2001 From: ynir3 Date: Wed, 13 Aug 2025 13:15:50 +0100 Subject: [PATCH 4/5] cleanup --- Lib/test/test_exceptions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 5ba986eca85925..637ea9aec3815f 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -2009,7 +2009,7 @@ def test_benchmark(self): stmt = "repr(ImportError('Cannot import some_missing_module', name='some_missing_module', path='/this/is/a/fake/path/that/is/quite/long/and/descriptive'))" # Run benchmark - iterations = 1_000_000 # Adjust for desired accuracy + iterations = 1_000_000 total_time = timeit.timeit(stmt, number=iterations) print(f"Total time for creating ImportError: {total_time:.10f} seconds") From 1651c2c77819061f296e4e20a11ad56869444f79 Mon Sep 17 00:00:00 2001 From: ynir3 Date: Wed, 13 Aug 2025 14:30:01 +0100 Subject: [PATCH 5/5] remove comments --- Lib/test/test_exceptions.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 637ea9aec3815f..482edd3c92efd6 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -2005,10 +2005,8 @@ def blech(self): class ImportErrorBenchmark(unittest.TestCase): def test_benchmark(self): - # Define the code to benchmark stmt = "repr(ImportError('Cannot import some_missing_module', name='some_missing_module', path='/this/is/a/fake/path/that/is/quite/long/and/descriptive'))" - # Run benchmark iterations = 1_000_000 total_time = timeit.timeit(stmt, number=iterations)