@@ -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+
503574def test_deploy_non_interactive_with_invalid_project (mocker : MockFixture ):
504575 mocker .patch (
505576 "reflex_cli.utils.hosting.get_authenticated_client" ,
0 commit comments