nimble-aws 0.1.0__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.
nimble_aws/__init__.py ADDED
File without changes
@@ -0,0 +1,38 @@
1
+ import json
2
+
3
+ from .config import env
4
+ from .session import Session
5
+
6
+
7
+ class ApiGateway(Session):
8
+
9
+ async def post_to_connection(self, connection_id, data, region=env.region):
10
+ """
11
+ Send a message to a client's WebSocket connection.
12
+ :param connection_id: The ID of the connection.
13
+ :param data: The message to send.
14
+ :param region: The region of the connection (default: us-east-1).
15
+ :return: The response from the API Gateway Management API.
16
+ """
17
+ session = await self.session
18
+ async with session.create_client("apigatewaymanagementapi", region_name=region) as client:
19
+ response = await client.post_to_connection(
20
+ ConnectionId=connection_id,
21
+ Data=json.dumps(data).encode("utf-8")
22
+ )
23
+ return response
24
+
25
+ async def get_api_key(self, api_key_id, region=env.region):
26
+ """
27
+ Get an API key.
28
+ :param api_key_id: The ID of the API key
29
+ :param region: The region of the API key (default: us-east-1).
30
+ :return: The response from the API Gateway API.
31
+ """
32
+ session = await self.session
33
+ async with session.create_client("apigateway", region_name=region) as client:
34
+ response = await client.get_api_key(
35
+ apiKey=api_key_id,
36
+ includeValue=True
37
+ )
38
+ return response
@@ -0,0 +1,51 @@
1
+ from .config import env
2
+ from .session import Session
3
+
4
+
5
+ class AppSync(Session):
6
+
7
+ async def list_keys(self, api_id, max_results=10, region=env.region):
8
+ """
9
+ List API keys.
10
+ :param api_id: The ID of the API.
11
+ :param max_results: The maximum number of results to return (default: 10).
12
+ :param region: The region of the API (default: us-east-1).
13
+ :return: The response from the AppSync API.
14
+ """
15
+ session = await self.session
16
+ async with session.create_client(service_name="appsync", region_name=region) as client:
17
+ response = await client.list_api_keys(
18
+ apiId=api_id,
19
+ maxResults=max_results
20
+ )
21
+ return response
22
+
23
+ async def get_key(self, api_id, key_id, region=env.region):
24
+ """
25
+ Get an API key.service_name=
26
+ :param api_id: The ID of the API.
27
+ :param key_id: The ID of the key.
28
+ :param region: The region of the API (default: us-east-1).
29
+ :return: The value of the provided API key id.
30
+ """
31
+ session = await self.session
32
+ async with session.create_client(service_name="appsync", region_name=region) as client:
33
+ response = await client.list_api_keys(
34
+ apiId=api_id,
35
+ maxResults=100
36
+ )
37
+ api_key = next((key["id"] for key in response["apiKeys"] if key["id"] == key_id), response["apiKeys"][0]["id"])
38
+ return api_key
39
+
40
+ async def get_domain(self, api_id, region=env.region):
41
+ """
42
+ Get the domain name of an API.
43
+ :param api_id: The ID of the API.
44
+ :param region: The region of the API (default: us-east-1).
45
+ :return: The domain name of the API.
46
+ """
47
+ session = await self.session
48
+ async with session.create_client(service_name="appsync", region_name=region) as client:
49
+ response = await client.list_graphql_apis()
50
+ domain_name = next((domain["uris"]["GRAPHQL"] for domain in response["graphqlApis"] if domain["apiId"] == api_id), None)
51
+ return domain_name
@@ -0,0 +1,19 @@
1
+ from .config import env
2
+ from .session import Session
3
+
4
+
5
+ class Cognito(Session):
6
+
7
+ async def get_user(self, auth, region=env.region):
8
+ """
9
+ Get a user.
10
+ :param auth: The user's authentication token.
11
+ :param region: The region of the user (default: us-east-1).
12
+ :return: The response from the Cognito Identity Provider API.
13
+ """
14
+ session = await self.session
15
+ async with session.create_client(service_name="cognito-idp", region_name=region) as client:
16
+ response = await client.get_user(
17
+ AccessToken=auth
18
+ )
19
+ return response
@@ -0,0 +1,10 @@
1
+ from pydantic import Field
2
+ from pydantic_settings import BaseSettings
3
+ from typing import Optional
4
+
5
+
6
+ class Environment(BaseSettings):
7
+ region: Optional[str] = Field(default="us-east-1", alias="REGION")
8
+
9
+
10
+ env = Environment()
@@ -0,0 +1,193 @@
1
+ import json
2
+ import asyncio
3
+ from decimal import Decimal
4
+
5
+ from functional import seq
6
+ from boto3.dynamodb.types import TypeDeserializer, TypeSerializer
7
+
8
+ from .config import env
9
+ from .session import Session
10
+
11
+
12
+ serializer = TypeSerializer()
13
+ deserializer = TypeDeserializer()
14
+
15
+
16
+ class DynamoDB(Session):
17
+
18
+ @staticmethod
19
+ def preprocess_item(item):
20
+ item = json.loads(json.dumps(item), parse_float=Decimal)
21
+ try:
22
+ item = {k: serializer.serialize(v) for k, v in item.items()}
23
+ except AttributeError:
24
+ return serializer.serialize(item)
25
+
26
+ @staticmethod
27
+ def process_item(item):
28
+ return {k: serializer.serialize(v) for k, v in item.items()}
29
+
30
+ async def describe_table(self, table_name, region=env.region):
31
+ """
32
+ Describe a DynamoDB table.
33
+ :param table_name: The name of the table.
34
+ :param region: The region of the table (default: us-east-1).
35
+ :return: The response from the DynamoDB API.
36
+ """
37
+
38
+ session = await self.session
39
+ async with session.create_client(service_name="dynamodb", region_name=region) as client:
40
+ response = await client.describe_table(
41
+ TableName=table_name
42
+ )
43
+ return response
44
+
45
+ async def put_items(self, table_name, items, region=env.region):
46
+ """
47
+ Put items into a DynamoDB table.
48
+ :param table_name: The name of the table.
49
+ :param items: The items to put.
50
+ :param region: The region of the table (default: us-east-1).
51
+ :return: The response from the DynamoDB API.
52
+ """
53
+
54
+ session = await self.session
55
+ async with session.create_client(service_name="dynamodb", region_name=region) as client:
56
+ tasks = [client.put_item(
57
+ TableName=table_name,
58
+ Item=self.preprocess_item(item)
59
+ ) for item in items]
60
+ result = await asyncio.gather(*tasks)
61
+ return result
62
+
63
+ async def delete_items(self, table_name, id_list, region=env.region):
64
+ """
65
+ Delete items from a DynamoDB table.
66
+ :param table_name: The name of the table.
67
+ :param id_list: The IDs of the items to delete.
68
+ :param region: The region of the table (default: us-east-1).
69
+ :return: The response from the DynamoDB API.
70
+ """
71
+
72
+ session = await self.session
73
+ async with session.create_client(service_name="dynamodb", region_name=region) as client:
74
+ tasks = [client.delete_item(
75
+ TableName=table_name,
76
+ Key=self.preprocess_item(id)
77
+ ) for id in id_list]
78
+ result = await asyncio.gather(*tasks)
79
+ return result
80
+
81
+ async def get_item(self, table_name, id, region=env.region):
82
+ """
83
+ Get an item from a DynamoDB table.
84
+ :param table_name: The name of the table.
85
+ :param id: The ID of the item to get.
86
+ :param region: The region of the table (default: us-east-1).
87
+ :return: The serialized item from the DynamoDB API.
88
+ """
89
+
90
+ session = await self.session
91
+ async with session.create_client(service_name="dynamodb", region_name=region) as client:
92
+ response = await client.get_item(
93
+ TableName=table_name,
94
+ Key=self.preprocess_item(id)
95
+ )
96
+ result = self.process_item(response.get("Item", {}))
97
+ return result
98
+
99
+ async def get_items(self, table_name, id_list, region=env.region):
100
+ """
101
+ Get many items from a DynamoDB table.
102
+ :param table_name: The name of the table.
103
+ :param id_list: The IDs of the items to get.
104
+ :param region: The region of the table (default: us-east-1).
105
+ :return: The serialized items from the DynamoDB API.
106
+ """
107
+
108
+ session = await self.session
109
+ async with session.create_client(service_name="dynamodb", region_name=region) as client:
110
+ tasks = [client.get_item(
111
+ TableName=table_name,
112
+ Key=self.preprocess_item(id)
113
+ ) for id in id_list]
114
+ response = await asyncio.gather(*tasks)
115
+ result = [self.process_item(item.get("Item", {})) for item in response]
116
+ return result
117
+
118
+ async def index_query(self, table_mname, index, filters, region=env.region, **kwargs):
119
+ """
120
+ Get many items from a DynamoDB table using an index.
121
+ :param table_mname: The name of the table.
122
+ :param index: The index definition to query (example: {"name": "metadata-index", "field": "metadata", "value": "audio"}).
123
+ :param filters: The filters to apply (example: {"deleted": false}).
124
+ :param region: The region of the table (default: us-east-1).
125
+ :param kwargs: Additional arguments to pass to the DynamoDB API.
126
+ :return: The serialized items from the DynamoDB API.
127
+ """
128
+
129
+ filters.update({index["field"]: index["value"]})
130
+ expression_attr = self.preprocess_item({f":{k}": filters[k] for k in filters.keys()})
131
+
132
+ session = await self.session
133
+ async with session.create_client(service_name="dynamodb", region_name=region) as client:
134
+ response = await client.query(
135
+ TableName=table_mname,
136
+ IndexName=index["name"],
137
+ KeyConditionExpression=f"#{index['field']} = :{index['field']}",
138
+ ExpressionAttributeNames={f"#{index['field']}": index["field"]},
139
+ ExpressionAttributeValues=expression_attr,
140
+ **kwargs
141
+ )
142
+ result = [self.process_item(item) for item in response.get("Items", [])]
143
+ return result
144
+
145
+ async def scan_dynamo(self, table_name, region=env.region):
146
+ """
147
+ Scan a DynamoDB table.
148
+ :param table_name: The name of the table.
149
+ :param region: The region of the table (default: us-east-1).
150
+ :return: The serialized items from the DynamoDB API
151
+ """
152
+
153
+ session = await self.session
154
+ async with session.create_client(service_name="dynamodb", region_name=region) as client:
155
+ response = await client.scan(
156
+ TableName=table_name
157
+ )
158
+ result = list(seq(response.get("Items", [])).map(self.process_item))
159
+ while "LastEvaluatedKey" in response:
160
+ response = await client.scan(
161
+ TableName=table_name,
162
+ ExclusiveStartKey=response["LastEvaluatedKey"]
163
+ )
164
+ result.extend(list(seq(response.get("Items", [])).map(self.process_item)))
165
+ return result
166
+
167
+ async def update_items(self, table_name, items, key_fields, region=env.region):
168
+ """
169
+ Update items in a DynamoDB table.
170
+ :param table_name: The name of the table.
171
+ :param items: The items to update.
172
+ :param key_fields: The fields to use as keys.
173
+ :param region: The region of the table (default: us-east-1).
174
+ :return: The serialized new items from the DynamoDB API.
175
+ """
176
+
177
+ items = [self.preprocess_item(item) for item in items]
178
+
179
+ session = await self.session
180
+ async with session.create_client(service_name="dynamodb", region_name=region) as client:
181
+ tasks = [client.update_item(
182
+ TableName=table_name,
183
+ Key={k: item.pop(k) for k in key_fields},
184
+ ReturnValues="ALL_NEW",
185
+ AttributeValues={
186
+ **{k: {
187
+ "Action": "PUT",
188
+ "Value": v,
189
+ } for k, v in item.items()}}
190
+ ) for item in items]
191
+ response = await asyncio.gather(*tasks)
192
+ result = [self.process_item(item.get("Attributes", {})) for item in response]
193
+ return result
@@ -0,0 +1,26 @@
1
+ import asyncio
2
+
3
+ from .config import env
4
+ from .session import Session
5
+
6
+
7
+ class EventBridge(Session):
8
+
9
+ async def publish_events(self, messages, batch_size=10, region=env.region):
10
+ """
11
+ Publish events to an EventBridge bus.
12
+ :param messages: The messages to publish.
13
+ :param batch_size: The number of messages to publish at a time (default: 10).
14
+ :param region: The region of the bus (default: us-east-1).
15
+ :return: The response from the EventBridge API.
16
+ """
17
+
18
+ chunks = [messages[i:i + batch_size] for i in range(0, len(messages), batch_size)]
19
+
20
+ session = await self.session
21
+ async with session.create_client(service_name="events", region_name=region) as client:
22
+ tasks = [client.put_events(
23
+ Entries=chunk
24
+ ) for chunk in chunks]
25
+ result = await asyncio.gather(*tasks)
26
+ return result
@@ -0,0 +1,51 @@
1
+ import asyncio
2
+
3
+ from .config import env
4
+ from .session import Session
5
+
6
+
7
+ class Glue(Session):
8
+
9
+ async def get_jobs(self, region=env.region):
10
+ """
11
+ Get a list of jobs.
12
+ :param region: The region of the jobs (default: us-east-1).
13
+ :return: The response from the Glue API.
14
+ """
15
+ session = await self.session
16
+ async with session.create_client(service_name="glue", region_name=region) as client:
17
+ response = await client.get_jobs()
18
+ return response
19
+
20
+ async def get_job_runs(self, job_name, max_results, region=env.region):
21
+ """
22
+ Get a list of job runs.
23
+ :param job_name: The name of the job.
24
+ :param max_results: The maximum number of results to return.
25
+ :param region: The region of the job (default: us-east-1).
26
+ :return: The response from the Glue API.
27
+ """
28
+ session = await self.session
29
+ async with session.create_client(service_name="glue", region_name=region) as client:
30
+ response = await client.get_job_runs(
31
+ JobName=job_name,
32
+ MaxResults=max_results
33
+ )
34
+ return response
35
+
36
+ async def get_jobs_runs(self, job_names, max_results, region=env.region):
37
+ """
38
+ Get a list of job runs for multiple jobs.
39
+ :param job_names: The names of the jobs.
40
+ :param max_results: The maximum number of results to return.
41
+ :param region: The region of the jobs (default: us-east-1).
42
+ :return: The response from the Glue API.
43
+ """
44
+ session = await self.session
45
+ async with session.create_client(service_name="glue", region_name=region) as client:
46
+ tasks = [client.get_job_runs(
47
+ JobName=job_name,
48
+ MaxResults=max_results
49
+ ) for job_name in job_names]
50
+ response = await asyncio.gather(*tasks)
51
+ return response
@@ -0,0 +1,26 @@
1
+ import json
2
+
3
+ from .config import env
4
+ from .session import Session
5
+
6
+
7
+ class Lambda(Session):
8
+
9
+ async def invoke(self, function_name, payload, invocation_type="RequestResponse", region=env.region):
10
+ """
11
+ Invoke a Lambda function.
12
+ :param function_name: The name of the function.
13
+ :param payload: The payload to send to the function.
14
+ :param invocation_type: The invocation type, valid values are Event | RequestResponse | DryRun (default: RequestResponse).
15
+ :param region: The region of the function (default: us-east-1).
16
+ :return: The response payload from the Lambda API.
17
+ """
18
+ session = await self.session
19
+ async with session.create_client("lambda", region_name=region) as client:
20
+ response = await client.invoke(
21
+ FunctionName=function_name,
22
+ InvocationType=invocation_type,
23
+ Payload=json.dumps(payload).encode("utf-8")
24
+ )
25
+ return json.loads(response["Payload"].read().decode("utf-8")) if invocation_type == "RequestResponse" else response["Payload"].read()
26
+
@@ -0,0 +1,167 @@
1
+ import asyncio
2
+ from botocore.client import Config
3
+
4
+ from .config import env
5
+ from .session import Session
6
+
7
+
8
+ class S3(Session):
9
+
10
+ @staticmethod
11
+ def extract_filename_from_files_list(files_list):
12
+ return [f"{file['Name']}/{content['Key']}" for file in files_list for content in file["Contents"]]
13
+
14
+ async def get_files(self, bucket, paths, decode=True, region=env.region):
15
+ """
16
+ Get a list of files from an S3 bucket.
17
+ :param bucket: The name of the bucket.
18
+ :param paths: The paths to the files.
19
+ :param decode: Whether to decode the files (default: True).
20
+ :param region: The region of the bucket (default: us-east-1).
21
+ :return: The files.
22
+ """
23
+
24
+ session = await self.session
25
+ async with session.create_client(service_name="s3", region_name=region) as client:
26
+ tasks = [client.get_object(Bucket=bucket, Key=path) for path in paths]
27
+ results = await asyncio.gather(*tasks)
28
+ files = [await result["Body"].read() for result in results]
29
+ return [file.decode("utf-8") for file in files] if decode else files
30
+
31
+ async def list_files(self, bucket, prefix_list, region=env.region):
32
+ """
33
+ List files in an S3 bucket.
34
+ :param bucket: The name of the bucket.
35
+ :param prefix_list: The prefixes to list.
36
+ :param region: The region of the bucket (default: us-east-1).
37
+ :return: The response from the S3 API.
38
+ """
39
+
40
+ session = await self.session
41
+ async with session.create_client(service_name="s3", region_name=region) as client:
42
+ tasks = [client.list_objects_v2(Bucket=bucket, Prefix=prefix, Delimiter="/") for prefix in prefix_list]
43
+ results = await asyncio.gather(*tasks)
44
+ return results
45
+
46
+ async def put_file(self, bucket, key, body, region=env.region):
47
+ """
48
+ Put a file into an S3 bucket.
49
+ :param bucket: The name of the bucket.
50
+ :param key: The key of the file.
51
+ :param body: The body of the file.
52
+ :param region: The region of the bucket (default: us-east-1).
53
+ :return: The response from the S3 API.
54
+ """
55
+
56
+ session = await self.session
57
+ async with session.create_client(service_name="s3", region_name=region) as client:
58
+ response = await client.put_object(Bucket=bucket, Key=key, Body=body)
59
+ return response
60
+
61
+ async def put_files(self, bucket, objects, region=env.region):
62
+ """
63
+ Put files into an S3 bucket.
64
+ :param bucket: The name of the bucket.
65
+ :param objects: The objects to put.
66
+ :param region: The region of the bucket (default: us-east-1).
67
+ :return: The response from the S3 API.
68
+ """
69
+
70
+ session = await self.session
71
+ async with session.create_client(service_name="s3", region_name=region) as client:
72
+ tasks = [client.put_object(Bucket=bucket, Key=object["key"], Body=object["body"]) for object in objects]
73
+ results = await asyncio.gather(*tasks)
74
+ return results
75
+
76
+ async def put_files_with_content_type(self, bucket, objects, region=env.region):
77
+ """
78
+ Put files into an S3 bucket with content type.
79
+ :param bucket: The name of the bucket.
80
+ :param objects: The objects to put.
81
+ :param region: The region of the bucket (default: us-east-1).
82
+ :return: The response from the S3 API.
83
+ """
84
+
85
+ session = await self.session
86
+ async with session.create_client(service_name="s3", region_name=region) as client:
87
+ tasks = [client.put_object(Bucket=bucket, Key=object["key"], Body=object["body"], ContentType=object["type"]) for object in objects]
88
+ results = await asyncio.gather(*tasks)
89
+ return results
90
+
91
+ async def put_files_with_metadata(self, bucket, objects, region=env.region):
92
+ """
93
+ Put files into an S3 bucket with metadata.
94
+ :param bucket: The name of the bucket.
95
+ :param objects: The objects to put.
96
+ :param region: The region of the bucket (default: us-east-1).
97
+ :return: The response from the S3 API.
98
+ """
99
+
100
+ session = await self.session
101
+ async with session.create_client(service_name="s3", region_name=region) as client:
102
+ tasks = [client.put_object(Bucket=bucket, Key=object["key"], Body=object["body"], Metadata=object["metadata"]) for object in objects]
103
+ results = await asyncio.gather(*tasks)
104
+ return results
105
+
106
+ async def head_files(self, bucket, keys, region=env.region):
107
+ """
108
+ Get the metadata of files in an S3 bucket.
109
+ :param bucket: The name of the bucket.
110
+ :param keys: The keys of the files.
111
+ :param region: The region of the bucket (default: us-east-1).
112
+ :return: The response from the S3 API.
113
+ """
114
+
115
+ session = await self.session
116
+ async with session.create_client(service_name="s3", region_name=region) as client:
117
+ tasks = [client.head_object(Bucket=bucket, Key=key) for key in keys]
118
+ results = await asyncio.gather(*tasks)
119
+ return results
120
+
121
+ async def generate_pre_signed_url(self, bucket, item, expiration, region=env.region):
122
+ """
123
+ Generate a pre-signed URL for a file in an S3 bucket.
124
+ :param bucket: The name of the bucket.
125
+ :param item: The item to generate a URL for.
126
+ :param expiration: The expiration time of the URL.
127
+ :param region: The region of the bucket (default: us-east-1).
128
+ :return: The pre-signed URL.
129
+ """
130
+
131
+ session = await self.session
132
+ async with session.create_client(service_name="s3", region_name=region, config=Config(signature_version="s3v4")) as client:
133
+ response = await client.generate_presigned_url(
134
+ ClientMethod="get_object",
135
+ Params={
136
+ "Bucket": bucket,
137
+ "Key": item["key"],
138
+ "ReponseContentDisposition": f"attachment; filename={item['name']}"
139
+ },
140
+ ExpiresIn=expiration
141
+ )
142
+ return response
143
+
144
+ async def generate_pre_signed_urls(self, bucket, data, expiration, region=env.region):
145
+ """
146
+ Generate pre-signed URLs for files in an S3 bucket.
147
+ :param bucket: The name of the bucket.
148
+ :param data: The data to generate URLs for.
149
+ :param expiration: The expiration time of the URLs.
150
+ :param region: The region of the bucket (default: us-east-1).
151
+ :return: The pre-signed URLs.
152
+ """
153
+
154
+ session = await self.session
155
+ async with session.create_client(service_name="s3", region_name=region, config=Config(signature_version="s3v4")) as client:
156
+ tasks = [
157
+ client.generate_presigned_url(
158
+ ClientMethod="get_object",
159
+ Params={
160
+ "Bucket": bucket,
161
+ "Key": item["key"],
162
+ "ReponseContentDisposition": f"attachment; filename={item['name']}"
163
+ },
164
+ ExpiresIn=expiration
165
+ ) for item in data]
166
+ results = await asyncio.gather(*tasks)
167
+ return results
@@ -0,0 +1,20 @@
1
+ import json
2
+
3
+ from .config import env
4
+ from .session import Session
5
+
6
+
7
+ class SecretsManager(Session):
8
+
9
+ async def get_secret(self, secret_id, region=env.region):
10
+ """
11
+ Get a secret.
12
+ :param secret_id: The ID of the secret.
13
+ :param region: The region of the secret (default: us-east-1).
14
+ :return: The requested secret id value.
15
+ """
16
+ session = await self.session
17
+ async with session.create_client(service_name="secretsmanager", region_name=region) as client:
18
+ response = await client.get_secret_value(SecretId=secret_id)
19
+ secrets = json.loads(response["SecretString"])
20
+ return secrets
@@ -0,0 +1,22 @@
1
+ from aiobotocore.session import get_session
2
+
3
+
4
+ class Singleton(type):
5
+ _instances = {}
6
+
7
+ def __call__(cls, *args, **kwargs):
8
+ if cls not in cls._instances:
9
+ cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
10
+ return cls._instances[cls]
11
+
12
+
13
+ class Session(metaclass=Singleton):
14
+
15
+ def __init__(self):
16
+ self._session = None
17
+
18
+ @property
19
+ def session(self):
20
+ if self._session is None:
21
+ self._session = get_session()
22
+ return self._session
@@ -0,0 +1,38 @@
1
+ import json
2
+ import asyncio
3
+
4
+ from .config import env
5
+ from .utils import flatten
6
+ from .session import Session
7
+
8
+
9
+ class SFN(Session):
10
+
11
+ async def run_sync_execution(self, state_machine_arn, payload, region=env.region):
12
+ """
13
+ Start an execution.
14
+ :param state_machine_arn: The ARN of the state machine.
15
+ :param input: The input to the execution.
16
+ :param region: The region of the state machine (default: us-east-1).
17
+ :return: The output from the Step Functions API.
18
+ """
19
+ session = await self.session
20
+ async with session.create_client(service_name="stepfunctions", region_name=region) as client:
21
+ response = await client.start_sync_execution(
22
+ stateMachineArn=state_machine_arn,
23
+ input=json.dumps(payload)
24
+ )
25
+ return json.loads(response.get("output") or response.get("cause"))
26
+
27
+ async def run_sync_executions(self, data, region=env.region):
28
+ """
29
+ Start multiple executions.
30
+ :param data: The data to execute.
31
+ :param region: The region of the state machine (default: us-east-1).
32
+ :return: The output from the Step Functions API.
33
+ """
34
+ session = await self.session
35
+ async with session.create_client(service_name="stepfunctions", region_name=region) as client:
36
+ tasks = [client.start_sync_execution(stateMachineArn=item["arn"], input=json.dumps(item["input"])) for item in data]
37
+ responses = await asyncio.gather(*tasks)
38
+ return flatten([json.loads(response.get("output") or response.get("cause")) for response in responses])
@@ -0,0 +1,35 @@
1
+ import asyncio
2
+
3
+ from .config import env
4
+ from .session import Session
5
+
6
+
7
+ class SNS(Session):
8
+
9
+ async def publish_messages_to_topic(self, topic_arn, messages, region=env.region):
10
+ """
11
+ Publish messages to a topic.
12
+ :param topic_arn: The ARN of the topic.
13
+ :param messages: The messages to publish.
14
+ :param region: The region of the topic (default: us-east-1).
15
+ :return: The response from the SNS API.
16
+ """
17
+ session = await self.session
18
+ async with session.create_client(service_name="sns", region_name=region) as client:
19
+ tasks = [client.publish(TopicArn=topic_arn, Message=message) for message in messages]
20
+ responses = await asyncio.gather(*tasks)
21
+ return responses
22
+
23
+ async def publish_messages_with_attributes_to_topic(self, topic_arn, messages, region=env.region):
24
+ """
25
+ Publish messages with attributes to a topic.
26
+ :param topic_arn: The ARN of the topic.
27
+ :param messages: The messages to publish.
28
+ :param region: The region of the topic (default: us-east-1).
29
+ :return: The response from the SNS API.
30
+ """
31
+ session = await self.session
32
+ async with session.create_client(service_name="sns", region_name=region) as client:
33
+ tasks = [client.publish(TopicArn=topic_arn, Message=message["message"], MessageAttributes=message["attributes"]) for message in messages]
34
+ responses = await asyncio.gather(*tasks)
35
+ return responses
@@ -0,0 +1,86 @@
1
+ import json
2
+ import asyncio
3
+ from uuid import uuid4
4
+
5
+ from .config import env
6
+ from .session import Session
7
+ from .utils import chunk_array
8
+
9
+
10
+ class SQS(Session):
11
+
12
+ @staticmethod
13
+ def get_messages(result):
14
+ return [json.loads(message["Body"]) for message in result.get("Messages", [])]
15
+
16
+ async def publish_messages_to_queue(self, queue_url, messages, batch_size=10, region=env.region):
17
+ """
18
+ Publish messages to a queue.
19
+ :param queue_url: The URL of the queue.
20
+ :param messages: The messages to publish.
21
+ :param batch_size: The number of messages to publish in a batch (default: 10).
22
+ :param region: The region of the queue (default: us-east-1).
23
+ :return: The response from the SQS API.
24
+ """
25
+ chunks = chunk_array(messages, batch_size)
26
+
27
+ session = await self.session
28
+ async with session.create_client(service_name="sqs", region_name=region) as client:
29
+ tasks = [
30
+ client.send_message_batch(
31
+ QueueUrl=queue_url,
32
+ Entries=[{"Id": str(uuid4()), "MessageBody": json.dumps(message)} for message in chunk]
33
+ ) for chunk in chunks]
34
+ responses = await asyncio.gather(*tasks)
35
+ return responses
36
+
37
+ async def read_ten_messages(self, queue_url, region=env.region, **kwargs):
38
+ """
39
+ Read ten messages from a queue.
40
+ :param queue_url: The URL of the queue.
41
+ :param region: The region of the queue (default: us-east-1).
42
+ :return: The messages from the SQS API.
43
+ """
44
+ session = await self.session
45
+ async with session.create_client(service_name="sqs", region_name=region) as client:
46
+ response = await client.receive_message(
47
+ QueueUrl=queue_url,
48
+ MaxNumberOfMessages=10,
49
+ **kwargs
50
+ )
51
+ return self.get_messages(response)
52
+
53
+
54
+ async def read_messages(self, queue_url, num_messages=10, region=env.region, **kwargs):
55
+ """
56
+ Read messages from a queue.
57
+ :param queue_url: The URL of the queue.
58
+ :param num_messages: The number of messages to read (default: 10).
59
+ :param region: The region of the queue (default: us-east-1).
60
+ :return: The messages from the SQS API.
61
+ """
62
+ messages_read = 0
63
+ all_messages = list()
64
+ messages = await self.read_ten_messages(queue_url, region, **kwargs)
65
+ all_messages.extend(messages)
66
+ messages_read += len(messages)
67
+ while messages and messages_read < num_messages:
68
+ messages = await self.read_ten_messages(queue_url, region, **kwargs)
69
+ all_messages.extend(messages)
70
+ messages_read += len(messages)
71
+ return all_messages
72
+
73
+ async def read_all_messages(self, queue_url, region=env.region, **kwargs):
74
+ """
75
+ Read all messages from a queue.
76
+ :param queue_url: The URL of the queue.
77
+ :param region: The region of the queue (default: us-east-1).
78
+ :return: The messages from the SQS API.
79
+ """
80
+ all_messages = list()
81
+ messages = await self.read_ten_messages(queue_url, region, **kwargs)
82
+ all_messages.extend(messages)
83
+ while messages:
84
+ messages = await self.read_ten_messages(queue_url, region, **kwargs)
85
+ all_messages.extend(messages)
86
+ return all_messages
@@ -0,0 +1,9 @@
1
+
2
+
3
+
4
+ def flatten(array):
5
+ return [item for sublist in array for item in sublist]
6
+
7
+
8
+ def chunk_array(array, chunk_size):
9
+ return [array[i:i + chunk_size] for i in range(0, len(array), chunk_size)]
@@ -0,0 +1,101 @@
1
+ import json
2
+ from decimal import Decimal
3
+ from datetime import datetime
4
+
5
+
6
+ class Encoder(json.JSONEncoder):
7
+
8
+ def defaul(self, obj):
9
+ if isinstance(obj, Decimal):
10
+ if obj % 1 == 0:
11
+ return int(obj)
12
+ return float(obj)
13
+ elif isinstance(obj, datetime):
14
+ return obj.strftime("%Y-%m-%d")
15
+ return str(obj)
16
+
17
+
18
+ class API:
19
+
20
+ def __init__(self, event, **args):
21
+ self.event = event
22
+ self.extra_params = args
23
+
24
+ @staticmethod
25
+ def get_default(data, field, default):
26
+ return data[field] if data.get(field) else default
27
+
28
+ @property
29
+ def body(self):
30
+ raw_body = self.get_default(self.event, field="body", default={})
31
+ return json.loads(raw_body)
32
+
33
+ @property
34
+ def headers(self):
35
+ raw_headers = self.get_default(self.event, field="headers", default={})
36
+ return {k.lower(): v for k, v in raw_headers.items()}
37
+
38
+ @property
39
+ def path_parameters(self):
40
+ return self.get_default(self.event, field="pathParameters", default={})
41
+
42
+ @property
43
+ def path(self):
44
+ return self.event["requestContext"]["resourcePath"] if self.event["requestContext"].get("resourcePath") else self.event["requestContext"]["routeKey"].split(" ")[-1]
45
+
46
+ @property
47
+ def query_string_parameters(self):
48
+ return self.get_default(self.event, field="queryStringParameters", default={})
49
+
50
+ @property
51
+ def request(self):
52
+ return {
53
+ "headers": self.headers,
54
+ "path": self.path,
55
+ "path_parameters": self.path_parameters,
56
+ "query_string_parameters": self.query_string_parameters,
57
+ "body": self.body
58
+ }
59
+
60
+ @property
61
+ def response_headers(self):
62
+ cors_headers = {}
63
+ origin = self.get_default(self.headers, field="origin", default="")
64
+ allowed = "*" in self.extra_params["cors-allowed-origin"]
65
+ if origin is self.extra_params["cors-allowed-origin"] or allowed:
66
+ cors_headers = {
67
+ "Access-Control-Allow-Origin": origin,
68
+ "Access-Control-Allow-Credentials": "true",
69
+ "Access-Control-Allow-Methods": self.extra_params["cors-allowed-methods"],
70
+ "Access-Control-Allow-Headers": self.extra_params["cors-allowed-headers"]
71
+ }
72
+ return {
73
+ **cors_headers,
74
+ "X-XSS-Protection": "1; mode=block",
75
+ "X-Frame-Options": "DENY",
76
+ "X-Content-Type-Options": "nosniff",
77
+ "Referrer-Policy": "strict-origin-when-cross-origin",
78
+ "Strict-Transport-Security": "max-age=31536000; includeSubDomains"
79
+ }
80
+
81
+ @property
82
+ def error_response(self, exception):
83
+ if exception.__class__.__name__ != "":
84
+ exception.args = ({"pt": "Erro", "en": "Error"}, 500)
85
+ return {
86
+ "statusCode": exception.args[1],
87
+ "headers": self.response_headers,
88
+ "body": {
89
+ "error": {
90
+ "type": type(exception).__name__,
91
+ "description": exception.args[0]
92
+ }
93
+ }
94
+ }
95
+
96
+ def success_response(self, data):
97
+ return {
98
+ "statusCode": 200,
99
+ "headers": self.response_headers,
100
+ "body": json.dumps(data, cls=Encoder, ensure_ascii=False)
101
+ }
@@ -0,0 +1,18 @@
1
+ Metadata-Version: 2.1
2
+ Name: nimble-aws
3
+ Version: 0.1.0
4
+ Summary:
5
+ Author: Lucas Tiense Blazzi
6
+ Author-email: lucast.blazzi@gmail.com
7
+ Requires-Python: >=3.11,<4.0
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.11
10
+ Classifier: Programming Language :: Python :: 3.12
11
+ Classifier: Programming Language :: Python :: 3.13
12
+ Requires-Dist: aiobotocore (==2.13.1)
13
+ Requires-Dist: boto3 (>=1.17.47,<2.0.0)
14
+ Requires-Dist: pydantic (>=2.4.2,<3.0.0)
15
+ Requires-Dist: pydantic-settings (>=2.0.3,<3.0.0)
16
+ Description-Content-Type: text/markdown
17
+
18
+
@@ -0,0 +1,20 @@
1
+ nimble_aws/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ nimble_aws/adapter/api_gateway.py,sha256=5nb06uiGIFeD6nD13UVSK0YbS21FJZQ3lNjiZsjEF0g,1410
3
+ nimble_aws/adapter/appsync.py,sha256=fMMJXiF0YUtRiMRVC_ZZsxumI4tJXvSLDvuHNsl4Uw0,2132
4
+ nimble_aws/adapter/cognito.py,sha256=r-mOMzYClgl-Y4kzZftcL8AxCcerIbIhSAyR09RKi6U,632
5
+ nimble_aws/adapter/config.py,sha256=LIubDzCOGNrDVOq8h-G0E7uhCtOYJYNrNQiF0aDAEOo,226
6
+ nimble_aws/adapter/dynamodb.py,sha256=gyNnrIJvskUAbeOn1BGO5uILSpcu8nfr9VaeeQazM7U,7916
7
+ nimble_aws/adapter/event_bridge.py,sha256=bIhx9v0gftIbwJgod1HNi_hLYvGaMQt3Whjq7OdK1Ik,930
8
+ nimble_aws/adapter/glue.py,sha256=IWJA2bIhov7g4z-7U3joWC9rAsVdVtpGAscy4dm72bU,1928
9
+ nimble_aws/adapter/lambda_serverless.py,sha256=2Qt0Jh5SRX9g47CsTqv0gpZI7T0RqSf0fs60HUw3AaY,1114
10
+ nimble_aws/adapter/s3.py,sha256=CHZZ7dgoUVxVv4qzeSqWS_lIwi-c_GcARQCwH6wYQZQ,7355
11
+ nimble_aws/adapter/secrets_manager.py,sha256=hDp-Y5PpCgaBxKsc_PaXfE01vQ7Q8M2J4NZS3FEdfIc,668
12
+ nimble_aws/adapter/session.py,sha256=-EwsD_mURbHK4Ywpt0JDoVzYbO6389BuUrW1gtlsdDk,523
13
+ nimble_aws/adapter/sfn.py,sha256=D3ixitC4niSgoLYULhbhTEHr3xq2OHSuxjnuwC1zCzc,1639
14
+ nimble_aws/adapter/sns.py,sha256=aZCN3Oh50YM2EfcWRURzIr-S6nUG94pWFStTOBNDvRg,1521
15
+ nimble_aws/adapter/sqs.py,sha256=3pBc49cWcnC8zd0-3EPjyxhSO5JXIo3GMlRHTwdfKmw,3430
16
+ nimble_aws/adapter/utils.py,sha256=4gvmhOUXksdIZs0t2NHb1r8qbQLnHWZUUkJC8cI4HuI,199
17
+ nimble_aws/middleware/api_gateway.py,sha256=CpWNfYtVcn5B7FQG60GUTWoAEP2ZJ8YD4yTWZkF9t5Q,3395
18
+ nimble_aws-0.1.0.dist-info/METADATA,sha256=S3eBpcnsgJSqbfEDQ73WvvUs4MzwbQczdX_g0ID3POY,571
19
+ nimble_aws-0.1.0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
20
+ nimble_aws-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: poetry-core 1.9.1
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any