-
Notifications
You must be signed in to change notification settings - Fork 30
[uss_qualifier/reports] Typing fixes #1385
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -110,6 +110,7 @@ def generate_globally_expanded_report( | |
|
|
||
| """ | ||
|
|
||
| assert report.configuration.v1 and report.configuration.v1.test_run | ||
| resource_pool = make_resources_config(report.configuration.v1.test_run) | ||
|
|
||
| def indented_ul(value) -> list[str]: | ||
|
|
@@ -184,6 +185,7 @@ def describe_pool_resource(k: str, v: dict) -> str: | |
|
|
||
| def _generate_sections(node: ActionNode) -> Iterator[_Section]: | ||
| if node.node_type == ActionNodeType.Scenario: | ||
| assert node.scenario | ||
| yield _generate_scenario_section(node.scenario) | ||
| elif node.node_type == ActionNodeType.SkippedAction: | ||
| yield _generate_skipped_scenario_section(node) | ||
|
|
@@ -195,7 +197,7 @@ def _generate_sections(node: ActionNode) -> Iterator[_Section]: | |
| def _generate_skipped_scenario_section(node: ActionNode) -> _Section: | ||
| return _Section( | ||
| title=f"[skipped] {node.name}", | ||
| body=f"This instance of this test scenario was skipped in this test run because: {node.skipped_action.reason}", | ||
| body=f"This instance of this test scenario was skipped in this test run because: {node.skipped_action.reason if node.skipped_action else '?'}", | ||
| ) | ||
|
|
||
|
|
||
|
|
@@ -237,15 +239,15 @@ def _indent_headings(elements: Sequence[marko.element.Element], levels: int) -> | |
| for element in elements: | ||
| if isinstance(element, marko.block.Heading): | ||
| element.level = min(element.level + levels, 6) | ||
| if hasattr(element, "children") and element.children: | ||
| _indent_headings(element.children, levels) | ||
| if children := getattr(element, "children", None): | ||
| _indent_headings(children, levels) | ||
|
|
||
|
|
||
| def _inflate_fragments(parent: marko.element.Element, origin_filename: str) -> None: | ||
| if hasattr(parent, "children") and parent.children: | ||
| if hasattr(parent, "children") and parent.children: # pyright: ignore[reportAttributeAccessIssue] | ||
BenjaminPelletier marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| c = 0 | ||
| while c < len(parent.children): | ||
| child = parent.children[c] | ||
| while c < len(parent.children): # pyright: ignore[reportAttributeAccessIssue] | ||
| child = parent.children[c] # pyright: ignore[reportAttributeAccessIssue] | ||
| if ( | ||
| isinstance(child, marko.block.Heading) | ||
| and hasattr(child, "children") | ||
|
|
@@ -260,12 +262,12 @@ def _inflate_fragments(parent: marko.element.Element, origin_filename: str) -> N | |
| doc = _get_test_step_fragment(absolute_path, child.level) | ||
| _update_links(doc, absolute_path) | ||
| _strip_link(child) | ||
| parent.children = ( | ||
| parent.children[0 : c + 1] + doc.children + parent.children[c + 1 :] | ||
| parent.children = ( # pyright: ignore[reportAttributeAccessIssue] | ||
| parent.children[0 : c + 1] + doc.children + parent.children[c + 1 :] # pyright: ignore[reportAttributeAccessIssue] | ||
| ) | ||
| c += len(doc.children) | ||
| elif isinstance(child, marko.element.Element): | ||
| _inflate_fragments(parent.children[c], origin_filename) | ||
| _inflate_fragments(parent.children[c], origin_filename) # pyright: ignore[reportAttributeAccessIssue] | ||
| c += 1 | ||
| else: | ||
| c += 1 | ||
|
|
@@ -286,14 +288,14 @@ def add_resource_origin(): | |
| note = marko.parse( | ||
| """∅ _This resource was not applicable to this test run and was therefore not provided._\n\n""" | ||
| ) | ||
| doc.children = doc.children[0:c] + note.children + doc.children[c:] | ||
| doc.children = doc.children[0:c] + note.children + doc.children[c:] # pyright: ignore[reportAttributeAccessIssue,reportOperatorIssue] | ||
| c += len(note.children) | ||
| return | ||
| # Insert resource origin information | ||
| origin = marko.parse( | ||
| f"\n\n✅ Provided by {scenario.resource_origins[current_resource]}.\n" | ||
| ) | ||
| doc.children = doc.children[0:c] + origin.children + doc.children[c:] | ||
| doc.children = doc.children[0:c] + origin.children + doc.children[c:] # pyright: ignore[reportOperatorIssue] | ||
| c += len(origin.children) | ||
|
|
||
| while c < len(doc.children): | ||
|
|
@@ -327,11 +329,11 @@ def add_resource_origin(): | |
|
|
||
|
|
||
| def _strip_link(element: marko.element.Element) -> None: | ||
| if hasattr(element, "children") and element.children: | ||
| for c in range(len(element.children)): | ||
| child = element.children[c] | ||
| if hasattr(element, "children") and element.children: # pyright: ignore[reportAttributeAccessIssue] | ||
| for c in range(len(element.children)): # pyright: ignore[reportAttributeAccessIssue] | ||
| child = element.children[c] # pyright: ignore[reportAttributeAccessIssue] | ||
| if isinstance(child, marko.block.inline.Link): | ||
| element.children[c] = child.children[0] | ||
| element.children[c] = child.children[0] # pyright: ignore[reportAttributeAccessIssue] | ||
| elif isinstance(child, marko.element.Element): | ||
| _strip_link(child) | ||
|
|
||
|
|
@@ -372,7 +374,7 @@ def add_context_to_case(): | |
| """∅ _This test case was not applicable to this test run and is therefore not statused._\n\n""" | ||
| ) | ||
| doc.children = ( | ||
| doc.children[0 : test_case_i0 + 1] | ||
| doc.children[0 : test_case_i0 + 1] # pyright: ignore[reportAttributeAccessIssue,reportOperatorIssue] | ||
| + note.children | ||
| + doc.children[test_case_i0 + 1 :] | ||
| ) | ||
|
|
@@ -396,6 +398,7 @@ def add_context_to_case(): | |
| for epoch in scenario.epochs: | ||
| if epoch.type != EpochType.Case: | ||
| continue | ||
| assert epoch.case | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The for epoch in scenario.epochs:
if not epoch.case:
continue
if case_name == ...
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I do agree we have it a lot and we should switch to use the fields directly, but this there is one catch: is it safe, through the code base so assume those fields uniquely define the thing we should do? Or in others words, is only one of (
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
That's the intent in these places -- basically equivalent to class Epoch(ImplicitDict):
# === OneOf: Only one of these properties may be specified ===
case: Optional[TestedCase] = None
events: Optional[list[Event]] = None
# === End OneOf ===The giveaway that this is the case when looking at existing code is something that implies only one may be set; e.g.: @property
def type(self) -> EpochType:
if self.case:
return EpochType.Case
elif self.events:
return EpochType.Events
else:
raise ValueError("Invalid Epoch did not specify case or events") |
||
| if case_name == epoch.case.name: | ||
| test_case = epoch.case | ||
| break | ||
|
|
@@ -409,6 +412,7 @@ def add_context_to_case(): | |
| for epoch in scenario.epochs: | ||
| if epoch.type != EpochType.Case: | ||
| continue | ||
| assert epoch.case | ||
| if len(epoch.case.steps) == 1 and epoch.case.steps[0].name == "Cleanup": | ||
| test_case = epoch.case | ||
| break | ||
|
|
@@ -444,7 +448,7 @@ def add_context_to_step(): | |
| ) | ||
| dc = len(note.children) | ||
| doc.children = ( | ||
| doc.children[0 : test_step_i0 + 1] | ||
| doc.children[0 : test_step_i0 + 1] # pyright: ignore[reportOperatorIssue] | ||
| + note.children | ||
| + doc.children[test_step_i0 + 1 :] | ||
| ) | ||
|
|
@@ -494,6 +498,7 @@ def _add_context_to_step( | |
| def add_context_to_check(): | ||
| nonlocal c, i1, added, test_check_name, test_check_i0, test_check_level | ||
| if test_check_name is not None: | ||
| assert test_check_i0 is not None | ||
| dc = _add_context_to_check(doc, step, test_check_name, test_check_i0, c) | ||
| c += dc | ||
| i1 += dc | ||
|
|
@@ -534,13 +539,15 @@ def _add_context_to_check( | |
| for event in step.events: | ||
| if ( | ||
| event.type == EventType.PassedCheck | ||
| and event.passed_check is not None | ||
| and event.passed_check.name == test_check_name | ||
| ): | ||
| check_text.append( | ||
| f"✅ {', '.join(event.passed_check.participants)} ({event.passed_check.timestamp})" | ||
| ) | ||
| elif ( | ||
| event.type == EventType.FailedCheck | ||
| and event.failed_check | ||
| and event.failed_check.name == test_check_name | ||
| ): | ||
| check_text.append( | ||
|
|
@@ -552,7 +559,7 @@ def _add_context_to_check( | |
| additions = marko.parse( | ||
| """∅ _This check was not applicable to this test run and is therefore not statused._\n\n""" | ||
| ) | ||
| doc.children = doc.children[0:i1] + additions.children + doc.children[i1:] | ||
| doc.children = doc.children[0:i1] + additions.children + doc.children[i1:] # pyright: ignore[reportOperatorIssue] | ||
| return len(additions.children) | ||
|
|
||
|
|
||
|
|
@@ -571,16 +578,16 @@ def _update_links(element: marko.element.Element, origin_filename: str) -> None: | |
| url = url.replace("/github.com/", "/raw.githubusercontent.com/") | ||
| url = url.replace("/blob/", "/") | ||
| element.dest = url | ||
| if hasattr(element, "children") and element.children: | ||
| for child in element.children: | ||
| if hasattr(element, "children") and element.children: # pyright: ignore[reportAttributeAccessIssue] | ||
| for child in element.children: # pyright: ignore[reportAttributeAccessIssue] | ||
| if isinstance(child, marko.element.Element): | ||
| _update_links(child, origin_filename) | ||
|
|
||
|
|
||
| def _add_section_numbers(elements: Sequence[marko.element.Element]) -> None: | ||
| heading_level = 2 | ||
| levels = [0] | ||
| headings = [None] | ||
| headings: list[str | None] = [None] | ||
| prev_heading = None | ||
| for i, element in enumerate(elements): | ||
| if isinstance(element, marko.block.Heading): | ||
|
|
@@ -599,7 +606,7 @@ def _add_section_numbers(elements: Sequence[marko.element.Element]) -> None: | |
| heading_level += 1 | ||
| else: | ||
| headings.append(text_of(element)) | ||
| heading_trace = " -> ".join(headings) | ||
| heading_trace = " -> ".join([str(heading) for heading in headings]) | ||
| raise ValueError( | ||
| f"Encountered a level {element.level} heading ({text_of(element)}) at element {i} following a level {heading_level} heading ({prev_heading}); expected heading levels to increase by 1 level at a time. Trace: {heading_trace}" | ||
| ) | ||
|
|
@@ -612,4 +619,4 @@ def _add_section_numbers(elements: Sequence[marko.element.Element]) -> None: | |
| else: | ||
| element.children = [ | ||
| marko.block.inline.RawText(section_number) | ||
| ] + element.children | ||
| ] + element.children # pyright: ignore[reportOperatorIssue] | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem with the approach is that IDEs don't generally seem to find fields by
getattrstring-literal usage. So, if someone was looking at the fieldchildrenin the type of object thatelementis, they would find an instance of that field's usage with the previous approach, but they wouldn't find an instance of that field's usage with this change.I'm not strongly against changing between two equally-valid approaches if basedpyright prefers one of them (although that is still a use of limited and valuable dev time that could be applied elsewhere), but we certainly shouldn't let basedpyright cause us to switch from an approach with more advantages to an approach with less advantages.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unlike the comment below, I think we do want to keep the original here to expose the use of the
childrenattribute to IDEs. So, I think#pyright: ignoreis appropriate here instead.