From 7a4b69edc032d5c09d1f4da50009ee99b699f1f0 Mon Sep 17 00:00:00 2001 From: Aanand Prasad Date: Thu, 9 Jan 2014 15:32:06 +0000 Subject: [PATCH] Remove compat texttable module - breaks on Python 2.7 --- fig/cli/formatter.py | 3 +- fig/compat/__init__.py | 23 -- fig/compat/texttable.py | 582 ---------------------------------------- requirements.txt | 1 + 4 files changed, 2 insertions(+), 607 deletions(-) delete mode 100644 fig/compat/__init__.py delete mode 100644 fig/compat/texttable.py diff --git a/fig/cli/formatter.py b/fig/cli/formatter.py index 47bf680c..3d7e2d51 100644 --- a/fig/cli/formatter.py +++ b/fig/cli/formatter.py @@ -1,8 +1,7 @@ from __future__ import unicode_literals from __future__ import absolute_import import os - -from fig.compat import texttable +import texttable class Formatter(object): diff --git a/fig/compat/__init__.py b/fig/compat/__init__.py deleted file mode 100644 index 5b01f6b3..00000000 --- a/fig/compat/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ - - -# Taken from python2.7/3.3 functools -def cmp_to_key(mycmp): - """Convert a cmp= function into a key= function""" - class K(object): - __slots__ = ['obj'] - def __init__(self, obj): - self.obj = obj - def __lt__(self, other): - return mycmp(self.obj, other.obj) < 0 - def __gt__(self, other): - return mycmp(self.obj, other.obj) > 0 - def __eq__(self, other): - return mycmp(self.obj, other.obj) == 0 - def __le__(self, other): - return mycmp(self.obj, other.obj) <= 0 - def __ge__(self, other): - return mycmp(self.obj, other.obj) >= 0 - def __ne__(self, other): - return mycmp(self.obj, other.obj) != 0 - __hash__ = None - return K diff --git a/fig/compat/texttable.py b/fig/compat/texttable.py deleted file mode 100644 index a9c91a50..00000000 --- a/fig/compat/texttable.py +++ /dev/null @@ -1,582 +0,0 @@ -#!/usr/bin/env python -# -# texttable - module for creating simple ASCII tables -# Copyright (C) 2003-2011 Gerome Fournier -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -"""module for creating simple ASCII tables - - -Example: - - table = Texttable() - table.set_cols_align(["l", "r", "c"]) - table.set_cols_valign(["t", "m", "b"]) - table.add_rows([ ["Name", "Age", "Nickname"], - ["Mr\\nXavier\\nHuon", 32, "Xav'"], - ["Mr\\nBaptiste\\nClement", 1, "Baby"] ]) - print(table.draw() + "\\n") - - table = Texttable() - table.set_deco(Texttable.HEADER) - table.set_cols_dtype(['t', # text - 'f', # float (decimal) - 'e', # float (exponent) - 'i', # integer - 'a']) # automatic - table.set_cols_align(["l", "r", "r", "r", "l"]) - table.add_rows([["text", "float", "exp", "int", "auto"], - ["abcd", "67", 654, 89, 128.001], - ["efghijk", 67.5434, .654, 89.6, 12800000000000000000000.00023], - ["lmn", 5e-78, 5e-78, 89.4, .000000000000128], - ["opqrstu", .023, 5e+78, 92., 12800000000000000000000]]) - print(table.draw()) - -Result: - - +----------+-----+----------+ - | Name | Age | Nickname | - +==========+=====+==========+ - | Mr | | | - | Xavier | 32 | | - | Huon | | Xav' | - +----------+-----+----------+ - | Mr | | | - | Baptiste | 1 | | - | Clement | | Baby | - +----------+-----+----------+ - - text float exp int auto - =========================================== - abcd 67.000 6.540e+02 89 128.001 - efgh 67.543 6.540e-01 90 1.280e+22 - ijkl 0.000 5.000e-78 89 0.000 - mnop 0.023 5.000e+78 92 1.280e+22 -""" -from __future__ import division -from __future__ import print_function -from functools import reduce - -__all__ = ["Texttable", "ArraySizeError"] - -__author__ = 'Gerome Fournier ' -__license__ = 'LGPL' -__version__ = '0.8.1' -__credits__ = """\ -Jeff Kowalczyk: - - textwrap improved import - - comment concerning header output - -Anonymous: - - add_rows method, for adding rows in one go - -Sergey Simonenko: - - redefined len() function to deal with non-ASCII characters - -Roger Lew: - - columns datatype specifications - -Brian Peterson: - - better handling of unicode errors -""" - -# Modified version of `texttable` for python3 support. - -import sys -import string - - -def len(iterable): - """Redefining len here so it will be able to work with non-ASCII characters - """ - if not isinstance(iterable, str): - return iterable.__len__() - - try: - return len(unicode(iterable, 'utf')) - except: - return iterable.__len__() - - -class ArraySizeError(Exception): - """Exception raised when specified rows don't fit the required size - """ - - def __init__(self, msg): - self.msg = msg - Exception.__init__(self, msg, '') - - def __str__(self): - return self.msg - -class Texttable: - - BORDER = 1 - HEADER = 1 << 1 - HLINES = 1 << 2 - VLINES = 1 << 3 - - def __init__(self, max_width=80): - """Constructor - - - max_width is an integer, specifying the maximum width of the table - - if set to 0, size is unlimited, therefore cells won't be wrapped - """ - - if max_width <= 0: - max_width = False - self._max_width = max_width - self._precision = 3 - - self._deco = Texttable.VLINES | Texttable.HLINES | Texttable.BORDER | \ - Texttable.HEADER - self.set_chars(['-', '|', '+', '=']) - self.reset() - - def reset(self): - """Reset the instance - - - reset rows and header - """ - - self._hline_string = None - self._row_size = None - self._header = [] - self._rows = [] - - def set_chars(self, array): - """Set the characters used to draw lines between rows and columns - - - the array should contain 4 fields: - - [horizontal, vertical, corner, header] - - - default is set to: - - ['-', '|', '+', '='] - """ - - if len(array) != 4: - raise ArraySizeError("array should contain 4 characters") - array = [ x[:1] for x in [ str(s) for s in array ] ] - (self._char_horiz, self._char_vert, - self._char_corner, self._char_header) = array - - def set_deco(self, deco): - """Set the table decoration - - - 'deco' can be a combinaison of: - - Texttable.BORDER: Border around the table - Texttable.HEADER: Horizontal line below the header - Texttable.HLINES: Horizontal lines between rows - Texttable.VLINES: Vertical lines between columns - - All of them are enabled by default - - - example: - - Texttable.BORDER | Texttable.HEADER - """ - - self._deco = deco - - def set_cols_align(self, array): - """Set the desired columns alignment - - - the elements of the array should be either "l", "c" or "r": - - * "l": column flushed left - * "c": column centered - * "r": column flushed right - """ - - self._check_row_size(array) - self._align = array - - def set_cols_valign(self, array): - """Set the desired columns vertical alignment - - - the elements of the array should be either "t", "m" or "b": - - * "t": column aligned on the top of the cell - * "m": column aligned on the middle of the cell - * "b": column aligned on the bottom of the cell - """ - - self._check_row_size(array) - self._valign = array - - def set_cols_dtype(self, array): - """Set the desired columns datatype for the cols. - - - the elements of the array should be either "a", "t", "f", "e" or "i": - - * "a": automatic (try to use the most appropriate datatype) - * "t": treat as text - * "f": treat as float in decimal format - * "e": treat as float in exponential format - * "i": treat as int - - - by default, automatic datatyping is used for each column - """ - - self._check_row_size(array) - self._dtype = array - - def set_cols_width(self, array): - """Set the desired columns width - - - the elements of the array should be integers, specifying the - width of each column. For example: - - [10, 20, 5] - """ - - self._check_row_size(array) - try: - array = map(int, array) - if reduce(min, array) <= 0: - raise ValueError - except ValueError: - sys.stderr.write("Wrong argument in column width specification\n") - raise - self._width = array - - def set_precision(self, width): - """Set the desired precision for float/exponential formats - - - width must be an integer >= 0 - - - default value is set to 3 - """ - - if not type(width) is int or width < 0: - raise ValueError('width must be an integer greater then 0') - self._precision = width - - def header(self, array): - """Specify the header of the table - """ - - self._check_row_size(array) - self._header = map(str, array) - - def add_row(self, array): - """Add a row in the rows stack - - - cells can contain newlines and tabs - """ - - self._check_row_size(array) - - if not hasattr(self, "_dtype"): - self._dtype = ["a"] * self._row_size - - cells = [] - for i,x in enumerate(array): - cells.append(self._str(i,x)) - self._rows.append(cells) - - def add_rows(self, rows, header=True): - """Add several rows in the rows stack - - - The 'rows' argument can be either an iterator returning arrays, - or a by-dimensional array - - 'header' specifies if the first row should be used as the header - of the table - """ - - # nb: don't use 'iter' on by-dimensional arrays, to get a - # usable code for python 2.1 - if header: - if hasattr(rows, '__iter__') and hasattr(rows, 'next'): - self.header(rows.next()) - else: - self.header(rows[0]) - rows = rows[1:] - for row in rows: - self.add_row(row) - - def draw(self): - """Draw the table - - - the table is returned as a whole string - """ - - if not self._header and not self._rows: - return - self._compute_cols_width() - self._check_align() - out = "" - if self._has_border(): - out += self._hline() - if self._header: - out += self._draw_line(self._header, isheader=True) - if self._has_header(): - out += self._hline_header() - length = 0 - for row in self._rows: - length += 1 - out += self._draw_line(row) - if self._has_hlines() and length < len(self._rows): - out += self._hline() - if self._has_border(): - out += self._hline() - return out[:-1] - - def _str(self, i, x): - """Handles string formatting of cell data - - i - index of the cell datatype in self._dtype - x - cell data to format - """ - try: - f = float(x) - except: - return str(x) - - n = self._precision - dtype = self._dtype[i] - - if dtype == 'i': - return str(int(round(f))) - elif dtype == 'f': - return '%.*f' % (n, f) - elif dtype == 'e': - return '%.*e' % (n, f) - elif dtype == 't': - return str(x) - else: - if f - round(f) == 0: - if abs(f) > 1e8: - return '%.*e' % (n, f) - else: - return str(int(round(f))) - else: - if abs(f) > 1e8: - return '%.*e' % (n, f) - else: - return '%.*f' % (n, f) - - def _check_row_size(self, array): - """Check that the specified array fits the previous rows size - """ - - if not self._row_size: - self._row_size = len(array) - elif self._row_size != len(array): - raise ArraySizeError("array should contain %d elements" % self._row_size) - - def _has_vlines(self): - """Return a boolean, if vlines are required or not - """ - - return self._deco & Texttable.VLINES > 0 - - def _has_hlines(self): - """Return a boolean, if hlines are required or not - """ - - return self._deco & Texttable.HLINES > 0 - - def _has_border(self): - """Return a boolean, if border is required or not - """ - - return self._deco & Texttable.BORDER > 0 - - def _has_header(self): - """Return a boolean, if header line is required or not - """ - - return self._deco & Texttable.HEADER > 0 - - def _hline_header(self): - """Print header's horizontal line - """ - - return self._build_hline(True) - - def _hline(self): - """Print an horizontal line - """ - - if not self._hline_string: - self._hline_string = self._build_hline() - return self._hline_string - - def _build_hline(self, is_header=False): - """Return a string used to separated rows or separate header from - rows - """ - horiz = self._char_horiz - if (is_header): - horiz = self._char_header - # compute cell separator - s = "%s%s%s" % (horiz, [horiz, self._char_corner][self._has_vlines()], - horiz) - # build the line - l = string.join([horiz * n for n in self._width], s) - # add border if needed - if self._has_border(): - l = "%s%s%s%s%s\n" % (self._char_corner, horiz, l, horiz, - self._char_corner) - else: - l += "\n" - return l - - def _len_cell(self, cell): - """Return the width of the cell - - Special characters are taken into account to return the width of the - cell, such like newlines and tabs - """ - - cell_lines = cell.split('\n') - maxi = 0 - for line in cell_lines: - length = 0 - parts = line.split('\t') - for part, i in zip(parts, range(1, len(parts) + 1)): - length = length + len(part) - if i < len(parts): - length = (length/8 + 1) * 8 - maxi = max(maxi, length) - return maxi - - def _compute_cols_width(self): - """Return an array with the width of each column - - If a specific width has been specified, exit. If the total of the - columns width exceed the table desired width, another width will be - computed to fit, and cells will be wrapped. - """ - - if hasattr(self, "_width"): - return - maxi = [] - if self._header: - maxi = [ self._len_cell(x) for x in self._header ] - for row in self._rows: - for cell,i in zip(row, range(len(row))): - try: - maxi[i] = max(maxi[i], self._len_cell(cell)) - except (TypeError, IndexError): - maxi.append(self._len_cell(cell)) - items = len(maxi) - length = reduce(lambda x,y: x+y, maxi) - if self._max_width and length + items * 3 + 1 > self._max_width: - maxi = [(self._max_width - items * 3 -1) / items \ - for n in range(items)] - self._width = maxi - - def _check_align(self): - """Check if alignment has been specified, set default one if not - """ - - if not hasattr(self, "_align"): - self._align = ["l"] * self._row_size - if not hasattr(self, "_valign"): - self._valign = ["t"] * self._row_size - - def _draw_line(self, line, isheader=False): - """Draw a line - - Loop over a single cell length, over all the cells - """ - - line = self._splitit(line, isheader) - space = " " - out = "" - for i in range(len(line[0])): - if self._has_border(): - out += "%s " % self._char_vert - length = 0 - for cell, width, align in zip(line, self._width, self._align): - length += 1 - cell_line = cell[i] - fill = width - len(cell_line) - if isheader: - align = "c" - if align == "r": - out += "%s " % (fill * space + cell_line) - elif align == "c": - out += "%s " % (fill/2 * space + cell_line \ - + (fill/2 + fill%2) * space) - else: - out += "%s " % (cell_line + fill * space) - if length < len(line): - out += "%s " % [space, self._char_vert][self._has_vlines()] - out += "%s\n" % ['', self._char_vert][self._has_border()] - return out - - def _splitit(self, line, isheader): - """Split each element of line to fit the column width - - Each element is turned into a list, result of the wrapping of the - string to the desired width - """ - - line_wrapped = [] - for cell, width in zip(line, self._width): - array = [] - for c in cell.split('\n'): - try: - c = unicode(c, 'utf') - except UnicodeDecodeError as strerror: - sys.stderr.write("UnicodeDecodeError exception for string '%s': %s\n" % (c, strerror)) - c = unicode(c, 'utf', 'replace') - array.extend(textwrap.wrap(c, width)) - line_wrapped.append(array) - max_cell_lines = reduce(max, map(len, line_wrapped)) - for cell, valign in zip(line_wrapped, self._valign): - if isheader: - valign = "t" - if valign == "m": - missing = max_cell_lines - len(cell) - cell[:0] = [""] * (missing / 2) - cell.extend([""] * (missing / 2 + missing % 2)) - elif valign == "b": - cell[:0] = [""] * (max_cell_lines - len(cell)) - else: - cell.extend([""] * (max_cell_lines - len(cell))) - return line_wrapped - -if __name__ == '__main__': - table = Texttable() - table.set_cols_align(["l", "r", "c"]) - table.set_cols_valign(["t", "m", "b"]) - table.add_rows([ ["Name", "Age", "Nickname"], - ["Mr\nXavier\nHuon", 32, "Xav'"], - ["Mr\nBaptiste\nClement", 1, "Baby"] ]) - print(table.draw() + "\n") - - table = Texttable() - table.set_deco(Texttable.HEADER) - table.set_cols_dtype(['t', # text - 'f', # float (decimal) - 'e', # float (exponent) - 'i', # integer - 'a']) # automatic - table.set_cols_align(["l", "r", "r", "r", "l"]) - table.add_rows([["text", "float", "exp", "int", "auto"], - ["abcd", "67", 654, 89, 128.001], - ["efghijk", 67.5434, .654, 89.6, 12800000000000000000000.00023], - ["lmn", 5e-78, 5e-78, 89.4, .000000000000128], - ["opqrstu", .023, 5e+78, 92., 12800000000000000000000]]) - print(table.draw()) - diff --git a/requirements.txt b/requirements.txt index bfc91093..7eedd09c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,6 @@ docker-py==0.2.3 docopt==0.6.1 PyYAML==3.10 +texttable==0.8.1 # docker requires six==1.3.0 six==1.3.0