boto3-assist 0.1.1__py3-none-any.whl → 0.1.3__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,47 @@
1
+ """
2
+ Geek Cafe, LLC
3
+ Maintainers: Eric Wilson
4
+ MIT License. See Project Root for the license information.
5
+ """
6
+
7
+
8
+ class ConnectionTracker:
9
+ """
10
+ Tracks Connection Requests.
11
+ Useful in for performance tuning and debugging.
12
+ """
13
+
14
+ def __init__(self, service_name: str) -> None:
15
+ self.__connection_couter: int = 0
16
+ self.__service_name: str = service_name
17
+
18
+ def increment_connection(self) -> None:
19
+ """Increments the connection counter"""
20
+ self.__connection_couter += 1
21
+
22
+ if self.connection_count > 1:
23
+ self.__log_warning(
24
+ f"Your dynamodb connection count is {self.connection_count}. "
25
+ "Under most circumstances you should be able to use the same connection "
26
+ "vs. creating a new one. Connections are expensive in terms of time / latency. "
27
+ "If you are seeing perforance issues, check how and where you are creating your "
28
+ "connections. You should be able to pass the .db connection to your other objects "
29
+ "and reuse your dynamodb boto connections."
30
+ )
31
+
32
+ def decrement_connection(self) -> None:
33
+ """Decrements the connection counter"""
34
+ self.__connection_couter -= 1
35
+
36
+ @property
37
+ def connection_count(self) -> int:
38
+ """Returns the current connection count"""
39
+ return self.__connection_couter
40
+
41
+ def reset(self) -> None:
42
+ """Resets the connection counter"""
43
+ self.__connection_couter = 0
44
+
45
+ def __log_warning(self, message: str) -> None:
46
+ """Logs a warning message"""
47
+ print(f"Warning: {message}")
@@ -6,7 +6,7 @@ https://github.com/geekcafe/boto3-assist
6
6
  """
7
7
 
8
8
  from __future__ import annotations
9
- from typing import Optional
9
+ from typing import Optional, Any
10
10
  from boto3.dynamodb.conditions import (
11
11
  ConditionBase,
12
12
  Key,
@@ -110,7 +110,8 @@ class DynamoDBIndex:
110
110
  *,
111
111
  include_sort_key: bool = True,
112
112
  condition: str = "begins_with",
113
- high_value: Optional[DynamoDBKey] = None,
113
+ low_value: Any = None,
114
+ high_value: Any = None,
114
115
  # sk_value_2: Optional[str | int | float] = None,
115
116
  ) -> dict | Key | ConditionBase | ComparisonCondition | Equals:
116
117
  """Get the key for a given index"""
@@ -129,6 +130,7 @@ class DynamoDBIndex:
129
130
  key = self._build_query_key(
130
131
  include_sort_key=include_sort_key,
131
132
  condition=condition,
133
+ low_value=low_value,
132
134
  high_value=high_value,
133
135
  )
134
136
  return key
@@ -138,7 +140,8 @@ class DynamoDBIndex:
138
140
  *,
139
141
  include_sort_key: bool = True,
140
142
  condition: str = "begins_with",
141
- high_value: Optional[DynamoDBKey] = None,
143
+ low_value: Any = None,
144
+ high_value: Any = None,
142
145
  ) -> And | Equals:
143
146
  """Get the GSI index name and key"""
144
147
 
@@ -146,13 +149,22 @@ class DynamoDBIndex:
146
149
  self.partition_key.value
147
150
  )
148
151
 
149
- if include_sort_key and self.sort_key.attribute_name and self.sort_key.value:
152
+ if (
153
+ include_sort_key
154
+ and self.sort_key.attribute_name
155
+ and (
156
+ self.sort_key.value
157
+ or (low_value is not None and high_value is not None)
158
+ )
159
+ ):
150
160
  # if self.sk_value_2:
151
- if high_value:
161
+ if low_value is not None and high_value is not None:
152
162
  match condition:
153
163
  case "between":
164
+ low = f"{self.sort_key.value}{low_value}"
165
+ high = f"{self.sort_key.value}{high_value}"
154
166
  key = key & Key(f"{self.sort_key.attribute_name}").between(
155
- self.sort_key.value, high_value.value
167
+ low, high
156
168
  )
157
169
 
158
170
  else:
@@ -53,9 +53,10 @@ class DynamoDBKey:
53
53
  """
