Closed ibdafna closed 3 years ago
This issue surfaced during routine CI tests in #272.
Moreover, jupyter_client >= 7.0.0 works fine with Python 3.6, but not >= 3.7. Specifically, it seems like grids with nested columns trigger this issue. The following snippet causes an exception:
jupyter_client
import ipydatagrid as ipg import pandas as pd import numpy as np # Columns col_top_level = [ "VeryLongValueFactors", "VeryLongValueFactors", "Even Longer Momentum Factors", "Even Longer Momentum Factors", ] col_bottom_level = ["Factor_A", "Factor_B", "Factor_C", "Factor_D"] # Rows row_top_level = ["Sector 1", "Sector 1", "Sector 2", "Sector 2"] row_bottom_level = ["Security A", "Security B", "Security C", "Security D"] nested_df = pd.DataFrame( np.random.randn(4, 4).round(4), columns=pd.MultiIndex.from_arrays([col_top_level, col_bottom_level]), index=pd.MultiIndex.from_arrays( [row_top_level, row_bottom_level], names=("Sector", "Ticker") ), ) nested_grid = ipg.DataGrid( nested_df, ) nested_grid
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) /tmp/ipykernel_9865/4137114305.py in <module> 26 27 nested_grid = ipg.DataGrid( ---> 28 nested_df, 29 ) 30 ~/dev/ipydatagrid/ipydatagrid/datagrid.py in __init__(self, dataframe, **kwargs) 356 self.data = dataframe 357 super().__init__(**kwargs) --> 358 self._cell_click_handlers = CallbackDispatcher() 359 self._cell_change_handlers = CallbackDispatcher() 360 self.on_msg(self.__handle_custom_msg) ~/miniconda3/envs/ipydatagrid/lib/python3.7/site-packages/ipywidgets/widgets/widget.py in __init__(self, **kwargs) 413 414 Widget._call_widget_constructed(self) --> 415 self.open() 416 417 def __del__(self): ~/miniconda3/envs/ipydatagrid/lib/python3.7/site-packages/ipywidgets/widgets/widget.py in open(self) 436 args['comm_id'] = self._model_id 437 --> 438 self.comm = Comm(**args) 439 440 @observe('comm') ~/miniconda3/envs/ipydatagrid/lib/python3.7/site-packages/ipykernel/comm/comm.py in __init__(self, target_name, data, metadata, buffers, **kwargs) 55 if self.primary: 56 # I am primary, open my peer. ---> 57 self.open(data=data, metadata=metadata, buffers=buffers) 58 else: 59 self._closed = False ~/miniconda3/envs/ipydatagrid/lib/python3.7/site-packages/ipykernel/comm/comm.py in open(self, data, metadata, buffers) 92 data=data, metadata=metadata, buffers=buffers, 93 target_name=self.target_name, ---> 94 target_module=self.target_module, 95 ) 96 self._closed = False ~/miniconda3/envs/ipydatagrid/lib/python3.7/site-packages/ipykernel/comm/comm.py in _publish_msg(self, msg_type, data, metadata, buffers, **keys) 69 parent=self.kernel.get_parent("shell"), 70 ident=self.topic, ---> 71 buffers=buffers, 72 ) 73 ~/miniconda3/envs/ipydatagrid/lib/python3.7/site-packages/jupyter_client/session.py in send(self, stream, msg_or_type, content, parent, ident, buffers, track, header, metadata) 821 if self.adapt_version: 822 msg = adapt(msg, self.adapt_version) --> 823 to_send = self.serialize(msg, ident) 824 to_send.extend(buffers) 825 longest = max([len(s) for s in to_send]) ~/miniconda3/envs/ipydatagrid/lib/python3.7/site-packages/jupyter_client/session.py in serialize(self, msg, ident) 695 content = self.none 696 elif isinstance(content, dict): --> 697 content = self.pack(content) 698 elif isinstance(content, bytes): 699 # content is already packed, as in a relayed message ~/miniconda3/envs/ipydatagrid/lib/python3.7/site-packages/jupyter_client/session.py in json_packer(obj) 97 default=json_default, 98 ensure_ascii=False, ---> 99 allow_nan=False, 100 ).encode("utf8") 101 ~/miniconda3/envs/ipydatagrid/lib/python3.7/json/__init__.py in dumps(obj, skipkeys, ensure_ascii, check_circular, allow_nan, cls, indent, separators, default, sort_keys, **kw) 236 check_circular=check_circular, allow_nan=allow_nan, indent=indent, 237 separators=separators, default=default, sort_keys=sort_keys, --> 238 **kw).encode(obj) 239 240 ~/miniconda3/envs/ipydatagrid/lib/python3.7/json/encoder.py in encode(self, o) 197 # exceptions aren't as detailed. The list call should be roughly 198 # equivalent to the PySequence_Fast that ''.join() would do. --> 199 chunks = self.iterencode(o, _one_shot=True) 200 if not isinstance(chunks, (list, tuple)): 201 chunks = list(chunks) ~/miniconda3/envs/ipydatagrid/lib/python3.7/json/encoder.py in iterencode(self, o, _one_shot) 255 self.key_separator, self.item_separator, self.sort_keys, 256 self.skipkeys, _one_shot) --> 257 return _iterencode(o, 0) 258 259 def _make_iterencode(markers, _default, _encoder, _indent, _floatstr, TypeError: keys must be str, int, float, bool or None, not tuple
cc @martinRenou
Seems to be caused by this serialisation function in ipywidgets: https://github.com/jupyter-widgets/ipywidgets/blob/3558ce6a22b4a6b1badb69f0507a6ac5b245a17f/ipywidgets/widgets/widget.py#L157
ipywidgets
Fixed via #274.
This issue surfaced during routine CI tests in #272.
Moreover,
jupyter_client
>= 7.0.0 works fine with Python 3.6, but not >= 3.7. Specifically, it seems like grids with nested columns trigger this issue. The following snippet causes an exception:cc @martinRenou