Skip to content

Commit cd26589

Browse files
feat: support for local Event invocation type (#8590)
* feat: support for local Event invocation type * test: assert that local lambda invoke function runs * test: lambda error responses * fix: use get_function utility
1 parent b2ee6c9 commit cd26589

12 files changed

Lines changed: 617 additions & 128 deletions

File tree

samcli/commands/local/lib/local_lambda.py

Lines changed: 69 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -96,47 +96,35 @@ def __init__(
9696
self.container_host_interface = container_host_interface
9797
self.extra_hosts = extra_hosts
9898

99-
def invoke(
100-
self,
101-
function_identifier: str,
102-
event: str,
103-
tenant_id: Optional[str] = None,
104-
stdout: Optional[StreamWriter] = None,
105-
stderr: Optional[StreamWriter] = None,
106-
override_runtime: Optional[str] = None,
107-
invocation_type: str = "RequestResponse",
108-
durable_execution_name: Optional[str] = None,
109-
) -> Optional[Dict[str, str]]:
99+
def get_function(self, function_identifier: str, tenant_id: Optional[str] = None) -> Function:
110100
"""
111-
Find the Lambda function with given name and invoke it. Pass the given event to the function and return
112-
response through the given streams.
113-
114-
This function will block until either the function completes or times out.
101+
Get a Lambda function by identifier, raising FunctionNotFound if not found.
115102
116103
Parameters
117104
----------
118-
function_identifier str
119-
Identifier of the Lambda function to invoke, it can be logicalID, function name or full path
120-
event str
121-
Event data passed to the function. Must be a valid JSON String.
122-
stdout samcli.lib.utils.stream_writer.StreamWriter
123-
Stream writer to write the output of the Lambda function to.
124-
stderr samcli.lib.utils.stream_writer.StreamWriter
125-
Stream writer to write the Lambda runtime logs to.
126-
Runtime: str
127-
To use instead of the runtime specified in the function configuration
128-
durable_execution_name: str
129-
Optional name for the durable execution (for durable functions only)
130-
105+
function_identifier : str
106+
Identifier of the Lambda function, it can be logicalID, function name or full path
107+
tenant_id : Optional[str]
108+
Optional tenant ID for multi-tenant functions
131109
Returns
132110
-------
133-
Optional[Dict[str, str]]
134-
HTTP headers dict if this was a durable function invocation, None otherwise
111+
Function
112+
The Lambda function configuration
135113
136114
Raises
137115
------
138-
FunctionNotfound
139-
When we cannot find a function with the given name
116+
InvalidFunctionNameException
117+
When the function identifier doesn't match AWS Lambda's validation pattern
118+
FunctionNotFound
119+
When we cannot find a function with the given identifier
120+
TenantIdValidationError
121+
When the tenant ID is not provided for multi-tenant functions
122+
UnsupportedInlineCodeError
123+
When the function has inline code and is being invoked locally
124+
InvalidIntermediateImageError
125+
When the function has an intermediate image and is being invoked locally
126+
UnsupportedRuntimeArchitectureError
127+
When the function runtime and architecture are not compatible
140128
"""
141129
# Normalize function identifier from ARN if provided
142130
normalized_function_identifier = normalize_sam_function_identifier(function_identifier)
@@ -182,6 +170,55 @@ def invoke(
182170
"Remove the tenant ID from your request and try again."
183171
)
184172

173+
return function
174+
175+
def invoke(
176+
self,
177+
function_identifier: str,
178+
event: str,
179+
tenant_id: Optional[str] = None,
180+
stdout: Optional[StreamWriter] = None,
181+
stderr: Optional[StreamWriter] = None,
182+
override_runtime: Optional[str] = None,
183+
invocation_type: str = "RequestResponse",
184+
durable_execution_name: Optional[str] = None,
185+
function: Optional[Function] = None,
186+
) -> Optional[Dict[str, str]]:
187+
"""
188+
Find the Lambda function with given name and invoke it. Pass the given event to the function and return
189+
response through the given streams.
190+
191+
This function will block until either the function completes or times out.
192+
193+
Parameters
194+
----------
195+
function_identifier str
196+
Identifier of the Lambda function to invoke, it can be logicalID, function name or full path
197+
event str
198+
Event data passed to the function. Must be a valid JSON String.
199+
stdout samcli.lib.utils.stream_writer.StreamWriter
200+
Stream writer to write the output of the Lambda function to.
201+
stderr samcli.lib.utils.stream_writer.StreamWriter
202+
Stream writer to write the Lambda runtime logs to.
203+
Runtime: str
204+
To use instead of the runtime specified in the function configuration
205+
durable_execution_name: str
206+
Optional name for the durable execution (for durable functions only)
207+
208+
Returns
209+
-------
210+
Optional[Dict[str, str]]
211+
HTTP headers dict if this was a durable function invocation, None otherwise
212+
213+
Raises
214+
------
215+
FunctionNotfound
216+
When we cannot find a function with the given name
217+
"""
218+
# Get the function configuration
219+
if not function:
220+
function = self.get_function(function_identifier, tenant_id)
221+
185222
config = self.get_invoke_config(function, override_runtime)
186223

187224
if (

samcli/local/lambda_service/lambda_error_responses.py

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
import json
44
from collections import OrderedDict
5+
from typing import Any, Dict
6+
7+
from flask import Response
58

69
from samcli.local.services.base_local_service import BaseLocalService
710

@@ -40,7 +43,7 @@ class LambdaErrorResponses:
4043
CONTENT_TYPE_HEADER_KEY = "Content-Type"
4144

4245
@staticmethod
43-
def resource_not_found(function_name):
46+
def resource_not_found(function_name: str) -> Response:
4447
"""
4548
Creates a Lambda Service ResourceNotFound Response
4649
@@ -66,7 +69,7 @@ def resource_not_found(function_name):
6669
)
6770

6871
@staticmethod
69-
def invalid_request_content(message):
72+
def invalid_request_content(message: str) -> Response:
7073
"""
7174
Creates a Lambda Service InvalidRequestContent Response
7275
@@ -89,7 +92,7 @@ def invalid_request_content(message):
8992
)
9093

9194
@staticmethod
92-
def validation_exception(message):
95+
def validation_exception(message: str) -> Response:
9396
"""
9497
Creates a Lambda Service ValidationException Response
9598
@@ -112,7 +115,7 @@ def validation_exception(message):
112115
)
113116

114117
@staticmethod
115-
def unsupported_media_type(content_type):
118+
def unsupported_media_type(content_type: str) -> Response:
116119
"""
117120
Creates a Lambda Service UnsupportedMediaType Response
118121
@@ -137,7 +140,7 @@ def unsupported_media_type(content_type):
137140
)
138141

139142
@staticmethod
140-
def generic_service_exception(*args):
143+
def generic_service_exception(*args: Any) -> Response:
141144
"""
142145
Creates a Lambda Service Generic ServiceException Response
143146
@@ -160,7 +163,7 @@ def generic_service_exception(*args):
160163
)
161164

162165
@staticmethod
163-
def not_implemented_locally(message):
166+
def not_implemented_locally(message: str) -> Response:
164167
"""
165168
Creates a Lambda Service NotImplementedLocally Response
166169
@@ -183,7 +186,7 @@ def not_implemented_locally(message):
183186
)
184187

