github.com/tiagovtristao/plz@v13.4.0+incompatible/tools/please_pex/unittest.py (about) 1 import os 2 import sys 3 import unittest 4 from importlib import import_module 5 6 7 def list_classes(suite): 8 for test in suite: 9 if isinstance(test, unittest.suite.TestSuite): 10 for cls, name in list_classes(test): 11 yield cls, name 12 else: 13 yield test, test.__class__.__module__ + '.' + test.id() 14 15 16 def get_suite(test_names, raise_on_empty=False): 17 """ 18 Get the test suite to run the test 19 20 :param test_names: Name of the tests to be filtered 21 :param raise_on_empty: raise Exception if result filtered is empty 22 23 :return: unittest.suite.TestSuite 24 """ 25 suite = unittest.TestSuite(unittest.defaultTestLoader.loadTestsFromModule(module) 26 for module in import_tests()) 27 # Filter to test name only, this ensures the extra flags does not get swallowed 28 test_names = list(filter(lambda x: not x.startswith('-'), test_names)) 29 30 # filter results if test_names is not empty 31 if test_names: 32 new_suite = unittest.suite.TestSuite() 33 for name in test_names: 34 new_suite.addTests(cls for cls, class_name in list_classes(suite) 35 if name in class_name) 36 if raise_on_empty and suite.countTestCases() == 0: 37 raise Exception('No matching tests found') 38 39 return new_suite 40 41 return suite 42 43 44 def import_tests(): 45 """Yields the set of test modules, from file if necessary.""" 46 # We have files available locally, but there may (likely) also be python files in the same 47 # Python package within the pex. We can't just import them because the parent package exists 48 # in only one of those places (this is similar to importing generated code from plz-out/gen). 49 for filename in TEST_NAMES: 50 pkg_name, _ = os.path.splitext(filename.replace('/', '.')) 51 try: 52 yield import_module(pkg_name) 53 except ImportError: 54 with open(filename, 'r') as f: 55 if PY_VERSION < 3: 56 mod = imp.load_module(pkg_name, f, filename, ('.py', 'r', imp.PY_SOURCE)) 57 else: 58 mod = machinery.SourceFileLoader(pkg_name, filename).load_module() 59 60 # Have to set the attribute on the parent module too otherwise some things 61 # can't find it. 62 parent, _, mod_name = pkg_name.rpartition('.') 63 if parent and parent in sys.modules: 64 setattr(sys.modules[parent], mod_name, mod) 65 yield mod 66 67 68 def run_tests(test_names): 69 """Runs tests using unittest, returns the number of failures.""" 70 # N.B. import must be deferred until we have set up import paths. 71 import xmlrunner 72 suite = get_suite(test_names, raise_on_empty=True) 73 74 runner = xmlrunner.XMLTestRunner(output='test.results', outsuffix='') 75 results = runner.run(suite) 76 return len(results.errors) + len(results.failures)