From a31ea469ba87461bb7dcc8b2cba66b97c9da3fa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Let=C3=ADcia=20Barbosa=20Neves?= Date: Fri, 26 Sep 2025 17:43:00 -0300 Subject: [PATCH 1/4] =?UTF-8?q?=E2=9C=A8=20Add=20support=20for=20'time'=20?= =?UTF-8?q?and=20'datetime-local'=20input=20types?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Update PropTypes in Input.react.js to include 'time' and 'datetime-local' - These input types have wide browser compatibility and are commonly requested - Fixes PyCharm type warnings when using these input types with dcc.Input Closes #3385 --- components/dash-core-components/src/components/Input.react.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/dash-core-components/src/components/Input.react.js b/components/dash-core-components/src/components/Input.react.js index 472a84fc1d..be020b7cbc 100644 --- a/components/dash-core-components/src/components/Input.react.js +++ b/components/dash-core-components/src/components/Input.react.js @@ -234,6 +234,8 @@ Input.propTypes = { 'tel', 'url', 'hidden', + 'time', + 'datetime-local', ]), /** From 6b056ea91511f9556355e8b000b1da57023c6e6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Let=C3=ADcia=20Barbosa=20Neves?= Date: Fri, 26 Sep 2025 17:43:34 -0300 Subject: [PATCH 2/4] =?UTF-8?q?=F0=9F=A7=AA=20Update=20integration=20tests?= =?UTF-8?q?=20for=20new=20input=20types?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add 'time' and 'datetime-local' to ALLOWED_TYPES in test_input_basics.py - Add proper test values for time and datetime inputs - Enhance test logic to handle time-specific input validation - Ensures existing test coverage includes the new input types --- .../tests/integration/input/test_input_basics.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/components/dash-core-components/tests/integration/input/test_input_basics.py b/components/dash-core-components/tests/integration/input/test_input_basics.py index 2b8eaa1c85..903a9dad5d 100644 --- a/components/dash-core-components/tests/integration/input/test_input_basics.py +++ b/components/dash-core-components/tests/integration/input/test_input_basics.py @@ -13,6 +13,8 @@ "tel", "url", "hidden", + "time", + "datetime-local", ) @@ -46,10 +48,16 @@ def cb_render(*vals): dash_dcc.find_element("#input_hidden").get_attribute("type") == "hidden" ), "hidden input element should present with hidden type" - for atype in ALLOWED_TYPES[:-1]: - dash_dcc.find_element(f"#input_{atype}").send_keys( - f"test intp001 - input[{atype}]" - ) + # Test all types except hidden (which should not accept user input) + testable_types = [t for t in ALLOWED_TYPES if t != 'hidden'] + for atype in testable_types: + element = dash_dcc.find_element(f"#input_{atype}") + if atype == 'time': + element.send_keys("12:30:45") + elif atype == 'datetime-local': + element.send_keys("2023-12-31T23:59:59") + else: + element.send_keys(f"test intp001 - input[{atype}]") with pytest.raises(WebDriverException): dash_dcc.find_element("#input_hidden").send_keys("no interaction") From af006f02b08b048c161f13533ee6e6a9fbfa0050 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Let=C3=ADcia=20Barbosa=20Neves?= Date: Fri, 26 Sep 2025 17:43:45 -0300 Subject: [PATCH 3/4] =?UTF-8?q?=F0=9F=A7=AA=20Add=20comprehensive=20tests?= =?UTF-8?q?=20for=20time=20and=20datetime-local=20inputs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Create dedicated test file for new input type functionality - Test time input with proper time values and callbacks - Test datetime-local input with ISO datetime strings - Test debounce functionality with time inputs - Test min/max constraints with datetime-local inputs - Provides full test coverage for the new input types --- .../input/test_time_datetime_inputs.py | 152 ++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 components/dash-core-components/tests/integration/input/test_time_datetime_inputs.py diff --git a/components/dash-core-components/tests/integration/input/test_time_datetime_inputs.py b/components/dash-core-components/tests/integration/input/test_time_datetime_inputs.py new file mode 100644 index 0000000000..01da11f146 --- /dev/null +++ b/components/dash-core-components/tests/integration/input/test_time_datetime_inputs.py @@ -0,0 +1,152 @@ +""" +Tests for time and datetime-local input types in dcc.Input component. + +This module tests the newly added support for 'time' and 'datetime-local' +input types that were previously unsupported in dcc.Input. +""" + +import pytest +from dash import Dash, Input, Output, dcc, html + + +def test_time_input_functionality(dash_dcc): + """Test that time input type works correctly.""" + app = Dash(__name__) + app.layout = html.Div([ + dcc.Input( + id='time-input', + type='time', + step=1, + value='14:30:15' + ), + html.Div(id='time-output') + ]) + + @app.callback( + Output('time-output', 'children'), + Input('time-input', 'value') + ) + def update_time_output(time_value): + return f"Time: {time_value}" + + dash_dcc.start_server(app) + + # Check that the input has the correct type + time_input = dash_dcc.find_element('#time-input') + assert time_input.get_attribute('type') == 'time' + assert time_input.get_attribute('value') == '14:30:15' + + # Test updating the time value + time_input.clear() + time_input.send_keys('09:45:30') + + # Wait for callback to update + dash_dcc.wait_for_text_to_equal('#time-output', 'Time: 09:45:30') + + assert dash_dcc.get_logs() == [] + + +def test_datetime_local_input_functionality(dash_dcc): + """Test that datetime-local input type works correctly.""" + app = Dash(__name__) + app.layout = html.Div([ + dcc.Input( + id='datetime-input', + type='datetime-local', + step=1, + value='2023-12-25T18:30:00' + ), + html.Div(id='datetime-output') + ]) + + @app.callback( + Output('datetime-output', 'children'), + Input('datetime-input', 'value') + ) + def update_datetime_output(datetime_value): + return f"DateTime: {datetime_value}" + + dash_dcc.start_server(app) + + # Check that the input has the correct type + datetime_input = dash_dcc.find_element('#datetime-input') + assert datetime_input.get_attribute('type') == 'datetime-local' + assert datetime_input.get_attribute('value') == '2023-12-25T18:30:00' + + # Test updating the datetime value + datetime_input.clear() + datetime_input.send_keys('2024-01-01T12:00:00') + + # Wait for callback to update + dash_dcc.wait_for_text_to_equal('#datetime-output', 'DateTime: 2024-01-01T12:00:00') + + assert dash_dcc.get_logs() == [] + + +def test_time_input_with_debounce(dash_dcc): + """Test that time input works correctly with debounce.""" + app = Dash(__name__) + app.layout = html.Div([ + dcc.Input( + id='time-debounce-input', + type='time', + debounce=True, + value='12:00:00' + ), + html.Div(id='time-debounce-output') + ]) + + @app.callback( + Output('time-debounce-output', 'children'), + Input('time-debounce-input', 'value') + ) + def update_debounce_output(time_value): + return f"Time with debounce: {time_value}" + + dash_dcc.start_server(app) + + time_input = dash_dcc.find_element('#time-debounce-input') + assert time_input.get_attribute('type') == 'time' + + # With debounce=True, value should update only after losing focus or Enter key + time_input.clear() + time_input.send_keys('15:30:45') + + # Trigger blur event to commit the debounced value + dash_dcc.find_element('body').click() # Click somewhere else to blur + + dash_dcc.wait_for_text_to_equal('#time-debounce-output', 'Time with debounce: 15:30:45') + + assert dash_dcc.get_logs() == [] + + +def test_datetime_local_input_with_min_max(dash_dcc): + """Test that datetime-local input works with min and max attributes.""" + app = Dash(__name__) + app.layout = html.Div([ + dcc.Input( + id='datetime-minmax-input', + type='datetime-local', + min='2023-01-01T00:00:00', + max='2023-12-31T23:59:59', + value='2023-06-15T12:00:00' + ), + html.Div(id='datetime-minmax-output') + ]) + + @app.callback( + Output('datetime-minmax-output', 'children'), + Input('datetime-minmax-input', 'value') + ) + def update_minmax_output(datetime_value): + return f"DateTime with constraints: {datetime_value}" + + dash_dcc.start_server(app) + + datetime_input = dash_dcc.find_element('#datetime-minmax-input') + assert datetime_input.get_attribute('type') == 'datetime-local' + assert datetime_input.get_attribute('min') == '2023-01-01T00:00:00' + assert datetime_input.get_attribute('max') == '2023-12-31T23:59:59' + assert datetime_input.get_attribute('value') == '2023-06-15T12:00:00' + + assert dash_dcc.get_logs() == [] From f516e6eefc329446f55561be0008dc4e7937f25c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Let=C3=ADcia=20Barbosa=20Neves?= Date: Sat, 27 Sep 2025 11:03:53 -0300 Subject: [PATCH 4/4] =?UTF-8?q?=F0=9F=A7=B9=20Fix=20pylint=20issues=20in?= =?UTF-8?q?=20test=5Ftime=5Fdatetime=5Finputs.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove unused pytest import - Clean up trailing whitespace - Code now rated 10.00/10 by pylint --- .../input/test_time_datetime_inputs.py | 47 +++++++++---------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/components/dash-core-components/tests/integration/input/test_time_datetime_inputs.py b/components/dash-core-components/tests/integration/input/test_time_datetime_inputs.py index 01da11f146..fb45bfdd41 100644 --- a/components/dash-core-components/tests/integration/input/test_time_datetime_inputs.py +++ b/components/dash-core-components/tests/integration/input/test_time_datetime_inputs.py @@ -5,7 +5,6 @@ input types that were previously unsupported in dcc.Input. """ -import pytest from dash import Dash, Input, Output, dcc, html @@ -21,28 +20,28 @@ def test_time_input_functionality(dash_dcc): ), html.Div(id='time-output') ]) - + @app.callback( Output('time-output', 'children'), Input('time-input', 'value') ) def update_time_output(time_value): return f"Time: {time_value}" - + dash_dcc.start_server(app) - + # Check that the input has the correct type time_input = dash_dcc.find_element('#time-input') assert time_input.get_attribute('type') == 'time' assert time_input.get_attribute('value') == '14:30:15' - + # Test updating the time value time_input.clear() time_input.send_keys('09:45:30') - + # Wait for callback to update dash_dcc.wait_for_text_to_equal('#time-output', 'Time: 09:45:30') - + assert dash_dcc.get_logs() == [] @@ -58,28 +57,28 @@ def test_datetime_local_input_functionality(dash_dcc): ), html.Div(id='datetime-output') ]) - + @app.callback( Output('datetime-output', 'children'), Input('datetime-input', 'value') ) def update_datetime_output(datetime_value): return f"DateTime: {datetime_value}" - + dash_dcc.start_server(app) - + # Check that the input has the correct type datetime_input = dash_dcc.find_element('#datetime-input') assert datetime_input.get_attribute('type') == 'datetime-local' assert datetime_input.get_attribute('value') == '2023-12-25T18:30:00' - + # Test updating the datetime value datetime_input.clear() datetime_input.send_keys('2024-01-01T12:00:00') - + # Wait for callback to update dash_dcc.wait_for_text_to_equal('#datetime-output', 'DateTime: 2024-01-01T12:00:00') - + assert dash_dcc.get_logs() == [] @@ -95,28 +94,28 @@ def test_time_input_with_debounce(dash_dcc): ), html.Div(id='time-debounce-output') ]) - + @app.callback( Output('time-debounce-output', 'children'), Input('time-debounce-input', 'value') ) def update_debounce_output(time_value): return f"Time with debounce: {time_value}" - + dash_dcc.start_server(app) - + time_input = dash_dcc.find_element('#time-debounce-input') assert time_input.get_attribute('type') == 'time' - + # With debounce=True, value should update only after losing focus or Enter key time_input.clear() time_input.send_keys('15:30:45') - + # Trigger blur event to commit the debounced value dash_dcc.find_element('body').click() # Click somewhere else to blur - + dash_dcc.wait_for_text_to_equal('#time-debounce-output', 'Time with debounce: 15:30:45') - + assert dash_dcc.get_logs() == [] @@ -133,20 +132,20 @@ def test_datetime_local_input_with_min_max(dash_dcc): ), html.Div(id='datetime-minmax-output') ]) - + @app.callback( Output('datetime-minmax-output', 'children'), Input('datetime-minmax-input', 'value') ) def update_minmax_output(datetime_value): return f"DateTime with constraints: {datetime_value}" - + dash_dcc.start_server(app) - + datetime_input = dash_dcc.find_element('#datetime-minmax-input') assert datetime_input.get_attribute('type') == 'datetime-local' assert datetime_input.get_attribute('min') == '2023-01-01T00:00:00' assert datetime_input.get_attribute('max') == '2023-12-31T23:59:59' assert datetime_input.get_attribute('value') == '2023-06-15T12:00:00' - + assert dash_dcc.get_logs() == []