fix(cli): set UTF-8 stdout in the console entry point - #2096
Conversation
The garak console script is declared as garak.__main__:main, so it calls main() directly and never runs the `if __name__ == "__main__"` block that reconfigured stdout to UTF-8. Redirected or piped output then truncated at the first emoji. Signed-off-by: Mohammed Alkindi <alkndymhmd692@gmail.com>
|
thanks, this seems reasonable. will take a look. |
jmartin-tech
left a comment
There was a problem hiding this comment.
I see the reasoning for this, since this is in __main__.py I think it is reasonable
I can see a concern with changing sys.stdout configuration in ways that might be triggered during library based import as an unexpected side-effect for the caller, though I think that is highly unlikely for this particular entry point as access to sys.argv should clearly signal to an integrator that this entry point should not be called directly by a wrapper.
Due to a recent upstream dependency lock need please rebase this PR on commit 3845757 or newer from main to enable CI/CD execution to pass.
Signed-off-by: Mohammed Alkindi <alkndymhmd692@gmail.com>
|
Picked up 3845757, though as a merge rather than a rebase — force-pushes are blocked in my setup, so the branch carries it as a merge commit instead of linear history. Say the word if you need it rebased properly and I'll sort that out. On the stdout concern: the reconfigure now sits inside |
|
CI is green and the rebase request is satisfied. The branch contains 3845757 ( On the import side-effect: the It landed as a merge commit rather than a rebase because force-pushing is blocked on my side. If you want linear history before this merges, say so and I will send a replacement PR from a fresh branch. |
On Windows,
garak <anything> > file.txtsilently truncates its output at the first emoji and still exits 0.[project.scripts]declares the console script asgarak.__main__:main, so it callsmain()directly and never runs theif __name__ == "__main__"block — which is wheresys.stdout.reconfigure(encoding="utf-8")lived.python -m garakdoes run that block, so the two entry points behave differently. When stdout is a pipe or a file, Python falls back to the ANSI code page (cp1252 here, cp936/cp932 elsewhere), and the first🌟in the plugin listing kills the write.CI does not see this because
test_windows.ymlsetsPYTHONUTF8: 1andPYTHONIOENCODING: utf-8. Those are not mentioned anywhere in the README or docs, so users do not have them set.This moves the one line into
main()so both entry points behave the same. It follows whatgarak/analyze/*already does — 11 of those scripts callsys.stdout.reconfigure(encoding="utf-8")themselves.Reproduction
Windows 11, Python 3.13.13, clean venv, no
PYTHONUTF8/PYTHONIOENCODINGset.Before:
probes.txtends mid-line, with the codec error written into stdout rather than raised:After: 234 lines, 560 non-ASCII bytes, no codec error — byte-identical to what
python -m garak --list_probesalready produced.Verification
python -m pytest tests/test_main_entrypoint.py— 1 passed, and fails onmainwithUnicodeEncodeError: 'charmap' codec can't encode character '\U0001f31f'python -m pytest tests/cli tests/test_config.py tests/test_configurable.py— 119 passedpython -m pytest tests/cli tests/test_config.py tests/test_main_entrypoint.py— 110 passed, new test passes in companypython -m garak --list_probesoutput is unchanged; the reconfigure just moved, so the-mpath still gets it exactly onceThe new test forces
PYTHONIOENCODING=cp1252in a subprocess, so it reproduces the failure on any OS rather than only on Windows.I did not run the full
tests/suite — several suites pull models and remote resources that I could not fetch here. I ran the CLI and config suites, which are the ones this change can affect.Not a duplicate
I checked open PRs for this symptom (
reconfigure,PYTHONUTF8,PYTHONIOENCODING,charmap,UnicodeEncodeError) and found none. #1790 does touchgarak/__main__.py, but it wraps the call assys.exit(cli.main(...))for exit codes and does not change the encoding behaviour — a different defect, and adjacent lines in the same small function, so the two may need sequencing.Worth noting the exit-code angle separately: the failure here surfaced as exit 0 with the error text on stdout, which is arguably its own bug. I have deliberately left that alone to keep this PR to one concern.
AI assistance
AI assistance was used for this change. I reviewed every changed line and ran the test commands listed above myself; the before/after output quoted here is from my own machine.
One deviation from AGENTS.md to flag rather than leave silent: I have not added a
Co-authored-by:commit trailer. My personal attribution policy is that commits carry only my identity and AI involvement is disclosed in prose, as it is here. Happy to add the trailer if you would rather the disclosure be in the commit metadata too.