From 48c169aa0bb70ef9034e11ffcbb87584c26bcf40 Mon Sep 17 00:00:00 2001 From: Florian Boucault Date: Wed, 8 Oct 2025 17:32:56 +0200 Subject: [PATCH] Fix #1614: Replace assertion with proper error handling in argument parser Replace bare `assert` statement in `_guess_method()` with proper error handling to prevent AssertionError from being exposed to users. The assertion `assert not self.args.request_items` at line 416 could fail in edge cases, causing users to see an unhelpful stack trace instead of a clear error message. Changes: - httpie/cli/argparser.py: Replace assertion with self.error() call - tests/test_cli.py: Add 2 regression tests to TestArgumentParser class Fixes #1614 --- httpie/cli/argparser.py | 11 ++++++++++- tests/test_cli.py | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/httpie/cli/argparser.py b/httpie/cli/argparser.py index 9bf09b3b73..d66da79332 100644 --- a/httpie/cli/argparser.py +++ b/httpie/cli/argparser.py @@ -413,7 +413,16 @@ def _guess_method(self): """ if self.args.method is None: # Invoked as `http URL'. - assert not self.args.request_items + if self.args.request_items: + # This can happen in edge cases when positional arguments are + # provided in an unexpected order, causing argparse to misparse. + # Provide a helpful error message instead of an assertion failure. + self.error( + 'unable to parse arguments: received request items without an HTTP method. ' + 'Please specify the URL before any request items, ' + 'or provide an explicit METHOD. ' + 'Expected: http [METHOD] URL [REQUEST_ITEM ...]' + ) if self.has_input_data: self.args.method = HTTP_POST else: diff --git a/tests/test_cli.py b/tests/test_cli.py index 2cd27574af..d4a2512ef3 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -316,6 +316,43 @@ def test_guess_when_method_set_but_invalid_and_item_exists(self): key='old_item', value='b', sep='=', orig='old_item=b'), ] + def test_guess_method_none_with_request_items_gives_helpful_error(self): + """ + Regression test for #1614: method=None with request_items should give + helpful error message, not AssertionError. + + Verifies that when _guess_method() encounters method=None with populated + request_items, it calls self.error() with a helpful message instead of + raising an AssertionError. + """ + from unittest.mock import Mock + + # Set up the problematic state: method=None with request_items + self.parser.args = argparse.Namespace() + self.parser.args.method = None + self.parser.args.url = 'http://example.com/' + self.parser.args.request_items = [ + KeyValueArg(key='data', value='field', sep='=', orig='data=field') + ] + self.parser.args.ignore_stdin = False + self.parser.env = MockEnvironment() + self.parser.has_input_data = False + + # Mock self.error() to verify it's called with the right message + self.parser.error = Mock(side_effect=SystemExit(2)) + + # Call _guess_method() and verify behavior + with pytest.raises(SystemExit): + self.parser._guess_method() + + # Verify error() was called (not AssertionError raised) + assert self.parser.error.called, "error() should be called" + + # Verify the error message is helpful + error_message = self.parser.error.call_args[0][0] + assert 'unable to parse arguments' in error_message + assert 'request items without an HTTP method' in error_message + class TestNoOptions: