Repository: Miserlou/Zappa

Issue:
Invoking function failed when function has type annotation
## Context / Env
- Python 3.6, in a virtualenv.
- Django 1.11 project
- Running zappa in production for a year

We started adding type annotation to our code base.

*task.py*
```
def run() -> None:
    print("hello")
```

When running `zappa invoke task.run`, it raises a `ValueError` in the lambda

*Traceback*
```
Function has keyword-only parameters or annotations, use getfullargspec() API which can support them: ValueError
Traceback (most recent call last):
  File "/var/task/handler.py", line 509, in lambda_handler
    return LambdaHandler.lambda_handler(event, context)
  File "/var/task/handler.py", line 240, in lambda_handler
    return handler.handler(event, context)
  File "/var/task/handler.py", line 345, in handler
    result = self.run_function(app_function, event, context)
  File "/var/task/handler.py", line 267, in run_function
    args, varargs, keywords, defaults = inspect.getargspec(app_function)
  File "/var/lang/lib/python3.6/inspect.py", line 1045, in getargspec
    raise ValueError("Function has keyword-only parameters or annotations"
ValueError: Function has keyword-only parameters or annotations, use getfullargspec() API which can support them
```

Potential fix is to use `getfullargspec` rather than `getargspec` in `handler.py` I will test it and submit a PR later today



Discussion:

Resolving patch:
diff --git a/zappa/handler.py b/zappa/handler.py
--- a/zappa/handler.py
+++ b/zappa/handler.py
@@ -264,7 +264,12 @@ def run_function(app_function, event, context):
         Given a function and event context,
         detect signature and execute, returning any result.
         """
-        args, varargs, keywords, defaults = inspect.getargspec(app_function)
+        # getargspec does not support python 3 method with type hints
+        # Related issue: https://github.com/Miserlou/Zappa/issues/1452
+        if hasattr(inspect, "getfullargspec"):  # Python 3
+            args, varargs, keywords, defaults, _, _, _ = inspect.getfullargspec(app_function)
+        else:  # Python 2
+            args, varargs, keywords, defaults = inspect.getargspec(app_function)
         num_args = len(args)
         if num_args == 0:
             result = app_function(event, context) if varargs else app_function()


Test patch:
diff --git a/tests/test_handler.py b/tests/test_handler.py
--- a/tests/test_handler.py
+++ b/tests/test_handler.py
@@ -1,5 +1,6 @@
-import unittest
 from mock import Mock
+import sys
+import unittest
 from zappa.handler import LambdaHandler
 
 
@@ -61,6 +62,15 @@ def test_run_function(self):
         except RuntimeError as e:
             pass
 
+    def test_run_fuction_with_type_hint(self):
+        python_version = sys.version_info[0]
+        # type hints are python 3 only
+        if python_version == 3:
+            scope = {}
+            exec('def f_with_type_hint() -> None: return', scope)
+            f_with_type_hint = scope['f_with_type_hint']
+            self.assertIsNone(LambdaHandler.run_function(f_with_type_hint, 'e', 'c'))
+
     def test_wsgi_script_name_on_aws_url(self):
         """
         Ensure that requests to the amazonaws.com host for an API with a