Skip to content

Commit 31f4703

Browse files
chore(sdk): use public boto3 Lambda client (#229)
* chore: remove internal lambda client * chore: making e2e happy * chore: making e2e happy
1 parent 1e60904 commit 31f4703

File tree

8 files changed

+46
-7950
lines changed

8 files changed

+46
-7950
lines changed

.github/workflows/integration-tests.yml

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -97,17 +97,12 @@ jobs:
9797
role-session-name: languageSDKIntegrationTest
9898
aws-region: ${{ env.AWS_REGION }}
9999

100-
- name: Install custom Lambda model
101-
working-directory: testing-sdk
102-
run: |
103-
aws configure add-model --service-model file://.github/model/lambda.json --service-name lambda
104-
105100
- name: Install Hatch and setup Testing SDK
106101
working-directory: testing-sdk
107102
env:
108103
AWS_DURABLE_SDK_URL: file://${{ github.workspace }}/language-sdk
109104
run: |
110-
pip install hatch
105+
pip install hatch==1.15.0
111106
python -m pip install -e .
112107
113108
- name: Get integration examples
@@ -116,6 +111,13 @@ jobs:
116111
run: |
117112
echo "examples=$(jq -c '.examples | map(select(.integration == true)) | .[0:2]' examples-catalog.json)" >> $GITHUB_OUTPUT
118113
114+
- name: Install AWS CLI v2
115+
run: |
116+
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "/tmp/awscliv2.zip"
117+
unzip -q /tmp/awscliv2.zip -d /tmp
118+
rm /tmp/awscliv2.zip
119+
sudo /tmp/aws/install --update
120+
rm -rf /tmp/aws/
119121
- name: Deploy and test examples
120122
working-directory: testing-sdk
121123
env:

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ classifiers = [
2121
"Programming Language :: Python :: Implementation :: CPython",
2222
"Programming Language :: Python :: Implementation :: PyPy",
2323
]
24-
dependencies = ["boto3>=1.40.30"]
24+
dependencies = ["boto3>=1.42.1"]
2525

2626
[project.urls]
2727
Documentation = "https://github.com/aws/aws-durable-execution-sdk-python#readme"

src/aws_durable_execution_sdk_python/botocore/data/lambdainternal/2015-03-31/service-2.json

Lines changed: 0 additions & 7864 deletions
This file was deleted.

src/aws_durable_execution_sdk_python/execution.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ def wrapper(event: Any, context: LambdaContext) -> MutableMapping[str, Any]:
237237
service_client = (
238238
LambdaClient(client=boto3_client)
239239
if boto3_client is not None
240-
else LambdaClient.initialize_from_env()
240+
else LambdaClient.initialize_client()
241241
)
242242

243243
raw_input_payload: str | None = (

src/aws_durable_execution_sdk_python/lambda_service.py

Lines changed: 7 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,8 @@
22

33
import datetime
44
import logging
5-
import os
65
from dataclasses import dataclass, field
76
from enum import Enum
8-
from pathlib import Path
97
from typing import TYPE_CHECKING, Any, Protocol, TypeAlias
108

119
import boto3 # type: ignore
@@ -943,41 +941,14 @@ def __init__(self, client: Any) -> None:
943941
self.client = client
944942

945943
@staticmethod
946-
def load_preview_botocore_models() -> None:
947-
"""
948-
Load boto3 models from the Python path for custom preview client.
949-
"""
950-
os.environ["AWS_DATA_PATH"] = str(
951-
Path(__file__).parent.joinpath("botocore", "data")
944+
def initialize_client() -> LambdaClient:
945+
client = boto3.client(
946+
"lambda",
947+
config=Config(
948+
connect_timeout=5,
949+
read_timeout=50,
950+
),
952951
)
953-
954-
@staticmethod
955-
def initialize_from_env() -> LambdaClient:
956-
LambdaClient.load_preview_botocore_models()
957-
958-
"""
959-
TODO - we can remove this when were using the actual lambda client,
960-
but we need this with the preview model because boto won't match against lambdainternal.
961-
"""
962-
endpoint_url = os.getenv("AWS_ENDPOINT_URL_LAMBDA", None)
963-
if not endpoint_url:
964-
client = boto3.client(
965-
"lambdainternal",
966-
config=Config(
967-
connect_timeout=5,
968-
read_timeout=50,
969-
),
970-
)
971-
else:
972-
client = boto3.client(
973-
"lambdainternal",
974-
endpoint_url=endpoint_url,
975-
config=Config(
976-
connect_timeout=5,
977-
read_timeout=50,
978-
),
979-
)
980-
981952
return LambdaClient(client=client)
982953

983954
def checkpoint(

tests/e2e/execution_int_test.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ def my_handler(event, context: DurableContext) -> list[str]:
7070
"aws_durable_execution_sdk_python.execution.LambdaClient"
7171
) as mock_client_class:
7272
mock_client = Mock()
73-
mock_client_class.initialize_from_env.return_value = mock_client
73+
mock_client_class.initialize_client.return_value = mock_client
7474

7575
# Mock the checkpoint method to track calls
7676
checkpoint_calls = []
@@ -156,7 +156,7 @@ def my_handler(event, context: DurableContext):
156156
"aws_durable_execution_sdk_python.execution.LambdaClient"
157157
) as mock_client_class:
158158
mock_client = Mock()
159-
mock_client_class.initialize_from_env.return_value = mock_client
159+
mock_client_class.initialize_client.return_value = mock_client
160160

161161
# Mock the checkpoint method to track calls
162162
checkpoint_calls = []
@@ -257,7 +257,7 @@ def my_handler(event, context):
257257
"aws_durable_execution_sdk_python.execution.LambdaClient"
258258
) as mock_client_class:
259259
mock_client = Mock()
260-
mock_client_class.initialize_from_env.return_value = mock_client
260+
mock_client_class.initialize_client.return_value = mock_client
261261

262262
# Mock the checkpoint method to track calls
263263
checkpoint_calls = []
@@ -363,7 +363,7 @@ def my_handler(event, context: DurableContext):
363363
"aws_durable_execution_sdk_python.execution.LambdaClient"
364364
) as mock_client_class:
365365
mock_client = Mock()
366-
mock_client_class.initialize_from_env.return_value = mock_client
366+
mock_client_class.initialize_client.return_value = mock_client
367367

