Wie schreibe ich einen Integrationstest auf einen Urwid Tui?Python

Python-Programme
Anonymous
 Wie schreibe ich einen Integrationstest auf einen Urwid Tui?

Post by Anonymous »

Beim Versuch, eine Urwid-basierte Frage mit Eingabevalidierung und automatischen Vorschlägen zu testen, habe ich einige Schwierigkeiten. Der Code, den ich mit PyTest testen möchte

Code: Select all

from typing import List

import urwid
from typeguard import typechecked

from tui_labeller.file_read_write_helper import write_to_file

@typechecked
def get_filtered_suggestions(
*, input_text: str, available_suggestions: List[str]
) -> List[str]:
"""
Filter suggestions based on input text, matching from start with wildcard support.
Special case: '*' alone shows all available suggestions.

Args:
input_text (str): The text entered by user, can include '*' as wildcard
available_suggestions (list): List of possible suggestion strings

Returns:
list: Filtered suggestions based on input criteria
"""
input_text = input_text.strip()

# Special case: if input is '*', return all suggestions
if input_text == "*":
return available_suggestions

# If no input, return all suggestions
if not input_text:
return available_suggestions

# Handle wildcard case
if "*" in input_text:
# Split input by wildcard
parts = input_text.lower().split("*")
prefix = parts[0]  # What comes before the wildcard

# Filter suggestions
filtered = [
suggestion
for suggestion in available_suggestions
if suggestion.lower().startswith(prefix)
and all(part in suggestion.lower() for part in parts[1:] if part)
]
else:
# Original filtering for non-wildcard case
filtered = [
suggestion
for suggestion in available_suggestions
if suggestion.lower().startswith(input_text.lower())
]

# If no matches found, return ['-']
return filtered if filtered else ["-"]

class InputValidationQuestion(urwid.Edit):
def __init__(
self, caption, suggestions=None, autocomplete_box=None, pile=None
):
super().__init__(caption=caption)
self.suggestions = suggestions or []
self.autocomplete_box = autocomplete_box
self.pile = pile
self._in_autocomplete: bool = False

def handle_autocomplete(self, key, size):
"""Handle autocomplete logic based on input key and suggestions.

Args:
key: The pressed key
size: The size parameter for keypress
Returns:
The result of keypress or None if handled
Raises:
ValueError: When autocomplete conditions aren't met
"""
if not self.suggestions:
write_to_file(
filename="eg.txt",
content=f"self.suggestions={self.suggestions}",
append=True,
)
return super().keypress(size, key)

# Handle automatic substitution when '*' yields single match
if "*"  in self.edit_text:
matches = [s for s in self.suggestions if self._match_pattern(s)]
if len(matches) == 1:
self.set_edit_text(matches[0])
self.owner.set_attr_map({None: "normal"})
write_to_file(
filename="eg.txt",
content=f"self.edit_text={self.edit_text}",
append=True,
)
return None
elif len(matches) == 0:
raise ValueError("No matches found for pattern")
# TODO: do stuff here.
# If multiple matches, continue to tab handling

# Handle tab key press
if key == "tab":
matches = [s for s in self.suggestions if self._match_pattern(s)]

if len(matches) == 1:
self.set_edit_text(matches[0])
self.owner.set_attr_map({None: "normal"})
return None
elif len(matches) == 0:
raise ValueError("No matching suggestion found")
else:
raise ValueError("Multiple ambiguous suggestions available")

return super().keypress(size, key)

def valid_char(self, ch):
return len(ch) == 1 and (ch.isalpha() or ch in [":", "*"])

def keypress(self, size, key):
write_to_file(
filename="eg.txt",
content=f"key={key}, self.edit_text={self.edit_text}",
append=True,
)
if key in ["tab", "*"]:
return self.handle_autocomplete(key, size)
elif key == "enter":
return "enter"
elif key in ("up", "down"):
if self.pile:
current_pos = self.pile.focus_position
new_pos = current_pos - 1 if key == "up" else current_pos + 1
if 0 
InputValidationquestions.py:
import urwid

from tui_labeller.file_read_write_helper import write_to_file
from tui_labeller.tuis.urwid.InputValidationQuestion import (
InputValidationQuestion,
)

