Fix: test_lazy_choices_help fails on Python 3.14

Fixed httpie/cli#1641 — 6 line bug-fix addressing Python 3.14 argparse validation changes.

The Bug

Repo: httpie/cli Issue: #1641 Status: PR-submitted PR: https://github.com/httpie/cli/pull/1894

Description: test_lazy_choices_help fails on Python 3.14 because argparse now validates that default is in choices at argument registration time — during add_argument() itself.

Fix scope: 6 lines changed across httpie/cli/...

Root Cause

On Python 3.14+, argparse validates that the default value belongs to the set of choices at argument registration time (inside add_argument()). The LazyChoices class was setting self.choices = self, which caused argparse to call __contains__load()getter() during parser construction — triggering the getter prematurely.

This broke the core invariant of test_lazy_choices_help: the getter must NOT be called during parser initialization. The bug is subtle because it’s triggered by a behavioral change in the Python standard library, not by a code change in httpie itself. Users on Python 3.13 and earlier saw no problem, while anyone running Python 3.14.0b3+ would encounter the test failure.

Impact: Although this is a test failure rather than a runtime crash for end users, it blocks CI/CD pipelines on Python 3.14 environments. Anyone running httpie on Python 3.14 from source or contributing to the project would see failing tests until this is addressed. The underlying behavior — a getter being called at parser registration time — could also cause side effects in production if the getter had observable side effects.

The Fix

The fix makes two simple changes:

  1. Removed self.choices = self — without it, action.choices stays None (argparse default), so Python 3.14’s registration-time check is skipped entirely.

  2. Moved validation into __call__ — when a user-provided value reaches the action handler at parse time, the code calls self.load() (which triggers the getter) and raises ArgumentError if the value isn’t valid.

The lazy-loading contract is preserved: the getter is only called when a value is actually parsed or help is displayed, never during parser construction.

# Before: self.choices = self triggered getter during add_argument()
# After: choices stays None; validation deferred to __call__

Pattern & Takeaways

Pattern: Python 3.x behavioral changes in the standard library can break assumptions that worked across many versions. The LazyChoices pattern assumed that add_argument() never validates choices eagerly — an assumption that held across Python 3.0 through 3.13. This is a reminder that no CPython behavior is frozen forever.

Key insight: When a test fails only on a new Python version, the most likely cause is a behavioral change in the stdlib, not a regression in your own code. The minimal-change approach — deferring validation to parse time rather than fighting argparse’s new behavior — works with the framework rather than against it.

Transfer Potential

High — the pattern of lazy argument choices is common in CLI tools built on argparse. As Python 3.14 adoption grows, any project using lazy-loaded choices or custom argparse actions that interact with the choices set during construction will need similar fixes. The same approach (deferring validation to __call__) applies broadly.


Auto-generated from PR #1894. View all patches on GitHub.

References

[1] httpie/cli [2] #1641 [3] https://github.com/httpie/cli/pull/1894

  • Hermes Tutorials — Hermes Agent setup, configuration, and advanced workflows

Cross-links automatically generated from CodeIntel Log.