Skip to content

fix: propagate input stream in Command.call() for interactive questions#532

Open
gaoflow wants to merge 2 commits into
python-poetry:mainfrom
gaoflow:fix/call-propagate-stream-for-interactive-questions
Open

fix: propagate input stream in Command.call() for interactive questions#532
gaoflow wants to merge 2 commits into
python-poetry:mainfrom
gaoflow:fix/call-propagate-stream-for-interactive-questions

Conversation

@gaoflow

@gaoflow gaoflow commented Jun 24, 2026

Copy link
Copy Markdown

Problem

When a command uses call() to invoke another command that contains interactive questions (confirm, ask, choice), the callee crashes with:

AttributeError: 'NoneType' object has no attribute 'readline'

Root cause: call() constructs a fresh StringInput whose _stream defaults to None, but never copies the parent IO's stream. When the callee calls:

confirm() → Question.ask() → io.read_line() → input.read_line() → self._stream.readline()

self._stream is None, causing the crash.

Fix

Propagate self._io.input.stream to the new StringInput before passing it to _run_command:

string_input = StringInput(args or "")
string_input.set_stream(self._io.input.stream)

Test

Added test_call_propagates_stream_for_confirm which exercises a caller→callee chain where the callee uses confirm(), providing inputs="yes\n" through ApplicationTester. Before this fix the test raises AttributeError; after it passes.

Fixes #333


This pull request was prepared with the assistance of AI, under my direction and review.

When a command uses call() to invoke another command that contains
interactive questions (confirm, ask, choice), the callee's input
stream was None, causing an AttributeError on readline().

The root cause: call() constructs a fresh StringInput whose _stream
defaults to None, but never copies the parent IO's stream. When the
callee calls confirm() → Question.ask() → io.read_line() →
input.read_line() → self._stream.readline(), the None stream raises
'NoneType' object has no attribute 'readline'.

Fix: propagate self._io.input.stream to the new StringInput before
passing it to _run_command, so the callee reads from the same stream
as the caller.

Fixes python-poetry#333
@dosubot dosubot Bot added the size:XS This PR changes 0-9 lines, ignoring generated files. label Jun 24, 2026
@gaoflow

gaoflow commented Jun 26, 2026

Copy link
Copy Markdown
Author

Pushed a follow-up for the red checks:

  • added news/333.bugfix.md for the bug fix
  • ran pre-commit run --all-files; it reformatted the new Command.call() return line, and the follow-up includes that formatting change

Verification:

  • uv run --with towncrier towncrier check --compare-with origin/main -> found news/333.bugfix.md
  • uv run --with pre-commit pre-commit run --all-files -> passed
  • uv run --with pytest python -m pytest tests/commands/test_command.py -q -> 6 passed
  • git diff --check --cached -> passed before commit

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XS This PR changes 0-9 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Using Call on a Command that Uses Confirm Doesn't Work

1 participant