Content-Length: 47956 | pFad | http://github.com/python/cpython/pull/136770.patch

thub.com From cb764d9dd9d6ad1e10ad89150c3634e1b567e1f9 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 6 Apr 2017 01:29:49 +0300 Subject: [PATCH 01/26] bpo-29999: repr() of ImportError now contains attributes name and path. --- Lib/test/test_exceptions.py | 30 +++++++++++++++++++++++ Objects/exceptions.c | 47 ++++++++++++++++++++++++++++++++----- 2 files changed, 71 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 57d0656487d4db..5140923b43107c 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -2595,6 +2595,36 @@ def after_with(): with ExitFails(): 1/0 self.lineno_after_raise(after_with, 1, 1) + def test_repr(self): + exc = ImportError() + self.assertEqual(repr(exc), "ImportError()") + + exc = ImportError('test') + self.assertEqual(repr(exc), "ImportError('test')") + + exc = ImportError('test', 'case') + self.assertEqual(repr(exc), "ImportError('test', 'case')") + + exc = ImportError(name='somemodule') + self.assertEqual(repr(exc), "ImportError(name='somemodule')") + + exc = ImportError('test', name='somemodule') + self.assertEqual(repr(exc), "ImportError('test', name='somemodule')") + + exc = ImportError(path='somepath') + self.assertEqual(repr(exc), "ImportError(path='somepath')") + + exc = ImportError('test', path='somepath') + self.assertEqual(repr(exc), "ImportError('test', path='somepath')") + + exc = ImportError(name='somename', path='somepath') + self.assertEqual(repr(exc), + "ImportError(name='somename', path='somepath')") + + exc = ImportError('test', name='somename', path='somepath') + self.assertEqual(repr(exc), + "ImportError('test', name='somename', path='somepath')") + if __name__ == '__main__': unittest.main() diff --git a/Objects/exceptions.c b/Objects/exceptions.c index b17cac83551670..ff0122c6aa2fa6 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -1864,6 +1864,30 @@ ImportError_reduce(PyObject *self, PyObject *Py_UNUSED(ignored)) return res; } +static PyObject * +ImportError_repr(PyImportErrorObject *self) +{ + int hasargs = PyTuple_GET_SIZE(((PyBaseExceptionObject *)self)->args) != 0; + PyObject *r = BaseException_repr((PyBaseExceptionObject *)self); + if (r && (self->name || self->path)) { + /* remove ')' */ + Py_SETREF(r, PyUnicode_Substring(r, 0, PyUnicode_GET_LENGTH(r) - 1)); + if (r && self->name) { + Py_SETREF(r, PyUnicode_FromFormat("%U%sname=%R", + r, hasargs ? ", " : "", self->name)); + hasargs = 1; + } + if (r && self->path) { + Py_SETREF(r, PyUnicode_FromFormat("%U%spath=%R", + r, hasargs ? ", " : "", self->path)); + } + if (r) { + Py_SETREF(r, PyUnicode_FromFormat("%U)", r)); + } + } + return r; +} + static PyMemberDef ImportError_members[] = { {"msg", _Py_T_OBJECT, offsetof(PyImportErrorObject, msg), 0, PyDoc_STR("exception message")}, @@ -1881,12 +1905,23 @@ static PyMethodDef ImportError_methods[] = { {NULL} }; -ComplexExtendsException(PyExc_Exception, ImportError, - ImportError, 0 /* new */, - ImportError_methods, ImportError_members, - 0 /* getset */, ImportError_str, - "Import can't find module, or can't find name in " - "module."); +static PyTypeObject _PyExc_ImportError = { + PyVarObject_HEAD_INIT(NULL, 0) + "ImportError", + sizeof(PyImportErrorObject), 0, + (destructor)ImportError_dealloc, 0, 0, 0, 0, + (reprfunc)ImportError_repr, 0, 0, 0, 0, 0, + (reprfunc)ImportError_str, 0, 0, 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, + PyDoc_STR("Import can't find module, or can't find name in " + "module."), + (traverseproc)ImportError_traverse, + (inquiry)ImportError_clear, 0, 0, 0, 0, ImportError_methods, + ImportError_members, 0, &_PyExc_Exception, + 0, 0, 0, offsetof(PyImportErrorObject, dict), + (initproc)ImportError_init, +}; +PyObject *PyExc_ImportError = (PyObject *)&_PyExc_ImportError; /* * ModuleNotFoundError extends ImportError From db41c7da327b82b9e9989ec03ab2c28437463f90 Mon Sep 17 00:00:00 2001 From: Oleg Iarygin Date: Sun, 12 Feb 2023 22:12:10 +0400 Subject: [PATCH 02/26] Use GitHub Actions version of Bedevere --- .github/workflows/trigger-bots.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 .github/workflows/trigger-bots.yml diff --git a/.github/workflows/trigger-bots.yml b/.github/workflows/trigger-bots.yml new file mode 100644 index 00000000000000..995ca2658bf173 --- /dev/null +++ b/.github/workflows/trigger-bots.yml @@ -0,0 +1,20 @@ +name: Bots + +on: + # PR synchronization is a push into a branch associated with the PR + pull_request: + types: [opened, edited, synchronize, labeled, unlabeled] + issue_comment: + types: [created, edited] + pull_request_review_comment: + types: [created, edited] + +jobs: + call_bedevere: + name: Call Bedevere + runs-on: ubuntu-latest + steps: + - uses: arhadthedev/bedevere@c51d1d2d5c7a9cec31ce16af209f42a5905070dd + with: + token: ${{ secrets.BEDEVERE_PAT }} + event: ${{ toJSON(github.event) }} From 1caeb91017146d86dfc0cb812f8b776a342701ff Mon Sep 17 00:00:00 2001 From: Oleg Iarygin Date: Mon, 13 Feb 2023 21:27:04 +0400 Subject: [PATCH 03/26] Add the news entry back --- .../2023-02-13-21-26-54.gh-issue-74185.Sk3O7m.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2023-02-13-21-26-54.gh-issue-74185.Sk3O7m.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2023-02-13-21-26-54.gh-issue-74185.Sk3O7m.rst b/Misc/NEWS.d/next/Core_and_Builtins/2023-02-13-21-26-54.gh-issue-74185.Sk3O7m.rst new file mode 100644 index 00000000000000..3a992bfe6b8413 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2023-02-13-21-26-54.gh-issue-74185.Sk3O7m.rst @@ -0,0 +1,2 @@ +:meth:`repr` of :class:`ImportError` now contains attributes name and path. +Patch by Serhiy Storchaka. From 7f29270d2ff442f62a532dfe3a7d211e2f58977e Mon Sep 17 00:00:00 2001 From: Oleg Iarygin Date: Mon, 13 Feb 2023 21:28:52 +0400 Subject: [PATCH 04/26] Remove an accidentally included untracked file --- .github/workflows/trigger-bots.yml | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100644 .github/workflows/trigger-bots.yml diff --git a/.github/workflows/trigger-bots.yml b/.github/workflows/trigger-bots.yml deleted file mode 100644 index 995ca2658bf173..00000000000000 --- a/.github/workflows/trigger-bots.yml +++ /dev/null @@ -1,20 +0,0 @@ -name: Bots - -on: - # PR synchronization is a push into a branch associated with the PR - pull_request: - types: [opened, edited, synchronize, labeled, unlabeled] - issue_comment: - types: [created, edited] - pull_request_review_comment: - types: [created, edited] - -jobs: - call_bedevere: - name: Call Bedevere - runs-on: ubuntu-latest - steps: - - uses: arhadthedev/bedevere@c51d1d2d5c7a9cec31ce16af209f42a5905070dd - with: - token: ${{ secrets.BEDEVERE_PAT }} - event: ${{ toJSON(github.event) }} From c80e056c025b2124152917bb97cd13e358c833f6 Mon Sep 17 00:00:00 2001 From: ynir3 Date: Sat, 19 Jul 2025 10:04:37 +0200 Subject: [PATCH 05/26] first commit --- .../2023-02-13-21-26-54.gh-issue-74185.Sk3O7m.rst | 2 -- Objects/exceptions.c | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2023-02-13-21-26-54.gh-issue-74185.Sk3O7m.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2023-02-13-21-26-54.gh-issue-74185.Sk3O7m.rst b/Misc/NEWS.d/next/Core_and_Builtins/2023-02-13-21-26-54.gh-issue-74185.Sk3O7m.rst deleted file mode 100644 index 3a992bfe6b8413..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2023-02-13-21-26-54.gh-issue-74185.Sk3O7m.rst +++ /dev/null @@ -1,2 +0,0 @@ -:meth:`repr` of :class:`ImportError` now contains attributes name and path. -Patch by Serhiy Storchaka. diff --git a/Objects/exceptions.c b/Objects/exceptions.c index ff0122c6aa2fa6..344d961b09b357 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -1868,7 +1868,7 @@ static PyObject * ImportError_repr(PyImportErrorObject *self) { int hasargs = PyTuple_GET_SIZE(((PyBaseExceptionObject *)self)->args) != 0; - PyObject *r = BaseException_repr((PyBaseExceptionObject *)self); + PyObject *r = BaseException_repr((PyObject *)self); if (r && (self->name || self->path)) { /* remove ')' */ Py_SETREF(r, PyUnicode_Substring(r, 0, PyUnicode_GET_LENGTH(r) - 1)); From 126be2061860537ec963915711c831387b4b365f Mon Sep 17 00:00:00 2001 From: ynir3 Date: Sat, 19 Jul 2025 10:23:59 +0200 Subject: [PATCH 06/26] add test_ModuleNotFoundError_repr_with_failed_import --- Lib/test/test_exceptions.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 5140923b43107c..747fd603907d69 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -2595,6 +2595,7 @@ def after_with(): with ExitFails(): 1/0 self.lineno_after_raise(after_with, 1, 1) + def test_repr(self): exc = ImportError() self.assertEqual(repr(exc), "ImportError()") @@ -2624,6 +2625,22 @@ def test_repr(self): exc = ImportError('test', name='somename', path='somepath') self.assertEqual(repr(exc), "ImportError('test', name='somename', path='somepath')") + + exc = ModuleNotFoundError('test', name='somename', path='somepath') + self.assertEqual(repr(exc), + "ModuleNotFoundError('test', name='somename', path='somepath')") + + def test_importerror_name_and_path(self): + try: + import does_not_exist # noqa: F401 + except ModuleNotFoundError as e: + self.assertEqual(e.name, "does_not_exist") + self.assertIsNone(e.path) + + self.assertEqual(repr(e), + "ModuleNotFoundError(\"No module named 'does_not_exist'\", name='does_not_exist')") + else: + self.fail("Expected ModuleNotFoundError was not raised") if __name__ == '__main__': From 4a97f5cc2dff67e0cf33d8a931e2f480e1d2ee90 Mon Sep 17 00:00:00 2001 From: ynir3 Date: Sat, 19 Jul 2025 10:26:12 +0200 Subject: [PATCH 07/26] add test_ModuleNotFoundError_repr_with_failed_import --- Lib/test/test_exceptions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 747fd603907d69..46397f5ab1a08b 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -2630,9 +2630,9 @@ def test_repr(self): self.assertEqual(repr(exc), "ModuleNotFoundError('test', name='somename', path='somepath')") - def test_importerror_name_and_path(self): + def test_ModuleNotFoundError_repr_with_failed_import(self): try: - import does_not_exist # noqa: F401 + import does_not_exist # type: ignore[import] except ModuleNotFoundError as e: self.assertEqual(e.name, "does_not_exist") self.assertIsNone(e.path) From 852da8c7a39c9c5191fd00b74c4fb81c20de44ea Mon Sep 17 00:00:00 2001 From: ynir3 Date: Sat, 19 Jul 2025 10:36:30 +0200 Subject: [PATCH 08/26] add blurb --- .../2025-07-19-10-35-31.gh-issue-74185.7hPCA5.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-07-19-10-35-31.gh-issue-74185.7hPCA5.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-19-10-35-31.gh-issue-74185.7hPCA5.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-19-10-35-31.gh-issue-74185.7hPCA5.rst new file mode 100644 index 00000000000000..d5fef8dc6e1c0b --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-19-10-35-31.gh-issue-74185.7hPCA5.rst @@ -0,0 +1,2 @@ +:meth:`repr` of :class:`ImportError` now contains attributes name and path. +Patch by Serhiy Storchaka, Oleg Iarygin, and Yoav Nir From 6ab73622820365efe0372c21f658ed445646091f Mon Sep 17 00:00:00 2001 From: ynir3 Date: Sat, 19 Jul 2025 10:42:34 +0200 Subject: [PATCH 09/26] add noqa:F401 --- 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 46397f5ab1a08b..fbf1c917bcbbea 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -2632,7 +2632,7 @@ def test_repr(self): def test_ModuleNotFoundError_repr_with_failed_import(self): try: - import does_not_exist # type: ignore[import] + import does_not_exist # type: ignore[import] # noqa: F401 except ModuleNotFoundError as e: self.assertEqual(e.name, "does_not_exist") self.assertIsNone(e.path) From 12c2293635c5e2af566e8d3a6e29968fa11ba66a Mon Sep 17 00:00:00 2001 From: ynir3 Date: Sat, 19 Jul 2025 10:49:56 +0200 Subject: [PATCH 10/26] remove whitespace --- Lib/test/test_exceptions.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index fbf1c917bcbbea..1db6d38709269c 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -2642,6 +2642,5 @@ def test_ModuleNotFoundError_repr_with_failed_import(self): else: self.fail("Expected ModuleNotFoundError was not raised") - if __name__ == '__main__': unittest.main() From a53da379c26ccef190ca4efa27aa3d80312bfcbd Mon Sep 17 00:00:00 2001 From: ynir3 Date: Sat, 19 Jul 2025 10:53:47 +0200 Subject: [PATCH 11/26] fix trailing-whitespace --- 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 1db6d38709269c..9f1c3b545bda6d 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -2625,7 +2625,7 @@ def test_repr(self): exc = ImportError('test', name='somename', path='somepath') self.assertEqual(repr(exc), "ImportError('test', name='somename', path='somepath')") - + exc = ModuleNotFoundError('test', name='somename', path='somepath') self.assertEqual(repr(exc), "ModuleNotFoundError('test', name='somename', path='somepath')") From 5b6d626086fcb9996172361cf4f62e679c7be670 Mon Sep 17 00:00:00 2001 From: ynir3 Date: Sat, 19 Jul 2025 11:23:15 +0200 Subject: [PATCH 12/26] use ComplexExtendsException --- Objects/exceptions.c | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/Objects/exceptions.c b/Objects/exceptions.c index 344d961b09b357..3ce822b0365ff4 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -1905,23 +1905,12 @@ static PyMethodDef ImportError_methods[] = { {NULL} }; -static PyTypeObject _PyExc_ImportError = { - PyVarObject_HEAD_INIT(NULL, 0) - "ImportError", - sizeof(PyImportErrorObject), 0, - (destructor)ImportError_dealloc, 0, 0, 0, 0, - (reprfunc)ImportError_repr, 0, 0, 0, 0, 0, - (reprfunc)ImportError_str, 0, 0, 0, - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, - PyDoc_STR("Import can't find module, or can't find name in " - "module."), - (traverseproc)ImportError_traverse, - (inquiry)ImportError_clear, 0, 0, 0, 0, ImportError_methods, - ImportError_members, 0, &_PyExc_Exception, - 0, 0, 0, offsetof(PyImportErrorObject, dict), - (initproc)ImportError_init, -}; -PyObject *PyExc_ImportError = (PyObject *)&_PyExc_ImportError; +ComplexExtendsException(PyExc_Exception, ImportError, + ImportError, 0 /* new */, + ImportError_methods, ImportError_members, + 0 /* getset */, ImportError_str, + "Import can't find module, or can't find name in " + "module."); /* * ModuleNotFoundError extends ImportError From 951e0a112e3e8b97e984f0a833537e984bbd2b53 Mon Sep 17 00:00:00 2001 From: ynir3 Date: Sat, 19 Jul 2025 11:56:40 +0200 Subject: [PATCH 13/26] return to non-macro style --- Objects/exceptions.c | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/Objects/exceptions.c b/Objects/exceptions.c index 3ce822b0365ff4..0419471e0efa85 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -1865,21 +1865,23 @@ ImportError_reduce(PyObject *self, PyObject *Py_UNUSED(ignored)) } static PyObject * -ImportError_repr(PyImportErrorObject *self) +ImportError_repr(PyObject *self) { int hasargs = PyTuple_GET_SIZE(((PyBaseExceptionObject *)self)->args) != 0; - PyObject *r = BaseException_repr((PyObject *)self); - if (r && (self->name || self->path)) { + PyObject *r = BaseException_repr(self); + 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 && self->name) { + if (r && exc->name) { Py_SETREF(r, PyUnicode_FromFormat("%U%sname=%R", - r, hasargs ? ", " : "", self->name)); + r, hasargs ? ", " : "", exc->name)); hasargs = 1; } - if (r && self->path) { + if (r && exc->path) { Py_SETREF(r, PyUnicode_FromFormat("%U%spath=%R", - r, hasargs ? ", " : "", self->path)); + r, hasargs ? ", " : "", exc->path)); } if (r) { Py_SETREF(r, PyUnicode_FromFormat("%U)", r)); @@ -1905,12 +1907,23 @@ static PyMethodDef ImportError_methods[] = { {NULL} }; -ComplexExtendsException(PyExc_Exception, ImportError, - ImportError, 0 /* new */, - ImportError_methods, ImportError_members, - 0 /* getset */, ImportError_str, - "Import can't find module, or can't find name in " - "module."); +static PyTypeObject _PyExc_ImportError = { + PyVarObject_HEAD_INIT(NULL, 0) + "ImportError", + sizeof(PyImportErrorObject), 0, + (destructor)ImportError_dealloc, 0, 0, 0, 0, + ImportError_repr, 0, 0, 0, 0, 0, + ImportError_str, 0, 0, 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, + PyDoc_STR("Import can't find module, or can't find name in " + "module."), + (traverseproc)ImportError_traverse, + (inquiry)ImportError_clear, 0, 0, 0, 0, ImportError_methods, + ImportError_members, 0, &_PyExc_Exception, + 0, 0, 0, offsetof(PyImportErrorObject, dict), + (initproc)ImportError_init, +}; +PyObject *PyExc_ImportError = (PyObject *)&_PyExc_ImportError; /* * ModuleNotFoundError extends ImportError From 8fbfd18afc103bb12278f70d4dcbb308cc9367dc Mon Sep 17 00:00:00 2001 From: ynir3 Date: Sat, 19 Jul 2025 12:11:23 +0200 Subject: [PATCH 14/26] use modern field initializers --- Objects/exceptions.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/Objects/exceptions.c b/Objects/exceptions.c index 0419471e0efa85..07309c2c911298 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -1909,19 +1909,20 @@ static PyMethodDef ImportError_methods[] = { static PyTypeObject _PyExc_ImportError = { PyVarObject_HEAD_INIT(NULL, 0) - "ImportError", - sizeof(PyImportErrorObject), 0, - (destructor)ImportError_dealloc, 0, 0, 0, 0, - ImportError_repr, 0, 0, 0, 0, 0, - ImportError_str, 0, 0, 0, - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, - PyDoc_STR("Import can't find module, or can't find name in " - "module."), - (traverseproc)ImportError_traverse, - (inquiry)ImportError_clear, 0, 0, 0, 0, ImportError_methods, - ImportError_members, 0, &_PyExc_Exception, - 0, 0, 0, offsetof(PyImportErrorObject, dict), - (initproc)ImportError_init, + .tp_name = "ImportError", + .tp_basicsize = sizeof(PyImportErrorObject), + .tp_dealloc = (destructor)ImportError_dealloc, + .tp_repr = ImportError_repr, + .tp_str = (reprfunc)ImportError_str, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, + .tp_doc = PyDoc_STR("Import can't find module, or can't find name in module."), + .tp_traverse = (traverseproc)ImportError_traverse, + .tp_clear = (inquiry)ImportError_clear, + .tp_methods = ImportError_methods, + .tp_members = ImportError_members, + .tp_base = &_PyExc_Exception, + .tp_dictoffset = offsetof(PyImportErrorObject, dict), + .tp_init = (initproc)ImportError_init, }; PyObject *PyExc_ImportError = (PyObject *)&_PyExc_ImportError; From 458bcd05d22e2b7f75005dc693ecf190ffadd7b3 Mon Sep 17 00:00:00 2001 From: ynir3 Date: Sat, 19 Jul 2025 12:12:48 +0200 Subject: [PATCH 15/26] remove un-necessary casts --- Objects/exceptions.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Objects/exceptions.c b/Objects/exceptions.c index 07309c2c911298..65a3ee1626ebf9 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -1911,18 +1911,18 @@ static PyTypeObject _PyExc_ImportError = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "ImportError", .tp_basicsize = sizeof(PyImportErrorObject), - .tp_dealloc = (destructor)ImportError_dealloc, + .tp_dealloc = ImportError_dealloc, .tp_repr = ImportError_repr, - .tp_str = (reprfunc)ImportError_str, + .tp_str = ImportError_str, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, .tp_doc = PyDoc_STR("Import can't find module, or can't find name in module."), - .tp_traverse = (traverseproc)ImportError_traverse, - .tp_clear = (inquiry)ImportError_clear, + .tp_traverse = ImportError_traverse, + .tp_clear = ImportError_clear, .tp_methods = ImportError_methods, .tp_members = ImportError_members, .tp_base = &_PyExc_Exception, .tp_dictoffset = offsetof(PyImportErrorObject, dict), - .tp_init = (initproc)ImportError_init, + .tp_init = ImportError_init, }; PyObject *PyExc_ImportError = (PyObject *)&_PyExc_ImportError; From fa2f884b23ca86a178b9e89c69a914269635b39c Mon Sep 17 00:00:00 2001 From: ynir3 Date: Sat, 19 Jul 2025 12:52:40 +0200 Subject: [PATCH 16/26] use PyUnicodeWriter --- Objects/exceptions.c | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/Objects/exceptions.c b/Objects/exceptions.c index 65a3ee1626ebf9..af39b3470af04e 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -1870,24 +1870,35 @@ ImportError_repr(PyObject *self) int hasargs = PyTuple_GET_SIZE(((PyBaseExceptionObject *)self)->args) != 0; PyObject *r = BaseException_repr(self); PyImportErrorObject *exc = PyImportErrorObject_CAST(self); - + PyUnicodeWriter *writer = PyUnicodeWriter_Create(0); + if (writer == NULL) goto error; + if (PyUnicodeWriter_WriteSubstring(writer, r, 0, PyUnicode_GET_LENGTH(r)-1) < 0) goto error; 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)); + if (exc->name) { + if (hasargs) { + if (PyUnicodeWriter_WriteASCII(writer, ", ", 2) < 0) goto error; + } + if (PyUnicodeWriter_WriteASCII(writer, "name='", 6) < 0) goto error; + if (PyUnicodeWriter_WriteSubstring(writer, exc->name, 0, PyUnicode_GET_LENGTH(exc->name)) < 0) goto error; + if (PyUnicodeWriter_WriteASCII(writer, "'", 1) < 0) goto error; hasargs = 1; } - if (r && exc->path) { - Py_SETREF(r, PyUnicode_FromFormat("%U%spath=%R", - r, hasargs ? ", " : "", exc->path)); - } - if (r) { - Py_SETREF(r, PyUnicode_FromFormat("%U)", r)); + if (exc->path) { + if (hasargs) { + if (PyUnicodeWriter_WriteASCII(writer, ", ", 2) < 0) goto error; + } + if (PyUnicodeWriter_WriteASCII(writer, "path='", 6) < 0) goto error; + if (PyUnicodeWriter_WriteSubstring(writer, exc->path, 0, PyUnicode_GET_LENGTH(exc->path)) < 0) goto error; + if (PyUnicodeWriter_WriteASCII(writer, "'", 1) < 0) goto error; } } - return r; + if (PyUnicodeWriter_WriteASCII(writer, ")", 1) < 0) goto error; + return PyUnicodeWriter_Finish(writer); + + error: + Py_XDECREF(r); + PyUnicodeWriter_Discard(writer); + return NULL; } static PyMemberDef ImportError_members[] = { From 35a6a292f49e56481be042596540d8f92dcc55a6 Mon Sep 17 00:00:00 2001 From: ynir3 Date: Sat, 19 Jul 2025 12:55:15 +0200 Subject: [PATCH 17/26] fix trailing whitespace --- Objects/exceptions.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Objects/exceptions.c b/Objects/exceptions.c index af39b3470af04e..c0bdc07649b0c7 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -1874,7 +1874,7 @@ ImportError_repr(PyObject *self) if (writer == NULL) goto error; if (PyUnicodeWriter_WriteSubstring(writer, r, 0, PyUnicode_GET_LENGTH(r)-1) < 0) goto error; if (r && (exc->name || exc->path)) { - if (exc->name) { + if (exc->name) { if (hasargs) { if (PyUnicodeWriter_WriteASCII(writer, ", ", 2) < 0) goto error; } From 6e416c650eb8153a3bacf13f95ea4dcd7e9cec02 Mon Sep 17 00:00:00 2001 From: ynir3 Date: Sat, 19 Jul 2025 13:01:43 +0200 Subject: [PATCH 18/26] reduce nesting --- Objects/exceptions.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/Objects/exceptions.c b/Objects/exceptions.c index c0bdc07649b0c7..e7ecfff1abe154 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -1873,24 +1873,22 @@ ImportError_repr(PyObject *self) PyUnicodeWriter *writer = PyUnicodeWriter_Create(0); if (writer == NULL) goto error; if (PyUnicodeWriter_WriteSubstring(writer, r, 0, PyUnicode_GET_LENGTH(r)-1) < 0) goto error; - if (r && (exc->name || exc->path)) { - if (exc->name) { - if (hasargs) { - if (PyUnicodeWriter_WriteASCII(writer, ", ", 2) < 0) goto error; - } - if (PyUnicodeWriter_WriteASCII(writer, "name='", 6) < 0) goto error; - if (PyUnicodeWriter_WriteSubstring(writer, exc->name, 0, PyUnicode_GET_LENGTH(exc->name)) < 0) goto error; - if (PyUnicodeWriter_WriteASCII(writer, "'", 1) < 0) goto error; - hasargs = 1; + if (exc->name) { + if (hasargs) { + if (PyUnicodeWriter_WriteASCII(writer, ", ", 2) < 0) goto error; } - if (exc->path) { - if (hasargs) { - if (PyUnicodeWriter_WriteASCII(writer, ", ", 2) < 0) goto error; - } - if (PyUnicodeWriter_WriteASCII(writer, "path='", 6) < 0) goto error; - if (PyUnicodeWriter_WriteSubstring(writer, exc->path, 0, PyUnicode_GET_LENGTH(exc->path)) < 0) goto error; - if (PyUnicodeWriter_WriteASCII(writer, "'", 1) < 0) goto error; + if (PyUnicodeWriter_WriteASCII(writer, "name='", 6) < 0) goto error; + if (PyUnicodeWriter_WriteSubstring(writer, exc->name, 0, PyUnicode_GET_LENGTH(exc->name)) < 0) goto error; + if (PyUnicodeWriter_WriteASCII(writer, "'", 1) < 0) goto error; + hasargs = 1; + } + if (exc->path) { + if (hasargs) { + if (PyUnicodeWriter_WriteASCII(writer, ", ", 2) < 0) goto error; } + if (PyUnicodeWriter_WriteASCII(writer, "path='", 6) < 0) goto error; + if (PyUnicodeWriter_WriteSubstring(writer, exc->path, 0, PyUnicode_GET_LENGTH(exc->path)) < 0) goto error; + if (PyUnicodeWriter_WriteASCII(writer, "'", 1) < 0) goto error; } if (PyUnicodeWriter_WriteASCII(writer, ")", 1) < 0) goto error; return PyUnicodeWriter_Finish(writer); From aa75f6aad0875698531b182b3912324705e68833 Mon Sep 17 00:00:00 2001 From: ynir3 Date: Sat, 19 Jul 2025 13:14:39 +0200 Subject: [PATCH 19/26] use PyUnicdodeWriter_Format and if statement braces --- Objects/exceptions.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/Objects/exceptions.c b/Objects/exceptions.c index e7ecfff1abe154..9c19139681f35c 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -1871,24 +1871,32 @@ ImportError_repr(PyObject *self) PyObject *r = BaseException_repr(self); PyImportErrorObject *exc = PyImportErrorObject_CAST(self); PyUnicodeWriter *writer = PyUnicodeWriter_Create(0); - if (writer == NULL) goto error; - if (PyUnicodeWriter_WriteSubstring(writer, r, 0, PyUnicode_GET_LENGTH(r)-1) < 0) goto error; + if (writer == NULL) { + goto error; + } + if (PyUnicodeWriter_WriteSubstring(writer, r, 0, PyUnicode_GET_LENGTH(r)-1) < 0) { + goto error; + } if (exc->name) { if (hasargs) { - if (PyUnicodeWriter_WriteASCII(writer, ", ", 2) < 0) goto error; + if (PyUnicodeWriter_WriteASCII(writer, ", ", 2) < 0) { + goto error; + } + } + if (PyUnicodeWriter_Format(writer, "name=%R", exc->name) < 0) { + goto error; } - if (PyUnicodeWriter_WriteASCII(writer, "name='", 6) < 0) goto error; - if (PyUnicodeWriter_WriteSubstring(writer, exc->name, 0, PyUnicode_GET_LENGTH(exc->name)) < 0) goto error; - if (PyUnicodeWriter_WriteASCII(writer, "'", 1) < 0) goto error; hasargs = 1; } if (exc->path) { if (hasargs) { - if (PyUnicodeWriter_WriteASCII(writer, ", ", 2) < 0) goto error; + if (PyUnicodeWriter_WriteASCII(writer, ", ", 2) < 0) { + goto error; + } + } + if (PyUnicodeWriter_Format(writer, "path=%R", exc->path) < 0) { + goto error; } - if (PyUnicodeWriter_WriteASCII(writer, "path='", 6) < 0) goto error; - if (PyUnicodeWriter_WriteSubstring(writer, exc->path, 0, PyUnicode_GET_LENGTH(exc->path)) < 0) goto error; - if (PyUnicodeWriter_WriteASCII(writer, "'", 1) < 0) goto error; } if (PyUnicodeWriter_WriteASCII(writer, ")", 1) < 0) goto error; return PyUnicodeWriter_Finish(writer); From 8b5e4edb254e54def0bba8ddbbf5eb5a3a89f0d7 Mon Sep 17 00:00:00 2001 From: ynir3 Date: Sat, 19 Jul 2025 13:22:23 +0200 Subject: [PATCH 20/26] indentation --- Lib/test/test_exceptions.py | 14 ++++++-------- Objects/exceptions.c | 8 ++++---- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 9f1c3b545bda6d..b0ecf6de4dccec 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -2631,16 +2631,14 @@ def test_repr(self): "ModuleNotFoundError('test', name='somename', path='somepath')") def test_ModuleNotFoundError_repr_with_failed_import(self): - try: + with self.assertRaises(ModuleNotFoundError) as cm: import does_not_exist # type: ignore[import] # noqa: F401 - except ModuleNotFoundError as e: - self.assertEqual(e.name, "does_not_exist") - self.assertIsNone(e.path) - self.assertEqual(repr(e), - "ModuleNotFoundError(\"No module named 'does_not_exist'\", name='does_not_exist')") - else: - self.fail("Expected ModuleNotFoundError was not raised") + self.assertEqual(cm.exception.name, "does_not_exist") + self.assertIsNone(cm.exception.path) + + self.assertEqual(repr(cm.exception), + "ModuleNotFoundError(\"No module named 'does_not_exist'\", name='does_not_exist')") if __name__ == '__main__': unittest.main() diff --git a/Objects/exceptions.c b/Objects/exceptions.c index 9c19139681f35c..337c11d2a81f29 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -1901,10 +1901,10 @@ ImportError_repr(PyObject *self) if (PyUnicodeWriter_WriteASCII(writer, ")", 1) < 0) goto error; return PyUnicodeWriter_Finish(writer); - error: - Py_XDECREF(r); - PyUnicodeWriter_Discard(writer); - return NULL; +error: + Py_XDECREF(r); + PyUnicodeWriter_Discard(writer); + return NULL; } static PyMemberDef ImportError_members[] = { From 28545e50f6ca0ab56fd6b6480aa9892296e09e91 Mon Sep 17 00:00:00 2001 From: ynir3 Date: Sat, 19 Jul 2025 14:55:17 +0200 Subject: [PATCH 21/26] move decref --- Objects/exceptions.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/Objects/exceptions.c b/Objects/exceptions.c index 337c11d2a81f29..4158d94262bc1f 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -1868,15 +1868,19 @@ static PyObject * ImportError_repr(PyObject *self) { int hasargs = PyTuple_GET_SIZE(((PyBaseExceptionObject *)self)->args) != 0; - PyObject *r = BaseException_repr(self); PyImportErrorObject *exc = PyImportErrorObject_CAST(self); PyUnicodeWriter *writer = PyUnicodeWriter_Create(0); if (writer == NULL) { goto error; } - if (PyUnicodeWriter_WriteSubstring(writer, r, 0, PyUnicode_GET_LENGTH(r)-1) < 0) { + PyObject *r = BaseException_repr(self); + 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) { @@ -1898,11 +1902,14 @@ ImportError_repr(PyObject *self) goto error; } } - if (PyUnicodeWriter_WriteASCII(writer, ")", 1) < 0) goto error; + + if (PyUnicodeWriter_WriteASCII(writer, ")", 1) < 0) { + goto error; + } + return PyUnicodeWriter_Finish(writer); error: - Py_XDECREF(r); PyUnicodeWriter_Discard(writer); return NULL; } @@ -1932,7 +1939,9 @@ static PyTypeObject _PyExc_ImportError = { .tp_repr = ImportError_repr, .tp_str = ImportError_str, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, - .tp_doc = PyDoc_STR("Import can't find module, or can't find name in module."), + .tp_doc = PyDoc_STR( + "Import can't find module, " + "or can't find name in module."), .tp_traverse = ImportError_traverse, .tp_clear = ImportError_clear, .tp_methods = ImportError_methods, From 4f63193f7d86b40f6ec10065a59652246421db58 Mon Sep 17 00:00:00 2001 From: ynir3 Date: Sun, 20 Jul 2025 10:11:07 +0200 Subject: [PATCH 22/26] check baseException_repr failure, add 3.15rst --- Doc/whatsnew/3.15.rst | 4 ++++ Lib/test/test_exceptions.py | 1 + .../2025-07-19-10-35-31.gh-issue-74185.7hPCA5.rst | 3 ++- Objects/exceptions.c | 5 ++++- 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index fe3d45b83a512e..c7e707e5d0dc32 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -200,6 +200,10 @@ Other language changes * Several error messages incorrectly using the term "argument" have been corrected. (Contributed by Stan Ulbrych in :gh:`133382`.) +* The :meth:`repr` of :class:`ImportError` and :class:`ModuleNotFoundError` now + contains attributes name and path. + (Contributed by Serhiy Storchaka, Oleg Iarygin, and Yoav Nir in :gh:`74185`.) + New modules =========== diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index b0ecf6de4dccec..92220925641a34 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -2640,5 +2640,6 @@ def test_ModuleNotFoundError_repr_with_failed_import(self): self.assertEqual(repr(cm.exception), "ModuleNotFoundError(\"No module named 'does_not_exist'\", name='does_not_exist')") + if __name__ == '__main__': unittest.main() diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-19-10-35-31.gh-issue-74185.7hPCA5.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-19-10-35-31.gh-issue-74185.7hPCA5.rst index d5fef8dc6e1c0b..6f9715987e3fac 100644 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-19-10-35-31.gh-issue-74185.7hPCA5.rst +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-19-10-35-31.gh-issue-74185.7hPCA5.rst @@ -1,2 +1,3 @@ -:meth:`repr` of :class:`ImportError` now contains attributes name and path. +The :meth:`repr` of :class:`ImportError` and :class:`ModuleNotFoundError` now +contains attributes name and path. Patch by Serhiy Storchaka, Oleg Iarygin, and Yoav Nir diff --git a/Objects/exceptions.c b/Objects/exceptions.c index 4158d94262bc1f..a2e26174282f23 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -1874,6 +1874,9 @@ ImportError_repr(PyObject *self) goto error; } PyObject *r = BaseException_repr(self); + if (r == NULL) { + goto error; + } if (PyUnicodeWriter_WriteSubstring( writer, r, 0, PyUnicode_GET_LENGTH(r) - 1) < 0) { @@ -1903,7 +1906,7 @@ ImportError_repr(PyObject *self) } } - if (PyUnicodeWriter_WriteASCII(writer, ")", 1) < 0) { + if (PyUnicodeWriter_WriteChar(writer, ")") < 0) { goto error; } From 25f3d429f3cb1275da2dc5a6dfa2c4ba11468a26 Mon Sep 17 00:00:00 2001 From: ynir3 Date: Sun, 20 Jul 2025 10:15:34 +0200 Subject: [PATCH 23/26] fix chr c input --- Objects/exceptions.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Objects/exceptions.c b/Objects/exceptions.c index a2e26174282f23..c41a8a0b37037f 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -1906,7 +1906,7 @@ ImportError_repr(PyObject *self) } } - if (PyUnicodeWriter_WriteChar(writer, ")") < 0) { + if (PyUnicodeWriter_WriteChar(writer, ')') < 0) { goto error; } From a45ed7561d129998fb41964b454a97f9939b27f1 Mon Sep 17 00:00:00 2001 From: ynir3 Date: Sun, 20 Jul 2025 11:16:21 +0200 Subject: [PATCH 24/26] move tests, edit rst wording --- Doc/whatsnew/3.15.rst | 5 +- Lib/test/test_exceptions.py | 89 +++++++++---------- ...5-07-19-10-35-31.gh-issue-74185.7hPCA5.rst | 7 +- 3 files changed, 51 insertions(+), 50 deletions(-) diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 116b0c64d8d234..736a8fb20e52fb 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -200,8 +200,9 @@ Other language changes * Several error messages incorrectly using the term "argument" have been corrected. (Contributed by Stan Ulbrych in :gh:`133382`.) -* The :meth:`repr` of :class:`ImportError` and :class:`ModuleNotFoundError` now - contains attributes name and path. +* The :meth:`~object.__repr__` of :class:`ImportError` and :class:`ModuleNotFoundError` + now shows "name" and "path" as ``name=`` and ``path=`` if they were given + as keyword arguments at construction time. (Contributed by Serhiy Storchaka, Oleg Iarygin, and Yoav Nir in :gh:`74185`.) diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 92220925641a34..59f77f91d85e5c 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -2079,6 +2079,50 @@ def test_copy_pickle(self): self.assertEqual(exc.name, orig.name) self.assertEqual(exc.path, orig.path) + def test_repr(self): + exc = ImportError() + self.assertEqual(repr(exc), "ImportError()") + + exc = ImportError('test') + self.assertEqual(repr(exc), "ImportError('test')") + + exc = ImportError('test', 'case') + self.assertEqual(repr(exc), "ImportError('test', 'case')") + + exc = ImportError(name='somemodule') + self.assertEqual(repr(exc), "ImportError(name='somemodule')") + + exc = ImportError('test', name='somemodule') + self.assertEqual(repr(exc), "ImportError('test', name='somemodule')") + + exc = ImportError(path='somepath') + self.assertEqual(repr(exc), "ImportError(path='somepath')") + + exc = ImportError('test', path='somepath') + self.assertEqual(repr(exc), "ImportError('test', path='somepath')") + + exc = ImportError(name='somename', path='somepath') + self.assertEqual(repr(exc), + "ImportError(name='somename', path='somepath')") + + exc = ImportError('test', name='somename', path='somepath') + self.assertEqual(repr(exc), + "ImportError('test', name='somename', path='somepath')") + + exc = ModuleNotFoundError('test', name='somename', path='somepath') + self.assertEqual(repr(exc), + "ModuleNotFoundError('test', name='somename', path='somepath')") + + def test_ModuleNotFoundError_repr_with_failed_import(self): + with self.assertRaises(ModuleNotFoundError) as cm: + import does_not_exist # type: ignore[import] # noqa: F401 + + self.assertEqual(cm.exception.name, "does_not_exist") + self.assertIsNone(cm.exception.path) + + self.assertEqual(repr(cm.exception), + "ModuleNotFoundError(\"No module named 'does_not_exist'\", name='does_not_exist')") + def run_script(source): if isinstance(source, str): @@ -2596,50 +2640,5 @@ def after_with(): 1/0 self.lineno_after_raise(after_with, 1, 1) - def test_repr(self): - exc = ImportError() - self.assertEqual(repr(exc), "ImportError()") - - exc = ImportError('test') - self.assertEqual(repr(exc), "ImportError('test')") - - exc = ImportError('test', 'case') - self.assertEqual(repr(exc), "ImportError('test', 'case')") - - exc = ImportError(name='somemodule') - self.assertEqual(repr(exc), "ImportError(name='somemodule')") - - exc = ImportError('test', name='somemodule') - self.assertEqual(repr(exc), "ImportError('test', name='somemodule')") - - exc = ImportError(path='somepath') - self.assertEqual(repr(exc), "ImportError(path='somepath')") - - exc = ImportError('test', path='somepath') - self.assertEqual(repr(exc), "ImportError('test', path='somepath')") - - exc = ImportError(name='somename', path='somepath') - self.assertEqual(repr(exc), - "ImportError(name='somename', path='somepath')") - - exc = ImportError('test', name='somename', path='somepath') - self.assertEqual(repr(exc), - "ImportError('test', name='somename', path='somepath')") - - exc = ModuleNotFoundError('test', name='somename', path='somepath') - self.assertEqual(repr(exc), - "ModuleNotFoundError('test', name='somename', path='somepath')") - - def test_ModuleNotFoundError_repr_with_failed_import(self): - with self.assertRaises(ModuleNotFoundError) as cm: - import does_not_exist # type: ignore[import] # noqa: F401 - - self.assertEqual(cm.exception.name, "does_not_exist") - self.assertIsNone(cm.exception.path) - - self.assertEqual(repr(cm.exception), - "ModuleNotFoundError(\"No module named 'does_not_exist'\", name='does_not_exist')") - - if __name__ == '__main__': unittest.main() diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-19-10-35-31.gh-issue-74185.7hPCA5.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-19-10-35-31.gh-issue-74185.7hPCA5.rst index 6f9715987e3fac..128ea4049b746b 100644 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-19-10-35-31.gh-issue-74185.7hPCA5.rst +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-19-10-35-31.gh-issue-74185.7hPCA5.rst @@ -1,3 +1,4 @@ -The :meth:`repr` of :class:`ImportError` and :class:`ModuleNotFoundError` now -contains attributes name and path. -Patch by Serhiy Storchaka, Oleg Iarygin, and Yoav Nir +The :meth:`~object.__repr__` of :class:`ImportError` and :class:`ModuleNotFoundError` +now shows "name" and "path" as ``name=`` and ``path=`` if they were given +as keyword arguments at construction time. +(Contributed by Serhiy Storchaka, Oleg Iarygin, and Yoav Nir in :gh:`74185`.) From 9c09cd03a51352d3b0df7fe3f015c9a6c81cfce5 Mon Sep 17 00:00:00 2001 From: ynir3 Date: Sun, 20 Jul 2025 11:21:40 +0200 Subject: [PATCH 25/26] edit blurb --- .../2025-07-19-10-35-31.gh-issue-74185.7hPCA5.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-19-10-35-31.gh-issue-74185.7hPCA5.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-19-10-35-31.gh-issue-74185.7hPCA5.rst index 128ea4049b746b..9f69a2a5c0a354 100644 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-19-10-35-31.gh-issue-74185.7hPCA5.rst +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-19-10-35-31.gh-issue-74185.7hPCA5.rst @@ -1,4 +1,4 @@ The :meth:`~object.__repr__` of :class:`ImportError` and :class:`ModuleNotFoundError` now shows "name" and "path" as ``name=`` and ``path=`` if they were given as keyword arguments at construction time. -(Contributed by Serhiy Storchaka, Oleg Iarygin, and Yoav Nir in :gh:`74185`.) +(Contributed by Serhiy Storchaka, Oleg Iarygin, and Yoav Nir.) From ca0e2a4d1201bf83718aedd2c3b8ba7fe42d9705 Mon Sep 17 00:00:00 2001 From: ynir3 Date: Sun, 20 Jul 2025 11:45:52 +0200 Subject: [PATCH 26/26] edit blurb --- .../2025-07-19-10-35-31.gh-issue-74185.7hPCA5.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-19-10-35-31.gh-issue-74185.7hPCA5.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-19-10-35-31.gh-issue-74185.7hPCA5.rst index 9f69a2a5c0a354..d149e7b2878574 100644 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-19-10-35-31.gh-issue-74185.7hPCA5.rst +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-19-10-35-31.gh-issue-74185.7hPCA5.rst @@ -1,4 +1,4 @@ The :meth:`~object.__repr__` of :class:`ImportError` and :class:`ModuleNotFoundError` now shows "name" and "path" as ``name=`` and ``path=`` if they were given as keyword arguments at construction time. -(Contributed by Serhiy Storchaka, Oleg Iarygin, and Yoav Nir.) +Patch by Serhiy Storchaka, Oleg Iarygin, and Yoav Nir








ApplySandwichStrip

pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

Fetched URL: http://github.com/python/cpython/pull/136770.patch

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy