1# -*- coding: utf-8 -*- 2 3"""Test support of the various forms of tabular data.""" 4 5from __future__ import print_function 6from __future__ import unicode_literals 7from tabulate import tabulate 8from common import assert_equal, assert_in, assert_raises, SkipTest 9 10 11def test_iterable_of_iterables(): 12 "Input: an interable of iterables." 13 ii = iter(map(lambda x: iter(x), [range(5), range(5, 0, -1)])) 14 expected = "\n".join( 15 ["- - - - -", "0 1 2 3 4", "5 4 3 2 1", "- - - - -"] 16 ) 17 result = tabulate(ii) 18 assert_equal(expected, result) 19 20 21def test_iterable_of_iterables_headers(): 22 "Input: an interable of iterables with headers." 23 ii = iter(map(lambda x: iter(x), [range(5), range(5, 0, -1)])) 24 expected = "\n".join( 25 [ 26 " a b c d e", 27 "--- --- --- --- ---", 28 " 0 1 2 3 4", 29 " 5 4 3 2 1", 30 ] 31 ) 32 result = tabulate(ii, "abcde") 33 assert_equal(expected, result) 34 35 36def test_iterable_of_iterables_firstrow(): 37 "Input: an interable of iterables with the first row as headers" 38 ii = iter(map(lambda x: iter(x), ["abcde", range(5), range(5, 0, -1)])) 39 expected = "\n".join( 40 [ 41 " a b c d e", 42 "--- --- --- --- ---", 43 " 0 1 2 3 4", 44 " 5 4 3 2 1", 45 ] 46 ) 47 result = tabulate(ii, "firstrow") 48 assert_equal(expected, result) 49 50 51def test_list_of_lists(): 52 "Input: a list of lists with headers." 53 ll = [["a", "one", 1], ["b", "two", None]] 54 expected = "\n".join( 55 [ 56 " string number", 57 "-- -------- --------", 58 "a one 1", 59 "b two", 60 ] 61 ) 62 result = tabulate(ll, headers=["string", "number"]) 63 assert_equal(expected, result) 64 65 66def test_list_of_lists_firstrow(): 67 "Input: a list of lists with the first row as headers." 68 ll = [["string", "number"], ["a", "one", 1], ["b", "two", None]] 69 expected = "\n".join( 70 [ 71 " string number", 72 "-- -------- --------", 73 "a one 1", 74 "b two", 75 ] 76 ) 77 result = tabulate(ll, headers="firstrow") 78 assert_equal(expected, result) 79 80 81def test_list_of_lists_keys(): 82 "Input: a list of lists with column indices as headers." 83 ll = [["a", "one", 1], ["b", "two", None]] 84 expected = "\n".join( 85 ["0 1 2", "--- --- ---", "a one 1", "b two"] 86 ) 87 result = tabulate(ll, headers="keys") 88 assert_equal(expected, result) 89 90 91def test_dict_like(): 92 "Input: a dict of iterables with keys as headers." 93 # columns should be padded with None, keys should be used as headers 94 dd = {"a": range(3), "b": range(101, 105)} 95 # keys' order (hence columns' order) is not deterministic in Python 3 96 # => we have to consider both possible results as valid 97 expected1 = "\n".join( 98 [" a b", "--- ---", " 0 101", " 1 102", " 2 103", " 104"] 99 ) 100 expected2 = "\n".join( 101 [" b a", "--- ---", "101 0", "102 1", "103 2", "104"] 102 ) 103 result = tabulate(dd, "keys") 104 print("Keys' order: %s" % dd.keys()) 105 assert_in(result, [expected1, expected2]) 106 107 108def test_numpy_2d(): 109 "Input: a 2D NumPy array with headers." 110 try: 111 import numpy 112 113 na = (numpy.arange(1, 10, dtype=numpy.float32).reshape((3, 3)) ** 3) * 0.5 114 expected = "\n".join( 115 [ 116 " a b c", 117 "----- ----- -----", 118 " 0.5 4 13.5", 119 " 32 62.5 108", 120 "171.5 256 364.5", 121 ] 122 ) 123 result = tabulate(na, ["a", "b", "c"]) 124 assert_equal(expected, result) 125 except ImportError: 126 print("test_numpy_2d is skipped") 127 raise SkipTest() # this test is optional 128 129 130def test_numpy_2d_firstrow(): 131 "Input: a 2D NumPy array with the first row as headers." 132 try: 133 import numpy 134 135 na = numpy.arange(1, 10, dtype=numpy.int32).reshape((3, 3)) ** 3 136 expected = "\n".join( 137 [" 1 8 27", "--- --- ----", " 64 125 216", "343 512 729"] 138 ) 139 result = tabulate(na, headers="firstrow") 140 assert_equal(expected, result) 141 except ImportError: 142 print("test_numpy_2d_firstrow is skipped") 143 raise SkipTest() # this test is optional 144 145 146def test_numpy_2d_keys(): 147 "Input: a 2D NumPy array with column indices as headers." 148 try: 149 import numpy 150 151 na = (numpy.arange(1, 10, dtype=numpy.float32).reshape((3, 3)) ** 3) * 0.5 152 expected = "\n".join( 153 [ 154 " 0 1 2", 155 "----- ----- -----", 156 " 0.5 4 13.5", 157 " 32 62.5 108", 158 "171.5 256 364.5", 159 ] 160 ) 161 result = tabulate(na, headers="keys") 162 assert_equal(expected, result) 163 except ImportError: 164 print("test_numpy_2d_keys is skipped") 165 raise SkipTest() # this test is optional 166 167 168def test_numpy_record_array(): 169 "Input: a 2D NumPy record array without header." 170 try: 171 import numpy 172 173 na = numpy.asarray( 174 [("Alice", 23, 169.5), ("Bob", 27, 175.0)], 175 dtype={ 176 "names": ["name", "age", "height"], 177 "formats": ["a32", "uint8", "float32"], 178 }, 179 ) 180 expected = "\n".join( 181 [ 182 "----- -- -----", 183 "Alice 23 169.5", 184 "Bob 27 175", 185 "----- -- -----", 186 ] 187 ) 188 result = tabulate(na) 189 assert_equal(expected, result) 190 except ImportError: 191 print("test_numpy_2d_keys is skipped") 192 raise SkipTest() # this test is optional 193 194 195def test_numpy_record_array_keys(): 196 "Input: a 2D NumPy record array with column names as headers." 197 try: 198 import numpy 199 200 na = numpy.asarray( 201 [("Alice", 23, 169.5), ("Bob", 27, 175.0)], 202 dtype={ 203 "names": ["name", "age", "height"], 204 "formats": ["a32", "uint8", "float32"], 205 }, 206 ) 207 expected = "\n".join( 208 [ 209 "name age height", 210 "------ ----- --------", 211 "Alice 23 169.5", 212 "Bob 27 175", 213 ] 214 ) 215 result = tabulate(na, headers="keys") 216 assert_equal(expected, result) 217 except ImportError: 218 print("test_numpy_2d_keys is skipped") 219 raise SkipTest() # this test is optional 220 221 222def test_numpy_record_array_headers(): 223 "Input: a 2D NumPy record array with user-supplied headers." 224 try: 225 import numpy 226 227 na = numpy.asarray( 228 [("Alice", 23, 169.5), ("Bob", 27, 175.0)], 229 dtype={ 230 "names": ["name", "age", "height"], 231 "formats": ["a32", "uint8", "float32"], 232 }, 233 ) 234 expected = "\n".join( 235 [ 236 "person years cm", 237 "-------- ------- -----", 238 "Alice 23 169.5", 239 "Bob 27 175", 240 ] 241 ) 242 result = tabulate(na, headers=["person", "years", "cm"]) 243 assert_equal(expected, result) 244 except ImportError: 245 print("test_numpy_2d_keys is skipped") 246 raise SkipTest() # this test is optional 247 248 249def test_pandas(): 250 "Input: a Pandas DataFrame." 251 try: 252 import pandas 253 254 df = pandas.DataFrame([["one", 1], ["two", None]], index=["a", "b"]) 255 expected = "\n".join( 256 [ 257 " string number", 258 "-- -------- --------", 259 "a one 1", 260 "b two nan", 261 ] 262 ) 263 result = tabulate(df, headers=["string", "number"]) 264 assert_equal(expected, result) 265 except ImportError: 266 print("test_pandas is skipped") 267 raise SkipTest() # this test is optional 268 269 270def test_pandas_firstrow(): 271 "Input: a Pandas DataFrame with the first row as headers." 272 try: 273 import pandas 274 275 df = pandas.DataFrame( 276 [["one", 1], ["two", None]], columns=["string", "number"], index=["a", "b"] 277 ) 278 expected = "\n".join( 279 ["a one 1.0", "--- ----- -----", "b two nan"] 280 ) 281 result = tabulate(df, headers="firstrow") 282 assert_equal(expected, result) 283 except ImportError: 284 print("test_pandas_firstrow is skipped") 285 raise SkipTest() # this test is optional 286 287 288def test_pandas_keys(): 289 "Input: a Pandas DataFrame with keys as headers." 290 try: 291 import pandas 292 293 df = pandas.DataFrame( 294 [["one", 1], ["two", None]], columns=["string", "number"], index=["a", "b"] 295 ) 296 expected = "\n".join( 297 [ 298 " string number", 299 "-- -------- --------", 300 "a one 1", 301 "b two nan", 302 ] 303 ) 304 result = tabulate(df, headers="keys") 305 assert_equal(expected, result) 306 except ImportError: 307 print("test_pandas_keys is skipped") 308 raise SkipTest() # this test is optional 309 310 311def test_sqlite3(): 312 "Input: an sqlite3 cursor" 313 try: 314 import sqlite3 315 316 conn = sqlite3.connect(":memory:") 317 cursor = conn.cursor() 318 cursor.execute("CREATE TABLE people (name, age, height)") 319 for values in [("Alice", 23, 169.5), ("Bob", 27, 175.0)]: 320 cursor.execute("INSERT INTO people VALUES (?, ?, ?)", values) 321 cursor.execute("SELECT name, age, height FROM people ORDER BY name") 322 result = tabulate(cursor, headers=["whom", "how old", "how tall"]) 323 expected = """\ 324whom how old how tall 325------ --------- ---------- 326Alice 23 169.5 327Bob 27 175""" 328 assert_equal(expected, result) 329 except ImportError: 330 print("test_sqlite3 is skipped") 331 raise SkipTest() # this test is optional 332 333 334def test_sqlite3_keys(): 335 "Input: an sqlite3 cursor with keys as headers" 336 try: 337 import sqlite3 338 339 conn = sqlite3.connect(":memory:") 340 cursor = conn.cursor() 341 cursor.execute("CREATE TABLE people (name, age, height)") 342 for values in [("Alice", 23, 169.5), ("Bob", 27, 175.0)]: 343 cursor.execute("INSERT INTO people VALUES (?, ?, ?)", values) 344 cursor.execute( 345 'SELECT name "whom", age "how old", height "how tall" FROM people ORDER BY name' 346 ) 347 result = tabulate(cursor, headers="keys") 348 expected = """\ 349whom how old how tall 350------ --------- ---------- 351Alice 23 169.5 352Bob 27 175""" 353 assert_equal(expected, result) 354 except ImportError: 355 print("test_sqlite3_keys is skipped") 356 raise SkipTest() # this test is optional 357 358 359def test_list_of_namedtuples(): 360 "Input: a list of named tuples with field names as headers." 361 from collections import namedtuple 362 363 NT = namedtuple("NT", ["foo", "bar"]) 364 lt = [NT(1, 2), NT(3, 4)] 365 expected = "\n".join(["- -", "1 2", "3 4", "- -"]) 366 result = tabulate(lt) 367 assert_equal(expected, result) 368 369 370def test_list_of_namedtuples_keys(): 371 "Input: a list of named tuples with field names as headers." 372 from collections import namedtuple 373 374 NT = namedtuple("NT", ["foo", "bar"]) 375 lt = [NT(1, 2), NT(3, 4)] 376 expected = "\n".join( 377 [" foo bar", "----- -----", " 1 2", " 3 4"] 378 ) 379 result = tabulate(lt, headers="keys") 380 assert_equal(expected, result) 381 382 383def test_list_of_dicts(): 384 "Input: a list of dictionaries." 385 lod = [{"foo": 1, "bar": 2}, {"foo": 3, "bar": 4}] 386 expected1 = "\n".join(["- -", "1 2", "3 4", "- -"]) 387 expected2 = "\n".join(["- -", "2 1", "4 3", "- -"]) 388 result = tabulate(lod) 389 assert_in(result, [expected1, expected2]) 390 391 392def test_list_of_dicts_keys(): 393 "Input: a list of dictionaries, with keys as headers." 394 lod = [{"foo": 1, "bar": 2}, {"foo": 3, "bar": 4}] 395 expected1 = "\n".join( 396 [" foo bar", "----- -----", " 1 2", " 3 4"] 397 ) 398 expected2 = "\n".join( 399 [" bar foo", "----- -----", " 2 1", " 4 3"] 400 ) 401 result = tabulate(lod, headers="keys") 402 assert_in(result, [expected1, expected2]) 403 404 405def test_list_of_dicts_with_missing_keys(): 406 "Input: a list of dictionaries, with missing keys." 407 lod = [{"foo": 1}, {"bar": 2}, {"foo": 4, "baz": 3}] 408 expected = "\n".join( 409 [ 410 " foo bar baz", 411 "----- ----- -----", 412 " 1", 413 " 2", 414 " 4 3", 415 ] 416 ) 417 result = tabulate(lod, headers="keys") 418 assert_equal(expected, result) 419 420 421def test_list_of_dicts_firstrow(): 422 "Input: a list of dictionaries, with the first dict as headers." 423 lod = [{"foo": "FOO", "bar": "BAR"}, {"foo": 3, "bar": 4, "baz": 5}] 424 # if some key is missing in the first dict, use the key name instead 425 expected1 = "\n".join( 426 [" FOO BAR baz", "----- ----- -----", " 3 4 5"] 427 ) 428 expected2 = "\n".join( 429 [" BAR FOO baz", "----- ----- -----", " 4 3 5"] 430 ) 431 result = tabulate(lod, headers="firstrow") 432 assert_in(result, [expected1, expected2]) 433 434 435def test_list_of_dicts_with_dict_of_headers(): 436 "Input: a dict of user headers for a list of dicts (issue #23)" 437 table = [{"letters": "ABCDE", "digits": 12345}] 438 headers = {"digits": "DIGITS", "letters": "LETTERS"} 439 expected1 = "\n".join( 440 [" DIGITS LETTERS", "-------- ---------", " 12345 ABCDE"] 441 ) 442 expected2 = "\n".join( 443 ["LETTERS DIGITS", "--------- --------", "ABCDE 12345"] 444 ) 445 result = tabulate(table, headers=headers) 446 assert_in(result, [expected1, expected2]) 447 448 449def test_list_of_dicts_with_list_of_headers(): 450 "Input: ValueError on a list of headers with a list of dicts (issue #23)" 451 table = [{"letters": "ABCDE", "digits": 12345}] 452 headers = ["DIGITS", "LETTERS"] 453 with assert_raises(ValueError): 454 tabulate(table, headers=headers) 455 456 457def test_py27orlater_list_of_ordereddicts(): 458 "Input: a list of OrderedDicts." 459 from collections import OrderedDict 460 461 od = OrderedDict([("b", 1), ("a", 2)]) 462 lod = [od, od] 463 expected = "\n".join([" b a", "--- ---", " 1 2", " 1 2"]) 464 result = tabulate(lod, headers="keys") 465 assert_equal(expected, result) 466