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
--- 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