Skip to content

Resolve the socket path in Server's repr instead of hard-coding /tmp - #727

Open
tony wants to merge 1 commit into
masterfrom
fix/723-repr-socket-dir
Open

Resolve the socket path in Server's repr instead of hard-coding /tmp#727
tony wants to merge 1 commit into
masterfrom
fix/723-repr-socket-dir

Conversation

@tony

@tony tony commented Jul 29, 2026

Copy link
Copy Markdown
Member

Summary

  • Fix repr(Server()) naming a socket the object is not talking to. The fall-through branch hard-coded /tmp/tmux-<euid>/default, but tmux resolves its socket directory from $TMUX_TMPDIR, so under a test harness, a sandbox, a container, or anyone with TMUX_TMPDIR exported the repr was simply wrong.
  • Add libtmux._internal.env.resolve_socket_path(), which computes tmux-<euid>/<socket_name or "default"> under $TMUX_TMPDIR, falling back to /tmp.
  • Replace the inline copy of that computation in pytest_plugin._reap_test_server, which carried a comment explaining it had to recompute what Server would not tell it. Both callers now share one resolver.
  • Remove a getattr(self, 'socket_name', 'default') in the socket_name branch that ran after self.socket_name is not None had already been established.

Display-only: which socket the object talks to is unchanged.

Why the repr matters

A repr is what appears in tracebacks, --showlocals banners, logs, and print(server) — precisely where someone is trying to work out which server they are looking at. Naming the wrong socket there is worse than naming none.

Before / After

Under a TMUX_TMPDIR:

repr(server)       # Server(socket_path=/tmp/tmux-1000/default)
server.cmd("display-message", "-p", "#{socket_path}").stdout[0]
                   # /tmp/repro-JxuS/tmux-1000/default
repr(server)       # Server(socket_path=/tmp/repro-JxuS/tmux-1000/default)
server.cmd("display-message", "-p", "#{socket_path}").stdout[0]
                   # /tmp/repro-JxuS/tmux-1000/default

With TMUX_TMPDIR unset the output is byte-identical to before, which is why the three shipped doctests that assert this repr needed no edit.

Design decisions

$TMUX_TMPDIR or /tmp, and nothing else. TMPDIR is deliberately not consulted, because tmux does not consult it either — man tmux: "the sockets are all created in a directory tmux-UID under the directory given by TMUX_TMPDIR or in /tmp". Confirmed empirically on tmux 3.7b: TMPDIR=<dir> tmux -L probe still lands in /tmp/tmux-1000/probe. Consulting TMPDIR would have broken the existing doctests on any machine that exports it.

Computed, not observed. The helper says where tmux would put the socket, not that a daemon is listening. Its docstring says so and points live callers at the #{socket_path} format instead. Server.__repr__ is the only non-test consumer, and it is display-only.

Lives in _internal. libtmux._internal.env already owns the tmux-environment readers (resolve_env, socket_path_from_env, pane_id_from_env), so this adds no public API surface.

Empty TMUX_TMPDIR is treated as unset. Verified against tmux 3.7b, where TMUX_TMPDIR= tmux -L probe also lands in /tmp.

Scope

Repairing the unreachable socket_path auto-derivation in Server.__init__ is deliberately not in this PR — that is a behaviour change with wider blast radius, tracked separately. This resolver would make it a small change, though.

Test plan

  • test_repr_socket_path_honors_tmux_tmpdir — sets TMUX_TMPDIR via monkeypatch and asserts the repr names a path inside it; fails on master
  • test_repr_socket_name — covers the getattr removal (behaviour-preserving, so it passes either way)
  • Doctests on Server.__repr__ and resolve_socket_path, which are collected and run
  • The three shipped doctests asserting the old output still pass unedited: README.md, docs/quickstart.md, docs/api/libtmux.neo.md
  • uv run ruff check . / uv run ruff format . / uv run mypy clean
  • uv run py.test --reruns 0 clean
  • just build-docs clean

Note for the merger

The CHANGES entry cites the issue number; swap it for this PR's number on merge. CHANGES will conflict with the sibling PRs for #724, #725 and #726, which all add to the same block — keep both sides.

why: The repr fell through to a hard-coded /tmp/tmux-<euid>/default when
neither socket_name nor socket_path was given, which is every bare
Server(). tmux resolves its socket directory from $TMUX_TMPDIR, so under
a test harness, sandbox, or container the repr named a socket the object
was not talking to -- in tracebacks, --showlocals banners, and logs,
which is where someone is trying to tell servers apart. Closes #723.

what:
- Add libtmux._internal.env.resolve_socket_path(), which resolves
  tmux-<euid>/<socket_name or "default"> under $TMUX_TMPDIR, else /tmp
  ($TMPDIR is not consulted, matching tmux)
- Use it for the Server.__repr__ fall-through, and for the socket unlink
  in pytest_plugin._reap_test_server, which had to compute it inline
- Drop the getattr(self, 'socket_name', 'default') in the socket_name
  branch, which had already established socket_name is not None
- Add regression tests setting $TMUX_TMPDIR via monkeypatch
@codecov

codecov Bot commented Jul 29, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 30.00000% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 52.28%. Comparing base (be7c8c1) to head (8f437fa).

Files with missing lines Patch % Lines
src/libtmux/_internal/env.py 22.22% 7 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #727      +/-   ##
==========================================
- Coverage   52.45%   52.28%   -0.17%     
==========================================
  Files          26       26              
  Lines        3729     3737       +8     
  Branches      747      747              
==========================================
- Hits         1956     1954       -2     
- Misses       1469     1479      +10     
  Partials      304      304              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant