boto3-assist 0.35.0__py3-none-any.whl → 0.37.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.
@@ -35,6 +35,7 @@ class DynamoDBConnection(Connection):
35
35
  assume_role_arn: Optional[str] = None,
36
36
  assume_role_chain: Optional[List[str]] = None,
37
37
  assume_role_duration_seconds: Optional[int] = 3600,
38
+ use_connection_pool: bool = False,
38
39
  ) -> None:
39
40
  super().__init__(
40
41
  service_name="dynamodb",
@@ -46,6 +47,7 @@ class DynamoDBConnection(Connection):
46
47
  assume_role_arn=assume_role_arn,
47
48
  assume_role_chain=assume_role_chain,
48
49
  assume_role_duration_seconds=assume_role_duration_seconds,
50
+ use_connection_pool=use_connection_pool,
49
51
  )
50
52
 
51
53
  self.__dynamodb_client: DynamoDBClient | None = None
@@ -48,15 +48,15 @@ class DynamoDBKey:
48
48
  def to_dict(self) -> dict[str, str]:
49
49
  """
50
50
  Return a dictionary representation of this key for debugging.
51
-
51
+
52
52
  Returns:
53
53
  Dictionary with attribute name as key and value as the value.
54
-
54
+
55
55
  Example:
56
56
  >>> key = DynamoDBKey(attribute_name="pk", value="user#123")
57
57
  >>> key.to_dict()
58
58
  {'pk': 'user#123'}
59
-
59
+
60
60
  >>> # With lambda
61
61
  >>> key = DynamoDBKey(attribute_name="pk", value=lambda: "user#456")
62
62
  >>> key.to_dict()
@@ -119,8 +119,13 @@ class DynamoDBKey:
119
119
  for key, value in key_value_pairs:
120
120
  prefix = f"{key}#" if key else ""
121
121
  if value is None:
122
- parts.append(f"{prefix}")
122
+ # don't add the prefix we may want loose begins with and compound here will break it
123
+ # parts.append(f"{prefix}")
124
+ if len(parts) == 0:
125
+ parts.append(f"{prefix}")
126
+ # exit after the first None
123
127
  break
128
+
124
129
  elif len(str(value).strip()) == 0:
125
130
  parts.append(f"{key}")
126
131
  else:
@@ -0,0 +1,9 @@
1
+ """
2
+ Geek Cafe, LLC
3
+ Maintainers: Eric Wilson
4
+ MIT License. See Project Root for the license information.
5
+ """
6
+
7
+ from .s3 import S3
8
+
9
+ __all__ = ["S3"]
boto3_assist/s3/s3.py CHANGED
@@ -26,6 +26,7 @@ class S3(S3Connection):
26
26
  aws_end_point_url: Optional[str] = None,
27
27
  aws_access_key_id: Optional[str] = None,
28
28
  aws_secret_access_key: Optional[str] = None,
29
+ use_connection_pool: bool = False,
29
30
  ) -> None:
30
31
  """_summary_
31
32
 
@@ -35,6 +36,7 @@ class S3(S3Connection):
35
36
  aws_end_point_url (Optional[str], optional): _description_. Defaults to None.
36
37
  aws_access_key_id (Optional[str], optional): _description_. Defaults to None.
37
38
  aws_secret_access_key (Optional[str], optional): _description_. Defaults to None.
