boto3-refresh-session 2.0.7__py3-none-any.whl → 2.0.9__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.
@@ -4,7 +4,7 @@ from .methods.sts import STSRefreshableSession
4
4
  from .session import RefreshableSession
5
5
 
6
6
  __all__ = ["RefreshableSession"]
7
- __version__ = "2.0.7"
7
+ __version__ = "2.0.9"
8
8
  __title__ = "boto3-refresh-session"
9
9
  __author__ = "Mike Letts"
10
10
  __maintainer__ = "Mike Letts"
@@ -4,11 +4,17 @@ __all__ = ["CustomRefreshableSession"]
4
4
 
5
5
  from typing import Any, Callable
6
6
 
7
- from ..exceptions import BRSError
7
+ from ..exceptions import BRSError, BRSWarning
8
8
  from ..session import BaseRefreshableSession
9
- from ..utils import RefreshMethod, TemporaryCredentials
9
+ from ..utils import (
10
+ CustomCredentialsMethod,
11
+ CustomCredentialsMethodArgs,
12
+ TemporaryCredentials,
13
+ refreshable_session,
14
+ )
10
15
 
11
16
 
17
+ @refreshable_session
12
18
  class CustomRefreshableSession(BaseRefreshableSession, registry_key="custom"):
13
19
  """A :class:`boto3.session.Session` object that automatically refreshes
14
20
  temporary credentials returned by a custom credential getter provided
@@ -17,11 +23,11 @@ class CustomRefreshableSession(BaseRefreshableSession, registry_key="custom"):
17
23
 
18
24
  Parameters
19
25
  ----------
20
- custom_credentials_method: Callable
26
+ custom_credentials_method: CustomCredentialsMethod
21
27
  Required. Accepts a callable object that returns temporary AWS
22
28
  security credentials. That object must return a dictionary containing
23
29
  'access_key', 'secret_key', 'token', and 'expiry_time' when called.
24
- custom_credentials_method_args : dict[str, Any], optional
30
+ custom_credentials_method_args : CustomCredentialsMethodArgs, optional
25
31
  Optional keyword arguments for the function passed to the
26
32
  ``custom_credentials_method`` parameter.
27
33
  defer_refresh : bool, optional
@@ -61,21 +67,29 @@ class CustomRefreshableSession(BaseRefreshableSession, registry_key="custom"):
61
67
 
62
68
  def __init__(
63
69
  self,
64
- custom_credentials_method: Callable,
65
- custom_credentials_method_args: dict[str, Any] | None = None,
66
- defer_refresh: bool | None = None,
70
+ custom_credentials_method: CustomCredentialsMethod,
71
+ custom_credentials_method_args: (
72
+ CustomCredentialsMethodArgs | None
73
+ ) = None,
67
74
  **kwargs,
68
75
  ):
69
- super().__init__(**kwargs)
70
- self.defer_refresh: bool = defer_refresh is not False
71
- self.refresh_method: RefreshMethod = "custom"
72
- self._custom_get_credentials = custom_credentials_method
73
- self._custom_get_credentials_args = (
76
+ if "refresh_method" in kwargs:
77
+ BRSWarning(
78
+ "'refresh_method' cannot be set manually. "
79
+ "Reverting to 'custom'."
80
+ )
81
+ del kwargs["refresh_method"]
82
+
83
+ # initializing BRSSession
84
+ super().__init__(refresh_method="custom", **kwargs)
85
+ self._custom_get_credentials: CustomCredentialsMethod = (
86
+ custom_credentials_method
87
+ )
88
+ self._custom_get_credentials_args: CustomCredentialsMethodArgs = (
74
89
  custom_credentials_method_args
75
90
  if custom_credentials_method_args is not None
76
91
  else {}
77
92
  )
78
- self.__post_init__()
79
93
 
80
94
  def _get_credentials(self) -> TemporaryCredentials:
81
95
  credentials: TemporaryCredentials = self._custom_get_credentials(
@@ -6,9 +6,9 @@ import os
6
6
 
7
7
  import requests
8
8
 
9
- from ..exceptions import BRSError
9
+ from ..exceptions import BRSError, BRSWarning
10
10
  from ..session import BaseRefreshableSession
11
- from ..utils import RefreshMethod, TemporaryCredentials
11
+ from ..utils import TemporaryCredentials, refreshable_session
12
12
 
13
13
  _ECS_CREDENTIALS_RELATIVE_URI = "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"
14
14
  _ECS_CREDENTIALS_FULL_URI = "AWS_CONTAINER_CREDENTIALS_FULL_URI"
@@ -16,6 +16,7 @@ _ECS_AUTHORIZATION_TOKEN = "AWS_CONTAINER_AUTHORIZATION_TOKEN"
16
16
  _DEFAULT_ENDPOINT_BASE = "http://169.254.170.2"
17
17
 
18
18
 
19
+ @refreshable_session
19
20
  class ECSRefreshableSession(BaseRefreshableSession, registry_key="ecs"):
20
21
  """A boto3 session that automatically refreshes temporary AWS credentials
