GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
GeezerVison is showing github.com — gh-108082: Add PyErr_FormatUnraisable() function by serhiy-storchaka · Pull Request #111086 · python/cpython Conversation
|
| Similar to :c:func:`PyErr_WriteUnraisable`, but the *format* and subsequent | ||
| parameters help format the warning message; they have the same meaning and | ||
| values as in :c:func:`PyUnicode_FromFormat`. | ||
| If *format* is ``NULL``, only the traceback is printed. |
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Would you mind to give examples? I'm not sure how to use this API.
I understood that PyErr_WriteUnraisable(obj) can be written as:
PyErr_FormatUnraisable("Exception ignored in: %R", obj);
And without an exception an object, it should be:
PyErr_FormatUnraisable("Exception ignored in:");
Do the format must end with a newline character?
If format is
NULL, only the traceback is printed.
What's the usage of this mode? Is the caller expected to log something like "Exception ignored in xxx" manually?
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
PyErr_FormatUnraisable(NULL) is the same as PyErr_WriteUnraisable(NULL). It just prints the traceback, without "Exception ignored ...".
I simply documented the existing behavior for PyErr_WriteUnraisable(), and for PyErr_FormatUnraisable(NULL) the most natural way is to do the same. What alternative do you propose?
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Sorry, my remark is not specific to NULL value, but more about the whole function. I don't know which string to pass to the function. I suggest to add an example to the doc. Like:
For example, ``PyErr_WriteUnraisable(obj)`` is similar to ``PyErr_FormatUnraisable("Exception ignored in: %R", obj);``.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Would it be possible to not add this function to the limited C API in Python 3.13, but wait for Python 3.14?
Sorry, something went wrong.
There was an error while loading. Please reload this page.
What if change |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| Similar to :c:func:`PyErr_WriteUnraisable`, but the *format* and subsequent | ||
| parameters help format the warning message; they have the same meaning and | ||
| values as in :c:func:`PyUnicode_FromFormat`. | ||
| If *format* is ``NULL``, only the traceback is printed. |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
PyErr_FormatUnraisable(NULL) is the same as PyErr_WriteUnraisable(NULL). It just prints the traceback, without "Exception ignored ...".
I simply documented the existing behavior for PyErr_WriteUnraisable(), and for PyErr_FormatUnraisable(NULL) the most natural way is to do the same. What alternative do you propose?
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| (ENOENT, 'No such file or directory', 'file')) | ||
| # CRASHES setfromerrnowithfilename(ENOENT, NULL, b'error') | ||
|
|
||
| def test_err_writeunraisable(self): |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
TODO: This test should be backported.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
See #111455.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Overall, the change LGTM. I just suggest to add a small example in the doc. I also propose to change how errors are handled, but that can be done later, and I can propose a followu-p PR for that if you want.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| Similar to :c:func:`PyErr_WriteUnraisable`, but the *format* and subsequent | ||
| parameters help format the warning message; they have the same meaning and | ||
| values as in :c:func:`PyUnicode_FromFormat`. | ||
| If *format* is ``NULL``, only the traceback is printed. |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Sorry, my remark is not specific to NULL value, but more about the whole function. I don't know which string to pass to the function. I suggest to add an example to the doc. Like:
For example, ``PyErr_WriteUnraisable(obj)`` is similar to ``PyErr_FormatUnraisable("Exception ignored in: %R", obj);``.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| self.assertEqual(str(cm.unraisable.exc_value), 'oops!') | ||
| self.assertEqual(cm.unraisable.exc_traceback.tb_lineno, | ||
| firstline + 15) | ||
| self.assertIsNone(cm.unraisable.err_msg) |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
I would prefer to log an error in the error handler in this case. Ignoring silently errors doesn't help :-(
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
_PyErr_WriteUnraisableMsg() does the same: silently ignores decoding and memory errors.
I minimized changes. Other changes can be made in a separate PR.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| _PyErr_WriteUnraisableMsg(const char *err_msg_str, PyObject *obj) | ||
|
|
||
| static void | ||
| format_unraisable_v(PyObject *obj, const char *format, va_list va) |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Would it be possible to move obj to end, last parameter?
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Sure. But I would make the order of arguments inconsistent in format_unraisable() and format_unraisable_v().
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| if (format != NULL) { | ||
| err_msg = PyUnicode_FromFormatV(format, va); | ||
| if (err_msg == NULL) { | ||
| PyErr_Clear(); |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
I don't think that it's the best behavior. I would prefer to goto error. What do you think?
Maybe PyUnicode_FromString("Exception ignored in sys.unraisablehook") can become a _Py_DECLARE_STR(exc_ignored_msg, "...") + _Py_STR(exc_ignored_msg) static immortal string to avoid error 3 while handling error 2 while handling error 1.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
It is the same as in _PyErr_WriteUnraisableMsg(). Changing the behavior of _PyErr_WriteUnraisableMsg() is out of the scope of this PR.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
The main limitation of the new function is that it doesn't allow to pass an object. But I'm not sure that it's really useful. Maybe we should just deprecated this attribute of sys.unraisablehook. I don't know. I mostly added it to delegate the string formatting to the hook. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
Only 6 of about 70 use cases in CPython code actually pass an object. If it is needed, we can add yet one function, but the function which do not require to pass mandatory NULL argument in 90% of cases is more convenient. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Thanks for the short example in the doc ;-) |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
Successfully merging this pull request may close these issues.
There was an error while loading. Please reload this page.