text boxes never stop listening

Open Beginner friendly
#6,744 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

  • #1 by @CJstate — closed without merging

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
88/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
python
Domain
cli

Research direction

Start with _text_area.py and _input.py at the cited _on_mount methods, then read Footer's unmount cleanup in _footer.py as a reference. Use the provided reproducer to check that removed Input and TextArea widgets are no longer retained without publishing the signal; done means the leak is fixed for both widgets.

Written by the indexing model from the issue text.

Description

The bug

TextArea._on_mount (_text_area.py:1904-1911) and Input._on_mount (_input.py:715-722) subscribe to self.screen.text_selection_started_signal with a callback that closes over self, and neither unsubscribes on unmount.
Signal keeps subscribers in a WeakKeyDictionary (signal.py:44), but the stored value is a wrapper holding that callback (signal.py:82-95), which holds self, so the weak key never dies. Dead subscribers are pruned only in publish() (signal.py:125-128), and nothing in Textual 8.2.8 publishes this signal. So every removed TextArea or Input stays alive, with its subtree, for the screen's lifetime.
Footer (_footer.py:333) and KeyPanel (_key_panel.py:182) already unsubscribe their own signal on unmount.

Example

import asyncio, gc
from textual.app import App
from textual.widgets import Input
async def main():
    app = App()
    async with app.run_test() as pilot:
        for _ in range(20):
            widget = Input()
            await app.mount(widget)
            await pilot.pause()
            await widget.remove()
            await pilot.pause()
        del widget
        gc.collect()
        print(sum(type(o) is Input for o in gc.get_objects()))  # 20, expected 0
asyncio.run(main())

One manual app.screen.text_selection_started_signal.publish(app.screen) drops it to 2. With TextArea in place of Input it stays at 20 until both a publish and an app theme change (the theme watcher is #6666).
Textual 8.2.8, Python 3.11.14, macOS.

Suggested fix

In TextArea and Input, unsubscribe on unmount, as Footer does:

self.screen.text_selection_started_signal.unsubscribe(self)
Dominant language
Python
Stars
37.6k
Forks
1.4k
PR merge metrics
No merged PRs in 30d

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from Textualize/textual

All issues in Textualize/textual

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.