Repository: GoogleCloudPlatform/functions-framework-python
Pull request #189 (2022-06-08 21:50:00)

feat: Add more details to MissingTargetException error
Replaces https://github.com/GoogleCloudPlatform/functions-framework-python/pull/158 since that PR is outdated.

Tested:

```
python -m tox -e py38-ubuntu-latest 
python -m tox -e lint
.tox/lint/bin/black tests
```


Patch:
diff --git a/src/functions_framework/_function_registry.py b/src/functions_framework/_function_registry.py
index cedb7e1..fdcf383 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)
             )


Test patch:
diff --git a/tests/test_functions.py b/tests/test_functions.py
index c343205..c26cb62 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),
     )