Hello community,

here is the log from the commit of package python-texttable for 
openSUSE:Factory checked in at 2017-12-08 13:02:38
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-texttable (Old)
 and      /work/SRC/openSUSE:Factory/.python-texttable.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-texttable"

Fri Dec  8 13:02:38 2017 rev:2 rq:555176 version:1.1.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-texttable/python-texttable.changes        
2015-08-26 10:01:06.000000000 +0200
+++ /work/SRC/openSUSE:Factory/.python-texttable.new/python-texttable.changes   
2017-12-08 13:03:31.980369415 +0100
@@ -1,0 +2,5 @@
+Thu Dec  7 13:10:46 UTC 2017 - [email protected]
+
+- update to 1.1.1, no upstream changelog available
+
+-------------------------------------------------------------------

Old:
----
  texttable-0.8.3.tar.gz

New:
----
  texttable-1.1.1.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-texttable.spec ++++++
--- /var/tmp/diff_new_pack.HnkuZZ/_old  2017-12-08 13:03:33.356319722 +0100
+++ /var/tmp/diff_new_pack.HnkuZZ/_new  2017-12-08 13:03:33.360319577 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-texttable
 #
-# Copyright (c) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany.
+# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany.
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -16,40 +16,49 @@
 #
 
 
-%define upstream_name texttable
+%{?!python_module:%define python_module() python-%{**} python3-%{**}}
+%bcond_with test
 Name:           python-texttable
-Version:        0.8.3
+Version:        1.1.1
 Release:        0
 Summary:        Module for creating simple ASCII tables
-License:        LGPL-3.0+
+License:        LGPL-3.0
 Group:          Development/Languages/Python
