tmux-python / tmux-python/libtmux
`Server.__repr__` hard-codes `/tmp/tmux-<euid>/default`, ignoring `$TMUX_TMPDIR`
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 1.2k
- Forks
- 127
- Avg merge
- 2h 13m
- Merged PRs (30d)
- 1
Description
Filed against tmux-python/libtmux v0.62.0. Found while writing tested documentation examples: the repr appeared in a pytest failure banner and named a socket the object was not talking to.
What happens
Server.__repr__ falls through to a hard-coded /tmp/tmux-<euid>/default when both socket_name and socket_path are None. tmux does not hard-code that path — it resolves the socket directory from $TMUX_TMPDIR, or /tmp when that is unset. TMPDIR is not consulted — 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=$t tmux still lands in /tmp/tmux-1000/default). So under any TMUX_TMPDIR (test harnesses, sandboxes, containers, anyone with TMUX_TMPDIR exported in their shell profile) the repr names a socket the object is not using.
src/libtmux/server.py#L2681-L2692— the__repr__fall-through
return (
f"{self.__class__.__name__}(socket_path=/tmp/tmux-{os.geteuid()}/default)"
)
This is a display bug, not a behaviour bug — the object talks to the right socket. But repr is what shows up in tracebacks, pytest --showlocals banners, logs, and print(server), which is exactly where someone is trying to work out which server they are looking at.
Recreation
import os, tempfile
os.environ["TMUX_TMPDIR"] = tempfile.mkdtemp(prefix="repro-")
from libtmux.server import Server
server = Server()
server.new_session(session_name="demo")
print("repr(server) :", repr(server))
print("actual socket_path:", server.cmd("display-message", "-p", "#{socket_path}").stdout[0])
server.kill()
Observed on libtmux v0.62.0 / tmux 3.7b:
repr(server) : Server(socket_path=/tmp/tmux-1000/default)
actual socket_path: /tmp/repro-pa15_hfr/tmux-1000/default
Expected: a repr that either names the real socket, or does not claim to know it.
Why the fall-through is reachable at all
Server.__init__ only assigns socket_path when the caller passes it, so a bare Server() has socket_name is None and socket_path is None and always lands in this branch.
That is the same root cause as #704 item 1 (the TMUX_TMPDIR-based socket_path derivation in __init__ being unreachable dead code). If #704 is fixed by repairing that derivation, socket_path becomes populated and this branch stops being reached for the common case — but the branch is still wrong and should not survive as a fallback.
What a fix needs
Pick one, in descending order of preference:
- Resolve the path the way tmux does and use it: socket directory is
$TMUX_TMPDIR, else/tmp, thentmux-<euid>/<socket_name or "default">. This also givessocket_patha correct value to return generally, and overlaps with #704. - Do not guess. Render
Server(socket_path=None)or justServer()when neither attribute is set. Honest, and cheap.
Note that libtmux already computes this, in the one place that needed it:
# ``Server(socket_name=...)`` does not populate ``socket_path`` --
# the Server class only derives the path when neither ``socket_name``
# nor ``socket_path`` was supplied. Recompute the location tmux uses
tmux_tmpdir = pathlib.Path(os.environ.get("TMUX_TMPDIR", "/tmp"))
socket_path = tmux_tmpdir / f"tmux-{os.geteuid()}" / socket_name
So the fix is less "write new logic" than "lift the logic the test plugin was forced to write into somewhere Server can use it too". src/libtmux/_internal/env.py already owns the tmux-environment readers and is the natural home.
Whichever is chosen, add a regression test that sets TMUX_TMPDIR via monkeypatch and asserts the repr does not contain a path outside it. Note the existing repr has a second oddity worth cleaning up in the same pass: the socket_name branch uses getattr(self, 'socket_name', 'default') even though it has already established self.socket_name is not None.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in src/libtmux/server.py at Server.repr and Server.init, then compare the TMUX_TMPDIR handling in src/libtmux/pytest_plugin.py and the environment helpers in src/libtmux/_internal/env.py. Add a regression test using monkeypatch to set TMUX_TMPDIR and verify the repr does not name a path outside it.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- cli
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 72/100