Skip to content

Log and survive exceptions raised by alarm callbacks - #1418

Merged
penguinolog merged 2 commits into
urwid:masterfrom
charan-rathore:fix/alarm-callback-errors
Oct 13, 2026
Merged

penguinolog merged 2 commits into
urwid:masterfrom
charan-rathore:fix/alarm-callback-errors

Conversation

@charan-rathore

Copy link
Copy Markdown
Contributor
Checklist
  • I've ensured that similar functionality has not already been implemented
  • I've ensured that similar functionality has not earlier been proposed and declined
  • I've branched off the master branch
  • I've merged fresh upstream into my branch recently
  • I've ran tox successfully in local environment
  • I've included docstrings and/or documentation and/or examples for my code (if this is a new feature)
Description:

Fixes #1269.

A callback registered through set_alarm_in/set_alarm_at with the wrong signature (or one that raises for any other reason) let the exception escape run(), tearing down the whole application with a traceback pointing at urwid internals rather than the offending callback.

  • _make_alarm_callback now wraps the callback: exceptions are logged with their traceback through the main loop's logger, naming the callback, and the loop keeps running.
  • ExitMainLoop is re-raised, so alarms can still exit the loop; the async def variant is wrapped identically.
  • The set_alarm_in/set_alarm_at docstrings now document the behavior and the callback signature requirement is spelled out in the parameter docs.

