I am unable to get the DatePicker to return a value. I have tried setting this using the click, typed and arrow keys. Nothing helps.
I have put in the text example to show that this works. Here is my code.
import ipywidgets as w
text_box = w.Text(placeholder='Type Contract Name')
start_date_widget = w.DatePicker(description='Start Date')
display(text_box, start_date_widget)
start_date = start_date_widget.value
contract = text_box.value
print(contract, start_date)
'hello' None
Chrome browser, using jupyter notebook through jupyterhub, ipywidgets 7.0.
Any debugging for system info needed then please let me know. Thanks.
I can reproduce this. Looking at the websocket messages, I notice that setting the value gives back an error:
TypeError Traceback (most recent call last)
/<snip>/ipywidgets/widgets/widget.py in [0;36m_handle_msg(self, msg)
598 if 'buffer_paths' in data:
599 _put_buffers(state, data['buffer_paths'], msg['buffers'])
--> 600 self.set_state(state)
601
602 # Handle a state request.
/<snip>/ipywidgets/widgets/widget.py in [0;36mset_state(self, sync_data)
479 from_json = self.trait_metadata(name, 'from_json',
480 self._trait_from_json)
--> 481 self.set_trait(name, from_json(sync_data[name], self))
482
483 def send(self, content, buffers=None):
/<snip>/ipywidgets/widgets/trait_types.py in [0;36mdatetime_from_json(js, manager)
66 else:
67 return dt.datetime(
---> 68 js['year'],
69 js['month'] + [0;36m1, # Months are 1-based in Python
70 js['date'],
TypeError: string indices must be integers"
So apparently we have a bug in the python code.
This also points out that we need some place for any unhandled output to go.
The python bug here should be pretty straightforward to fix, so setting as sprint-friendly. I'll open another issue about providing a place for unhandled output to show.
I'll open another issue about providing a place for unhandled output to show.
This is now https://github.com/jupyter/notebook/issues/2455. However, we can maybe mitigate this issue by having a single OutputWidget that is created by default when widgets are instantiated, and always syncing when in the scope of that output widget. If you want to see the log, just display that output widget.
However, we can maybe mitigate this issue by having a single OutputWidget that is created by default when widgets are instantiated, and always syncing when in the scope of that output widget.
This is #1321.
@JoshuaC3 - feel free to submit a fix, and thanks so much for trying out the 7.0 alpha so soon! It looks like the problem is that we are trying to add 1 to a string: https://github.com/jupyter-widgets/ipywidgets/blob/2a5588787e0130b45d3698273541c25399f2d9ca/ipywidgets/widgets/trait_types.py#L69
Hmmm, no, it seems like the js argument to that datetime_from_json is actually a string, instead of a dict, so it's complaining that we're addressing a string like js['month'].
Here is the update message when I change a value in the DatePicker widget:
{"header":{"msg_id":"F3D7CD2A4CC4443B8CEE49BB275181C9","username":"username","session":"C4A566E40CB643B5B14B652217B812B3","msg_type":"comm_msg","version":"5.0"},"metadata":{},"content":{"comm_id":"037f44a2cc78490b977e0df7954ca3d9","data":{"method":"update","state":{"value":"2017-04-19T04:00:00.000Z"},"buffer_paths":[]}},"buffers":[],"parent_header":{},"channel":"shell"}
So it appears that what is sent as the value is a string, but what is expected is a dictionary of year, month, day, etc. So it appears that the problem may be on the javascript side? Somewhere there is a miscommunication.
In the javascript, it looks like the date should be going through this function: https://github.com/jupyter-widgets/ipywidgets/blob/2a5588787e0130b45d3698273541c25399f2d9ca/jupyter-js-widgets/src/widget_date.ts#L15 in order to be converted from a date to a dictionary of year, month, day, etc. Apparently this isn't happening and it isn't be serialized through this function. So debugging that would probably lead to the answer.
Here is the update message when I change a value in the DatePicker widget:
(By the way, I got that by going to the Chrome debugger Network panel, clicking on the websocket connection, and examining the websocket frames...)
I stumbled across this when addressing #1322 . The custom date serialisers never get called, so the date gets serialised as an ISO string.
I think the problem is in the WidgetModel$serialize method: at the moment, this iterates over the state using (widget.ts, line 405):
for (const k of state) { // handle custom serialisers here }
Since state is an object, this doesn't work, so the method just falls back on raw JSON.stringify for everything.
Changing the iteration to be for (const k in state) { ... } fixes it (though we should probably use the Object.keys method).
Does this sound correct, or am I missing something? If not, I'm happy to go ahead and implement this.
I think I would use object.keys
For reference, I was surprised that the code as it stands does not throw an exception, since typing for (var key of {a: 2}) { console.log(key) ; } in a browser console does throw. It turns out that typescript converts this:
for (const k of state) { }
to
for (var _i = 0, state_1 = state; _i < state_1.length; _i++) { }
Since state_1.length is undefined, _i < state_1.length is always false, so the entire for-loop is just silently skipped.
Since state_1.length is undefined, _i < state_1.length is always false, so the entire for-loop is just silently skipped.
We should type state so that this throws an errror:
let state: { [key: string]: any};
for (let i of state) {
// compile error
}
This is now fixed. Thanks again @JoshuaC3 and @pbugnion!

Most helpful comment
This is now fixed. Thanks again @JoshuaC3 and @pbugnion!