Opened 6 months ago

Closed 6 months ago

Last modified 5 months ago

#27656 closed defect (fixed)

py3: Fix table display in Jupyter notebook with Sage kernel

Reported by: slelievre Owned by:
Priority: critical Milestone: sage-8.8
Component: notebook Keywords: jupyter, table, display
Cc: chapoton, embray, jdemeyer, kcrisman, vbraun Merged in:
Authors: Erik Bray Reviewers: John Palmieri
Report Upstream: N/A Work issues:
Branch: 9214d1c (Commits) Commit:
Dependencies: Stopgaps:

Description (last modified by slelievre)

As reported in

the following fails to display the expected table properly in the Jupyter Notebook with the Python3-based SageMath kernel:

%display latex
rows = [('A', 'B', 'C'), (0, 1, 2), (3, 4, 5)]
table(rows)

It works fine with the Python2-based SageMath kernel.

Observed with SageMath 8.8.beta1, on MacOS and on CoCalc.

The table displays fine in text mode in the Sage REPL:

sage: rows = [('A', 'B', 'C'), (0, 1, 2), (3, 4, 5)]
sage: table(rows)
  A   B   C
  0   1   2
  3   4   5

Change History (19)

comment:1 Changed 6 months ago by jhpalmieri

Please provide OS information and the Sage version. The command works just fine for me in the Jupyter notebook with Sage 8.8.beta1 on OS X, with both Safari and Firefox.

comment:2 Changed 6 months ago by jhpalmieri

Oh, is it a Python 3 problem? I see this issue with Python 3 but not Python 2.

comment:3 Changed 6 months ago by slelievre

  • Description modified (diff)
  • Summary changed from Fix table display in Jupyter notebook with Sage kernel to py3: Fix table display in Jupyter notebook with Sage kernel

Right, forgot to mention this is with Python 3.

comment:4 Changed 6 months ago by slelievre

  • Description modified (diff)

comment:5 Changed 6 months ago by jhpalmieri

This reminds me of #24784. I would guess that the problem is in the _html_ method for tables, possibly in the use of StringIO.

comment:6 Changed 6 months ago by jhpalmieri

Maybe the problem is really in HtmlFragment. Note that this code produces similar gibberish with Python 3 but not Python 2:

A = ([1, 1], [3, 1], [-1, -1])
b = (1000, 1500, -400)
c = (10, 5)
P = InteractiveLPProblemStandardForm(A, b, c)
P.run_simplex_method()

The run_simplex_method also calls HtmlFragment.

Or try this:

a = 123
html.eval('<sage>a</sage>')

comment:7 Changed 6 months ago by jhpalmieri

  • Cc vbraun added
  • Priority changed from major to critical

comment:8 Changed 6 months ago by slelievre

  • Cc chapoton embray added

Hopefully a Python3 expert can help with this.

comment:9 Changed 6 months ago by embray

I didn't realize this was only on Python 3. Mostly likely the problem is something returning bytes when it should return str.

comment:10 Changed 6 months ago by jhpalmieri

I don't know enough about how the Jupyter notebook displays things. The failure of

sage.misc.html.HtmlFragment('hello')

says that the problem is in how the notebook displays instances of HtmlFragment. This is Python 3 only, so Erik is likely right that something is producing bytes instead of str. Can someone who understands the Jupyter notebook shed any light on this?

comment:11 Changed 6 months ago by embray

I haven't tested it yet, but this is likely the fix we want:

  • src/sage/repl/rich_output/backend_ipython.py

    diff --git a/src/sage/repl/rich_output/backend_ipython.py b/src/sage/repl/rich_output/backend_ipython.py
    index eeeb526183..7c27d48a21 100644
    a b class BackendIPythonNotebook(BackendIPython): 
    539539                     u'text/plain': plain_text.text.get_unicode(),
    540540            }, {})
    541541        elif isinstance(rich_output, OutputHtml):
    542             return ({u'text/html':  rich_output.html.get(),
    543                      u'text/plain': plain_text.text.get(),
     542            return ({u'text/html':  rich_output.html.get_unicode(),
     543                     u'text/plain': plain_text.text.get_unicode(),
    544544            }, {})
    545545        elif isinstance(rich_output, OutputImagePng):
    546546            return ({u'image/png':  rich_output.png.get(),
    class BackendIPythonNotebook(BackendIPython): 
    548548            }, {})
    549549        elif isinstance(rich_output, OutputImageGif):
    550550            return ({u'text/html':  rich_output.html_fragment(),
    551                      u'text/plain': plain_text.text.get(),
     551                     u'text/plain': plain_text.text.get_unicode(),
    552552            }, {})
    553553        elif isinstance(rich_output, OutputImageJpg):
    554554            return ({u'image/jpeg':  rich_output.jpg.get(),

comment:12 Changed 6 months ago by jhpalmieri

That works for me.

comment:13 Changed 6 months ago by jhpalmieri

  • Branch set to u/jhpalmieri/jupyter-html-fragment

comment:14 Changed 6 months ago by jhpalmieri

  • Authors set to Erik Bray
  • Commit set to 9214d1cbcd06e87390b36e851623eafffbb70263
  • Reviewers set to John Palmieri
  • Status changed from new to needs_review

New commits:

9214d1ctrac 27656: fix unicode issue with HtmlFragment

comment:15 Changed 6 months ago by jhpalmieri

  • Status changed from needs_review to positive_review

comment:16 Changed 6 months ago by vbraun

  • Branch changed from u/jhpalmieri/jupyter-html-fragment to 9214d1cbcd06e87390b36e851623eafffbb70263
  • Resolution set to fixed
  • Status changed from positive_review to closed

comment:17 Changed 6 months ago by embray

  • Commit 9214d1cbcd06e87390b36e851623eafffbb70263 deleted

Thanks for making the branch and reviewing it.

comment:18 Changed 5 months ago by chapoton

This was also proposed long ago in #19186.

comment:19 Changed 5 months ago by slelievre

Sorry! I looked for an existing ticket before opening this one but missed #19186.

Note: See TracTickets for help on using tickets.