Skip to content

Commit

Permalink
Use proper bokehjs' types in src/widgets.ts
Browse files Browse the repository at this point in the history
  • Loading branch information
mattpap committed Apr 18, 2024
1 parent 38d8fd5 commit 190641f
Show file tree
Hide file tree
Showing 5 changed files with 363 additions and 117 deletions.
26 changes: 1 addition & 25 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,5 @@ module.exports = {
},
plugins: ['@typescript-eslint'],
rules: {
'@typescript-eslint/naming-convention': [
'warn',
{
'selector': 'interface',
'format': ['PascalCase'],
'custom': {
'regex': '^I[A-Z]',
'match': true
}
}
],
'@typescript-eslint/no-unused-vars': ['warn', { args: 'none' }],
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-namespace': 'off',
'@typescript-eslint/no-use-before-define': 'off',
'@typescript-eslint/quotes': [
'error',
'single',
{ avoidEscape: true, allowTemplateLiterals: false }
],
curly: ['error', 'all'],
semi: ['warn', 'never'],
eqeqeq: 'warn',
'prefer-arrow-callback': 'error'
}
};
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
"@jupyter-widgets/jupyterlab-manager": "^5.0.4"
},
"devDependencies": {
"@bokeh/bokehjs": "~3.4.0",
"@jupyterlab/builder": "^4",
"@typescript-eslint/eslint-plugin": "^7.0.1",
"@typescript-eslint/parser": "^7.0.1",
Expand Down
152 changes: 63 additions & 89 deletions src/widgets.ts
Original file line number Diff line number Diff line change
@@ -1,62 +1,46 @@
import { DOMWidgetModel, DOMWidgetView } from '@jupyter-widgets/base'
import {DOMWidgetModel, DOMWidgetView} from "@jupyter-widgets/base"

//import {Document, DocumentChangedEvent, ModelChangedEvent} from "document"
//import {Receiver, Fragment} from "protocol/receiver"
//import {keys, values} from "core/util/object"
// Use only `import type`, so that all imports are erased at run time
import type {Document, DocJson, Patch, DocumentChangedEvent} from "@bokeh/bokehjs/document"
import type {DocumentChanged} from "@bokeh/bokehjs/document/events"
import type {Receiver, Fragment} from "@bokeh/bokehjs/protocol/receiver"
import type {RenderItem} from "@bokeh/bokehjs/embed/json"
import type {HasProps} from "@bokeh/bokehjs/core/has_props"
import type {Ref} from "@bokeh/bokehjs/core/util/refs"
import type {Serializer} from "@bokeh/bokehjs/core/serialization"
import type {BokehEvent} from "@bokeh/bokehjs/core/bokeh_events"
import type {add_document_standalone} from "@bokeh/bokehjs/embed/standalone"

import { name, version } from './metadata'
import {name, version} from './metadata'

function bk_require(name: string): any {
return (window as any).Bokeh.require(name)
declare const Bokeh: {require(name: string): unknown}

function bk_require<T>(name: string): T {
return Bokeh.require(name) as T
}

type DocsJson = any
type RenderItem = any
type Document = any
type DocumentChangedEvent = any
type Receiver = any
type Fragment = any
type HasProps = any
type Ref = any
declare const Jupyter: {notebook?: unknown}

declare function require(name: string): unknown

const { keys, values } = Object
const {keys} = Object

const version_range = `^${version}`

export type RenderBundle = {
docs_json: DocsJson
docs_json: DocJson[]
render_items: RenderItem[]
div: string
}

export interface DocumentChanged {
event: 'jsevent'
kind: string
}

export interface ModelChanged extends DocumentChanged {
event: 'jsevent'
kind: 'ModelChanged'
id: string
new: unknown
attr: string
}

export interface MessageSent extends DocumentChanged {
event: 'jsevent'
kind: 'MessageSent'
msg_data: {
event_name: string
event_values: {
model: { id: string }
[other: string]: any
}
}
msg_type: string
/*
declare interface DocumentChanged {
event: "jsevent"
}
*/

export class BokehModel extends DOMWidgetModel {
defaults(): any {
defaults(): {[key: string]: unknown} {
return {
...super.defaults(),

Expand All @@ -69,7 +53,7 @@ export class BokehModel extends DOMWidgetModel {
_view_module_version: version_range,

combine_events: false,
render_bundle: {}
render_bundle: {},
}
}

Expand All @@ -82,26 +66,23 @@ export class BokehView extends DOMWidgetView {
private _document: Document | null
private _receiver: Receiver
private _blocked: boolean
private _msgs: any[]
private _msgs: DocumentChanged[]
private _idle: boolean
private _combine: boolean

constructor(options?: any) {
constructor(options?: unknown) {
super(options)
this._document = null
this._blocked = false
this._idle = true
this._combine = true
this._msgs = []
const { Receiver } = bk_require('protocol/receiver')
this._receiver = new Receiver()
const receiver = bk_require<{Receiver: typeof Receiver}>('protocol/receiver')
this._receiver = new receiver.Receiver()
this.model.on('change:render_bundle', () => this.render())
if (
(window as any).Jupyter != null &&
(window as any).Jupyter.notebook != null
) {
if (Jupyter?.notebook != null) {
// Handle classic Jupyter notebook
const events = (window as any).require('base/js/events')
const events = require('base/js/events')
events.on('kernel_idle.Kernel', () => this._process_msg())
} else if ((this.model.widget_manager as any).context != null) {

Check failure on line 87 in src/widgets.ts

View workflow job for this annotation

GitHub Actions / build

Unexpected any. Specify a different type
// Handle JupyterLab and Voila
Expand All @@ -117,15 +98,11 @@ export class BokehView extends DOMWidgetView {
}
})
} else if (this.model.get('combine_events')) {
console.warn(
'BokehView cannot combine events because Kernel idle status cannot be determined.'
)
console.warn('BokehView cannot combine events because Kernel idle status cannot be determined.')
this._combine = false
}
} else if (this.model.get('combine_events')) {
console.warn(
'BokehView cannot combine events because Kernel idle status cannot be determined.'
)
console.warn('BokehView cannot combine events because Kernel idle status cannot be determined.')
this._combine = false
}
this.listenTo(this.model, 'msg:custom', (content, buffers) =>
Expand All @@ -143,27 +120,25 @@ export class BokehView extends DOMWidgetView {

render(): void {
const bundle = JSON.parse(this.model.get('render_bundle'))
const { docs_json, render_items, div } = bundle as RenderBundle
const {docs_json, render_items, div} = bundle as RenderBundle
this.el.innerHTML = div
const element = this.el.children[0]
const json = values(docs_json)[0]
const { Document } = bk_require('document')
const { add_document_standalone } = bk_require('embed/standalone')
this._document = Document.from_json(json)
for (const item of render_items) {
const roots: { [key: string]: Element } = {}
for (const root_id in item.roots) {
roots[root_id] = element
}
add_document_standalone(this._document, element, roots)
const element = this.el.children[0] as HTMLElement
// assumes docs_json.length == 1 && render_items.length == 1
const doc_json = docs_json[0]
const render_item = render_items[0]
const document = bk_require<{Document: typeof Document}>('document')
const standalone = bk_require<{add_document_standalone: typeof add_document_standalone}>('embed/standalone')
this._document = document.Document.from_json(doc_json)
const roots: {[key: string]: HTMLElement} = {}
for (const root_id in render_item.roots) {
roots[root_id] = element
}
this._document.on_change((event: any) => this._change_event(event))
standalone.add_document_standalone(this._document, element, roots)
this._document.on_change((event) => this._change_event(event))
}

_combine_events(
new_msg: ModelChanged | MessageSent
): (ModelChanged | MessageSent)[] {
const new_msgs = []
_combine_events(new_msg: DocumentChanged): DocumentChanged[] {
const new_msgs: DocumentChanged[] = []
for (const msg of this._msgs) {
if (new_msg.kind != msg.kind) {
new_msgs.push(msg)
Expand All @@ -172,11 +147,13 @@ export class BokehView extends DOMWidgetView {
new_msgs.push(msg)
}
} else if (msg.kind == 'MessageSent' && new_msg.kind == 'MessageSent') {
// assert msg.msg_type == "bokeh_event"
const data = msg.msg_data as BokehEvent
const new_data = new_msg.msg_data as BokehEvent
if (
msg.msg_data.event_values.model == null ||
msg.msg_data.event_values.model.id !=
new_msg.msg_data.event_values.model.id ||
msg.msg_data.event_name != new_msg.msg_data.event_name
data.event_values.model == null ||
data.event_values.model.id != new_data.event_values.model.id ||
data.event_name != new_data.event_name
) {
new_msgs.push(msg)
}
Expand All @@ -186,7 +163,7 @@ export class BokehView extends DOMWidgetView {
return new_msgs
}

_send(msg: ModelChanged | MessageSent): void {
_send(msg: DocumentChanged): void {
if (!this._idle && this._combine && this.model.get('combine_events')) {
// Queue event and drop previous events on same model attribute
this._msgs = this._combine_events(msg)
Expand All @@ -200,21 +177,18 @@ export class BokehView extends DOMWidgetView {
if (this._blocked) {
return
}
const { Serializer } = bk_require('core/serialization')
const serialization = bk_require<{Serializer: typeof Serializer}>("core/serialization")
const references: Map<HasProps, Ref> = new Map()
for (const model of event.document._all_models.values()) {
references.set(model, model.ref())
}
const serializer = new Serializer({references})
const event_rep = serializer.encode(event)
event_rep.event = 'jsevent'
const serializer = new serialization.Serializer({references})
const event_rep = serializer.encode(event) as DocumentChanged & {event: "jsevent"}
event_rep.event = "jsevent"
this._send(event_rep)
}

protected _consume_patch(
content: { msg: 'patch'; payload?: Fragment },
buffers: DataView[]
): void {
protected _consume_patch(content: {msg: 'patch'; payload?: Fragment}, buffers: DataView[]): void {
if (this._document == null) {
return
}
Expand All @@ -225,7 +199,7 @@ export class BokehView extends DOMWidgetView {
if (comm_msg != null && keys(comm_msg.content).length > 0) {
this._blocked = true
try {
this._document.apply_json_patch(comm_msg.content, comm_msg.buffers)
this._document.apply_json_patch(comm_msg.content as Patch, comm_msg.buffers)
} finally {
this._blocked = false
}
Expand Down
7 changes: 6 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,12 @@
"strict": true,
"strictNullChecks": false,
"target": "es2017",
"types": []
"types": [],
"paths": {
"@bokeh/bokehjs/*": [
"./node_modules/@bokeh/bokehjs/build/js/lib/*"
]
}
},
"include": ["src/*"]
}
Loading

0 comments on commit 190641f

Please sign in to comment.