-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Description
I re-created an odd issue I just ran into. Here's my reproducible example:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import dash
import dash_core_components as dcc
import dash_html_components as html
def generate_inputs():
print('getting value!')
f = open('./value.txt', 'r')
current_value = str(f.read())
f.close()
print('current_value: ' + str(current_value))
input_box = [html.Label(html.Strong('value to write; currently: ')),
dcc.Input(type='number', value=current_value, id='input_value')]
return input_box
app = dash.Dash()
app.layout = html.Div([
html.H2('debug: getting and setting'),
html.Div(
generate_inputs()
),
html.Div(id='file_value_written')
]) # app.layout
@app.callback(
dash.dependencies.Output(component_id='file_value_written', component_property='children'),
[dash.dependencies.Input(component_id='input_value', component_property='value')])
def update_file_value(value_to_write):
print('set value!')
print('value_to_write: ' + str(value_to_write))
f = open('./value.txt', 'w')
f.write(str(value_to_write))
f.close()
return value_to_write
if __name__ == '__main__':
app.run_server(debug=True)
I walked through my process step by step as well:
| step | description | printed | cat | gui | |
| | | | | box | output |
|------+---------------------------------+--------------------------------------+-------+-------+--------|
| 0 | touch value.txt | - | - | - | - |
| 1 | echo "1" > value.txt | - | 1 | - | - |
| 2 | python debug-get-set.py | getting value! current_value: 1 (2x) | 1 | - | - |
| 3 | open localhost:8050 | set value! value_to_write: 1 | 1 | 1 | 1 |
| 4 | click in box; delete 1 | set value! written value: empty | empty | blank | blank |
| 5 | type 2 in box | set value! written value: 2 | 2 | 2 | 2 |
| 6 | click to remove cursor from box | no message | 2 | 2 | 2 |
| 6 | Ctrl+R; reload page | set value! value_to_write: 1 | 1 | 1 | 1 |
This seems odd to me, but I'm very new to dash, so please let me know where my thinking is awry. Throughout the changes, we can check four key values:
- the value read from the file, stored as
current_value - the
dcc.Inputdefault value, passed asvalue=current_value, to be shown as the prompt in the text input box - the value passed to the callback and written to the file,
value_to_write, which we call if ourdcc.Inputvalue changes (not sure howdashchecks for a change) - the return from the callback, put on the page with
html.Div(id='file_value_written')
Upon load, they all agree on the value being 1. It's printed, the file contains it, and it's displayed in the box and below the box. We change the box contents to 2, and the effect pushes through to the html.Div on the screen and the file (checked with cat). It's also still in the box, obviously.
When we reload we're told we're setting the file contents, but that should only change if we're in callback. That only happens if the current text box changes, and we didn't touch it. It almost behaves like the value currently in the box might be cached (or in some sense not really changed), and even when we delete/replace it with 2, the cached/stored value is 1. On refresh, things work in reverse: 2 is treated as the last value seen and the cached value, 1, shows up as a user change and is written. Is that a crazy interpretation?
What I expected: reloading would re-run things top to bottom, it should read 2 from the file, use 2 as the default value in the box, and wait for a callback trigger if the user changes what's in the box 2.
This was a wild chase to just work through in my head and I am coming up clueless. Thanks for taking a look!