Skip to content

fix(tests): Windows-aware path-list split and UTF-8 progress output in parallel runner - #57152

Closed
lEWFkRAD wants to merge 1 commit into
NousResearch:mainfrom
lEWFkRAD:fix/test-runner-windows-pathsep
Closed

fix(tests): Windows-aware path-list split and UTF-8 progress output in parallel runner#57152
lEWFkRAD wants to merge 1 commit into
NousResearch:mainfrom
lEWFkRAD:fix/test-runner-windows-pathsep

Conversation

@lEWFkRAD

@lEWFkRAD lEWFkRAD commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Fixes two pre-existing Windows bugs in the parallel test runner (scripts/run_tests_parallel.py), both verified on main @ 30e947e on Windows 11:

  1. Drive-letter-safe path-list splitting. --files, --paths, and HERMES_TEST_PATHS were split with a naive .split(":"), which shreds absolute Windows paths at the drive letter: --paths C:\repo\tests became ['C', '\repo\tests']. The bogus C turned into a phantom discovery root (visible in the discovery banner), and the rooted remainder only resolved by accident of WindowsPath.__truediv__ re-anchoring it onto repo_root's drive — point it at another drive and discovery silently finds nothing. Two roots joined with os.pathsep (;) were shredded even worse. A new _split_pathspec() helper keeps : as the separator on POSIX and, on Windows, accepts both ; (os.pathsep) and : while keeping drive-letter colons glued to their paths — so the :-joined repo-relative lists emitted by the CI generate job keep working unchanged on every platform.

  2. Per-file progress lines no longer vanish on piped Windows output (this is what made tests/test_run_tests_parallel.py::test_bare_value_flag_keeps_its_value fail on win32). With stdout attached to a pipe (CI, subprocess capture, redirection), Windows encodes it with the legacy ANSI code page (cp1252), which cannot encode the / glyphs — every _print_progress() call raised UnicodeEncodeError inside the ThreadPoolExecutor done-callback, so all per-file progress lines were silently swallowed (with traceback spam on stderr). The failing test was a symptom: it asserts "1✓" in stdout or "1 passed" in stdout, but the 1✓ line never printed and the ASCII summary reads 1 tests passed, which doesn't contain the substring 1 passed. The runner now reconfigures its own stdout/stderr to UTF-8 (errors="replace") on Windows at the top of main(), and the test helpers decode the captured output as UTF-8 explicitly so the glyphs round-trip instead of turning into mojibake.

The runner fix (not an assertion relaxation) was chosen for bug 2 because losing every per-file progress line under CI/redirection is a real product defect, not just a test-expectation mismatch.

Related Issue

Fixes #57149

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)

Changes Made

  • scripts/run_tests_parallel.py
    • New _split_pathspec() — drive-letter-aware splitting for --files / --paths / HERMES_TEST_PATHS; both call sites switched to it; help text and module docstring updated.
    • main() reconfigures sys.stdout/sys.stderr to UTF-8 with errors="replace" on win32 (guarded, no-op elsewhere).
  • tests/test_run_tests_parallel.py
    • _run_runner() and the inline subprocess.run capture the runner's output with encoding="utf-8", errors="replace" (previously locale-dependent text=True).
    • New regression test test_multiple_absolute_paths_split_on_pathsep (all platforms): two absolute roots joined with os.pathsep are both discovered.
    • New regression test test_drive_letter_colon_is_not_a_path_separator (win32-only): no phantom drive-letter root in the discovery banner.

