diff --git a/e2e/scripts/st_file_uploader.py b/e2e/scripts/st_file_uploader.py index 1ecc534993b3..5475d1e2d496 100644 --- a/e2e/scripts/st_file_uploader.py +++ b/e2e/scripts/st_file_uploader.py @@ -20,6 +20,10 @@ else: st.text(single_file.read()) +# Here and throughout this file, we use if st._is_running_with_streamlit: +# since we also run e2e python files in "bare Python mode" as part of our +# Python tests, and this doesn't work in that circumstance +# st.session_state can only be accessed while running with streamlit if st._is_running_with_streamlit: st.write(repr(st.session_state.single) == repr(single_file)) @@ -56,3 +60,20 @@ st.text("No upload") else: st.text(form_file.read()) + + +if st._is_running_with_streamlit: + if not st.session_state.get("counter"): + st.session_state["counter"] = 0 + + def file_uploader_on_change(): + st.session_state.counter += 1 + + st.file_uploader( + "Drop a file:", + type=["txt"], + key="on_change_file_uploader_key", + on_change=file_uploader_on_change, + ) + + st.text(st.session_state.counter) diff --git a/e2e/specs/st_file_uploader.spec.js b/e2e/specs/st_file_uploader.spec.js index 9194efc665ad..3bd0f7410baa 100644 --- a/e2e/specs/st_file_uploader.spec.js +++ b/e2e/specs/st_file_uploader.spec.js @@ -393,4 +393,51 @@ describe("st.file_uploader", () => { ); }); }); + + // regression test for https://github.com/streamlit/streamlit/issues/4256 bug + it("does not call a callback when not changed", () => { + const fileName1 = "file1.txt"; + const uploaderIndex = 4; + + cy.fixture(fileName1).then(file1 => { + const files = [ + { fileContent: file1, fileName: fileName1, mimeType: "text/plain" } + ]; + + // Script contains counter variable stored in session_state with + // default value 0. We increment counter inside file_uploader callback + // Since callback did not called at this moment, counter value should + // be equal 0 + cy.getIndexed("[data-testid='stText']", uploaderIndex).should( + "contain.text", + "0" + ); + + // Uploading file, should invoke on_change call and counter increment + cy.getIndexed( + "[data-testid='stFileUploadDropzone']", + uploaderIndex + ).attachFile(files[0], { + force: true, + subjectType: "drag-n-drop", + events: ["dragenter", "drop"] + }); + + // Make sure callback called + cy.getIndexed("[data-testid='stText']", uploaderIndex).should( + "contain.text", + "1" + ); + + // On rerun, make sure callback is not called, since file not changed + cy.get("body").type("r"); + cy.wait(1000); + + // Counter should be still equal 1 + cy.getIndexed("[data-testid='stText']", uploaderIndex).should( + "contain.text", + "1" + ); + }); + }); }); diff --git a/scripts/run_bare_integration_tests.py b/scripts/run_bare_integration_tests.py index 1123670b7e87..67bcb71cc59b 100755 --- a/scripts/run_bare_integration_tests.py +++ b/scripts/run_bare_integration_tests.py @@ -29,9 +29,6 @@ from typing import Set import click -import matplotlib - -IS_PYTHON_3_6 = sys.version_info[:2] == (3, 6) # Where we expect to find the example files. E2E_DIR = "e2e/scripts" @@ -47,10 +44,6 @@ # that doesn't require a display. os.environ["MPLBACKEND"] = "Agg" -# magic.py uses contextlib.asynccontextmanager, which is Python 3.7+ -if IS_PYTHON_3_6: - EXCLUDED_FILENAMES.add("st_magic.py") - def _command_to_string(command): if isinstance(command, list):