boto3 1.40.31__tar.gz → 1.42.22__tar.gz
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.
- {boto3-1.40.31 → boto3-1.42.22}/PKG-INFO +12 -7
- {boto3-1.40.31 → boto3-1.42.22}/README.rst +8 -2
- {boto3-1.40.31 → boto3-1.42.22}/boto3/__init__.py +1 -1
- {boto3-1.40.31 → boto3-1.42.22}/boto3/compat.py +9 -4
- {boto3-1.40.31 → boto3-1.42.22}/boto3/crt.py +53 -3
- {boto3-1.40.31 → boto3-1.42.22}/boto3/docs/__init__.py +1 -1
- {boto3-1.40.31 → boto3-1.42.22}/boto3/docs/service.py +1 -1
- {boto3-1.40.31 → boto3-1.42.22}/boto3/dynamodb/conditions.py +3 -3
- {boto3-1.40.31 → boto3-1.42.22}/boto3/exceptions.py +4 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/resources/base.py +7 -11
- {boto3-1.40.31 → boto3-1.42.22}/boto3/resources/factory.py +3 -3
- {boto3-1.40.31 → boto3-1.42.22}/boto3/resources/model.py +3 -3
- {boto3-1.40.31 → boto3-1.42.22}/boto3/resources/params.py +1 -1
- {boto3-1.40.31 → boto3-1.42.22}/boto3/s3/constants.py +1 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/s3/transfer.py +113 -36
- {boto3-1.40.31 → boto3-1.42.22}/boto3/session.py +1 -1
- {boto3-1.40.31 → boto3-1.42.22}/boto3/utils.py +1 -11
- {boto3-1.40.31 → boto3-1.42.22}/boto3.egg-info/PKG-INFO +12 -7
- {boto3-1.40.31 → boto3-1.42.22}/boto3.egg-info/requires.txt +2 -2
- {boto3-1.40.31 → boto3-1.42.22}/pyproject.toml +9 -1
- {boto3-1.40.31 → boto3-1.42.22}/setup.cfg +2 -2
- {boto3-1.40.31 → boto3-1.42.22}/setup.py +3 -4
- {boto3-1.40.31 → boto3-1.42.22}/CONTRIBUTING.rst +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/LICENSE +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/MANIFEST.in +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/NOTICE +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/data/cloudformation/2010-05-15/resources-1.json +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/data/cloudwatch/2010-08-01/resources-1.json +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/data/dynamodb/2012-08-10/resources-1.json +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/data/ec2/2014-10-01/resources-1.json +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/data/ec2/2015-03-01/resources-1.json +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/data/ec2/2015-04-15/resources-1.json +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/data/ec2/2015-10-01/resources-1.json +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/data/ec2/2016-04-01/resources-1.json +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/data/ec2/2016-09-15/resources-1.json +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/data/ec2/2016-11-15/resources-1.json +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/data/glacier/2012-06-01/resources-1.json +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/data/iam/2010-05-08/resources-1.json +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/data/s3/2006-03-01/resources-1.json +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/data/sns/2010-03-31/resources-1.json +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/data/sqs/2012-11-05/resources-1.json +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/docs/action.py +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/docs/attr.py +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/docs/base.py +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/docs/client.py +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/docs/collection.py +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/docs/docstring.py +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/docs/method.py +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/docs/resource.py +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/docs/subresource.py +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/docs/utils.py +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/docs/waiter.py +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/dynamodb/__init__.py +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/dynamodb/table.py +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/dynamodb/transform.py +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/dynamodb/types.py +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/ec2/__init__.py +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/ec2/createtags.py +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/ec2/deletetags.py +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/examples/cloudfront.rst +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/examples/s3.rst +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/resources/__init__.py +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/resources/action.py +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/resources/collection.py +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/resources/response.py +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/s3/__init__.py +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3/s3/inject.py +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3.egg-info/SOURCES.txt +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3.egg-info/dependency_links.txt +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/boto3.egg-info/top_level.txt +0 -0
- {boto3-1.40.31 → boto3-1.42.22}/requirements.txt +0 -0
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: boto3
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.42.22
|
|
4
4
|
Summary: The AWS SDK for Python
|
|
5
5
|
Home-page: https://github.com/boto/boto3
|
|
6
6
|
Author: Amazon Web Services
|
|
7
|
-
License: Apache
|
|
7
|
+
License: Apache-2.0
|
|
8
8
|
Project-URL: Documentation, https://boto3.amazonaws.com/v1/documentation/api/latest/index.html
|
|
9
9
|
Project-URL: Source, https://github.com/boto/boto3
|
|
10
10
|
Classifier: Development Status :: 5 - Production/Stable
|
|
11
11
|
Classifier: Intended Audience :: Developers
|
|
12
12
|
Classifier: Natural Language :: English
|
|
13
|
-
Classifier: License :: OSI Approved :: Apache Software License
|
|
14
13
|
Classifier: Programming Language :: Python
|
|
15
14
|
Classifier: Programming Language :: Python :: 3
|
|
16
15
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
@@ -23,9 +22,9 @@ Classifier: Programming Language :: Python :: 3.14
|
|
|
23
22
|
Requires-Python: >= 3.9
|
|
24
23
|
License-File: LICENSE
|
|
25
24
|
License-File: NOTICE
|
|
26
|
-
Requires-Dist: botocore<1.
|
|
25
|
+
Requires-Dist: botocore<1.43.0,>=1.42.22
|
|
27
26
|
Requires-Dist: jmespath<2.0.0,>=0.7.1
|
|
28
|
-
Requires-Dist: s3transfer<0.
|
|
27
|
+
Requires-Dist: s3transfer<0.17.0,>=0.16.0
|
|
29
28
|
Provides-Extra: crt
|
|
30
29
|
Requires-Dist: botocore[crt]<2.0a0,>=1.21.0; extra == "crt"
|
|
31
30
|
|
|
@@ -48,10 +47,16 @@ Boto (pronounced boh-toh) was named after the fresh water dolphin native to the
|
|
|
48
47
|
Notices
|
|
49
48
|
-------
|
|
50
49
|
|
|
50
|
+
On 2026-04-29, support for Python 3.9 will end for Boto3. This follows the
|
|
51
|
+
Python Software Foundation `end of support <https://peps.python.org/pep-0596/#lifespan>`__
|
|
52
|
+
for the runtime which occurred on 2025-10-31.
|
|
53
|
+
|
|
51
54
|
On 2025-04-22, support for Python 3.8 ended for Boto3. This follows the
|
|
52
55
|
Python Software Foundation `end of support <https://peps.python.org/pep-0569/#lifespan>`__
|
|
53
56
|
for the runtime which occurred on 2024-10-07.
|
|
54
|
-
|
|
57
|
+
|
|
58
|
+
For more information on deprecations, see this
|
|
59
|
+
`blog post <https://aws.amazon.com/blogs/developer/python-support-policy-updates-for-aws-sdks-and-tools/>`__.
|
|
55
60
|
|
|
56
61
|
.. _boto: https://docs.pythonboto.org/
|
|
57
62
|
.. _`doc site`: https://boto3.amazonaws.com/v1/documentation/api/latest/index.html
|
|
@@ -110,7 +115,7 @@ Then, set up a default region (in e.g. ``~/.aws/config``):
|
|
|
110
115
|
.. code-block:: ini
|
|
111
116
|
|
|
112
117
|
[default]
|
|
113
|
-
region=us-east-1
|
|
118
|
+
region = us-east-1
|
|
114
119
|
|
|
115
120
|
Other credential configuration methods can be found `here <https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html>`__
|
|
116
121
|
|
|
@@ -17,10 +17,16 @@ Boto (pronounced boh-toh) was named after the fresh water dolphin native to the
|
|
|
17
17
|
Notices
|
|
18
18
|
-------
|
|
19
19
|
|
|
20
|
+
On 2026-04-29, support for Python 3.9 will end for Boto3. This follows the
|
|
21
|
+
Python Software Foundation `end of support <https://peps.python.org/pep-0596/#lifespan>`__
|
|
22
|
+
for the runtime which occurred on 2025-10-31.
|
|
23
|
+
|
|
20
24
|
On 2025-04-22, support for Python 3.8 ended for Boto3. This follows the
|
|
21
25
|
Python Software Foundation `end of support <https://peps.python.org/pep-0569/#lifespan>`__
|
|
22
26
|
for the runtime which occurred on 2024-10-07.
|
|
23
|
-
|
|
27
|
+
|
|
28
|
+
For more information on deprecations, see this
|
|
29
|
+
`blog post <https://aws.amazon.com/blogs/developer/python-support-policy-updates-for-aws-sdks-and-tools/>`__.
|
|
24
30
|
|
|
25
31
|
.. _boto: https://docs.pythonboto.org/
|
|
26
32
|
.. _`doc site`: https://boto3.amazonaws.com/v1/documentation/api/latest/index.html
|
|
@@ -79,7 +85,7 @@ Then, set up a default region (in e.g. ``~/.aws/config``):
|
|
|
79
85
|
.. code-block:: ini
|
|
80
86
|
|
|
81
87
|
[default]
|
|
82
|
-
region=us-east-1
|
|
88
|
+
region = us-east-1
|
|
83
89
|
|
|
84
90
|
Other credential configuration methods can be found `here <https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html>`__
|
|
85
91
|
|
|
@@ -18,6 +18,8 @@ import warnings
|
|
|
18
18
|
|
|
19
19
|
from boto3.exceptions import PythonDeprecationWarning
|
|
20
20
|
|
|
21
|
+
from s3transfer.manager import TransferConfig
|
|
22
|
+
|
|
21
23
|
# In python3, socket.error is OSError, which is too general
|
|
22
24
|
# for what we want (i.e FileNotFoundError is a subclass of OSError).
|
|
23
25
|
# In py3 all the socket related errors are in a newly created
|
|
@@ -29,6 +31,9 @@ _APPEND_MODE_CHAR = 'a'
|
|
|
29
31
|
import collections.abc as collections_abc
|
|
30
32
|
|
|
31
33
|
|
|
34
|
+
TRANSFER_CONFIG_SUPPORTS_CRT = hasattr(TransferConfig, 'UNSET_DEFAULT')
|
|
35
|
+
|
|
36
|
+
|
|
32
37
|
if sys.platform.startswith('win'):
|
|
33
38
|
def rename_file(current_filename, new_filename):
|
|
34
39
|
try:
|
|
@@ -60,8 +65,8 @@ def filter_python_deprecation_warnings():
|
|
|
60
65
|
|
|
61
66
|
def _warn_deprecated_python():
|
|
62
67
|
"""Use this template for future deprecation campaigns as needed."""
|
|
63
|
-
|
|
64
|
-
'date': '
|
|
68
|
+
py_39_params = {
|
|
69
|
+
'date': 'April 29, 2026',
|
|
65
70
|
'blog_link': (
|
|
66
71
|
'https://aws.amazon.com/blogs/developer/'
|
|
67
72
|
'python-support-policy-updates-for-aws-sdks-and-tools/'
|
|
@@ -69,7 +74,7 @@ def _warn_deprecated_python():
|
|
|
69
74
|
}
|
|
70
75
|
deprecated_versions = {
|
|
71
76
|
# Example template for future deprecations
|
|
72
|
-
(3,
|
|
77
|
+
(3, 9): py_39_params,
|
|
73
78
|
}
|
|
74
79
|
py_version = sys.version_info[:2]
|
|
75
80
|
|
|
@@ -78,7 +83,7 @@ def _warn_deprecated_python():
|
|
|
78
83
|
warning = (
|
|
79
84
|
"Boto3 will no longer support Python {}.{} "
|
|
80
85
|
"starting {}. To continue receiving service updates, "
|
|
81
|
-
"bug fixes, and security updates please upgrade to Python 3.
|
|
86
|
+
"bug fixes, and security updates please upgrade to Python 3.10 or "
|
|
82
87
|
"later. More information can be found here: {}"
|
|
83
88
|
).format(py_version[0], py_version[1], params['date'], params['blog_link'])
|
|
84
89
|
warnings.warn(warning, PythonDeprecationWarning)
|
|
@@ -19,6 +19,7 @@ project and is not intended for external consumption. All interfaces
|
|
|
19
19
|
contained within are subject to abrupt breaking changes.
|
|
20
20
|
"""
|
|
21
21
|
|
|
22
|
+
import logging
|
|
22
23
|
import threading
|
|
23
24
|
|
|
24
25
|
import botocore.exceptions
|
|
@@ -31,6 +32,12 @@ from s3transfer.crt import (
|
|
|
31
32
|
create_s3_crt_client,
|
|
32
33
|
)
|
|
33
34
|
|
|
35
|
+
from boto3.compat import TRANSFER_CONFIG_SUPPORTS_CRT
|
|
36
|
+
from boto3.exceptions import InvalidCrtTransferConfigError
|
|
37
|
+
from boto3.s3.constants import CRT_TRANSFER_CLIENT
|
|
38
|
+
|
|
39
|
+
logger = logging.getLogger(__name__)
|
|
40
|
+
|
|
34
41
|
# Singletons for CRT-backed transfers
|
|
35
42
|
CRT_S3_CLIENT = None
|
|
36
43
|
BOTOCORE_CRT_SERIALIZER = None
|
|
@@ -39,6 +46,15 @@ CLIENT_CREATION_LOCK = threading.Lock()
|
|
|
39
46
|
PROCESS_LOCK_NAME = 'boto3'
|
|
40
47
|
|
|
41
48
|
|
|
49
|
+
_ALLOWED_CRT_TRANSFER_CONFIG_OPTIONS = {
|
|
50
|
+
'multipart_threshold',
|
|
51
|
+
'max_concurrency',
|
|
52
|
+
'max_request_concurrency',
|
|
53
|
+
'multipart_chunksize',
|
|
54
|
+
'preferred_transfer_client',
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
|
|
42
58
|
def _create_crt_client(session, config, region_name, cred_provider):
|
|
43
59
|
"""Create a CRT S3 Client for file transfer.
|
|
44
60
|
|
|
@@ -157,11 +173,45 @@ def compare_identity(boto3_creds, crt_s3_creds):
|
|
|
157
173
|
return is_matching_identity
|
|
158
174
|
|
|
159
175
|
|
|
176
|
+
def _validate_crt_transfer_config(config):
|
|
177
|
+
if config is None:
|
|
178
|
+
return
|
|
179
|
+
# CRT client can also be configured via `AUTO_RESOLVE_TRANSFER_CLIENT`
|
|
180
|
+
# but it predates this validation. We only validate against CRT client
|
|
181
|
+
# configured via `CRT_TRANSFER_CLIENT` to preserve compatibility.
|
|
182
|
+
if config.preferred_transfer_client != CRT_TRANSFER_CLIENT:
|
|
183
|
+
return
|
|
184
|
+
invalid_crt_args = []
|
|
185
|
+
for param in config.DEFAULTS.keys():
|
|
186
|
+
val = config.get_deep_attr(param)
|
|
187
|
+
if (
|
|
188
|
+
param not in _ALLOWED_CRT_TRANSFER_CONFIG_OPTIONS
|
|
189
|
+
and val is not config.UNSET_DEFAULT
|
|
190
|
+
):
|
|
191
|
+
invalid_crt_args.append(param)
|
|
192
|
+
if len(invalid_crt_args) > 0:
|
|
193
|
+
raise InvalidCrtTransferConfigError(
|
|
194
|
+
"The following transfer config options are invalid "
|
|
195
|
+
"when preferred_transfer_client is set to crt: "
|
|
196
|
+
f"{', '.join(invalid_crt_args)}`"
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
|
|
160
200
|
def create_crt_transfer_manager(client, config):
|
|
161
201
|
"""Create a CRTTransferManager for optimized data transfer."""
|
|
162
202
|
crt_s3_client = get_crt_s3_client(client, config)
|
|
163
203
|
if is_crt_compatible_request(client, crt_s3_client):
|
|
164
|
-
|
|
165
|
-
crt_s3_client.crt_client,
|
|
166
|
-
|
|
204
|
+
crt_transfer_manager_kwargs = {
|
|
205
|
+
'crt_s3_client': crt_s3_client.crt_client,
|
|
206
|
+
'crt_request_serializer': BOTOCORE_CRT_SERIALIZER,
|
|
207
|
+
}
|
|
208
|
+
if TRANSFER_CONFIG_SUPPORTS_CRT:
|
|
209
|
+
_validate_crt_transfer_config(config)
|
|
210
|
+
crt_transfer_manager_kwargs['config'] = config
|
|
211
|
+
if not TRANSFER_CONFIG_SUPPORTS_CRT and config:
|
|
212
|
+
logger.warning(
|
|
213
|
+
'Using TransferConfig with CRT client requires '
|
|
214
|
+
's3transfer >= 0.16.0, configured values will be ignored.'
|
|
215
|
+
)
|
|
216
|
+
return CRTTransferManager(**crt_transfer_manager_kwargs)
|
|
167
217
|
return None
|
|
@@ -45,7 +45,7 @@ def generate_docs(root_dir, session):
|
|
|
45
45
|
service_name, session, services_doc_path
|
|
46
46
|
).document_service()
|
|
47
47
|
service_doc_path = os.path.join(
|
|
48
|
-
services_doc_path, service_name
|
|
48
|
+
services_doc_path, f"{service_name}.rst"
|
|
49
49
|
)
|
|
50
50
|
with open(service_doc_path, 'wb') as f:
|
|
51
51
|
f.write(docs)
|
|
@@ -190,7 +190,7 @@ class ServiceDocumenter(BaseServiceDocumenter):
|
|
|
190
190
|
|
|
191
191
|
def _get_example_file(self):
|
|
192
192
|
return os.path.realpath(
|
|
193
|
-
os.path.join(self.EXAMPLE_PATH, self._service_name
|
|
193
|
+
os.path.join(self.EXAMPLE_PATH, f"{self._service_name}.rst")
|
|
194
194
|
)
|
|
195
195
|
|
|
196
196
|
def _document_examples(self, section):
|
|
@@ -311,10 +311,10 @@ class ConditionExpressionBuilder:
|
|
|
311
311
|
self._value_placeholder = 'v'
|
|
312
312
|
|
|
313
313
|
def _get_name_placeholder(self):
|
|
314
|
-
return
|
|
314
|
+
return f"#{self._name_placeholder}{self._name_count}"
|
|
315
315
|
|
|
316
316
|
def _get_value_placeholder(self):
|
|
317
|
-
return
|
|
317
|
+
return f":{self._value_placeholder}{self._value_count}"
|
|
318
318
|
|
|
319
319
|
def reset(self):
|
|
320
320
|
"""Resets the placeholder name and values"""
|
|
@@ -451,7 +451,7 @@ class ConditionExpressionBuilder:
|
|
|
451
451
|
# Assuming the values are grouped by parenthesis.
|
|
452
452
|
# IN is the currently the only one that uses this so it maybe
|
|
453
453
|
# needed to be changed in future.
|
|
454
|
-
return
|
|
454
|
+
return f"({', '.join(placeholder_list)})"
|
|
455
455
|
# Otherwise, treat the value as a single value that needs only
|
|
456
456
|
# one placeholder.
|
|
457
457
|
else:
|
|
@@ -104,7 +104,7 @@ class ServiceResource:
|
|
|
104
104
|
# Allow setting identifiers as positional arguments in the order
|
|
105
105
|
# in which they were defined in the ResourceJSON.
|
|
106
106
|
for i, value in enumerate(args):
|
|
107
|
-
setattr(self,
|
|
107
|
+
setattr(self, f"_{self.meta.identifiers[i]}", value)
|
|
108
108
|
|
|
109
109
|
# Allow setting identifiers via keyword arguments. Here we need
|
|
110
110
|
# extra logic to ignore other keyword arguments like ``client``.
|
|
@@ -115,7 +115,7 @@ class ServiceResource:
|
|
|
115
115
|
if name not in self.meta.identifiers:
|
|
116
116
|
raise ValueError(f'Unknown keyword argument: {name}')
|
|
117
117
|
|
|
118
|
-
setattr(self,
|
|
118
|
+
setattr(self, f"_{name}", value)
|
|
119
119
|
|
|
120
120
|
# Validate that all identifiers have been set.
|
|
121
121
|
for identifier in self.meta.identifiers:
|
|
@@ -123,15 +123,11 @@ class ServiceResource:
|
|
|
123
123
|
raise ValueError(f'Required parameter {identifier} not set')
|
|
124
124
|
|
|
125
125
|
def __repr__(self):
|
|
126
|
-
identifiers = [
|
|
127
|
-
|
|
128
|
-
identifiers
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
return "{}({})".format(
|
|
132
|
-
self.__class__.__name__,
|
|
133
|
-
', '.join(identifiers),
|
|
134
|
-
)
|
|
126
|
+
identifiers = [
|
|
127
|
+
f'{identifier}={repr(getattr(self, identifier))}'
|
|
128
|
+
for identifier in self.meta.identifiers
|
|
129
|
+
]
|
|
130
|
+
return f"{self.__class__.__name__}({', '.join(identifiers)})"
|
|
135
131
|
|
|
136
132
|
def __eq__(self, other):
|
|
137
133
|
# Should be instances of the same resource class
|
|
@@ -145,7 +145,7 @@ class ResourceFactory:
|
|
|
145
145
|
cls_name = resource_name
|
|
146
146
|
if service_context.service_name == resource_name:
|
|
147
147
|
cls_name = 'ServiceResource'
|
|
148
|
-
cls_name = service_context.service_name
|
|
148
|
+
cls_name = f"{service_context.service_name}.{cls_name}"
|
|
149
149
|
|
|
150
150
|
base_classes = [ServiceResource]
|
|
151
151
|
if self._emitter is not None:
|
|
@@ -325,7 +325,7 @@ class ResourceFactory:
|
|
|
325
325
|
# identifiers have a value ``None``. If any are ``None``,
|
|
326
326
|
# a more informative user error than a generic AttributeError
|
|
327
327
|
# is raised.
|
|
328
|
-
return getattr(self,
|
|
328
|
+
return getattr(self, f"_{identifier.name}", None)
|
|
329
329
|
|
|
330
330
|
get_identifier.__name__ = str(identifier.name)
|
|
331
331
|
get_identifier.__doc__ = docstring.IdentifierDocstring(
|
|
@@ -344,7 +344,7 @@ class ResourceFactory:
|
|
|
344
344
|
"""
|
|
345
345
|
|
|
346
346
|
def get_identifier(self):
|
|
347
|
-
return getattr(self,
|
|
347
|
+
return getattr(self, f"_{identifier.name}", None)
|
|
348
348
|
|
|
349
349
|
get_identifier.__name__ = str(identifier.member_name)
|
|
350
350
|
get_identifier.__doc__ = docstring.AttributeDocstring(
|
|
@@ -366,9 +366,9 @@ class ResourceModel:
|
|
|
366
366
|
name = xform_name(name)
|
|
367
367
|
|
|
368
368
|
if name in names:
|
|
369
|
-
logger.debug(
|
|
370
|
-
self._renamed[(category, name)] = name
|
|
371
|
-
name +=
|
|
369
|
+
logger.debug('Renaming %s %s %s', self.name, category, name)
|
|
370
|
+
self._renamed[(category, name)] = f"{name}_{category}"
|
|
371
|
+
name += f"_{category}"
|
|
372
372
|
|
|
373
373
|
if name in names:
|
|
374
374
|
# This isn't good, let's raise instead of trying to keep
|
|
@@ -132,7 +132,7 @@ def build_param_structure(params, target, value, index=None):
|
|
|
132
132
|
else:
|
|
133
133
|
# We have an explicit index
|
|
134
134
|
index = int(result.group(1))
|
|
135
|
-
part = part[: -len(
|
|
135
|
+
part = part[: -len(f"{index}[]")]
|
|
136
136
|
else:
|
|
137
137
|
# Index will be set after we know the proper part
|
|
138
138
|
# name and that it's a list instance.
|
|
@@ -128,7 +128,7 @@ import threading
|
|
|
128
128
|
from os import PathLike, fspath, getpid
|
|
129
129
|
|
|
130
130
|
from botocore.compat import HAS_CRT
|
|
131
|
-
from botocore.exceptions import ClientError
|
|
131
|
+
from botocore.exceptions import ClientError, MissingDependencyException
|
|
132
132
|
from s3transfer.exceptions import (
|
|
133
133
|
RetriesExceededError as S3TransferRetriesExceededError,
|
|
134
134
|
)
|
|
@@ -139,7 +139,11 @@ from s3transfer.subscribers import BaseSubscriber
|
|
|
139
139
|
from s3transfer.utils import OSUtils
|
|
140
140
|
|
|
141
141
|
import boto3.s3.constants as constants
|
|
142
|
-
from boto3.
|
|
142
|
+
from boto3.compat import TRANSFER_CONFIG_SUPPORTS_CRT
|
|
143
|
+
from boto3.exceptions import (
|
|
144
|
+
RetriesExceededError,
|
|
145
|
+
S3UploadFailedError,
|
|
146
|
+
)
|
|
143
147
|
|
|
144
148
|
if HAS_CRT:
|
|
145
149
|
import awscrt.s3
|
|
@@ -171,38 +175,54 @@ def create_transfer_manager(client, config, osutil=None):
|
|
|
171
175
|
crt_transfer_manager = create_crt_transfer_manager(client, config)
|
|
172
176
|
if crt_transfer_manager is not None:
|
|
173
177
|
logger.debug(
|
|
174
|
-
|
|
178
|
+
"Using CRT client. pid: %s, thread: %s",
|
|
179
|
+
getpid(),
|
|
180
|
+
threading.get_ident(),
|
|
175
181
|
)
|
|
176
182
|
return crt_transfer_manager
|
|
177
183
|
|
|
178
184
|
# If we don't resolve something above, fallback to the default.
|
|
179
185
|
logger.debug(
|
|
180
|
-
|
|
186
|
+
"Using default client. pid: %s, thread: %s",
|
|
187
|
+
getpid(),
|
|
188
|
+
threading.get_ident(),
|
|
181
189
|
)
|
|
182
190
|
return _create_default_transfer_manager(client, config, osutil)
|
|
183
191
|
|
|
184
192
|
|
|
185
193
|
def _should_use_crt(config):
|
|
186
194
|
# This feature requires awscrt>=0.19.18
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
else:
|
|
190
|
-
is_optimized_instance = False
|
|
195
|
+
has_min_crt = HAS_CRT and has_minimum_crt_version((0, 19, 18))
|
|
196
|
+
is_optimized_instance = has_min_crt and awscrt.s3.is_optimized_for_system()
|
|
191
197
|
pref_transfer_client = config.preferred_transfer_client.lower()
|
|
192
198
|
|
|
199
|
+
if (
|
|
200
|
+
pref_transfer_client == constants.CRT_TRANSFER_CLIENT
|
|
201
|
+
and not has_min_crt
|
|
202
|
+
):
|
|
203
|
+
msg = (
|
|
204
|
+
"CRT transfer client is configured but is missing minimum CRT "
|
|
205
|
+
f"version. CRT installed: {HAS_CRT}"
|
|
206
|
+
)
|
|
207
|
+
if HAS_CRT:
|
|
208
|
+
msg += f", with version: {awscrt.__version__}"
|
|
209
|
+
raise MissingDependencyException(msg=msg)
|
|
210
|
+
|
|
193
211
|
if (
|
|
194
212
|
is_optimized_instance
|
|
195
213
|
and pref_transfer_client == constants.AUTO_RESOLVE_TRANSFER_CLIENT
|
|
196
|
-
):
|
|
214
|
+
) or pref_transfer_client == constants.CRT_TRANSFER_CLIENT:
|
|
197
215
|
logger.debug(
|
|
198
216
|
"Attempting to use CRTTransferManager. Config settings may be ignored."
|
|
199
217
|
)
|
|
200
218
|
return True
|
|
201
219
|
|
|
202
220
|
logger.debug(
|
|
203
|
-
"Opting out of CRT Transfer Manager.
|
|
204
|
-
|
|
205
|
-
|
|
221
|
+
"Opting out of CRT Transfer Manager. "
|
|
222
|
+
"Preferred client: %s, CRT available: %s, Instance Optimized: %s",
|
|
223
|
+
pref_transfer_client,
|
|
224
|
+
HAS_CRT,
|
|
225
|
+
is_optimized_instance,
|
|
206
226
|
)
|
|
207
227
|
return False
|
|
208
228
|
|
|
@@ -235,18 +255,31 @@ class TransferConfig(S3TransferConfig):
|
|
|
235
255
|
'max_concurrency': 'max_request_concurrency',
|
|
236
256
|
'max_io_queue': 'max_io_queue_size',
|
|
237
257
|
}
|
|
258
|
+
DEFAULTS = {
|
|
259
|
+
'multipart_threshold': 8 * MB,
|
|
260
|
+
'max_concurrency': 10,
|
|
261
|
+
'max_request_concurrency': 10,
|
|
262
|
+
'multipart_chunksize': 8 * MB,
|
|
263
|
+
'num_download_attempts': 5,
|
|
264
|
+
'max_io_queue': 100,
|
|
265
|
+
'max_io_queue_size': 100,
|
|
266
|
+
'io_chunksize': 256 * KB,
|
|
267
|
+
'use_threads': True,
|
|
268
|
+
'max_bandwidth': None,
|
|
269
|
+
'preferred_transfer_client': constants.AUTO_RESOLVE_TRANSFER_CLIENT,
|
|
270
|
+
}
|
|
238
271
|
|
|
239
272
|
def __init__(
|
|
240
273
|
self,
|
|
241
|
-
multipart_threshold=
|
|
242
|
-
max_concurrency=
|
|
243
|
-
multipart_chunksize=
|
|
244
|
-
num_download_attempts=
|
|
245
|
-
max_io_queue=
|
|
246
|
-
io_chunksize=
|
|
247
|
-
use_threads=
|
|
274
|
+
multipart_threshold=None,
|
|
275
|
+
max_concurrency=None,
|
|
276
|
+
multipart_chunksize=None,
|
|
277
|
+
num_download_attempts=None,
|
|
278
|
+
max_io_queue=None,
|
|
279
|
+
io_chunksize=None,
|
|
280
|
+
use_threads=None,
|
|
248
281
|
max_bandwidth=None,
|
|
249
|
-
preferred_transfer_client=
|
|
282
|
+
preferred_transfer_client=None,
|
|
250
283
|
):
|
|
251
284
|
"""Configuration object for managed S3 transfers
|
|
252
285
|
|
|
@@ -270,23 +303,30 @@ class TransferConfig(S3TransferConfig):
|
|
|
270
303
|
Other retryable exceptions such as throttling errors and 5xx
|
|
271
304
|
errors are already retried by botocore (this default is 5). This
|
|
272
305
|
does not take into account the number of exceptions retried by
|
|
273
|
-
botocore.
|
|
306
|
+
botocore. Note: This value is ignored when resolved transfer
|
|
307
|
+
manager type is CRTTransferManager.
|
|
274
308
|
|
|
275
309
|
:param max_io_queue: The maximum amount of read parts that can be
|
|
276
310
|
queued in memory to be written for a download. The size of each
|
|
277
311
|
of these read parts is at most the size of ``io_chunksize``.
|
|
312
|
+
Note: This value is ignored when resolved transfer manager type
|
|
313
|
+
is CRTTransferManager.
|
|
278
314
|
|
|
279
315
|
:param io_chunksize: The max size of each chunk in the io queue.
|
|
280
316
|
Currently, this is size used when ``read`` is called on the
|
|
281
|
-
downloaded stream as well.
|
|
317
|
+
downloaded stream as well. Note: This value is ignored when
|
|
318
|
+
resolved transfer manager type is CRTTransferManager.
|
|
282
319
|
|
|
283
320
|
:param use_threads: If True, threads will be used when performing
|
|
284
321
|
S3 transfers. If False, no threads will be used in
|
|
285
322
|
performing transfers; all logic will be run in the current thread.
|
|
323
|
+
Note: This value is ignored when resolved transfer manager type is
|
|
324
|
+
CRTTransferManager.
|
|
286
325
|
|
|
287
326
|
:param max_bandwidth: The maximum bandwidth that will be consumed
|
|
288
327
|
in uploading and downloading file content. The value is an integer
|
|
289
|
-
in terms of bytes per second.
|
|
328
|
+
in terms of bytes per second. Note: This value is ignored when
|
|
329
|
+
resolved transfer manager type is CRTTransferManager.
|
|
290
330
|
|
|
291
331
|
:param preferred_transfer_client: String specifying preferred transfer
|
|
292
332
|
client for transfer operations.
|
|
@@ -296,23 +336,40 @@ class TransferConfig(S3TransferConfig):
|
|
|
296
336
|
are made with supported environment and settings.
|
|
297
337
|
* classic - Only use the origin S3TransferManager with
|
|
298
338
|
requests. Disables possible CRT upgrade on requests.
|
|
339
|
+
* crt - Only use the CRTTransferManager with requests.
|
|
299
340
|
"""
|
|
341
|
+
init_args = {
|
|
342
|
+
'multipart_threshold': multipart_threshold,
|
|
343
|
+
'max_concurrency': max_concurrency,
|
|
344
|
+
'multipart_chunksize': multipart_chunksize,
|
|
345
|
+
'num_download_attempts': num_download_attempts,
|
|
346
|
+
'max_io_queue': max_io_queue,
|
|
347
|
+
'io_chunksize': io_chunksize,
|
|
348
|
+
'use_threads': use_threads,
|
|
349
|
+
'max_bandwidth': max_bandwidth,
|
|
350
|
+
'preferred_transfer_client': preferred_transfer_client,
|
|
351
|
+
}
|
|
352
|
+
resolved = self._resolve_init_args(init_args)
|
|
300
353
|
super().__init__(
|
|
301
|
-
multipart_threshold=multipart_threshold,
|
|
302
|
-
max_request_concurrency=max_concurrency,
|
|
303
|
-
multipart_chunksize=multipart_chunksize,
|
|
304
|
-
num_download_attempts=num_download_attempts,
|
|
305
|
-
max_io_queue_size=max_io_queue,
|
|
306
|
-
io_chunksize=io_chunksize,
|
|
307
|
-
max_bandwidth=max_bandwidth,
|
|
354
|
+
multipart_threshold=resolved['multipart_threshold'],
|
|
355
|
+
max_request_concurrency=resolved['max_concurrency'],
|
|
356
|
+
multipart_chunksize=resolved['multipart_chunksize'],
|
|
357
|
+
num_download_attempts=resolved['num_download_attempts'],
|
|
358
|
+
max_io_queue_size=resolved['max_io_queue'],
|
|
359
|
+
io_chunksize=resolved['io_chunksize'],
|
|
360
|
+
max_bandwidth=resolved['max_bandwidth'],
|
|
308
361
|
)
|
|
309
362
|
# Some of the argument names are not the same as the inherited
|
|
310
363
|
# S3TransferConfig so we add aliases so you can still access the
|
|
311
364
|
# old version of the names.
|
|
312
365
|
for alias in self.ALIAS:
|
|
313
|
-
setattr(
|
|
314
|
-
|
|
315
|
-
|
|
366
|
+
setattr(
|
|
367
|
+
self,
|
|
368
|
+
alias,
|
|
369
|
+
object.__getattribute__(self, self.ALIAS[alias]),
|
|
370
|
+
)
|
|
371
|
+
self.use_threads = resolved['use_threads']
|
|
372
|
+
self.preferred_transfer_client = resolved['preferred_transfer_client']
|
|
316
373
|
|
|
317
374
|
def __setattr__(self, name, value):
|
|
318
375
|
# If the alias name is used, make sure we set the name that it points
|
|
@@ -322,6 +379,28 @@ class TransferConfig(S3TransferConfig):
|
|
|
322
379
|
# Always set the value of the actual name provided.
|
|
323
380
|
super().__setattr__(name, value)
|
|
324
381
|
|
|
382
|
+
def __getattribute__(self, item):
|
|
383
|
+
value = object.__getattribute__(self, item)
|
|
384
|
+
if not TRANSFER_CONFIG_SUPPORTS_CRT:
|
|
385
|
+
return value
|
|
386
|
+
defaults = object.__getattribute__(self, 'DEFAULTS')
|
|
387
|
+
if item not in defaults:
|
|
388
|
+
return value
|
|
389
|
+
if value is self.UNSET_DEFAULT:
|
|
390
|
+
return defaults[item]
|
|
391
|
+
return value
|
|
392
|
+
|
|
393
|
+
def _resolve_init_args(self, init_args):
|
|
394
|
+
resolved = {}
|
|
395
|
+
for init_arg, val in init_args.items():
|
|
396
|
+
if val is not None:
|
|
397
|
+
resolved[init_arg] = val
|
|
398
|
+
elif TRANSFER_CONFIG_SUPPORTS_CRT:
|
|
399
|
+
resolved[init_arg] = self.UNSET_DEFAULT
|
|
400
|
+
else:
|
|
401
|
+
resolved[init_arg] = self.DEFAULTS[init_arg]
|
|
402
|
+
return resolved
|
|
403
|
+
|
|
325
404
|
|
|
326
405
|
class S3Transfer:
|
|
327
406
|
ALLOWED_DOWNLOAD_ARGS = TransferManager.ALLOWED_DOWNLOAD_ARGS
|
|
@@ -377,9 +456,7 @@ class S3Transfer:
|
|
|
377
456
|
# client error.
|
|
378
457
|
except ClientError as e:
|
|
379
458
|
raise S3UploadFailedError(
|
|
380
|
-
"Failed to upload {} to {}: {}"
|
|
381
|
-
filename, '/'.join([bucket, key]), e
|
|
382
|
-
)
|
|
459
|
+
f"Failed to upload {filename} to {bucket}/{key}: {e}"
|
|
383
460
|
)
|
|
384
461
|
|
|
385
462
|
def download_file(
|
|
@@ -72,7 +72,7 @@ class Session:
|
|
|
72
72
|
if self._session.user_agent_name == 'Botocore':
|
|
73
73
|
botocore_info = f'Botocore/{self._session.user_agent_version}'
|
|
74
74
|
if self._session.user_agent_extra:
|
|
75
|
-
self._session.user_agent_extra +=
|
|
75
|
+
self._session.user_agent_extra += f" {botocore_info}"
|
|
76
76
|
else:
|
|
77
77
|
self._session.user_agent_extra = botocore_info
|
|
78
78
|
self._session.user_agent_name = 'Boto3'
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
|
11
11
|
# ANY KIND, either express or implied. See the License for the specific
|
|
12
12
|
# language governing permissions and limitations under the License.
|
|
13
|
-
import sys
|
|
14
13
|
from collections import namedtuple
|
|
14
|
+
from importlib import import_module
|
|
15
15
|
|
|
16
16
|
_ServiceContext = namedtuple(
|
|
17
17
|
'ServiceContext',
|
|
@@ -47,16 +47,6 @@ class ServiceContext(_ServiceContext):
|
|
|
47
47
|
pass
|
|
48
48
|
|
|
49
49
|
|
|
50
|
-
def import_module(name):
|
|
51
|
-
"""Import module given a name.
|
|
52
|
-
|
|
53
|
-
Does not support relative imports.
|
|
54
|
-
|
|
55
|
-
"""
|
|
56
|
-
__import__(name)
|
|
57
|
-
return sys.modules[name]
|
|
58
|
-
|
|
59
|
-
|
|
60
50
|
def lazy_call(full_name, **kwargs):
|
|
61
51
|
parent_kwargs = kwargs
|
|
62
52
|
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: boto3
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.42.22
|
|
4
4
|
Summary: The AWS SDK for Python
|
|
5
5
|
Home-page: https://github.com/boto/boto3
|
|
6
6
|
Author: Amazon Web Services
|
|
7
|
-
License: Apache
|
|
7
|
+
License: Apache-2.0
|
|
8
8
|
Project-URL: Documentation, https://boto3.amazonaws.com/v1/documentation/api/latest/index.html
|
|
9
9
|
Project-URL: Source, https://github.com/boto/boto3
|
|
10
10
|
Classifier: Development Status :: 5 - Production/Stable
|
|
11
11
|
Classifier: Intended Audience :: Developers
|
|
12
12
|
Classifier: Natural Language :: English
|
|
13
|
-
Classifier: License :: OSI Approved :: Apache Software License
|
|
14
13
|
Classifier: Programming Language :: Python
|
|
15
14
|
Classifier: Programming Language :: Python :: 3
|
|
16
15
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
@@ -23,9 +22,9 @@ Classifier: Programming Language :: Python :: 3.14
|
|
|
23
22
|
Requires-Python: >= 3.9
|
|
24
23
|
License-File: LICENSE
|
|
25
24
|
License-File: NOTICE
|
|
26
|
-
Requires-Dist: botocore<1.
|
|
25
|
+
Requires-Dist: botocore<1.43.0,>=1.42.22
|
|
27
26
|
Requires-Dist: jmespath<2.0.0,>=0.7.1
|
|
28
|
-
Requires-Dist: s3transfer<0.
|
|
27
|
+
Requires-Dist: s3transfer<0.17.0,>=0.16.0
|
|
29
28
|
Provides-Extra: crt
|
|
30
29
|
Requires-Dist: botocore[crt]<2.0a0,>=1.21.0; extra == "crt"
|
|
31
30
|
|
|
@@ -48,10 +47,16 @@ Boto (pronounced boh-toh) was named after the fresh water dolphin native to the
|
|
|
48
47
|
Notices
|
|
49
48
|
-------
|
|
50
49
|
|
|
50
|
+
On 2026-04-29, support for Python 3.9 will end for Boto3. This follows the
|
|
51
|
+
Python Software Foundation `end of support <https://peps.python.org/pep-0596/#lifespan>`__
|
|
52
|
+
for the runtime which occurred on 2025-10-31.
|
|
53
|
+
|
|
51
54
|
On 2025-04-22, support for Python 3.8 ended for Boto3. This follows the
|
|
52
55
|
Python Software Foundation `end of support <https://peps.python.org/pep-0569/#lifespan>`__
|
|
53
56
|
for the runtime which occurred on 2024-10-07.
|
|
54
|
-
|
|
57
|
+
|
|
58
|
+
For more information on deprecations, see this
|
|
59
|
+
`blog post <https://aws.amazon.com/blogs/developer/python-support-policy-updates-for-aws-sdks-and-tools/>`__.
|
|
55
60
|
|
|
56
61
|
.. _boto: https://docs.pythonboto.org/
|
|
57
62
|
.. _`doc site`: https://boto3.amazonaws.com/v1/documentation/api/latest/index.html
|
|
@@ -110,7 +115,7 @@ Then, set up a default region (in e.g. ``~/.aws/config``):
|
|
|
110
115
|
.. code-block:: ini
|
|
111
116
|
|
|
112
117
|
[default]
|
|
113
|
-
region=us-east-1
|
|
118
|
+
region = us-east-1
|
|
114
119
|
|
|
115
120
|
Other credential configuration methods can be found `here <https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html>`__
|
|
116
121
|
|
|
@@ -43,7 +43,15 @@ target-version = "py39"
|
|
|
43
43
|
# Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default.
|
|
44
44
|
# Unlike Flake8, Ruff doesn't enable pycodestyle warnings (`W`) or
|
|
45
45
|
# McCabe complexity (`C901`) by default.
|
|
46
|
-
select = [
|
|
46
|
+
select = [
|
|
47
|
+
"E4", # pycodestyle
|
|
48
|
+
"E7", # pycodestyle
|
|
49
|
+
"E9", # pycodestyle
|
|
50
|
+
"F", # pyflakes
|
|
51
|
+
"G", # flake8-logging-format
|
|
52
|
+
"I", # isort
|
|
53
|
+
"UP", # pyupgrade
|
|
54
|
+
]
|
|
47
55
|
ignore = []
|
|
48
56
|
|
|
49
57
|
# Allow fix for all enabled rules (when `--fix`) is provided.
|
|
@@ -14,9 +14,9 @@ VERSION_RE = re.compile(r'''__version__ = ['"]([0-9.]+)['"]''')
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
requires = [
|
|
17
|
-
'botocore>=1.
|
|
17
|
+
'botocore>=1.42.22,<1.43.0',
|
|
18
18
|
'jmespath>=0.7.1,<2.0.0',
|
|
19
|
-
's3transfer>=0.
|
|
19
|
+
's3transfer>=0.16.0,<0.17.0',
|
|
20
20
|
]
|
|
21
21
|
|
|
22
22
|
|
|
@@ -37,13 +37,12 @@ setup(
|
|
|
37
37
|
package_data={'boto3': ['data/aws/resources/*.json', 'examples/*.rst']},
|
|
38
38
|
include_package_data=True,
|
|
39
39
|
install_requires=requires,
|
|
40
|
-
license="Apache
|
|
40
|
+
license="Apache-2.0",
|
|
41
41
|
python_requires=">= 3.9",
|
|
42
42
|
classifiers=[
|
|
43
43
|
'Development Status :: 5 - Production/Stable',
|
|
44
44
|
'Intended Audience :: Developers',
|
|
45
45
|
'Natural Language :: English',
|
|
46
|
-
'License :: OSI Approved :: Apache Software License',
|
|
47
46
|
'Programming Language :: Python',
|
|
48
47
|
'Programming Language :: Python :: 3',
|
|
49
48
|
'Programming Language :: Python :: 3 :: Only',
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|