The regression test registers a mis-shaped one-argument callback (the issue's case): it fails on current master with the bare TypeError escaping run(), and with the fix asserts the error is logged naming the callback while a following alarm still runs and exits the loop normally.

tox -e py313: 1914 passed, 17 skipped, 1317 subtests passed.

A callback registered through set_alarm_in/set_alarm_at with the
wrong signature (or one that raises for any other reason) let the
exception escape run(), tearing down the whole application with a
traceback pointing at urwid internals rather than the offending
callback.

Wrap the alarm callback in _make_alarm_callback: exceptions are
logged with their traceback naming the callback, and the loop keeps
running. ExitMainLoop is re-raised so alarms can still exit the
loop, and the async def variant is wrapped identically. The
set_alarm_in/set_alarm_at docstrings now document the behavior.

Fixes urwid#1269

Signed-off-by: Charan Rathore <[email protected]>
@penguinolog
penguinolog merged commit b2c8404 into urwid:master Oct 13, 2026
28 checks passed
netbsd-srcmastr pushed a commit to NetBSD/pkgsrc that referenced this pull request Nov 2, 2026
Urwid 5.0.0

2026-10-28

Breaking Changes ⚠

    Drop Python 3.9 and 3.10: urwid requires Python 3.11 or newer by @penguinolog in urwid/urwid#1401

    Allow display attributes to inherit colors and settings: canvas content and Text.get_text() carry LayeredAttr for nested attributes, custom screens have to call BaseScreen.resolve_attr() instead of reading the palette, and an attribute an AttrMap maps to None shows the map’s None attribute by @penguinolog in urwid/urwid#1409

    🗹 AttrSpec foreground and background default to 'inherit'; also a new feature, see “Major features” below: Draw OSC 8 hyperlinks from display attributes by @penguinolog in urwid/urwid#1415

    Drop code planned for removal in 5.0: the Columns, Pile, GridFlow, Frame and ListBox get_focus/set_focus methods and 1.1-era list attributes, the Frame header/body/footer getters and setters, ListBox.contents() called as a method, content_delta, shards_delta, shard_cviews_delta, BaseScreen.run_wrapper, font.add_font, WidgetWrap._set_w, AttrWrap.w and Filler.body; MonitoredDeque.insert() with an index without __index__ raises TypeError by @penguinolog in urwid/urwid#1402

    ⚡ Remove the vterm escape compatibility constants and plain-tuple CSI_COMMANDS entries, return WHSettings members from Pile.options() for 'given' and 'weight', and require typing_extensions on Python older than 3.13; also see “Deprecations” below: Unify deprecation warnings and removal versions by @penguinolog in urwid/urwid#1421

    Stop re-exporting unrelated names from urwid.graphics by @penguinolog in urwid/urwid#1163

    🗹 ANSIText keeps bold as a setting of its own: ESC[1;31m is 'dark red,bold', no longer 'light red,bold'; also a new feature, see “New features” below: Read the raw display’s attributes back in ANSIText by @penguinolog in urwid/urwid#1502

    🗹 The raw display can detect more colors than before: the colors capability of the terminfo entry raises the count (mintty, vscode and others from 16 to 256); also a new feature, see “New features” below: Read colour depth from terminfo in the raw display by @penguinolog in urwid/urwid#1464

    🗹 Pickles of MonitoredList written at protocol 2 or higher no longer load in older urwid releases; also a new feature, see “New features” below: Make focus lists and list walkers picklable by @penguinolog in urwid/urwid#1469

    🕷 Terminal returns a key with no TERM=linux form (shift up, meta f5, focus in) unhandled instead of typing its name into the child; also bug fixes, see “Bug fixes” below by @luantaraschi in urwid/urwid#1473 and by @penguinolog in urwid/urwid#1498

    Drop GraalPy 3.11 (GraalPy 24): its os module has no O_NOFOLLOW and its ASCII and Latin-1 codecs ignore registered error handlers. GraalPy 3.12 stays experimental, and GraalPy 3.13 is listed as experimental too by @penguinolog in urwid/urwid#1510

Major features 🗹

    ⚠ Draw OSC 8 hyperlinks from display attributes (Hyperlink, AttrSpec(hyperlink=...), set_terminal_properties(hyperlinks=True)); see “Breaking Changes” above by @penguinolog in urwid/urwid#1415

    Parse OSC 8 hyperlinks in ANSIText and Terminal by @penguinolog in urwid/urwid#1419

    Report extended keys via the kitty and modifyOtherKeys protocols: Screen(extended_keys=True) tells ctrl i from tab and ctrl enter from enter, and adds the super and hyper modifiers by @penguinolog in urwid/urwid#1504

    Alternate screen and kitty keyboard protocol in Terminal by @penguinolog in urwid/urwid#1505

    Forward mouse events to the Terminal child by @penguinolog in urwid/urwid#1501

    Add DropDown choice widget and anchored pop-up placement by @penguinolog in urwid/urwid#1471

    Add urwid.testing: render widgets to text and attribute runs, check their sizing, feed keys and mouse events, and run a MainLoop on ScriptedScreen without a terminal by @penguinolog in urwid/urwid#1481

    Add MainLoop.paused() to run another program, such as $EDITOR, in the terminal by @penguinolog in urwid/urwid#1485

    Add tree navigation helpers and keyword-only walker positions by @penguinolog in urwid/urwid#1451

    Add opt-in Tab navigation to standard containers: Pile, Columns, Frame, ListBox and GridFlow created with select_navigation=True move the focus on tab, shift tab, ctrl n and ctrl p; SelectNavigationMixin and SelectNavigationListContentsMixin give other containers the same behaviour by @penguinolog in urwid/urwid#1478

New features 🗹

    Add ScrollBar visible option and fix scrollbar mouse handling by @penguinolog in urwid/urwid#1462

    Add ScrollBar end markers and attributes by @penguinolog in urwid/urwid#1470

    Render ListBox and ScrollBar at a flow size by @penguinolog in urwid/urwid#1488

    ⚠ Read colour depth from terminfo in the raw display, and add detect_term_colors(); see “Breaking Changes” above by @penguinolog in urwid/urwid#1464 and in urwid/urwid#1466

    ⚠ Make focus lists and list walkers picklable; see “Breaking Changes” above by @penguinolog in urwid/urwid#1469

    Add set_ascii_fallbacks() for characters the encoding rejects by @penguinolog in urwid/urwid#1479

    Add CommandMap.bind() that refuses a key bound twice by @penguinolog in urwid/urwid#1472

    Accept plain foreground canvases in CanvasOverlay by @IlyaKhalafi in urwid/urwid#1428

    Name DEC private modes and act on DECRQM replies by @penguinolog in urwid/urwid#1500

    ⚠ Read the raw display’s attributes back in ANSIText; see “Breaking Changes” above by @penguinolog in urwid/urwid#1502

    Add PopUpLauncher close_on_menu, pop_up_widget and launcher_size by @penguinolog in urwid/urwid#1513

    Add ListBox.scroll_to_top(), scroll_to_bottom() and focus_next_match() by @penguinolog in urwid/urwid#1514

    Add Edit.set_edit_text(..., edit_pos=...), the Edit signal "submit" and readline editing commands for Edit by @penguinolog in urwid/urwid#1515

    Add follow_end to SimpleFocusListWalker, SimpleFocusDequeWalker, MonitoredFocusList and MonitoredFocusDeque by @penguinolog in urwid/urwid#1516

    Add Text(..., selectable=True), SelectableIcon(cursor_position=None) and Button left, right and cursor_position by @penguinolog in urwid/urwid#1517

    Add WidgetDisable(..., disabled=False) and a settable WidgetDisable.disabled property by @penguinolog in urwid/urwid#1518

    LineBox titles accept text markup: LineBox(w, title=[("key", "F1"), " Help"]) and set_title() by @penguinolog in urwid/urwid#1519

    Add ListBox(..., focus_when_empty=False), so an empty list does not take the focus, and an opt-in delegate_selectable that makes ScrollBar and Scrollable report the wrapped widget’s selectable() by @penguinolog in urwid/urwid#1520

    Add the Thin5x4Font BigText font, letters for HalfBlock6x5Font and HalfBlockHeavy6x5Font, and the missing ASCII punctuation for every BigText font that has letters by @penguinolog in urwid/urwid#1521

    Add Edit(..., max_length=None) and a settable Edit.max_length property: a key that would go over it is returned unhandled, and longer text from the constructor, set_edit_text() or insert_text(), or a limit below the current text, raises ValueError by @penguinolog in urwid/urwid#1524

    Add the "focus changed" signal to Pile, Columns and GridFlow, sent with the old and the new focus position after the focus moved, and MonitoredFocusList.set_focus_moved_callback() by @penguinolog in urwid/urwid#1528

Deprecations ⚡

    ⚠ Unify deprecation warnings and removal versions: every deprecation names its removal release, and APIs still used by pudb, mitmproxy, khal, zulip-terminal and others are postponed to 7.0; also removes APIs, see “Breaking Changes” above by @penguinolog in urwid/urwid#1421

    Deprecate a positional reverse in positions() of the Simple*ListWalker and Simple*DequeWalker classes (removal in 8.0) by @penguinolog in urwid/urwid#1451

    Deprecate the private _MOUSE_*_FLAG constants in favour of MouseBit (removal in 6.0) by @penguinolog in urwid/urwid#1500

Bug fixes 🕷
Text layout and canvas rendering

    Do not crash on a zero-width line with clip or ellipsis wrap by @luantaraschi in urwid/urwid#1403

    Do not crash on zero-width text before a break in wrap modes by @penguinolog in urwid/urwid#1404

    Fix shard_tail gap errors from canvas shards of no rows by @penguinolog in urwid/urwid#1483

    Fix the ListBox rows_max cache and overlays of rowless canvases by @penguinolog in urwid/urwid#1486

    Keep mixed-width characters in place on the last screen row by @nk-batman21 in urwid/urwid#1506

    Keep zero-width runs and raw sequences intact on the last row by @penguinolog in urwid/urwid#1511

Raw and curses displays

    Fix terminal input after stop and Linux console palette by @penguinolog in urwid/urwid#1463

    Keep mouse tracking across a screen stop and restart by @penguinolog in urwid/urwid#1484

    Fix the swapped 80x24 fallback size in raw displays by @penguinolog in urwid/urwid#1491

    Use and track the visible Windows console window size by @penguinolog in urwid/urwid#1492

    Fix BytesWarning when restoring tty signal keys by @luantaraschi in urwid/urwid#1448

    Fix bytes/str leftovers and typing in displays and event loops by @penguinolog in urwid/urwid#1456

    Fix curses input waits longer than 25.5 seconds by @hengweiyv in urwid/urwid#1394

Escape sequences and key decoding

    Fix escape sequence handling in Terminal, ANSIText and raw display by @penguinolog in urwid/urwid#1497

    Strip whole CSI sequences with sub-parameters or intermediate bytes by @nk-batman21 in urwid/urwid#1496

    Decode st Insert and Delete key sequences by @IlyaKhalafi in urwid/urwid#1423

    Decode modified Insert and the remaining xterm keypad keys by @penguinolog in urwid/urwid#1499

Terminal widget

    Fix vterm hangs, crashes and leaks by @penguinolog in urwid/urwid#1406

    ⚠ Send ESC before the key for meta keys in Terminal; see “Breaking Changes” above by @luantaraschi in urwid/urwid#1473

    ⚠ Send Terminal keys as TERM=linux defines them; see “Breaking Changes” above by @penguinolog in urwid/urwid#1498

    Cancel a pending wrap when the Terminal cursor moves by @ybai08 in urwid/urwid#1474

    Do not scroll the Terminal region when wrapping below it by @ybai08 in urwid/urwid#1475

    Fix Terminal keypress before the first render by @penguinolog in urwid/urwid#1490

Event loops

    Skip closing an already closed asyncio loop in __del__ by @penguinolog in urwid/urwid#1417

    Log and survive exceptions raised by alarm callbacks by @charan-rathore in urwid/urwid#1418

    Run expired select alarms while input stays readable by @IlyaKhalafi in urwid/urwid#1424

    Run expired ZMQ alarms while input stays readable by @IlyaKhalafi in urwid/urwid#1427

    Fix event loop callback races and idle handling by @penguinolog in urwid/urwid#1461

    Wait for input on a descriptor opened from /dev/tty on macOS, which kqueue refuses with EINVAL, in SelectEventLoop and the raw display by falling back to select() by @penguinolog in urwid/urwid#1522

Containers, lists and walkers

    Use the index protocol in monitored containers by @IlyaKhalafi in urwid/urwid#1441

    Preserve deque walker bounds when copying by @IlyaKhalafi in urwid/urwid#1446

    Preserve focused object identity when sorting by @IlyaKhalafi in urwid/urwid#1454

    Notify after partially extending a list by @IlyaKhalafi in urwid/urwid#1460

    Preserve focus for empty forward slices by @IlyaKhalafi in urwid/urwid#1455

    Preserve nested focus after undirected ListBox jumps by @IlyaKhalafi in urwid/urwid#1425

    Return Tab at the ends of a wrap_around walker in ListBox by @penguinolog in urwid/urwid#1495

    Keep the correct parent during offscreen tree navigation by @IlyaKhalafi in urwid/urwid#1431

    Fix Columns cursor and positions for hidden columns by @penguinolog in urwid/urwid#1467

    Stop base_widget at mock objects by @penguinolog in urwid/urwid#1468

    Pickle widgets with protocols 0 and 1 on GraalPy, which built them from typing.Generic and failed by @penguinolog in urwid/urwid#1510

    Report a GridFlow mouse event as handled only when a cell handled it or the focus moved, so a parent ListBox scrolls on the wheel over it; a click on empty space now reaches unhandled_input, as for Pile and Columns by @penguinolog in urwid/urwid#1526

    Fix the errors that precise widget typing exposed: Frame and Overlay get_cursor_coords() and get_focus_path() no longer crash on a missing focus part or a top widget without a cursor, Columns.pack(()) raises ColumnsError, an unknown focus_column raises ValueError, TreeListBox.focus_end() and Filler.move_cursor_to_coords() no longer use the column count as the row count, Overlay rejects clip and weight widths and flow and weight heights, and Pile and Columns reject a float 'given' amount by @penguinolog in urwid/urwid#1443

    Skip a child sized (GIVEN, 0), which is not drawn, when the arrow keys or Tab move the focus in Pile, Columns and GridFlow by @penguinolog in urwid/urwid#1526

ScrollBar

    Fix ScrollBar keypress before the first render by @penguinolog in urwid/urwid#1465

    Render ScrollBar with no rows at a size of no rows by @penguinolog in urwid/urwid#1482

Edit widget

    Move the Edit cursor before "postchange" is sent for an editing key, through set_edit_pos() so that an override still sees every move by @penguinolog in urwid/urwid#1523

    Scroll a focused Edit with wrap="ellipsis" to the cursor: the row with the cursor is clipped and the other rows keep their ellipsis by @penguinolog in urwid/urwid#1523

Numeric edit widgets

    Accept negative string defaults in IntegerEdit by @IlyaKhalafi in urwid/urwid#1436

    Apply FloatEdit separators to default values by @IlyaKhalafi in urwid/urwid#1434

    Fix FloatEdit exponent defaults and long-value quantization by @charan-rathore in urwid/urwid#1447

    Refuse a second decimal separator in FloatEdit by @nk-batman21 in urwid/urwid#1493

    Keep a lone zero in numeric edit widgets by @nk-batman21 in urwid/urwid#1487

    Trim leading zeros after the minus sign in NumEdit by @penguinolog in urwid/urwid#1489

    Send IntEdit change signals at most once per key: not again for the leading zeros it removes, and not at all when the text stays the same by @penguinolog in urwid/urwid#1523

Progress bar

    Preserve Unicode labels in progress bars by @IlyaKhalafi in urwid/urwid#1432

    Fix early completion for very large finite progress values by @charan-rathore in urwid/urwid#1507

BigText fonts

    Draw 0, S, I and | of the BigText fonts apart from O, 5 and l, which they matched, and slope the Half Block 5x4 backtick the right way by @penguinolog in urwid/urwid#1521

Other displays and utilities

    Send the web display’s “polling child” update as UTF-8 bytes, which socket.sendall() requires, watch the LCD serial port by its fileno(), and stop split_repr from recursing in subclasses by @penguinolog in urwid/urwid#1410

Documentation 🕮

    Complete the parameter, return, exception and warning fields in docstrings by @penguinolog in urwid/urwid#1494

    Forward the mouse to the child in the terminal demo by @penguinolog in urwid/urwid#1503

    Document receiving Ctrl+S and Ctrl+Q as keys through tty_signal_keys(start="undefined", stop="undefined") by @penguinolog in urwid/urwid#1293

Refactoring 🛠

    Cover all refurb warnings by @penguinolog in urwid/urwid#1185
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

set_alarm_in callbacks: a wrong signature kills the entire MainLoop with a misleading traceback

2 participants