185188
@staticmethod
186-
def generic_path_not_found(*args):
189+
def generic_path_not_found(*args: Any) -> Response:
187190
"""
188191
Creates a Lambda Service Generic PathNotFound Response
189192
@@ -208,7 +211,7 @@ def generic_path_not_found(*args):
208211
)
209212

210213
@staticmethod
211-
def generic_method_not_allowed(*args):
214+
def generic_method_not_allowed(*args: Any) -> Response:
212215
"""
213216
Creates a Lambda Service Generic MethodNotAllowed Response
214217
@@ -233,13 +236,13 @@ def generic_method_not_allowed(*args):
233236
)
234237

235238
@staticmethod
236-
def container_creation_failed(message):
239+
def container_creation_failed(message: str) -> Response:
237240
"""
238241
Creates a Container Creation Failed response
239242
Parameters
240243
----------
241-
args list
242-
List of arguments Flask passes to the method
244+
message str
245+
Message to be added to the body of the response
243246
Returns
244247
-------
245248
Flask.Response
@@ -256,7 +259,7 @@ def container_creation_failed(message):
256259
)
257260

258261
@staticmethod
259-
def _construct_error_response_body(error_type, error_message):
262+
def _construct_error_response_body(error_type: str, error_message: str) -> str:
260263
"""
261264
Constructs a string to be used in the body of the Response that conforms
262265
to the structure of the Lambda Service Responses
@@ -278,7 +281,7 @@ def _construct_error_response_body(error_type, error_message):
278281

279282
# Durable Functions Error Responses
280283
@staticmethod
281-
def durable_execution_not_found(execution_arn):
284+
def durable_execution_not_found(execution_arn: str) -> Response:
282285
"""Creates a ResourceNotFound response for durable executions"""
283286
exception_tuple = LambdaErrorResponses.ResourceNotFoundException
284287
return BaseLocalService.service_response(
@@ -290,7 +293,7 @@ def durable_execution_not_found(execution_arn):
290293
)
291294

292295
@staticmethod
293-
def _construct_headers(error_type):
296+
def _construct_headers(error_type: str) -> Dict[str, str]:
294297
"""
295298
Constructs Headers for the Local Lambda Error Response
296299

0 commit comments

Comments
 (0)