Format an empty set as set() in the console exporter

Merged
CH
1d ago
+35-2

The console exporter prints an empty set as {}, the same text as an empty dict, because JsonArgsValueFormatter sends sets through _format_list_like with {/} and an empty list writes nothing between them. An empty frozenset comes out as frozenset({}).

# base 56c8455, python 3.12; repro.py calls logfire.configure(send_to_logfire=False,
# console=ConsoleOptions(verbose=True, colors='never')) and then
# logfire.info('tags', tags=set(), frozen=frozenset(), mapping={})
$ python repro.py | tail -3
│ tags={}
│ frozen=frozenset({})
│ mapping={}
$ python repro.py | tail -3   # this branch
│ tags=set()
│ frozen=frozenset()
│ mapping={}

Both formatters now write set() and frozenset() for an empty value, as repr() does, the way empty_tuple already gives (). A non-empty set goes through _format_list_like unchanged.

Verification

$ uv run --no-sync pytest -n 4 -q tests/test_json_args_formatting.py tests/test_json_args.py tests/test_console_exporter.py
336 passed   # this branch, rebased on c711ee6, Python 3.14.7
332 passed   # base c711ee6
$ # same command with json_formatter.py reverted, tests kept
4 failed, 332 passed   # the four new empty_set / empty_frozenset cases
$ uv run --no-sync ruff check <both files> && uv run --no-sync ruff format --check <both files>   # ruff 0.16.10
All checks passed!
2 files already formatted
$ uv run --no-sync pyright logfire-sdk/logfire/_internal/json_formatter.py tests/test_json_args_formatting.py
0 errors, 0 warnings, 0 informations
# not run: the full suite

There is no issue for this. It follows #2534 and #2591, which fixed range and bytearray in the same formatter.

@alexmojaki, I'd keep this to set and frozenset, since deque and tuple already print an unambiguous empty value. Anything else you'd want covered here?