21
22
  from the ECS container credentials metadata endpoint.
@@ -34,14 +35,21 @@ class ECSRefreshableSession(BaseRefreshableSession, registry_key="ecs"):
34
35
  Optional keyword arguments passed to :class:`boto3.session.Session`.
35
36
  """
36
37
 
37
- def __init__(self, defer_refresh: bool | None = None, **kwargs):
38
- super().__init__(**kwargs)
39
- self.defer_refresh: bool = defer_refresh is not False
40
- self.refresh_method: RefreshMethod = "ecs-container-metadata"
38
+ def __init__(self, **kwargs):
39
+ if "refresh_method" in kwargs:
40
+ BRSWarning(
41
+ "'refresh_method' cannot be set manually. "
42
+ "Reverting to 'ecs-container-metadata'."
43
+ )
44
+ del kwargs["refresh_method"]
45
+
46
+ # initializing BRSSession
47
+ super().__init__(refresh_method="ecs-container-metadata", **kwargs)
48
+
49
+ # initializing various other attributes
41
50
  self._endpoint = self._resolve_endpoint()
42
51
  self._headers = self._build_headers()
43
52
  self._http = self._init_http_session()
44
- self.__post_init__()
45
53
 
46
54
  def _resolve_endpoint(self) -> str:
47
55
  uri = os.environ.get(_ECS_CREDENTIALS_FULL_URI) or os.environ.get(
@@ -4,10 +4,11 @@ from pathlib import Path
4
4
  from typing import Any
5
5
 
6
6
  from ...exceptions import BRSError
7
- from ...utils import PKCS11, TemporaryCredentials
7
+ from ...utils import PKCS11, TemporaryCredentials, refreshable_session
8
8
  from .core import BaseIoTRefreshableSession
9
9
 
10
10
 
11
+ @refreshable_session
11
12
  class IoTCertificateRefreshableSession(
12
13
  BaseIoTRefreshableSession, registry_key="certificate"
13
14
  ):
@@ -2,10 +2,11 @@ __all__ = ["IoTCognitoRefreshableSession"]
2
2
 
3
3
  from typing import Any
4
4
 
5
- from ...utils import TemporaryCredentials
5
+ from ...utils import TemporaryCredentials, refreshable_session
6
6
  from .core import BaseIoTRefreshableSession
7
7
 
8
8
 
9
+ @refreshable_session
9
10
  class IoTCognitoRefreshableSession(
10
11
  BaseIoTRefreshableSession, registry_key="cognito"
11
12
  ):
@@ -8,12 +8,13 @@ from ..exceptions import BRSWarning
8
8
  from ..session import BaseRefreshableSession
9
9
  from ..utils import (
10
10
  AssumeRoleParams,
11
- RefreshMethod,
12
11
  STSClientParams,
13
12
  TemporaryCredentials,
13
+ refreshable_session,
14
14
  )
15
15
 
16
16
 
17
+ @refreshable_session
17
18
  class STSRefreshableSession(BaseRefreshableSession, registry_key="sts"):
18
19
  """A :class:`boto3.session.Session` object that automatically refreshes
