boto3-refresh-session 1.0.41__py3-none-any.whl → 1.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.
@@ -1,8 +1,6 @@
1
- __all__ = []
2
-
3
- from . import session
4
1
  from .session import RefreshableSession
2
+ from .sts import STSRefreshableSession
5
3
 
6
- __all__.extend(session.__all__)
7
- __version__ = "1.0.41"
4
+ __all__ = ["RefreshableSession"]
5
+ __version__ = "1.1.0"
8
6
  __author__ = "Mike Letts"
@@ -1,159 +1,155 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  __doc__ = """
4
- A :class:`boto3.session.Session` object that automatically refreshes temporary AWS
5
- credentials.
4
+ boto3_refresh_session.session
5
+ =============================
6
+
7
+ This module provides the main interface for constructing refreshable boto3 sessions.
8
+
9
+ The ``RefreshableSession`` class serves as a factory that dynamically selects the appropriate
10
+ credential refresh strategy based on the ``method`` parameter, e.g., ``sts``.
11
+
12
+ Users can interact with AWS services just like they would with a normal :class:`boto3.session.Session`,
13
+ with the added benefit of automatic credential refreshing.
14
+
15
+ Examples
16
+ --------
17
+ >>> from boto3_refresh_session import RefreshableSession
18
+ >>> session = RefreshableSession(
19
+ ... assume_role_kwargs={"RoleArn": "...", "RoleSessionName": "..."},
20
+ ... region_name="us-east-1"
21
+ ... )
22
+ >>> s3 = session.client("s3")
23
+ >>> s3.list_buckets()
24
+
25
+ .. seealso::
26
+ :class:`boto3_refresh_session.sts.STSRefreshableSession`
27
+
28
+ Factory interface
29
+ -----------------
30
+ .. autosummary::
31
+ :toctree: generated/
32
+ :nosignatures:
33
+
34
+ RefreshableSession
6
35
  """
36
+
7
37
  __all__ = ["RefreshableSession"]
8
38
 
9
- from typing import Any, Dict
39
+ from abc import ABC, abstractmethod
40
+ from typing import Any, Callable, ClassVar, Literal, get_args
10
41
  from warnings import warn
11
42
 
12
- from boto3 import client
13
43
  from boto3.session import Session
14
44
  from botocore.credentials import (
15
45
  DeferredRefreshableCredentials,
16
46
  RefreshableCredentials,
17
47
  )
18
48
 
49
+ #: Type alias for all currently available credential refresh methods.
50
+ Method = Literal["sts"]
51
+ RefreshMethod = Literal["sts-assume-role"]
52
+
53
+
54
+ class BaseRefreshableSession(ABC, Session):
55
+ """Abstract base class for implementing refreshable AWS sessions.
19
56
 
20
- class RefreshableSession(Session):
21
- """A :class:`boto3.session.Session` object that automatically refreshes temporary AWS
22
- credentials.
57
+ Provides a common interface and factory registration mechanism
58
+ for subclasses that generate temporary credentials using various
59
+ AWS authentication methods (e.g., STS).
60
+
61
+ Subclasses must implement ``_get_credentials()`` and ``get_identity()``.
62
+ They should also register themselves using the ``method=...`` argument
63
+ to ``__init_subclass__``.
23
64
 
24
65
  Parameters
25
66
  ----------
