Skip to content

Commit f3d14c7

Browse files
committed
Merge the Report._files/_chunks
Instead of maintaining two separate fields, this merges the previous `_files` which was a dict from filename to `totals`, and the `_chunks` which was either a fully parsed `ReportFile`, or just a shallow `list` of lines. Maintaining only a single structure for the list of files makes a ton of internals of the `Report` simpler. It also solves the problem of `file_totals` getting out of sync with the `ReportFile.totals`.
1 parent d6735e6 commit f3d14c7

12 files changed

+192
-970
lines changed

shared/reports/carryforward.py

+10-14
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
import re
33
from typing import Mapping, Sequence
44

5-
from shared.reports.editable import EditableReport
65
from shared.reports.resources import Report
76
from shared.utils.match import Matcher
87
from shared.utils.sessions import SessionType
@@ -36,7 +35,7 @@ def generate_carryforward_report(
3635
flags: Sequence[str],
3736
paths: Sequence[str],
3837
session_extras: Mapping[str, str] | None = None,
39-
) -> EditableReport:
38+
) -> Report:
4039
"""
4140
Generates a carriedforward report starting from report `report`, flags `flags`
4241
and paths `paths`
@@ -66,19 +65,16 @@ def generate_carryforward_report(
6665
Returns:
6766
EditableReport: A new report with only the info related to `flags` on it, as described above
6867
"""
69-
new_report = EditableReport(
70-
chunks=report._chunks,
71-
files=report._files,
72-
sessions=report.sessions,
73-
totals=None,
74-
)
7568
if paths:
7669
matcher = Matcher(paths)
77-
for filename in new_report.files:
78-
if not matcher.match(filename):
79-
del new_report[filename]
70+
files_to_delete = {
71+
filename for filename in report._files.keys() if not matcher.match(filename)
72+
}
73+
for filename in files_to_delete:
74+
del report[filename]
75+
8076
sessions_to_delete = []
81-
for sid, session in new_report.sessions.items():
77+
for sid, session in report.sessions.items():
8278
if not contain_any_of_the_flags(flags, session.flags):
8379
sessions_to_delete.append(int(sid))
8480
else:
@@ -89,8 +85,8 @@ def generate_carryforward_report(
8985
"Removing sessions that are not supposed to carryforward",
9086
extra=dict(deleted_sessions=sessions_to_delete),
9187
)
92-
new_report.delete_multiple_sessions(sessions_to_delete)
93-
return new_report
88+
report.delete_multiple_sessions(sessions_to_delete)
89+
return report
9490

9591

9692
def contain_any_of_the_flags(expected_flags, actual_flags):

shared/reports/readonly.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,7 @@ def from_chunks(cls, files=None, sessions=None, totals=None, chunks=None):
6565
)
6666
totals = inner_report._totals
6767
filename_mapping = {
68-
filename: file_summary.file_index
69-
for (filename, file_summary) in inner_report._files.items()
68+
filename: idx for idx, filename in enumerate(inner_report._files.keys())
7069
}
7170
session_mapping = {
7271
sid: (session.flags or []) for sid, session in inner_report.sessions.items()

shared/reports/reportfile.py

+22-11
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,20 @@
1313
log = logging.getLogger(__name__)
1414

1515

16-
class ReportFile(object):
16+
class ReportFile:
17+
name: str
18+
_totals: ReportTotals | None
19+
diff_totals: ReportTotals | None
20+
_lines: list[None | str | ReportLine]
21+
_details: dict[str, Any]
22+
__present_sessions: set[int] | None
23+
1724
def __init__(
1825
self,
1926
name: str,
2027
totals: ReportTotals | list | None = None,
2128
lines: list[None | str | ReportLine] | str | None = None,
29+
diff_totals: ReportTotals | list | None = None,
2230
ignore=None,
2331
):
2432
"""
@@ -32,18 +40,20 @@ def __init__(
3240
{eof:N, lines:[1,10]}
3341
"""
3442
self.name = name
35-
self._details: dict[str, Any] = {}
43+
self._totals = None
44+
self.diff_totals = None
45+
self._lines = []
46+
self._details = {}
47+
self.__present_sessions = None
3648

37-
# lines = [<details dict()>, <Line #1>, ....]
38-
self._lines: list[None | str | ReportLine] = []
3949
if lines:
4050
if isinstance(lines, list):
4151
self._lines = lines
4252

4353
else:
4454
lines = lines.splitlines()
4555
if detailsline := lines.pop(0):
46-
self._details = orjson.loads(detailsline) or {}
56+
self._details = orjson.loads(detailsline or b"null") or {}
4757
self._lines = lines
4858

4959
self._ignore = _ignore_to_func(ignore) if ignore else None
@@ -54,18 +64,22 @@ def __init__(
5464
# All mutating methods (like `append`, `merge`, etc) will either re-calculate these values
5565
# directly, or clear them so the `@property` accessors re-calculate them when needed.
5666

57-
self._totals: ReportTotals | None = None
5867
if isinstance(totals, ReportTotals):
5968
self._totals = totals
6069
elif totals:
6170
self._totals = ReportTotals(*totals)
6271

63-
self.__present_sessions: set[int] | None = None
72+
if isinstance(diff_totals, ReportTotals):
73+
self.diff_totals = diff_totals
74+
elif diff_totals:
75+
self.diff_totals = ReportTotals(*diff_totals)
76+
6477
if present_sessions := self._details.get("present_sessions"):
6578
self.__present_sessions = set(present_sessions)
6679

6780
def _invalidate_caches(self):
6881
self._totals = None
82+
self.diff_totals = None
6983
self.__present_sessions = None
7084

7185
@property
@@ -84,12 +98,9 @@ def details(self):
8498
@property
8599
def totals(self):
86100
if not self._totals:
87-
self._totals = self._process_totals()
101+
self._totals = get_line_totals(line for _ln, line in self.lines)
88102
return self._totals
89103

90-
def _process_totals(self) -> ReportTotals:
91-
return get_line_totals(line for _ln, line in self.lines)
92-
93104
def __repr__(self):
94105
try:
95106
return "<%s name=%s lines=%s>" % (

0 commit comments

Comments
 (0)