Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions evidence/handler-allocation-20261007/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Handler lookup allocations

The existing metaclass already collects decorated declarations and parses selectors. No declaration registry or event cache is needed. Named handlers must remain live: an awaited decorated handler can replace the named handler that follows it. C3 order, instance binding, selectors and bubbling remain runtime work.

The original lookup constructed an empty list on every missing decorated-handler match, including each message ancestor in each decorated class table. It also allocated a duplicate-tracking set even when no decorated candidate existed. Lookup now uses the immutable empty tuple on a miss and creates its set at the first decorated candidate. Existing declaration lists and post-yield duplicate accounting are unchanged.

The existing refactor-audit Package parsed 250 production modules without omissions. `_get_dispatch_methods` is used by `_on_message` and idle delivery; both use the same changed implementation. No other declaration-table writer was found beyond `_MessagePumpMeta`; dynamic class mappings and decorated lists remain live.

Fourteen affected original decorator/message checks passed in 2.18 seconds, including inherited duplicate suppression, C3/private precedence, selector matching and live replacement during awaited dispatch.

One original channel App check passed: 160 authored private messages, 20 arrivals, focused history paging; sequence113 to73, 88 mounted rows, no App error, empty stderr. Installed Toad/Core came from viewer-cut-and-header-delivery-20261007; only native source was supplied. The installed message-pump diff consists exactly of these allocation changes. No provider, installed-package write or public operation. Original fixture teardown joined its private work; individual child birth identities were not collected.

Raw result/profile/logs: /home/ts/.cache/agent-scratch/native-handler-allocation-20261007. Previous profile: /home/ts/.cache/agent-scratch/installed-viewer-cut-header-20261007/ui.pstats.

Profiling recorded229908→214884 lookup calls, own time.9755→.9351s and inclusive1.5684→1.4606s. Own time per invocation4.24→4.35microseconds did not improve. Heartbeatp95 went46.13→35.11ms, maximum182.39→227.40ms; arrangement workload and final scroll position differed. These runs do not establish a reliable responsiveness or overall speed gain. Layout remains substantial required work.
15 changes: 15 additions & 0 deletions evidence/handler-allocation-20261007/app-result.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"main_loop_samples": 2387,
"median_ms": 6.166572915390134,
"p95_ms": 35.106428898870945,
"max_ms": 227.4037009337917,
"gaps_above_50ms": 61,
"mounted_rows": 88,
"oldest_sequence": 73,
"app_error": null,
"profiling": true,
"initial_scroll": 215,
"final_scroll": 803,
"initial_oldest": 113,
"older_page": 73
}
6 changes: 4 additions & 2 deletions src/textual/message_pump.py
Original file line number Diff line number Diff line change
Expand Up @@ -836,7 +836,7 @@ def _get_dispatch_methods(
"""
from textual.widget import Widget

methods_dispatched: set[Callable] = set()
methods_dispatched: set[Callable] | None = None
message_types = message.__class__.__mro__
message_mro: list[type[Message]] | None = None
private_method_name = f"_{method_name}"
Expand All @@ -856,9 +856,11 @@ def _get_dispatch_methods(
_type for _type in message_types if issubclass(_type, Message)
]
for message_class in message_mro:
handlers = decorated_handlers.get(message_class, [])
handlers = decorated_handlers.get(message_class, ())

for method, selectors in handlers:
if methods_dispatched is None:
methods_dispatched = set()
if method in methods_dispatched:
continue
if not selectors:
Expand Down
Loading