Skip to content
This repository was archived by the owner on Jun 13, 2025. It is now read-only.

Commit 0f4aea1

Browse files
committed
Do not double-filter Reports in ReportPaths
Previously, the `ReportPaths.files` accessor would manually filter through the `unfiltered_report`. Even though the `self.report` was already filtered. Now the custom filtering logic is a bit updated, but taking care of existing bugs in `FilteredReport`, as that is still yielding files even though they are not matching any `flags`.
1 parent de5e284 commit 0f4aea1

File tree

2 files changed

+50
-51
lines changed

2 files changed

+50
-51
lines changed

graphql_api/tests/test_branch.py

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -772,18 +772,15 @@ def test_fetch_path_contents_component_filter_missing_coverage(
772772
@patch("services.components.component_filtered_report")
773773
@patch("services.components.commit_components")
774774
@patch("shared.reports.api_report_service.build_report_from_commit")
775+
@patch("services.path.ReportPaths.files", new_callable=PropertyMock)
775776
def test_fetch_path_contents_component_filter_has_coverage(
776-
self, report_mock, commit_components_mock, filtered_mock
777+
self, files_mock, report_mock, commit_components_mock, filtered_mock
777778
):
778-
components = ["Global"]
779-
variables = {
780-
"org": self.org.username,
781-
"repo": self.repo.name,
782-
"branch": self.branch.name,
783-
"path": "",
784-
"filters": {"components": components},
785-
}
786-
779+
files_mock.return_value = [
780+
"folder/fileB.py",
781+
"folder/subfolder/fileC.py",
782+
"folder/subfolder/fileD.py",
783+
]
787784
report_mock.return_value = MockReport()
788785
commit_components_mock.return_value = [
789786
Component.from_dict(
@@ -810,6 +807,14 @@ def test_fetch_path_contents_component_filter_has_coverage(
810807
]
811808
filtered_mock.return_value = MockReport()
812809

810+
components = ["Global"]
811+
variables = {
812+
"org": self.org.username,
813+
"repo": self.repo.name,
814+
"branch": self.branch.name,
815+
"path": "",
816+
"filters": {"components": components},
817+
}
813818
data = self.gql_request(query_files, variables=variables)
814819

815820
assert data == {
@@ -841,18 +846,15 @@ def test_fetch_path_contents_component_filter_has_coverage(
841846
@patch("services.components.component_filtered_report")
842847
@patch("services.components.commit_components")
843848
@patch("shared.reports.api_report_service.build_report_from_commit")
844-
@patch("services.report.files_belonging_to_flags")
845-
@patch("services.report.files_in_sessions")
849+
@patch("services.path.ReportPaths.files", new_callable=PropertyMock)
846850
def test_fetch_path_contents_component_and_flag_filters(
847851
self,
848-
session_files_mock,
849-
flag_files_mock,
852+
files_mock,
850853
report_mock,
851854
commit_components_mock,
852855
filtered_mock,
853856
):
854-
session_files_mock.return_value = ["fileA.py"]
855-
flag_files_mock.return_value = ["fileA.py"]
857+
files_mock.return_value = ["fileA.py"]
856858
report_mock.return_value = MockReport()
857859
commit_components_mock.return_value = [
858860
Component.from_dict(
@@ -945,11 +947,11 @@ def test_fetch_path_contents_component_and_flag_filters(
945947
@patch("services.components.component_filtered_report")
946948
@patch("services.components.commit_components")
947949
@patch("shared.reports.api_report_service.build_report_from_commit")
948-
@patch("services.report.files_belonging_to_flags")
950+
@patch("services.path.ReportPaths.files", new_callable=PropertyMock)
949951
def test_fetch_path_contents_component_and_flag_filters_unknown_flags(
950-
self, flag_files_mock, report_mock, commit_components_mock, filtered_mock
952+
self, files_mock, report_mock, commit_components_mock, filtered_mock
951953
):
952-
flag_files_mock.return_value = ["fileA.py"]
954+
files_mock.return_value = ["fileA.py"]
953955
report_mock.return_value = MockNoFlagsReport()
954956
commit_components_mock.return_value = [
955957
Component.from_dict(
@@ -1035,18 +1037,15 @@ def test_fetch_path_contents_component_and_flag_filters_unknown_flags(
10351037
@patch("services.components.component_filtered_report")
10361038
@patch("services.components.commit_components")
10371039
@patch("shared.reports.api_report_service.build_report_from_commit")
1038-
@patch("services.report.files_belonging_to_flags")
1039-
@patch("services.report.files_in_sessions")
1040+
@patch("services.path.ReportPaths.files", new_callable=PropertyMock)
10401041
def test_fetch_path_contents_component_flags_filters(
10411042
self,
1042-
session_files_mock,
1043-
flag_files_mock,
1043+
files_mock,
10441044
report_mock,
10451045
commit_components_mock,
10461046
filtered_mock,
10471047
):
1048-
session_files_mock.return_value = ["fileA.py"]
1049-
flag_files_mock.return_value = ["fileA.py"]
1048+
files_mock.return_value = ["fileA.py"]
10501049
report_mock.return_value = MockReport()
10511050
commit_components_mock.return_value = [
10521051
Component.from_dict(

services/path.py

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from asgiref.sync import async_to_sync
1010
from django.conf import settings
1111
from shared.reports.resources import Report
12+
from shared.reports.filtered import FilteredReport, FilteredReportFile
1213
from shared.reports.types import ReportTotals
1314
from shared.torngit.exceptions import TorngitClientError
1415
from shared.utils.match import Matcher
@@ -150,13 +151,12 @@ def __init__(
150151
report: Report,
151152
path: str | None = None,
152153
search_term: str | None = None,
153-
filter_flags: list[str] = [],
154-
filter_paths: list[str] = [],
154+
filter_flags: list[str] = None,
155+
filter_paths: list[str] = None,
155156
):
156-
self.report = report
157-
self.unfiltered_report = report
158-
self.filter_flags = filter_flags
159-
self.filter_paths = filter_paths
157+
self.report: Report | FilteredReport = report
158+
self.filter_flags = filter_flags or []
159+
self.filter_paths = filter_paths or []
160160
self.prefix = path or ""
161161

162162
# Filter report if flags or paths exist
@@ -172,37 +172,37 @@ def __init__(
172172
]
173173

174174
if search_term:
175+
search_term = search_term.lower()
175176
self._paths = [
176177
path
177-
for path in self.paths
178-
if search_term.lower() in path.relative_path.lower()
178+
for path in self._paths
179+
if search_term in path.relative_path.lower()
179180
]
180181

181182
@cached_property
182183
def files(self) -> list[str]:
183-
# No filtering, just return files in Report
184-
if not self.filter_flags and not self.filter_paths:
184+
# No flags filtering, just return (path-filtered) files in Report
185+
if not self.filter_flags:
185186
return self.report.files
186187

188+
# When there is a flag filter, `FilteredReport` currently yields
189+
# `FilteredReportFile`s without actually checking whether they match the sessions.
190+
# Before that bug is fixed, lets do the filtering manually here. Once that bug is fixed,
191+
# this should just forward to `self.report.files` like above.
187192
files = []
188-
# Do flag filtering if needed
189-
if self.filter_flags:
190-
files = report_service.files_belonging_to_flags(
191-
commit_report=self.unfiltered_report, flags=self.filter_flags
192-
)
193-
else:
194-
files = [file.name for file in self.unfiltered_report]
195-
196-
# Do path filtering if needed
197-
if self.filter_paths:
198-
matcher = Matcher(self.filter_paths)
199-
files = [file for file in files if matcher.match(file)]
200-
193+
for file in self.report:
194+
if isinstance(file, FilteredReportFile):
195+
found = False
196+
for _ln, line in file.lines:
197+
if line and any(s.id in file.session_ids for s in line.sessions):
198+
found = True
199+
break
200+
if not found:
201+
continue
202+
203+
files.append(file.name)
201204
return files
202205

203-
def _filter_commit_report(self) -> None:
204-
self.report = self.report.filter(flags=self.filter_flags)
205-
206206
@property
207207
def paths(self) -> list[PrefixedPath]:
208208
return self._paths

0 commit comments

Comments
 (0)