docs(automation_patterns): the wait helpers never wait — the marker matches the command echo

Aperta
#706 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
3/5
Tempo stimato
1-2 giorni
Idoneità per principianti
72/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Tranquilla
Stack tecnologico
python
Ambito
documentation

Direzione di ricerca

Start with docs/topics/automation_patterns.md and review the wait_for_output and capture_after_marker examples, then read Server.wait_for() in src/libtmux/server.py. Run the page's doctests or the automation_patterns.md[4] check and add assertions covering delayed output, timeout, and captured command output. Done means the documented helpers no longer return on the echoed command and the examples reliably pass.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

bug

Bug

Both wait helpers taught in docs/topics/automation_patterns.md return before the command they are waiting on has produced any output, because the shell echoes the command line and the marker is matched in that echo.

Same root cause as #654, but in the documentation — so it is the pattern readers copy into their own code.

The two helpers fail differently, and the quieter one is the worse one:

helper failure
wait_for_output always returns True immediately. timeout and poll_interval are dead parameters. Its doctest passes vacuously — it would pass if the command never ran at all.
capture_after_marker its poll loop exits on the first capture, so timeout=2.0 never waits; the only real wait is a bare time.sleep(0.3). Visibly flaky — automation_patterns.md[4] fails intermittently.

Root cause

send-keys types the command into the pane, and the shell echoes it back before running it. The echoed line contains the marker string, so a substring match over capture_pane() succeeds instantly.

docs/topics/automation_patterns.md#L137-L139:

>>> monitor_pane.send_keys('sleep 0.2; echo "READY"')
>>> wait_for_output(monitor_pane, 'READY', timeout=2.0)
True

READY is in sleep 0.2; echo "READY" — the command itself. The helper matches the echo, not the output.

Reproduction

The helper verbatim from the page, with the sleep raised so the race is unmissable:

pane.send_keys('sleep 2.0; echo "READY"')
got = wait_for_output(pane, "READY", timeout=5.0)   # helper copied from the docs

Observed:

wait_for_output(...) returned True after 0.02s
the command needs >= 2.0s to print READY
screen at that moment:
   'sleep 2.0; echo "READY"'      <- only the echo; no output yet

Observed: True in 0.02 s.
Expected: blocks ~2 s, then True — or False on timeout.

capture_after_marker fails the same way: its first captured line containing MARKER is index 0, the echoed command.

Suggested fix

Teach tmux wait-for rather than polling for a string. libtmux already wraps it — Server.wait_for() — and it is race-free by construction: no marker, no poll interval, no sleep.

pane.send_keys('sleep 2.0; echo "captured data"; tmux wait-for -S done')
server.wait_for('done')            # blocks until the command actually finished
result = pane.capture_pane()

There is no lost-wakeup race even if the command finishes before the wait is issued. From tmux's cmd-wait-for.c:

/* signal: nobody waiting yet -> remember it */
if (TAILQ_EMPTY(&wc->waiters) && !wc->woken) { wc->woken = 1; return (CMD_RETURN_NORMAL); }

/* wait: already woken -> return at once */
if (wc->woken) { cmd_wait_for_remove(wc); return (CMD_RETURN_NORMAL); }

Inside a pane $TMUX is already set, so a bare tmux wait-for -S done reaches the right server with no extra wiring.

If a string-matching example is still wanted — reasonable for output you do not control — it must not be matchable against the echo. Either match per line and skip the echoed command (the fix proposed in #654), or use a sentinel that cannot appear in the command line, e.g. assemble it at runtime so the literal is never typed.

Tests

The page's doctests currently prove nothing, so they need to become real assertions:

  1. wait_for_output against a command that sleeps longer than the poll interval must take at least that long to return — that fails today.
  2. wait_for_output must return False on timeout when the text never appears (today it cannot, since it matches the echo).
  3. capture_after_marker must return the command's output, not the tail of the echoed line.

Related

  • #654 — same root cause, in a test rather than the docs
  • #484, #456 — adjacent capture_pane reliability

Environment

  • libtmux: v0.61.0 (both helpers unchanged since the tag)
  • tmux: 3.7b
  • Python: 3.14
Lingua principale
Python
Stelle
1.2k
Fork
127
Merge medio
2h 13m
PR unite (30g)
1

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di tmux-python/libtmux

Tutte le issue di tmux-python/libtmux

Issue simili

Altre issue su Python

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.