From e50d811161dab89478f9a7127f857054ed6e0da7 2017-05-24 21:01:11 From: Matthias Bussonnier Date: 2017-05-24 21:01:11 Subject: [PATCH] Vendor shutil.get_terminal_size. Use the vendored version only if import error. That should fix import error for many users. Closes #9815. This is only against the 5.x branch as this is in the stdlib on Python 3 --- diff --git a/IPython/utils/_get_terminal_size.py b/IPython/utils/_get_terminal_size.py new file mode 100644 index 0000000..b402b7b --- /dev/null +++ b/IPython/utils/_get_terminal_size.py @@ -0,0 +1,103 @@ +# vendored version of backports.get_terminal_size as nemesapece package are a +# mess and break, especially on ubuntu. This file is under MIT Licence. +# See https://pypi.python.org/pypi/backports.shutil_get_terminal_size +"""This is a backport of shutil.get_terminal_size from Python 3.3. + +The original implementation is in C, but here we use the ctypes and +fcntl modules to create a pure Python version of os.get_terminal_size. +""" + +import os +import struct +import sys + +from collections import namedtuple + +__all__ = ["get_terminal_size"] + + +terminal_size = namedtuple("terminal_size", "columns lines") + +try: + from ctypes import windll, create_string_buffer + + _handles = { + 0: windll.kernel32.GetStdHandle(-10), + 1: windll.kernel32.GetStdHandle(-11), + 2: windll.kernel32.GetStdHandle(-12), + } + + def _get_terminal_size(fd): + columns = lines = 0 + + try: + handle = _handles[fd] + csbi = create_string_buffer(22) + res = windll.kernel32.GetConsoleScreenBufferInfo(handle, csbi) + if res: + res = struct.unpack("hhhhHhhhhhh", csbi.raw) + left, top, right, bottom = res[5:9] + columns = right - left + 1 + lines = bottom - top + 1 + except Exception: + pass + + return terminal_size(columns, lines) + +except ImportError: + import fcntl + import termios + + def _get_terminal_size(fd): + try: + res = fcntl.ioctl(fd, termios.TIOCGWINSZ, b"\x00" * 4) + lines, columns = struct.unpack("hh", res) + except Exception: + columns = lines = 0 + + return terminal_size(columns, lines) + + +def get_terminal_size(fallback=(80, 24)): + """Get the size of the terminal window. + + For each of the two dimensions, the environment variable, COLUMNS + and LINES respectively, is checked. If the variable is defined and + the value is a positive integer, it is used. + + When COLUMNS or LINES is not defined, which is the common case, + the terminal connected to sys.__stdout__ is queried + by invoking os.get_terminal_size. + + If the terminal size cannot be successfully queried, either because + the system doesn't support querying, or because we are not + connected to a terminal, the value given in fallback parameter + is used. Fallback defaults to (80, 24) which is the default + size used by many terminal emulators. + + The value returned is a named tuple of type os.terminal_size. + """ + # Try the environment first + try: + columns = int(os.environ["COLUMNS"]) + except (KeyError, ValueError): + columns = 0 + + try: + lines = int(os.environ["LINES"]) + except (KeyError, ValueError): + lines = 0 + + # Only query if necessary + if columns <= 0 or lines <= 0: + try: + size = _get_terminal_size(sys.__stdout__.fileno()) + except (NameError, OSError): + size = terminal_size(*fallback) + + if columns <= 0: + columns = size.columns + if lines <= 0: + lines = size.lines + + return terminal_size(columns, lines) diff --git a/IPython/utils/terminal.py b/IPython/utils/terminal.py index 3bdcee3..0f3a45d 100644 --- a/IPython/utils/terminal.py +++ b/IPython/utils/terminal.py @@ -9,6 +9,8 @@ Authors: * Alexander Belchenko (e-mail: bialix AT ukr.net) """ +from __future__ import absolute_import + # Copyright (c) IPython Development Team. # Distributed under the terms of the Modified BSD License. @@ -19,7 +21,10 @@ try: from shutil import get_terminal_size as _get_terminal_size except ImportError: # use backport on Python 2 - from backports.shutil_get_terminal_size import get_terminal_size as _get_terminal_size + try: + from backports.shutil_get_terminal_size import get_terminal_size as _get_terminal_size + except ImportError: + from ._get_terminal_size import _get_terminal_size from . import py3compat