simple_aws_lambda 0.3.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,60 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ from pathlib import Path
4
+ from functools import cached_property
5
+
6
+ _dir_here = Path(__file__).absolute().parent
7
+ PACKAGE_NAME = _dir_here.name
8
+
9
+
10
+ class PathEnum:
11
+ """
12
+ Centralized enumeration of all project paths with absolute path references.
13
+
14
+ Provides IDE-autocomplete-friendly access to all project directories and files using
15
+ absolute paths to eliminate current directory dependencies and ensure consistent path
16
+ resolution across different execution contexts and DevOps workflows.
17
+ """
18
+
19
+ @cached_property
20
+ def dir_home(self):
21
+ return Path.home()
22
+
23
+ dir_project_root = _dir_here.parent
24
+ dir_tmp = dir_project_root / "tmp"
25
+
26
+ # Source Code
27
+ dir_package = _dir_here
28
+ path_pyproject_toml = dir_project_root / "pyproject.toml"
29
+ path_requirements_txt = dir_project_root / "requirements.txt"
30
+ path_authors = dir_project_root / "AUTHORS.rst"
31
+ path_license = dir_project_root / "LICENSE.txt"
32
+ path_release_history = dir_project_root / "release-history.rst"
33
+
34
+ # Virtual Environment
35
+ dir_venv = dir_project_root / ".venv"
36
+ dir_venv_bin = dir_venv / "bin"
37
+ path_venv_bin_pip = dir_venv_bin / "pip"
38
+ path_venv_bin_python = dir_venv_bin / "python"
39
+ path_venv_bin_pytest = dir_venv_bin / "pytest"
40
+
41
+ # Test
42
+ dir_htmlcov = dir_project_root / "htmlcov"
43
+ path_cov_index_html = dir_htmlcov / "index.html"
44
+ dir_unit_test = dir_project_root / "tests"
45
+ dir_int_test = dir_project_root / "tests_int"
46
+ dir_load_test = dir_project_root / "tests_load"
47
+
48
+ # Documentation
49
+ dir_docs_source = dir_project_root / "docs" / "source"
50
+ dir_docs_build_html = dir_project_root / "docs" / "build" / "html"
51
+
52
+ # Build
53
+ dir_build = dir_project_root / "build"
54
+ dir_dist = dir_project_root / "dist"
55
+
56
+
57
+ path_enum = PathEnum()
58
+ """
59
+ Single entry point for all project paths with absolute path references.
60
+ """
@@ -0,0 +1,320 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ """
4
+ High-level recipes built on top of the client functions, such as finding the
5
+ latest layer version, cleaning up old versions, and managing cross account access.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import typing as T
11
+ import enum
12
+ from datetime import datetime
13
+ from datetime import timezone
14
+ from datetime import timedelta
15
+
16
+ import botocore.exceptions
17
+ from func_args.api import OPT
18
+
19
+ from .model import LayerVersion
20
+ from .client import list_layer_versions
21
+
22
+ if T.TYPE_CHECKING: # pragma: no cover
23
+ from mypy_boto3_lambda.client import LambdaClient
24
+
25
+
26
+ def get_latest_layer_version(
27
+ lambda_client: LambdaClient,
28
+ layer_name: str,
29
+ compatible_runtime: str = OPT,
30
+ compatible_architecture: str = OPT,
31
+ _sort_descending: bool = False,
32
+ ) -> LayerVersion | None:
33
+ """
34
+ Call the AWS Lambda Layer API to retrieve the latest deployed layer version.
35
+ If it returns ``None``, it indicates that no layer has been deployed yet.
36
+
37
+ Example: if layer has version 1, 2, 3, then this function return 3.
38
+ If there's no layer version created yet, then this function returns None.
39
+
40
+ Reference:
41
+
42
+ - https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/lambda.html#Lambda.Client.list_layer_versions
43
+ """
44
+ if _sort_descending:
45
+ max_items = 10
46
+ else:
47
+ max_items = 1
48
+ layer_versions = list_layer_versions(
49
+ lambda_client=lambda_client,
50
+ layer_name=layer_name,
51
+ compatible_runtime=compatible_runtime,
52
+ compatible_architecture=compatible_architecture,
53
+ max_items=max_items,
54
+ _sort_descending=_sort_descending,
55
+ ).all()
56
+ if len(layer_versions) == 0:
57
+ return None
58
+ else:
59
+ return layer_versions[0]
60
+
61
+
62
+ def cleanup_old_layer_versions(
63
+ lambda_client: LambdaClient,
64
+ layer_name: str,
65
+ keep_last_n_versions: int = 5,
66
+ keep_versions_newer_than_seconds: int = 90 * 24 * 60 * 60,
67
+ real_run: bool = False,
68
+ _sort_descending: bool = False,
69
+ ) -> list[int]:
70
+ """
71
+ Delete old Lambda layer versions based on retention policy.
72
+
73
+ Keeps layer versions if they meet ANY of these conditions:
74
+
75
+ - Among the last N versions (most recent)
76
+ - Created within the last N seconds
77
+
78
+ :param lambda_client: AWS Lambda client
79
+ :param layer_name: Name of the Lambda layer
80
+ :param keep_last_n_versions: Number of most recent versions to keep
81
+ :param keep_versions_newer_than_seconds: Keep versions newer than this many seconds
82
+ :param real_run: If True, actually delete versions. If False, only return what would be deleted
83
+
84
+ :returns: List of version numbers that were deleted (or would be deleted in simulation mode)
85
+
86
+ Ref:
87
+
88
+ - `delete_layer_version <https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/lambda/client/delete_layer_version.html>`_
89
+ """
90
+ # Get all layer versions
91
+ all_versions = list_layer_versions(
92
+ lambda_client=lambda_client,
93
+ layer_name=layer_name,
94
+ max_items=9999,
95
+ _sort_descending=True,
96
+ ).all()
97
+
98
+ # Only exam versions beyond the last N to keep
99
+ other_versions = all_versions[keep_last_n_versions:]
100
+
101
+ if len(other_versions) == 0:
102
+ return []
103
+
104
+ # Calculate cutoff date
105
+ delta = timedelta(seconds=keep_versions_newer_than_seconds)
106
+ cutoff_date = datetime.now(timezone.utc) - delta
107
+
108
+ versions_to_delete = []
109
+
110
+ for version in other_versions:
111
+ # Keep if it's newer than cutoff date
112
+ if version.created_datetime > cutoff_date: # pragma: no cover
113
+ continue
114
+
115
+ # This version should be deleted
116
+ versions_to_delete.append(version.version)
117
+
118
+ # Delete the versions (if real_run is True)
119
+ deleted_versions = []
120
+ for version_number in versions_to_delete:
121
+ deleted_versions.append(version_number)
122
+ if real_run:
123
+ try:
124
+ lambda_client.delete_layer_version(
125
+ LayerName=layer_name,
126
+ VersionNumber=version_number,
127
+ )
128
+ except botocore.exceptions.ClientError: # pragma: no cover
129
+ # Continue with other versions even if one fails
130
+ pass
131
+
132
+ return deleted_versions
133
+
134
+
135
+ class LambdaPermissionActionEnum(str, enum.Enum):
136
+ """
137
+ Enum for different Lambda layer permission actions.
138
+
139
+ See: https://docs.aws.amazon.com/lambda/latest/dg/permissions-layer-cross-account.html
140
+ """
141
+
142
+ get_layer_version = "lambda:GetLayerVersion"
143
+ list_layer_versions = "lambda:ListLayerVersions"
144
+
145
+
146
+ # Map action to a more human friendly name for statement id naming convention
147
+ action_to_name_mapper: dict[str, str] = {
148
+ LambdaPermissionActionEnum.get_layer_version.value: "GetLayerVersion",
149
+ LambdaPermissionActionEnum.list_layer_versions.value: "ListLayerVersions",
150
+ }
151
+
152
+
153
+ class LayerPrincipalTypeEnum(str, enum.Enum):
154
+ """
155
+ Enum for different types of layer principals.
156
+
157
+ Based on this AWS doc https://docs.aws.amazon.com/lambda/latest/dg/permissions-layer-cross-account.html
158
+ There are only three cross account Lambda layer permission patterns
159
+ The grant_aws_account_or_aws_organization_lambda_layer_version_access
160
+ and revoke_aws_account_or_aws_organization_lambda_layer_version_access
161
+ recipes only support these three patterns.
162
+ """
163
+
164
+ public = "public"
165
+ aws_account = "aws_account"
166
+ aws_organization = "aws_organization"
167
+
168
+
169
+ def identify_principal_type(principal: str) -> LayerPrincipalTypeEnum:
170
+ """
171
+ Identify the type of principal based on its format.
172
+
173
+ :param principal: The principal string to identify:
174
+ - "*" for public access
175
+ - "123456789012" for specific AWS account (12-digit account ID)
176
+ - "o-example123456" for AWS organization ID
177
+
178
+ :returns: The identified LayerPrincipalTypeEnum
179
+ """
180
+ if principal == "*":
181
+ return LayerPrincipalTypeEnum.public
182
+ elif principal.isdigit() and len(principal) == 12:
183
+ return LayerPrincipalTypeEnum.aws_account
184
+ elif principal.startswith("o-"):
185
+ return LayerPrincipalTypeEnum.aws_organization
186
+ else: # pragma: no cover
187
+ raise ValueError(f"Invalid principal format: {principal}")
188
+
189
+
190
+ def get_layer_permission_statement_id(
191
+ action: str,
192
+ principal: str,
193
+ ) -> str:
194
+ """
195
+ Encode the statement ID for Lambda layer permission based on action and principal.
196
+
197
+ A statement ID may only contain ``[a-zA-Z0-9-_]``, so the public principal
198
+ ``"*"`` is written as ``public``.
199
+ """
200
+ name = action_to_name_mapper[action]
201
+ if principal == "*":
202
+ principal_part = "public"
203
+ else:
204
+ principal_part = principal
205
+ return f"allow-{principal_part}-{name}"
206
+
207
+
208
+ def grant_aws_account_or_aws_organization_lambda_layer_version_access(
209
+ lambda_client: LambdaClient,
210
+ layer_name: str,
211
+ version_number: int,
212
+ principal: str,
213
+ ):
214
+ """
215
+ Grant other AWS accounts Lambda layer access to a specific layer version.
216
+
217
+ Idempotent version of the AWS Lambda add_layer_version_permission API that
218
+ automatically handles statement ID generation and manages conflicts by
219
+ allowing existing permissions to remain.
220
+
221
+ Grants the GetLayerVersion permission to the specified principal
222
+ (AWS account, AWS organization, or public access).
223
+
224
+ :param lambda_client: AWS Lambda client for the account that owns the layer
225
+ :param layer_name: Name of the Lambda layer
226
+ :param version_number: Version number of the layer to grant access to
227
+ :param principal: Principal to grant access to:
228
+ - "*" for public access
229
+ - "123456789012" for specific AWS account (12-digit account ID)
230
+ - "o-example123456" for AWS organization ID
231
+
232
+ Ref:
233
+
234
+ - `add_layer_version_permission <https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/lambda/client/add_layer_version_permission.html>`_
235
+ """
236
+ layer_principal_type = identify_principal_type(principal)
237
+ if layer_principal_type == LayerPrincipalTypeEnum.public:
238
+ kwargs = {"Principal": principal}
239
+ elif layer_principal_type == LayerPrincipalTypeEnum.aws_account:
240
+ kwargs = {"Principal": principal}
241
+ elif layer_principal_type == LayerPrincipalTypeEnum.aws_organization:
242
+ kwargs = {
243
+ "Principal": "*",
244
+ "OrganizationId": principal,
245
+ }
246
+ else: # pragma: no cover
247
+ raise ValueError(f"Unsupported principal type: {principal}")
248
+
249
+ def add_layer_version_permission(action: str):
250
+ statement_id = get_layer_permission_statement_id(
251
+ action=action,
252
+ principal=principal,
253
+ )
254
+ try:
255
+ lambda_client.add_layer_version_permission(
256
+ LayerName=layer_name,
257
+ VersionNumber=version_number,
258
+ StatementId=statement_id,
259
+ Action=action,
260
+ **kwargs,
261
+ )
262
+ except botocore.exceptions.ClientError as e: # pragma: no cover
263
+ if e.response["Error"]["Code"] == "ResourceConflictException":
264
+ pass
265
+ else:
266
+ raise
267
+
268
+ # Currently, AWS Lambda only supports granting GetLayerVersion permission
269
+ add_layer_version_permission(LambdaPermissionActionEnum.get_layer_version.value)
270
+
271
+
272
+ def revoke_aws_account_or_aws_organization_lambda_layer_version_access(
273
+ lambda_client: LambdaClient,
274
+ layer_name: str,
275
+ version_number: int,
276
+ principal: str,
277
+ ):
278
+ """
279
+ Revoke AWS accounts Lambda layer access from a specific layer version.
280
+
281
+ Idempotent version of the AWS Lambda remove_layer_version_permission API that
282
+ automatically handles statement ID generation and gracefully handles cases
283
+ where permissions don't exist.
284
+
285
+ Removes the GetLayerVersion permission from the specified principal
286
+ (AWS account, AWS organization, or public access).
287
+
288
+ :param lambda_client: AWS Lambda client for the account that owns the layer
289
+ :param layer_name: Name of the Lambda layer
290
+ :param version_number: Version number of the layer to revoke access from
291
+ :param principal: Principal to revoke access from:
292
+ - "*" for public access
293
+ - "123456789012" for specific AWS account (12-digit account ID)
294
+ - "o-example123456" for AWS organization ID
295
+
296
+ Ref:
297
+
298
+ - `remove_layer_version_permission <https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/lambda/client/remove_layer_version_permission.html>`_
299
+ """
300
+ identify_principal_type(principal)
301
+
302
+ def remove_layer_version_permission(action: str):
303
+ statement_id = get_layer_permission_statement_id(
304
+ action=action,
305
+ principal=principal,
306
+ )
307
+ try:
308
+ lambda_client.remove_layer_version_permission(
309
+ LayerName=layer_name,
310
+ VersionNumber=version_number,
311
+ StatementId=statement_id,
312
+ )
313
+ except botocore.exceptions.ClientError as e: # pragma: no cover
314
+ if e.response["Error"]["Code"] == "ResourceNotFoundException":
315
+ pass
316
+ else:
317
+ raise
318
+
319
+ # Currently, AWS Lambda only supports granting GetLayerVersion permission
320
+ remove_layer_version_permission(LambdaPermissionActionEnum.get_layer_version.value)
@@ -0,0 +1,2 @@
1
+ # -*- coding: utf-8 -*-
2
+
@@ -0,0 +1,148 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ import os
4
+ import sys
5
+ import contextlib
6
+ import subprocess
7
+ from pathlib import Path
8
+
9
+ __version__ = "0.2.1"
10
+
11
+
12
+ @contextlib.contextmanager
13
+ def temp_cwd(path: Path):
14
+ """
15
+ Temporarily set the current working directory (CWD) and automatically
16
+ switch back when it's done.
17
+ """
18
+ cwd = os.getcwd()
19
+ os.chdir(str(path))
20
+ try:
21
+ yield path
22
+ finally:
23
+ os.chdir(cwd)
24
+
25
+
26
+ def run_unit_test(
27
+ script: str,
28
+ root_dir: str,
29
+ ):
30
+ """
31
+ Run ``pytest -s --tb=native /path/to/script.py`` Command.
32
+
33
+ :param script: the path to test script
34
+ :param root_dir: the dir you want to temporarily set as cwd
35
+ """
36
+ bin_pytest = Path(sys.executable).parent / "pytest"
37
+ args = [
38
+ f"{bin_pytest}",
39
+ "-s",
40
+ "--tb=native",
41
+ script,
42
+ ]
43
+ with temp_cwd(Path(root_dir)):
44
+ subprocess.run(args)
45
+
46
+
47
+ def run_cov_test(
48
+ script: str,
49
+ module: str,
50
+ root_dir: str,
51
+ htmlcov_dir: str,
52
+ preview: bool = False,
53
+ is_folder: bool = False,
54
+ ):
55
+ """
56
+ The pytest-cov plugin gives you the coverage for entire project. What if
57
+ I want run per-module test independently and get per-module coverage?
58
+
59
+ This is a simple wrapper around pytest + coverage cli command. Allow you to run
60
+ coverage test from Python script and set the code coverage measurement scope.
61
+
62
+ Usage example:
63
+
64
+ suppose you have a source code folder structure like this::
65
+
66
+ /dir_git_repo/
67
+ /dir_git_repo/my_library
68
+ /dir_git_repo/my_library/__init__.py
69
+ /dir_git_repo/my_library/module1.py
70
+ /dir_git_repo/my_library/module2.py
71
+
72
+ In your module 1 unit test script, you can do this:
73
+
74
+ .. code-block:: python
75
+
76
+ from my_library.module1 import func1, func2
77
+
78
+ def test_func1():
79
+ pass
80
+
81
+ def test_func2():
82
+ pass
83
+
84
+ if __name__ == "__main__":
85
+ from fixa.pytest_cov_helper import run_cov_test
86
+
87
+ run_cov_test(
88
+ script=__file__,
89
+ module="my_library.module1", # test scope is the module1.py
90
+ root_dir="/path/to/dir_git_repo",
91
+ htmlcov_dir="/path/to/dir_git_repo/htmlcov",
92
+ )
93
+
94
+ In your all modules unit test script, you can do this:
95
+
96
+ .. code-block:: python
97
+
98
+ if __name__ == "__main__":
99
+ from fixa.pytest_cov_helper import run_cov_test
100
+
101
+ run_cov_test(
102
+ script=__file__,
103
+ module="my_library", # test scope is the my_library/
104
+ root_dir="/path/to/dir_git_repo",
105
+ htmlcov_dir="/path/to/dir_git_repo/htmlcov",
106
+ is_folder=True, # my_library is a folder
107
+ )
108
+
109
+ :param script: the test script absolute path
110
+ :param module: the dot notation to the python module you want to calculate
111
+ coverage
112
+ :param root_dir: the dir to dump coverage results binary file
113
+ :param htmlcov_dir: the dir to dump HTML output
114
+ :param preview: whether to open the HTML output in web browser after the test
115
+ :param is_folder: whether the module is a folder
116
+
117
+ Reference:
118
+
119
+ - https://pypi.org/project/pytest-cov/
120
+ """
121
+ bin_pytest = Path(sys.executable).parent / "pytest"
122
+ if is_folder:
123
+ script = f"{Path(script).parent}"
124
+ if module.endswith(".py"): # pragma: no cover
125
+ module = module[:-3]
126
+ args = [
127
+ f"{bin_pytest}",
128
+ "-s",
129
+ "--tb=native",
130
+ f"--rootdir={root_dir}",
131
+ f"--cov={module}",
132
+ "--cov-report",
133
+ "term-missing",
134
+ "--cov-report",
135
+ f"html:{htmlcov_dir}",
136
+ script,
137
+ ]
138
+ with temp_cwd(Path(root_dir)):
139
+ subprocess.run(args)
140
+ if preview: # pragma: no cover
141
+ platform = sys.platform
142
+ if platform in ["win32", "cygwin"]:
143
+ open_command = "start"
144
+ elif platform in ["darwin", "linux"]:
145
+ open_command = "open"
146
+ else:
147
+ raise NotImplementedError
148
+ subprocess.run([open_command, f"{Path(htmlcov_dir).joinpath('index.html')}"])
@@ -0,0 +1,134 @@
1
+ Metadata-Version: 2.4
2
+ Name: simple_aws_lambda
3
+ Version: 0.3.1
4
+ Summary: Objective Oriented Python SDK for AWS Lambda.
5
+ Author-email: Sanhe Hu <husanhe@gmail.com>
6
+ Maintainer-email: Sanhe Hu <husanhe@gmail.com>
7
+ License-Expression: MIT
8
+ Project-URL: Homepage, https://github.com/MacHu-GWU/simple_aws_lambda-project
9
+ Project-URL: Documentation, https://simple-aws-lambda.readthedocs.io/en/latest/
10
+ Project-URL: Repository, https://github.com/MacHu-GWU/simple_aws_lambda-project
11
+ Project-URL: Issues, https://github.com/MacHu-GWU/simple_aws_lambda-project/issues
12
+ Project-URL: Changelog, https://github.com/MacHu-GWU/simple_aws_lambda-project/blob/main/release-history.rst
13
+ Project-URL: Download, https://pypi.org/pypi/simple-aws-lambda#files
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Natural Language :: English
17
+ Classifier: Operating System :: Microsoft :: Windows
18
+ Classifier: Operating System :: MacOS
19
+ Classifier: Operating System :: Unix
20
+ Classifier: Programming Language :: Python :: 3
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Programming Language :: Python :: 3.14
25
+ Requires-Python: <4.0,>=3.11
26
+ Description-Content-Type: text/x-rst
27
+ License-File: LICENSE.txt
28
+ License-File: AUTHORS.rst
29
+ Requires-Dist: boto3<2.0.0,>=1.35.99
30
+ Requires-Dist: iterproxy<1.0.0,>=0.3.1
31
+ Requires-Dist: func_args<2.0.0,>=1.0.1
32
+ Provides-Extra: dev
33
+ Requires-Dist: rich<15.0.0,>=14.3.4; extra == "dev"
34
+ Requires-Dist: boto3-stubs[lambda]<2.0.0,>=1.35.99; extra == "dev"
35
+ Provides-Extra: test
36
+ Requires-Dist: pytest<10.0.0,>=9.1.1; extra == "test"
37
+ Requires-Dist: pytest-cov<8.0.0,>=7.1.0; extra == "test"
38
+ Requires-Dist: moto<6.0.0,>=5.1.10; extra == "test"
39
+ Provides-Extra: doc
40
+ Requires-Dist: Sphinx<9.0.0,>=8.2.3; extra == "doc"
41
+ Requires-Dist: sphinx-copybutton<1.0.0,>=0.5.2; extra == "doc"
42
+ Requires-Dist: sphinx-design<1.0.0,>=0.7.0; extra == "doc"
43
+ Requires-Dist: sphinx-jinja<3.0.0,>=2.0.2; extra == "doc"
44
+ Requires-Dist: furo==2025.12.19; extra == "doc"
45
+ Requires-Dist: pygments<3.0.0,>=2.18.0; extra == "doc"
46
+ Requires-Dist: ipython<8.19.0,>=8.18.1; extra == "doc"
47
+ Requires-Dist: ipykernel<8.0.0,>=7.3.0; extra == "doc"
48
+ Requires-Dist: nbsphinx<1.0.0,>=0.9.8; extra == "doc"
49
+ Requires-Dist: rstobj<3.0.0,>=2.0.0; extra == "doc"
50
+ Requires-Dist: docfly<4.0.0,>=3.0.3; extra == "doc"
51
+ Provides-Extra: mise
52
+ Requires-Dist: PyGithub<3.0.0,>=2.8.0; extra == "mise"
53
+ Requires-Dist: httpx2<3.0.0,>=2.13.1; extra == "mise"
54
+ Dynamic: license-file
55
+
56
+
57
+ .. image:: https://readthedocs.org/projects/simple-aws-lambda/badge/?version=latest
58
+ :target: https://simple-aws-lambda.readthedocs.io/en/latest/
59
+ :alt: Documentation Status
60
+
61
+ .. image:: https://github.com/MacHu-GWU/simple_aws_lambda-project/actions/workflows/main.yml/badge.svg
62
+ :target: https://github.com/MacHu-GWU/simple_aws_lambda-project/actions?query=workflow:CI
63
+
64
+ .. image:: https://codecov.io/gh/MacHu-GWU/simple_aws_lambda-project/branch/main/graph/badge.svg
65
+ :target: https://codecov.io/gh/MacHu-GWU/simple_aws_lambda-project
66
+
67
+ .. image:: https://img.shields.io/pypi/v/simple-aws-lambda.svg
68
+ :target: https://pypi.python.org/pypi/simple-aws-lambda
69
+
70
+ .. image:: https://img.shields.io/pypi/l/simple-aws-lambda.svg
71
+ :target: https://pypi.python.org/pypi/simple-aws-lambda
72
+
73
+ .. image:: https://img.shields.io/pypi/pyversions/simple-aws-lambda.svg
74
+ :target: https://pypi.python.org/pypi/simple-aws-lambda
75
+
76
+ .. image:: https://img.shields.io/badge/✍️_Release_History!--None.svg?style=social&logo=github
77
+ :target: https://github.com/MacHu-GWU/simple_aws_lambda-project/blob/main/release-history.rst
78
+
79
+ .. image:: https://img.shields.io/badge/⭐_Star_me_on_GitHub!--None.svg?style=social&logo=github
80
+ :target: https://github.com/MacHu-GWU/simple_aws_lambda-project
81
+
82
+ ------
83
+
84
+ .. image:: https://img.shields.io/badge/Link-API-blue.svg
85
+ :target: https://simple-aws-lambda.readthedocs.io/en/latest/py-modindex.html
86
+
87
+ .. image:: https://img.shields.io/badge/Link-Install-blue.svg
88
+ :target: `install`_
89
+
90
+ .. image:: https://img.shields.io/badge/Link-GitHub-blue.svg
91
+ :target: https://github.com/MacHu-GWU/simple_aws_lambda-project
92
+
93
+ .. image:: https://img.shields.io/badge/Link-Submit_Issue-blue.svg
94
+ :target: https://github.com/MacHu-GWU/simple_aws_lambda-project/issues
95
+
96
+ .. image:: https://img.shields.io/badge/Link-Request_Feature-blue.svg
97
+ :target: https://github.com/MacHu-GWU/simple_aws_lambda-project/issues
98
+
99
+ .. image:: https://img.shields.io/badge/Link-Download-blue.svg
100
+ :target: https://pypi.org/pypi/simple-aws-lambda#files
101
+
102
+
103
+ Welcome to ``simple_aws_lambda`` Documentation
104
+ ==============================================================================
105
+ .. image:: https://simple-aws-lambda.readthedocs.io/en/latest/_static/simple_aws_lambda-logo.png
106
+ :target: https://simple-aws-lambda.readthedocs.io/en/latest/
107
+
108
+ simple_aws_lambda is a Pythonic library that provides a simplified, high-level interface for AWS Lambda operations. Built on top of boto3, it offers intuitive data models, property-based access patterns, and comprehensive type hints to make working with AWS Lambda resources more developer-friendly and maintainable.
109
+
110
+ **Key Features:**
111
+
112
+ `Data Models <https://simple-aws-lambda.readthedocs.io/en/latest/02-Data-Model/index.html>`_ - Transform raw boto3 responses into Pythonic objects with property-based access, following the Raw Data Storage, Property-Based Access, and Core Data Extraction patterns to ensure API resilience and clean interfaces.
113
+
114
+ `Better Client <https://simple-aws-lambda.readthedocs.io/en/latest/01-Quick-Start/index.html>`_ - Enhance the standard boto3 Lambda client with idempotent operations, automatic pagination, better error handling, and direct return of data model objects instead of raw dictionaries.
115
+
116
+ `Recipes <https://simple-aws-lambda.readthedocs.io/en/latest/03-Cleanup-Old-Layer-Versions/index.html>`_ - Provide high-level functions for common Lambda layer management tasks such as version cleanup, cross-account access management, and intelligent layer discovery that combine multiple API calls with best practices.
117
+
118
+
119
+ .. _install:
120
+
121
+ Install
122
+ ------------------------------------------------------------------------------
123
+
124
+ ``simple_aws_lambda`` is released on PyPI, so all you need is to:
125
+
126
+ .. code-block:: console
127
+
128
+ $ pip install simple-aws-lambda
129
+
130
+ To upgrade to latest version:
131
+
132
+ .. code-block:: console
133
+
134
+ $ pip install --upgrade simple-aws-lambda
@@ -0,0 +1,14 @@
1
+ simple_aws_lambda/__init__.py,sha256=iwhKnzeBJLKxpRVjvzwiRE63_zNpIBfaKLITauVph-0,24
2
+ simple_aws_lambda/api.py,sha256=lcnw2LKEVWVPDsdy8Vjr9BCOMqd6-aZiiBzp5a6E320,761
3
+ simple_aws_lambda/client.py,sha256=Mu4OwobuS5NhJxi8R9sZrWR3gY0dUI-haHhOIImQiVQ,4216
4
+ simple_aws_lambda/model.py,sha256=jtepEmAnYzVuz-adFJ248idl81qHkUfGNdl_32vuysY,16085
5
+ simple_aws_lambda/paths.py,sha256=oL2TejRi1R5WntezHlZEtbOoEzTDrUwH3wnUIjB0YIU,1897
6
+ simple_aws_lambda/recipe.py,sha256=wqDGNQ2yCl102ALVU-lqgfprIRbSE6lncNOLlchYOD0,11219
7
+ simple_aws_lambda/vendor/__init__.py,sha256=O9CT1B2F-cVB8elT0EoCJbgkcffjvlmqteqavs4giDg,25
8
+ simple_aws_lambda/vendor/pytest_cov_helper.py,sha256=H2BJtFq3bwJHZtt-bxZ1yF9LnXHVDRZZ0NH-OvkRJdE,4063
9
+ simple_aws_lambda-0.3.1.dist-info/licenses/AUTHORS.rst,sha256=oo38V9AD_y57Ac69mKmiItWquV29SRi2aTCdKQo531A,767
10
+ simple_aws_lambda-0.3.1.dist-info/licenses/LICENSE.txt,sha256=Vc2EgX0hR-6Qw_RxS1IR-2qllqh4PiqSWFvrdnqZSDU,1084
11
+ simple_aws_lambda-0.3.1.dist-info/METADATA,sha256=icixOk-T_wg-R_idrHBrc-F85xqGAUy4uUjQ1zTfpSo,6516
12
+ simple_aws_lambda-0.3.1.dist-info/WHEEL,sha256=a-udL2m4V_6Yn8b-uKzWb12RjRxwwMo6ohYFM24tpaY,91
13
+ simple_aws_lambda-0.3.1.dist-info/top_level.txt,sha256=mbr6KY_Z2qyDT959NtI0sDtzWj-OPUaDXj-qu95C8Uk,18
14
+ simple_aws_lambda-0.3.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.2.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+