fix(tui): resolve lint and AmbiguousStep errors in TuiMaterializer
CI / load-versions (push) Successful in 16s
CI / push-validation (push) Successful in 28s
CI / build (push) Successful in 33s
CI / lint (push) Successful in 50s
CI / typecheck (push) Successful in 1m0s
CI / quality (push) Successful in 1m8s
CI / security (push) Successful in 1m17s
CI / helm (push) Successful in 39s
CI / unit_tests (push) Successful in 6m53s
CI / docker (push) Successful in 1m55s
CI / integration_tests (push) Successful in 10m43s
CI / coverage (push) Successful in 13m43s
CI / status-check (push) Successful in 3s
CI / load-versions (pull_request) Successful in 13s
CI / push-validation (pull_request) Successful in 34s
CI / lint (pull_request) Successful in 48s
CI / quality (pull_request) Successful in 54s
CI / typecheck (pull_request) Successful in 59s
CI / security (pull_request) Successful in 1m12s
CI / build (pull_request) Successful in 51s
CI / helm (pull_request) Successful in 58s
CI / unit_tests (pull_request) Successful in 6m37s
CI / integration_tests (pull_request) Successful in 10m35s
CI / benchmark-publish (push) Has been cancelled
CI / benchmark-regression (push) Has been cancelled
CI / docker (pull_request) Failing after 13m18s
CI / coverage (pull_request) Failing after 28m20s
CI / status-check (pull_request) Has been cancelled

- Fix ruff format violations: collapse list comprehension in
  materializer.py, collapse function signature, collapse decorators
  and assertion in tui_materializer_steps.py, remove trailing
  whitespace in vulture_whitelist.py
- Remove duplicate Behave step definitions from tui_materializer_steps.py
  that conflicted with output_rendering_steps.py and
  project_commands_coverage_steps.py: create status handle,
  create code handle, close panel handle, close status handle,
  no error should be raised
- Rename render_element_for_tui step texts to avoid conflict with
  tui_first_run_steps.py: rendered text should contain/be empty ->
  render output should contain/be empty
- Update tui_materializer.feature to use renamed step texts and
  replace no error should be raised with materializer still running

ISSUES CLOSED: #11164
This commit was merged in pull request #11164.
This commit is contained in:
2026-06-11 13:42:30 -04:00
committed by Forgejo
parent 10b9fb941f
commit 5e71221f61
4 changed files with 34 additions and 73 deletions
+6 -39
View File
@@ -130,11 +130,6 @@ def step_call_on_session_begin(context: Any) -> None:
context.materializer.on_session_begin(None) # type: ignore[arg-type] context.materializer.on_session_begin(None) # type: ignore[arg-type]
@then("no error should be raised")
def step_no_error_raised(context: Any) -> None:
pass # If we got here, no exception was raised
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# OutputSession integration # OutputSession integration
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
@@ -157,21 +152,11 @@ def step_create_table_handle(context: Any, title: str) -> None:
context.table_handle = context.session.table(title) context.table_handle = context.session.table(title)
@when('I create a status handle with message "{message}"')
def step_create_status_handle(context: Any, message: str) -> None:
context.status_handle = context.session.status(message)
@when('I create a progress handle with label "{label}"') @when('I create a progress handle with label "{label}"')
def step_create_progress_handle(context: Any, label: str) -> None: def step_create_progress_handle(context: Any, label: str) -> None:
context.progress_handle = context.session.progress(label, indeterminate=True) context.progress_handle = context.session.progress(label, indeterminate=True)
@when('I create a code handle with content "{content}" and language "{language}"')
def step_create_code_handle(context: Any, content: str, language: str) -> None:
context.code_handle = context.session.code(content, language=language)
@when("I create a separator handle") @when("I create a separator handle")
def step_create_separator_handle(context: Any) -> None: def step_create_separator_handle(context: Any) -> None:
context.separator_handle = context.session.separator() context.separator_handle = context.session.separator()
@@ -182,16 +167,6 @@ def step_create_action_hint_handle(context: Any, command: str) -> None:
context.action_hint_handle = context.session.action_hint([command]) context.action_hint_handle = context.session.action_hint([command])
@when("I close the panel handle")
def step_close_panel_handle(context: Any) -> None:
context.panel_handle.close()
@when("I close the status handle")
def step_close_status_handle(context: Any) -> None:
context.status_handle.close()
@when("I close the session") @when("I close the session")
def step_close_session(context: Any) -> None: def step_close_session(context: Any) -> None:
context.session.close() context.session.close()
@@ -363,9 +338,7 @@ def step_render_tree_element(context: Any, root: str, child: str) -> None:
context.rendered_text = render_element_for_tui(element) context.rendered_text = render_element_for_tui(element)
@when( @when('I render a CodeBlock element with language "{language}" and content "{content}"')
'I render a CodeBlock element with language "{language}" and content "{content}"'
)
def step_render_code_element(context: Any, language: str, content: str) -> None: def step_render_code_element(context: Any, language: str, content: str) -> None:
from cleveragents.cli.output.handles._models import CodeBlock from cleveragents.cli.output.handles._models import CodeBlock
from cleveragents.tui.materializer import render_element_for_tui from cleveragents.tui.materializer import render_element_for_tui
@@ -374,9 +347,7 @@ def step_render_code_element(context: Any, language: str, content: str) -> None:
context.rendered_text = render_element_for_tui(element) context.rendered_text = render_element_for_tui(element)
@when( @when('I render a DiffBlock element with file_a "{file_a}" and file_b "{file_b}"')
'I render a DiffBlock element with file_a "{file_a}" and file_b "{file_b}"'
)
def step_render_diff_element(context: Any, file_a: str, file_b: str) -> None: def step_render_diff_element(context: Any, file_a: str, file_b: str) -> None:
from cleveragents.cli.output.handles._models import DiffBlock from cleveragents.cli.output.handles._models import DiffBlock
from cleveragents.tui.materializer import render_element_for_tui from cleveragents.tui.materializer import render_element_for_tui
@@ -423,14 +394,14 @@ def step_render_text_element_with_indent(
context.rendered_text = render_element_for_tui(element) context.rendered_text = render_element_for_tui(element)
@then('the rendered text should contain "{text}"') @then('the render output should contain "{text}"')
def step_check_rendered_text_contains(context: Any, text: str) -> None: def step_check_rendered_text_contains(context: Any, text: str) -> None:
assert text in context.rendered_text, ( assert text in context.rendered_text, (
f"Expected {text!r} in rendered_text={context.rendered_text!r}" f"Expected {text!r} in rendered_text={context.rendered_text!r}"
) )
@then("the rendered text should be empty") @then("the render output should be empty")
def step_check_rendered_text_empty(context: Any) -> None: def step_check_rendered_text_empty(context: Any) -> None:
assert context.rendered_text == "", ( assert context.rendered_text == "", (
f"Expected empty rendered_text, got: {context.rendered_text!r}" f"Expected empty rendered_text, got: {context.rendered_text!r}"
@@ -442,9 +413,7 @@ def step_check_rendered_text_empty(context: Any) -> None:
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
@when( @when('I route a permission request for "{file_path}" with type "{request_type}"')
'I route a permission request for "{file_path}" with type "{request_type}"'
)
def step_route_permission_request( def step_route_permission_request(
context: Any, file_path: str, request_type: str context: Any, file_path: str, request_type: str
) -> None: ) -> None:
@@ -537,9 +506,7 @@ def step_create_multiple_status_handles_concurrently(context: Any) -> None:
@then("all events should be recorded without data corruption") @then("all events should be recorded without data corruption")
def step_check_thread_safety(context: Any) -> None: def step_check_thread_safety(context: Any) -> None:
assert context.thread_errors == [], ( assert context.thread_errors == [], f"Thread errors: {context.thread_errors}"
f"Thread errors: {context.thread_errors}"
)
events = context.materializer.events events = context.materializer.events
# We should have at least 10 element_created + 10 element_closed events # We should have at least 10 element_created + 10 element_closed events
created = [e for e in events if e.event_type == "element_created"] created = [e for e in events if e.event_type == "element_created"]
+25 -25
View File
@@ -31,7 +31,7 @@ Feature: TUI Materializer
Scenario: TuiMaterializer implements on_session_begin Scenario: TuiMaterializer implements on_session_begin
When I create a TuiMaterializer without a callback When I create a TuiMaterializer without a callback
And I call on_session_begin with a mock session And I call on_session_begin with a mock session
Then no error should be raised Then the materializer should still be running
Scenario: TuiMaterializer emits element_created event for panel Scenario: TuiMaterializer emits element_created event for panel
When I create a TuiMaterializer without a callback When I create a TuiMaterializer without a callback
@@ -141,72 +141,72 @@ Feature: TUI Materializer
Scenario: render_element_for_tui renders Panel with title and entries Scenario: render_element_for_tui renders Panel with title and entries
When I render a Panel element with title "Info" and entry "key" "value" When I render a Panel element with title "Info" and entry "key" "value"
Then the rendered text should contain "Info" Then the render output should contain "Info"
And the rendered text should contain "key" And the render output should contain "key"
And the rendered text should contain "value" And the render output should contain "value"
Scenario: render_element_for_tui renders Table with columns and rows Scenario: render_element_for_tui renders Table with columns and rows
When I render a Table element with title "Data" and column "Name" When I render a Table element with title "Data" and column "Name"
Then the rendered text should contain "Data" Then the render output should contain "Data"
And the rendered text should contain "Name" And the render output should contain "Name"
Scenario: render_element_for_tui renders StatusMessage ok level Scenario: render_element_for_tui renders StatusMessage ok level
When I render a StatusMessage element with level "ok" and message "Success" When I render a StatusMessage element with level "ok" and message "Success"
Then the rendered text should contain "ok" Then the render output should contain "ok"
And the rendered text should contain "Success" And the render output should contain "Success"
Scenario: render_element_for_tui renders StatusMessage error level Scenario: render_element_for_tui renders StatusMessage error level
When I render a StatusMessage element with level "error" and message "Failed" When I render a StatusMessage element with level "error" and message "Failed"
Then the rendered text should contain "error" Then the render output should contain "error"
And the rendered text should contain "Failed" And the render output should contain "Failed"
Scenario: render_element_for_tui renders indeterminate ProgressIndicator Scenario: render_element_for_tui renders indeterminate ProgressIndicator
When I render an indeterminate ProgressIndicator with label "Thinking" When I render an indeterminate ProgressIndicator with label "Thinking"
Then the rendered text should contain "Thinking" Then the render output should contain "Thinking"
Scenario: render_element_for_tui renders determinate ProgressIndicator Scenario: render_element_for_tui renders determinate ProgressIndicator
When I render a determinate ProgressIndicator with label "Loading" current 5 total 10 When I render a determinate ProgressIndicator with label "Loading" current 5 total 10
Then the rendered text should contain "Loading" Then the render output should contain "Loading"
And the rendered text should contain "50%" And the render output should contain "50%"
Scenario: render_element_for_tui renders Tree with root and children Scenario: render_element_for_tui renders Tree with root and children
When I render a Tree element with root "root" and child "child1" When I render a Tree element with root "root" and child "child1"
Then the rendered text should contain "root" Then the render output should contain "root"
And the rendered text should contain "child1" And the render output should contain "child1"
Scenario: render_element_for_tui renders CodeBlock with language Scenario: render_element_for_tui renders CodeBlock with language
When I render a CodeBlock element with language "python" and content "x = 1" When I render a CodeBlock element with language "python" and content "x = 1"
Then the rendered text should contain "python" Then the render output should contain "python"
And the rendered text should contain "x = 1" And the render output should contain "x = 1"
Scenario: render_element_for_tui renders DiffBlock with hunks Scenario: render_element_for_tui renders DiffBlock with hunks
When I render a DiffBlock element with file_a "old.py" and file_b "new.py" When I render a DiffBlock element with file_a "old.py" and file_b "new.py"
Then the rendered text should contain "old.py" Then the render output should contain "old.py"
And the rendered text should contain "new.py" And the render output should contain "new.py"
Scenario: render_element_for_tui renders Separator line style Scenario: render_element_for_tui renders Separator line style
When I render a Separator element with style "line" When I render a Separator element with style "line"
Then the rendered text should contain "-" Then the render output should contain "-"
Scenario: render_element_for_tui renders Separator blank style Scenario: render_element_for_tui renders Separator blank style
When I render a Separator element with style "blank" When I render a Separator element with style "blank"
Then the rendered text should be empty Then the render output should be empty
Scenario: render_element_for_tui renders Separator double style Scenario: render_element_for_tui renders Separator double style
When I render a Separator element with style "double" When I render a Separator element with style "double"
Then the rendered text should contain "=" Then the render output should contain "="
Scenario: render_element_for_tui renders ActionHint with commands Scenario: render_element_for_tui renders ActionHint with commands
When I render an ActionHint element with command "agents plan list" When I render an ActionHint element with command "agents plan list"
Then the rendered text should contain "agents plan list" Then the render output should contain "agents plan list"
Scenario: render_element_for_tui renders TextBlock content Scenario: render_element_for_tui renders TextBlock content
When I render a TextBlock element with content "Hello world" When I render a TextBlock element with content "Hello world"
Then the rendered text should contain "Hello world" Then the render output should contain "Hello world"
Scenario: render_element_for_tui renders TextBlock with indent Scenario: render_element_for_tui renders TextBlock with indent
When I render a TextBlock element with content "indented" and indent 4 When I render a TextBlock element with content "indented" and indent 4
Then the rendered text should contain " indented" Then the render output should contain " indented"
# ── A2A event routing ───────────────────────────────────────────────────── # ── A2A event routing ─────────────────────────────────────────────────────
+2 -8
View File
@@ -139,11 +139,7 @@ class TuiMaterializer:
Useful for testing and headless inspection. Useful for testing and headless inspection.
""" """
with self._lock: with self._lock:
parts = [ parts = [text for _, text in sorted(self._rendered.items()) if text]
text
for _, text in sorted(self._rendered.items())
if text
]
return "\n\n".join(parts) return "\n\n".join(parts)
# ------------------------------------------------------------------ # ------------------------------------------------------------------
@@ -269,9 +265,7 @@ class TuiMaterializer:
self._emit(tui_event) self._emit(tui_event)
return tui_event return tui_event
def route_thought_block( def route_thought_block(self, thought: ThoughtBlock) -> TuiWidgetEvent:
self, thought: ThoughtBlock
) -> TuiWidgetEvent:
"""Route a thought block event to the TUI. """Route a thought block event to the TUI.
Creates a ``TuiWidgetEvent`` with ``event_type="thought_block"`` Creates a ``TuiWidgetEvent`` with ``event_type="thought_block"``
+1 -1
View File
@@ -301,7 +301,7 @@ _snapshot_to_dict # noqa: B018, F821
_create_strategy # noqa: B018, F821 _create_strategy # noqa: B018, F821
VALID_FORMATS # noqa: B018, F821 VALID_FORMATS # noqa: B018, F821
# TUI materializer — bridges Output Rendering Framework to Textual widgets # TUI materializer — bridges Output Rendering Framework to Textual widgets
TuiMaterializer # noqa: B018, F821 TuiMaterializer # noqa: B018, F821
TuiWidgetEvent # noqa: B018, F821 TuiWidgetEvent # noqa: B018, F821
TuiWidgetEventType # noqa: B018, F821 TuiWidgetEventType # noqa: B018, F821