From 7be2fdcf9258de4a4eb1fa66fce064f7066226f8 Mon Sep 17 00:00:00 2001 From: Casper da Costa-Luis Date: Tue, 27 Oct 2015 16:09:24 +0000 Subject: [PATCH] More OS support for dynamic environment column width --- tqdm/_tqdm.py | 19 ++++++++------ tqdm/_utils.py | 68 ++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 78 insertions(+), 9 deletions(-) diff --git a/tqdm/_tqdm.py b/tqdm/_tqdm.py index 5734a772..1bb822df 100644 --- a/tqdm/_tqdm.py +++ b/tqdm/_tqdm.py @@ -11,7 +11,7 @@ Usage: # a result precise floating numbers (instead of truncated int) from __future__ import division, absolute_import # import compatibility functions and utilities -from ._utils import _supports_unicode, _environ_cols, _range, _unich +from ._utils import _supports_unicode, _environ_cols_wrapper, _range, _unich import sys from time import time @@ -263,7 +263,11 @@ class tqdm(object): if ((ncols is None) and (file in (sys.stderr, sys.stdout))) or \ dynamic_ncols: - ncols = _environ_cols(file) + if dynamic_ncols: + dynamic_ncols = _environ_cols_wrapper() + ncols = dynamic_ncols(file) + else: + ncols = _environ_cols_wrapper()(file) if miniters is None: miniters = 0 @@ -359,8 +363,9 @@ class tqdm(object): # Initialize the screen printer self.sp = StatusPrinter(self.file) if not disable: - self.sp(format_meter( - 0, total, 0, ncols, self.desc, ascii, unit, unit_scale)) + self.sp(format_meter(0, total, 0, + (dynamic_ncols(file) if dynamic_ncols else ncols), + self.desc, ascii, unit, unit_scale)) # Init the time/iterations counters self.start_t = self.last_print_t = time() @@ -474,7 +479,7 @@ class tqdm(object): else: sp(format_meter( n, self.total, elapsed, - (_environ_cols(self.file) if dynamic_ncols + (dynamic_ncols(self.file) if dynamic_ncols else ncols), self.desc, ascii, unit, unit_scale)) @@ -584,7 +589,7 @@ class tqdm(object): else: self.sp(format_meter( self.n, self.total, elapsed, - (_environ_cols(self.file) if self.dynamic_ncols + (self.dynamic_ncols(self.file) if self.dynamic_ncols else self.ncols), self.desc, self.ascii, self.unit, self.unit_scale)) @@ -621,7 +626,7 @@ class tqdm(object): cur_t = time() self.sp(format_meter( self.n, self.total, cur_t-self.start_t, - (_environ_cols(self.file) if self.dynamic_ncols + (self.dynamic_ncols(self.file) if self.dynamic_ncols else self.ncols), self.desc, self.ascii, self.unit, self.unit_scale)) self.file.write('\n') diff --git a/tqdm/_utils.py b/tqdm/_utils.py index 2b3664ca..cad222e1 100644 --- a/tqdm/_utils.py +++ b/tqdm/_utils.py @@ -20,7 +20,71 @@ def _supports_unicode(file): return _is_utf(file.encoding) -def _environ_cols(file): # pragma: no cover +def _environ_cols_wrapper(): # pragma: no cover + """ + Return a function which gets width and height of console + (linux,osx,windows,cygwin). + """ + import platform + current_os = platform.system() + _environ_cols = None + if current_os == 'Windows': + _environ_cols = _environ_cols_windows + if _environ_cols is None: + _environ_cols = _environ_cols_tput + if current_os in ['Linux', 'Darwin'] or current_os.startswith('CYGWIN'): + _environ_cols = _environ_cols_linux + return _environ_cols + + +def _environ_cols_windows(fp): # pragma: no cover + try: + from ctypes import windll, create_string_buffer + import struct + from sys import stdin, stdout + + io_handle = None + if fp == stdin: + io_handle = -10 + elif fp == stdout: + io_handle = -11 + else: # assume stderr + io_handle = -12 + + h = windll.kernel32.GetStdHandle(io_handle) + csbi = create_string_buffer(22) + res = windll.kernel32.GetConsoleScreenBufferInfo(h, csbi) + if res: + (bufx, bufy, curx, cury, wattr, left, top, right, bottom, + maxx, maxy) = struct.unpack("hhhhHhhhhhh", csbi.raw) + # nlines = bottom - top + 1 + return right - left + 1 + except: + pass + return None + + +def _environ_cols_tput(*args): # pragma: no cover + """ cygwin xterm (windows) """ + try: + import subprocess + import shlex + cols = int(subprocess.check_call(shlex.split('tput cols'))) + # rows = int(subprocess.check_call(shlex.split('tput lines'))) + return cols + except: + pass + return None + + +def _environ_cols_linux(fp): # pragma: no cover + + # import os + # if fp is None: + # try: + # fp = os.open(os.ctermid(), os.O_RDONLY) + # except: + # pass try: from termios import TIOCGWINSZ from fcntl import ioctl @@ -29,7 +93,7 @@ def _environ_cols(file): # pragma: no cover return None else: try: - return array('h', ioctl(file, TIOCGWINSZ, '\0' * 8))[1] + return array('h', ioctl(fp, TIOCGWINSZ, '\0' * 8))[1] except: try: from os.environ import get