Calysto / metakernel

Jupyter/IPython Kernel Tools

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

%%python prints traceback, no exception name or value

parente opened this issue · comments

%%python
def foo(x, y):
    return x / y

foo(1, 0)

in a metakernel_bash notebook shows a traceback, but doesn't include the exception name and value:

  File "/Users/parente/miniconda3/envs/spylon-kernel-dev/lib/python3.6/site-packages/metakernel/magics/python_magic.py", line 25, in exec_code
    exec(code, globals())

  File "<string>", line 4, in <module>

  File "<string>", line 2, in foo

I know the exception name and description are available because running the function that does the exec for the python magic like so:

from metakernel.magics import python_magic
z = python_magic.exec_code('''
def foo(x, y):
    return x / y
foo(1, 0)
''', globals(), None)

print(z.ename) # 'ZeroDivisionError'
print(z.evalue) # ('division by zero',)

shows the ename and evalue attributes include the additional information that is missing from the magic's default output of the traceback alone.

I'm looking into this... appears to be a change upstream in jupyter api...

Ok, I have found two things:

  1. The only thing that displays in both the console and the notebook is the traceback list.
  2. The Python traceback for an exec() is not useful.

Given 1, it makes sense to give a better "traceback" that includes the error. Also, given that this is an exec(), it makes sense to manufacture our own traceback that leaves out the details of the exec.

Three alternatives:

  1. Work a better API into Jupyter for all kernels.
  2. Come up with a standard in metakernel for all metakernel kernels
  3. Have each metakernel kernel do its own thing with errors

Unless anyone has a better idea, I'll just make the traceback better, and write some metakernel documentation. There is a good reason to work with the Jupyter API: by signaling an error, the system will be able to handle it, and do the "right thing" (eg, stopping running, etc).

Additionally, it would be handy to expand the Jupyter API to allow more options. For example, Calysto Scheme displays the error message on standard error in red. We could send an error message (with no traceback) but send the traceback (and other info) to stderror ourselves.

I think it is fair to use each channel independently (send to stderr if appropriate, outside of the error channel). I agree with your approach of better traceback and documentation.

Better traceback and documentation sounds fine to me.

92a90a3 should fix the error representation in Metakernel Python. (The error repr could be made better). Other kernels may need to be adjusted.

The docs should include these points:

  1. The stacktrace in the error message should be a list of strings (no newlines)
  2. Include anything that you want printed on error.
  3. Nothing else is shown.

Thanks for the fix. I'll give it a test drive soon.

screen shot 2017-06-11 at 4 44 47 pm

Sorry for the delay. The 0.20.3 release looks good!

That is weird that the output is repeated though.

Replicated output fixed in latest, version 0.20.4, available from pypi and conda. Thanks!

Ha! I didn't even notice the dupe output when I posted. Thanks for the fix (x2).

So I did some real digging, and my initial diagnosis wasn't exactly on point.

Essentially, here's how I see it. octave-cli prints to stderr when it has an error. However the REPL wrapper class is redirecting everything (both stdout and stderr) straight to the Print handler. Really what should be happening is that replwrapper (and/or pexpect) should be distinguishing between stdout and stderr, and if there is anything on stderr, it should be sent to the client as a _reply error instead of just lamely printing to stdout.

This probably requires either modifications to the REPLWrapper/Pexpect classes, or Metakernel should be using a different Pexpect class, like the file descriptor oriented one (though I haven't looked at all at how that might go yet).

Edits: formatting for readability instead of a big paragraph.

Also, I would mention why this suddenly became worth three issues and maybe a PR to me.

This is super breaking to my use case ( I'm working on a new non-notebook interface ), and my error handling requires that the Jupyter spec is adhered to, or else we go down the rabbit hole of custom checking for every kernel and potentially not being able to distinguish between stdout stuff and error stuff. Secondarily, I was hoping to make octave_kernel a key feature in this new interface, so I'm kinda blocked until it can be addressed.

Thanks for digging into the issue. I'll follow-up back on the #149 issue.