How to Test

  1. On Windows, on main @ 30e947e: python -m pytest tests/test_run_tests_parallel.py::test_bare_value_flag_keeps_its_value -x → fails; the captured runner output shows the phantom ['C', 'C:\\...'] discovery root and a UnicodeEncodeError traceback from the progress callback.
  2. On this branch: python -m pytest tests/test_run_tests_parallel.py -q6 passed, 1 skipped (the skip is the POSIX-only zombie-cleanup verifier).
  3. Manual: python scripts/run_tests_parallel.py --paths C:\abs\path\to\tests -j 1 -q | more → discovery banner shows a single intact root and the per-file progress line survives the pipe.
  4. On POSIX nothing changes: :-joined lists (including CI's generate-job output) split exactly as before.

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/ -q and all tests pass (full tests/test_run_tests_parallel.py suite; runner also exercised end-to-end)
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: Windows 11 (Python 3.11)

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — runner docstring + --paths/--files help text
  • I've updated cli-config.yaml.example if I added/changed config keys — N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — POSIX splitting behavior is byte-for-byte unchanged; UTF-8 reconfigure is win32-only
  • I've updated tool descriptions/schemas if I changed tool behavior — N/A

Screenshots / Logs

Before (win32, piped stdout):

Discovered 1 test files (~2 tests) under ['C', 'C:\\Users\\...\\probe']; running with -j 1
exception calling callback for <Future at 0x25e25b00850 state=finished returned tuple>
  ...
  File "scripts\run_tests_parallel.py", line 437, in _print_progress
    print(msg, flush=True)
UnicodeEncodeError: 'charmap' codec can't encode character '✓' in position 21: character maps to <undefined>
=== Summary: 1 files, 1 tests passed, 0 failed (100% complete) in 2.4s (1 workers) ===

After (win32, piped stdout):

Discovered 1 test files (~11 tests) under ['tests\\test_run_tests_parallel.py']; running with -j 1
[100.0% |    11/~11 | ✓1 | ✗0] ✓ tests\test_run_tests_parallel.py (1✓, 22.9s)
=== Summary: 1 files, 1 tests passed, 0 failed (100% complete) in 22.9s (1 workers) ===
$ python -m pytest tests/test_run_tests_parallel.py -q
6 passed, 1 skipped in 69.75s (0:01:09)

…n parallel runner

Two Windows bugs in scripts/run_tests_parallel.py:

- --files/--paths/HERMES_TEST_PATHS were split on ':', which shreds
  absolute Windows paths at the drive letter ('C:\repo\tests' ->
  ['C', '\repo\tests']): the drive letter became a phantom discovery
  root and the rooted remainder only resolved by WindowsPath
  re-anchoring it onto repo_root's drive. New _split_pathspec() keeps
  drive-letter colons glued to their path and accepts ';' (os.pathsep)
  on Windows, while ':'-joined lists (CI generate job) keep working.

- With piped stdout (CI, subprocess capture) Windows encodes the
  runner's output as the ANSI code page, so printing the per-file
  progress glyphs raised UnicodeEncodeError inside the executor
  done-callback and every progress line was silently lost -- which is
  also why test_bare_value_flag_keeps_its_value failed on win32 (no
  '1[check]' line, and the summary says '1 tests passed', which does not
  contain '1 passed'). The runner now reconfigures its own
  stdout/stderr to UTF-8 on Windows, and the tests decode the captured
  output as UTF-8.

Adds regression tests: os.pathsep-joined absolute roots (all
platforms) and no-phantom-drive-root (win32).

Fixes NousResearch#57149
@alt-glitch alt-glitch added type/bug Something isn't working platform/windows Native Windows-specific behavior or breakage P3 Low — cosmetic, nice to have sweeper:risk-platform-windows Sweeper risk: may break or behave differently on native Windows labels Jul 2, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Fix PR for #57149 (issue↔PR pair). This is a superset of the open #51896, which fixes only the legacy-encoding (UnicodeEncodeError) half of the same file — this PR fixes both that and the drive-letter path-list split. Related to the broader Windows test-runner compat work in #42775. Flagging the #57152 / #51896 overlap so a maintainer picks one.

@teknium1 teknium1 added sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 15, 2026
@teknium1

Copy link
Copy Markdown
Contributor

Thanks for the focused Windows compatibility fix. The current-main implementation still has the two reported failure mechanisms: scripts/run_tests_parallel.py:751 and :759 split path lists with ":", while :389-436 emits Unicode progress glyphs without configuring Windows output streams.

Problems

  • The new coverage in tests/test_run_tests_parallel.py exercises the --paths route, but the PR also changes the --files and HERMES_TEST_PATHS routes in scripts/run_tests_parallel.py. Those advertised interfaces have no direct regression coverage, so a future wiring mistake there would escape the suite.

Suggested changes

  • Add an end-to-end test for --files and one for HERMES_TEST_PATHS, ideally parameterized with the existing path-list fixture. Retain the win32-only drive-letter assertion for the Windows-specific behavior.

This is an automated hermes-sweeper review.

@teknium1

teknium1 commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Half merged in #81965: your _split_pathspec drive-letter fix + tests are on main with authorship. The stdio-UTF-8 half was superseded by July's _make_stdio_glyph_safe on main (pin-to-utf-8 with replace fallback — same goal, stronger form). Thanks!

@teknium1 teknium1 closed this Aug 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P3 Low — cosmetic, nice to have platform/windows Native Windows-specific behavior or breakage sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-platform-windows Sweeper risk: may break or behave differently on native Windows type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

run_tests_parallel.py on Windows: ':' path-list split breaks drive letters; per-file progress lines lost to UnicodeEncodeError on piped stdout

3 participants