368368
# Mock the checkpoint method to raise an error (using RuntimeError as a generic exception)
369369
def mock_checkpoint_failure(
@@ -426,7 +426,7 @@ def my_handler(event: Any, context: DurableContext):
426426
"aws_durable_execution_sdk_python.execution.LambdaClient"
427427
) as mock_client_class:
428428
mock_client = Mock()
429-
mock_client_class.initialize_from_env.return_value = mock_client
429+
mock_client_class.initialize_client.return_value = mock_client
430430

431431
# Mock the checkpoint method to track calls
432432
checkpoint_calls = []
@@ -509,7 +509,7 @@ def my_handler(event, context):
509509
"aws_durable_execution_sdk_python.execution.LambdaClient"
510510
) as mock_client_class:
511511
mock_client = Mock()
512-
mock_client_class.initialize_from_env.return_value = mock_client
512+
mock_client_class.initialize_client.return_value = mock_client
513513

514514
checkpoint_calls = []
515515

tests/execution_test.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ def test_durable_execution_client_selection_env_normal_result():
337337
"aws_durable_execution_sdk_python.execution.LambdaClient"
338338
) as mock_lambda_client:
339339
mock_client = Mock(spec=DurableServiceClient)
340-
mock_lambda_client.initialize_from_env.return_value = mock_client
340+
mock_lambda_client.initialize_client.return_value = mock_client
341341

