from __future__ import print_function import os import re import sys import time import signal import traceback import warnings import __res from __res import importer def setup_test_environment(): try: from yatest_lib.ya import Ya import yatest.common as yc yc.runtime._set_ya_config(ya=Ya()) except ImportError: pass def check_imports(no_check=(), extra=(), skip_func=None, py_main=None): """ tests all bundled modules are importable just add "PEERDIR(library/python/import_test)" to your CMakeLists.txt and "from import_test import test_imports" to your python test source file. """ if not isinstance(b'', str): def str_(s): return s.decode('UTF-8') else: def str_(s): return s exceptions = list(no_check) for key, _ in __res.iter_keys(b'py/no_check_imports/'): exceptions += str_(__res.find(key)).split() if exceptions: exceptions.sort() print('NO_CHECK_IMPORTS', ' '.join(exceptions)) # all test modules get imported when tests are run exceptions.append('__tests__.*') patterns = [re.escape(s).replace(r'\*', r'.*') for s in exceptions] rx = re.compile('^({})$'.format('|'.join(patterns))) failed = [] import_times = {} def norm(s): return s[:-9] if s.endswith('.__init__') else s modules = sys.extra_modules | set(extra) modules = sorted(modules, key=norm) if py_main: modules = [py_main] + modules for module in modules: if module not in extra and (rx.search(module) or skip_func and skip_func(module)): print('SKIP', module) continue name = module.rsplit('.', 1)[-1] if name == '__main__' and 'if __name__ ==' not in importer.get_source(module): print('SKIP', module, '''without "if __name__ == '__main__'" check''') continue def print_backtrace_marked(e): tb_exc = traceback.format_exception(*e) for item in tb_exc: for line in item.splitlines(): print('FAIL:', line, file=sys.stderr) try: print('TRY', module) # XXX waiting for py3 to use print(..., flush=True) sys.stdout.flush() s = time.time() with warnings.catch_warnings(): warnings.filterwarnings(action="ignore", category=DeprecationWarning) if module == '__main__': importer.load_module('__main__', '__main__py') elif module.endswith('.__init__'): __import__(module[: -len('.__init__')]) else: __import__(module) delay = time.time() - s import_times[str(module)] = delay print('OK ', module, '{:.3f}s'.format(delay)) except Exception as e: print('FAIL:', module, e, file=sys.stderr) print_backtrace_marked(sys.exc_info()) failed.append('{}: {}'.format(module, e)) except BaseException: e = sys.exc_info() print('FAIL:', module, e, file=sys.stderr) print_backtrace_marked(e) failed.append('{}: {}'.format(module, e)) raise print("Slowest imports:") for m, t in sorted(import_times.items(), key=lambda x: x[1], reverse=True)[:30]: print(' ', '{:.3f}s'.format(t), m) if failed: raise ImportError('modules not imported:\n' + '\n'.join(failed)) test_imports = check_imports def main(): setup_test_environment() skip_names = sys.argv[1:] # SIGUSR2 is used by test_tool to teardown tests if hasattr(signal, "SIGUSR2"): # Dump python import tracing import library.python.import_tracing.lib.regulator as regulator # get the original handler to return control to it after dumping signum = signal.SIGUSR2 orig_handler = signal.getsignal(signum) if not hasattr(signal, 'raise_signal'): # Only available for Python 3.8+ def raise_signal(signum): os.kill(os.getpid(), signum) else: raise_signal = signal.raise_signal def stop_tracing_handler(s, f): regulator.disable(close_not_finished=True) signal.signal(signal.SIGUSR2, orig_handler) raise_signal(signum) signal.signal(signal.SIGUSR2, stop_tracing_handler) try: import faulthandler except ImportError: faulthandler = None if faulthandler: # Dump python backtrace in case of any errors faulthandler.enable() if hasattr(signal, "SIGUSR2"): # SIGUSR2 is used by test_tool to teardown tests faulthandler.register(signal.SIGUSR2, chain=True) os.environ['Y_PYTHON_IMPORT_TEST'] = '' # We should initialize Django before importing any applications if os.getenv('DJANGO_SETTINGS_MODULE'): try: import django except ImportError: pass else: django.setup() py_main = __res.find('PY_MAIN') if py_main: py_main_module = py_main.split(b':', 1)[0].decode('UTF-8') else: py_main_module = None try: check_imports(no_check=skip_names, py_main=py_main_module) except Exception: sys.exit(1)