Skip to content

Commit 9fffe53

Browse files
authored
fix(hosting-cli): exit deploy when --envfile requires missing python-dotenv (#6414)
* fix(hosting-cli): exit deploy when envfile parser is unavailable * fix(test): annotate mock_export_fn as MagicMock to satisfy pyright The test calls .assert_not_called() which is a MagicMock method, not available on plain Callable types.
1 parent d23c667 commit 9fffe53

2 files changed

Lines changed: 72 additions & 0 deletions

File tree

  • packages/reflex-hosting-cli/src/reflex_cli/v2
  • tests/units/reflex_cli/v2

packages/reflex-hosting-cli/src/reflex_cli/v2/cli.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,7 @@ def deploy(
386386
console.error(
387387
"""The `python-dotenv` package is required to load environment variables from a file. Run `pip install "python-dotenv>=1.0.1"`."""
388388
)
389+
raise click.exceptions.Exit(1) from None
389390

390391
# Compile the app in production mode: backend first then frontend.
391392
temporary_dir = tempfile.TemporaryDirectory()

tests/units/reflex_cli/v2/test_cli.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,77 @@ def test_deploy_non_interactive_export_failure(
500500
watch_deployment.assert_not_called()
501501

502502

503+
def test_deploy_envfile_missing_python_dotenv_exits(
504+
mocker: MockerFixture,
505+
mock_export_fn: MagicMock,
506+
):
507+
"""Deploy should exit when --envfile is used without python-dotenv."""
508+
import builtins
509+
510+
mocker.patch(
511+
"reflex_cli.utils.hosting.get_authenticated_client",
512+
return_value=hosting.AuthenticatedClient(
513+
token="fake-token", validated_data={"foo": "bar"}
514+
),
515+
)
516+
mocker.patch(
517+
"reflex_cli.utils.hosting.validate_deployment_args",
518+
return_value="success",
519+
)
520+
mocker.patch(
521+
"reflex_cli.utils.hosting.get_selected_project",
522+
return_value="fake-project",
523+
)
524+
mocker.patch(
525+
"reflex_cli.utils.hosting.search_app",
526+
return_value={
527+
"name": "fake-app",
528+
"id": "fake-id",
529+
"project_id": "fake-project",
530+
},
531+
)
532+
mocker.patch(
533+
"reflex_cli.utils.hosting.get_hostname",
534+
return_value={"hostname": "fake-hostname", "server": "fake-server"},
535+
)
536+
mocker.patch(
537+
"reflex_cli.utils.hosting.get_project",
538+
)
539+
create_deployment = mocker.patch(
540+
"reflex_cli.utils.hosting.create_deployment",
541+
return_value={"deployment_id": "fake-deployment-id"},
542+
)
543+
watch_deployment = mocker.patch(
544+
"reflex_cli.utils.hosting.watch_deployment_status",
545+
return_value={"status": "ready"},
546+
)
547+
console_error = mocker.patch("reflex_cli.utils.console.error")
548+
549+
real_import = builtins.__import__
550+
551+
def _mock_import(name: str, *args, **kwargs):
552+
if name == "dotenv":
553+
raise ImportError
554+
return real_import(name, *args, **kwargs)
555+
556+
mocker.patch("builtins.__import__", side_effect=_mock_import)
557+
558+
with pytest.raises(click.exceptions.Exit):
559+
cli.deploy(
560+
app_name="fake-app",
561+
export_fn=mock_export_fn,
562+
interactive=False,
563+
envfile=".env",
564+
)
565+
566+
console_error.assert_any_call(
567+
"""The `python-dotenv` package is required to load environment variables from a file. Run `pip install "python-dotenv>=1.0.1"`."""
568+
)
569+
mock_export_fn.assert_not_called()
570+
create_deployment.assert_not_called()
571+
watch_deployment.assert_not_called()
572+
573+
503574
def test_deploy_non_interactive_with_invalid_project(mocker: MockFixture):
504575
mocker.patch(
505576
"reflex_cli.utils.hosting.get_authenticated_client",

0 commit comments

Comments
 (0)