39
+ use_connection_pool (bool, optional): Use connection pooling. Defaults to False.
38
40
  """
39
41
  super().__init__(
40
42
  aws_profile=aws_profile,
@@ -42,11 +44,52 @@ class S3(S3Connection):
42
44
  aws_end_point_url=aws_end_point_url,
43
45
  aws_access_key_id=aws_access_key_id,
44
46
  aws_secret_access_key=aws_secret_access_key,
47
+ use_connection_pool=use_connection_pool,
45
48
  )
46
49
 
47
50
  self.__s3_object: S3Object | None = None
48
51
  self.__s3_bucket: S3Bucket | None = None
49
52
 
53
+ @classmethod
54
+ def from_pool(
55
+ cls,
56
+ aws_profile: Optional[str] = None,
57
+ aws_region: Optional[str] = None,
58
+ aws_end_point_url: Optional[str] = None,
59
+ **kwargs,
60
+ ) -> "S3":
61
+ """
62
+ Create S3 connection using connection pool (recommended for Lambda).
63
+
64
+ This is the recommended pattern for Lambda functions as it reuses
65
+ boto3 sessions across invocations in warm containers.
66
+
67
+ Args:
68
+ aws_profile: AWS profile name (optional)
69
+ aws_region: AWS region (optional)
70
+ aws_end_point_url: Custom endpoint URL (optional, for moto testing)
71
+ **kwargs: Additional S3 parameters
72
+
73
+ Returns:
74
+ S3 instance configured to use connection pool
75
+
76
+ Example:
77
+ >>> # Recommended pattern for Lambda
78
+ >>> s3 = S3.from_pool()
79
+ >>> s3.object.upload_file(file_path="/tmp/file.txt", bucket="my-bucket", key="file.txt")
80
+ >>>
81
+ >>> # Subsequent calls reuse the same connection
82
+ >>> s3_2 = S3.from_pool()
83
+ >>> assert s3.session is s3_2.session
84
+ """
85
+ return cls(
86
+ aws_profile=aws_profile,
87
+ aws_region=aws_region,
88
+ aws_end_point_url=aws_end_point_url,
89
+ use_connection_pool=True,
90
+ **kwargs,
91
+ )
92
+
50
93
  @property
51
94
  def object(self) -> S3Object:
52
95
  """s3 object"""
@@ -35,6 +35,7 @@ class S3Connection(Connection):
35
35
  aws_access_key_id: Optional[str] = None,
36
36
  aws_secret_access_key: Optional[str] = None,
37
37
  signature_version: Optional[str] = None,
38
+ use_connection_pool: bool = False,
38
39
  ) -> None:
39
40
  # Build S3-specific config if signature_version is specified
40
41
  config: Optional[Config] = None
@@ -50,6 +51,7 @@ class S3Connection(Connection):
50
51
  aws_secret_access_key=aws_secret_access_key,
51
52
  aws_end_point_url=aws_end_point_url,
52
53
  config=config,
54
+ use_connection_pool=use_connection_pool,
53
55
  )
54
56
 
55
57
  self.__client: S3Client | None = None
@@ -33,6 +33,7 @@ class SQSConnection(Connection):
33
33
  aws_end_point_url: Optional[str] = None,
34
34
  aws_access_key_id: Optional[str] = None,
35
35
  aws_secret_access_key: Optional[str] = None,
36
+ use_connection_pool: bool = False,
36
37
  ) -> None:
37
38
  """
38
39
  Initialize SQS connection.
@@ -43,6 +44,7 @@ class SQSConnection(Connection):
43
44
  aws_end_point_url: Custom endpoint URL (for LocalStack, etc.)
44
45
  aws_access_key_id: AWS access key ID
45
46
  aws_secret_access_key: AWS secret access key