26
- assume_role_kwargs : dict
27
- Required keyword arguments for the :meth:`STS.Client.assume_role` method.
28
- defer_refresh : bool, optional
29
- If ``True`` then temporary credentials are not automatically refreshed until
30
- they are explicitly needed. If ``False`` then temporary credentials refresh
31
- immediately upon expiration. It is highly recommended that you use ``True``.
32
- Default is ``True``.
33
- sts_client_kwargs : dict, optional
34
- Optional keyword arguments for the :class:`STS.Client` object. Do not provide
35
- values for ``service_name``. Default is None.
67
+ registry : dict[str, type[BaseRefreshableSession]]
68
+ Class-level registry mapping method names to registered session types.
69
+ """
36
70
 
37
- Other Parameters
38
- ----------------
39
- kwargs : dict
40
- Optional keyword arguments for the :class:`boto3.session.Session` object.
71
+ # adding this and __init_subclass__ to avoid circular imports
72
+ # as well as simplify future addition of new methods
73
+ registry: ClassVar[dict[Method, type[BaseRefreshableSession]]] = {}
41
74
 
42
- Notes
43
- -----
44
- Check the :ref:`authorization documentation <authorization>` for additional
45
- information concerning how to authorize access to AWS.
75
+ def __init_subclass__(cls, method: Method):
76
+ super().__init_subclass__()
46
77
 
47
- Check the `AWS documentation <https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp.html>`_
48
- for additional information concerning temporary security credentials in IAM.
78
+ # guarantees that methods are unique
79
+ if method in BaseRefreshableSession.registry:
80
+ warn(f"Method '{method}' is already registered. Overwriting.")
49
81
 
50
- Examples
51
- --------
52
- In order to use this object, you are required to configure parameters for the
53
- :meth:`STS.Client.assume_role` method.
54
-
55
- >>> assume_role_kwargs = {
56
- >>> 'RoleArn': '<your-role-arn>',
57
- >>> 'RoleSessionName': '<your-role-session-name>',
58
- >>> 'DurationSeconds': '<your-selection>',
59
- >>> ...
60
- >>> }
61
-
62
- You may also want to provide optional parameters for the :class:`STS.Client` object.
63
-
64
- >>> sts_client_kwargs = {
65
- >>> ...
66
- >>> }
67
-
68
- You may also provide optional parameters for the :class:`boto3.session.Session` object
69
- when initializing the ``RefreshableSession`` object. Below, we use the ``region_name``
70
- parameter for illustrative purposes.
71
-
72
- >>> session = boto3_refresh_session.RefreshableSession(
73
- >>> assume_role_kwargs=assume_role_kwargs,
74
- >>> sts_client_kwargs=sts_client_kwargs,
75
- >>> region_name='us-east-1',
76
- >>> )
77
-
78
- Using the ``session`` variable that you just created, you can now use all of the methods
79
- available from the :class:`boto3.session.Session` object. In the below example, we
80
- initialize an S3 client and list all available buckets.
81
-
82
- >>> s3 = session.client(service_name='s3')
83
- >>> buckets = s3.list_buckets()
84
-
85
- There are two ways of refreshing temporary credentials automatically with the
86
- ``RefreshableSession`` object: refresh credentials the moment they expire, or wait until
87
- temporary credentials are explicitly needed. The latter is the default. The former must
88
- be configured using the ``defer_refresh`` parameter, as shown below.
89
-
90
- >>> session = boto3_refresh_session.RefreshableSession(
91
- >>> defer_refresh=False,
92
- >>> assume_role_kwargs=assume_role_kwargs,
93
- >>> sts_client_kwargs=sts_client_kwargs,
94
- >>> region_name='us-east-1',
95
- >>> )
96
- """
82
+ BaseRefreshableSession.registry[method] = cls
97
83
 
98
- def __init__(
99
- self,
100
- assume_role_kwargs: Dict[Any],
101
- defer_refresh: bool = None,
102
- sts_client_kwargs: Dict[Any] = None,
103
- **kwargs,
104
- ):
105
- # inheriting from boto3.session.Session
84
+ def __init__(self, **kwargs):
106
85
  super().__init__(**kwargs)
107
86
 
108
- # setting defer_refresh default
109
- if defer_refresh is None:
110
- defer_refresh = True
111
-
112
- # initializing custom parameters that are necessary outside of __init__
113
- self.assume_role_kwargs = assume_role_kwargs
114
-
115
- # initializing the STS client
116
- if sts_client_kwargs is not None:
117
- # overwriting 'service_name' in case it appears in sts_client_kwargs
118
- if "service_name" in sts_client_kwargs:
119
- warn(
120
- "The sts_client_kwargs parameter cannot contain values for service_name. Reverting to service_name = 'sts'."
121
- )
122
- del sts_client_kwargs["service_name"]
123
- self._sts_client = client(service_name="sts", **sts_client_kwargs)
124
- else:
125
- self._sts_client = client(service_name="sts")
87
+ @abstractmethod
88
+ def _get_credentials(self) -> dict[str, str]: ...
126
89
 
