Skip to content
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

Reimplement the live TUI using textual #274

Merged
merged 6 commits into from
Nov 9, 2023

Conversation

ayshiff
Copy link
Contributor

@ayshiff ayshiff commented Dec 14, 2022

Closes #238

Describe your changes
This patch ports TUI using rich to textual.

Testing performed

Here is a small sketch representing the different components of the live TUI and their interactions.

Capture d’écran, le 2022-12-14 à 16 54 26

Additional context

This is still a work in progress since I might need some help to:

  • Add proper test support (I took a look in tests/unit/test_tui_reporter.py but couldn't find the correct way to make it work with my work).
  • Prevent the default left-right arrow behavior of the textual Table to interfere with the switching threads behavior.
  • Remove the horizontal data table scroll.
  • Check that the dynamic behavior of the TUI is correct (it seems that some variables are wrongly updated some of the time).
  • Check that the styling match with the rich version (e.g. the data table).
  • Some refactoring to make everything nice.

Thanks for your help! :)

@godlygeek
Copy link
Contributor

Thanks a lot for the work on this! This is quite a large PR, so I haven't yet made time to review this, but I definitely appreciate the work you've put in here!

@godlygeek
Copy link
Contributor

Sorry, @ayshiff - we've owed you a response on this for far too long, and I just haven't had the bandwidth to sit down and give this a proper review.

First of all: holy cow, this is really impressive! Being able to use the mouse wheel to scroll the TUI is very, very cool. And it's much, much faster than the existing Rich TUI. So much faster that we probably need to put in some sort of a delay: top updates only once every 3 seconds by default, perhaps we ought to do something similar here...

I notice that right when the Textual TUI first appears, before the grid is populated for the first time, the live memory graph in the top right starts off narrow, and then when we start getting samples it abruptly expands to the appropriate width. That seems like a minor bug.

There's a small omission, as well: on the Rich TUI, there's a dotted line in between the "Current heap size:" line and the top of the location grid. That line isn't just a separator, it's also a "progress bar", let's say. It shows what percentage the current heap size is, compared to the maximum heap size we ever saw. I think we want to keep that, though we could pick a different way to draw it that feels more natural for Textual.

This handles different terminal sizes pretty well, but not perfectly. I notice that if there's not enough horizontal room for the Memory graph in the top right, it seems to line wrap (you'll notice this if you try making the terminal window too skinny). Also, I notice that if I fullscreen my terminal (63 lines x 239 columns, it seems), there are a few unnecessary blank lines above and below the "Current heap size" line.

To address your points:

