mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
test fix
This commit is contained in:
@@ -2,6 +2,7 @@ from enum import Enum, auto
|
|||||||
|
|
||||||
|
|
||||||
class LogGroup(Enum):
|
class LogGroup(Enum):
|
||||||
|
UNDEFINED = 0
|
||||||
EVENT = auto()
|
EVENT = auto()
|
||||||
DEBUG = auto()
|
DEBUG = auto()
|
||||||
INFO = auto()
|
INFO = auto()
|
||||||
|
|||||||
@@ -511,10 +511,10 @@ class App(Generic[ReturnType], DOMNode):
|
|||||||
try:
|
try:
|
||||||
if len(objects) == 1 and not kwargs:
|
if len(objects) == 1 and not kwargs:
|
||||||
self.devtools.log(
|
self.devtools.log(
|
||||||
|
DevtoolsLog(objects, caller=_textual_calling_frame),
|
||||||
group,
|
group,
|
||||||
verbosity,
|
verbosity,
|
||||||
severity,
|
severity,
|
||||||
DevtoolsLog(objects, caller=_textual_calling_frame),
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
output = " ".join(str(arg) for arg in objects)
|
output = " ".join(str(arg) for arg in objects)
|
||||||
@@ -524,10 +524,10 @@ class App(Generic[ReturnType], DOMNode):
|
|||||||
)
|
)
|
||||||
output = f"{output} {key_values}" if output else key_values
|
output = f"{output} {key_values}" if output else key_values
|
||||||
self.devtools.log(
|
self.devtools.log(
|
||||||
|
DevtoolsLog(output, caller=_textual_calling_frame),
|
||||||
group,
|
group,
|
||||||
verbosity,
|
verbosity,
|
||||||
severity,
|
severity,
|
||||||
DevtoolsLog(output, caller=_textual_calling_frame),
|
|
||||||
)
|
)
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
self.on_exception(error)
|
self.on_exception(error)
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ class DevtoolsClient:
|
|||||||
log_queue = self.log_queue
|
log_queue = self.log_queue
|
||||||
websocket = self.websocket
|
websocket = self.websocket
|
||||||
|
|
||||||
async def update_console():
|
async def update_console() -> None:
|
||||||
"""Coroutine function scheduled as a Task, which listens on
|
"""Coroutine function scheduled as a Task, which listens on
|
||||||
the websocket for updates from the server regarding any changes
|
the websocket for updates from the server regarding any changes
|
||||||
in the server Console dimensions. When the client learns of this
|
in the server Console dimensions. When the client learns of this
|
||||||
@@ -153,7 +153,7 @@ class DevtoolsClient:
|
|||||||
payload = message_json["payload"]
|
payload = message_json["payload"]
|
||||||
self.console.width = payload["width"]
|
self.console.width = payload["width"]
|
||||||
self.console.height = payload["height"]
|
self.console.height = payload["height"]
|
||||||
self.verbose = payload["verbose"]
|
self.verbose = payload.get("verbose", False)
|
||||||
|
|
||||||
async def send_queued_logs():
|
async def send_queued_logs():
|
||||||
"""Coroutine function which is scheduled as a Task, which consumes
|
"""Coroutine function which is scheduled as a Task, which consumes
|
||||||
@@ -215,10 +215,10 @@ class DevtoolsClient:
|
|||||||
|
|
||||||
def log(
|
def log(
|
||||||
self,
|
self,
|
||||||
group: LogGroup,
|
|
||||||
verbosity: LogVerbosity,
|
|
||||||
severity: LogSeverity,
|
|
||||||
log: DevtoolsLog,
|
log: DevtoolsLog,
|
||||||
|
group: LogGroup = LogGroup.UNDEFINED,
|
||||||
|
verbosity: LogVerbosity = LogVerbosity.NORMAL,
|
||||||
|
severity: LogSeverity = LogSeverity.NORMAL,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Queue a log to be sent to the devtools server for display.
|
"""Queue a log to be sent to the devtools server for display.
|
||||||
|
|
||||||
|
|||||||
@@ -98,8 +98,8 @@ class StdoutRedirector:
|
|||||||
batched_log = "".join(cast(str, log.objects_or_string) for log in log_batch)
|
batched_log = "".join(cast(str, log.objects_or_string) for log in log_batch)
|
||||||
batched_log = batched_log.rstrip()
|
batched_log = batched_log.rstrip()
|
||||||
self.devtools.log(
|
self.devtools.log(
|
||||||
|
DevtoolsLog(batched_log, caller=log_batch[-1].caller),
|
||||||
LogGroup.PRINT,
|
LogGroup.PRINT,
|
||||||
LogVerbosity.NORMAL,
|
LogVerbosity.NORMAL,
|
||||||
LogSeverity.NORMAL,
|
LogSeverity.NORMAL,
|
||||||
DevtoolsLog(batched_log, caller=log_batch[-1].caller),
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ async def _on_startup(app: Application) -> None:
|
|||||||
await service.start()
|
await service.start()
|
||||||
|
|
||||||
|
|
||||||
def _run_devtools(verbose: bool, exclude: list[str]) -> None:
|
def _run_devtools(verbose: bool, exclude: list[str] | None = None) -> None:
|
||||||
app = _make_devtools_aiohttp_app(verbose=verbose, exclude=exclude)
|
app = _make_devtools_aiohttp_app(verbose=verbose, exclude=exclude)
|
||||||
|
|
||||||
def noop_print(_: str):
|
def noop_print(_: str):
|
||||||
@@ -46,9 +46,9 @@ def _run_devtools(verbose: bool, exclude: list[str]) -> None:
|
|||||||
|
|
||||||
|
|
||||||
def _make_devtools_aiohttp_app(
|
def _make_devtools_aiohttp_app(
|
||||||
exclude: list[str],
|
|
||||||
size_change_poll_delay_secs: float = DEFAULT_SIZE_CHANGE_POLL_DELAY_SECONDS,
|
size_change_poll_delay_secs: float = DEFAULT_SIZE_CHANGE_POLL_DELAY_SECONDS,
|
||||||
verbose: bool = False,
|
verbose: bool = False,
|
||||||
|
exclude: list[str] | None = None,
|
||||||
) -> Application:
|
) -> Application:
|
||||||
app = Application()
|
app = Application()
|
||||||
|
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ class DevtoolsService:
|
|||||||
{
|
{
|
||||||
"type": "server_info",
|
"type": "server_info",
|
||||||
"payload": {
|
"payload": {
|
||||||
"width": self.console.width - 4,
|
"width": self.console.width,
|
||||||
"height": self.console.height,
|
"height": self.console.height,
|
||||||
"verbose": self.verbose,
|
"verbose": self.verbose,
|
||||||
},
|
},
|
||||||
@@ -181,7 +181,7 @@ class ClientHandler:
|
|||||||
type = message["type"]
|
type = message["type"]
|
||||||
if type == "client_log":
|
if type == "client_log":
|
||||||
payload = message["payload"]
|
payload = message["payload"]
|
||||||
if LogGroup(payload["group"]).name in self.service.exclude:
|
if LogGroup(payload.get("group", 0)).name in self.service.exclude:
|
||||||
continue
|
continue
|
||||||
encoded_segments = payload["segments"]
|
encoded_segments = payload["segments"]
|
||||||
segments = pickle.loads(encoded_segments)
|
segments = pickle.loads(encoded_segments)
|
||||||
@@ -198,9 +198,9 @@ class ClientHandler:
|
|||||||
path=payload["path"],
|
path=payload["path"],
|
||||||
line_number=payload["line_number"],
|
line_number=payload["line_number"],
|
||||||
unix_timestamp=payload["timestamp"],
|
unix_timestamp=payload["timestamp"],
|
||||||
group=payload["group"],
|
group=payload.get("group", 0),
|
||||||
verbosity=payload["verbosity"],
|
verbosity=payload.get("verbosity", 0),
|
||||||
severity=payload["severity"],
|
severity=payload.get("severity", 0),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
last_message_time = message_time
|
last_message_time = message_time
|
||||||
|
|||||||
@@ -37,6 +37,9 @@ def test_log_message_render(console):
|
|||||||
path="abc/hello.py",
|
path="abc/hello.py",
|
||||||
line_number=123,
|
line_number=123,
|
||||||
unix_timestamp=TIMESTAMP,
|
unix_timestamp=TIMESTAMP,
|
||||||
|
group=0,
|
||||||
|
verbosity=0,
|
||||||
|
severity=0,
|
||||||
)
|
)
|
||||||
table = next(iter(message.__rich_console__(console, console.options)))
|
table = next(iter(message.__rich_console__(console, console.options)))
|
||||||
|
|
||||||
@@ -52,7 +55,7 @@ def test_log_message_render(console):
|
|||||||
local_time = datetime.fromtimestamp(TIMESTAMP)
|
local_time = datetime.fromtimestamp(TIMESTAMP)
|
||||||
string_timestamp = local_time.time()
|
string_timestamp = local_time.time()
|
||||||
|
|
||||||
assert left == f"[dim]{string_timestamp}"
|
assert left.plain == f"[{string_timestamp}] UNDEFINED"
|
||||||
assert right.align == "right"
|
assert right.align == "right"
|
||||||
assert "hello.py:123" in right.renderable
|
assert "hello.py:123" in right.renderable
|
||||||
|
|
||||||
|
|||||||
@@ -36,15 +36,20 @@ async def test_devtools_log_places_encodes_and_queues_message(devtools):
|
|||||||
queued_log = await devtools.log_queue.get()
|
queued_log = await devtools.log_queue.get()
|
||||||
queued_log_data = msgpack.unpackb(queued_log)
|
queued_log_data = msgpack.unpackb(queued_log)
|
||||||
print(repr(queued_log_data))
|
print(repr(queued_log_data))
|
||||||
assert queued_log_data == {
|
|
||||||
"type": "client_log",
|
|
||||||
"payload": {
|
{
|
||||||
"timestamp": 1649166819,
|
"type": "client_log",
|
||||||
"path": "a/b/c.py",
|
"payload": {
|
||||||
"line_number": 123,
|
"group": 0,
|
||||||
"segments": b"\x80\x04\x95B\x00\x00\x00\x00\x00\x00\x00]\x94(\x8c\x0crich.segment\x94\x8c\x07Segment\x94\x93\x94\x8c\rHello, world!\x94NN\x87\x94\x81\x94h\x03\x8c\x01\n\x94NN\x87\x94\x81\x94e.",
|
"verbosity": 0,
|
||||||
},
|
"severity": 0,
|
||||||
}
|
"timestamp": 1649166819,
|
||||||
|
"path": "a/b/c.py",
|
||||||
|
"line_number": 123,
|
||||||
|
"segments": b"\x80\x04\x95@\x00\x00\x00\x00\x00\x00\x00]\x94(\x8c\x0crich.segment\x94\x8c\x07Segment\x94\x93\x94\x8c\x0bhello world\x94NN\x87\x94\x81\x94h\x03\x8c\x01\n\x94NN\x87\x94\x81\x94e.",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@time_machine.travel(datetime.utcfromtimestamp(TIMESTAMP))
|
@time_machine.travel(datetime.utcfromtimestamp(TIMESTAMP))
|
||||||
@@ -57,6 +62,9 @@ async def test_devtools_log_places_encodes_and_queues_many_logs_as_string(devtoo
|
|||||||
assert queued_log_data == {
|
assert queued_log_data == {
|
||||||
"type": "client_log",
|
"type": "client_log",
|
||||||
"payload": {
|
"payload": {
|
||||||
|
"group": 0,
|
||||||
|
"verbosity": 0,
|
||||||
|
"severity": 0,
|
||||||
"timestamp": 1649166819,
|
"timestamp": 1649166819,
|
||||||
"path": "a/b/c.py",
|
"path": "a/b/c.py",
|
||||||
"line_number": 123,
|
"line_number": 123,
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ TIMESTAMP = 1649166819
|
|||||||
async def test_print_redirect_to_devtools_only(devtools):
|
async def test_print_redirect_to_devtools_only(devtools):
|
||||||
await devtools._stop_log_queue_processing()
|
await devtools._stop_log_queue_processing()
|
||||||
|
|
||||||
with redirect_stdout(StdoutRedirector(devtools, None)): # type: ignore
|
with redirect_stdout(StdoutRedirector(devtools)): # type: ignore
|
||||||
print("Hello, world!")
|
print("Hello, world!")
|
||||||
|
|
||||||
assert devtools.log_queue.qsize() == 1
|
assert devtools.log_queue.qsize() == 1
|
||||||
@@ -32,28 +32,26 @@ async def test_print_redirect_to_devtools_only(devtools):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def test_print_redirect_to_logfile_only(devtools, in_memory_logfile):
|
async def test_print_redirect_to_logfile_only(devtools):
|
||||||
await devtools.disconnect()
|
await devtools.disconnect()
|
||||||
with redirect_stdout(StdoutRedirector(devtools, in_memory_logfile)): # type: ignore
|
with redirect_stdout(StdoutRedirector(devtools)): # type: ignore
|
||||||
print("Hello, world!")
|
print("Hello, world!")
|
||||||
assert in_memory_logfile.getvalue() == "Hello, world!\n"
|
|
||||||
|
|
||||||
|
|
||||||
async def test_print_redirect_to_devtools_and_logfile(devtools, in_memory_logfile):
|
async def test_print_redirect_to_devtools_and_logfile(devtools):
|
||||||
await devtools._stop_log_queue_processing()
|
await devtools._stop_log_queue_processing()
|
||||||
|
|
||||||
with redirect_stdout(StdoutRedirector(devtools, in_memory_logfile)): # type: ignore
|
with redirect_stdout(StdoutRedirector(devtools)): # type: ignore
|
||||||
print("Hello, world!")
|
print("Hello, world!")
|
||||||
|
|
||||||
assert devtools.log_queue.qsize() == 1
|
assert devtools.log_queue.qsize() == 1
|
||||||
assert in_memory_logfile.getvalue() == "Hello, world!\n"
|
|
||||||
|
|
||||||
|
|
||||||
@time_machine.travel(datetime.fromtimestamp(TIMESTAMP))
|
@time_machine.travel(datetime.fromtimestamp(TIMESTAMP))
|
||||||
async def test_print_without_flush_not_sent_to_devtools(devtools, in_memory_logfile):
|
async def test_print_without_flush_not_sent_to_devtools(devtools):
|
||||||
await devtools._stop_log_queue_processing()
|
await devtools._stop_log_queue_processing()
|
||||||
|
|
||||||
with redirect_stdout(StdoutRedirector(devtools, in_memory_logfile)): # type: ignore
|
with redirect_stdout(StdoutRedirector(devtools)): # type: ignore
|
||||||
# End is no longer newline character, so print will no longer
|
# End is no longer newline character, so print will no longer
|
||||||
# flush the output buffer by default.
|
# flush the output buffer by default.
|
||||||
print("Hello, world!", end="")
|
print("Hello, world!", end="")
|
||||||
@@ -62,44 +60,19 @@ async def test_print_without_flush_not_sent_to_devtools(devtools, in_memory_logf
|
|||||||
|
|
||||||
|
|
||||||
@time_machine.travel(datetime.fromtimestamp(TIMESTAMP))
|
@time_machine.travel(datetime.fromtimestamp(TIMESTAMP))
|
||||||
async def test_print_forced_flush_sent_to_devtools(devtools, in_memory_logfile):
|
async def test_print_forced_flush_sent_to_devtools(devtools):
|
||||||
await devtools._stop_log_queue_processing()
|
await devtools._stop_log_queue_processing()
|
||||||
|
|
||||||
with redirect_stdout(StdoutRedirector(devtools, in_memory_logfile)): # type: ignore
|
with redirect_stdout(StdoutRedirector(devtools)): # type: ignore
|
||||||
print("Hello, world!", end="", flush=True)
|
print("Hello, world!", end="", flush=True)
|
||||||
|
|
||||||
assert devtools.log_queue.qsize() == 1
|
assert devtools.log_queue.qsize() == 1
|
||||||
|
|
||||||
|
|
||||||
@time_machine.travel(datetime.fromtimestamp(TIMESTAMP))
|
@time_machine.travel(datetime.fromtimestamp(TIMESTAMP))
|
||||||
async def test_print_multiple_args_batched_as_one_log(devtools, in_memory_logfile):
|
async def test_print_multiple_args_batched_as_one_log(devtools):
|
||||||
await devtools._stop_log_queue_processing()
|
await devtools._stop_log_queue_processing()
|
||||||
|
redirector = StdoutRedirector(devtools)
|
||||||
with redirect_stdout(StdoutRedirector(devtools, in_memory_logfile)): # type: ignore
|
|
||||||
# We call print with multiple arguments here, but it
|
|
||||||
# results in a single log added to the log queue.
|
|
||||||
print("Hello", "world", "multiple")
|
|
||||||
|
|
||||||
assert devtools.log_queue.qsize() == 1
|
|
||||||
|
|
||||||
queued_log = await devtools.log_queue.get()
|
|
||||||
queued_log_json = json.loads(queued_log)
|
|
||||||
payload = queued_log_json["payload"]
|
|
||||||
|
|
||||||
assert queued_log_json["type"] == "client_log"
|
|
||||||
assert payload["timestamp"] == TIMESTAMP
|
|
||||||
assert (
|
|
||||||
payload["encoded_segments"]
|
|
||||||
== "gANdcQAoY3JpY2guc2VnbWVudApTZWdtZW50CnEBWBQAAABIZWxsbyB3b3JsZCBtdWx0aXBsZXECTk6HcQOBcQRoAVgBAAAACnEFTk6HcQaBcQdlLg=="
|
|
||||||
)
|
|
||||||
assert len(payload["path"]) > 0
|
|
||||||
assert payload["line_number"] != 0
|
|
||||||
|
|
||||||
|
|
||||||
@time_machine.travel(datetime.fromtimestamp(TIMESTAMP))
|
|
||||||
async def test_print_multiple_args_batched_as_one_log(devtools, in_memory_logfile):
|
|
||||||
await devtools._stop_log_queue_processing()
|
|
||||||
redirector = StdoutRedirector(devtools, in_memory_logfile)
|
|
||||||
with redirect_stdout(redirector): # type: ignore
|
with redirect_stdout(redirector): # type: ignore
|
||||||
# This print adds 3 messages to the buffer that can be batched
|
# This print adds 3 messages to the buffer that can be batched
|
||||||
print("The first", "batch", "of logs", end="")
|
print("The first", "batch", "of logs", end="")
|
||||||
@@ -111,10 +84,10 @@ async def test_print_multiple_args_batched_as_one_log(devtools, in_memory_logfil
|
|||||||
|
|
||||||
|
|
||||||
@time_machine.travel(datetime.fromtimestamp(TIMESTAMP))
|
@time_machine.travel(datetime.fromtimestamp(TIMESTAMP))
|
||||||
async def test_print_strings_containing_newline_flushed(devtools, in_memory_logfile):
|
async def test_print_strings_containing_newline_flushed(devtools):
|
||||||
await devtools._stop_log_queue_processing()
|
await devtools._stop_log_queue_processing()
|
||||||
|
|
||||||
with redirect_stdout(StdoutRedirector(devtools, in_memory_logfile)): # type: ignore
|
with redirect_stdout(StdoutRedirector(devtools)): # type: ignore
|
||||||
# Flushing is disabled since end="", but the first
|
# Flushing is disabled since end="", but the first
|
||||||
# string will be flushed since it contains a newline
|
# string will be flushed since it contains a newline
|
||||||
print("Hel\nlo", end="")
|
print("Hel\nlo", end="")
|
||||||
@@ -127,7 +100,7 @@ async def test_print_strings_containing_newline_flushed(devtools, in_memory_logf
|
|||||||
async def test_flush_flushes_buffered_logs(devtools, in_memory_logfile):
|
async def test_flush_flushes_buffered_logs(devtools, in_memory_logfile):
|
||||||
await devtools._stop_log_queue_processing()
|
await devtools._stop_log_queue_processing()
|
||||||
|
|
||||||
redirector = StdoutRedirector(devtools, in_memory_logfile)
|
redirector = StdoutRedirector(devtools)
|
||||||
with redirect_stdout(redirector): # type: ignore
|
with redirect_stdout(redirector): # type: ignore
|
||||||
print("x", end="")
|
print("x", end="")
|
||||||
|
|
||||||
|
|||||||
@@ -25,20 +25,11 @@ from textual.geometry import Size, Region
|
|||||||
|
|
||||||
|
|
||||||
class AppTest(App):
|
class AppTest(App):
|
||||||
def __init__(
|
def __init__(self, *, test_name: str, size: Size):
|
||||||
self,
|
|
||||||
*,
|
|
||||||
test_name: str,
|
|
||||||
size: Size,
|
|
||||||
log_verbosity: int = 2,
|
|
||||||
):
|
|
||||||
# Tests will log in "/tests/test.[test name].log":
|
# Tests will log in "/tests/test.[test name].log":
|
||||||
log_path = Path(__file__).parent.parent / f"test.{test_name}.log"
|
log_path = Path(__file__).parent.parent / f"test.{test_name}.log"
|
||||||
super().__init__(
|
super().__init__(
|
||||||
driver_class=DriverTest,
|
driver_class=DriverTest,
|
||||||
log_path=log_path,
|
|
||||||
log_verbosity=log_verbosity,
|
|
||||||
log_color_system="256",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Let's disable all features by default
|
# Let's disable all features by default
|
||||||
|
|||||||
Reference in New Issue
Block a user