342342
# Mock successful checkpoint
343343
mock_output = CheckpointOutput(
@@ -379,7 +379,7 @@ def test_handler(event: Any, context: DurableContext) -> dict:
379379

380380
assert result["Status"] == InvocationStatus.SUCCEEDED.value
381381
assert result["Result"] == '{"result": "success"}'
382-
mock_lambda_client.initialize_from_env.assert_called_once()
382+
mock_lambda_client.initialize_client.assert_called_once()
383383
mock_client.checkpoint.assert_not_called()
384384

385385

@@ -389,7 +389,7 @@ def test_durable_execution_client_selection_env_large_result():
389389
"aws_durable_execution_sdk_python.execution.LambdaClient"
390390
) as mock_lambda_client:
391391
mock_client = Mock(spec=DurableServiceClient)
392-
mock_lambda_client.initialize_from_env.return_value = mock_client
392+
mock_lambda_client.initialize_client.return_value = mock_client
393393

394394
# Mock successful checkpoint
395395
mock_output = CheckpointOutput(
@@ -431,7 +431,7 @@ def test_handler(event: Any, context: DurableContext) -> dict:
431431

432432
assert result["Status"] == InvocationStatus.SUCCEEDED.value
433433
assert not result["Result"]
434-
mock_lambda_client.initialize_from_env.assert_called_once()
434+
mock_lambda_client.initialize_client.assert_called_once()
435435
mock_client.checkpoint.assert_called_once()
436436

437437

@@ -725,7 +725,7 @@ def test_durable_execution_client_selection_default():
725725
"aws_durable_execution_sdk_python.execution.LambdaClient"
726726
) as mock_lambda_client:
727727
mock_client = Mock(spec=DurableServiceClient)
728-
mock_lambda_client.initialize_from_env.return_value = mock_client
728+
mock_lambda_client.initialize_client.return_value = mock_client
729729

