-
Notifications
You must be signed in to change notification settings - Fork 433
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
Fix animation of long lines #247
Conversation
Nice! Should the size be retrieved more frequently since there is no guarantee it will remain the same during the entire session? |
I'm trying to think of the ways that might happen--would it only happen if the user resized the terminal while a pipx command was running? I wasn't worrying about it, but |
I think something like |
OK, I moved Do you think it needs to be in the |
pipx/animate.py
Outdated
cur_line = f"{message}{s}" | ||
if len(message) <= term_cols - 4: | ||
cur_line = f"{message}{s}" | ||
else: |
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.
Also I think for this to not suffer easily regressions going ahead we should add some tests that validate the change.
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.
Agree, but I'm frankly not sure how to do that with animated (transient) text. Anybody have a pointer or ideas?
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.
when the pytest capsys is attached the override does not happen, allowing you to check byte-wise; see https://github.com/tox-dev/tox/blob/master/tests/unit/util/test_spinner.py#L60-L81 for example
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.
Nice. And the test above it is testing with animation.
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.
Another tidbit I just figured out, is that by setting env variables COLUMNS
and ROWS
you can make shutil.get_terminal_size()
return values at your command.
tests/test_animate.py
Outdated
HIDE_CURSOR = "\033[?25l" | ||
SHOW_CURSOR = "\033[?25h" | ||
CLEAR_LINE = "\033[K" |
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.
These should be defined in animate.py
and imported here
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.
Done.
tests/test_animate.py
Outdated
|
||
frame_strings = [ | ||
f"{CLEAR_LINE}\r{x} {expected_message[i]}" | ||
for x in ["⣷", "⣯", "⣟", "⡿", "⢿", "⣻", "⣽", "⣾"] |
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 animation list should be imported from animate.py
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.
Done.
tests/test_animate.py
Outdated
pipx.animate.stderr_is_tty = True | ||
pipx.animate.emoji_support = 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.
Recommend defining a fixture to ensure pipx.animate.stderr_is_tty, pipx.animate.emoji_support values are stored at entry to the fixture, then yield
to let the test run, then reset the values to their orignal value in the fixture. We should not assume what they were at the time they were computed on first pass.
https://docs.pytest.org/en/latest/fixture.html#fixture-finalization-executing-teardown-code
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, for the hint.
Done.
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.
Used @gaborbernat 's tip about monkeypatch instead, but if things get more complicated in the future I am happy to know how to do teardown.
tests/test_animate.py
Outdated
frames_to_test = 4 | ||
# matches animate.py | ||
frame_period = 0.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.
Recommend making these values importable from animate.py and using them directly
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.
Done.
@@ -0,0 +1,93 @@ | |||
#!/usr/bin/env python3 | |||
import time |
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 great! Thanks for adding these tests.
tests/test_animate.py
Outdated
@@ -0,0 +1,93 @@ | |||
#!/usr/bin/env python3 |
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 probably a copy+paste thing, but in general pipx has a bunch of these at the top of files that should be removed. It can be removed here.
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.
Ack, yes. Force of habit!
Done.
tests/test_animate.py
Outdated
captured = capsys.readouterr() | ||
|
||
# print for debug help if fail | ||
print("expected_string:") |
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.
adding '-rvva --showlocals`` achieves the same, not?
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, didn't know about that.
tests/test_animate.py
Outdated
def test_line_lengths_no_emoji(capsys, monkeypatch): | ||
# emoji_support and stderr_is_tty is set only at import animate.py | ||
# since we are already after that, we must override both here | ||
pipx.animate.stderr_is_tty = 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.
use monkeypatch instead of direct set to ensure their correctly reset in case tests fails for the next test
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 for the tip!
pipx/animate.py
Outdated
EMOJI_ANIMATION_FRAMES = ["⣷", "⣯", "⣟", "⡿", "⢿", "⣻", "⣽", "⣾"] | ||
NONEMOJI_ANIMATION_FRAMES = ["", ".", "..", "..."] |
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.
nice
…animate_long_lines
Am I clear to merge this now? I think I've addressed all the comments. |
I believe this is the first PR that I have not approved+merged! Thank you and congrats! 🎉 In the future please squash commits to avoid polluting commits on the master branch. |
Ah ok! Is the idea one commit per PR? |
I think the idea is more one commit per feature/bug fix. |
The idea is as many commits on a PR as you want, but when you click the "merge" button, there are a couple options. One is "merge and squash commits into a single commit" and the other is "merge all commits" (the exact text is not this, but this is the idea). We should always opt for the "squash" option. If you look at the commit history, you generally see a single commit with the pull request number in parentheses, such as
this is what we want, so you can look through commits on master and get a basic idea of all the PRs that went into the codebase. If you don't mind, I will do some work with git and do a force push so the master branch looks like this so there is a single commit for this PR. |
I don't mind at all, thanks for offering to clean it up. Thanks for the tip. |
This fixes a problem with the text animation during install. With a long
--spec
, the animation during install of a pipx package can be corrupted, resulting in a page or more of spurious identical messages being printed. This is because the\r
carriage return does not work if the printed text is so long that it moves the cursor to the next line. Under these circumstances,\r
only moves to the beginning of this terminal line, leaving the previous part of the printed text still printed above it.The patch truncates the animated printed text so it does not run over to the next line of the terminal. It uses
shutil.get_terminal_size()
. The fallback in caseshutil.get_terminal_size()
cannot determine the terminal size is 9999 columns, essentially "infinity", making sure that we revert to the original behavior if we cannot determine the actual terminal size (or we are in some circumstance like a pipe, etc. where it wouldn't matter anyway.)Current behavior:
(Note, in my Terminal this wraps so it looks like many lines.)
With this pull request:
During:
Afterwards: