Skip to content

Commit

Permalink
Merge pull request #7988 from McSinyx/tabulate
Browse files Browse the repository at this point in the history
Fix tabulate col size in case of empty cell
  • Loading branch information
xavfernandez authored Apr 9, 2020
2 parents c110953 + 26b76f6 commit ea9cb06
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 20 deletions.
Empty file.
20 changes: 1 addition & 19 deletions src/pip/_internal/commands/list.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import logging

from pip._vendor import six
from pip._vendor.six.moves import zip_longest

from pip._internal.cli import cmdoptions
from pip._internal.cli.req_command import IndexGroupCommand
Expand All @@ -18,6 +17,7 @@
from pip._internal.utils.misc import (
dist_is_editable,
get_installed_distributions,
tabulate,
write_output,
)
from pip._internal.utils.packaging import get_installer
Expand Down Expand Up @@ -241,24 +241,6 @@ def output_package_listing_columns(self, data, header):
write_output(val)


def tabulate(vals):
# From pfmoore on GitHub:
# https://github.com/pypa/pip/issues/3651#issuecomment-216932564
assert len(vals) > 0

sizes = [0] * max(len(x) for x in vals)
for row in vals:
sizes = [max(s, len(str(c))) for s, c in zip_longest(sizes, row)]

result = []
for row in vals:
display = " ".join([str(c).ljust(s) if c is not None else ''
for s, c in zip_longest(sizes, row)])
result.append(display)

return result, sizes


def format_for_columns(pkgs, options):
"""
Convert the package data into something usable
Expand Down
17 changes: 16 additions & 1 deletion src/pip/_internal/utils/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
# why we ignore the type on this import.
from pip._vendor.retrying import retry # type: ignore
from pip._vendor.six import PY2, text_type
from pip._vendor.six.moves import input, zip_longest
from pip._vendor.six.moves import input, map, zip_longest
from pip._vendor.six.moves.urllib import parse as urllib_parse
from pip._vendor.six.moves.urllib.parse import unquote as urllib_unquote

Expand Down Expand Up @@ -275,6 +275,21 @@ def format_size(bytes):
return '{} bytes'.format(int(bytes))


def tabulate(rows):
# type: (Iterable[Iterable[Any]]) -> Tuple[List[str], List[int]]
"""Return a list of formatted rows and a list of column sizes.
For example::
>>> tabulate([['foobar', 2000], [0xdeadbeef]])
(['foobar 2000', '3735928559'], [10, 4])
"""
rows = [tuple(map(str, row)) for row in rows]
sizes = [max(map(len, col)) for col in zip_longest(*rows, fillvalue='')]
table = [" ".join(map(str.ljust, row, sizes)).rstrip() for row in rows]
return table, sizes


def is_installable_dir(path):
# type: (str) -> bool
"""Is path is a directory containing setup.py or pyproject.toml?
Expand Down
18 changes: 18 additions & 0 deletions tests/unit/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
rmtree_errorhandler,
split_auth_from_netloc,
split_auth_netloc_from_url,
tabulate,
)
from pip._internal.utils.setuptools_build import make_setuptools_shim_args

Expand Down Expand Up @@ -970,3 +971,20 @@ def test_is_console_interactive(monkeypatch, isatty, no_stdin, expected):
])
def test_format_size(size, expected):
assert format_size(size) == expected


@pytest.mark.parametrize(
('rows', 'table', 'sizes'),
[([], [], []),
([('I?', 'version', 'sdist', 'wheel'),
('', '1.18.2', 'zip', 'cp38-cp38m-win_amd64'),
('v', 1.18, 'zip')],
['I? version sdist wheel',
' 1.18.2 zip cp38-cp38m-win_amd64',
'v 1.18 zip'],
[2, 7, 5, 20]),
([('I?', 'version', 'sdist', 'wheel'), (), ('v', '1.18.1', 'zip')],
['I? version sdist wheel', '', 'v 1.18.1 zip'],
[2, 7, 5, 5])])
def test_tabulate(rows, table, sizes):
assert tabulate(rows) == (table, sizes)

0 comments on commit ea9cb06

Please sign in to comment.