19
20
  temporary AWS credentials using an IAM role that is assumed via STS.
@@ -43,13 +44,20 @@ class STSRefreshableSession(BaseRefreshableSession, registry_key="sts"):
43
44
  def __init__(
44
45
  self,
45
46
  assume_role_kwargs: AssumeRoleParams,
46
- defer_refresh: bool | None = None,
47
47
  sts_client_kwargs: STSClientParams | None = None,
48
48
  **kwargs,
49
49
  ):
50
- super().__init__(**kwargs)
51
- self.defer_refresh: bool = defer_refresh is not False
52
- self.refresh_method: RefreshMethod = "sts-assume-role"
50
+ if "refresh_method" in kwargs:
51
+ BRSWarning(
52
+ "'refresh_method' cannot be set manually. "
53
+ "Reverting to 'sts-assume-role'."
54
+ )
55
+ del kwargs["refresh_method"]
56
+
57
+ # initializing BRSSession
58
+ super().__init__(refresh_method="sts-assume-role", **kwargs)
59
+
60
+ # initializing various other attributes
53
61
  self.assume_role_kwargs = assume_role_kwargs
54
62
 
55
63
  if sts_client_kwargs is not None:
@@ -66,8 +74,6 @@ class STSRefreshableSession(BaseRefreshableSession, registry_key="sts"):
66
74
  else:
67
75
  self._sts_client = self.client(service_name="sts")
68
76
 
69
- self.__post_init__()
70
-
71
77
  def _get_credentials(self) -> TemporaryCredentials:
72
78
  temporary_credentials = self._sts_client.assume_role(
73
79
  **self.assume_role_kwargs
@@ -1,5 +1,8 @@
1
+ from __future__ import annotations
2
+
1
3
  from abc import ABC, abstractmethod
2
4
  from datetime import datetime
5
+ from functools import wraps
3
6
  from typing import (
4
7
  Any,
5
8
  Callable,
@@ -7,8 +10,12 @@ from typing import (
7
10
  Generic,
8
11
  List,
9
12
  Literal,
13
+ Mapping,
14
+ Protocol,
15
+ TypeAlias,
10
16
  TypedDict,
11
17
  TypeVar,
18
+ cast,
12
19
  )
13
20
 
14
21
  from boto3.session import Session
@@ -45,6 +52,52 @@ RefreshMethod = Literal[
45
52
  #: Type alias for all currently registered credential refresh methods.
46
53
  RegistryKey = TypeVar("RegistryKey", bound=str)
47
54
 
55
+ #: Type alias for a generic refreshable session type.
56
+ BRSSessionType = TypeVar("BRSSessionType", bound="BRSSession")
57
+
58
+
59
+ def refreshable_session(
60
+ cls: type[BRSSessionType],
61
+ ) -> type[BRSSessionType]:
62
+ """Wraps cls.__init__ so self.__post_init__ runs after init (if present).
63
+
64
+ Returns
65
+ -------
66
+ BRSSessionType
67
+ The decorated class.
68
+ """
69
+
70
+ init = getattr(cls, "__init__", None)
71
+
72
+ # synthesize __init__ if undefined in the class
73
+ if init in (None, object.__init__):
74
+
75
+ def __init__(self, *args, **kwargs):
76
+ super(cls, self).__init__(*args, **kwargs)
77
+ post = getattr(self, "__post_init__", None)
78
+ if callable(post) and not getattr(self, "_post_inited", False):
79
+ post()
80
+ setattr(self, "_post_inited", True)
81
+
82
+ cls.__init__ = __init__ # type: ignore[assignment]
83
+ return cls
84
+
85
+ # avoids double wrapping
86
+ if getattr(init, "__post_init_wrapped__", False):
87
+ return cls
88
+
89
+ @wraps(init)
90
+ def wrapper(self, *args, **kwargs):
91
+ init(self, *args, **kwargs)
92
+ post = getattr(self, "__post_init__", None)
93
+ if callable(post) and not getattr(self, "_post_inited", False):
94
+ post()
95
+ setattr(self, "_post_inited", True)
96
+
97
+ wrapper.__post_init_wrapped__ = True # type: ignore[attr-defined]
98
+ cls.__init__ = cast(Callable[..., None], wrapper)
99
+ return cls
100
+
48
101
 
49
102
  class Registry(Generic[RegistryKey]):
50
103
  """Gives any hierarchy a class-level registry."""
@@ -76,6 +129,17 @@ class TemporaryCredentials(TypedDict):
76
129
  expiry_time: datetime | str
77
130
 
78
131
 
132
+ class _CustomCredentialsMethod(Protocol):
133
+ def __call__(self, **kwargs: Any) -> TemporaryCredentials: ...
134
+
135
+
136
+ #: Type alias for custom credential retrieval methods.
137
+ CustomCredentialsMethod: TypeAlias = _CustomCredentialsMethod
138
+
139
+ #: Type alias for custom credential method arguments.
140
+ CustomCredentialsMethodArgs: TypeAlias = Mapping[str, Any]
141
+
142
+
79
143
  class RefreshableTemporaryCredentials(TypedDict):
80
144
  """Refreshable IAM credentials.
81
145
 
@@ -107,12 +171,28 @@ class CredentialProvider(ABC):
107
171
  class BRSSession(Session):
108
172
  """Wrapper for boto3.session.Session.
109
173
 
174
+ Parameters
175
+ ----------
176
+ refresh_method : RefreshMethod
177
+ The method to use for refreshing temporary credentials.
178
+ defer_refresh : bool, default=True
179
+ If True, the initial credential refresh is deferred until the
180
+ credentials are first accessed. If False, the initial refresh
181
+
110
182
  Other Parameters
111
183
  ----------------
112
184
  kwargs : Any
113
- Optional keyword arguments for initializing boto3.session.Session."""
185
+ Optional keyword arguments for initializing boto3.session.Session.
186
+ """
114
187
 
115
- def __init__(self, **kwargs):
188
+ def __init__(
189
+ self,
190
+ refresh_method: RefreshMethod,
191
+ defer_refresh: bool | None = None,
192
+ **kwargs,
193
+ ):
194
+ self.refresh_method: RefreshMethod = refresh_method
195
+ self.defer_refresh: bool = defer_refresh is not False
116
196
  super().__init__(**kwargs)
117
197
 
118
198
  def __post_init__(self):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: boto3-refresh-session
3
- Version: 2.0.7
3
+ Version: 2.0.9
4
4
  Summary: A simple Python package for refreshing the temporary security credentials in a boto3.session.Session object automatically.
5
5
  License: MIT
6
6
  Keywords: boto3,botocore,aws,sts,ecs,credentials,token,refresh
@@ -0,0 +1,17 @@
1
+ boto3_refresh_session/__init__.py,sha256=oUmq6AKEMx1Gvi0U6BPMiktIargvfJVoMwyC4jm60eA,387
2
+ boto3_refresh_session/exceptions.py,sha256=cP5d9S8QnUEwXIU3pzMGr6jMOz447kddNJ_UIRERMrk,964
3
+ boto3_refresh_session/methods/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ boto3_refresh_session/methods/custom.py,sha256=fMqaSgbmv-mfDMe1lXEPF1V4dQcwPsCN8qcRHW2IeqE,4209
5
+ boto3_refresh_session/methods/ecs.py,sha256=aXQXS7beS2RBXIeQkUNQkM4zhtDQv0n1Mkf9wnFbOTE,3931
6
+ boto3_refresh_session/methods/iot/__init__.typed,sha256=Z33nIB6oCsz9TZwikHfNHgY1SKxkSCdB5rwdPSUl3C4,135
7
+ boto3_refresh_session/methods/iot/certificate.typed,sha256=xBucJJfRb0_iKuhbtRxOWeRERzyJxo7iYW6-0VbmdA0,1816
8
+ boto3_refresh_session/methods/iot/cognito.typed,sha256=OgFYOCDIkt2QC_F0KLL_BrxVxT6qMwjn-0yi4ZIwZYo,431
9
+ boto3_refresh_session/methods/iot/core.typed,sha256=tL-ngB2XYq0XtxhS9mbggCJYdX3eEE0u1Gvcq8sEYGE,1422
10
+ boto3_refresh_session/methods/sts.py,sha256=FvblbuXDaczEfsRIs59eKOodrJjHcMKHrnrmxjXfNeU,3401
11
+ boto3_refresh_session/session.py,sha256=_Z3uB5Xq3S-dFqOFmWhMQbcd__NPGThjULLPStHI6E4,2914
12
+ boto3_refresh_session/utils.py,sha256=9Nru9GWWMAboDRJMstKIBFtKA2R8u3DFFcCvsQYSNCI,7976
13
+ boto3_refresh_session-2.0.9.dist-info/LICENSE,sha256=I3ZYTXAjbIly6bm6J-TvFTuuHwTKws4h89QaY5c5HiY,1067
14
+ boto3_refresh_session-2.0.9.dist-info/METADATA,sha256=0M9RJlmPWHbmYrbgz1MjLU7BaSsm8wpr4dAkuJJ86Hs,8795
15
+ boto3_refresh_session-2.0.9.dist-info/NOTICE,sha256=1s8r33qbl1z0YvPB942iWgvbkP94P_e8AnROr1qXXuw,939
16
+ boto3_refresh_session-2.0.9.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
17
+ boto3_refresh_session-2.0.9.dist-info/RECORD,,
@@ -1,17 +0,0 @@
1
- boto3_refresh_session/__init__.py,sha256=3VYnpC-52TTWbTfkoYwW5o7ImCNWsLGeKNWk5CmL5k8,387
2
- boto3_refresh_session/exceptions.py,sha256=cP5d9S8QnUEwXIU3pzMGr6jMOz447kddNJ_UIRERMrk,964
3
- boto3_refresh_session/methods/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- boto3_refresh_session/methods/custom.py,sha256=JDDfBszAesNV2gSv8lJvGxCpbM9-lUn0L9HDt-rPETM,3846
5
- boto3_refresh_session/methods/ecs.py,sha256=qejldriuTVpHPSkquHeo4vLGbe0_WAg_iayuJFk6W9Q,3728
6
- boto3_refresh_session/methods/iot/__init__.typed,sha256=Z33nIB6oCsz9TZwikHfNHgY1SKxkSCdB5rwdPSUl3C4,135
7
- boto3_refresh_session/methods/iot/certificate.typed,sha256=yvKptwH-GagBREI_1AXs_mCaU6vL3AcUDQ58vn7V8QM,1774
8
- boto3_refresh_session/methods/iot/cognito.typed,sha256=0VorzOXHpsVemiGWZzHE9fuX-MZcpqzWQ4nK3gNDUMg,389
9
- boto3_refresh_session/methods/iot/core.typed,sha256=tL-ngB2XYq0XtxhS9mbggCJYdX3eEE0u1Gvcq8sEYGE,1422
10
- boto3_refresh_session/methods/sts.py,sha256=SjeVNXXB50wLINr5GhjALrnytPleu6UeE0BBAJU28Lc,3226
11
- boto3_refresh_session/session.py,sha256=_Z3uB5Xq3S-dFqOFmWhMQbcd__NPGThjULLPStHI6E4,2914
12
- boto3_refresh_session/utils.py,sha256=z-lN5szAETD88-h4pNEwBDcqAPqzeGo5QJ0hNUJdDWA,5560
13
- boto3_refresh_session-2.0.7.dist-info/LICENSE,sha256=I3ZYTXAjbIly6bm6J-TvFTuuHwTKws4h89QaY5c5HiY,1067
14
- boto3_refresh_session-2.0.7.dist-info/METADATA,sha256=fhSKcYLuhphxBm8uLmzAKt7kO4YE1dbl3gsPj_Li4DU,8795
15
- boto3_refresh_session-2.0.7.dist-info/NOTICE,sha256=1s8r33qbl1z0YvPB942iWgvbkP94P_e8AnROr1qXXuw,939
16
- boto3_refresh_session-2.0.7.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
17
- boto3_refresh_session-2.0.7.dist-info/RECORD,,