helm: drop the codec import and relax the nltk pin, fixing the extra on Python 3.14 - #243
helm: drop the codec import and relax the nltk pin, fixing the extra on Python 3.14#243borgr wants to merge 4 commits into
Conversation
`pytest.importorskip('helm')` passes on a `helm` install whose
`helm.common.codec` does not import — the case on Python 3.14, where
crfm-helm's spacy dependency ships no wheel. The tests then fail at
collection with the converter's own ImportError instead of skipping.
Use the same condition as tests/test_helm_adapter.py: the converter's
`_HELM_IMPORT_ERROR`, which is the signal the converter itself acts on.
The converter needs six HELM modules, which pull in cattrs and nothing else. `helm.common.codec` pulls torch, spacy, nltk and regex, for one call in a file that already decodes three other HELM dataclasses with dacite. Decode the fourth the same way.
3.10.1 is the only release carrying the inisec import guard.
`pyproject.toml` relaxed the helm extra's cap to `nltk!=3.10.1` but the lock still recorded `<3.10.1`, so a resolve from the lockfile disagreed with the project it was locked from.
mrshu
left a comment
There was a problem hiding this comment.
⚒️ review-anvil report
Review decision: COMMENT — This is a focused compatibility improvement;
one medium-priority test-coverage suggestion remains.
Result: The codec removal and dependency relaxation look well targeted. The
review found one opportunity to make the full-dependency CI signal more robust.
Scope: Reviewed the four-file PR at d66facf1, including the HELM decoder,
dependency metadata, lockfile, and generation-argument tests.
Checks: Reproduction was not needed because two independent reviewers
identified the same concrete behavior from the exact head.
Second check: Targeted challenge with 2 Codex reviewers; both upheld the
finding, and one refined the proposed fix to cover local full-dependency runs
as well as CI.
Actionable suggestion
RAV-RUN1-R1-F001 [medium] Keep a failing signal for broken installed HELM dependencies
tests/test_helm_generation_args.py:17 now applies the
_HELM_IMPORT_ERROR skip to the whole module. That is useful for core installs,
but it also means the full CI rows can stay green if HELM is installed and one
of the guarded converter imports is broken—the same import-compatibility class
this PR is designed to improve. The other HELM tests skip on the same condition,
so they do not provide an independent full-install sentinel.
A small way to preserve both behaviors would be to move the skip marker onto
the generation-argument tests and add one unmarked sentinel test. That sentinel
can skip only when the top-level helm package is absent; when it is present,
it can call _require_helm_dependencies() and allow a broken converter import
to fail. This keeps core installs optional while making --all-extras CI and
equivalent local test runs verify that the installed HELM extra is usable.
Would-apply plan
- Keep the current generation-argument cases skipped when HELM is genuinely
unavailable. - Add one unmarked test that skips only for an absent
helmpackage and
otherwise calls_require_helm_dependencies(). - Confirm core-only runs skip cleanly and full-extra runs fail on a broken
guarded HELM import.
Run details
- Target: PR #243 (
fix/helm-extra-imports, 4 files, +35/-19) - Head reviewed:
d66facf1a24e53e9f84172425c7e1368789ea9a2 - Rounds: 1/1 completed
- Mix: 3
codex-execreviewers - Reviewer timeout: 1200 seconds
- Adversarial mode: targeted (2 Codex challengers)
- Focus: constructive, positive review language and optional suggestions while
preserving technical accuracy - Earlier review comments: none
Reviewed with review-anvil.
| # `import helm` alone is not enough: on Python 3.14 the top-level package imports | ||
| # but `helm.common.codec` does not, so the converter's own import guard is the | ||
| # only reliable signal. Same condition as tests/test_helm_adapter.py. | ||
| pytestmark = pytest.mark.skipif( |
There was a problem hiding this comment.
RAV-RUN1-R1-F001 [medium] tests — Nice improvement over checking only import helm: the converter guard is the right signal for these cases. One follow-up worth considering is preserving a failing signal when HELM is installed but a guarded converter import is broken. Because this module-wide marker skips for every _HELM_IMPORT_ERROR, the full --all-extras CI rows can also pass with a skipped HELM suite. Could we move this marker onto the generation-argument tests and add one unmarked sentinel that skips only when the top-level helm package is absent, but otherwise calls _require_helm_dependencies()? That would keep core installs optional while checking that a full HELM install is actually usable.
What / source
Three changes that make the
helmextra work outside the locked 3.12/3.13 environment, plus the lockfile sync the last one needs. No conversion output changes.helm.common.codec. It needs six HELM modules, which pull incattrsand nothing else.helm.common.codecpulls torch, spacy, nltk and regex — for onefrom_jsoncall, in a file that already decodes three other HELM dataclasses withdacite. The fourth now decodes the same way.nltk<3.10.1→nltk!=3.10.1. 3.10.1 is the only release carrying theinisecimport guard; 3.10.2 replaced it with apathsecguard that covers corpus paths, not imports. The cap was holding theloosematrix rows to an nltk from before the fix, for a problem that release fixed._HELM_IMPORT_ERROR, like the rest of the HELM tests, instead ofpytest.importorskip('helm')— which passes on an install where the top-level package imports but a submodule does not, so the tests failed at collection instead of skipping.Why it matters, measured
_HELM_IMPORT_ERRORon Python 3.14 with--all-extras:_HELM_IMPORT_ERRORConfigError('unable to infer type for attribute "REGEX"')Nonepytest testsThat error comes from thinc/spacy, reached only through
helm.common.codec. Dropping the import is what makes the HELM converter run on 3.14 at all — crfm-helm's spacy dependency ships no 3.14 wheel, and it was never needed.Unchanged elsewhere: 3.13 + all extras 467 passed on both. Core install 411 passed on both, skips 20 → 24 (the generation-args module now skipping as a unit rather than half-collecting).
nltk 3.10.2in a venv under the CWD — the layout that tripped the guard — importshelm.common.codeccleanly, so the relaxed specifier is not re-opening the problem the cap was for.Review lane
Checklist
uv run pytest testsgreen (and green on 3.14, where main is not)uv run ruff checkcleanDecisions & coverage
per_instance_statswithdacite.from_dictper entry, inconverters/helm/adapter.py.Chose / instead of: keeping
helm.common.codec.from_jsonand documenting 3.14 as unsupported.Confidence: high — the file already decodes
RunSpec,ScenarioStateandScenariothis way, and the HELM case's 80 pinned sidecar rows and 24 pinned results go through this path.General? no.
nltk!=3.10.1rather thannltk>=3.10.2.Chose / instead of: a floor, which would drop the 3.9.x the locked rows resolve to for no reason.
Confidence: high.
General? no.
Coverage: unchanged — same records, same values; this is an import path and a specifier.