Skip to content

Commit 568d6d7

Browse files
committed
automatically display image.Image or display.Data returned by REPL only if it's the only non-nil result
1 parent bfa25f8 commit 568d6d7

File tree

5 files changed

+73
-63
lines changed

5 files changed

+73
-63
lines changed

CONTRIBUTORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ Fransesc Campoy <campoy@golang.org>
2323
Harry Moreno <harry@capsulerx.com>
2424
Josh Cheek <josh.cheek@gmail.com>
2525
Kevin Burke <kev@inburke.com>
26+
Massimiliano Ghilardi <massimiliano.ghilardi@gmail.com>
2627
Matthew Steffen <matt@pachyderm.io>
2728
Sebastien Binet <binet@cern.ch>
2829
Spencer Park <spinnr95@gmail.com>

display.go

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -27,87 +27,87 @@ const (
2727

2828
// injected as placeholder in the interpreter, it's then replaced at runtime
2929
// by a closure that knows how to talk with Jupyter
30-
func stubDisplay(DisplayData) error {
31-
return errors.New("cannot display: connection with Jupiter not registered")
30+
func stubDisplay(Data) error {
31+
return errors.New("cannot display: connection with Jupyter not available")
3232
}
3333

3434
// TODO handle the metadata
3535

36-
func MakeDisplayData(mimeType string, data interface{}) DisplayData {
37-
return DisplayData{
36+
func MakeData(mimeType string, data interface{}) Data {
37+
return Data{
3838
Data: BundledMIMEData{
3939
"text/plain": fmt.Sprint(data),
4040
mimeType: data,
4141
},
4242
}
4343
}
4444

45-
func MakeDisplayData3(mimeType string, plaintext string, data interface{}) DisplayData {
46-
return DisplayData{
45+
func MakeData3(mimeType string, plaintext string, data interface{}) Data {
46+
return Data{
4747
Data: BundledMIMEData{
4848
"text/plain": plaintext,
4949
mimeType: data,
5050
},
5151
}
5252
}
5353

54-
func Bytes(mimeType string, bytes []byte) DisplayData {
55-
return MakeDisplayData3(mimeType, mimeType, bytes)
54+
func Bytes(mimeType string, bytes []byte) Data {
55+
return MakeData3(mimeType, mimeType, bytes)
5656
}
5757

58-
func HTML(html string) DisplayData {
59-
return MakeDisplayData(MIMETypeHTML, html)
58+
func HTML(html string) Data {
59+
return MakeData(MIMETypeHTML, html)
6060
}
6161

62-
func JSON(json map[string]interface{}) DisplayData {
63-
return MakeDisplayData(MIMETypeJSON, json)
62+
func JSON(json map[string]interface{}) Data {
63+
return MakeData(MIMETypeJSON, json)
6464
}
6565

66-
func JavaScript(javascript string) DisplayData {
67-
return MakeDisplayData(MIMETypeJavaScript, javascript)
66+
func JavaScript(javascript string) Data {
67+
return MakeData(MIMETypeJavaScript, javascript)
6868
}
6969

70-
func JPEG(jpeg []byte) DisplayData {
71-
return MakeDisplayData3(MIMETypeJPEG, "jpeg image", jpeg) // []byte are encoded as base64 by the marshaller
70+
func JPEG(jpeg []byte) Data {
71+
return MakeData3(MIMETypeJPEG, "jpeg image", jpeg) // []byte are encoded as base64 by the marshaller
7272
}
7373

74-
func Latex(latex string) DisplayData {
75-
return MakeDisplayData3(MIMETypeLatex, latex, "$"+strings.Trim(latex, "$")+"$")
74+
func Latex(latex string) Data {
75+
return MakeData3(MIMETypeLatex, latex, "$"+strings.Trim(latex, "$")+"$")
7676
}
7777

78-
func Markdown(markdown string) DisplayData {
79-
return MakeDisplayData(MIMETypeMarkdown, markdown)
78+
func Markdown(markdown string) Data {
79+
return MakeData(MIMETypeMarkdown, markdown)
8080
}
8181

82-
func Math(latex string) DisplayData {
83-
return MakeDisplayData3(MIMETypeLatex, latex, "$$"+strings.Trim(latex, "$")+"$$")
82+
func Math(latex string) Data {
83+
return MakeData3(MIMETypeLatex, latex, "$$"+strings.Trim(latex, "$")+"$$")
8484
}
8585

86-
func PDF(pdf []byte) DisplayData {
87-
return MakeDisplayData3(MIMETypePDF, "pdf document", pdf) // []byte are encoded as base64 by the marshaller
86+
func PDF(pdf []byte) Data {
87+
return MakeData3(MIMETypePDF, "pdf document", pdf) // []byte are encoded as base64 by the marshaller
8888
}
8989

90-
func PNG(png []byte) DisplayData {
91-
return MakeDisplayData3(MIMETypePNG, "png image", png) // []byte are encoded as base64 by the marshaller
90+
func PNG(png []byte) Data {
91+
return MakeData3(MIMETypePNG, "png image", png) // []byte are encoded as base64 by the marshaller
9292
}
9393

94-
func String(mimeType string, s string) DisplayData {
95-
return MakeDisplayData(mimeType, s)
94+
func String(mimeType string, s string) Data {
95+
return MakeData(mimeType, s)
9696
}
9797

98-
func SVG(svg string) DisplayData {
99-
return MakeDisplayData(MIMETypeSVG, svg)
98+
func SVG(svg string) Data {
99+
return MakeData(MIMETypeSVG, svg)
100100
}
101101

102-
// MIME encapsulates the data and metadata into a DisplayData.
102+
// MIME encapsulates the data and metadata into a Data.
103103
// The 'data' map is expected to contain at least one {key,value} pair,
104104
// with value being a string, []byte or some other JSON serializable representation,
105105
// and key equal to the MIME type of such value.
106106
// The exact structure of value is determined by what the frontend expects.
107107
// Some easier-to-use functions for common formats supported by the Jupyter frontend
108108
// are provided by the various functions above.
109-
func MIME(data, metadata map[string]interface{}) DisplayData {
110-
return DisplayData{data, metadata, nil}
109+
func MIME(data, metadata map[string]interface{}) Data {
110+
return Data{data, metadata, nil}
111111
}
112112

113113
// prepare imports.Package for interpreted code
@@ -120,8 +120,8 @@ var display = imports.Package{
120120
"JSON": r.ValueOf(JSON),
121121
"JavaScript": r.ValueOf(JavaScript),
122122
"Latex": r.ValueOf(Latex),
123-
"MakeDisplayData": r.ValueOf(MakeDisplayData),
124-
"MakeDisplayData3": r.ValueOf(MakeDisplayData3),
123+
"MakeData": r.ValueOf(MakeData),
124+
"MakeData3": r.ValueOf(MakeData3),
125125
"Markdown": r.ValueOf(Markdown),
126126
"Math": r.ValueOf(Math),
127127
"MIME": r.ValueOf(MIME),
@@ -141,7 +141,7 @@ var display = imports.Package{
141141
},
142142
Types: map[string]r.Type{
143143
"BundledMIMEData": r.TypeOf((*BundledMIMEData)(nil)).Elem(),
144-
"DisplayData": r.TypeOf((*DisplayData)(nil)).Elem(),
144+
"Data": r.TypeOf((*Data)(nil)).Elem(),
145145
},
146146
}
147147

image.go

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ import (
99

1010
// Image converts an image.Image to DisplayData containing PNG []byte,
1111
// or to DisplayData containing error if the conversion fails
12-
func Image(img image.Image) DisplayData {
12+
func Image(img image.Image) Data {
1313
data, err := image0(img)
1414
if err != nil {
15-
return DisplayData{
15+
return Data{
1616
Data: BundledMIMEData{
1717
"ename": "ERROR",
1818
"evalue": err.Error(),
@@ -24,14 +24,14 @@ func Image(img image.Image) DisplayData {
2424
return data
2525
}
2626

27-
// image0 converts an image.Image to DisplayData containing PNG []byte,
27+
// Image converts an image.Image to Data containing PNG []byte,
2828
// or error if the conversion fails
29-
func image0(img image.Image) (DisplayData, error) {
29+
func image0(img image.Image) (Data, error) {
3030
bytes, mime, err := encodePng(img)
3131
if err != nil {
32-
return DisplayData{}, err
32+
return Data{}, err
3333
}
34-
return DisplayData{
34+
return Data{
3535
Data: BundledMIMEData{
3636
mime: bytes,
3737
},
@@ -60,43 +60,52 @@ func imageMetadata(img image.Image) BundledMIMEData {
6060
}
6161
}
6262

63-
// publishImages sends a "display_data" broadcast message for given image.Image.
64-
func publishImage(img image.Image, receipt *msgReceipt) error {
63+
// PublishImage sends a "display_data" broadcast message for given image.Image.
64+
func (receipt *msgReceipt) PublishImage(img image.Image) error {
6565
data, err := image0(img)
6666
if err != nil {
6767
return err
6868
}
6969
return receipt.PublishDisplayData(data)
7070
}
7171

72-
// publishImagesAndDisplayData sends a "display_data" broadcast message for each
73-
// image.Image and DisplayData found in vals, then replaces it with nil
74-
// to avoid overloading the front-end with huge amounts of output text:
72+
// if vals[] contain a single non-nil value which is an image.Image
73+
// or a display.Data, publishImageOrDisplayData sends a "display_data"
74+
// broadcast message for such value, then returns nil to avoid overloading
75+
// the front-end with huge amounts of output text:
7576
// fmt.Sprint(val) is often very large for an image and other multimedia data.
76-
func publishImagesAndDisplayData(vals []interface{}, receipt *msgReceipt) []interface{} {
77-
for i, val := range vals {
77+
func (receipt *msgReceipt) PublishImageOrDisplayData(vals []interface{}) []interface{} {
78+
var nilcount int
79+
var data interface{}
80+
for _, val := range vals {
7881
switch obj := val.(type) {
82+
case image.Image, Data:
83+
data = obj
84+
case nil:
85+
nilcount++
86+
}
87+
}
88+
if data != nil && nilcount == len(vals)-1 {
89+
switch obj := data.(type) {
7990
case image.Image:
80-
err := publishImage(obj, receipt)
91+
err := receipt.PublishImage(obj)
8192
if err != nil {
8293
log.Printf("Error publishing image.Image: %v\n", err)
8394
} else {
84-
vals[i] = nil
95+
nilcount++
8596
}
86-
case DisplayData:
97+
case Data:
8798
err := receipt.PublishDisplayData(obj)
8899
if err != nil {
89-
log.Printf("Error publishing DisplayData: %v\n", err)
100+
log.Printf("Error publishing Data: %v\n", err)
90101
} else {
91-
vals[i] = nil
102+
nilcount++
92103
}
93104
}
94105
}
95-
// if all values are nil, return empty slice
96-
for _, val := range vals {
97-
if val != nil {
98-
return vals
99-
}
106+
if nilcount == len(vals) {
107+
// if all values are nil, return empty slice
108+
return nil
100109
}
101-
return nil
110+
return vals
102111
}

kernel.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,7 @@ func handleExecuteRequest(ir *interp.Interp, receipt msgReceipt) error {
399399

400400
if executionErr == nil {
401401
// if one or more value is image.Image or DisplayData, display it instead
402-
vals = publishImagesAndDisplayData(vals, &receipt)
402+
vals = receipt.PublishImageOrDisplayData(vals)
403403

404404
content["status"] = "ok"
405405
content["user_expressions"] = make(map[string]string)

messages.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ type msgReceipt struct {
4242
// at least a "text/plain" representation with a string value.
4343
type BundledMIMEData map[string]interface{}
4444

45-
type DisplayData struct {
45+
type Data struct {
4646
Data BundledMIMEData `json:"data"`
4747
Metadata BundledMIMEData `json:"metadata"`
4848
Transient BundledMIMEData `json:"transient"`
@@ -274,7 +274,7 @@ func (receipt *msgReceipt) PublishExecutionError(err string, trace []string) err
274274
}
275275

276276
// PublishDisplayData publishes a single image.
277-
func (receipt *msgReceipt) PublishDisplayData(data DisplayData) error {
277+
func (receipt *msgReceipt) PublishDisplayData(data Data) error {
278278
if data.Metadata == nil {
279279
data.Metadata = make(BundledMIMEData)
280280
}

0 commit comments

Comments
 (0)