Skip to content

Improve progress alignment #10940

@brl0

Description

@brl0

First of all, thanks to all contributors, your work is much appreciated!

The right aligned percent progress looks great in the terminal, but sometimes the nice alignment is marred by verbose (-vv+) output.
Here is an example of the current alignment:

tests/implementations/test_hdfs.py::TestUPathHDFS::test_fsspec_compat SKIPPED (Possible installation
 problem, error: Unable to load libhdfs: ./libhdfs.so: cannot open shared object file: No such file 
or directory) [ 49%]
tests/test_core.py::TestUPathMock::test_instance_type <- upath/tests/cases.py PASSED          [ 50%]

I was thinking that it would be nice to keep the percentages aligned even for multiline output. It struck me that this could be done by always padding to the rounded up next multiple of terminal width. I think this would make the output in these situations look much nicer.

Here is an example of how the output could be improved:

tests/implementations/test_hdfs.py::TestUPathHDFS::test_fsspec_compat SKIPPED (Possible
installation problem, error: Unable to load libhdfs: ./libhdfs.so: cannot open shared object
file: No such file or directory)                                                              [ 49%]
tests/test_core.py::TestUPathMock::test_instance_type <- upath/tests/cases.py PASSED          [ 50%]

I wrote a function using python's built-in text wrap module that should be easy to drop in to accomplish this, along with a test.

import textwrap

_DEFAULT_PROGRESS_MARGIN_SIZE = 7

def _pad_wrap_message(
    msg: str,
    width: int,
    margin: int = _DEFAULT_PROGRESS_MARGIN_SIZE,
    line_sep: str="",
):
    """Wrap and pad message with margin for progress info."""
    wrapped = textwrap.wrap(msg, width - margin, drop_whitespace=True)
    out_lines = [line.ljust(width) for line in wrapped[:-1]]
    out_lines.append(wrapped[-1].ljust(width - margin))
    msg_out = line_sep.join(out_lines)
    return msg_out

def test_pad_wrap_message():
    width = 80
    count = 200
    msg = "b"
    progress = " [100%]"
    margin = len(progress)
    result = _pad_wrap_message(msg * count, width=width, line_sep="\n")
    assert result.count(msg) == count
    lines = (result + progress).split("\n")
    expected_lines = (len(msg) * count) // (width - margin) + 1
    assert len(lines) == expected_lines
    expected_len = expected_lines * (width + 1) - margin - 1
    assert len(result) == expected_len
    for _ in lines:
        assert len(_) == width
        assert _[-len(progress)] == " "  # space before progress column

If this approach is acceptable, I can submit a PR.

Metadata

Metadata

Assignees

No one assigned

    Labels

    topic: reportingrelated to terminal output and user-facing messages and errorstype: proposalproposal for a new feature, often to gather opinions or design the API around the new feature

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions