From 44e16e9d062d0dab7b152e2c1402fbb3ce3e0d8d Mon Sep 17 00:00:00 2001 From: Alex Castillo Date: Wed, 4 Nov 2026 19:06:38 -0400 Subject: [PATCH] fix: keep a valid saved OAuth account in non-interactive mode when several accounts are authorized Co-Authored-By: Claude Sonnet 5.5 --- lean/models/json_module.py | 6 +-- .../util/test_json_modules_handler.py | 46 +++++++++++++++++++ 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/lean/models/json_module.py b/lean/models/json_module.py index 3110da27..cfc47c49 100644 --- a/lean/models/json_module.py +++ b/lean/models/json_module.py @@ -335,9 +335,9 @@ def config_build(self, f"available: {api_account_ids}") existing_account = lean_config.get(inner_config._id) if existing_account and (existing_account not in api_account_ids - or len(api_account_ids) > 1): - # Clear stale or ambiguous account so the user is prompted - # to select from the current API choices + or (interactive and len(api_account_ids) > 1)): + # Clear a stale account, or an ambiguous one when the user can be prompted, + # so the user selects from the current API choices lean_config.pop(inner_config._id) break continue diff --git a/tests/components/util/test_json_modules_handler.py b/tests/components/util/test_json_modules_handler.py index 2113be8d..94be1323 100644 --- a/tests/components/util/test_json_modules_handler.py +++ b/tests/components/util/test_json_modules_handler.py @@ -193,3 +193,49 @@ def test_config_build_uses_lean_config_account_when_valid() -> None: mock_prompt.assert_not_called() account_config = next(c for c in module._lean_configs if c._id == "test-account-number") assert account_config._value == "60102549" + + +def test_config_build_keeps_valid_saved_account_when_not_interactive_with_multiple_accounts() -> None: + create_fake_lean_cli_directory() + initialize_container() + + module = JsonModule(_SCHWAB_LIKE_MODULE_DATA, MODULE_BROKERAGE, MODULE_CLI_PLATFORM) + + lean_config = {"project-id": 123, "test-account-number": "60102549"} # valid and in the authorized list + + mock_auth = mock.MagicMock() + mock_auth.get_authorization_config_without_account.return_value = {"token": "abc"} + mock_auth.get_account_ids.return_value = ["60102549", "99887766"] + + with mock.patch("lean.models.json_module.get_current_context") as mock_ctx, \ + mock.patch("lean.models.json_module.get_authorization", return_value=mock_auth), \ + mock.patch("lean.models.configuration.prompt") as mock_prompt, \ + mock.patch.object(module, "_save_property"): + mock_ctx.return_value.get_parameter_source.return_value = None + + module.config_build(lean_config, mock.Mock(), interactive=False) + + mock_prompt.assert_not_called() + account_config = next(c for c in module._lean_configs if c._id == "test-account-number") + assert account_config._value == "60102549" + + +def test_config_build_requires_account_when_saved_account_is_not_authorized_and_not_interactive() -> None: + create_fake_lean_cli_directory() + initialize_container() + + module = JsonModule(_SCHWAB_LIKE_MODULE_DATA, MODULE_BROKERAGE, MODULE_CLI_PLATFORM) + + lean_config = {"project-id": 123, "test-account-number": "00000000"} # not authorized any more + + mock_auth = mock.MagicMock() + mock_auth.get_authorization_config_without_account.return_value = {"token": "abc"} + mock_auth.get_account_ids.return_value = ["60102549", "99887766"] + + with mock.patch("lean.models.json_module.get_current_context") as mock_ctx, \ + mock.patch("lean.models.json_module.get_authorization", return_value=mock_auth), \ + mock.patch.object(module, "_save_property"): + mock_ctx.return_value.get_parameter_source.return_value = None + + with pytest.raises(RuntimeError, match="--test-account-number"): + module.config_build(lean_config, mock.Mock(), interactive=False)