turbo_broccoli.custom.bokeh
Bokeh objects (de)serialization utilities.
1"""Bokeh objects (de)serialization utilities.""" 2 3from typing import Any, Callable, Tuple 4 5from bokeh.core.serialization import ( 6 Buffer, 7 Deserializer, 8 Serialized, 9 Serializer, 10) 11from bokeh.models import Model 12from bokeh.plotting import figure as Figure 13 14from turbo_broccoli.context import Context 15from turbo_broccoli.exceptions import DeserializationError, TypeNotSupported 16 17 18def _buffer_to_json(obj: Buffer, ctx: Context) -> dict: 19 return { 20 "__type__": "bokeh.buffer", 21 "__version__": 2, 22 "id": obj.id, 23 "data": obj.to_bytes(), 24 } 25 26 27def _generic_to_json(obj: Figure, ctx: Context) -> dict: 28 s = Serializer().serialize(obj) 29 return { 30 "__type__": "bokeh.generic", 31 "__version__": 2, 32 "content": s.content, 33 "buffers": s.buffers, 34 } 35 36 37def _json_to_buffer(dct: dict, ctx: Context) -> Buffer: 38 decoders = { 39 2: _json_to_buffer_v2, 40 } 41 return decoders[dct["__version__"]](dct, ctx) 42 43 44def _json_to_buffer_v2(dct: dict, ctx: Context) -> Buffer: 45 return Buffer(id=dct["id"], data=dct["data"]) 46 47 48def _json_to_generic(dct: dict, ctx: Context) -> Any: 49 decoders = { 50 2: _json_to_generic_v2, 51 } 52 return decoders[dct["__version__"]](dct, ctx) 53 54 55def _json_to_generic_v2(dct: dict, ctx: Context) -> Any: 56 c, b = dct["content"], dct["buffers"] 57 return Deserializer().deserialize(Serialized(content=c, buffers=b)) 58 59 60# pylint: disable=missing-function-docstring 61def from_json(dct: dict, ctx: Context) -> Any: 62 ctx.raise_if_nodecode("bytes") 63 decoders = { 64 "bokeh.buffer": _json_to_buffer, 65 "bokeh.generic": _json_to_generic, 66 } 67 try: 68 type_name = dct["__type__"] 69 return decoders[type_name](dct, ctx) 70 except KeyError as exc: 71 raise DeserializationError() from exc 72 73 74def to_json(obj: Any, ctx: Context) -> dict: 75 """ 76 Serializes a bokeh object. The return dict has the following structure: 77 78 - `bokeh.plotting._figure.figure` or `bokeh.models.Model`: 79 80 ```py 81 { 82 "__type__": "bokeh.generic", 83 "__version__": 2, 84 "content": {...}, 85 "buffers": [...], 86 } 87 ``` 88 89 - `bokeh.core.serialization.Buffer`: (for internal use) 90 91 ```py 92 { 93 "__type__": "bokeh.buffer", 94 "__version__": 2, 95 "id": <str>, 96 "data": <bytes>, 97 } 98 ``` 99 100 """ 101 encoders: list[Tuple[type, Callable[[Any, Context], dict]]] = [ 102 (Buffer, _buffer_to_json), 103 (Figure, _generic_to_json), 104 (Model, _generic_to_json), 105 ] 106 for t, f in encoders: 107 if isinstance(obj, t): 108 return f(obj, ctx) 109 raise TypeNotSupported()
62def from_json(dct: dict, ctx: Context) -> Any: 63 ctx.raise_if_nodecode("bytes") 64 decoders = { 65 "bokeh.buffer": _json_to_buffer, 66 "bokeh.generic": _json_to_generic, 67 } 68 try: 69 type_name = dct["__type__"] 70 return decoders[type_name](dct, ctx) 71 except KeyError as exc: 72 raise DeserializationError() from exc
75def to_json(obj: Any, ctx: Context) -> dict: 76 """ 77 Serializes a bokeh object. The return dict has the following structure: 78 79 - `bokeh.plotting._figure.figure` or `bokeh.models.Model`: 80 81 ```py 82 { 83 "__type__": "bokeh.generic", 84 "__version__": 2, 85 "content": {...}, 86 "buffers": [...], 87 } 88 ``` 89 90 - `bokeh.core.serialization.Buffer`: (for internal use) 91 92 ```py 93 { 94 "__type__": "bokeh.buffer", 95 "__version__": 2, 96 "id": <str>, 97 "data": <bytes>, 98 } 99 ``` 100 101 """ 102 encoders: list[Tuple[type, Callable[[Any, Context], dict]]] = [ 103 (Buffer, _buffer_to_json), 104 (Figure, _generic_to_json), 105 (Model, _generic_to_json), 106 ] 107 for t, f in encoders: 108 if isinstance(obj, t): 109 return f(obj, ctx) 110 raise TypeNotSupported()
Serializes a bokeh object. The return dict has the following structure:
bokeh.plotting._figure.figure
orbokeh.models.Model
:{ "__type__": "bokeh.generic", "__version__": 2, "content": {...}, "buffers": [...], }
bokeh.core.serialization.Buffer
: (for internal use){ "__type__": "bokeh.buffer", "__version__": 2, "id": <str>, "data": <bytes>, }