47 lines
		
	
	
		
			1.7 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			47 lines
		
	
	
		
			1.7 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
|   | import itertools | ||
|  | import sys | ||
|  | from typing import Any, Callable, Iterable | ||
|  | 
 | ||
|  | 
 | ||
|  | def classvar_matrix(**kwargs: Iterable[Any]) -> Callable[[type], None]: | ||
|  |     """
 | ||
|  |     Create a new class for each variation of input, allowing to generate a TestCase matrix / parametrization that | ||
|  |     supports multi-threading and has better reporting for ``unittest --durations=...`` and ``pytest --durations=...`` | ||
|  |     than subtests. | ||
|  | 
 | ||
|  |     The kwargs will be set as ClassVars in the newly created classes. Use as :: | ||
|  | 
 | ||
|  |         @classvar_matrix(var_name=[value1, value2]) | ||
|  |         class MyTestCase(unittest.TestCase): | ||
|  |             var_name: typing.ClassVar[...] | ||
|  | 
 | ||
|  |     :param kwargs: A dict of ClassVars to set, where key is the variable name and value is a list of all values. | ||
|  |     :return: A decorator to be applied to a class. | ||
|  |     """
 | ||
|  |     keys: tuple[str] | ||
|  |     values: Iterable[Iterable[Any]] | ||
|  |     keys, values = zip(*kwargs.items()) | ||
|  |     values = map(lambda v: sorted(v) if isinstance(v, (set, frozenset)) else v, values) | ||
|  |     permutations_dicts = [dict(zip(keys, v)) for v in itertools.product(*values)] | ||
|  | 
 | ||
|  |     def decorator(cls: type) -> None: | ||
|  |         mod = sys.modules[cls.__module__] | ||
|  | 
 | ||
|  |         for permutation in permutations_dicts: | ||
|  | 
 | ||
|  |             class Unrolled(cls):  # type: ignore | ||
|  |                 pass | ||
|  | 
 | ||
|  |             for k, v in permutation.items(): | ||
|  |                 setattr(Unrolled, k, v) | ||
|  |             params = ", ".join([f"{k}={repr(v)}" for k, v in permutation.items()]) | ||
|  |             params = f"{{{params}}}" | ||
|  | 
 | ||
|  |             Unrolled.__module__ = cls.__module__ | ||
|  |             Unrolled.__qualname__ = f"{cls.__qualname__}{params}" | ||
|  |             setattr(mod, f"{cls.__name__}{params}", Unrolled) | ||
|  | 
 | ||
|  |         return None | ||
|  | 
 | ||
|  |     return decorator |