1# -*- coding: utf-8 -*- 2 3######################################################################## 4# 5# License: BSD 6# Created: 2006-10-19 7# Author: Ivan Vilata i Balaguer - ivan@selidor.net 8# 9# $Id$ 10# 11######################################################################## 12 13"""Test module for queries on datasets.""" 14 15import re 16import sys 17import types 18import warnings 19import functools 20 21import numpy 22 23import tables 24from tables.utils import SizeType 25from tables.tests import common 26from tables.tests.common import unittest 27from tables.tests.common import verbosePrint as vprint 28from tables.tests.common import PyTablesTestCase as TestCase 29 30 31from numpy import (log10, exp, log, abs, sqrt, sin, cos, tan, 32 arcsin, arccos, arctan) 33 34 35# Data parameters 36# --------------- 37row_period = 50 38"""Maximum number of unique rows before they start cycling.""" 39md_shape = (2, 2) 40"""Shape of multidimensional fields.""" 41 42_maxnvalue = row_period + numpy.prod(md_shape, dtype=SizeType) - 1 43_strlen = int(numpy.log10(_maxnvalue-1)) + 1 44 45str_format = '%%0%dd' % _strlen 46"""Format of string values.""" 47 48small_blocksizes = (300, 60, 20, 5) 49# small_blocksizes = (512, 128, 32, 4) # for manual testing only 50"""Sensible parameters for indexing with small blocksizes.""" 51 52 53# Type information 54# ---------------- 55type_info = { 56 'bool': (numpy.bool_, bool), 57 'int8': (numpy.int8, int), 58 'uint8': (numpy.uint8, int), 59 'int16': (numpy.int16, int), 60 'uint16': (numpy.uint16, int), 61 'int32': (numpy.int32, int), 62 'uint32': (numpy.uint32, int), 63 'int64': (numpy.int64, int), 64 'uint64': (numpy.uint64, int), 65 'float32': (numpy.float32, float), 66 'float64': (numpy.float64, float), 67 'complex64': (numpy.complex64, complex), 68 'complex128': (numpy.complex128, complex), 69 'time32': (numpy.int32, int), 70 'time64': (numpy.float64, float), 71 'enum': (numpy.uint8, int), # just for these tests 72 'string': ('S%s' % _strlen, numpy.string_), # just for these tests 73} 74"""NumPy and Numexpr type for each PyTables type that will be tested.""" 75 76# globals dict for eval() 77func_info = {'log10': log10, 'log': log, 'exp': exp, 78 'abs': abs, 'sqrt': sqrt, 79 'sin': sin, 'cos': cos, 'tan': tan, 80 'arcsin': arcsin, 'arccos': arccos, 'arctan': arctan} 81"""functions and NumPy.ufunc() for each function that will be tested.""" 82 83 84if hasattr(numpy, 'float16'): 85 type_info['float16'] = (numpy.float16, float) 86# if hasattr(numpy, 'float96'): 87# type_info['float96'] = (numpy.float96, float) 88# if hasattr(numpy, 'float128'): 89# type_info['float128'] = (numpy.float128, float) 90# if hasattr(numpy, 'complex192'): 91# type_info['complex192'] = (numpy.complex192, complex) 92# if hasattr(numpy, 'complex256'): 93# type_info['complex256'] = (numpy.complex256, complex) 94 95sctype_from_type = dict((type_, info[0]) 96 for (type_, info) in type_info.items()) 97"""Maps PyTables types to NumPy scalar types.""" 98nxtype_from_type = dict((type_, info[1]) 99 for (type_, info) in type_info.items()) 100"""Maps PyTables types to Numexpr types.""" 101 102heavy_types = frozenset(['uint8', 'int16', 'uint16', 'float32', 'complex64']) 103"""PyTables types to be tested only in heavy mode.""" 104 105enum = tables.Enum(dict(('n%d' % i, i) for i in range(_maxnvalue))) 106"""Enumerated type to be used in tests.""" 107 108 109# Table description 110# ----------------- 111def append_columns(classdict, shape=()): 112 """Append a ``Col`` of each PyTables data type to the `classdict`. 113 114 A column of a certain TYPE gets called ``c_TYPE``. The number of 115 added columns is returned. 116 117 """ 118 heavy = common.heavy 119 for (itype, type_) in enumerate(sorted(type_info.keys())): 120 if not heavy and type_ in heavy_types: 121 continue # skip heavy type in non-heavy mode 122 colpos = itype + 1 123 colname = 'c_%s' % type_ 124 if type_ == 'enum': 125 base = tables.Atom.from_sctype(sctype_from_type[type_]) 126 col = tables.EnumCol(enum, enum(0), base, shape=shape, pos=colpos) 127 else: 128 sctype = sctype_from_type[type_] 129 dtype = numpy.dtype((sctype, shape)) 130 col = tables.Col.from_dtype(dtype, pos=colpos) 131 classdict[colname] = col 132 ncols = colpos 133 return ncols 134 135 136def nested_description(classname, pos, shape=()): 137 """Return a nested column description with all PyTables data types. 138 139 A column of a certain TYPE gets called ``c_TYPE``. The nested 140 column will be placed in the position indicated by `pos`. 141 142 """ 143 classdict = {} 144 append_columns(classdict, shape=shape) 145 classdict['_v_pos'] = pos 146 return type(classname, (tables.IsDescription,), classdict) 147 148 149def table_description(classname, nclassname, shape=()): 150 """Return a table description for testing queries. 151 152 The description consists of all PyTables data types, both in the 153 top level and in the ``c_nested`` nested column. A column of a 154 certain TYPE gets called ``c_TYPE``. An extra integer column 155 ``c_extra`` is also provided. If a `shape` is given, it will be 156 used for all columns. Finally, an extra indexed column 157 ``c_idxextra`` is added as well in order to provide some basic 158 tests for multi-index queries. 159 160 """ 161 classdict = {} 162 colpos = append_columns(classdict, shape) 163 164 ndescr = nested_description(nclassname, colpos, shape=shape) 165 classdict['c_nested'] = ndescr 166 colpos += 1 167 168 extracol = tables.IntCol(shape=shape, pos=colpos) 169 classdict['c_extra'] = extracol 170 colpos += 1 171 172 idxextracol = tables.IntCol(shape=shape, pos=colpos) 173 classdict['c_idxextra'] = idxextracol 174 colpos += 1 175 176 return type(classname, (tables.IsDescription,), classdict) 177 178TableDescription = table_description( 179 'TableDescription', 'NestedDescription') 180"""Unidimensional table description for testing queries.""" 181 182MDTableDescription = table_description( 183 'MDTableDescription', 'MDNestedDescription', shape=md_shape) 184"""Multidimensional table description for testing queries.""" 185 186 187# Table data 188# ---------- 189table_data = {} 190"""Cached table data for a given shape and number of rows.""" 191# Data is cached because computing it row by row is quite slow. Hop! 192 193 194def fill_table(table, shape, nrows): 195 """Fill the given `table` with `nrows` rows of data. 196 197 Values in the i-th row (where 0 <= i < `row_period`) for a 198 multidimensional field with M elements span from i to i + M-1. For 199 subsequent rows, values repeat cyclically. 200 201 The same goes for the ``c_extra`` column, but values range from 202 -`row_period`/2 to +`row_period`/2. 203 204 """ 205 # Reuse already computed data if possible. 206 tdata = table_data.get((shape, nrows)) 207 if tdata is not None: 208 table.append(tdata) 209 table.flush() 210 return 211 212 heavy = common.heavy 213 size = int(numpy.prod(shape, dtype=SizeType)) 214 215 row, value = table.row, 0 216 for nrow in range(nrows): 217 data = numpy.arange(value, value + size).reshape(shape) 218 for (type_, sctype) in sctype_from_type.items(): 219 if not heavy and type_ in heavy_types: 220 continue # skip heavy type in non-heavy mode 221 colname = 'c_%s' % type_ 222 ncolname = 'c_nested/%s' % colname 223 if type_ == 'bool': 224 coldata = data > (row_period // 2) 225 elif type_ == 'string': 226 sdata = [str_format % x for x in range(value, value + size)] 227 coldata = numpy.array(sdata, dtype=sctype).reshape(shape) 228 else: 229 coldata = numpy.asarray(data, dtype=sctype) 230 row[ncolname] = row[colname] = coldata 231 row['c_extra'] = data - (row_period // 2) 232 row['c_idxextra'] = data - (row_period // 2) 233 row.append() 234 value += 1 235 if value == row_period: 236 value = 0 237 table.flush() 238 239 # Make computed data reusable. 240 tdata = table.read() 241 table_data[(shape, nrows)] = tdata 242 243 244class SilentlySkipTest(unittest.SkipTest): 245 pass 246 247 248# Base test cases 249# --------------- 250class BaseTableQueryTestCase(common.TempFileMixin, TestCase): 251 """Base test case for querying tables. 252 253 Sub-classes must define the following attributes: 254 255 ``tableDescription`` 256 The description of the table to be created. 257 ``shape`` 258 The shape of data fields in the table. 259 ``nrows`` 260 The number of data rows to be generated for the table. 261 262 Sub-classes may redefine the following attributes: 263 264 ``indexed`` 265 Whether columns shall be indexed, if possible. Default is not 266 to index them. 267 ``optlevel`` 268 The level of optimisation of column indexes. Default is 0. 269 270 """ 271 272 indexed = False 273 optlevel = 0 274 275 colNotIndexable_re = re.compile(r"\bcan not be indexed\b") 276 condNotBoolean_re = re.compile(r"\bdoes not have a boolean type\b") 277 278 def create_indexes(self, colname, ncolname, extracolname): 279 if not self.indexed: 280 return 281 try: 282 kind = self.kind 283 vprint("* Indexing ``%s`` columns. Type: %s." % (colname, kind)) 284 for acolname in [colname, ncolname, extracolname]: 285 acolumn = self.table.colinstances[acolname] 286 acolumn.create_index( 287 kind=self.kind, optlevel=self.optlevel, 288 _blocksizes=small_blocksizes, _testmode=True) 289 290 except TypeError as te: 291 if self.colNotIndexable_re.search(str(te)): 292 raise SilentlySkipTest( 293 "Columns of this type can not be indexed.") 294 raise 295 except NotImplementedError: 296 raise SilentlySkipTest( 297 "Indexing columns of this type is not supported yet.") 298 299 def setUp(self): 300 super(BaseTableQueryTestCase, self).setUp() 301 self.table = self.h5file.create_table( 302 '/', 'test', self.tableDescription, expectedrows=self.nrows) 303 fill_table(self.table, self.shape, self.nrows) 304 305 306class ScalarTableMixin: 307 tableDescription = TableDescription 308 shape = () 309 310 311class MDTableMixin: 312 tableDescription = MDTableDescription 313 shape = md_shape 314 315 316# Test cases on query data 317# ------------------------ 318operators = [ 319 None, '~', 320 '<', '<=', '==', '!=', '>=', '>', 321 ('<', '<='), ('>', '>=')] 322"""Comparison operators to check with different types.""" 323heavy_operators = frozenset(['~', '<=', '>=', '>', ('>', '>=')]) 324"""Comparison operators to be tested only in heavy mode.""" 325left_bound = row_period // 4 326"""Operand of left side operator in comparisons with operator pairs.""" 327right_bound = row_period * 3 // 4 328"""Operand of right side operator in comparisons with operator pairs.""" 329func_bound = 0.8 # must be <1 for trig functions to be able to fail 330"""Operand of right side operator in comparisons with functions. """ 331extra_conditions = [ 332 '', # uses one index 333 '& ((c_extra + 1) < 0)', # uses one index 334 '| (c_idxextra > 0)', # uses two indexes 335 '| ((c_idxextra > 0) | ((c_extra + 1) > 0))', # can't use indexes 336] 337"""Extra conditions to append to comparison conditions.""" 338 339 340class TableDataTestCase(BaseTableQueryTestCase): 341 """Base test case for querying table data. 342 343 Automatically created test method names have the format 344 ``test_XNNNN``, where ``NNNN`` is the zero-padded test number and 345 ``X`` indicates whether the test belongs to the light (``l``) or 346 heavy (``h``) set. 347 348 """ 349 _testfmt_light = 'test_l%04d' 350 _testfmt_heavy = 'test_h%04d' 351 352 353def create_test_method(type_, op, extracond, func=None): 354 sctype = sctype_from_type[type_] 355 356 # Compute the value of bounds. 357 condvars = {'bound': right_bound, 358 'lbound': left_bound, 359 'rbound': right_bound, 360 'func_bound': func_bound} 361 for (bname, bvalue) in condvars.items(): 362 if type_ == 'string': 363 bvalue = str_format % bvalue 364 bvalue = nxtype_from_type[type_](bvalue) 365 condvars[bname] = bvalue 366 367 # Compute the name of columns. 368 colname = 'c_%s' % type_ 369 ncolname = 'c_nested/%s' % colname 370 371 # Compute the query condition. 372 if not op: # as is 373 cond = colname 374 elif op == '~': # unary 375 cond = '~(%s)' % colname 376 elif op == '<' and func is None: # binary variable-constant 377 cond = '%s %s %s' % (colname, op, repr(condvars['bound'])) 378 elif isinstance(op, tuple): # double binary variable-constant 379 cond = ('(lbound %s %s) & (%s %s rbound)' 380 % (op[0], colname, colname, op[1])) 381 elif func is not None: 382 cond = '%s(%s) %s func_bound' % (func, colname, op) 383 else: # function or binary variable-variable 384 cond = '%s %s bound' % (colname, op) 385 if extracond: 386 cond = '(%s) %s' % (cond, extracond) 387 388 def ignore_skipped(oldmethod): 389 @functools.wraps(oldmethod) 390 def newmethod(self, *args, **kwargs): 391 self._verboseHeader() 392 try: 393 return oldmethod(self, *args, **kwargs) 394 except SilentlySkipTest as se: 395 if se.args: 396 msg = se.args[0] 397 else: 398 msg = "<skipped>" 399 common.verbosePrint("\nSkipped test: %s" % msg) 400 finally: 401 common.verbosePrint('') # separator line between tests 402 return newmethod 403 404 @ignore_skipped 405 def test_method(self): 406 vprint("* Condition is ``%s``." % cond) 407 # Replace bitwise operators with their logical counterparts. 408 pycond = cond 409 for (ptop, pyop) in [('&', 'and'), ('|', 'or'), ('~', 'not')]: 410 pycond = pycond.replace(ptop, pyop) 411 pycond = compile(pycond, '<string>', 'eval') 412 413 table = self.table 414 self.create_indexes(colname, ncolname, 'c_idxextra') 415 416 table_slice = dict(start=1, stop=table.nrows - 5, step=3) 417 rownos, fvalues = None, None 418 # Test that both simple and nested columns work as expected. 419 # Knowing how the table is filled, results must be the same. 420 for acolname in [colname, ncolname]: 421 # First the reference Python version. 422 pyrownos, pyfvalues, pyvars = [], [], condvars.copy() 423 for row in table.iterrows(**table_slice): 424 pyvars[colname] = row[acolname] 425 pyvars['c_extra'] = row['c_extra'] 426 pyvars['c_idxextra'] = row['c_idxextra'] 427 try: 428 with warnings.catch_warnings(): 429 warnings.filterwarnings( 430 'ignore', 431 'invalid value encountered in arc(cos|sin)', 432 RuntimeWarning) 433 isvalidrow = eval(pycond, func_info, pyvars) 434 except TypeError: 435 raise SilentlySkipTest( 436 "The Python type does not support the operation.") 437 if isvalidrow: 438 pyrownos.append(row.nrow) 439 pyfvalues.append(row[acolname]) 440 pyrownos = numpy.array(pyrownos) # row numbers already sorted 441 pyfvalues = numpy.array(pyfvalues, dtype=sctype) 442 pyfvalues.sort() 443 vprint("* %d rows selected by Python from ``%s``." 444 % (len(pyrownos), acolname)) 445 if rownos is None: 446 rownos = pyrownos # initialise reference results 447 fvalues = pyfvalues 448 else: 449 self.assertTrue(numpy.all(pyrownos == rownos)) # check 450 self.assertTrue(numpy.all(pyfvalues == fvalues)) 451 452 # Then the in-kernel or indexed version. 453 ptvars = condvars.copy() 454 ptvars[colname] = table.colinstances[acolname] 455 ptvars['c_extra'] = table.colinstances['c_extra'] 456 ptvars['c_idxextra'] = table.colinstances['c_idxextra'] 457 try: 458 isidxq = table.will_query_use_indexing(cond, ptvars) 459 # Query twice to trigger possible query result caching. 460 ptrownos = [table.get_where_list(cond, condvars, sort=True, 461 **table_slice) 462 for _ in range(2)] 463 ptfvalues = [ 464 table.read_where(cond, condvars, field=acolname, 465 **table_slice) 466 for _ in range(2) 467 ] 468 except TypeError as te: 469 if self.condNotBoolean_re.search(str(te)): 470 raise SilentlySkipTest("The condition is not boolean.") 471 raise 472 except NotImplementedError: 473 raise SilentlySkipTest( 474 "The PyTables type does not support the operation.") 475 for ptfvals in ptfvalues: # row numbers already sorted 476 ptfvals.sort() 477 vprint("* %d rows selected by PyTables from ``%s``" 478 % (len(ptrownos[0]), acolname), nonl=True) 479 vprint("(indexing: %s)." % ["no", "yes"][bool(isidxq)]) 480 self.assertTrue(numpy.all(ptrownos[0] == rownos)) 481 self.assertTrue(numpy.all(ptfvalues[0] == fvalues)) 482 # The following test possible caching of query results. 483 self.assertTrue(numpy.all(ptrownos[0] == ptrownos[1])) 484 self.assertTrue(numpy.all(ptfvalues[0] == ptfvalues[1])) 485 486 test_method.__doc__ = "Testing ``%s``." % cond 487 return test_method 488 489 490def add_test_method(type_, op, extracond='', func=None): 491 global testn 492 # Decide to which set the test belongs. 493 heavy = type_ in heavy_types or op in heavy_operators 494 if heavy: 495 testfmt = TableDataTestCase._testfmt_heavy 496 numfmt = ' [#H%d]' 497 else: 498 testfmt = TableDataTestCase._testfmt_light 499 numfmt = ' [#L%d]' 500 tmethod = create_test_method(type_, op, extracond, func) 501 # The test number is appended to the docstring to help 502 # identify failing methods in non-verbose mode. 503 tmethod.__name__ = testfmt % testn 504 # tmethod.__doc__ += numfmt % testn 505 tmethod.__doc__ += testfmt % testn 506 setattr(TableDataTestCase, tmethod.__name__, tmethod) 507 testn += 1 508 509# Create individual tests. You may restrict which tests are generated 510# by replacing the sequences in the ``for`` statements. For instance: 511testn = 0 512for type_ in type_info: # for type_ in ['string']: 513 for op in operators: # for op in ['!=']: 514 for extracond in extra_conditions: # for extracond in ['']: 515 add_test_method(type_, op, extracond) 516 517for type_ in ['float32', 'float64']: 518 for func in func_info: # i for func in ['log10']: 519 for op in operators: 520 add_test_method(type_, op, func=func) 521 522# Base classes for non-indexed queries. 523NX_BLOCK_SIZE1 = 128 # from ``interpreter.c`` in Numexpr 524NX_BLOCK_SIZE2 = 8 # from ``interpreter.c`` in Numexpr 525 526 527class SmallNITableMixin: 528 nrows = row_period * 2 529 assert NX_BLOCK_SIZE2 < nrows < NX_BLOCK_SIZE1 530 assert nrows % NX_BLOCK_SIZE2 != 0 # to have some residual rows 531 532 533class BigNITableMixin: 534 nrows = row_period * 3 535 assert nrows > NX_BLOCK_SIZE1 + NX_BLOCK_SIZE2 536 assert nrows % NX_BLOCK_SIZE1 != 0 537 assert nrows % NX_BLOCK_SIZE2 != 0 # to have some residual rows 538 539# Parameters for non-indexed queries. 540table_sizes = ['Small', 'Big'] 541heavy_table_sizes = frozenset(['Big']) 542table_ndims = ['Scalar'] # to enable multidimensional testing, include 'MD' 543 544# Non-indexed queries: ``[SB][SM]TDTestCase``, where: 545# 546# 1. S is for small and B is for big size table. 547# Sizes are listed in `table_sizes`. 548# 2. S is for scalar and M for multidimensional columns. 549# Dimensionalities are listed in `table_ndims`. 550 551 552def niclassdata(): 553 for size in table_sizes: 554 heavy = size in heavy_table_sizes 555 for ndim in table_ndims: 556 classname = '%s%sTDTestCase' % (size[0], ndim[0]) 557 cbasenames = ('%sNITableMixin' % size, '%sTableMixin' % ndim, 558 'TableDataTestCase') 559 classdict = dict(heavy=heavy) 560 yield (classname, cbasenames, classdict) 561 562 563# Base classes for the different type index. 564class UltraLightITableMixin: 565 kind = "ultralight" 566 567 568class LightITableMixin: 569 kind = "light" 570 571 572class MediumITableMixin: 573 kind = "medium" 574 575 576class FullITableMixin: 577 kind = "full" 578 579# Base classes for indexed queries. 580 581 582class SmallSTableMixin: 583 nrows = 50 584 585 586class MediumSTableMixin: 587 nrows = 100 588 589 590class BigSTableMixin: 591 nrows = 500 592 593# Parameters for indexed queries. 594ckinds = ['UltraLight', 'Light', 'Medium', 'Full'] 595itable_sizes = ['Small', 'Medium', 'Big'] 596heavy_itable_sizes = frozenset(['Medium', 'Big']) 597itable_optvalues = [0, 1, 3, 7, 9] 598heavy_itable_optvalues = frozenset([0, 1, 7, 9]) 599 600# Indexed queries: ``[SMB]I[ulmf]O[01379]TDTestCase``, where: 601# 602# 1. S is for small, M for medium and B for big size table. 603# Sizes are listed in `itable_sizes`. 604# 2. U is for 'ultraLight', L for 'light', M for 'medium', F for 'Full' indexes 605# Index types are listed in `ckinds`. 606# 3. 0 to 9 is the desired index optimization level. 607# Optimizations are listed in `itable_optvalues`. 608 609 610def iclassdata(): 611 for ckind in ckinds: 612 for size in itable_sizes: 613 for optlevel in itable_optvalues: 614 heavy = (optlevel in heavy_itable_optvalues 615 or size in heavy_itable_sizes) 616 classname = '%sI%sO%dTDTestCase' % ( 617 size[0], ckind[0], optlevel) 618 cbasenames = ('%sSTableMixin' % size, 619 '%sITableMixin' % ckind, 620 'ScalarTableMixin', 621 'TableDataTestCase') 622 classdict = dict(heavy=heavy, optlevel=optlevel, indexed=True) 623 yield (classname, cbasenames, classdict) 624 625 626# Create test classes. 627for cdatafunc in [niclassdata, iclassdata]: 628 for (cname, cbasenames, cdict) in cdatafunc(): 629 cbases = tuple(eval(cbase) for cbase in cbasenames) 630 class_ = type(cname, cbases, cdict) 631 exec('%s = class_' % cname) 632 633 634# Test cases on query usage 635# ------------------------- 636class BaseTableUsageTestCase(BaseTableQueryTestCase): 637 nrows = row_period 638 639_gvar = None 640"""Use this when a global variable is needed.""" 641 642 643class ScalarTableUsageTestCase(ScalarTableMixin, BaseTableUsageTestCase): 644 """Test case for query usage on scalar tables. 645 646 This also tests for most usage errors and situations. 647 648 """ 649 650 def test_empty_condition(self): 651 """Using an empty condition.""" 652 653 self.assertRaises(SyntaxError, self.table.where, '') 654 655 def test_syntax_error(self): 656 """Using a condition with a syntax error.""" 657 658 self.assertRaises(SyntaxError, self.table.where, 'foo bar') 659 660 def test_unsupported_object(self): 661 """Using a condition with an unsupported object.""" 662 663 self.assertRaises(TypeError, self.table.where, '[]') 664 self.assertRaises(TypeError, self.table.where, 'obj', {'obj': {}}) 665 self.assertRaises(TypeError, self.table.where, 'c_bool < []') 666 667 def test_unsupported_syntax(self): 668 """Using a condition with unsupported syntax.""" 669 670 self.assertRaises(TypeError, self.table.where, 'c_bool[0]') 671 self.assertRaises(TypeError, self.table.where, 'c_bool()') 672 self.assertRaises(NameError, self.table.where, 'c_bool.__init__') 673 674 def test_no_column(self): 675 """Using a condition with no participating columns.""" 676 677 self.assertRaises(ValueError, self.table.where, 'True') 678 679 def test_foreign_column(self): 680 """Using a condition with a column from other table.""" 681 682 table2 = self.h5file.create_table('/', 'other', self.tableDescription) 683 self.assertRaises(ValueError, self.table.where, 684 'c_int32_a + c_int32_b > 0', 685 {'c_int32_a': self.table.cols.c_int32, 686 'c_int32_b': table2.cols.c_int32}) 687 688 def test_unsupported_op(self): 689 """Using a condition with unsupported operations on types.""" 690 691 NIE = NotImplementedError 692 self.assertRaises(NIE, self.table.where, 'c_complex128 > 0j') 693 self.assertRaises(NIE, self.table.where, 'c_string + b"a" > b"abc"') 694 695 def test_not_boolean(self): 696 """Using a non-boolean condition.""" 697 698 self.assertRaises(TypeError, self.table.where, 'c_int32') 699 700 def test_nested_col(self): 701 """Using a condition with nested columns.""" 702 703 self.assertRaises(TypeError, self.table.where, 'c_nested') 704 705 def test_implicit_col(self): 706 """Using implicit column names in conditions.""" 707 708 # If implicit columns didn't work, a ``NameError`` would be raised. 709 self.assertRaises(TypeError, self.table.where, 'c_int32') 710 # If overriding didn't work, no exception would be raised. 711 self.assertRaises(TypeError, self.table.where, 712 'c_bool', {'c_bool': self.table.cols.c_int32}) 713 # External variables do not override implicit columns. 714 715 def where_with_locals(): 716 c_int32 = self.table.cols.c_bool # this wouldn't cause an error 717 self.assertIsNotNone(c_int32) 718 self.table.where('c_int32') 719 self.assertRaises(TypeError, where_with_locals) 720 721 def test_condition_vars(self): 722 """Using condition variables in conditions.""" 723 724 # If condition variables didn't work, a ``NameError`` would be raised. 725 self.assertRaises(NotImplementedError, self.table.where, 726 'c_string > bound', {'bound': 0}) 727 728 def where_with_locals(): 729 bound = 'foo' # this wouldn't cause an error 730 # silence pyflakes warnings 731 self.assertIsInstance(bound, str) 732 self.table.where('c_string > bound', {'bound': 0}) 733 self.assertRaises(NotImplementedError, where_with_locals) 734 735 def where_with_globals(): 736 global _gvar 737 _gvar = 'foo' # this wouldn't cause an error 738 # silence pyflakes warnings 739 self.assertIsInstance(_gvar, str) 740 try: 741 self.table.where('c_string > _gvar', {'_gvar': 0}) 742 finally: 743 del _gvar # to keep global namespace clean 744 self.assertRaises(NotImplementedError, where_with_globals) 745 746 def test_scopes(self): 747 """Looking up different scopes for variables.""" 748 749 # Make sure the variable is not implicit. 750 self.assertRaises(NameError, self.table.where, 'col') 751 752 # First scope: dictionary of condition variables. 753 self.assertRaises(TypeError, self.table.where, 754 'col', {'col': self.table.cols.c_int32}) 755 756 # Second scope: local variables. 757 def where_whith_locals(): 758 col = self.table.cols.c_int32 759 self.assertIsNotNone(col) 760 self.table.where('col') 761 self.assertRaises(TypeError, where_whith_locals) 762 763 # Third scope: global variables. 764 def where_with_globals(): 765 global _gvar 766 _gvar = self.table.cols.c_int32 767 # silence pyflakes warnings 768 self.assertIsNotNone(_gvar) 769 try: 770 self.table.where('_gvar') 771 finally: 772 del _gvar # to keep global namespace clean 773 774 self.assertRaises(TypeError, where_with_globals) 775 776 777class MDTableUsageTestCase(MDTableMixin, BaseTableUsageTestCase): 778 """Test case for query usage on multidimensional tables.""" 779 780 def test(self): 781 """Using a condition on a multidimensional table.""" 782 783 # Easy: queries on multidimensional tables are not implemented yet! 784 self.assertRaises(NotImplementedError, self.table.where, 'c_bool') 785 786 787class IndexedTableUsage(ScalarTableMixin, BaseTableUsageTestCase): 788 """Test case for query usage on indexed tables. 789 790 Indexing could be used in more cases, but it is expected to kick in 791 at least in the cases tested here. 792 793 """ 794 nrows = 50 795 indexed = True 796 797 def setUp(self): 798 super(IndexedTableUsage, self).setUp() 799 self.table.cols.c_bool.create_index(_blocksizes=small_blocksizes) 800 self.table.cols.c_int32.create_index(_blocksizes=small_blocksizes) 801 self.will_query_use_indexing = self.table.will_query_use_indexing 802 self.compileCondition = self.table._compile_condition 803 self.requiredExprVars = self.table._required_expr_vars 804 usable_idxs = set() 805 for expr in self.idx_expr: 806 idxvar = expr[0] 807 if idxvar not in usable_idxs: 808 usable_idxs.add(idxvar) 809 self.usable_idxs = frozenset(usable_idxs) 810 811 def test(self): 812 for condition in self.conditions: 813 c_usable_idxs = self.will_query_use_indexing(condition, {}) 814 self.assertEqual(c_usable_idxs, self.usable_idxs, 815 "\nQuery with condition: ``%s``\n" 816 "Computed usable indexes are: ``%s``\n" 817 "and should be: ``%s``" % 818 (condition, c_usable_idxs, self.usable_idxs)) 819 condvars = self.requiredExprVars(condition, None) 820 compiled = self.compileCondition(condition, condvars) 821 c_idx_expr = compiled.index_expressions 822 self.assertEqual(c_idx_expr, self.idx_expr, 823 "\nWrong index expression in condition:\n``%s``\n" 824 "Compiled index expression is:\n``%s``\n" 825 "and should be:\n``%s``" % 826 (condition, c_idx_expr, self.idx_expr)) 827 c_str_expr = compiled.string_expression 828 self.assertEqual(c_str_expr, self.str_expr, 829 "\nWrong index operations in condition:\n``%s``\n" 830 "Computed index operations are:\n``%s``\n" 831 "and should be:\n``%s``" % 832 (condition, c_str_expr, self.str_expr)) 833 vprint("* Query with condition ``%s`` will use " 834 "variables ``%s`` for indexing." 835 % (condition, compiled.index_variables)) 836 837 838class IndexedTableUsage1(IndexedTableUsage): 839 conditions = [ 840 '(c_int32 > 0)', 841 '(c_int32 > 0) & (c_extra > 0)', 842 '(c_int32 > 0) & ((~c_bool) | (c_extra > 0))', 843 '(c_int32 > 0) & ((c_extra < 3) & (c_extra > 0))', 844 ] 845 idx_expr = [('c_int32', ('gt',), (0,))] 846 str_expr = 'e0' 847 848 849class IndexedTableUsage2(IndexedTableUsage): 850 conditions = [ 851 '(c_int32 > 0) & (c_int32 < 5)', 852 '(c_int32 > 0) & (c_int32 < 5) & (c_extra > 0)', 853 '(c_int32 > 0) & (c_int32 < 5) & ((c_bool == True) | (c_extra > 0))', 854 '(c_int32 > 0) & (c_int32 < 5) & ((c_extra > 0) | (c_bool == True))', 855 ] 856 idx_expr = [('c_int32', ('gt', 'lt'), (0, 5))] 857 str_expr = 'e0' 858 859 860class IndexedTableUsage3(IndexedTableUsage): 861 conditions = [ 862 '(c_bool == True)', 863 '(c_bool == True) & (c_extra > 0)', 864 '(c_extra > 0) & (c_bool == True)', 865 '((c_extra > 0) & (c_extra < 4)) & (c_bool == True)', 866 '(c_bool == True) & ((c_extra > 0) & (c_extra < 4))', 867 ] 868 idx_expr = [('c_bool', ('eq',), (True,))] 869 str_expr = 'e0' 870 871 872class IndexedTableUsage4(IndexedTableUsage): 873 conditions = [ 874 '((c_int32 > 0) & (c_bool == True)) & (c_extra > 0)', 875 '((c_int32 > 0) & (c_bool == True)) & ((c_extra > 0)' + 876 ' & (c_extra < 4))', 877 ] 878 idx_expr = [('c_int32', ('gt',), (0,)), 879 ('c_bool', ('eq',), (True,)), 880 ] 881 str_expr = '(e0 & e1)' 882 883 884class IndexedTableUsage5(IndexedTableUsage): 885 conditions = [ 886 '(c_int32 >= 1) & (c_int32 < 2) & (c_bool == True)', 887 '(c_int32 >= 1) & (c_int32 < 2) & (c_bool == True)' + 888 ' & (c_extra > 0)', 889 ] 890 idx_expr = [('c_int32', ('ge', 'lt'), (1, 2)), 891 ('c_bool', ('eq',), (True,)), 892 ] 893 str_expr = '(e0 & e1)' 894 895 896class IndexedTableUsage6(IndexedTableUsage): 897 conditions = [ 898 '(c_int32 >= 1) & (c_int32 < 2) & (c_int32 > 0) & (c_int32 < 5)', 899 '(c_int32 >= 1) & (c_int32 < 2) & (c_int32 > 0) & (c_int32 < 5)' + 900 ' & (c_extra > 0)', 901 ] 902 idx_expr = [('c_int32', ('ge', 'lt'), (1, 2)), 903 ('c_int32', ('gt',), (0,)), 904 ('c_int32', ('lt',), (5,)), 905 ] 906 str_expr = '((e0 & e1) & e2)' 907 908 909class IndexedTableUsage7(IndexedTableUsage): 910 conditions = [ 911 '(c_int32 >= 1) & (c_int32 < 2) & ((c_int32 > 0) & (c_int32 < 5))', 912 '((c_int32 >= 1) & (c_int32 < 2)) & ((c_int32 > 0) & (c_int32 < 5))', 913 '((c_int32 >= 1) & (c_int32 < 2)) & ((c_int32 > 0) & (c_int32 < 5))' + 914 ' & (c_extra > 0)', 915 ] 916 idx_expr = [('c_int32', ('ge', 'lt'), (1, 2)), 917 ('c_int32', ('gt', 'lt'), (0, 5)), 918 ] 919 str_expr = '(e0 & e1)' 920 921 922class IndexedTableUsage8(IndexedTableUsage): 923 conditions = [ 924 '(c_extra > 0) & ((c_int32 > 0) & (c_int32 < 5))', 925 ] 926 idx_expr = [('c_int32', ('gt', 'lt'), (0, 5)), 927 ] 928 str_expr = 'e0' 929 930 931class IndexedTableUsage9(IndexedTableUsage): 932 conditions = [ 933 '(c_extra > 0) & (c_int32 > 0) & (c_int32 < 5)', 934 '((c_extra > 0) & (c_int32 > 0)) & (c_int32 < 5)', 935 '(c_extra > 0) & (c_int32 > 0) & (c_int32 < 5) & (c_extra > 3)', 936 ] 937 idx_expr = [('c_int32', ('gt',), (0,)), 938 ('c_int32', ('lt',), (5,))] 939 str_expr = '(e0 & e1)' 940 941 942class IndexedTableUsage10(IndexedTableUsage): 943 conditions = [ 944 '(c_int32 < 5) & (c_extra > 0) & (c_bool == True)', 945 '(c_int32 < 5) & (c_extra > 2) & c_bool', 946 '(c_int32 < 5) & (c_bool == True) & (c_extra > 0) & (c_extra < 4)', 947 '(c_int32 < 5) & (c_extra > 0) & (c_bool == True) & (c_extra < 4)', 948 ] 949 idx_expr = [('c_int32', ('lt',), (5,)), 950 ('c_bool', ('eq',), (True,))] 951 str_expr = '(e0 & e1)' 952 953 954class IndexedTableUsage11(IndexedTableUsage): 955 """Complex operations are not eligible for indexing.""" 956 957 conditions = [ 958 'sin(c_int32) > 0', 959 '(c_int32 * 2.4) > 0', 960 '(c_int32 + c_int32) > 0', 961 'c_int32**2 > 0', 962 ] 963 idx_expr = [] 964 str_expr = '' 965 966 967class IndexedTableUsage12(IndexedTableUsage): 968 conditions = [ 969 '~c_bool', 970 '~(c_bool)', 971 '~c_bool & (c_extra > 0)', 972 '~(c_bool) & (c_extra > 0)', 973 ] 974 idx_expr = [('c_bool', ('eq',), (False,))] 975 str_expr = 'e0' 976 977 978class IndexedTableUsage13(IndexedTableUsage): 979 conditions = [ 980 '~(c_bool == True)', 981 '~((c_bool == True))', 982 '~(c_bool == True) & (c_extra > 0)', 983 '~((c_bool == True)) & (c_extra > 0)', 984 ] 985 idx_expr = [('c_bool', ('eq',), (False,))] 986 str_expr = 'e0' 987 988 989class IndexedTableUsage14(IndexedTableUsage): 990 conditions = [ 991 '~(c_int32 > 0)', 992 '~((c_int32 > 0)) & (c_extra > 0)', 993 '~(c_int32 > 0) & ((~c_bool) | (c_extra > 0))', 994 '~(c_int32 > 0) & ((c_extra < 3) & (c_extra > 0))', 995 ] 996 idx_expr = [('c_int32', ('le',), (0,))] 997 str_expr = 'e0' 998 999 1000class IndexedTableUsage15(IndexedTableUsage): 1001 conditions = [ 1002 '(~(c_int32 > 0) | ~c_bool)', 1003 '(~(c_int32 > 0) | ~(c_bool)) & (c_extra > 0)', 1004 '(~(c_int32 > 0) | ~(c_bool == True)) & ((c_extra > 0)' + 1005 ' & (c_extra < 4))', 1006 ] 1007 idx_expr = [('c_int32', ('le',), (0,)), 1008 ('c_bool', ('eq',), (False,)), 1009 ] 1010 str_expr = '(e0 | e1)' 1011 1012 1013class IndexedTableUsage16(IndexedTableUsage): 1014 conditions = [ 1015 '(~(c_int32 > 0) & ~(c_int32 < 2))', 1016 '(~(c_int32 > 0) & ~(c_int32 < 2)) & (c_extra > 0)', 1017 '(~(c_int32 > 0) & ~(c_int32 < 2)) & ((c_extra > 0)' + 1018 ' & (c_extra < 4))', 1019 ] 1020 idx_expr = [('c_int32', ('le',), (0,)), 1021 ('c_int32', ('ge',), (2,)), 1022 ] 1023 str_expr = '(e0 & e1)' 1024 1025 1026class IndexedTableUsage17(IndexedTableUsage): 1027 conditions = [ 1028 '(~(c_int32 > 0) & ~(c_int32 < 2))', 1029 '(~(c_int32 > 0) & ~(c_int32 < 2)) & (c_extra > 0)', 1030 '(~(c_int32 > 0) & ~(c_int32 < 2)) & ((c_extra > 0)' + 1031 ' & (c_extra < 4))', 1032 ] 1033 idx_expr = [('c_int32', ('le',), (0,)), 1034 ('c_int32', ('ge',), (2,)), 1035 ] 1036 str_expr = '(e0 & e1)' 1037 1038# Negations of complex conditions are not supported yet 1039 1040 1041class IndexedTableUsage18(IndexedTableUsage): 1042 conditions = [ 1043 '~((c_int32 > 0) & (c_bool))', 1044 '~((c_int32 > 0) & (c_bool)) & (c_extra > 0)', 1045 '~((c_int32 > 0) & (c_bool)) & ((c_extra > 0)' + 1046 ' & (c_extra < 4))', 1047 ] 1048 idx_expr = [] 1049 str_expr = '' 1050 1051 1052class IndexedTableUsage19(IndexedTableUsage): 1053 conditions = [ 1054 '~((c_int32 > 0) & (c_bool)) & ((c_bool == False)' + 1055 ' & (c_extra < 4))', 1056 ] 1057 idx_expr = [('c_bool', ('eq',), (False,)), 1058 ] 1059 str_expr = 'e0' 1060 1061 1062class IndexedTableUsage20(IndexedTableUsage): 1063 conditions = [ 1064 '((c_int32 > 0) & ~(c_bool))', 1065 '((c_int32 > 0) & ~(c_bool)) & (c_extra > 0)', 1066 '((c_int32 > 0) & ~(c_bool == True)) & ((c_extra > 0) & (c_extra < 4))' 1067 ] 1068 idx_expr = [ 1069 ('c_int32', ('gt',), (0,)), 1070 ('c_bool', ('eq',), (False,)), 1071 ] 1072 str_expr = '(e0 & e1)' 1073 1074 1075class IndexedTableUsage21(IndexedTableUsage): 1076 conditions = [ 1077 '(~(c_int32 > 0) & (c_bool))', 1078 '(~(c_int32 > 0) & (c_bool)) & (c_extra > 0)', 1079 '(~(c_int32 > 0) & (c_bool == True)) & ((c_extra > 0)' + 1080 ' & (c_extra < 4))', 1081 ] 1082 idx_expr = [('c_int32', ('le',), (0,)), 1083 ('c_bool', ('eq',), (True,)), 1084 ] 1085 str_expr = '(e0 & e1)' 1086 1087 1088class IndexedTableUsage22(IndexedTableUsage): 1089 conditions = [ 1090 '~((c_int32 >= 1) & (c_int32 < 2)) & ~(c_bool == True)', 1091 '~(c_bool == True) & (c_extra > 0)', 1092 '~((c_int32 >= 1) & (c_int32 < 2)) & (~(c_bool == True)' + 1093 ' & (c_extra > 0))', 1094 ] 1095 idx_expr = [('c_bool', ('eq',), (False,)), 1096 ] 1097 str_expr = 'e0' 1098 1099 1100class IndexedTableUsage23(IndexedTableUsage): 1101 conditions = [ 1102 'c_int32 != 1', 1103 'c_bool != False', 1104 '~(c_int32 != 1)', 1105 '~(c_bool != False)', 1106 '(c_int32 != 1) & (c_extra != 2)', 1107 ] 1108 idx_expr = [] 1109 str_expr = '' 1110 1111 1112class IndexedTableUsage24(IndexedTableUsage): 1113 conditions = [ 1114 'c_bool', 1115 'c_bool == True', 1116 'True == c_bool', 1117 '~(~c_bool)', 1118 '~~c_bool', 1119 '~~~~c_bool', 1120 '~(~c_bool) & (c_extra != 2)', 1121 ] 1122 idx_expr = [('c_bool', ('eq',), (True,)), 1123 ] 1124 str_expr = 'e0' 1125 1126 1127class IndexedTableUsage25(IndexedTableUsage): 1128 conditions = [ 1129 '~c_bool', 1130 'c_bool == False', 1131 'False == c_bool', 1132 '~(c_bool)', 1133 '~((c_bool))', 1134 '~~~c_bool', 1135 '~~(~c_bool) & (c_extra != 2)', 1136 ] 1137 idx_expr = [ 1138 ('c_bool', ('eq',), (False,)), 1139 ] 1140 str_expr = 'e0' 1141 1142 1143class IndexedTableUsage26(IndexedTableUsage): 1144 conditions = [ 1145 'c_bool != True', 1146 'True != c_bool', 1147 'c_bool != False', 1148 'False != c_bool', 1149 ] 1150 idx_expr = [] 1151 str_expr = '' 1152 1153 1154class IndexedTableUsage27(IndexedTableUsage): 1155 conditions = [ 1156 '(c_int32 == 3) | c_bool | (c_int32 == 5)', 1157 '(((c_int32 == 3) | (c_bool == True)) | (c_int32 == 5))' + 1158 ' & (c_extra > 0)', 1159 ] 1160 idx_expr = [ 1161 ('c_int32', ('eq',), (3,)), 1162 ('c_bool', ('eq',), (True,)), 1163 ('c_int32', ('eq',), (5,)), 1164 ] 1165 str_expr = '((e0 | e1) | e2)' 1166 1167 1168class IndexedTableUsage28(IndexedTableUsage): 1169 conditions = [ 1170 '((c_int32 == 3) | c_bool) & (c_int32 == 5)', 1171 '(((c_int32 == 3) | (c_bool == True)) & (c_int32 == 5))' + 1172 ' & (c_extra > 0)', 1173 ] 1174 idx_expr = [ 1175 ('c_int32', ('eq',), (3,)), 1176 ('c_bool', ('eq',), (True,)), 1177 ('c_int32', ('eq',), (5,)), 1178 ] 1179 str_expr = '((e0 | e1) & e2)' 1180 1181 1182class IndexedTableUsage29(IndexedTableUsage): 1183 conditions = [ 1184 '(c_int32 == 3) | ((c_int32 == 4) & (c_int32 == 5))', 1185 '((c_int32 == 3) | ((c_int32 == 4) & (c_int32 == 5)))' + 1186 ' & (c_extra > 0)', 1187 ] 1188 idx_expr = [ 1189 ('c_int32', ('eq',), (4,)), 1190 ('c_int32', ('eq',), (5,)), 1191 ('c_int32', ('eq',), (3,)), 1192 ] 1193 str_expr = '((e0 & e1) | e2)' 1194 1195 1196class IndexedTableUsage30(IndexedTableUsage): 1197 conditions = [ 1198 '((c_int32 == 3) | (c_int32 == 4)) & (c_int32 == 5)', 1199 '((c_int32 == 3) | (c_int32 == 4)) & (c_int32 == 5)' + 1200 ' & (c_extra > 0)', 1201 ] 1202 idx_expr = [ 1203 ('c_int32', ('eq',), (3,)), 1204 ('c_int32', ('eq',), (4,)), 1205 ('c_int32', ('eq',), (5,)), 1206 ] 1207 str_expr = '((e0 | e1) & e2)' 1208 1209 1210class IndexedTableUsage31(IndexedTableUsage): 1211 conditions = [ 1212 '(c_extra > 0) & ((c_extra < 4) & (c_bool == True))', 1213 '(c_extra > 0) & ((c_bool == True) & (c_extra < 5))', 1214 '((c_int32 > 0) | (c_extra > 0)) & (c_bool == True)', 1215 ] 1216 idx_expr = [ 1217 ('c_bool', ('eq',), (True,)), 1218 ] 1219 str_expr = 'e0' 1220 1221 1222class IndexedTableUsage32(IndexedTableUsage): 1223 conditions = [ 1224 '(c_int32 < 5) & (c_extra > 0) & (c_bool == True) | (c_extra < 4)', 1225 ] 1226 idx_expr = [] 1227 str_expr = '' 1228 1229 1230# Main part 1231# --------- 1232def suite(): 1233 """Return a test suite consisting of all the test cases in the module.""" 1234 1235 testSuite = unittest.TestSuite() 1236 1237 cdatafuncs = [niclassdata] # non-indexing data tests 1238 cdatafuncs.append(iclassdata) # indexing data tests 1239 1240 heavy = common.heavy 1241 # Choose which tests to run in classes with autogenerated tests. 1242 if heavy: 1243 autoprefix = 'test' # all tests 1244 else: 1245 autoprefix = 'test_l' # only light tests 1246 1247 niter = 1 1248 for i in range(niter): 1249 # Tests on query data. 1250 for cdatafunc in cdatafuncs: 1251 for cdata in cdatafunc(): 1252 class_ = eval(cdata[0]) 1253 if heavy or not class_.heavy: 1254 suite_ = unittest.makeSuite(class_, prefix=autoprefix) 1255 testSuite.addTest(suite_) 1256 # Tests on query usage. 1257 testSuite.addTest(unittest.makeSuite(ScalarTableUsageTestCase)) 1258 testSuite.addTest(unittest.makeSuite(MDTableUsageTestCase)) 1259 testSuite.addTest(unittest.makeSuite(IndexedTableUsage1)) 1260 testSuite.addTest(unittest.makeSuite(IndexedTableUsage2)) 1261 testSuite.addTest(unittest.makeSuite(IndexedTableUsage3)) 1262 testSuite.addTest(unittest.makeSuite(IndexedTableUsage4)) 1263 testSuite.addTest(unittest.makeSuite(IndexedTableUsage5)) 1264 testSuite.addTest(unittest.makeSuite(IndexedTableUsage6)) 1265 testSuite.addTest(unittest.makeSuite(IndexedTableUsage7)) 1266 testSuite.addTest(unittest.makeSuite(IndexedTableUsage8)) 1267 testSuite.addTest(unittest.makeSuite(IndexedTableUsage9)) 1268 testSuite.addTest(unittest.makeSuite(IndexedTableUsage10)) 1269 testSuite.addTest(unittest.makeSuite(IndexedTableUsage11)) 1270 testSuite.addTest(unittest.makeSuite(IndexedTableUsage12)) 1271 testSuite.addTest(unittest.makeSuite(IndexedTableUsage13)) 1272 testSuite.addTest(unittest.makeSuite(IndexedTableUsage14)) 1273 testSuite.addTest(unittest.makeSuite(IndexedTableUsage15)) 1274 testSuite.addTest(unittest.makeSuite(IndexedTableUsage16)) 1275 testSuite.addTest(unittest.makeSuite(IndexedTableUsage17)) 1276 testSuite.addTest(unittest.makeSuite(IndexedTableUsage18)) 1277 testSuite.addTest(unittest.makeSuite(IndexedTableUsage19)) 1278 testSuite.addTest(unittest.makeSuite(IndexedTableUsage20)) 1279 testSuite.addTest(unittest.makeSuite(IndexedTableUsage21)) 1280 testSuite.addTest(unittest.makeSuite(IndexedTableUsage22)) 1281 testSuite.addTest(unittest.makeSuite(IndexedTableUsage23)) 1282 testSuite.addTest(unittest.makeSuite(IndexedTableUsage24)) 1283 testSuite.addTest(unittest.makeSuite(IndexedTableUsage25)) 1284 testSuite.addTest(unittest.makeSuite(IndexedTableUsage26)) 1285 testSuite.addTest(unittest.makeSuite(IndexedTableUsage27)) 1286 testSuite.addTest(unittest.makeSuite(IndexedTableUsage28)) 1287 testSuite.addTest(unittest.makeSuite(IndexedTableUsage29)) 1288 testSuite.addTest(unittest.makeSuite(IndexedTableUsage30)) 1289 testSuite.addTest(unittest.makeSuite(IndexedTableUsage31)) 1290 testSuite.addTest(unittest.makeSuite(IndexedTableUsage32)) 1291 1292 return testSuite 1293 1294 1295if __name__ == '__main__': 1296 common.parse_argv(sys.argv) 1297 common.print_versions() 1298 unittest.main(defaultTest='suite') 1299