730730
# Mock successful checkpoint
731731
mock_output = CheckpointOutput(
@@ -766,7 +766,7 @@ def test_handler(event: Any, context: DurableContext) -> dict:
766766
result = test_handler(event, lambda_context)
767767

768768
assert result["Status"] == InvocationStatus.SUCCEEDED.value
769-
mock_lambda_client.initialize_from_env.assert_called_once()
769+
mock_lambda_client.initialize_client.assert_called_once()
770770

771771

772772
def test_initial_execution_state_get_execution_operation_no_operations():

tests/lambda_service_test.py

Lines changed: 17 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1906,18 +1906,17 @@ def test_lambda_client_constructor():
19061906

19071907
@patch.dict("os.environ", {}, clear=True)
19081908
@patch("boto3.client")
1909-
def test_lambda_client_initialize_from_env_default(mock_boto_client):
1910-
"""Test LambdaClient.initialize_from_env with default endpoint."""
1909+
def test_lambda_client_initialize_client_default(mock_boto_client):
1910+
"""Test LambdaClient.initialize_client with default endpoint."""
19111911
mock_client = Mock()
19121912
mock_boto_client.return_value = mock_client
19131913

1914-
with patch.object(LambdaClient, "load_preview_botocore_models"):
1915-
client = LambdaClient.initialize_from_env()
1914+
client = LambdaClient.initialize_client()
19161915

19171916
# Check that boto3.client was called with the right service name and config
19181917
mock_boto_client.assert_called_once()
19191918
call_args = mock_boto_client.call_args
1920-
assert call_args[0][0] == "lambdainternal"
1919+
assert call_args[0][0] == "lambda"
19211920
assert "config" in call_args[1]
19221921
config = call_args[1]["config"]
19231922
assert config.connect_timeout == 5
@@ -1927,19 +1926,18 @@ def test_lambda_client_initialize_from_env_default(mock_boto_client):
19271926

19281927
@patch.dict("os.environ", {"AWS_ENDPOINT_URL_LAMBDA": "http://localhost:3000"})
19291928
@patch("boto3.client")
1930-
def test_lambda_client_initialize_from_env_with_endpoint(mock_boto_client):
1931-
"""Test LambdaClient.initialize_from_env with custom endpoint."""
1929+
def test_lambda_client_initialize_client_with_endpoint(mock_boto_client):
1930+
"""Test LambdaClient.initialize_client with custom endpoint (boto3 handles it automatically)."""
19321931
mock_client = Mock()
19331932
mock_boto_client.return_value = mock_client
19341933

1935-
with patch.object(LambdaClient, "load_preview_botocore_models"):
1936-
client = LambdaClient.initialize_from_env()
1934+
client = LambdaClient.initialize_client()
19371935

19381936
# Check that boto3.client was called with the right parameters and config
1937+
# Note: boto3 automatically picks up AWS_ENDPOINT_URL_LAMBDA from environment
19391938
mock_boto_client.assert_called_once()
19401939
call_args = mock_boto_client.call_args
1941-
assert call_args[0][0] == "lambdainternal"
1942-
assert call_args[1]["endpoint_url"] == "http://localhost:3000"
1940+
assert call_args[0][0] == "lambda"
19431941
assert "config" in call_args[1]
19441942
config = call_args[1]["config"]
19451943
assert config.connect_timeout == 5
@@ -1981,23 +1979,13 @@ def test_durable_service_client_protocol_get_execution_state():
19811979

19821980

19831981
@patch.dict("os.environ", {}, clear=True)
1984-
@patch(
1985-
"aws_durable_execution_sdk_python.lambda_service.LambdaClient.initialize_from_env"
1986-
)
1987-
def test_lambda_client_initialize_from_env_defaults(mock_init):
1988-
"""Test LambdaClient.initialize_from_env with default environment values."""
1989-
LambdaClient.initialize_from_env()
1982+
@patch("aws_durable_execution_sdk_python.lambda_service.LambdaClient.initialize_client")
1983+
def test_lambda_client_initialize_client_defaults(mock_init):
1984+
"""Test LambdaClient.initialize_client with default environment values."""
1985+
LambdaClient.initialize_client()
19901986
mock_init.assert_called_once_with()
19911987

19921988

1993-
@patch("os.environ")
1994-
def test_lambda_client_load_preview_botocore_models(mock_environ):
1995-
"""Test LambdaClient.load_preview_botocore_models method."""
1996-
LambdaClient.load_preview_botocore_models()
1997-
# Verify that AWS_DATA_PATH is set
1998-
assert "AWS_DATA_PATH" in mock_environ.__setitem__.call_args[0]
1999-
2000-
20011989
def test_checkpoint_error_handling():
20021990
"""Test CheckpointError exception handling in LambdaClient.checkpoint."""
20031991
mock_client = Mock()
@@ -2016,17 +2004,16 @@ def test_checkpoint_error_handling():
20162004

20172005
@patch.dict("os.environ", {}, clear=True)
20182006
@patch("boto3.client")
2019-
def test_lambda_client_initialize_from_env_no_endpoint(mock_boto_client):
2020-
"""Test LambdaClient.initialize_from_env without AWS_ENDPOINT_URL_LAMBDA."""
2007+
def test_lambda_client_initialize_client_no_endpoint(mock_boto_client):
2008+
"""Test LambdaClient.initialize_client without AWS_ENDPOINT_URL_LAMBDA."""
20212009
mock_client = Mock()
20222010
mock_boto_client.return_value = mock_client
20232011

2024-
with patch.object(LambdaClient, "load_preview_botocore_models"):
2025-
client = LambdaClient.initialize_from_env()
2012+
client = LambdaClient.initialize_client()
20262013

20272014
# Verify the call was made with the expected arguments including config
20282015
call_args = mock_boto_client.call_args
2029-
assert call_args[0] == ("lambdainternal",)
2016+
assert call_args[0] == ("lambda",)
20302017
assert "config" in call_args[1]
20312018
assert isinstance(client, LambdaClient)
20322019

0 commit comments

Comments
 (0)