diff --git a/src/functions_framework/_function_registry.py b/src/functions_framework/_function_registry.py index cedb7e15..fdcf383f 100644 --- a/src/functions_framework/_function_registry.py +++ b/src/functions_framework/_function_registry.py @@ -38,16 +38,21 @@ def get_user_function(source, source_module, target): """Returns user function, raises exception for invalid function.""" # Extract the target function from the source file if not hasattr(source_module, target): + non_target_functions = ", ".join( + "'{attr}'".format(attr=attr) + for attr in dir(source_module) + if isinstance(getattr(source_module, attr), types.FunctionType) + ) raise MissingTargetException( - "File {source} is expected to contain a function named {target}".format( - source=source, target=target + "File {source} is expected to contain a function named '{target}'. Found: {non_target_functions} instead".format( + source=source, target=target, non_target_functions=non_target_functions ) ) function = getattr(source_module, target) # Check that it is a function if not isinstance(function, types.FunctionType): raise InvalidTargetTypeException( - "The function defined in file {source} as {target} needs to be of " + "The function defined in file {source} as '{target}' needs to be of " "type function. Got: invalid type {target_type}".format( source=source, target=target, target_type=type(function) ) diff --git a/tests/test_functions.py b/tests/test_functions.py index c343205f..c26cb625 100644 --- a/tests/test_functions.py +++ b/tests/test_functions.py @@ -275,7 +275,8 @@ def test_invalid_function_definition_multiple_entry_points(): create_app(target, source, "event") assert re.match( - "File .* is expected to contain a function named function", str(excinfo.value) + "File .* is expected to contain a function named 'function'. Found: 'fun', 'myFunctionBar', 'myFunctionFoo' instead", + str(excinfo.value), ) @@ -287,7 +288,7 @@ def test_invalid_function_definition_multiple_entry_points_invalid_function(): create_app(target, source, "event") assert re.match( - "File .* is expected to contain a function named invalidFunction", + "File .* is expected to contain a function named 'invalidFunction'. Found: 'fun', 'myFunctionBar', 'myFunctionFoo' instead", str(excinfo.value), ) @@ -300,7 +301,7 @@ def test_invalid_function_definition_multiple_entry_points_not_a_function(): create_app(target, source, "event") assert re.match( - "The function defined in file .* as notAFunction needs to be of type " + "The function defined in file .* as 'notAFunction' needs to be of type " "function. Got: .*", str(excinfo.value), )