-
Notifications
You must be signed in to change notification settings - Fork 118
(4a -> 4) Add UnlinkedVideosTable to SessionsDock
#1720
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
(4a -> 4) Add UnlinkedVideosTable to SessionsDock
#1720
Conversation
WalkthroughThe recent updates focus on enhancing video linkage within the SLEAP application. Key improvements include adding checks and updates for unlinked videos, enabling a "link video" button, and updating models and tables for better management of video sessions. Additionally, a new command for linking videos to sessions has been introduced, along with minor adjustments and test enhancements to ensure smooth functionality. Changes
Poem
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (invoked as PR comments)
Additionally, you can add CodeRabbit Configration 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.
Looks pretty good, a few requests. I am sure we will find out if anything else is missing in tests.
sleap/gui/dataviews.py
Outdated
| class UnlinkedVideosTableModel(GenericTableModel): | ||
| properties = ("path", "h", "w", "frames", "channels") | ||
|
|
||
| def item_to_data(self, obj, item): | ||
| res = {} | ||
| res["path"] = item.filename | ||
| res["h"] = item.height | ||
| res["w"] = item.width | ||
| res["frames"] = item.num_framesd | ||
| res["channels"] = item.channels | ||
| return res | ||
|
|
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.
Remove - I think we should just be able to re-use the VideosTableModel since we display the exact same data.
sleap/gui/widgets/docks.py
Outdated
| VideosTableModel, | ||
| CamerasTableModel, | ||
| SessionsTableModel, | ||
| UnlinkedVideosTableModel, |
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.
Remove
sleap/gui/widgets/docks.py
Outdated
| ): | ||
| self.sessions_model_type = SessionsTableModel | ||
| self.camera_model_type = CamerasTableModel | ||
| self.unlinked_videos_model_type = UnlinkedVideosTableModel |
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.
Change to VideosTableModel
sleap/io/dataset.py
Outdated
| self._track_occupancy = dict() | ||
| self._frame_count_cache = dict() | ||
| self._session_by_video: Dict[Video, RecordingSession] = dict() | ||
| self.linkage_of_videos = {"linked": [], "unlinked": []} |
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.
Let's stick with previous convention and add an underscore:
| self.linkage_of_videos = {"linked": [], "unlinked": []} | |
| self._linkage_of_videos = {"linked": [], "unlinked": []} |
just so that others know not just to be using/updating this variable wherever (supposedly "private" to the containing class, even though that doesn't exist in python).
| for video in session.videos: | ||
| self._session_by_video[video] = session | ||
|
|
||
| # Build linkage of videos by session |
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.
We also want to handle just updating the cache in LabelsDataCache.update
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.
The LinkVideoToSession command needs some work.
sleap/gui/commands.py
Outdated
| return len(filename) > 0 | ||
|
|
||
| class LinkVideoToSession(EditCommand): | ||
| topics = [UpdateTopic.video] |
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.
A bit confusing, it seems like the update topic would be the video, but actually, we are making changes to the RecordingSession, not to the Video.
| topics = [UpdateTopic.video] | |
| topics = [UpdateTopic.sessions] |
sleap/gui/commands.py
Outdated
| video = context.state["video"] | ||
| session = context.state["session"] |
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.
The Video and RecordingSession should come from the selected items in the UnlinkedVideosTable and SessionsTable respectively. We also need the selected camera as the last piece of our linking.
| video = context.state["video"] | |
| session = context.state["session"] | |
| video = context.state["selected_unlinked_video"] | |
| session = context.state["selected_session"] | |
| camcorder = context.state["selected_camera"] |
sleap/gui/commands.py
Outdated
| if video is None: | ||
| raise ValueError("No video selected.") | ||
|
|
||
| if session is None: | ||
| raise ValueError("No session selected.") |
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 is okay, but also, we should never get the ValueError because we are disabling the video_link_button when there is no selected RecordingSession or no selected Video. And, we also need a selected Camcorder.
sleap/gui/app.py
Outdated
| "generate_button" | ||
| ].setEnabled(has_videos) | ||
| self._buttons["remove session"].setEnabled(has_selected_session) | ||
| self._buttons["link video"].setEnabled(has_selected_video) |
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.
We require three items to perform the LinkVideoToSession command:
- a selected
RecordingSession - a selected
Videoand a - selected
Camcorder
We should probably check thathas_selected_video and has_selected_session and has_selected_camera.
| self._buttons["link video"].setEnabled(has_selected_video) | |
| self._buttons["link video"].setEnabled(has_selected_video and has_selected_session and has_selected_camera) |
sleap/gui/commands.py
Outdated
| @staticmethod | ||
| def ask(context: CommandContext, params: dict) -> bool: | ||
| """Shows gui for adding video to project.""" | ||
| if context.state["video"] is None: | ||
| QtWidgets.QMessageBox(text="No video selected.").exec_() | ||
| return False | ||
|
|
||
| if context.state["session"] is None: | ||
| QtWidgets.QMessageBox(text="No session selected.").exec_() | ||
| return False | ||
|
|
||
| return True |
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.
Remove - the ask method is intended to be (although has not always been) used to ask the user for additional input through the GUI (i.e. the name of a file, "are you sure", etc.).
| @staticmethod | |
| def ask(context: CommandContext, params: dict) -> bool: | |
| """Shows gui for adding video to project.""" | |
| if context.state["video"] is None: | |
| QtWidgets.QMessageBox(text="No video selected.").exec_() | |
| return False | |
| if context.state["session"] is None: | |
| QtWidgets.QMessageBox(text="No session selected.").exec_() | |
| return False | |
| return True |
sleap/gui/commands.py
Outdated
| if session is None: | ||
| raise ValueError("No session selected.") | ||
|
|
||
| video.recording_session = session |
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.
Hmm... that attribute doesn't exist. We intentionally tried to develop the multiview feature to leave existing datastructures untouched. Instead, try using
| video.recording_session = session | |
| session.add_video(video=video, camcorder=camcorder) |
sleap/gui/commands.py
Outdated
| raise ValueError("No session selected.") | ||
|
|
||
| video.recording_session = session | ||
|
|
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.
Lets also reset the selected video and camera here:
| # Reset the selected camera and video | |
| context.state["selected_camera"] = None | |
| context.state["selected_unlinked_video"] = None |
UnlinkedVideosTable to SessionsDockUnlinkedVideosTable to SessionsDock
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## liezl/add-gui-elements-for-sessions #1720 +/- ##
=======================================================================
+ Coverage 73.37% 73.84% +0.46%
=======================================================================
Files 134 135 +1
Lines 23973 24689 +716
=======================================================================
+ Hits 17591 18231 +640
- Misses 6382 6458 +76 ☔ View full report in Codecov by Sentry. |
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.
Actionable comments posted: 1
Review Status
Configuration used: CodeRabbit UI
Files selected for processing (6)
- sleap/gui/app.py (5 hunks)
- sleap/gui/commands.py (2 hunks)
- sleap/gui/dataviews.py (1 hunks)
- sleap/gui/widgets/docks.py (5 hunks)
- sleap/io/dataset.py (7 hunks)
- tests/gui/widgets/test_docks.py (2 hunks)
Files not reviewed due to errors (2)
- (no review received)
- (no review received)
Files skipped from review due to trivial changes (1)
- sleap/gui/dataviews.py
Additional Context Used
Additional comments not posted (11)
tests/gui/widgets/test_docks.py (1)
194-251: The test casetest_sessions_dock_unlinked_videos_tableeffectively covers the functionality of the unlinked videos table within theSessionsDock. It checks the initial state, the update mechanism after unlinking videos, and the functionality of the "Link" button. However, consider adding assertions to verify the state of thelinkedvideos in the cache after linking and unlinking operations to ensure bothlinkedandunlinkedlists are correctly updated.sleap/gui/widgets/docks.py (5)
626-634: The creation of the "Link Video" button withincreate_video_link_buttonmethod is well-implemented. It's clear and follows the established pattern for adding buttons to docks. Just ensure that thelinkVideoToSessioncommand is correctly implemented and handles all necessary logic for linking videos.
644-646: The creation ofunlinked_videos_modelwithincreate_modelsmethod is correctly implemented. However, it's important to ensure that the items passed to the model are indeed the unlinked videos. This might require filtering or additional logic to separate linked from unlinked videos based on the current session's state.
668-672: The creation ofunlinked_videos_tableis correctly implemented, following the established pattern for adding tables to docks. Ensure that the table is properly configured to display the relevant information about unlinked videos and that interactions with the table (e.g., selecting a video to link) are handled appropriately.
678-680: The connection ofupdate_unlinked_videos_modelto theselected_sessionstate change is crucial for ensuring that the unlinked videos table is updated when the selected session changes. Verify thatupdate_unlinked_videos_modelcorrectly updates the model with the new set of unlinked videos corresponding to the newly selected session.
724-727: Adding the unlinked videos table and the "Link Video" button to the dock's layout is correctly done. This ensures that users have the necessary UI components to manage unlinked videos within theSessionsDock. It's important to test the UI to ensure that the table and button are displayed correctly and that the button's functionality integrates seamlessly with the rest of the application.sleap/io/dataset.py (5)
114-114: The addition of_linkage_of_videosto track linked and unlinked videos and the corresponding logic to update this tracking seem well-integrated and align with the PR objectives. Ensure that theupdate_linkage_of_videosmethod is robust and correctly maintains the linkage status of videos across various operations in theLabelsDataCache.Also applies to: 131-137, 172-172, 174-184, 205-206
1737-1737: The update toremove_session_videoto callself._cache.update()after removing a video from a session is a good practice for maintaining cache consistency. Verify that this cache update operation is efficient and does not introduce performance issues.
1737-1737: The addition of theload_nwbclass method to support loading labels from NWB files is a valuable enhancement. Ensure that the implementation of thereadfunction for the NWB format is robust and that theload_nwbmethod has been thoroughly tested to confirm its correct functionality.
1737-1737: Themerge_nodesmethod is a useful addition for managing skeletons within theLabelsclass. Ensure thorough testing to verify that it correctly updates instances and the skeleton, handles edge cases, and maintains data integrity.
1737-1737: The addition ofmake_gui_video_callbackandmake_video_callbackmethods enhances theLabelsclass by providing mechanisms to handle missing videos. Verify the effectiveness of the generated callback functions and their correct integration into the video loading process.
| self.unlinked_videos_model_type = VideosTableModel | ||
| super().__init__( | ||
| name="Sessions", | ||
| main_window=main_window, | ||
| model_type=[self.sessions_model_type, self.camera_model_type], | ||
| model_type=[self.sessions_model_type, self.camera_model_type, self.unlinked_videos_model_type], |
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.
Tip
Codebase Verification
The verification process reveals that SessionsDock is instantiated in two places within the codebase, and neither instantiation includes the unlinked_videos_model_type as a parameter. This oversight could lead to runtime errors, confirming the initial review comment's concern. It is recommended to ensure that unlinked_videos_model_type is correctly passed and utilized wherever SessionsDock is instantiated.
Analysis chain
Adding unlinked_videos_model_type as an initialization parameter for SessionsDock is a good approach to maintain consistency with other docks. However, ensure that the unlinked_videos_model_type is correctly passed and utilized wherever SessionsDock is instantiated to avoid runtime errors.
Scripts Executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Verify that SessionsDock is correctly instantiated with unlinked_videos_model_type
rg "SessionsDock\(" --type py
Length of output: 251
Description
Very similar steps to
SessionsTable(#1654) andCamerasTable(#1671) (to be filled in), except for these few items:{linked: ..., unlinked: ...}toLabelsDataCachethat remembers which videos are linked/unlinked to aRecordingSessioninlabels.sessions(this dictionary will be used for the items in theUnlinkedVideosTable)CommandContext.link_video_to_cameramethod to link aVideoto aRecordingSessionCommandContextmethod created above)Types of changes
Does this address any currently open issues?
[list open issues here]
Outside contributors checklist
Thank you for contributing to SLEAP!
❤️
Summary by CodeRabbit