Skip to content

DatePicker not setting value #1320

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
JoshuaC3 opened this issue Apr 28, 2017 · 13 comments
Closed

DatePicker not setting value #1320

JoshuaC3 opened this issue Apr 28, 2017 · 13 comments
Labels
good first issue resolved-locked Closed issues are locked after 30 days inactivity. Please open a new issue for related discussion.
Milestone

Comments

@JoshuaC3
Copy link

JoshuaC3 commented Apr 28, 2017

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.

@jasongrout
Copy link
Member

jasongrout commented Apr 28, 2017

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.

@jasongrout jasongrout added this to the 7.0 milestone Apr 28, 2017
@jasongrout
Copy link
Member

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.

@jasongrout
Copy link
Member

I'll open another issue about providing a place for unhandled output to show.

This is now jupyter/notebook#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.

@jasongrout
Copy link
Member

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.

@jasongrout
Copy link
Member

@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:

js['month'] + 1, # Months are 1-based in Python

@jasongrout
Copy link
Member

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'].

@jasongrout
Copy link
Member

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:

function serialize_datetime(value, manager) {
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.

@jasongrout
Copy link
Member

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...)

@pbugnion
Copy link
Member

pbugnion commented May 3, 2017

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.

@jasongrout
Copy link
Member

I think I would use object.keys

@pbugnion
Copy link
Member

pbugnion commented May 3, 2017

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.

@jasongrout
Copy link
Member

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
}

pbugnion added a commit to pbugnion/ipywidgets that referenced this issue May 10, 2017
This commit explicitly specifies that the argument to serialise should be an object. This would have prevented issue jupyter-widgets#1320.
@jasongrout
Copy link
Member

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

screen shot 2017-05-16 at 3 51 24 pm

@github-actions github-actions bot added the resolved-locked Closed issues are locked after 30 days inactivity. Please open a new issue for related discussion. label Feb 13, 2021
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Feb 13, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
good first issue resolved-locked Closed issues are locked after 30 days inactivity. Please open a new issue for related discussion.
Projects
None yet
Development

No branches or pull requests

3 participants