headroom/tests/test_compression
Ashish 6cdb846200
fix(compression): use thread-local tree-sitter parsers in code handler (#893)
## Description

`CodeStructureHandler` cached tree-sitter parsers in a process-global
dict; the lock only guarded creation, while `parse()` ran unlocked on
any thread. tree-sitter `Parser` objects are pyo3 `unsendable` — using
one from a non-creator thread panics. The proxy invokes handlers from
executor pool threads, so a shared parser is an eventual crash. Same
class already fixed in `transforms/code_compressor.py` (#604). Stacked
on #892.

Closes # <!-- compression-handler review -->

## Type of Change

- [x] Bug fix (non-breaking change that fixes an issue)
- [ ] New feature (non-breaking change that adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] Documentation update
- [ ] Performance improvement
- [ ] Code refactoring (no functional changes)

## Changes Made

- `headroom/compression/handlers/code_handler.py`: one parser per
(thread, language) via `threading.local()`, porting the pattern from
`transforms/code_compressor.py`.
- `tests/test_compression/test_code_handler.py`: regression test parsing
from a 4-worker thread pool, asserting every call stays on the
tree-sitter path.

## Testing

- [x] Unit tests pass (`pytest`)
- [x] Linting passes (`ruff check .`)
- [x] Type checking passes (`mypy headroom`)
- [x] New tests added for new functionality
- [x] Manual testing performed

### Test Output

```text
$ pytest tests/test_compression/ -q
94 passed, 8 skipped
```

## Real Behavior Proof

- Environment: local macOS, Python 3.11, tree-sitter-language-pack
1.8.1, branch `fix/code-threadlocal-parsers` (stacked on #892).
- Exact command / steps: `pytest tests/test_compression/ -q`.
- Observed result: 16 parses across a 4-worker pool all stay on the
tree-sitter path with no pyo3 panic; previously a shared parser would be
touched cross-thread.
- Not tested: Reproducing the original panic under production
concurrency (covered structurally by the thread-pool test).

## Review Readiness

- [x] I have performed a self-review
- [x] This PR is ready for human review

## Checklist

- [x] My code follows the project's style guidelines
- [x] I have performed a self-review of my code
- [x] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] I have updated the CHANGELOG.md if applicable

## Screenshots (if applicable)

N/A — library change. See Test Output.

## Additional Notes

Stacked on #892 — review the top commit until that merges. PR 5 of 7.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: JD Davis <mxjerrett@gmail.com>
2026-06-15 16:38:08 -05:00
..
__init__.py Add universal compression module with ML-based content detection 2026-01-15 15:26:14 -08:00
test_code_handler.py fix(compression): use thread-local tree-sitter parsers in code handler (#893) 2026-06-15 16:38:08 -05:00
test_evals.py Remove LLMLingua: Kompress is the sole text compressor 2026-03-26 11:11:00 -07:00
test_json_handler.py fix(compression): measure short-value threshold on payload, not token (#889) 2026-06-15 10:23:26 -05:00
test_llm_eval.py Remove LLMLingua: Kompress is the sole text compressor 2026-03-26 11:11:00 -07:00
test_masks.py Add universal compression module with ML-based content detection 2026-01-15 15:26:14 -08:00
test_universal.py Remove LLMLingua: Kompress is the sole text compressor 2026-03-26 11:11:00 -07:00