class InputValidationQuestions:
def __init__(self):
self.questions = [
("Question 1: ", ["apple", "apricot", "avocado"]),
("Question 2: ", ["banana", "blueberry", "blackberry"]),
("Question 3:  ", ["cat", "caterpillar", "cactus"]),
]

self.palette = [
("normal", "white", "black"),
("highlight", "white", "dark red"),
("autocomplete", "yellow", "dark blue"),
]

self.autocomplete_box = urwid.AttrMap(
urwid.Text("", align="left"), "autocomplete"
)

self.pile = urwid.Pile([])
self.inputs = []
for question, suggestions in self.questions:
edit = InputValidationQuestion(
question, suggestions, self.autocomplete_box, self.pile
)
attr_edit = urwid.AttrMap(edit, "normal")
edit.owner = attr_edit
self.inputs.append(attr_edit)

self.pile.contents = [
(self.inputs[0], ("pack", None)),
(self.inputs[1], ("pack", None)),
(self.inputs[2], ("pack", None)),
(urwid.Divider(), ("pack", None)),
(
urwid.Columns(
[(30, urwid.Text("Autocomplete: ")), self.autocomplete_box]
),
("pack", None),
),
]

self.fill = urwid.Filler(self.pile, valign="top")
self.loop = urwid.MainLoop(
self.fill, self.palette, unhandled_input=self.handle_input
)

def handle_input(self, key):
print(f"Unhandled input: {key}")
write_to_file(
filename="eg.txt", content=f"Unhandled input: {key}", append=False
)
# TODO: if cursor is at the first question and up is pressed, go to last question.

# TODO: if cursor is at the last question and down is pressed, go to first question.
raise ValueError(f"STOPPED at:{key}")

def run(self):
def update_autocomplete(widget, new_text):
widget.update_autocomplete()

for input_widget in self.inputs:
urwid.connect_signal(
input_widget.base_widget, "change", update_autocomplete
)

if self.inputs:
self.pile.focus_position = 0
self.inputs[0].base_widget.update_autocomplete()

self.loop.run()

< /code>
Diese werden mit: < /p>
 ausgeführt.from typeguard import typechecked

from src.tui_labeller.tuis.urwid.InputValidationQuestions import (
InputValidationQuestions,
)

app = InputValidationQuestions()
app.run()
Erwartete Verhalten
Die Klasse verhandelt inkrementelle Eingaben (z. B. tippt "a, v, " Select "Avocado") in einem Tui -App mit Python -m Src.tui_labeller -i -o -tur -Tuwid . Im realen Lauf wirkt "A, V, " und drücken Sie die Eingabetaste ein ValueError: Stopp bei: Enter , was erwartet wird/fein. Verarbeitung.

Code: Select all

import urwid
import pytest
from tui_labeller.tuis.urwid.SUBSTITUECLASSHERE import SUBSTITUECLASSHERE
@pytest.fixture
def app():
app = SUBSTITUECLASSHERE()
app.loop.screen = urwid.raw_display.Screen()
return app
def test_avocado_selection(app):
input_sequence = ["a", "v", "*"]
for key in input_sequence:
app.loop.process_input([key])
if hasattr(app.loop, "unhandled_input") and app.loop.unhandled_input:
app.loop.unhandled_input(key)
# How to check "avocado" is selected? Edit widget, ListBox, or custom attribute?
def test_enter_error_handling(app):
input_sequence = ["a", "v", "*", "enter"]
with pytest.raises(ValueError, match="STOPPED at:enter"):
for key in input_sequence:
app.loop.process_input([key])
if hasattr(app.loop, "unhandled_input") and app.loop.unhandled_input:
app.loop.unhandled_input(key)
< /code>
Der Test schlägt fehl mit: < /p>
ValueError: STOPPED at:a
AssertionError: Regex pattern 'STOPPED at:enter' did not match 'STOPPED at:a'
Frage
Wie modifiziere ich den Test an:

[*] Prozess "a, v,*", um "Avocado" ohne frühes Erhäuerungsfehler auszuwählen,
Verifizieren Sie die Selektion (was Widget/Attribut hält es.>

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post