Repository navigation
py/modsys.c: Add sys._exc_traceback. - #11244
DavidEGrayson wants to merge 1 commit into
Conversation
2b52b5b to
e7a799e
Compare
|
Code size report: |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #11244 +/- ##
=======================================
Coverage 98.41% 98.41%
=======================================
Files 174 174
Lines 22325 22338 +13
=======================================
+ Hits 21972 21985 +13
Misses 353 353 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
First thing to ask is how would one do this in CPython? Then we need to consider if it's worth the cost (code size) and whether it should be guarded by a config macro. I would say yes it should be, but then at what level would it be enabled, eg |
|
You can get this info in CPython is like this: import traceback
def foo():
1/0
try:
foo()
except Exception as e:
tb = e.__traceback__
while tb is not None:
print("====")
print(" filename: " + str(tb.tb_frame.f_code.co_filename))
print(" line: " + str(tb.tb_lineno))
print(" name: " + str(tb.tb_frame.f_code.co_name))
tb = tb.tb_nextThis involves at least three different classes:
The Python standard library also comes with a traceback module that introduces more classes. MicroPython implements a minimal traceback module. CPython does not have |
|
I changed it so that this function is only enabled by default if |
4b5c6c3 to
d872e6e
Compare
|
This is an automated heads-up that we've just merged a Pull Request See #13763 A search suggests this PR might apply the STATIC macro to some C code. If it Although this is an automated message, feel free to @-reply to me directly if |
d872e6e to
2775717
Compare
|
Thanks for keeping this PR alive. I can see how it would be useful. To reduce code size I suggest implementing the functionality as an attribute of the exception type, rather than as a new function. So it would go in import sys
def foo():
1/0
try:
foo()
except Exception as e:
sys.print_exception(e)
print(e.__traceback__)Now, that's not fully compatible with CPython, but it's a little bit closer than having a separate And then if you don't care about CPython compatibility and you want to efficiently get the traceback data, you can use the value of |
ed19b16 to
3fc9822
Compare
9316ad0 to
3a90db5
Compare
ad0a411 to
56fbc2e
Compare
This makes it easier to provide custom formatting of exception stack traces, e.g. to make them fit on a tiny display. Signed-off-by: David (Pololu) <[email protected]>
56fbc2e to
22bb986
Compare
|
I think this is ready to be merged in. I changed it to make a list of tuples, so we can easily extend it in the future by adding to the tuple, and well-written user code will not break. And there are tests and documentation now. Perhaps the "minimal" build on Unix should not have this feature because it doesn't track line numbers. |
| "basics/class_inplace_op.py", # all special methods not supported | ||
| "basics/subclass_native_init.py", # native subclassing corner cases not support | ||
| "micropython/opt_level.py", # don't assume line numbers are stored | ||
| "micropython/traceback.py", # no line numbers, no list[N:] syntax |
There was a problem hiding this comment.
Please don't remove these (see comment below).
| # Skip platform-specific tests. | ||
| skip_tests.update(platform_tests_to_skip.get(args.platform, ())) | ||
| if args.build == "minimal": | ||
| skip_tests.update(platform_tests_to_skip.get(args.build, ())) |
There was a problem hiding this comment.
I understand why you made this change, but it's not the right approach. We should not mix up the platform with the build.
If really needed we can add a build_tests_to_skip dict, to mirror platform_tests_to_skip, but for only one test I suggest following 7db50cc and adding the same code at the top of traceback.py to skip that test automatically.
| @@ -0,0 +1,26 @@ | |||
| # This comment allows test runners like run_script_on_remote_target | |||
There was a problem hiding this comment.
Suggest calling this test exc_traceback.py.
And then adding (or changing this comment) to briefly mention what it's testing, eg Test values of BaseException.__traceback__ which are MicroPython specific".
|
This increases the size of minimal ports by quite a bit. But I think it's useful to have, and IMO more useful than But, let's do that in a separate PR, because it'll probably need changes to the test suite. |
|
@DavidEGrayson are you able to respond to the above review? If not then I can make my suggested changes during rebase and merge of this PR. |
|
@DavidEGrayson I'll leave this up to you, let me know after you've had a chance to get back to it. |
dpgeorge
left a comment
There was a problem hiding this comment.
Regarding replacing sys.print_exception(exc) with this new exc.__traceback__ feature: that might not work very well because sys.print_exception has a lot of nice features that aren't easily available with exc.__traceback__, such as errno name printing and nice formatting of the exception type and arguments.
I guess you could write Python to emulate that pretty printing. Alternatively, could add another attribute to exceptions that return a pretty exception string, eg exc.__str__ (to reuse a qstr).
| size_t *src = &data[i * TRACEBACK_ENTRY_LEN]; | ||
| mp_obj_t entry[3]; | ||
| entry[0] = MP_OBJ_NEW_QSTR(src[0]); // filename | ||
| entry[1] = MP_OBJ_NEW_SMALL_INT(src[1]); // line number |
There was a problem hiding this comment.
If MICROPY_ENABLE_SOURCE_LINE is disabled then this number is always 1. Maybe worth storing 0 (or -1?) instead, to indicate that line numbers are unavailable?
| mp_obj_t entry[3]; | ||
| entry[0] = MP_OBJ_NEW_QSTR(src[0]); // filename | ||
| entry[1] = MP_OBJ_NEW_SMALL_INT(src[1]); // line number | ||
| entry[2] = MP_OBJ_NEW_QSTR(src[2]); // block |
There was a problem hiding this comment.
src[2] may be MP_QSTRnull if the block name is unknown, which shouldn't then be converted to a qstr object.
Not sure what the best way to handle this is. Maybe change it so MP_QSTR_ is used instead of MP_QSTRnull when the block name is unknown.
This new function makes it easier to provide custom formatting of exception stack traces, for example to make them fit on a tiny 16x8-character display. (Without this, I think you'd have to call
sys.print_exception, somehow get the output as a string, and then scrape information from that string.)I'm thinking of this as an experimental function that exposes internal details of MicroPython and therefore might change in the future. That's why it has the underscore in the name.
Here is an example of its output:
The regular output from
sys.print_exceptionfor the same exception is:Both outputs were generated by the following script:
Is this the right approach for getting info about exception stack traces? I'd be happy to change the name, change the output format, add tests, or add documentation.