tmux-python / tmux-python/libtmux

`show_option` coerces user options, so an `@` option set to `123` or `on` comes back as an int or a bool

Open Beginner friendly
#759 0 comments 0 reactions 0 assignees View on GitHub

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, tmux 3.6a.

What happens

convert_value applies tmux's built-in option coercion to every value, and the call sites reach user options too:

src/libtmux/options.py#L245convert_values, dict branch
src/libtmux/options.py#L1216_show_option, direct lookup

tmux(1) defines a user option as carrying an arbitrary string:

tmux also supports user options which are prefixed with a '@'. User options may have any name, so long as they are prefixed with '@', and be set to any string.

So a user option does not survive the round trip when its value happens to read as a tmux boolean or a number:

set show_option returns type
123 123 int
on True bool
off False bool
true 'true' str
3.5 '3.5' str

show_options() returns the same converted values.

The coercion is right for built-in options — tmux really does use on/off there. For a @ name it is also not self-consistent: on converts but true does not, 123 converts but 3.5 does not.

Repro

import libtmux

server = libtmux.Server(socket_name="probe")
pane = server.new_session("probe").windows[0].panes[0]

for raw in ("123", "on", "off", "true", "3.5"):
    pane.cmd("set-option", "-p", "@probe", raw)
    got = pane.show_option("@probe")
    print(f"{raw!r:8} -> {got!r:8} {type(got).__name__}")
'123'    -> 123      int
'on'     -> True     bool
'off'    -> False    bool
'true'   -> 'true'   str
'3.5'    -> '3.5'    str

Why it bites

A @ option is the natural place to stamp an identity on a pane. When that identity is user-supplied, someone who names a thing 123, on or off gets back a value that no longer compares equal to what they set, so the pane cannot be found again.

Found while fixing awslabs/cli-agent-orchestrator, where it made a terminal named 123 unaddressable.

Note

The module docstring already treats these as their own category:

There are also custom user options, preceded with @, which exist are stored to Options.context.user_options as a dictionary.

Options.context.user_options does not appear anywhere else in the source, so that looks like an intent that was never implemented.

I have a patch that guards both call sites on the @ prefix and adds the round-trip case to test_custom_options. Built-in options keep converting (exit-unattachedFalse, history-limit2000). Happy to open it as a PR if you want it shaped that way — it changes behaviour for anyone relying on the current conversion, so it seemed like your call rather than mine.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in src/libtmux/options.py at convert_values around line 245 and _show_option around line 1216, then read the existing test_custom_options coverage. Verify the behavior for @ options using the reported values, while confirming built-in options such as exit-unattached and history-limit still undergo conversion. Done means user-option strings round-trip unchanged and the relevant tests pass.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
api
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
88/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.