Tags: tmux-python/tmuxp
Tags
tests(perf[conftest]) Pin \$SHELL=/bin/sh in autouse fixture why: Profiling tmuxp's test suite showed the dominant per-pane cost was tmux spawning the contributor's interactive \$SHELL — typically ``/bin/zsh`` with a full rcfile chain (oh-my-zsh, plugins, prompt themes, etc.) — for every pane created across the suite. Each init costs ~60ms warm and up to ~400ms cold; multiplied across hundreds of pane spawns in workspace/builder tests, that's the single largest line item in suite wall time. tmux falls back to ``\$SHELL`` for new panes when ``default-shell`` is unset (the default in libtmux's bundled test ``.tmux.conf``), so monkey-patching \$SHELL=/bin/sh in an autouse function-scoped fixture forces every test pane to spawn ``/bin/sh`` instead. Empty rcfiles, deterministic prompt, no plugin chains. A/B measured locally with the project's standard ``uv run py.test`` (defaults: ``--reruns=0 --doctest-modules``): master ~76-78s pytest, ~71s wall this branch (1st run) 37.01s pytest, 35.08s wall this branch (2nd run) 36.24s pytest, 34.29s wall That's a ~51% wall-time reduction, consistent with the upstream libtmux PR (tmux-python/libtmux#662) that pins the same env var in libtmux's pytest plugin and reports a similar "~70s -> ~32s" delta. Applying the pin at the tmuxp conftest level lands the gain immediately without waiting for the libtmux PR to merge and release; once libtmux ships the upstream pin, this commit becomes redundant and can be reverted cleanly. what: - conftest.py: add ``_pin_test_shell_env`` function-scoped autouse fixture that calls ``monkeypatch.setenv("SHELL", "/bin/sh")``. ``monkeypatch`` restores the prior value at teardown so no global state leaks across tests or out of pytest's process. - Leading-underscore name signals "internal autouse plumbing" — no test should depend on it explicitly. - USING_ZSH constant and ``zshrc`` autouse-on-USING_ZSH fixture retained for now; they become dead at runtime once \$SHELL is always ``/bin/sh`` (no zsh first-run greeting to suppress) but the cleanup is left as a follow-up to keep this commit's diff minimal and the perf claim independently revertible.
workspace(refactor[builder]) route set-option loops through _bulk_set… …_options why: Workspace loading dispatches one tmux ``set-option`` per loop iteration across four hot loops (session ``options``, ``global_options``, per-window ``options``, ``options_after``). The helper that ``f4c95faa`` introduced provides a single, batch-shaped entry point for these calls; this commit moves the existing call sites onto it. Today the helper is a plain loop so this is a pure refactor (same N round-trips, same observable behaviour). Once libtmux exposes a pipelined ``Server.batch()`` the helper body can swap internally and the call sites automatically benefit without further changes here. what: - Replace the session ``options`` loop in ``build`` with ``_bulk_set_options(..., scope_flag="-s")`` targeting ``session.session_id``. - Replace the ``global_options`` loop in ``build`` with ``_bulk_set_options(..., target=None, scope_flag="-g")``. - Replace the per-window ``options`` loop in ``iter_create_windows`` with ``_bulk_set_options(..., scope_flag="-w")`` targeting ``window.window_id``. - Replace the ``options_after`` loop in ``_apply_options_after`` (or equivalent post-build hook) with ``_bulk_set_options(..., scope_flag="-w")`` targeting ``window.window_id``. Salvaged from libtmux-protocol@2390ce3b. The original commit described the change as a perf win; against current libtmux 0.56.0 the helper body issues N round-trips per call site (no ``Server.batch()`` yet), so this commit is documented as a refactor and the perf framing is deferred to whenever libtmux ships a batching API.
workspace(perf[builder]) batch set-option loops via _bulk_set_options why: workspace loading dispatches one tmux ``set-option`` per loop iteration across four hot loops (session options, global_options, window options, options_after). Each call is a separate round-trip; on libtmux's control_mode engine that's N stdin write+flush pairs for purely metadata work. Routing the loops through ``_bulk_set_options`` collapses each to one batched ``Server.batch()`` write+flush while leaving subprocess and imsg engines on their existing per-call cost. what: - Replace the session ``options`` loop (builder.py:579-581) with ``_bulk_set_options(..., scope_flag="-s")`` targeting the session_id. - Replace the ``global_options`` loop (builder.py:583-585) with ``_bulk_set_options(..., target=None, scope_flag="-g")``. - Replace the per-window ``options`` loop inside ``iter_create_windows`` (builder.py:730-731) with ``_bulk_set_options(..., scope_flag="-w")`` targeting the window_id. - Replace the ``options_after`` loop in ``config_after_window`` (builder.py:903-904) with the same window-scoped helper call. - ``set_environment`` loop and per-pane ``send_keys`` are intentionally untouched: different command shape and readiness-coupled sequencing respectively.
PreviousNext