54
54
  parts = []
55
55
  for key, value in key_value_pairs:
56
+ prefix = f"{key}#" if key else ""
56
57
  if value is None:
57
- parts.append(f"{key}#")
58
+ parts.append(f"{prefix}")
58
59
  break
59
60
  else:
60
- parts.append(f"{key}#{value}")
61
+ parts.append(f"{prefix}{value}")
61
62
  return "#".join(parts)
@@ -130,6 +130,14 @@ class DynamoDBModelBase:
130
130
  self, include_indexes=include_indexes
131
131
  )
132
132
 
133
+ def to_dictionary(self):
134
+ """
135
+ Convert the instance to a dictionary without an indexes/keys.
136
+ Usefull for turning an object into a dictionary for serialization.
137
+ This is the same as to_resource_dictionary(include_indexes=False)
138
+ """
139
+ return DynamoDBSerializer.to_resource_dictionary(self, include_indexes=False)
140
+
133
141
  def get_key(self, index_name: str) -> DynamoDBIndex:
134
142
  """Get the index name and key"""
135
143
 
@@ -0,0 +1,103 @@
1
+ """
2
+ Geek Cafe, LLC
3
+ Maintainers: Eric Wilson
4
+ MIT License. See Project Root for the license information.
5
+ """
6
+
7
+ from typing import Optional
8
+ from typing import TYPE_CHECKING
9
+
10
+ from aws_lambda_powertools import Logger
11
+ from boto3_assist.boto3session import Boto3SessionManager
12
+ from boto3_assist.environment_services.environment_variables import (
13
+ EnvironmentVariables,
14
+ )
15
+ from boto3_assist.connection_tracker import ConnectionTracker
16
+
17
+ if TYPE_CHECKING:
18
+ from mypy_boto3_ec2 import Client
19
+ else:
20
+ Client = object
21
+
22
+ SERVICE_NAME = "ec2"
23
+ logger = Logger()
24
+ tracker: ConnectionTracker = ConnectionTracker(service_name=SERVICE_NAME)
25
+
26
+
27
+ class EC2Connection:
28
+ """DB Environment"""
29
+
30
+ def __init__(
31
+ self,
32
+ *,
33
+ aws_profile: Optional[str] = None,
34
+ aws_region: Optional[str] = None,
35
+ aws_access_key_id: Optional[str] = None,
36
+ aws_secret_access_key: Optional[str] = None,
37
+ ) -> None:
38
+ self.aws_profile = aws_profile
39
+ self.aws_region = aws_region
40
+
41
+ self.aws_access_key_id = aws_access_key_id
42
+ self.aws_secret_access_key = aws_secret_access_key
43
+ self.__session: Boto3SessionManager | None = None
44
+ self.__client: Client | None = None
45
+
46
+ self.raise_on_error: bool = True
47
+
48
+ def setup(self, setup_source: Optional[str] = None) -> None:
49
+ """
50
+ Setup the environment. Automatically called via init.
51
+ You can run setup at anytime with new parameters.
52
+ Args: setup_source: Optional[str] = None
53
+ Defines the source of the setup. Useful for logging.
54
+ Returns: None
55
+ """
56
+
57
+ logger.info(
58
+ {
59
+ "metric_filter": "connection_setup",
60
+ "source": "setup",
61
+ "aws_profile": self.aws_profile,
62
+ "aws_region": self.aws_region,
63
+ "setup_source": setup_source,
64
+ }
65
+ )
66
+
67
+ # lazy load the session
68
+ self.__session = Boto3SessionManager(
69
+ service_name=SERVICE_NAME,
70
+ aws_profile=self.aws_profile,
71
+ aws_region=self.aws_region or EnvironmentVariables.AWS.region(),
72
+ aws_access_key_id=self.aws_access_key_id
73
+ or EnvironmentVariables.AWS.aws_access_key_id(),
74
+ aws_secret_access_key=self.aws_secret_access_key
75
+ or EnvironmentVariables.AWS.aws_secret_access_key(),
76
+ )
77
+
78
+ tracker.increment_connection()
79
+
80
+ self.raise_on_error = EnvironmentVariables.AWS.DynamoDB.raise_on_error_setting()
81
+
82
+ @property
83
+ def session(self) -> Boto3SessionManager:
84
+ """Session"""
85
+ if self.__session is None:
86
+ self.setup(setup_source="session init")
87
+ return self.__session
88
+
89
+ @property
90
+ def client(self) -> Client:
91
+ """Client Connection"""
92
+ if self.__client is None:
93
+ logger.info("Creating Client")
94
+ self.__client = self.session.client
95
+
96
+ if self.raise_on_error and self.__client is None:
97
+ raise RuntimeError("Client is not available")
98
+ return self.__client
99
+
100
+ @client.setter
101
+ def client(self, value: Client):
102
+ logger.info("Setting Client")
103
+ self.__client = value
@@ -83,6 +83,22 @@ class EnvironmentVariables:
83
83
  )
84
84
  return value
85
85
 
86
+ @staticmethod
87
+ def aws_access_key_id() -> str | None:
88
+ """
89
+ The aws_access_key_id. Often used for local development.
90
+ """
91
+ value = os.getenv("ACCESS_KEY_ID")
92
+ return value
93
+
94
+ @staticmethod
95
+ def aws_secret_access_key() -> str | None:
96
+ """
97
+ The aws_secret_access_key. Often used for local development.
98
+ """
99
+ value = os.getenv("SECRET_ACCESS_KEY")
100
+ return value
101
+
86
102
  class SES:
87
103
  """SES Settings"""
88
104
 
boto3_assist/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = '0.1.1'
1
+ __version__ = '0.1.3'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: boto3_assist
3
- Version: 0.1.1
3
+ Version: 0.1.3
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,28 +1,30 @@
1
1
  boto3_assist/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  boto3_assist/boto3session.py,sha256=J20E2lkqJOaey4Ohi-xRe2xABj7QsA8DrggzK29-5es,6415
3
- boto3_assist/version.py,sha256=ls1camlIoMxEZz9gSkZ1OJo-MXqHWwKPtdPbZJmwp7E,22
3
+ boto3_assist/connection_tracker.py,sha256=k59-7CdEvo5Slab80wwYz65sE1-sxVP1-wpQhZZXBZo,1632
4
+ boto3_assist/version.py,sha256=uZsygMXMKRw-7qhWojAjnpm8GFPXU92xW6XA8O5GwFY,22
4
5
  boto3_assist/dynamodb/dynamodb.py,sha256=jU4R__5jjI1CmH9xVNUeU8PICD2dtbQ2CYUFKMRw0P0,14561
5
6
  boto3_assist/dynamodb/dynamodb_connection.py,sha256=JMCmWOsMzy45rikGl3Z2xqlG2vUTEKSYqi6dpsfJ750,4418
6
7
  boto3_assist/dynamodb/dynamodb_connection_tracker.py,sha256=nTNQ99sIidDoLMhMbBju2umgLmcttsmnvmd_DMy_J9M,1582
7
8
  boto3_assist/dynamodb/dynamodb_helpers.py,sha256=ajpTJ5bJOm9PDgE2Zx9p2zkTRFV4xswqJRS81SOTn1s,12198
8
9
  boto3_assist/dynamodb/dynamodb_importer.py,sha256=8SlT2W03Dvb3LIs6xqtzXP4IShyv655PgMCDNr4kmPk,2559
9
- boto3_assist/dynamodb/dynamodb_index.py,sha256=Uw2MmFivLp8VwDc3sNWgifc0yUvDcZD1TNawqvioi_8,5953
10
+ boto3_assist/dynamodb/dynamodb_index.py,sha256=LRQgSci222s-pU-JXgnaAoOa71ABX9h3uJPeCVPl1GE,6315
10
11
  boto3_assist/dynamodb/dynamodb_iservice.py,sha256=2AuaKxt7DUZbB-GpBBtPtPMpAlgZkumkAldm8vy7-sg,701
11
- boto3_assist/dynamodb/dynamodb_key.py,sha256=HInymjT-NyJb21fuXnvFMxBBLr2HA4O8XOUSsU5Te1w,1726
12
- boto3_assist/dynamodb/dynamodb_model_base.py,sha256=B8E4D2btjcIJjpzDnULlQk5Ccp5Qp3vN8vRdUHlshns,10949
12
+ boto3_assist/dynamodb/dynamodb_key.py,sha256=X3I3gUPx2T858vjRDi9SN8qn8ez5UJUo0vZiKBeeUWg,1776
13
+ boto3_assist/dynamodb/dynamodb_model_base.py,sha256=IIcqdMN1SMvaDAvN2x1j8FMUPyVp8SdH8Vai8Qr4Nfs,11308
13
14
  boto3_assist/dynamodb/dynamodb_model_base_interfaces.py,sha256=yT4zDRI8vP15WVOHnCvY3FsEy_QSIta5-bnUby70Xow,747
14
15
  boto3_assist/dynamodb/dynamodb_reindexer.py,sha256=_I-W7Ply-82fRHnhsRZuquRYxEIXubuWGq7E7B4Pa7I,6204
15
16
  boto3_assist/dynamodb/readme.md,sha256=wNMzdRwk0qRV0kE88UUYnJos3pEK0HNjEIVkq2PATf8,1490
16
17
  boto3_assist/dynamodb/troubleshooting.md,sha256=uGpBaBUt_MyzjzwFOLOe0udTgcvaOpiTFxfj7ilLNkM,136
18
+ boto3_assist/ec2/ec2_connection.py,sha256=KN1AivKY6yYpx_AjmaA3aQUZtUwKIvWk4FO8OPq1aTY,3182
17
19
  boto3_assist/environment_services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
20
  boto3_assist/environment_services/environment_loader.py,sha256=aW-PvlNi8EuavKPXDAi5txLbJFVRkBpkFIgmnR0OWDw,1581
19
- boto3_assist/environment_services/environment_variables.py,sha256=x0TzoIyes4poy12xKb22pqa7Ym_nKtrfI2bcELjsHWA,6191
21
+ boto3_assist/environment_services/environment_variables.py,sha256=29ujkcFdgVgDgTK_pcVkpcFofEOYTbMXYyRim5vLj-k,6691
20
22
  boto3_assist/utilities/datetime_utility.py,sha256=TbqGQkJDTahqvaZAIV550nhYnW1Bsq0Hdu3Go6P4RRs,10282
21
23
  boto3_assist/utilities/logging_utility.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
24
  boto3_assist/utilities/serialization_utility.py,sha256=s_QQRIhtwIE7xN5nU13mNk2wtWyErBX_Sg7n0gbHj-M,4308
23
25
  boto3_assist/utilities/string_utility.py,sha256=w8l063UT3GE48tuJopETyZrjG4CgAzWkyDWMAYMg5Og,7432
24
- boto3_assist-0.1.1.dist-info/METADATA,sha256=cVmT6i7LxZJ15TJ_n2yBcrhvoGzaTNs21BnOuV5gvI8,1804
25
- boto3_assist-0.1.1.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
26
- boto3_assist-0.1.1.dist-info/licenses/LICENSE-EXPLAINED.txt,sha256=WFREvTpfTjPjDHpOLADxJpCKpIla3Ht87RUUGii4ODU,606
27
- boto3_assist-0.1.1.dist-info/licenses/LICENSE.txt,sha256=PXDhFWS5L5aOTkVhNvoitHKbAkgxqMI2uUPQyrnXGiI,1105
28
- boto3_assist-0.1.1.dist-info/RECORD,,
26
+ boto3_assist-0.1.3.dist-info/METADATA,sha256=xeuPDWUGFeqRDPD_rCtuZENt7b0-RU-e8SoPbZigwns,1804
27
+ boto3_assist-0.1.3.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
28
+ boto3_assist-0.1.3.dist-info/licenses/LICENSE-EXPLAINED.txt,sha256=WFREvTpfTjPjDHpOLADxJpCKpIla3Ht87RUUGii4ODU,606
29
+ boto3_assist-0.1.3.dist-info/licenses/LICENSE.txt,sha256=PXDhFWS5L5aOTkVhNvoitHKbAkgxqMI2uUPQyrnXGiI,1105
30
+ boto3_assist-0.1.3.dist-info/RECORD,,