-Url:            http://foutaise.org/code
-Source0:        %{upstream_name}-%{version}.tar.gz
-BuildRequires:  python-setuptools
-BuildRoot:      %{_tmppath}/%{name}-%{version}-build
-
-%if 0%{?suse_version} && 0%{?suse_version} <= 1110
-%{!?python_sitelib: %global python_sitelib %(python -c "from 
distutils.sysconfig import get_python_lib; print get_python_lib()")}
-%else
-BuildArch:      noarch
+Url:            https://github.com/foutaise/texttable/
+Source:         
https://files.pythonhosted.org/packages/source/t/texttable/texttable-%{version}.tar.gz
+BuildRequires:  %{python_module devel}
+BuildRequires:  %{python_module setuptools}
+%if %{with test}
+BuildRequires:  python3-testsuite
 %endif
+BuildRequires:  fdupes
+BuildRequires:  python-rpm-macros
+BuildArch:      noarch
+
+%python_subpackages
 
 %description
-Texttable is a module to generate a formatted text table, using ASCII
+texttable is a module to generate a formatted text table, using ASCII
 characters.
 
 %prep
-%setup -q -n %{upstream_name}-%{version}
+%setup -q -n texttable-%{version}
 
 %build
-python setup.py build
+%python_build
 
 %install
-python setup.py install --prefix=%{_prefix} --root=%{buildroot}
+%python_install
+%python_expand %fdupes %{buildroot}%{$python_sitelib}
+
+%if %{with test}
+%check
+%python_exec setup.py test
+%endif
 
-%files
-%defattr(-,root,root,-)
-%{python_sitelib}/%{upstream_name}.py*
-%{python_sitelib}/%{upstream_name}-%{version}*egg-info
+%files %{python_files}
+%license LICENSE
+%doc README.md
+%{python_sitelib}/*
 
 %changelog

++++++ texttable-0.8.3.tar.gz -> texttable-1.1.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/texttable-0.8.3/.gitignore 
new/texttable-1.1.1/.gitignore
--- old/texttable-0.8.3/.gitignore      1970-01-01 01:00:00.000000000 +0100
+++ new/texttable-1.1.1/.gitignore      2017-10-26 14:23:51.000000000 +0200
@@ -0,0 +1,7 @@
+/.cache/
+/.coverage
+/.tox/
+/MANIFEST
+/__pycache__/
+*.egg-info/
+*.pyc
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/texttable-0.8.3/PKG-INFO new/texttable-1.1.1/PKG-INFO
--- old/texttable-0.8.3/PKG-INFO        2015-03-11 20:28:47.000000000 +0100
+++ new/texttable-1.1.1/PKG-INFO        2017-10-26 14:23:51.000000000 +0200
@@ -1,12 +1,12 @@
 Metadata-Version: 1.0
 Name: texttable
-Version: 0.8.3
+Version: 1.1.1
 Summary: module for creating simple ASCII tables
-Home-page: http://foutaise.org/code/
+Home-page: https://github.com/foutaise/texttable/
 Author: Gerome Fournier
-Author-email: jef(at)foutaise.org
+Author-email: [email protected]
 License: LGPL
-Download-URL: http://foutaise.org/code/texttable/texttable-0.8.3.tar.gz
+Download-URL: https://github.com/foutaise/texttable/archive/v1.1.1.tar.gz
 Description: texttable is a module to generate a formatted text table, using 
ASCII
         characters.
 Platform: any
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/texttable-0.8.3/README.md 
new/texttable-1.1.1/README.md
--- old/texttable-0.8.3/README.md       1970-01-01 01:00:00.000000000 +0100
+++ new/texttable-1.1.1/README.md       2017-10-26 14:23:51.000000000 +0200
@@ -0,0 +1,233 @@
+# texttable
+
+Python module for creating simple ASCII tables
+
+## Availability
+
+This module is available on 
[PypI](https://pypi.python.org/pypi/texttable/1.1.1), and has been packaged for 
several Linux/Unix platforms
+([Debian](https://packages.debian.org/search?&searchon=names&keywords=python-texttable+),
+[FreeBSD](https://www.freebsd.org/cgi/ports.cgi?query=texttable&stype=all), 
Fedora, Suse...).
+
+## Documentation
+
+```
+NAME
+    texttable - module for creating simple ASCII tables
+
+FILE
+    /usr/local/lib/python2.7/dist-packages/texttable.py
+
+DESCRIPTION
+
+    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"],
+                        ["Mme\nLouise\nBourgeau", 28, "Lou\n\nLoue"]])
+        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   |
+        +----------+-----+----------+
+        | Mme      |     |   Lou    |
+        | Louise   |  28 |          |
+        | Bourgeau |     |   Loue   |
+        +----------+-----+----------+
+
+         text     float       exp      int     auto
+        ==============================================
+        abcd      67.000   6.540e+02    89   128.001
+        efghijk   67.543   6.540e-01    90   1.280e+22
+        lmn        0.000   5.000e-78    89   0.000
+        opqrstu    0.023   5.000e+78    92   1.280e+22
+
+CLASSES
+    class Texttable
+     |  Methods defined here:
+     |
+     |  __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
+     |
+     |  add_row(self, array)
+     |      Add a row in the rows stack
+     |
+     |      - cells can contain newlines and tabs
+     |
+     |  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
+     |
+     |  draw(self)
+     |      Draw the table
+     |
+     |      - the table is returned as a whole string
+     |
+     |  header(self, array)
+     |      Specify the header of the table
+     |
+     |  reset(self)
+     |      Reset the instance
+     |
+     |      - reset rows and header
+     |
+     |  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:
+     |
+     |          ['-', '|', '+', '=']
+     |
+     |  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
+     |
+     |  set_cols_dtype(self, array)
+     |      Set the desired columns datatype for the cols.
+     |
+     |      - the elements of the array should be either a callable or any of
+     |        "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
+     |          * a callable: should return formatted string for any value 
given
+     |
+     |      - by default, automatic datatyping is used for each column
+     |
+     |  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
+     |
+     |  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]
+     |
+     |  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
+     |
+     |  set_precision(self, width)
+     |      Set the desired precision for float/exponential formats
+     |
+     |      - width must be an integer >= 0
+     |
+     |      - default value is set to 3
+     |
+     |  ----------------------------------------------------------------------
+     |  Data and other attributes defined here:
+     |
+     |  BORDER = 1
+     |
+     |  HEADER = 2
+     |
+     |  HLINES = 4
+     |
+     |  VLINES = 8
+
+DATA
+    __all__ = ['Texttable', 'ArraySizeError']
+    __author__ = 'Gerome Fournier <jef(at)foutaise.org>'
+    __credits__ = 'Jeff Kowalczyk:\n    - textwrap improved import\n ...at...
+    __license__ = 'LGPL'
+    __version__ = '1.1.1'
+
+VERSION
+    1.1.1
+
+AUTHOR
+    Gerome Fournier <jef(at)foutaise.org>
+
+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
+
+    Frank Sachsenheim:
+        - add Python 2/3-compatibility
+
+    Maximilian Hils:
+        - fix minor bug for Python 3 compatibility
+
+    frinkelpi:
+        - preserve empty lines
+```
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/texttable-0.8.3/setup.py new/texttable-1.1.1/setup.py
--- old/texttable-0.8.3/setup.py        2015-03-11 20:29:06.000000000 +0100
+++ new/texttable-1.1.1/setup.py        2017-10-26 14:23:51.000000000 +0200
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 #
 # texttable - module for creating simple ASCII tables
-# Copyright (C) 2003-2011 Gerome Fournier <jef(at)foutaise.org>
+# Copyright (C) 2003-2015 Gerome Fournier <jef(at)foutaise.org>
 #
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Lesser General Public
@@ -33,11 +33,11 @@
 
 setup(
     name = "texttable",
-    version = "0.8.3",
-    author = "Gerome Fournier", 
-    author_email = "jef(at)foutaise.org",
-    url = "http://foutaise.org/code/";,
-    download_url = "http://foutaise.org/code/texttable/texttable-0.8.3.tar.gz";,
+    version = "1.1.1",
+    author = "Gerome Fournier",
+    author_email = "[email protected]",
+    url = "https://github.com/foutaise/texttable/";,
+    download_url = 
"https://github.com/foutaise/texttable/archive/v1.1.1.tar.gz";,
     license = "LGPL",
     py_modules = ["texttable"],
     description = DESCRIPTION,
@@ -55,5 +55,11 @@
         'Topic :: Software Development :: Libraries :: Python Modules',
         'Topic :: Text Processing',
         'Topic :: Utilities',
+        'Programming Language :: Python',
+        'Programming Language :: Python :: 2',
+        'Programming Language :: Python :: 2.7',
+        'Programming Language :: Python :: 3',
+        'Programming Language :: Python :: 3.5',
+        'Programming Language :: Python :: 3.6',
     ]
 )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/texttable-0.8.3/tests.py new/texttable-1.1.1/tests.py
--- old/texttable-0.8.3/tests.py        1970-01-01 01:00:00.000000000 +0100
+++ new/texttable-1.1.1/tests.py        2017-10-26 14:23:51.000000000 +0200
@@ -0,0 +1,198 @@
+#coding: utf-8
+
+import re
+import sys
+from textwrap import dedent
+from texttable import Texttable
+
+if sys.version >= '3':
+    u_dedent = dedent
+else:
+    def u_dedent(b):
+       return unicode(dedent(b), 'utf-8')
+
+def clean(text):
+    return re.sub(r'( +)$', '', text, flags=re.MULTILINE) + '\n'
+
+def test_texttable():
+    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"],
+        ["Mme\nLouise\nBourgeau", 28, "Lou\n \nLoue"],
+    ])
+    assert clean(table.draw()) == dedent('''\
+        +----------+-----+----------+
+        |   Name   | Age | Nickname |
+        +==========+=====+==========+
+        | Mr       |     |          |
+        | Xavier   |  32 |          |
+        | Huon     |     |   Xav'   |
+        +----------+-----+----------+
+        | Mr       |     |          |
+        | Baptiste |   1 |          |
+        | Clement  |     |   Baby   |
+        +----------+-----+----------+
+        | Mme      |     |   Lou    |
+        | Louise   |  28 |          |
+        | Bourgeau |     |   Loue   |
+        +----------+-----+----------+
+    ''')
+
+def test_texttable_header():
+    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],
+    ])
+    assert clean(table.draw()) == dedent('''\
+         text     float       exp      int     auto
+        ==============================================
+        abcd      67.000   6.540e+02    89   128.001
+        efghijk   67.543   6.540e-01    90   1.280e+22
+        lmn        0.000   5.000e-78    89   0.000
+        opqrstu    0.023   5.000e+78    92   1.280e+22
+    ''')
+
+def test_set_cols_width():
+    table = Texttable()
+    table.set_deco(Texttable.HEADER)
+    table.set_cols_width([10, 10])
+    table.add_rows([
+        ["key", "value"],
+        [1,     "a"],
+        [2,     "b"],
+    ])
+    assert clean(table.draw()) == dedent('''\
+           key         value
+        =======================
+        1            a
+        2            b
+    ''')
+
+def test_exceeding_max_width():
+    table = Texttable(max_width=35)
+    table.set_deco(Texttable.HEADER)
+    table.add_rows([
+        ["key", "value"],
+        [1,     "a"],
+        [2,     "b"],
+        [3,     "very long, very long, very long"],
+    ])
+    assert clean(table.draw()) == dedent('''\
+        key               value
+        ===================================
+        1     a
+        2     b
+        3     very long, very long, very
+              long
+    ''')
+
+def test_exceeding_max_width2():
+    table = Texttable(max_width=14)
+    table.add_rows([
+        ["a", "b"],
+        [1, "+"],
+        [22, "++++++++"],
+    ])
+    assert clean(table.draw()) == dedent('''\
+        +----+-------+
+        | a  |   b   |
+        +====+=======+
+        | 1  | +     |
+        +----+-------+
+        | 22 | +++++ |
+        |    | +++   |
+        +----+-------+
+    ''')
+
+def test_obj2unicode():
+    table = Texttable()
+    table.set_deco(Texttable.HEADER)
+    table.add_rows([
+        ["key", "value"],
+        [1,     "a"],
+        [2,     1],
+        [3,     None],
+    ])
+    assert clean(table.draw()) == dedent('''\
+        key   value
+        ===========
+        1     a
+        2     1
+        3     None
+    ''')
+
+def test_combining_char():
+    table = Texttable()
+    table.set_cols_align(["l", "r", "r"])
+    table.add_rows([
+        ["str", "code-point\nlength", "display\nwidth"],
+        ["ā", 2, 1],
+        ["a", 1, 1],
+    ])
+    assert clean(table.draw()) == u_dedent('''\
+        +-----+------------+---------+
+        | str | code-point | display |
+        |     |   length   |  width  |
+        +=====+============+=========+
+        | ā   |          2 |       1 |
+        +-----+------------+---------+
+        | a   |          1 |       1 |
+        +-----+------------+---------+
+    ''')
+
+def test_combining_char2():
+    table = Texttable()
+    table.add_rows([
+        ["a", "b", "c"],
+        ["诶诶诶", "bbb", "西西西"],
+    ], False)
+    assert clean(table.draw()) == u_dedent('''\
+        +--------+-----+--------+
+        | a      | b   | c      |
+        +--------+-----+--------+
+        | 诶诶诶 | bbb | 西西西 |
+        +--------+-----+--------+
+    ''')
+
+
+def test_user_dtype():
+    table = Texttable()
+
+    table.set_cols_align(["l", "r", "r"])
+    table.set_cols_dtype([
+        'a',  # automatic
+        lambda s:str(s)+"s", # user-def
+        lambda s:('%s'%s) if s>=0 else '[%s]'%(-s),  # user-def
+    ])
+    table.add_rows([
+        ["str", "code-point\nlength", "display\nwidth"],
+        ["a", 2, 1],
+        ["a", 1,-3],
+    ])
+    assert clean(table.draw()) == u_dedent('''\
+        +-----+------------+---------+
+        | str | code-point | display |
+        |     |   length   |  width  |
+        +=====+============+=========+
+        | a   |         2s |       1 |
+        +-----+------------+---------+
+        | a   |         1s |     [3] |
+        +-----+------------+---------+
+    ''')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/texttable-0.8.3/texttable.py 
new/texttable-1.1.1/texttable.py
--- old/texttable-0.8.3/texttable.py    2015-03-11 20:34:27.000000000 +0100
+++ new/texttable-1.1.1/texttable.py    2017-10-26 14:23:51.000000000 +0200
@@ -1,5 +1,3 @@
-#!/usr/bin/env python
-#
 # texttable - module for creating simple ASCII tables
 # Copyright (C) 2003-2015 Gerome Fournier <jef(at)foutaise.org>
 #
@@ -25,14 +23,15 @@
     table = Texttable()
     table.set_cols_align(["l", "r", "c"])
     table.set_cols_valign(["t", "m", "b"])
-    table.add_rows([["Name", "Age", "Nickname"], 
+    table.add_rows([["Name", "Age", "Nickname"],
                     ["Mr\\nXavier\\nHuon", 32, "Xav'"],
-                    ["Mr\\nBaptiste\\nClement", 1, "Baby"]])
+                    ["Mr\\nBaptiste\\nClement", 1, "Baby"],
+                    ["Mme\\nLouise\\nBourgeau", 28, "Lou\\n\\nLoue"]])
     print table.draw() + "\\n"
 
     table = Texttable()
     table.set_deco(Texttable.HEADER)
-    table.set_cols_dtype(['t',  # text 
+    table.set_cols_dtype(['t',  # text
                           'f',  # float (decimal)
                           'e',  # float (exponent)
                           'i',  # integer
@@ -58,6 +57,10 @@
     | Baptiste |   1 |          |
     | Clement  |     |   Baby   |
     +----------+-----+----------+
+    | Mme      |     |   Lou    |
+    | Louise   |  28 |          |
+    | Bourgeau |     |   Loue   |
+    +----------+-----+----------+
 
     text   float       exp      int     auto
     ===========================================
@@ -67,11 +70,13 @@
     mnop   0.023    5.000e+78   92    1.280e+22
 """
 
+from __future__ import division
+
 __all__ = ["Texttable", "ArraySizeError"]
 
 __author__ = 'Gerome Fournier <jef(at)foutaise.org>'
 __license__ = 'LGPL'
-__version__ = '0.8.3'
+__version__ = '1.1.1'
 __credits__ = """\
 Jeff Kowalczyk:
     - textwrap improved import
@@ -94,15 +99,19 @@
 
 Maximilian Hils:
     - fix minor bug for Python 3 compatibility
+
+frinkelpi:
+    - preserve empty lines
 """
 
 import sys
 import string
+import unicodedata
 
 try:
-    if sys.version >= '2.3':
+    if sys.version_info >= (2, 3):
         import textwrap
-    elif sys.version >= '2.2':
+    elif sys.version_info >= (2, 2):
         from optparse import textwrap
     else:
         from optik import textwrap
@@ -110,21 +119,43 @@
     sys.stderr.write("Can't import textwrap module!\n")
     raise
 
-if sys.version >= '2.7':
+if sys.version_info >= (2, 7):
     from functools import reduce
 
+if sys.version_info >= (3, 0):
+    unicode_type = str
+    bytes_type = bytes
+else:
+    unicode_type = unicode
+    bytes_type = str
+
+
+def obj2unicode(obj):
+    """Return a unicode representation of a python object
+    """
+    if isinstance(obj, unicode_type):
+        return obj
+    elif isinstance(obj, bytes_type):
+        try:
+            return unicode_type(obj, 'utf-8')
+        except UnicodeDecodeError as strerror:
+            sys.stderr.write("UnicodeDecodeError exception for string '%s': 
%s\n" % (obj, strerror))
+            return unicode_type(obj, 'utf-8', 'replace')
+    else:
+        return unicode_type(obj)
+
+
 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:
-        if sys.version >= '3.0':
-            return len(str)
+    if isinstance(iterable, bytes_type) or isinstance(iterable, unicode_type):
+        unicode_data = obj2unicode(iterable)
+        if hasattr(unicodedata, 'east_asian_width'):
+            w = unicodedata.east_asian_width
+            return sum([w(c) in 'WF' and 2 or (0 if unicodedata.combining(c) 
else 1) for c in unicode_data])
         else:
-            return len(unicode(iterable, 'utf'))
-    except:
+            return unicode_data.__len__()
+    else:
         return iterable.__len__()
 
 
@@ -140,6 +171,11 @@
         return self.msg
 
 
+class FallbackToText(Exception):
+    """Used for failed conversion to float"""
+    pass
+
+
 class Texttable:
 
     BORDER = 1
@@ -241,13 +277,15 @@
     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":
+        - the elements of the array should be either a callable or any of
+          "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
+            * a callable: should return formatted string for any value given
 
         - by default, automatic datatyping is used for each column
         """
@@ -291,7 +329,7 @@
         """
 
         self._check_row_size(array)
-        self._header = list(map(str, array))
+        self._header = list(map(obj2unicode, array))
 
     def add_row(self, array):
         """Add a row in the rows stack
@@ -303,7 +341,7 @@
 
         if not hasattr(self, "_dtype"):
             self._dtype = ["a"] * self._row_size
-            
+
         cells = []
         for i, x in enumerate(array):
             cells.append(self._str(i, x))
@@ -318,7 +356,7 @@
           of the table
         """
 
-        # nb: don't use 'iter' on by-dimensional arrays, to get a 
+        # 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'):
@@ -356,39 +394,88 @@
             out += self._hline()
         return out[:-1]
 
+    @classmethod
+    def _to_float(cls, x):
+        if x is None:
+            raise FallbackToText()
+        try:
+            return float(x)
+        except (TypeError, ValueError):
+            raise FallbackToText()
+
+    @classmethod
+    def _fmt_int(cls, x, **kw):
+        """Integer formatting class-method.
+
+        - x will be float-converted and then used.
+        """
+        return str(int(round(cls._to_float(x))))
+
+    @classmethod
+    def _fmt_float(cls, x, **kw):
+        """Float formatting class-method.
+
+        - x parameter is ignored. Instead kw-argument f being x float-converted
+          will be used.
+
+        - precision will be taken from `n` kw-argument.
+        """
+        n = kw.get('n')
+        return '%.*f' % (n, cls._to_float(x))
+
+    @classmethod
+    def _fmt_exp(cls, x, **kw):
+        """Exponential formatting class-method.
+
+        - x parameter is ignored. Instead kw-argument f being x float-converted
+          will be used.
+
+        - precision will be taken from `n` kw-argument.
+        """
+        n = kw.get('n')
+        return '%.*e' % (n, cls._to_float(x))
+
+    @classmethod
+    def _fmt_text(cls, x, **kw):
+        """String formatting class-method."""
+        return obj2unicode(x)
+
+    @classmethod
+    def _fmt_auto(cls, x, **kw):
+        """auto formatting class-method."""
+        f = cls._to_float(x)
+        if abs(f) > 1e8:
+            fn = cls._fmt_exp
+        else:
+            if f - round(f) == 0:
+                fn = cls._fmt_int
+            else:
+                fn = cls._fmt_float
+        return fn(x, **kw)
+
     def _str(self, i, x):
         """Handles string formatting of cell data
 
-            i - index of the cell datatype in self._dtype 
+            i - index of the cell datatype in self._dtype
             x - cell data to format
         """
-        try:
-            f = float(x)
-        except:
-            return str(x)
+        FMT = {
+            'a':self._fmt_auto,
+            'i':self._fmt_int,
+            'f':self._fmt_float,
+            'e':self._fmt_exp,
+            't':self._fmt_text,
+            }
 
         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)))
+        try:
+            if callable(dtype):
+                return dtype(x)
             else:
-                if abs(f) > 1e8:
-                    return '%.*e' % (n, f)
-                else:
-                    return '%.*f' % (n, f)
+                return FMT[dtype](x, n=n)
+        except FallbackToText:
+            return self._fmt_text(x)
 
     def _check_row_size(self, array):
         """Check that the specified array fits the previous rows size
@@ -496,11 +583,25 @@
                     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)]
+
+        ncols = len(maxi)
+        content_width = sum(maxi)
+        deco_width = 3*(ncols-1) + [0,4][self._has_border()]
+        if self._max_width and (content_width + deco_width) > self._max_width:
+            """ content too wide to fit the expected max_width
+            let's recompute maximum cell width for each cell
+            """
+            if self._max_width < (ncols + deco_width):
+                raise ValueError('max_width too low to render data')
+            available_width = self._max_width - deco_width
+            newmaxi = [0] * ncols
+            i = 0
+            while available_width > 0:
+                if newmaxi[i] < maxi[i]:
+                    newmaxi[i] += 1
+                    available_width -= 1
+                i = (i + 1) % ncols
+            maxi = newmaxi
         self._width = maxi
 
     def _check_align(self):
@@ -532,15 +633,15 @@
                 if isheader:
                     align = "c"
                 if align == "r":
-                    out += "%s " % (fill * space + cell_line)
+                    out += fill * space + cell_line
                 elif align == "c":
-                    out += "%s " % (int(fill/2) * space + cell_line \
+                    out += (int(fill/2) * space + cell_line \
                             + int(fill/2 + fill%2) * space)
                 else:
-                    out += "%s " % (cell_line + fill * space)
+                    out += 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()]
+                    out += " %s " % [space, 
self._char_vert][self._has_vlines()]
+            out += "%s\n" % ['', space + self._char_vert][self._has_border()]
         return out
 
     def _splitit(self, line, isheader):
@@ -554,18 +655,10 @@
         for cell, width in zip(line, self._width):
             array = []
             for c in cell.split('\n'):
-                try:
-                    if sys.version >= '3.0':
-                        c = str(c)
-                    else:
-                        c = unicode(c, 'utf')
-                except UnicodeDecodeError as strerror:
-                    sys.stderr.write("UnicodeDecodeError exception for string 
'%s': %s\n" % (c, strerror))
-                    if sys.version >= '3.0':
-                        c = str(c, 'utf', 'replace')
-                    else:
-                        c = unicode(c, 'utf', 'replace')
-                array.extend(textwrap.wrap(c, width))
+                if c.strip() == "":
+                    array.append("")
+                else:
+                    array.extend(textwrap.wrap(c, width))
             line_wrapped.append(array)
         max_cell_lines = reduce(max, list(map(len, line_wrapped)))
         for cell, valign in zip(line_wrapped, self._valign):
@@ -588,12 +681,13 @@
     table.set_cols_valign(["t", "m", "b"])
     table.add_rows([["Name", "Age", "Nickname"],
                     ["Mr\nXavier\nHuon", 32, "Xav'"],
-                    ["Mr\nBaptiste\nClement", 1, "Baby"]])
+                    ["Mr\nBaptiste\nClement", 1, "Baby"],
+                    ["Mme\nLouise\nBourgeau", 28, "Lou\n \nLoue"]])
     print(table.draw() + "\n")
 
     table = Texttable()
     table.set_deco(Texttable.HEADER)
-    table.set_cols_dtype(['t',  # text 
+    table.set_cols_dtype(['t',  # text
                           'f',  # float (decimal)
                           'e',  # float (exponent)
                           'i',  # integer
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/texttable-0.8.3/tox.ini new/texttable-1.1.1/tox.ini
--- old/texttable-0.8.3/tox.ini 1970-01-01 01:00:00.000000000 +0100
+++ new/texttable-1.1.1/tox.ini 2017-10-26 14:23:51.000000000 +0200
@@ -0,0 +1,8 @@
+[tox]
+envlist = py27,py35,py36
+
+[testenv]
+deps =
+    pytest
+    pytest-cov
+commands = py.test --cov-report=term-missing --cov=texttable tests.py


Reply via email to