-
-
Notifications
You must be signed in to change notification settings - Fork 35k
gh-153785: Generate AttributeError messages from context
#153786
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
ac555bc
4f22a16
b30d676
28e04d3
e5c4922
3854563
1e88331
2fd216a
356f56e
8db0394
ebcc795
b6fda10
d624835
c50a356
7ad5204
b65a7fd
e99d875
8c29de3
6faf358
086a0c9
e5bb17e
f2507a5
9c81069
e905ab2
7d720ac
337cef4
6aa47db
4ff6a48
e00db5f
b5ce3c9
da8c723
c941657
9ea6c8a
f825f27
7b73fb8
7378e30
faf6e53
a86fde5
9b00321
df7682c
a419eb2
a7e7f0a
08f8818
b9b8d7d
cb5ae96
404359d
f28f1d5
42522c0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -215,6 +215,8 @@ The following exceptions are the exceptions that are usually raised. | |
|
|
||
| The object that was accessed for the named attribute. | ||
|
|
||
| When possible, :attr:`name` and :attr:`obj` are set automatically. | ||
|
|
||
| .. versionchanged:: 3.10 | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We dropped the
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @serhiy-storchaka, do you agree on bringing it back?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We usually do not add versionchanged for minor changes like changed error message. Otherwise our documentation would be overwhelmed by them. |
||
| Added the :attr:`name` and :attr:`obj` attributes. | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| :exc:`AttributeError`: The default error message is now generated from ``name`` | ||
| and ``obj`` attributes when both are set and the exception was constructed with | ||
| no positional arguments, or with a single positional argument equal to ``name``. | ||
| Patch by Bartosz Sławecki. |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -11,9 +11,11 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include "pycore_exceptions.h" // struct _Py_exc_state | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include "pycore_initconfig.h" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include "pycore_modsupport.h" // _PyArg_NoKeywords() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include "pycore_moduleobject.h" // _PyModule_CAST() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include "pycore_object.h" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include "pycore_pyerrors.h" // struct _PyErr_SetRaisedException | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include "pycore_tuple.h" // _PyTuple_FromPair | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include "pycore_unicodeobject.h" // _PyUnicode_Equal() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include "osdefs.h" // SEP | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include "clinic/exceptions.c.h" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -2702,6 +2704,65 @@ AttributeError_dealloc(PyObject *self) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Py_TYPE(self)->tp_free(self); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| static PyObject * | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| AttributeError_str(PyObject *op) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PyAttributeErrorObject *self = PyAttributeErrorObject_CAST(op); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PyObject *arg; // borrowed ref | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PyObject *obj = NULL, *name = NULL; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /* .name and .obj are set automatically when attribute lookup fails, so | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| synthesize a more informative message from them when the caller | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| didn't supply a meaningful one of their own -- that is, when args is | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| empty, or contains only the attribute name. Otherwise, use the | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| message the caller gave. */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Py_BEGIN_CRITICAL_SECTION(self); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| self->obj && self->name && PyUnicode_Check(self->name) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| && ((PyTuple_GET_SIZE(self->args) == 1 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| && PyUnicode_Check(arg = PyTuple_GET_ITEM(self->args, 0)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| && _PyUnicode_Equal(arg, self->name)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| || PyTuple_GET_SIZE(self->args) == 0) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
johnslavik marked this conversation as resolved.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| obj = Py_NewRef(self->obj); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name = Py_NewRef(self->name); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
serhiy-storchaka marked this conversation as resolved.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Py_END_CRITICAL_SECTION(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!obj) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert(!name); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return BaseException_str(op); /* re-acquires lock */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
johnslavik marked this conversation as resolved.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PyObject *result = NULL; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (PyModule_Check(obj)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PyModuleObject *mod = _PyModule_CAST(obj); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
johnslavik marked this conversation as resolved.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PyObject *modname; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (PyDict_GetItemRef(mod->md_dict, &_Py_ID(__name__), &modname) < 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| goto done; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (modname && PyUnicode_Check(modname)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| result = PyUnicode_FromFormat("module %R has no attribute %R", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| modname, name); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Py_DECREF(modname); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Py_XDECREF(modname); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| result = PyUnicode_FromFormat("module has no attribute %R", name); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else if (PyType_Check(obj)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| result = PyUnicode_FromFormat("type object '%N' has no attribute %R", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| obj, name); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| result = PyUnicode_FromFormat("'%T' object has no attribute %R", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| obj, name); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+2745
to
+2758
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The exc=AttributeError()
exc.name = "a'b"
exc.obj = ["list"]
print(str(exc))Current output: I suggesting using
Suggested change
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, although we could say the same thing about module names and type names, no?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using import, I don't think that you can have a module name which contains quotes. You might hack the module name to insert quotes later. For consistency, I would be fine with using %R to format the module name. It's also shorter 😁
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For the type name, quotes or other special characters are very unlikely. I don't think that it's worth it to care about these ones.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks! Changes applied.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. First of all, we should be consistent with the original error messages raised in corresponding
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree that it's worth it to use
But I disagree with that. IMO it's fine to use
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| done: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Py_DECREF(obj); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Py_DECREF(name); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return result; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| static int | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| AttributeError_traverse(PyObject *op, visitproc visit, void *arg) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -2770,7 +2831,7 @@ static PyMethodDef AttributeError_methods[] = { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ComplexExtendsException(PyExc_Exception, AttributeError, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| AttributeError, 0, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| AttributeError_methods, AttributeError_members, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 0, BaseException_str, 0, "Attribute not found."); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 0, AttributeError_str, 0, "Attribute not found."); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /* | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * SyntaxError extends Exception | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.