-
Notifications
You must be signed in to change notification settings - Fork 4k
Clean up file update calls #2597
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
Clean up file update calls #2597
Conversation
tconkling
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Without tests, it's hard to understand what the broken behavior currently is, and how this fixes it.
If I understand correctly, there are circumstances where UploadedFileManager.on_files_updated is being emitted too frequently, and this PR fixes that issue?
(What's the harm caused the the signal being emitted too frequently?)
Is it possible to add a test that fails on the current, broken behavior and succeeds with this PR, so that we can prevent a regression?
Same with FileUploader.tsx - is it possible to add a test that validates the setState is called the expected number of times (or whatever) for file removals?
|
That's kind of the difficult part. We do have a test that was failing but it seems like the regression itself was flaky (#2567). And tbh I don't quite get how all this relates to the deploy button change. However as I started looking into the regression I noticed that we were making a lot of calls that wasn't really needed. When I optimized all that it seems like I can't reproduce the issue anymore 🤷♀️ I'll add in some unit tests that specifically tests the replace functionality and a unit test to make sure |
7bee202 to
ca46e77
Compare
ca46e77 to
7fe18bf
Compare
6772958 to
58dcb34
Compare
tconkling
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey, I'm being a total pain in the ass, and I apologize :( - I'm just finding a lot of little things to be surprising or confusing. I've left a number of requests for comments.
I'm also wondering if there's a cleaner way to track "number of uploaded files":
- In Python, why are we tracking
UploadedFileManager._file_counts_by_id, and how does that number relate to the lengths of theUploadedFileManager._files_by_idlists? - In the frontend, why are we tracking
FileUploader.state.validFilesand how does that number relate to the length of theFileUploader.state.filesarray?
In general, I'm wary of using multiple independent bits of state to track a single thing, because they can get out of sync, and it makes future changes more tricky to reason about. Is there a more atomic way of tracking these things?
| this.props.uploadClient | ||
| .uploadFiles( | ||
| this.props.element.id, | ||
| [file], | ||
| [updatedFile], | ||
| this.state.validFiles, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't your doing, but I find the updatedFile vs file thing happening here to be really confusing. It looks like this.handleFile is returning a new object, but it's actually just mutating its passed-in object, which means that file and updatedFile are the same thing. (I wish that "handleFile" just didn't return the passed-in file.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was my doing :(
| public removeFile = (fileId: string): void => { | ||
| this.setState(state => { | ||
| const filteredFiles = state.files.filter(file => file.id !== fileId) | ||
|
|
||
| return { | ||
| status: filteredFiles.length ? FileStatus.UPLOADED : FileStatus.READY, | ||
| errorMessage: undefined, | ||
| files: filteredFiles, | ||
| validFiles: state.validFiles - 1, | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if this function is called with a non-existent fileId? (Or with a fileId that's not "valid"). Is that possible? It looks like validFiles would be improperly decremented. Is there a sanity check we can do here, to throw an error if someone down the road calls the function improperly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True, we can do something like state.validFiles - (state.files.length - filteredFiles.length)
| try: | ||
| total_files = self._require_arg(args, "totalFiles") | ||
| self._file_mgr.update_file_count( | ||
| session_id=session_id, | ||
| widget_id=widget_id, | ||
| file_count=int(total_files), | ||
| ) | ||
|
|
||
| except Exception as e: | ||
| self._file_mgr.update_file_count( | ||
| session_id=session_id, | ||
| widget_id=widget_id, | ||
| file_count=1, | ||
| ) | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this try/except handling errors thrown by _require_arg or update_file_count or both? Why would we want to swallow an error thrown here? (My assumption from glancing at the code is that it's to catch a missing "totalFiles" argument - if that's the case, why would this argument be missing? Is it optional from the client?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It handles the errors from _require_arg. It's not optional from what we have currently on the client side but I left it open so that it could work with in the future with totalFiles as an optional param. We can make it an optional parameter on the client side if that's preferred.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool. How about this slight tweak:
try:
total_files = int(self._require_arg(args, "totalFiles"))
except:
total_files = 1
self._file_mgr.update_file_count(
session_id=session_id,
widget_id=widget_id,
file_count=total_files
)
This way we don't erroneously catch exceptions thrown by update_file_count
dc395c2 to
7063301
Compare
7063301 to
dd8ad16
Compare
tconkling
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! The additional comments you added make a huge difference.
|
|
||
| // Can delete | ||
| cy.get("[data-testid='fileDeleteBtn'] button") | ||
| .first() | ||
| .click(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this missing a check that the file's actually been deleted, after the button is clicked?
| try: | ||
| total_files = self._require_arg(args, "totalFiles") | ||
| self._file_mgr.update_file_count( | ||
| session_id=session_id, | ||
| widget_id=widget_id, | ||
| file_count=int(total_files), | ||
| ) | ||
|
|
||
| except Exception as e: | ||
| self._file_mgr.update_file_count( | ||
| session_id=session_id, | ||
| widget_id=widget_id, | ||
| file_count=1, | ||
| ) | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool. How about this slight tweak:
try:
total_files = int(self._require_arg(args, "totalFiles"))
except:
total_files = 1
self._file_mgr.update_file_count(
session_id=session_id,
widget_id=widget_id,
file_count=total_files
)
This way we don't erroneously catch exceptions thrown by update_file_count
|
LGTM. Verified functionality with multiple CSV files. Normal file uploader functionality also looks good! |
* develop: Fix svg rendering in st.image() (streamlit#2666) Indicate widgets need to have labels (streamlit#2688) Clean up file update calls (streamlit#2597) Revert "🔧 "Run on save" now defaults to true (streamlit#2641)" (streamlit#2694)
* develop: Fix svg rendering in st.image() (streamlit#2666) Indicate widgets need to have labels (streamlit#2688) Clean up file update calls (streamlit#2597) Revert "🔧 "Run on save" now defaults to true (streamlit#2641)" (streamlit#2694)
* Clean up file update calls * Add more tests * Move updating of file count to upload file request handler * Fix tests * Fix deleting * Address PR comments * PR cleanup * Fix test
* develop: Autofocus "clear cache" button (#2739) Fix checkbox spacing (#2738) Fix progress bar alignment (#2734) Fix select menu not autoselecting first item (#2732) Show user command line in disconnect dialog (#2735) Up version to 0.76.0 Update change log Improve usage warning wording and formatting Finally remove beta versions of set_page_config and color_picker (#2711) Finally remove beta versions of set_page_config and color_picker (#2711) Clean up file update calls (#2597)
* develop: Slider thumb values are always visible (streamlit#2724) Update component-template submodule to latest (streamlit#2767) `allow_multiple_files` -> `accept_multiple_files` (streamlit#2761) Autofocus "clear cache" button (streamlit#2739) Fix checkbox spacing (streamlit#2738) Fix progress bar alignment (streamlit#2734) Fix select menu not autoselecting first item (streamlit#2732) Show user command line in disconnect dialog (streamlit#2735) Up version to 0.76.0 Update change log Improve usage warning wording and formatting Finally remove beta versions of set_page_config and color_picker (streamlit#2711) Finally remove beta versions of set_page_config and color_picker (streamlit#2711) Clean up file update calls (streamlit#2597)
Issue: #2561
Description:
Unclear why the deploy button caused a regression, potentially because of new message type. Looking at the changes for the deploy button, it looks correct. Instead cleaned up areas of file uploader to become more stable.
Changes include
on_files_updatedwas being signaled more than required. Minimized requests to update.Tests added
Test cases
[ ] Works with multiple sessions
[ ] Upload single file
[ ] Upload another single file replaces initial file
[ ] Upload multiple files
[ ] Delete file(s)
Contribution License Agreement
By submitting this pull request you agree that all contributions to this project are made under the Apache 2.0 license.