Skip to content

Commit e016967

Browse files
committed
feat: main index page links to other index pages
1 parent 3d47c9f commit e016967

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+744
-366
lines changed

coverage/html.py

+138-105
Large diffs are not rendered by default.

coverage/htmlfiles/index.html

+6
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,12 @@ <h1>{{ title|escape }}:
6464
</div>
6565
</form>
6666

67+
<h2>
68+
{% for ibtn in index_buttons %}
69+
<a class="button{% if ibtn.current %} current{% endif %}"{% if ibtn.url %} href="{{ ibtn.url }}"{% endif %}>{{ ibtn.label }}</a>{#-#}
70+
{% endfor %}
71+
</h2>
72+
6773
<p class="text">
6874
<a class="nav" href="{{__url__}}">coverage.py v{{__version__}}</a>,
6975
created at {{ time_stamp }}

coverage/htmlfiles/style.css

+15-1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,18 @@ header .content { padding: 1rem 3.5rem; }
4040

4141
header h2 { margin-top: .5em; font-size: 1em; }
4242

43+
header h2 a.button { font-family: inherit; font-size: inherit; border: 1px solid; border-radius: .2em; background: #eee; color: inherit; text-decoration: none; padding: .1em .5em; margin: 1px calc(.1em + 1px); cursor: pointer; border-color: #ccc; }
44+
45+
@media (prefers-color-scheme: dark) { header h2 a.button { background: #333; } }
46+
47+
@media (prefers-color-scheme: dark) { header h2 a.button { border-color: #444; } }
48+
49+
header h2 a.button.current { border: 2px solid; background: #fff; border-color: #999; cursor: default; }
50+
51+
@media (prefers-color-scheme: dark) { header h2 a.button.current { background: #1e1e1e; } }
52+
53+
@media (prefers-color-scheme: dark) { header h2 a.button.current { border-color: #777; } }
54+
4355
header p.text { margin: .5em 0 -.5em; color: #666; font-style: italic; }
4456

4557
@media (prefers-color-scheme: dark) { header p.text { color: #aaa; } }
@@ -88,7 +100,9 @@ h1 { font-size: 1.25em; display: inline-block; }
88100

89101
@media (prefers-color-scheme: dark) { #filter_container label { color: #aaa; } }
90102

91-
header button { font-family: inherit; font-size: inherit; border: 1px solid; border-radius: .2em; color: inherit; padding: .1em .5em; margin: 1px calc(.1em + 1px); cursor: pointer; border-color: #ccc; }
103+
header button { font-family: inherit; font-size: inherit; border: 1px solid; border-radius: .2em; background: #eee; color: inherit; text-decoration: none; padding: .1em .5em; margin: 1px calc(.1em + 1px); cursor: pointer; border-color: #ccc; }
104+
105+
@media (prefers-color-scheme: dark) { header button { background: #333; } }
92106

93107
@media (prefers-color-scheme: dark) { header button { border-color: #444; } }
94108

coverage/htmlfiles/style.scss

+29-10
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,22 @@ $dark-context-bg-color: #056;
9696
}
9797
}
9898

99+
@mixin button-shape {
100+
font-family: inherit;
101+
font-size: inherit;
102+
border: 1px solid;
103+
border-radius: .2em;
104+
background: $light-gray2;
105+
@include background-dark($dark-gray2);
106+
color: inherit;
107+
text-decoration: none;
108+
padding: .1em .5em;
109+
margin: 1px calc(.1em + 1px);
110+
cursor: pointer;
111+
border-color: $light-gray3;
112+
@include border-color-dark($dark-gray3);
113+
}
114+
99115
// Page-wide styles
100116
html, body, h1, h2, h3, p, table, td, th {
101117
margin: 0;
@@ -177,6 +193,18 @@ header {
177193
h2 {
178194
margin-top: .5em;
179195
font-size: 1em;
196+
197+
a.button {
198+
@include button-shape;
199+
&.current {
200+
border: 2px solid;
201+
background: $light-bg;
202+
@include background-dark($dark-bg);
203+
border-color: $light-gray4;
204+
@include border-color-dark($dark-gray4);
205+
cursor: default;
206+
}
207+
}
180208
}
181209

182210
p.text {
@@ -274,16 +302,7 @@ h1 {
274302
}
275303

276304
header button {
277-
font-family: inherit;
278-
font-size: inherit;
279-
border: 1px solid;
280-
border-radius: .2em;
281-
color: inherit;
282-
padding: .1em .5em;
283-
margin: 1px calc(.1em + 1px);
284-
cursor: pointer;
285-
border-color: $light-gray3;
286-
@include border-color-dark($dark-gray3);
305+
@include button-shape;
287306
@include focus-border;
288307

289308
&.run {

coverage/plugin.py

+9-17
Original file line numberDiff line numberDiff line change
@@ -114,15 +114,16 @@ def coverage_init(reg, options):
114114

115115
from __future__ import annotations
116116

117-
import dataclasses
118117
import functools
119118

120119
from types import FrameType
121120
from typing import Any, Iterable
122121

123122
from coverage import files
124123
from coverage.misc import _needs_to_implement
125-
from coverage.types import TArc, TConfigurable, TLineNo, TSourceTokenLines
124+
from coverage.types import (
125+
CodeRegion, TArc, TConfigurable, TLineNo, TSourceTokenLines,
126+
)
126127

127128

128129
class CoveragePlugin:
@@ -345,19 +346,6 @@ def line_number_range(self, frame: FrameType) -> tuple[TLineNo, TLineNo]:
345346
return lineno, lineno
346347

347348

348-
@dataclasses.dataclass
349-
class CodeRegion:
350-
"""Data for each region found by FileReporter.code_regions.
351-
352-
`name`: the description of the regions.
353-
`start`: the first line of the named region.
354-
`lines`: a super-set of the executable source lines in the region.
355-
"""
356-
name: str
357-
start: int
358-
lines: set[int]
359-
360-
361349
@functools.total_ordering
362350
class FileReporter(CoveragePluginBase):
363351
"""Support needed for files during the analysis and reporting phases.
@@ -557,9 +545,13 @@ def source_token_lines(self) -> TSourceTokenLines:
557545
for line in self.source().splitlines():
558546
yield [("txt", line)]
559547

560-
def code_regions(self) -> dict[str, list[CodeRegion]]:
548+
def code_regions(self) -> Iterable[CodeRegion]:
561549
"""TODO XXX"""
562-
return {}
550+
return []
551+
552+
def code_region_kinds(self) -> Iterable[tuple[str, str]]:
553+
"""TODO XXX"""
554+
return []
563555

564556
def __eq__(self, other: Any) -> bool:
565557
return isinstance(other, FileReporter) and self.filename == other.filename

coverage/python.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -253,5 +253,11 @@ def should_be_python(self) -> bool:
253253
def source_token_lines(self) -> TSourceTokenLines:
254254
return source_token_lines(self.source())
255255

256-
def code_regions(self) -> dict[str, list[CodeRegion]]:
256+
def code_regions(self) -> Iterable[CodeRegion]:
257257
return code_regions(self.source())
258+
259+
def code_region_kinds(self) -> Iterable[tuple[str, str]]:
260+
return [
261+
("function", "functions"),
262+
("class", "classes"),
263+
]

coverage/regions.py

+19-10
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
from typing import cast
1212

13-
from coverage.plugin import CodeRegion
13+
from coverage.types import CodeRegion
1414

1515

1616
@dataclasses.dataclass
@@ -29,10 +29,7 @@ class RegionFinder(ast.NodeVisitor):
2929
3030
"""
3131
def __init__(self) -> None:
32-
self.regions: dict[str, list[CodeRegion]] = {
33-
"function": [],
34-
"class": [],
35-
}
32+
self.regions: list[CodeRegion] = []
3633
self.context: list[Context] = []
3734

3835
def parse_source(self, source: str) -> None:
@@ -55,8 +52,13 @@ def visit_FunctionDef(self, node: ast.FunctionDef) -> None:
5552
ancestor.lines -= lines
5653
break
5754
self.context.append(Context(node.name, "function", lines))
58-
self.regions["function"].append(
59-
CodeRegion(name=self.fq_node_name(), start=node.lineno, lines=lines)
55+
self.regions.append(
56+
CodeRegion(
57+
kind="function",
58+
name=self.fq_node_name(),
59+
start=node.lineno,
60+
lines=lines,
61+
)
6062
)
6163
self.generic_visit(node)
6264
self.context.pop()
@@ -70,8 +72,13 @@ def visit_ClassDef(self, node: ast.ClassDef) -> None:
7072
# finds.
7173
lines: set[int] = set()
7274
self.context.append(Context(node.name, "class", lines))
73-
self.regions["class"].append(
74-
CodeRegion(name=self.fq_node_name(), start=node.lineno, lines=lines)
75+
self.regions.append(
76+
CodeRegion(
77+
kind="class",
78+
name=self.fq_node_name(),
79+
start=node.lineno,
80+
lines=lines,
81+
)
7582
)
7683
self.generic_visit(node)
7784
self.context.pop()
@@ -81,9 +88,11 @@ def visit_ClassDef(self, node: ast.ClassDef) -> None:
8188
ancestor.lines -= lines
8289

8390

84-
def code_regions(source: str) -> dict[str, list[CodeRegion]]:
91+
def code_regions(source: str) -> list[CodeRegion]:
8592
"""Find function and class regions in source code.
8693
94+
TODO: Fix this description.
95+
8796
Takes the program `source`, and returns a dict: the keys are "function" and
8897
"class". Each has a value which is a dict: the keys are fully qualified
8998
names, the values are sets of line numbers included in that region::

coverage/types.py

+23
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
from __future__ import annotations
99

10+
import dataclasses
1011
import os
1112
import pathlib
1213

@@ -161,6 +162,28 @@ def get_plugin_options(self, plugin: str) -> TConfigSectionOut:
161162

162163
TSourceTokenLines = Iterable[List[Tuple[str, str]]]
163164

165+
166+
@dataclasses.dataclass
167+
class CodeRegion:
168+
"""Data for each region found by FileReporter.code_regions.
169+
170+
`kind`: the kind of region.
171+
`name`: the description of the region.
172+
`start`: the first line of the named region.
173+
`lines`: a super-set of the executable source lines in the region.
174+
"""
175+
kind: str
176+
name: str
177+
start: int
178+
lines: set[int]
179+
180+
def __lt__(self, other: CodeRegion) -> bool:
181+
"""To support sorting to make test-writing easier."""
182+
if self.name == other.name:
183+
return min(self.lines) < min(other.lines)
184+
return self.name < other.name
185+
186+
164187
## Plugins
165188

166189
class TPlugin(Protocol):

tests/gold/html/a/class_index.html

+9-4
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,14 @@ <h1>Coverage report:
4848
<label for="hide100">hide covered</label>
4949
</div>
5050
</form>
51+
<h2>
52+
<a class="button" href="index.html">Files</a>
53+
<a class="button" href="function_index.html">Functions</a>
54+
<a class="button current">Classes</a>
55+
</h2>
5156
<p class="text">
5257
<a class="nav" href="https://coverage.readthedocs.io/en/7.5.0a1.dev1">coverage.py v7.5.0a1.dev1</a>,
53-
created at 2024-04-19 13:27 -0400
58+
created at 2024-04-21 10:14 -0400
5459
</p>
5560
</div>
5661
</header>
@@ -95,12 +100,12 @@ <h1>Coverage report:
95100
<div class="content">
96101
<p>
97102
<a class="nav" href="https://coverage.readthedocs.io/en/7.5.0a1.dev1">coverage.py v7.5.0a1.dev1</a>,
98-
created at 2024-04-19 13:27 -0400
103+
created at 2024-04-21 10:14 -0400
99104
</p>
100105
</div>
101106
<aside class="hidden">
102-
<a id="prevFileLink" class="nav" href="index.html"/>
103-
<a id="nextFileLink" class="nav" href="index.html"/>
107+
<a id="prevFileLink" class="nav" href=""></a>
108+
<a id="nextFileLink" class="nav" href=""></a>
104109
<button type="button" class="button_prev_file" data-shortcut="["/>
105110
<button type="button" class="button_next_file" data-shortcut="]"/>
106111
<button type="button" class="button_show_hide_help" data-shortcut="?"/>

tests/gold/html/a/function_index.html

+9-4
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,14 @@ <h1>Coverage report:
4848
<label for="hide100">hide covered</label>
4949
</div>
5050
</form>
51+
<h2>
52+
<a class="button" href="index.html">Files</a>
53+
<a class="button current">Functions</a>
54+
<a class="button" href="class_index.html">Classes</a>
55+
</h2>
5156
<p class="text">
5257
<a class="nav" href="https://coverage.readthedocs.io/en/7.5.0a1.dev1">coverage.py v7.5.0a1.dev1</a>,
53-
created at 2024-04-19 13:27 -0400
58+
created at 2024-04-21 10:14 -0400
5459
</p>
5560
</div>
5661
</header>
@@ -95,12 +100,12 @@ <h1>Coverage report:
95100
<div class="content">
96101
<p>
97102
<a class="nav" href="https://coverage.readthedocs.io/en/7.5.0a1.dev1">coverage.py v7.5.0a1.dev1</a>,
98-
created at 2024-04-19 13:27 -0400
103+
created at 2024-04-21 10:14 -0400
99104
</p>
100105
</div>
101106
<aside class="hidden">
102-
<a id="prevFileLink" class="nav" href="index.html"/>
103-
<a id="nextFileLink" class="nav" href="index.html"/>
107+
<a id="prevFileLink" class="nav" href=""></a>
108+
<a id="nextFileLink" class="nav" href=""></a>
104109
<button type="button" class="button_prev_file" data-shortcut="["/>
105110
<button type="button" class="button_next_file" data-shortcut="]"/>
106111
<button type="button" class="button_show_hide_help" data-shortcut="?"/>

tests/gold/html/a/index.html

+9-4
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,14 @@ <h1>Coverage report:
4747
<label for="hide100">hide covered</label>
4848
</div>
4949
</form>
50+
<h2>
51+
<a class="button current">Files</a>
52+
<a class="button" href="function_index.html">Functions</a>
53+
<a class="button" href="class_index.html">Classes</a>
54+
</h2>
5055
<p class="text">
5156
<a class="nav" href="https://coverage.readthedocs.io/en/7.5.0a1.dev1">coverage.py v7.5.0a1.dev1</a>,
52-
created at 2024-04-19 13:27 -0400
57+
created at 2024-04-21 10:14 -0400
5358
</p>
5459
</div>
5560
</header>
@@ -91,12 +96,12 @@ <h1>Coverage report:
9196
<div class="content">
9297
<p>
9398
<a class="nav" href="https://coverage.readthedocs.io/en/7.5.0a1.dev1">coverage.py v7.5.0a1.dev1</a>,
94-
created at 2024-04-19 13:27 -0400
99+
created at 2024-04-21 10:14 -0400
95100
</p>
96101
</div>
97102
<aside class="hidden">
98-
<a id="prevFileLink" class="nav" href="a_py.html"/>
99-
<a id="nextFileLink" class="nav" href="a_py.html"/>
103+
<a id="prevFileLink" class="nav" href="a_py.html"></a>
104+
<a id="nextFileLink" class="nav" href="a_py.html"></a>
100105
<button type="button" class="button_prev_file" data-shortcut="["/>
101106
<button type="button" class="button_next_file" data-shortcut="]"/>
102107
<button type="button" class="button_show_hide_help" data-shortcut="?"/>

0 commit comments

Comments
 (0)