47
+ use_connection_pool: Use connection pooling (recommended for Lambda)
46
48
  """
47
49
  super().__init__(
48
50
  service_name="sqs",
@@ -51,11 +53,52 @@ class SQSConnection(Connection):
51
53
  aws_access_key_id=aws_access_key_id,
52
54
  aws_secret_access_key=aws_secret_access_key,
53
55
  aws_end_point_url=aws_end_point_url,
56
+ use_connection_pool=use_connection_pool,
54
57
  )
55
58
 
56
59
  self.__client: SQSClient | None = None
57
60
  self.__resource: SQSServiceResource | None = None
58
61
 
62
+ @classmethod
63
+ def from_pool(
64
+ cls,
65
+ aws_profile: Optional[str] = None,
66
+ aws_region: Optional[str] = None,
67
+ aws_end_point_url: Optional[str] = None,
68
+ **kwargs,
69
+ ) -> "SQSConnection":
70
+ """
71
+ Create SQS connection using connection pool (recommended for Lambda).
72
+
73
+ This is the recommended pattern for Lambda functions as it reuses
74
+ boto3 sessions across invocations in warm containers.
75
+
76
+ Args:
77
+ aws_profile: AWS profile name (optional)
78
+ aws_region: AWS region (optional)
79
+ aws_end_point_url: Custom endpoint URL (optional, for LocalStack/moto)
80
+ **kwargs: Additional SQS parameters
81
+
82
+ Returns:
83
+ SQSConnection instance configured to use connection pool
84
+
85
+ Example:
86
+ >>> # Recommended pattern for Lambda
87
+ >>> sqs = SQSConnection.from_pool()
88
+ >>> queue = SQSQueue(sqs, queue_url="https://...")
89
+ >>>
90
+ >>> # Subsequent calls reuse the same connection
91
+ >>> sqs2 = SQSConnection.from_pool()
92
+ >>> assert sqs.session is sqs2.session
93
+ """
94
+ return cls(
95
+ aws_profile=aws_profile,
96
+ aws_region=aws_region,
97
+ aws_end_point_url=aws_end_point_url,
98
+ use_connection_pool=True,
99
+ **kwargs,
100
+ )
101
+
59
102
  @property
60
103
  def client(self) -> SQSClient:
61
104
  """Get SQS client."""
boto3_assist/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.35.0"
1
+ __version__ = "0.37.0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boto3_assist
3
- Version: 0.35.0
3
+ Version: 0.37.0
4
4
  Summary: Additional boto3 wrappers to make your life a little easier
5
5
  Author-email: Eric Wilson <boto3-assist@geekcafe.com>
6
6
  License-File: LICENSE-EXPLAINED.txt
@@ -1,12 +1,13 @@
1
- boto3_assist/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1
+ boto3_assist/__init__.py,sha256=lS-oHTASzgSd4UyYByxydFm_EQjTCYvIelzkG6pPgY4,231
2
2
  boto3_assist/aws_config.py,sha256=evmk_blj498ugptJa8lxIDJOIursxY6mT4joLfEbrl0,6558
3
3
  boto3_assist/boto3session.py,sha256=p4FKVSX5A-xNHdpRan8pgMoY4iIywNfwriyTfjQ-zTQ,2967
4
- boto3_assist/connection.py,sha256=dfVq2nAwElmo0ek0PLBEf9HdULOuzKZG0fu7tDDewhA,5046
4
+ boto3_assist/connection.py,sha256=veKhcZJew3hDukSkUgQ84Ow3XbxwVeEPlGj5IBORMtI,8288
5
+ boto3_assist/connection_pool.py,sha256=I4pfZu7PKW7nkz2lWhlUDK6OB8G7a--GjTyBjerD6FE,6053
5
6
  boto3_assist/connection_tracker.py,sha256=UgfR9RlvXf3A4ssMr3gDMpw89ka8mSRvJn4M34SzhbU,4378
6
7
  boto3_assist/http_status_codes.py,sha256=G0zRSWenwavYKETvDF9tNVUXQz3Ae2gXdBETYbjvJe8,3284
7
8
  boto3_assist/role_assumption_mixin.py,sha256=PMUU5yC2FUBjFD1UokVkRY3CPB5zTw85AhIB5BMtbc8,1031
8
9
  boto3_assist/session_setup_mixin.py,sha256=X-JQKyyaWNA8Z8kKgf2V2I5vsiLAH8udLTX_xepnsdQ,3140
9
- boto3_assist/version.py,sha256=w3TvNFSYTcLj3nBuRCGicelGZOzvgYOfnmgrBAuIKqY,23
10
+ boto3_assist/version.py,sha256=XBXO7SJLNyshet4jr9-3xk5IGG5EjpIAS0aNB4_SuTk,23
10
11
  boto3_assist/aws_lambda/event_info.py,sha256=OkZ4WzuGaHEu_T8sB188KBgShAJhZpWASALKRGBOhMg,14648
11
12
  boto3_assist/aws_lambda/mock_context.py,sha256=LPjHP-3YSoY6iPl1kPqJDwSVf1zLNTcukUunDtYcbK0,116
12
13
  boto3_assist/cloudwatch/cloudwatch_connection.py,sha256=mnGWaLSQpHh5EeY7Ek_2o9JKHJxOELIYtQVMX1IaHn4,2480
@@ -19,13 +20,14 @@ boto3_assist/cognito/cognito_connection.py,sha256=deuXR3cNHz0mCYff2k0LfAvK--9Okq
19
20
  boto3_assist/cognito/cognito_utility.py,sha256=IVZAg58nHG1U7uxe7FsTYpqwwZiwwdIBGiVTZuLCFqg,18417
20
21
  boto3_assist/cognito/jwks_cache.py,sha256=1Y9r-YfQ8qrgZN5xYPvjUEEV0vthbdcPdAIaPbZP7kU,373
21
22
  boto3_assist/cognito/user.py,sha256=qc44qLx3gwq6q2zMxcPQze1EjeZwy5Kuav93vbe-4WU,820
22
- boto3_assist/dynamodb/dynamodb.py,sha256=MElfzO0kDKHdMye5vtIOC4sGH32P2xxvPlxj76NEDe4,48632
23
- boto3_assist/dynamodb/dynamodb_connection.py,sha256=D4KmVpMpE0OuVOwW5g4JBWllUNkwy0hMXEGUiToAMBc,3608
23
+ boto3_assist/dynamodb/__init__.py,sha256=uuRqUY9FHTwequ3oMq_VcMcmzhpAKG08GSnZPMNge2k,163
24
+ boto3_assist/dynamodb/dynamodb.py,sha256=VHt5keB-N38nbbytT_pyY6P6PmveI5t4xrYVqVM6HR8,49163
25
+ boto3_assist/dynamodb/dynamodb_connection.py,sha256=JtdS7ciJDuB1pLOUM2UKWxqNh2gXJtVIU9KYzV4VN2U,3704
24
26
  boto3_assist/dynamodb/dynamodb_helpers.py,sha256=BYJEuXaQVCPbDfbtPswWA_OvV_yC3fVoTtKvIoZeIBc,12092
25
27
  boto3_assist/dynamodb/dynamodb_importer.py,sha256=nCKsyRQeMqDSf0Q5mQ_X_oVIg4PRnu0hcUzZnBli610,3471
26
28
  boto3_assist/dynamodb/dynamodb_index.py,sha256=2AKxHo8HrRbaxL0ePj7S6ek36_sy5cHkDp5I9wIp8Kw,19797
27
29
  boto3_assist/dynamodb/dynamodb_iservice.py,sha256=O9Aj0PFEvcuk2vhARifWTFnUwcQW5EXzwZS478Hm-N0,796
28
- boto3_assist/dynamodb/dynamodb_key.py,sha256=3VPFBGLXSLNGol5WodLiOFGU60VU9ZAdLjd2oqZ1YH4,3928
30
+ boto3_assist/dynamodb/dynamodb_key.py,sha256=k09E9gXEckQ20oRaIZdhyoJL3I6FUls5ysEgsLd3FP0,4126
29
31
  boto3_assist/dynamodb/dynamodb_model_base.py,sha256=gCUG0UKXV9AUcPBlbxJ3Xb8wOS8awrGG7DZpZjgIS58,21291
30
32
  boto3_assist/dynamodb/dynamodb_model_base_interfaces.py,sha256=SFw-yK7TDPL4cK52bpn2zMm5G4mX7eYNU7eFytEw0-A,749
31
33
  boto3_assist/dynamodb/dynamodb_re_indexer.py,sha256=D9gCGTJMS1R-ovAbqXK9gMbkl7a9zkBwA8_pxOAkHSY,6164
@@ -42,15 +44,16 @@ boto3_assist/erc/__init__.py,sha256=ZVpE1TayNer4ZFb3t3wlo5LkWD9G-HbYE2DkoQoMI9w,
42
44
  boto3_assist/erc/ecr_connection.py,sha256=5fbJiouHe2uta4OiN-NKOo3fS2608Zcc01fWBOyPbI4,1370
43
45
  boto3_assist/errors/custom_exceptions.py,sha256=QAMW49NbClELVnRd00u4NHfzVtRS3Tc1TrsIMUP9wLw,1041
44
46
  boto3_assist/models/serializable_model.py,sha256=ZMrRJRvJWLY8PBSKK_nPCgYKv1qUxDPEVdcADKbIHsI,266
45
- boto3_assist/s3/s3.py,sha256=ESTPXtyDi8mrwHaYNWjQLNGTuTUV4CxKDqw-O_KGzKs,2052
47
+ boto3_assist/s3/__init__.py,sha256=trlSMj2kjpY27qGkuSVXKwSbbvwTaosPznLkD9xYUVo,145
48
+ boto3_assist/s3/s3.py,sha256=rw27qX7vQuZZ5KCenHun9p8K0vHjDNdZVSCdUrrsaLk,3593
46
49
  boto3_assist/s3/s3_bucket.py,sha256=GfyBbuI5BWz_ybwU_nDqUZiC0wt24PNt49GKZmb05OY,2018
47
- boto3_assist/s3/s3_connection.py,sha256=iIWtOgTXaj4FQfkyWLI9jnD340XKkKT2UqPAMvItBM4,2421
50
+ boto3_assist/s3/s3_connection.py,sha256=jfoqeEYq4LF7Y9hVutzkPHuLR1oYiPA2k0O4PP1EPnc,2517
48
51
  boto3_assist/s3/s3_event_data.py,sha256=Q7QUI1pwkc7g6yZ3IZWMXBIAfsMlPRC7wac2RvrQoA4,4112
49
52
  boto3_assist/s3/s3_object.py,sha256=77jZeIUFpQX3cFYGGwRFBvL-peCe54iILnthm-GFjMc,22518
50
53
  boto3_assist/securityhub/securityhub.py,sha256=ne-J_v4DaCVZm5YgJa_-LKVomLJQo5Gpw6wleAKSsws,5467
51
54
  boto3_assist/securityhub/securityhub_connection.py,sha256=hWfcj9gjS2lNXUObyw4cShtveoqJPIp8kKFuz-fz1J4,1449
52
55
  boto3_assist/sqs/__init__.py,sha256=VRuPPit-hSSbumKL2pN5AUtZKr_c9MpLeuqQ5a6wBLk,285
53
- boto3_assist/sqs/sqs_connection.py,sha256=Gacka0Aqco3qNSTVmPiJf8LeaLgNzhL1-npCOn85GmQ,2469
56
+ boto3_assist/sqs/sqs_connection.py,sha256=MEDA2KKlpoRiDcCVh_i37CLhA0a5dlNkfuA9voG-Lxs,4011
54
57
  boto3_assist/sqs/sqs_queue.py,sha256=sjz2Q4BbJMCO-cxSNM02UxMmgnRfPLFAC3Pt1kiqc14,9542
55
58
  boto3_assist/ssm/connection.py,sha256=gYpKn5HsUR3hcRUqJzF5QcTITCk0DReq9KhoE_8-Htg,1370
56
59
  boto3_assist/ssm/parameter_store/parameter_store.py,sha256=2ISi-SmR29mESHFH-onJkxPX1aThIgBRojA3ZoNcP9s,3949
@@ -63,8 +66,8 @@ boto3_assist/utilities/logging_utility.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5N
63
66
  boto3_assist/utilities/numbers_utility.py,sha256=wzv9d0uXT_2_ZHHio7LBzibwxPqhGpvbq9HinrVn_4A,10160
64
67
  boto3_assist/utilities/serialization_utility.py,sha256=m5wRZNeWW9VltQPVNziR27OGKO3MDJm6mFmcDHwN-n4,24479
65
68
  boto3_assist/utilities/string_utility.py,sha256=XxUIz19L2LFFTRDAAmdPa8Qhn40u9yO7g4nULFuvg0M,11033
66
- boto3_assist-0.35.0.dist-info/METADATA,sha256=xa5U1elxKIetkG0QKmbCEt_3ge6uO5ZyhdGNsNUW1o8,2879
67
- boto3_assist-0.35.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
68
- boto3_assist-0.35.0.dist-info/licenses/LICENSE-EXPLAINED.txt,sha256=WFREvTpfTjPjDHpOLADxJpCKpIla3Ht87RUUGii4ODU,606
69
- boto3_assist-0.35.0.dist-info/licenses/LICENSE.txt,sha256=PXDhFWS5L5aOTkVhNvoitHKbAkgxqMI2uUPQyrnXGiI,1105
70
- boto3_assist-0.35.0.dist-info/RECORD,,
69
+ boto3_assist-0.37.0.dist-info/METADATA,sha256=ErrRoU35Bb3qt-O7C2jpCEYWJ23DxZxGCKUI1tanF2Y,2879
70
+ boto3_assist-0.37.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
71
+ boto3_assist-0.37.0.dist-info/licenses/LICENSE-EXPLAINED.txt,sha256=WFREvTpfTjPjDHpOLADxJpCKpIla3Ht87RUUGii4ODU,606
72
+ boto3_assist-0.37.0.dist-info/licenses/LICENSE.txt,sha256=PXDhFWS5L5aOTkVhNvoitHKbAkgxqMI2uUPQyrnXGiI,1105
73
+ boto3_assist-0.37.0.dist-info/RECORD,,