90
+ @abstractmethod
91
+ def get_identity(self) -> dict[str, Any]: ...
92
+
93
+ def _refresh_using(
94
+ self,
95
+ credentials_method: Callable,
96
+ defer_refresh: bool,
97
+ refresh_method: RefreshMethod,
98
+ ):
127
99
  # determining how exactly to refresh expired temporary credentials
128
100
  if not defer_refresh:
129
- self._session._credentials = (
130
- RefreshableCredentials.create_from_metadata(
131
- metadata=self._get_credentials(),
132
- refresh_using=self._get_credentials,
133
- method="sts-assume-role",
134
- )
101
+ self._credentials = RefreshableCredentials.create_from_metadata(
102
+ metadata=credentials_method(),
103
+ refresh_using=credentials_method,
104
+ method=refresh_method,
135
105
  )
136
106
  else:
137
- self._session._credentials = DeferredRefreshableCredentials(
138
- refresh_using=self._get_credentials, method="sts-assume-role"
107
+ self._credentials = DeferredRefreshableCredentials(
108
+ refresh_using=credentials_method, method=refresh_method
139
109
  )
140
110
 
141
- def _get_credentials(self) -> Dict[Any]:
142
- """Returns temporary credentials via AWS STS.
111
+
112
+ class RefreshableSession:
113
+ """Factory class for constructing refreshable boto3 sessions using various authentication
114
+ methods, e.g. STS.
115
+
116
+ This class provides a unified interface for creating boto3 sessions whose credentials are
117
+ automatically refreshed in the background.
118
+
119
+ Use ``RefreshableSession(method="...")`` to construct an instance using the desired method.
120
+
121
+ For additional information on required parameters, refer to the See Also section below.
122
+
123
+ Parameters
124
+ ----------
125
+ method : Method
126
+ The authentication and refresh method to use for the session. Must match a registered method name.
127
+ Default is "sts".
128
+
129
+ Other Parameters
130
+ ----------------
131
+ **kwargs : dict
132
+ Additional keyword arguments forwarded to the constructor of the selected session class.
133
+
134
+ See Also
135
+ --------
136
+ boto3_refresh_session.sts.STSRefreshableSession
137
+ """
138
+
139
+ def __new__(
140
+ cls, method: Method = "sts", **kwargs
141
+ ) -> BaseRefreshableSession:
142
+ obj = BaseRefreshableSession.registry[method]
143
+ return obj(**kwargs)
144
+
145
+ @classmethod
146
+ def get_available_methods(cls) -> list[str]:
147
+ """Lists all currently available credential refresh methods.
143
148
 
144
149
  Returns
145
150
  -------
146
- dict
147
- AWS temporary credentials.
151
+ list[str]
152
+ A list of all currently available credential refresh methods, e.g. 'sts'.
148
153
  """
149
154
 
150
- # fetching temporary credentials
151
- temporary_credentials = self._sts_client.assume_role(
152
- **self.assume_role_kwargs
153
- )["Credentials"]
154
- return {
155
- "access_key": temporary_credentials.get("AccessKeyId"),
156
- "secret_key": temporary_credentials.get("SecretAccessKey"),
157
- "token": temporary_credentials.get("SessionToken"),
158
- "expiry_time": temporary_credentials.get("Expiration").isoformat(),
159
- }
155
+ return list(get_args(Method))
@@ -0,0 +1,124 @@
1
+ from __future__ import annotations
2
+
3
+ __doc__ = """
4
+ boto3_refresh_session.sts
5
+ =========================
6
+
7
+ Implements the STS-based credential refresh strategy for use with
8
+ :class:`boto3_refresh_session.session.RefreshableSession`.
9
+
10
+ This module defines the :class:`STSRefreshableSession` class, which uses
11
+ IAM role assumption via STS to automatically refresh temporary credentials
12
+ in the background.
13
+
14
+ .. versionadded:: 1.1.0
15
+
16
+ Examples
17
+ --------
18
+ >>> from boto3_refresh_session import RefreshableSession
19
+ >>> session = RefreshableSession(
20
+ ... method="sts",
21
+ ... assume_role_kwargs={
22
+ ... "RoleArn": "arn:aws:iam::123456789012:role/MyRole",
23
+ ... "RoleSessionName": "my-session"
24
+ ... },
25
+ ... region_name="us-east-1"
26
+ ... )
27
+ >>> s3 = session.client("s3")
28
+ >>> s3.list_buckets()
29
+
30
+ .. seealso::
31
+ :class:`boto3_refresh_session.session.RefreshableSession`
32
+
33
+ STS
34
+ ---
35
+
36
+ .. autosummary::
37
+ :toctree: generated/
38
+ :nosignatures:
39
+
40
+ STSRefreshableSession
41
+ """
42
+ __all__ = ["STSRefreshableSession"]
43
+
44
+ from typing import Any
45
+ from warnings import warn
46
+
47
+ from boto3 import client
48
+
49
+ from .session import BaseRefreshableSession
50
+
51
+
52
+ class STSRefreshableSession(BaseRefreshableSession, method="sts"):
53
+ """A :class:`boto3.session.Session` object that automatically refreshes temporary AWS
54
+ credentials using an IAM role that is assumed via STS.
55
+
56
+ Parameters
57
+ ----------
58
+ assume_role_kwargs : dict
59
+ Required keyword arguments for :meth:`STS.Client.assume_role` (i.e. boto3 STS client).
60
+ defer_refresh : bool, optional
61
+ If ``True`` then temporary credentials are not automatically refreshed until
62
+ they are explicitly needed. If ``False`` then temporary credentials refresh
63
+ immediately upon expiration. It is highly recommended that you use ``True``.
64
+ Default is ``True``.
65
+ sts_client_kwargs : dict, optional
66
+ Optional keyword arguments for the :class:`STS.Client` object. Do not provide
67
+ values for ``service_name`` as they are unnecessary. Default is None.
68
+
69
+ Other Parameters
70
+ ----------------
71
+ kwargs : dict
72
+ Optional keyword arguments for the :class:`boto3.session.Session` object.
73
+ """
74
+
75
+ def __init__(
76
+ self,
77
+ assume_role_kwargs: dict,
78
+ defer_refresh: bool = None,
79
+ sts_client_kwargs: dict | None = None,
80
+ **kwargs,
81
+ ):
82
+ super().__init__(**kwargs)
83
+ defer_refresh = defer_refresh is not False
84
+ self.assume_role_kwargs = assume_role_kwargs
85
+
86
+ if sts_client_kwargs is not None:
87
+ # overwriting 'service_name' in case it appears in sts_client_kwargs
88
+ if "service_name" in sts_client_kwargs:
89
+ warn(
90
+ "The sts_client_kwargs parameter cannot contain values for service_name. Reverting to service_name = 'sts'."
91
+ )
92
+ del sts_client_kwargs["service_name"]
93
+ self._sts_client = client(service_name="sts", **sts_client_kwargs)
94
+ else:
95
+ self._sts_client = client(service_name="sts")
96
+
97
+ # mounting refreshable credentials
98
+ self._refresh_using(
99
+ credentials_method=self._get_credentials,
100
+ defer_refresh=defer_refresh,
101
+ refresh_method="sts-assume-role",
102
+ )
103
+
104
+ def _get_credentials(self) -> dict[str, str]:
105
+ temporary_credentials = self._sts_client.assume_role(
106
+ **self.assume_role_kwargs
107
+ )["Credentials"]
108
+ return {
109
+ "access_key": temporary_credentials.get("AccessKeyId"),
110
+ "secret_key": temporary_credentials.get("SecretAccessKey"),
111
+ "token": temporary_credentials.get("SessionToken"),
112
+ "expiry_time": temporary_credentials.get("Expiration").isoformat(),
113
+ }
114
+
115
+ def get_identity(self) -> dict[str, Any]:
116
+ """Returns metadata about the identity assumed.
117
+
118
+ Returns
119
+ -------
120
+ dict[str, Any]
121
+ Dict containing caller identity according to AWS STS.
122
+ """
123
+
124
+ return self._sts_client.get_caller_identity()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: boto3-refresh-session
3
- Version: 1.0.41
3
+ Version: 1.1.0
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
@@ -56,7 +56,7 @@ Description-Content-Type: text/markdown
56
56
  </a>
57
57
 
58
58
  <a href="https://pepy.tech/project/boto3-refresh-session">
59
- <img src="https://img.shields.io/badge/downloads-56.7K-red?logo=python&color=%23FF0000&label=Downloads" alt="Downloads"/>
59
+ <img src="https://img.shields.io/badge/downloads-57.4K-red?logo=python&color=%23FF0000&label=Downloads" alt="Downloads"/>
60
60
  </a>
61
61
 
62
62
  <a href="https://michaelthomasletts.github.io/boto3-refresh-session/index.html">
@@ -79,28 +79,23 @@ Description-Content-Type: text/markdown
79
79
  - Drop-in replacement for `boto3.session.Session`
80
80
  - Supports `assume_role` configuration, custom STS clients, and profile / region configuration, as well as all other parameters supported by `boto3.session.Session`
81
81
  - Tested, documented, and published to PyPI
82
- - Used in production at major tech companies
83
82
 
84
- ## Adoption and Recognition
83
+ ## Recognition, Adoption, and Testimonials
85
84
 
86
- [Mentioned in TL;DR Sec](https://tldrsec.com/p/tldr-sec-282).
85
+ [Featured in TL;DR Sec.](https://tldrsec.com/p/tldr-sec-282)
87
86
 
88
- Received honorable mention during AWS Community Day Midwest on June 5th, 2025.
87
+ Recognized during AWS Community Day Midwest on June 5th, 2025.
89
88
 
90
- Used by multiple teams and large companies including FAANG.
89
+ A testimonial from a Cyber Security Engineer at a FAANG company:
91
90
 
92
- The following line plot illustrates the adoption of BRS from the last three months in terms of average daily downloads over a rolling seven day window.
91
+ > _Most of my work is on tooling related to AWS security, so I'm pretty choosy about boto3 credentials-adjacent code. I often opt to just write this sort of thing myself so I at least know that I can reason about it. But I found boto3-refresh-session to be very clean and intuitive [...] We're using the RefreshableSession class as part of a client cache construct [...] We're using AWS Lambda to perform lots of operations across several regions in hundreds of accounts, over and over again, all day every day. And it turns out that there's a surprising amount of overhead to creating boto3 clients (mostly deserializing service definition json), so we can run MUCH more efficiently if we keep a cache of clients, all equipped with automatically refreshing sessions._
92
+
93
+ The following line plot illustrates the adoption of BRS over the last three months in terms of average daily downloads over a rolling seven day window.
93
94
 
94
95
  <p align="center">
95
96
  <img src="https://raw.githubusercontent.com/michaelthomasletts/boto3-refresh-session/refs/heads/main/doc/downloads.png" />
96
97
  </p>
97
98
 
98
- ## Testimonials
99
-
100
- From a Cyber Security Engineer at a FAANG company:
101
-
102
- > _Most of my work is on tooling related to AWS security, so I'm pretty choosy about boto3 credentials-adjacent code. I often opt to just write this sort of thing myself so I at least know that I can reason about it. But I found boto3-refresh-session to be very clean and intuitive [...] We're using the RefreshableSession class as part of a client cache construct [...] We're using AWS Lambda to perform lots of operations across several regions in hundreds of accounts, over and over again, all day every day. And it turns out that there's a surprising amount of overhead to creating boto3 clients (mostly deserializing service definition json), so we can run MUCH more efficiently if we keep a cache of clients, all equipped with automatically refreshing sessions._
103
-
104
99
  ## Installation
105
100
 
106
101
  ```bash
@@ -148,27 +143,28 @@ buckets = s3.list_buckets()
148
143
 
149
144
  ## Raison d'être
150
145
 
151
- It is common for data pipelines and workflows that interact with the AWS API via
152
- `boto3` to run for a long time and, accordingly, for temporary credentials to
153
- expire.
146
+ Long-running data pipelines, security tooling, ETL jobs, and cloud automation scripts frequently interact with the AWS API using boto3 — and often run into the same problem:
147
+
148
+ **Temporary credentials expire.**
149
+
150
+ When that happens, engineers typically fall back on one of two strategies:
151
+
152
+ - Wrapping AWS calls in try/except blocks that catch ClientError exceptions
153
+ - Writing ad hoc logic to refresh credentials using botocore credentials internals
154
154
 
155
- Usually, engineers deal with that problem one of two ways:
155
+ Both approaches are fragile, tedious to maintain, and error-prone at scale.
156
156
 
157
- - `try except` blocks that catch `ClientError` exceptions
158
- - A similar approach as that used in this project -- that is, using methods available
159
- within `botocore` for refreshing temporary credentials automatically.
160
-
161
- Speaking personally, variations of the code found herein exists in code bases at
162
- nearly every company where I have worked. Sometimes, I turned that code into a module;
163
- other times, I wrote it from scratch. Clearly, that is inefficient.
157
+ Over the years, I noticed that every company I worked for — whether a scrappy startup or FAANG — ended up with some variation of the same pattern:
158
+ a small in-house module to manage credential refresh, written in haste, duplicated across services, and riddled with edge cases. Things only
159
+ got more strange and difficult when I needed to run things in parallel.
164
160
 
165
- I decided to finally turn that code into a proper Python package with unit testing,
166
- automatic documentation, and quality checks; the idea being that, henceforth, depending
167
- on my employer's open source policy, I may simply import this package instead of
168
- reproducing the code herein for the Nth time.
161
+ Eventually, I decided to build boto3-refresh-session as a proper open-source Python package:
169
162
 
170
- If any of that sounds relatable, then `boto3-refresh-session` should help you.
163
+ - Fully tested
164
+ - Extensible
165
+ - Integrated with boto3 idioms
166
+ - Equipped with automatic documentation and CI tooling
171
167
 
172
- ---
168
+ **The goal:** to solve a real, recurring problem once — cleanly, consistently, and for everyone -- with multiple refresh strategies.
173
169
 
174
- 📄 Licensed under the MIT License.
170
+ If you've ever written the same AWS credential-refresh boilerplate more than once, this library is for you.
@@ -0,0 +1,8 @@
1
+ boto3_refresh_session/__init__.py,sha256=q_SWX2IjsvgROUhgsVpW3h70mSbnIz1fPIYUbsxJSY8,161
2
+ boto3_refresh_session/session.py,sha256=J3FW6nkc_s9C0gj1Xs1wKaCWQMzR6S4ncDKDqu1DYxk,4879
3
+ boto3_refresh_session/sts.py,sha256=8vUBPTtoqJIgF-NOg4617WbmJ92GiKcmsVDdINieoFo,4043
4
+ boto3_refresh_session-1.1.0.dist-info/LICENSE,sha256=I3ZYTXAjbIly6bm6J-TvFTuuHwTKws4h89QaY5c5HiY,1067
5
+ boto3_refresh_session-1.1.0.dist-info/METADATA,sha256=Ny4vrpfNYQdXGuBAkAJW8LPMqO54qysxVHfNsJxCKts,7534
6
+ boto3_refresh_session-1.1.0.dist-info/NOTICE,sha256=1s8r33qbl1z0YvPB942iWgvbkP94P_e8AnROr1qXXuw,939
7
+ boto3_refresh_session-1.1.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
8
+ boto3_refresh_session-1.1.0.dist-info/RECORD,,
@@ -1,7 +0,0 @@
1
- boto3_refresh_session/__init__.py,sha256=NryXLl4sSu3AO_-yrcFsiWU09XnHr-ap4-qr39btGLI,158
2
- boto3_refresh_session/session.py,sha256=ZB1X0ajFZSpuRKi4N3KGg56Y7ZJPMN3jwjMh-6grbvo,5881
3
- boto3_refresh_session-1.0.41.dist-info/LICENSE,sha256=I3ZYTXAjbIly6bm6J-TvFTuuHwTKws4h89QaY5c5HiY,1067
4
- boto3_refresh_session-1.0.41.dist-info/METADATA,sha256=GJZhfPAymeIm1kWAzY4GDrvO_biuYWVMgp4ep28qclA,7406
5
- boto3_refresh_session-1.0.41.dist-info/NOTICE,sha256=1s8r33qbl1z0YvPB942iWgvbkP94P_e8AnROr1qXXuw,939
6
- boto3_refresh_session-1.0.41.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
7
- boto3_refresh_session-1.0.41.dist-info/RECORD,,