diff --git a/src/functions_framework/__init__.py b/src/functions_framework/__init__.py index 8d47670c..ece4f446 100644 --- a/src/functions_framework/__init__.py +++ b/src/functions_framework/__init__.py @@ -357,11 +357,30 @@ def handle_none(rv): # Execute the module, within the application context with _app.app_context(): - spec.loader.exec_module(source_module) + try: + spec.loader.exec_module(source_module) + function = _function_registry.get_user_function( + source, source_module, target + ) + except Exception as e: + if werkzeug.serving.is_running_from_reloader(): + # When reloading, print out the error immediately, but raise + # it later so the debugger or server can handle it. + import traceback + + traceback.print_exc() + err = e + + def function(*_args, **_kwargs): + raise err from None + + else: + # When not reloading, raise the error immediately so the + # command fails. + raise e from None # Get the configured function signature type signature_type = _function_registry.get_func_signature_type(target, signature_type) - function = _function_registry.get_user_function(source, source_module, target) _configure_app(_app, function, signature_type) diff --git a/tests/test_functions.py b/tests/test_functions.py index 81860cae..f0bd7793 100644 --- a/tests/test_functions.py +++ b/tests/test_functions.py @@ -323,6 +323,19 @@ def test_invalid_function_definition_function_syntax_error(): ) +def test_invalid_function_definition_function_syntax_robustness_with_debug(monkeypatch): + monkeypatch.setattr( + functions_framework.werkzeug.serving, "is_running_from_reloader", lambda: True + ) + source = TEST_FUNCTIONS_DIR / "background_load_error" / "main.py" + target = "function" + + client = create_app(target, source).test_client() + + resp = client.get("/") + assert resp.status_code == 500 + + def test_invalid_function_definition_missing_dependency(): source = TEST_FUNCTIONS_DIR / "background_missing_dependency" / "main.py" target = "function"