Skip to content
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

#3702 breaks printing an exception twice #3771

Merged
merged 1 commit into from
Dec 15, 2020

Conversation

cwalther
Copy link

Just so it isn’t forgotten, since I can’t seem to reopen #3702:

I believe the fix proposed there is wrong: It prevents printing an exception twice, which I do in #3696 (once to measure the length of the traceback, once to get the text) and which people may want to do for other reasons, it’s available from Python via sys.print_exception(). (For some reason, it also causes the terminalio screen to be drawn over the stage screen, haven’t investigated that yet.)

The problem observed in micropython#2056 is specific to adafruit_midi in that it raises the same exception instance every time, a usage that apparently wasn’t anticipated in the core. Will have to dig deeper into how exceptions work to figure out how to properly fix that. It may be nontrivial – there would need to be a way to distinguish an exception reused in the way adafruit_midi does it from one re-raised in an except block.

In fact, I’m not sure it should be fixed, since CPython appears to do the same:

Python 3.8.3 (default, Jul  8 2020, 14:25:02) 
[Clang 11.0.0 (clang-1100.0.33.17)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> e = ValueError('X')
>>> raise e
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
    <?xml version="1.0" encoding="UTF-8"?>
ValueError: X
>>> raise e
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
    <?xml version="1.0" encoding="UTF-8"?>
  File "<stdin>", line 1, in <module>
    <?xml version="1.0" encoding="UTF-8"?>
ValueError: X
>>> raise e
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
    <?xml version="1.0" encoding="UTF-8"?>
  File "<stdin>", line 1, in <module>
    <?xml version="1.0" encoding="UTF-8"?>
  File "<stdin>", line 1, in <module>
    <?xml version="1.0" encoding="UTF-8"?>
ValueError: X

So maybe the proper fix is rather to make adafruit_midi stop reusing exceptions. @kevinjwalters, looks like that would be your territory? It comes from adafruit/Adafruit_CircuitPython_MIDI@0f96357.

This reverts commit 0cd951f.

It is not a correct solution because it prevents printing the same exception twice.
@kevinjwalters
Copy link

Is the CPython behaviour specified somewhere?

@cwalther
Copy link
Author

Good question. As far as I can find, only by absence: https://docs.python.org/3/reference/datamodel.html#traceback-objects says how traceback objects are added, but there is nothing that says that any previously accumulated traceback would be cleared when an exception is raised outside of an except block.

@tannewt
Copy link
Member

tannewt commented Nov 30, 2020

@DavePutz What do you think?

@DavePutz
Copy link
Collaborator

DavePutz commented Dec 1, 2020

I don't see the value in showing multiple exceptions for a single error. It gives the impression that more than one thing went wrong. i.e. I think CPython is probably not doing it correctly. I do understand, though, the value of #3696 to get a previous traceback. Would it be worth adding a parameter to mp_obj_print_exception() to indicate that we don't want to clear i.e. when calling supervisor.get_previous_traceback() ? That would involve changing the 15 or so places in the code where mp_obj_print_exception() is called. I'm willing to do that if it is a reasonable solution.

@tannewt
Copy link
Member

tannewt commented Dec 1, 2020

Could we prevent the duplicate traceback in a different way? We could clear the traceback before computing it a second time.

@jepler
Copy link
Member

jepler commented Dec 3, 2020

It is "normal" to raise a single exception object multiple times, as in

try:
   1/random.randint(0, 10)
except ZeroDivisionError as e:
   print("unlucky")
   raise e

this second raise statement should not clear any exception frames already associated with e.

@DavePutz
Copy link
Collaborator

DavePutz commented Dec 3, 2020 via email

@cwalther
Copy link
Author

cwalther commented Dec 3, 2020

It pertains to clearing on raise, as I (perhaps unclearly) proposed in the initial post (and is what I meant when I said it’s nontrivial), not to clearing on print, as you implemented in #3702.

As far as the other proposed solutions go, I could probably live with a flag to restrict the clearing-on-print to a subset of cases, but really the more I think about it the more it feels to me like a case of garbage-in-garbage-out where the proper solution is just “don’t reuse exceptions”.

@tannewt
Copy link
Member

tannewt commented Dec 4, 2020

I agree with @cwalther. It's weird to reuse an exception object for multiple errors. The better fix for the original issue micropython#2056 is to not reuse ValueError in the MIDI library. I'll transfer the issue.

@tannewt
Copy link
Member

tannewt commented Dec 4, 2020

I've rerun the jobs for this PR too.

@cwalther
Copy link
Author

cwalther commented Dec 5, 2020

Context for confused readers (as I was at first): The moved issue is adafruit/Adafruit_CircuitPython_MIDI#28, which is why mentions of its previous number #2056 now erroneously link to micropython#2056.

Copy link
Member

@jepler jepler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[CI failure was a network problem]

@jepler jepler merged commit afcc00f into adafruit:main Dec 15, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants