boto3-assist 0.32.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.
Files changed (67) hide show
  1. boto3_assist/__init__.py +0 -0
  2. boto3_assist/aws_config.py +199 -0
  3. boto3_assist/aws_lambda/event_info.py +414 -0
  4. boto3_assist/aws_lambda/mock_context.py +5 -0
  5. boto3_assist/boto3session.py +87 -0
  6. boto3_assist/cloudwatch/cloudwatch_connection.py +84 -0
  7. boto3_assist/cloudwatch/cloudwatch_connection_tracker.py +17 -0
  8. boto3_assist/cloudwatch/cloudwatch_log_connection.py +62 -0
  9. boto3_assist/cloudwatch/cloudwatch_logs.py +39 -0
  10. boto3_assist/cloudwatch/cloudwatch_query.py +191 -0
  11. boto3_assist/cognito/cognito_authorizer.py +169 -0
  12. boto3_assist/cognito/cognito_connection.py +59 -0
  13. boto3_assist/cognito/cognito_utility.py +514 -0
  14. boto3_assist/cognito/jwks_cache.py +21 -0
  15. boto3_assist/cognito/user.py +27 -0
  16. boto3_assist/connection.py +146 -0
  17. boto3_assist/connection_tracker.py +120 -0
  18. boto3_assist/dynamodb/dynamodb.py +1206 -0
  19. boto3_assist/dynamodb/dynamodb_connection.py +113 -0
  20. boto3_assist/dynamodb/dynamodb_helpers.py +333 -0
  21. boto3_assist/dynamodb/dynamodb_importer.py +102 -0
  22. boto3_assist/dynamodb/dynamodb_index.py +507 -0
  23. boto3_assist/dynamodb/dynamodb_iservice.py +29 -0
  24. boto3_assist/dynamodb/dynamodb_key.py +130 -0
  25. boto3_assist/dynamodb/dynamodb_model_base.py +382 -0
  26. boto3_assist/dynamodb/dynamodb_model_base_interfaces.py +34 -0
  27. boto3_assist/dynamodb/dynamodb_re_indexer.py +165 -0
  28. boto3_assist/dynamodb/dynamodb_reindexer.py +165 -0
  29. boto3_assist/dynamodb/dynamodb_reserved_words.py +52 -0
  30. boto3_assist/dynamodb/dynamodb_reserved_words.txt +573 -0
  31. boto3_assist/dynamodb/readme.md +68 -0
  32. boto3_assist/dynamodb/troubleshooting.md +7 -0
  33. boto3_assist/ec2/ec2_connection.py +57 -0
  34. boto3_assist/environment_services/__init__.py +0 -0
  35. boto3_assist/environment_services/environment_loader.py +128 -0
  36. boto3_assist/environment_services/environment_variables.py +219 -0
  37. boto3_assist/erc/__init__.py +64 -0
  38. boto3_assist/erc/ecr_connection.py +57 -0
  39. boto3_assist/errors/custom_exceptions.py +46 -0
  40. boto3_assist/http_status_codes.py +80 -0
  41. boto3_assist/models/serializable_model.py +9 -0
  42. boto3_assist/role_assumption_mixin.py +38 -0
  43. boto3_assist/s3/s3.py +64 -0
  44. boto3_assist/s3/s3_bucket.py +67 -0
  45. boto3_assist/s3/s3_connection.py +76 -0
  46. boto3_assist/s3/s3_event_data.py +168 -0
  47. boto3_assist/s3/s3_object.py +695 -0
  48. boto3_assist/securityhub/securityhub.py +150 -0
  49. boto3_assist/securityhub/securityhub_connection.py +57 -0
  50. boto3_assist/session_setup_mixin.py +70 -0
  51. boto3_assist/ssm/connection.py +57 -0
  52. boto3_assist/ssm/parameter_store/parameter_store.py +116 -0
  53. boto3_assist/utilities/datetime_utility.py +349 -0
  54. boto3_assist/utilities/decimal_conversion_utility.py +140 -0
  55. boto3_assist/utilities/dictionary_utility.py +32 -0
  56. boto3_assist/utilities/file_operations.py +135 -0
  57. boto3_assist/utilities/http_utility.py +48 -0
  58. boto3_assist/utilities/logging_utility.py +0 -0
  59. boto3_assist/utilities/numbers_utility.py +329 -0
  60. boto3_assist/utilities/serialization_utility.py +664 -0
  61. boto3_assist/utilities/string_utility.py +337 -0
  62. boto3_assist/version.py +1 -0
  63. boto3_assist-0.32.0.dist-info/METADATA +76 -0
  64. boto3_assist-0.32.0.dist-info/RECORD +67 -0
  65. boto3_assist-0.32.0.dist-info/WHEEL +4 -0
  66. boto3_assist-0.32.0.dist-info/licenses/LICENSE-EXPLAINED.txt +11 -0
  67. boto3_assist-0.32.0.dist-info/licenses/LICENSE.txt +21 -0
@@ -0,0 +1,146 @@
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, List
8
+
9
+ from aws_lambda_powertools import Logger
10
+ from boto3_assist.boto3session import Boto3SessionManager
11
+ from boto3_assist.environment_services.environment_variables import (
12
+ EnvironmentVariables,
13
+ )
14
+ from boto3_assist.connection_tracker import ConnectionTracker
15
+
16
+
17
+ logger = Logger()
18
+ tracker: ConnectionTracker = ConnectionTracker()
19
+
20
+
21
+ class Connection:
22
+ """Base Boto 3 Connection"""
23
+
24
+ def __init__(
25
+ self,
26
+ *,
27
+ service_name: Optional[str] = None,
28
+ aws_profile: Optional[str] = None,
29
+ aws_region: Optional[str] = None,
30
+ aws_access_key_id: Optional[str] = None,
31
+ aws_secret_access_key: Optional[str] = None,
32
+ aws_end_point_url: Optional[str] = None,
33
+ assume_role_arn: Optional[str] = None,
34
+ assume_role_chain: Optional[List[str]] = None,
35
+ assume_role_duration_seconds: Optional[int] = 3600,
36
+ ) -> None:
37
+ self.__aws_profile = aws_profile
38
+ self.__aws_region = aws_region
39
+ self.__aws_access_key_id = aws_access_key_id
40
+ self.__aws_secret_access_key = aws_secret_access_key
41
+ self.end_point_url = aws_end_point_url
42
+ self.__session: Boto3SessionManager | None = None
43
+ self.__assume_role_arn: Optional[str] = assume_role_arn
44
+ self.__service_name: str | None = service_name
45
+ self.__assume_role_chain = assume_role_chain
46
+ self.__assume_role_duration_seconds = assume_role_duration_seconds
47
+ if self.__service_name is None:
48
+ raise RuntimeError(
49
+ "Service Name is not available. The service name is required."
50
+ )
51
+
52
+ self.raise_on_error: bool = True
53
+
54
+ def setup(self, setup_source: Optional[str] = None) -> None:
55
+ """
56
+ Setup the environment. Automatically called via init.
57
+ You can run setup at anytime with new parameters.
58
+ Args: setup_source: Optional[str] = None
59
+ Defines the source of the setup. Useful for logging.
60
+ Returns: None
61
+ """
62
+
63
+ logger.debug(
64
+ {
65
+ "metric_filter": f"{self.service_name}_connection_setup",
66
+ "source": f"{self.service_name} Connection",
67
+ "aws_profile": self.aws_profile,
68
+ "aws_region": self.aws_region,
69
+ "setup_source": setup_source,
70
+ }
71
+ )
72
+
73
+ self.__session = Boto3SessionManager(
74
+ service_name=self.service_name,
75
+ aws_profile=self.aws_profile,
76
+ aws_region=self.aws_region,
77
+ aws_access_key_id=self.aws_access_key_id,
78
+ aws_secret_access_key=self.aws_secret_access_key,
79
+ aws_endpoint_url=self.end_point_url,
80
+ assume_role_arn=self.__assume_role_arn,
81
+ assume_role_chain=self.__assume_role_chain,
82
+ assume_role_duration_seconds=self.__assume_role_duration_seconds,
83
+ )
84
+
85
+ tracker.add(service_name=self.service_name)
86
+
87
+ @property
88
+ def asw_profile(self) -> str | None:
89
+ """The AWS Profile"""
90
+ return self.__aws_profile or EnvironmentVariables.AWS.profile()
91
+
92
+ @asw_profile.setter
93
+ def aws_profile(self, value: str | None):
94
+ self.__aws_profile = value
95
+
96
+ @property
97
+ def aws_region(self) -> str | None:
98
+ """The AWS Region"""
99
+ return self.__aws_region or EnvironmentVariables.AWS.region()
100
+
101
+ @aws_region.setter
102
+ def aws_region(self, value: str | None):
103
+ self.__aws_region = value
104
+
105
+ @property
106
+ def aws_access_key_id(self) -> str | None:
107
+ """The AWS Access Key"""
108
+ return self.__aws_access_key_id or EnvironmentVariables.AWS.aws_access_key_id()
109
+
110
+ @aws_access_key_id.setter
111
+ def aws_access_key_id(self, value: str | None):
112
+ self.__aws_access_key_id = value
113
+
114
+ @property
115
+ def aws_secret_access_key(self) -> str | None:
116
+ """The AWS Access Key"""
117
+ return (
118
+ self.__aws_secret_access_key
119
+ or EnvironmentVariables.AWS.aws_secret_access_key()
120
+ )
121
+
122
+ @aws_secret_access_key.setter
123
+ def aws_secret_access_key(self, value: str | None):
124
+ self.__aws_secret_access_key = value
125
+
126
+ @property
127
+ def service_name(self) -> str:
128
+ """Service Name"""
129
+ if self.__service_name is None:
130
+ raise RuntimeError("Service Name is not available")
131
+ return self.__service_name
132
+
133
+ @service_name.setter
134
+ def service_name(self, value: str):
135
+ logger.debug("Setting Service Name")
136
+ self.__service_name = value
137
+
138
+ @property
139
+ def session(self) -> Boto3SessionManager:
140
+ """Session"""
141
+ if self.__session is None:
142
+ self.setup(setup_source="session init")
143
+
144
+ if self.__session is None:
145
+ raise RuntimeError("Session is not available")
146
+ return self.__session
@@ -0,0 +1,120 @@
1
+ """
2
+ Geek Cafe, LLC
3
+ Maintainers: Eric Wilson
4
+ MIT License. See Project Root for the license information.
5
+ """
6
+
7
+ import traceback
8
+ import os
9
+ from typing import Dict
10
+
11
+
12
+ class ConnectionTracker:
13
+ """
14
+ Tracks Boto3 connection requests for performance tuning and debugging.
15
+
16
+ Attributes:
17
+ __stack_trace_env_var (str): Environment variable name to enable stack trace logging.
18
+ __issue_stack_trace (bool | None): Caches the result of whether stack trace logging is enabled.
19
+ __connection_counter (Dict[str, int]): Tracks the number of connections per service.
20
+ """
21
+
22
+ def __init__(self) -> None:
23
+ self.__stack_trace_env_var: str = "BOTO3_ASSIST_CONNECTION_STACK_TRACE"
24
+ self.__issue_stack_trace: bool | None = None
25
+ self.__connection_counter: Dict[str, int] = {}
26
+
27
+ def add(self, service_name: str) -> None:
28
+ """
29
+ Increments the connection count for a given service and
30
+ performs a check on the number of connections.
31
+
32
+ Args:
33
+ service_name (str): Name of the AWS service.
34
+ """
35
+ self.__connection_counter[service_name] = (
36
+ self.__connection_counter.get(service_name, 0) + 1
37
+ )
38
+
39
+ self.check(service_name=service_name)
40
+
41
+ @property
42
+ def issue_stack_trace(self) -> bool:
43
+ """
44
+ Checks if stack trace logging is enabled by the environment variable.
45
+
46
+ Returns:
47
+ bool: True if stack trace logging is enabled, False otherwise.
48
+ """
49
+ if self.__issue_stack_trace is None:
50
+ self.__issue_stack_trace = (
51
+ os.getenv(self.__stack_trace_env_var, "").lower() == "true"
52
+ )
53
+ return self.__issue_stack_trace
54
+
55
+ def check(self, service_name: str) -> None:
56
+ """
57
+ Checks the connection count for a service and logs warnings if needed.
58
+
59
+ Args:
60
+ service_name (str): Name of the AWS service.
61
+ """
62
+ connection_count = self.__connection_counter.get(service_name, 0)
63
+ if connection_count > 1:
64
+ service_message = (
65
+ f"Your {service_name} service has more than one connection.\n"
66
+ )
67
+
68
+ if not self.issue_stack_trace:
69
+ stack_trace_message = (
70
+ f"๐Ÿ“„ NOTE: To add additional information ๐Ÿ‘€ to the log and determine where additional connections are being created: "
71
+ f"set the environment variable ๐Ÿ‘‰{self.__stack_trace_env_var}๐Ÿ‘ˆ to true โœ…. \n"
72
+ )
73
+ else:
74
+ stack = "\n".join(traceback.format_stack())
75
+ stack_trace_message = (
76
+ f"\nStack Trace Enabled with {self.__stack_trace_env_var}\n{stack}"
77
+ )
78
+
79
+ self.__log_warning(
80
+ f"{service_message}"
81
+ f"Your boto3 connection count is {connection_count}. "
82
+ "Under most circumstances, you should be able to use the same connection "
83
+ "instead of creating a new one. Connections are expensive in terms of time and latency. "
84
+ "If you are seeing performance issues, check how and where you are creating your "
85
+ "connections. You should be able to pass the connection to your other objects "
86
+ "and reuse your boto3 connections. "
87
+ "\n๐Ÿงช MOCK Testing may show this message as well, in which case you can dismiss this warning.๐Ÿงช\n"
88
+ f"{stack_trace_message}"
89
+ )
90
+
91
+ def decrement_connection(self, service_name: str) -> None:
92
+ """
93
+ Decrements the connection count for a service.
94
+
95
+ Args:
96
+ service_name (str): Name of the AWS service.
97
+ """
98
+ if (
99
+ service_name in self.__connection_counter
100
+ and self.__connection_counter[service_name] > 0
101
+ ):
102
+ self.__connection_counter[service_name] -= 1
103
+
104
+ def reset(self, service_name: str) -> None:
105
+ """
106
+ Resets the connection count for a service to zero.
107
+
108
+ Args:
109
+ service_name (str): Name of the AWS service.
110
+ """
111
+ self.__connection_counter[service_name] = 0
112
+
113
+ def __log_warning(self, message: str) -> None:
114
+ """
115
+ Logs a warning message.
116
+
117
+ Args:
118
+ message (str): The warning message to log.
119
+ """
120
+ print(f"Warning: {message}")