They've deprecated a bunch of API but the suggested replacement is either not present in versions of python that are not EOLed or doesn't actually work.
115 lines
4.2 KiB
Python
115 lines
4.2 KiB
Python
#!/usr/bin/env python
|
|
# License: GPLv3 Copyright: 2021, Kovid Goyal <kovid at kovidgoyal.net>
|
|
|
|
import importlib
|
|
import os
|
|
import shutil
|
|
import sys
|
|
import unittest
|
|
from typing import Callable, Generator, Iterator, NoReturn, Sequence, Set
|
|
|
|
|
|
def contents(package: str) -> Iterator[str]:
|
|
try:
|
|
if sys.version_info[:2] < (3, 10):
|
|
raise ImportError('importlib.resources.files() doesnt work with frozen builds on python 3.9')
|
|
from importlib.resources import files
|
|
except ImportError:
|
|
from importlib.resources import contents
|
|
return iter(contents(package))
|
|
return (path.name for path in files(package).iterdir())
|
|
|
|
|
|
def itertests(suite: unittest.TestSuite) -> Generator[unittest.TestCase, None, None]:
|
|
stack = [suite]
|
|
while stack:
|
|
suite = stack.pop()
|
|
for test in suite:
|
|
if isinstance(test, unittest.TestSuite):
|
|
stack.append(test)
|
|
continue
|
|
if test.__class__.__name__ == 'ModuleImportFailure':
|
|
raise Exception('Failed to import a test module: %s' % test)
|
|
yield test
|
|
|
|
|
|
def find_all_tests(package: str = '', excludes: Sequence[str] = ('main', 'gr')) -> unittest.TestSuite:
|
|
suits = []
|
|
if not package:
|
|
package = __name__.rpartition('.')[0] if '.' in __name__ else 'kitty_tests'
|
|
for x in contents(package):
|
|
name, ext = os.path.splitext(x)
|
|
if ext in ('.py', '.pyc') and name not in excludes:
|
|
m = importlib.import_module(package + '.' + x.partition('.')[0])
|
|
suits.append(unittest.defaultTestLoader.loadTestsFromModule(m))
|
|
return unittest.TestSuite(suits)
|
|
|
|
|
|
def filter_tests(suite: unittest.TestSuite, test_ok: Callable[[unittest.TestCase], bool]) -> unittest.TestSuite:
|
|
ans = unittest.TestSuite()
|
|
added: Set[unittest.TestCase] = set()
|
|
for test in itertests(suite):
|
|
if test_ok(test) and test not in added:
|
|
ans.addTest(test)
|
|
added.add(test)
|
|
return ans
|
|
|
|
|
|
def filter_tests_by_name(suite: unittest.TestSuite, *names: str) -> unittest.TestSuite:
|
|
names_ = {x if x.startswith('test_') else 'test_' + x for x in names}
|
|
|
|
def q(test: unittest.TestCase) -> bool:
|
|
return test._testMethodName in names_
|
|
return filter_tests(suite, q)
|
|
|
|
|
|
def filter_tests_by_module(suite: unittest.TestSuite, *names: str) -> unittest.TestSuite:
|
|
names_ = frozenset(names)
|
|
|
|
def q(test: unittest.TestCase) -> bool:
|
|
m = test.__class__.__module__.rpartition('.')[-1]
|
|
return m in names_
|
|
return filter_tests(suite, q)
|
|
|
|
|
|
def type_check() -> NoReturn:
|
|
from kitty.cli_stub import generate_stub # type:ignore
|
|
generate_stub()
|
|
from kittens.tui.operations_stub import generate_stub # type: ignore
|
|
generate_stub()
|
|
py = os.environ.get('PYTHON_FOR_TYPE_CHECK') or shutil.which('python') or shutil.which('python3')
|
|
os.execlp(py, py, '-m', 'mypy', '--pretty')
|
|
|
|
|
|
def run_cli(suite: unittest.TestSuite, verbosity: int = 4) -> None:
|
|
r = unittest.TextTestRunner
|
|
r.resultclass = unittest.TextTestResult
|
|
runner = r(verbosity=verbosity)
|
|
runner.tb_locals = True # type: ignore
|
|
result = runner.run(suite)
|
|
if not result.wasSuccessful():
|
|
raise SystemExit(1)
|
|
|
|
|
|
def run_tests() -> None:
|
|
import argparse
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument(
|
|
'name', nargs='*', default=[],
|
|
help='The name of the test to run, for e.g. linebuf corresponds to test_linebuf. Can be specified multiple times')
|
|
parser.add_argument('--verbosity', default=4, type=int, help='Test verbosity')
|
|
parser.add_argument('--module', default='', help='Name of a test module to restrict to. For example: ssh')
|
|
args = parser.parse_args()
|
|
if args.name and args.name[0] in ('type-check', 'type_check', 'mypy'):
|
|
type_check()
|
|
tests = find_all_tests()
|
|
if args.module:
|
|
tests = filter_tests_by_module(tests, args.module)
|
|
if not tests._tests:
|
|
raise SystemExit('No test module named %s found' % args.module)
|
|
if args.name:
|
|
tests = filter_tests_by_name(tests, *args.name)
|
|
if not tests._tests:
|
|
raise SystemExit('No test named %s found' % args.name)
|
|
run_cli(tests, args.verbosity)
|