Add proper test support (I took a look in tests/unit/test_tui_reporter.py but couldn't find the correct way to make it work with my work).

Let's hold off on worrying about tests for now. Let's get the interface as polished as we can and working just how we want it to, and then we'll figure out what automated testing we can do. We have a lot of flexibility here, and we can always choose to throw the existing tests away and start from scratch if that turns out to be what makes the most sense. I've never worked with Textual before, but the docs have a app.run_test() asynchronous context manager that seems to be used for driving the tests in Textual's own test suite, and which it looks like we ought to be able to use to drive ours as well, at least at first glance. We'll probably want to add pytest-asyncio as a test dependency if we go that route.

Prevent the default left-right arrows behavior of the textual Table to interfere with the switching threads behavior.

That's interesting - sometimes the arrows switch threads, sometimes they scroll the table! We may just need to pick different keys for these things. Perhaps < and > for switching threads instead of left and right arrow, and perhaps even a clickable button for users with mouse support enabled.

I noticed something else funny with the scroll bar as well - if I scroll the table all the way to the bottom, then switch threads, and then switch back to the first thread, I see that the scroll bar looks as though I'm at the bottom, when actually the rows being shown are the ones at the top. It looks like we may need to re-sync the scroll bar with the grid position, or re-scroll the grid to whatever position the scroll bar thinks we should be at. Maybe remember the position when we switch away from a thread, and try to scroll back to that same position when we return to that thread...

I'm not sure what the limit of what we can do for ourselves there is, and at what point we might need a feature request to the Textual devs.

Remove the horizontal data table scroll.

I wouldn't! If someone makes their terminal too narrow to be able to see all the columns, being able to scroll to see the others is a nice feature.

Check that the dynamic behavior of the TUI is correct (it seems that some variables are wrongly updated some of the time).

Can you give any specifics for that? I don't think I managed to reproduce that, but I'm not sure what I should have been looking for.

Check that the styling match with the rich version (e.g the data table).

I'm not too worried about the style matching. If we find a nicer or prettier way to display anything, I don't want to be held back because of backwards compatibility with how the old grid table looked. I'm happy to take this as an opportunity to modernize the look and feel, so I think we should make choices based on what looks and feels right, not just on what the Rich version looked like.


I realize that it's been a while since you sent this PR - is this still something that you're interested in pushing forward? If not, we can try to pick this up ourselves and polish it and finish it off sometime in the next month or so, but if you're interested we'd still be very glad to have your help, and I'll try to be more responsive to any future requests for comment.

I really can't stress enough: this really looks awesome already, and I'm thrilled with everything you've done so far. This is very, very cool.

@godlygeek
Copy link
Contributor

I realize that it's been a while since you sent this PR - is this still something that you're interested in pushing forward? If not, we can try to pick this up ourselves and polish it and finish it off sometime in the next month or so, but if you're interested we'd still be very glad to have your help, and I'll try to be more responsive to any future requests for comment.

Ping - are you still interested in pushing this forward, @ayshiff?

@ayshiff
Copy link
Contributor Author

ayshiff commented Apr 29, 2023

I realize that it's been a while since you sent this PR - is this still something that you're interested in pushing forward? If not, we can try to pick this up ourselves and polish it and finish it off sometime in the next month or so, but if you're interested we'd still be very glad to have your help, and I'll try to be more responsive to any future requests for comment.

Ping - are you still interested in pushing this forward, @ayshiff?

Yes definitely! Sorry for the delay, I've been a little busy lately.

@godlygeek godlygeek force-pushed the feat/tui-textual branch 6 times, most recently from 3ba7855 to e640ef1 Compare October 21, 2023 08:28
@godlygeek
Copy link
Contributor

@ayshiff We've decided to take this PR over. Holy cow, this was a lot more work than I expected, so thanks so much for getting the ball rolling for us!

I've got one last thing I need to ask you for, though. Would you mind editing the commit message for your commit to add a DCO signoff?

If you're using the github CLI, you should be able to do that using something like:

gh pr checkout -f 274

to check out the latest commits that I've pushed, then

git rebase -i c5672788e1472cb3a6eda4a65c400bd6ca8764a7~1

then change the first line from "pick" to "edit", and save and quit. From there you can:

git commit --amend -C HEAD -s

to add the signoff to the commit message, and finally

git rebase --continue

to finish rebasing and

git push --force-with-lease

to push the updated commits.

@ayshiff ayshiff marked this pull request as ready for review November 1, 2023 20:39
@ayshiff
Copy link
Contributor Author

ayshiff commented Nov 1, 2023

@godlygeek Thanks a lot for taking over my work! And sorry for having been a bit busy lately.
Can't wait to see the new TUI live using textual! :)

@codecov-commenter
Copy link

codecov-commenter commented Nov 9, 2023

Codecov Report

Attention: 19 lines in your changes are missing coverage. Please review.

Comparison is base (2defa44) 92.23% compared to head (5196081) 92.24%.
Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #274      +/-   ##
==========================================
+ Coverage   92.23%   92.24%   +0.01%     
==========================================
  Files          91       91              
  Lines       10872    11029     +157     
  Branches     1499     1520      +21     
==========================================
+ Hits        10028    10174     +146     
- Misses        841      851      +10     
- Partials        3        4       +1     
Flag Coverage Δ
cpp 85.72% <ø> (-0.20%) ⬇️
python_and_cython 95.49% <97.30%> (+0.04%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files Coverage Δ
src/memray/commands/live.py 94.44% <100.00%> (+20.53%) ⬆️
src/memray/commands/run.py 89.10% <100.00%> (ø)
src/memray/reporters/summary.py 100.00% <100.00%> (ø)
tests/integration/test_main.py 93.03% <ø> (+0.41%) ⬆️
tests/integration/test_tracing.py 99.81% <100.00%> (+<0.01%) ⬆️
tests/unit/test_cli.py 100.00% <100.00%> (ø)
tests/unit/test_tui_reporter.py 98.81% <98.52%> (-1.19%) ⬇️
src/memray/reporters/tui.py 96.36% <96.00%> (-2.50%) ⬇️

... and 5 files with indirect coverage changes

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

ayshiff and others added 3 commits November 8, 2023 20:02
Signed-off-by: Remi Doreau <remi.d45@gmail.com>
This test was leaving a profile function installed when it shouldn't.

Signed-off-by: Matt Wozniski <mwozniski@bloomberg.net>
This will allow us to migrate the TUI to Textual while leaving the
summary reporter on Rich.

Signed-off-by: Matt Wozniski <mwozniski@bloomberg.net>
@godlygeek godlygeek force-pushed the feat/tui-textual branch 2 times, most recently from 4fba1f6 to 33aba70 Compare November 9, 2023 02:11

default_sort_column_id = 1
sort_column_id = reactive(default_sort_column_id)
max_rows = reactive(None)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is used anywhere

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, will remove

snapshot = reactive(_EMPTY_SNAPSHOT)
paused = reactive(False)
disconnected = reactive(False)
footer_message = reactive("")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems is also not used anywhere

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, will remove


from memray import AllocationRecord
from memray import SocketReader
from memray._memray import size_fmt

MAX_MEMORY_RATIO = 0.95

DEFAULT_TERMINAL_LINES = 24
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this used? Seems that we copied it to summary.py

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Used only for type annotations.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, wait, I misread - I thought you were asking about the highlighted line in the diff, not the last line in it. Yep, that's unused now.

table.sort(table.ordered_columns[sort_column_id].key, reverse=True)

@staticmethod
def _percent_to_style(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this needed for something?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not anymore! Will remove.

Copy link
Member

@pablogsal pablogsal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Appart from the small nits to delete some unneeded things: LGTM.

Fantastic work @godlygeek! 🚀 I know how difficult was to do the refactor. You did a fantastic work ✨ Outstanding!

And thanks a lot for all the work and design in the initial version @ayshiff! This was certainly NOT a small issue, so this was super useful and you helped the project a lot ❤️

Signed-off-by: Matt Wozniski <mwozniski@bloomberg.net>
Everything this test exercises is also exercised by the
`test_live_tracking_server_exits_properly_on_sigint` test that still
remains in the `TestLiveRemoteSubcommand` class (same test name,
different test class). That test uses `_wait_until_process_blocks` to
ensure that the SIGINT is sent at a known point in the process's
execution, but this one can't. With this test, the SIGINT is sometimes
delivered while the TUI is still starting up, and at that point, the
signal can result in exceptions (teardown of the TUI tries to access
attributes that weren't created because startup was interrupted).

So, remove this test and rely on the remaining one for coverage of how
SIGINT behaves when interrupting our TUI.

Signed-off-by: Matt Wozniski <mwozniski@bloomberg.net>
Capture stdout from some tests that run the TUI, so that it doesn't
flash across the screen while running the test suite.

Signed-off-by: Matt Wozniski <mwozniski@bloomberg.net>
@godlygeek godlygeek merged commit 38e9ac8 into bloomberg:main Nov 9, 2023
34 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Reimplement the live TUI using textual
5 participants