diff --git a/doc/source/whatsnew/v0.24.2.rst b/doc/source/whatsnew/v0.24.2.rst index c95ed818c9da0..d6fe59a5c4114 100644 --- a/doc/source/whatsnew/v0.24.2.rst +++ b/doc/source/whatsnew/v0.24.2.rst @@ -51,6 +51,7 @@ Bug Fixes **I/O** +- Better handling of terminal printing when the terminal dimensions are not known (:issue:`25080`); - Bug in reading a HDF5 table-format ``DataFrame`` created in Python 2, in Python 3 (:issue:`24925`) - Bug where float indexes could have misaligned values when printing (:issue:`25061`) - diff --git a/pandas/io/formats/terminal.py b/pandas/io/formats/terminal.py index bb34259d710c7..cf2383955d593 100644 --- a/pandas/io/formats/terminal.py +++ b/pandas/io/formats/terminal.py @@ -15,6 +15,7 @@ import os import shutil +import subprocess from pandas.compat import PY3 @@ -94,22 +95,29 @@ def _get_terminal_size_tput(): # get terminal width # src: http://stackoverflow.com/questions/263890/how-do-i-find-the-width # -height-of-a-terminal-window + try: - import subprocess proc = subprocess.Popen(["tput", "cols"], stdin=subprocess.PIPE, stdout=subprocess.PIPE) - output = proc.communicate(input=None) - cols = int(output[0]) + output_cols = proc.communicate(input=None) proc = subprocess.Popen(["tput", "lines"], stdin=subprocess.PIPE, stdout=subprocess.PIPE) - output = proc.communicate(input=None) - rows = int(output[0]) - return (cols, rows) + output_rows = proc.communicate(input=None) except OSError: return None + try: + # Some terminals (e.g. spyder) may report a terminal size of '', + # making the `int` fail. + + cols = int(output_cols[0]) + rows = int(output_rows[0]) + return cols, rows + except (ValueError, IndexError): + return None + def _get_terminal_size_linux(): def ioctl_GWINSZ(fd): diff --git a/pandas/tests/io/formats/test_console.py b/pandas/tests/io/formats/test_console.py index 055763bf62d6e..45c5e982c1c48 100644 --- a/pandas/tests/io/formats/test_console.py +++ b/pandas/tests/io/formats/test_console.py @@ -1,6 +1,9 @@ +import subprocess # noqa: F401 + import pytest from pandas.io.formats.console import detect_console_encoding +from pandas.io.formats.terminal import _get_terminal_size_tput class MockEncoding(object): # TODO(py27): replace with mock @@ -72,3 +75,19 @@ def test_detect_console_encoding_fallback_to_default(monkeypatch, std, locale): context.setattr('sys.stdout', MockEncoding(std)) context.setattr('sys.getdefaultencoding', lambda: 'sysDefaultEncoding') assert detect_console_encoding() == 'sysDefaultEncoding' + + +@pytest.mark.parametrize("size", ['', ['']]) +def test_terminal_unknown_dimensions(monkeypatch, size): + mock = pytest.importorskip("unittest.mock") + + def communicate(*args, **kwargs): + return size + + monkeypatch.setattr('subprocess.Popen', mock.Mock()) + monkeypatch.setattr('subprocess.Popen.return_value.returncode', None) + monkeypatch.setattr( + 'subprocess.Popen.return_value.communicate', communicate) + result = _get_terminal_size_tput() + + assert result is None