-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdocsubfile.py
124 lines (106 loc) · 3.66 KB
/
docsubfile.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
from dataclasses import dataclass
import json
from pathlib import Path
import re
from tabulate import tabulate
from typing import Self
from unittest import TestCase
import bracex
from docsub import click
from doctestcase import to_markdown
from importloc import Location, get_subclasses, random_name
@click.group()
def x() -> None:
pass
@x.command()
@click.argument('testpath', type=click.Path(exists=True, dir_okay=False))
@click.argument('nameregex')
def cases(testpath: click.Path, nameregex: str) -> None:
"""
Print usage section based on test case docstrings.
"""
cases = get_subclasses(Location(str(testpath)).load(random_name), TestCase)
cases.sort(key=lambda c: c.__firstlineno__) # type: ignore[attr-defined]
for case in cases:
if re.fullmatch(nameregex, case.__name__):
click.echo(to_markdown(case, include_title=False))
@x.command()
@click.argument('obj', type=str)
def dirtree(obj: str) -> None:
"""
Print directory tree from Dir object.
"""
tree = Location(obj).load(on_conflict='reuse')
tree.print_rich(hide_root=True)
@dataclass
class TestResult:
envname: str # tox env name
frag: tuple[str, ...] # mapping of fragment prefixes to suffixes
marks: set[str] # pass marks
@classmethod
def from_tox_env(
cls,
envdir: Path,
fragment_groups: list[list[str]],
fragment_sep: str = '-',
passmark_prefix: str = '.pass-',
) -> Self | None:
# parse fragments
fragments = set(envdir.name.split(fragment_sep))
if len(fragments) != len(fragment_groups):
return None
frag = []
for g in fragment_groups:
match = fragments & set(g)
if len(match) != 1:
return None
frag.append(match.pop())
# load pass marks
marks = set()
for markfile in envdir.glob(f'{passmark_prefix}*'):
marks.add(markfile.name.removeprefix(passmark_prefix))
#
return cls(envname=envdir.name, frag=tuple(frag), marks=marks)
@x.command()
@click.argument('toxdir', type=click.Path(file_okay=False, path_type=Path))
@click.option('-f', '--fragments', type=str)
@click.option('-i', '--icons', type=str)
def testres(toxdir: Path, fragments: str, icons: str) -> None:
"""
Print matrix of tox test results.
"""
if not toxdir.exists():
raise ValueError('Test results are not available.')
fgroup = [list(reversed(bracex.expand(g))) for g in fragments.split(';')]
if len(fgroup) > 2:
raise ValueError('Maximum 2 fragments are allowed')
markicons = json.loads(icons)
# load results
results: list[TestResult] = []
for toxenv in toxdir.iterdir():
if not toxenv.is_dir():
continue
res = TestResult.from_tox_env(toxenv, fragment_groups=fgroup)
if res is not None:
results.append(res)
# print matrix
failicon = next(iter(markicons.values()))
def result_icon(res: TestResult, default=failicon) -> str | None:
for mark, icon in reversed(markicons.items()):
if mark in res.marks:
return icon
return default
headers = ['', *fgroup[1]]
body = []
for row in fgroup[0]:
res = [r for r in results if r.frag[0] == row]
res.sort(key=lambda r: fgroup[1].index(r.frag[1]))
body.append([row, *(result_icon(r) for r in res)])
table = tabulate(
tabular_data=body,
headers=headers,
tablefmt='github',
colalign=['left'] + ['center'] * len(fgroup[1]),
maxcolwidths=[max(len(c) for c in fgroup[0]) + 2, *(len(c) for c in fgroup[1])],
)
click.echo(table)