Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/boto3/session.py: 60%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

107 statements  

1# Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved. 

2# 

3# Licensed under the Apache License, Version 2.0 (the "License"). You 

4# may not use this file except in compliance with the License. A copy of 

5# the License is located at 

6# 

7# https://aws.amazon.com/apache2.0/ 

8# 

9# or in the "license" file accompanying this file. This file is 

10# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 

11# ANY KIND, either express or implied. See the License for the specific 

12# language governing permissions and limitations under the License. 

13 

14import copy 

15import os 

16 

17import botocore.session 

18from botocore.client import Config 

19from botocore.exceptions import ( 

20 DataNotFoundError, 

21 NoCredentialsError, 

22 UnknownServiceError, 

23) 

24 

25import boto3 

26import boto3.utils 

27from boto3.exceptions import ResourceNotExistsError, UnknownAPIVersionError 

28 

29from .resources.factory import ResourceFactory 

30 

31 

32class Session: 

33 """ 

34 A session stores configuration state and allows you to create service 

35 clients and resources. 

36 

37 :type aws_access_key_id: string 

38 :param aws_access_key_id: AWS access key ID 

39 :type aws_secret_access_key: string 

40 :param aws_secret_access_key: AWS secret access key 

41 :type aws_session_token: string 

42 :param aws_session_token: AWS temporary session token 

43 :type region_name: string 

44 :param region_name: Default region when creating new connections 

45 :type botocore_session: botocore.session.Session 

46 :param botocore_session: Use this Botocore session instead of creating 

47 a new default one. 

48 :type profile_name: string 

49 :param profile_name: The name of a profile to use. If not given, then 

50 the default profile is used. 

51 :type aws_account_id: string 

52 :param aws_account_id: AWS account ID 

53 """ 

54 

55 def __init__( 

56 self, 

57 aws_access_key_id=None, 

58 aws_secret_access_key=None, 

59 aws_session_token=None, 

60 region_name=None, 

61 botocore_session=None, 

62 profile_name=None, 

63 aws_account_id=None, 

64 ): 

65 if botocore_session is not None: 

66 self._session = botocore_session 

67 else: 

68 # Create a new default session 

69 self._session = botocore.session.get_session() 

70 

71 # Setup custom user-agent string if it isn't already customized 

72 if self._session.user_agent_name == 'Botocore': 

73 botocore_info = f'Botocore/{self._session.user_agent_version}' 

74 if self._session.user_agent_extra: 

75 self._session.user_agent_extra += ' ' + botocore_info 

76 else: 

77 self._session.user_agent_extra = botocore_info 

78 self._session.user_agent_name = 'Boto3' 

79 self._session.user_agent_version = boto3.__version__ 

80 

81 if profile_name is not None: 

82 self._session.set_config_variable('profile', profile_name) 

83 

84 credentials_kwargs = { 

85 "aws_access_key_id": aws_access_key_id, 

86 "aws_secret_access_key": aws_secret_access_key, 

87 "aws_session_token": aws_session_token, 

88 "aws_account_id": aws_account_id, 

89 } 

90 

91 if any(credentials_kwargs.values()): 

92 if self._account_id_set_without_credentials(**credentials_kwargs): 

93 raise NoCredentialsError() 

94 

95 if aws_account_id is None: 

96 del credentials_kwargs["aws_account_id"] 

97 

98 self._session.set_credentials(*credentials_kwargs.values()) 

99 

100 if region_name is not None: 

101 self._session.set_config_variable('region', region_name) 

102 

103 self.resource_factory = ResourceFactory( 

104 self._session.get_component('event_emitter') 

105 ) 

106 self._setup_loader() 

107 self._register_default_handlers() 

108 

109 def __repr__(self): 

110 return '{}(region_name={})'.format( 

111 self.__class__.__name__, 

112 repr(self._session.get_config_variable('region')), 

113 ) 

114 

115 @property 

116 def profile_name(self): 

117 """ 

118 The **read-only** profile name. 

119 """ 

120 return self._session.profile or 'default' 

121 

122 @property 

123 def region_name(self): 

124 """ 

125 The **read-only** region name. 

126 """ 

127 return self._session.get_config_variable('region') 

128 

129 @property 

130 def events(self): 

131 """ 

132 The event emitter for a session 

133 """ 

134 return self._session.get_component('event_emitter') 

135 

136 @property 

137 def available_profiles(self): 

138 """ 

139 The profiles available to the session credentials 

140 """ 

141 return self._session.available_profiles 

142 

143 def _setup_loader(self): 

144 """ 

145 Setup loader paths so that we can load resources. 

146 """ 

147 self._loader = self._session.get_component('data_loader') 

148 self._loader.search_paths.append( 

149 os.path.join(os.path.dirname(__file__), 'data') 

150 ) 

151 

152 def get_available_services(self): 

153 """ 

154 Get a list of available services that can be loaded as low-level 

155 clients via :py:meth:`Session.client`. 

156 

157 :rtype: list 

158 :return: List of service names 

159 """ 

160 return self._session.get_available_services() 

161 

162 def get_available_resources(self): 

163 """ 

164 Get a list of available services that can be loaded as resource 

165 clients via :py:meth:`Session.resource`. 

166 

167 :rtype: list 

168 :return: List of service names 

169 """ 

170 return self._loader.list_available_services(type_name='resources-1') 

171 

172 def get_available_partitions(self): 

173 """Lists the available partitions 

174 

175 :rtype: list 

176 :return: Returns a list of partition names (e.g., ["aws", "aws-cn"]) 

177 """ 

178 return self._session.get_available_partitions() 

179 

180 def get_available_regions( 

181 self, service_name, partition_name='aws', allow_non_regional=False 

182 ): 

183 """Lists the region and endpoint names of a particular partition. 

184 

185 The list of regions returned by this method are regions that are 

186 explicitly known by the client to exist and is not comprehensive. A 

187 region not returned in this list may still be available for the 

188 provided service. 

189 

190 :type service_name: string 

191 :param service_name: Name of a service to list endpoint for (e.g., s3). 

192 

193 :type partition_name: string 

194 :param partition_name: Name of the partition to limit endpoints to. 

195 (e.g., aws for the public AWS endpoints, aws-cn for AWS China 

196 endpoints, aws-us-gov for AWS GovCloud (US) Endpoints, etc.) 

197 

198 :type allow_non_regional: bool 

199 :param allow_non_regional: Set to True to include endpoints that are 

200 not regional endpoints (e.g., s3-external-1, 

201 fips-us-gov-west-1, etc). 

202 

203 :return: Returns a list of endpoint names (e.g., ["us-east-1"]). 

204 """ 

205 return self._session.get_available_regions( 

206 service_name=service_name, 

207 partition_name=partition_name, 

208 allow_non_regional=allow_non_regional, 

209 ) 

210 

211 def get_credentials(self): 

212 """ 

213 Return the :class:`botocore.credentials.Credentials` object 

214 associated with this session. If the credentials have not 

215 yet been loaded, this will attempt to load them. If they 

216 have already been loaded, this will return the cached 

217 credentials. 

218 """ 

219 return self._session.get_credentials() 

220 

221 def get_partition_for_region(self, region_name): 

222 """Lists the partition name of a particular region. 

223 

224 :type region_name: string 

225 :param region_name: Name of the region to list partition for (e.g., 

226 us-east-1). 

227 

228 :rtype: string 

229 :return: Returns the respective partition name (e.g., aws). 

230 """ 

231 return self._session.get_partition_for_region(region_name) 

232 

233 def client( 

234 self, 

235 service_name, 

236 region_name=None, 

237 api_version=None, 

238 use_ssl=True, 

239 verify=None, 

240 endpoint_url=None, 

241 aws_access_key_id=None, 

242 aws_secret_access_key=None, 

243 aws_session_token=None, 

244 config=None, 

245 aws_account_id=None, 

246 ): 

247 """ 

248 Create a low-level service client by name. 

249 

250 :type service_name: string 

251 :param service_name: The name of a service, e.g. 's3' or 'ec2'. You 

252 can get a list of available services via 

253 :py:meth:`get_available_services`. 

254 

255 :type region_name: string 

256 :param region_name: The name of the region associated with the client. 

257 A client is associated with a single region. 

258 

259 :type api_version: string 

260 :param api_version: The API version to use. By default, botocore will 

261 use the latest API version when creating a client. You only need 

262 to specify this parameter if you want to use a previous API version 

263 of the client. 

264 

265 :type use_ssl: boolean 

266 :param use_ssl: Whether or not to use SSL. By default, SSL is used. 

267 Note that not all services support non-ssl connections. 

268 

269 :type verify: boolean/string 

270 :param verify: Whether or not to verify SSL certificates. By default 

271 SSL certificates are verified. You can provide the following 

272 values: 

273 

274 * False - do not validate SSL certificates. SSL will still be 

275 used (unless use_ssl is False), but SSL certificates 

276 will not be verified. 

277 * path/to/cert/bundle.pem - A filename of the CA cert bundle to 

278 uses. You can specify this argument if you want to use a 

279 different CA cert bundle than the one used by botocore. 

280 

281 :type endpoint_url: string 

282 :param endpoint_url: The complete URL to use for the constructed 

283 client. Normally, botocore will automatically construct the 

284 appropriate URL to use when communicating with a service. You 

285 can specify a complete URL (including the "http/https" scheme) 

286 to override this behavior. If this value is provided, 

287 then ``use_ssl`` is ignored. 

288 

289 :type aws_access_key_id: string 

290 :param aws_access_key_id: The access key to use when creating 

291 the client. This is entirely optional, and if not provided, 

292 the credentials configured for the session will automatically 

293 be used. You only need to provide this argument if you want 

294 to override the credentials used for this specific client. 

295 

296 :type aws_secret_access_key: string 

297 :param aws_secret_access_key: The secret key to use when creating 

298 the client. Same semantics as aws_access_key_id above. 

299 

300 :type aws_session_token: string 

301 :param aws_session_token: The session token to use when creating 

302 the client. Same semantics as aws_access_key_id above. 

303 

304 :type config: botocore.client.Config 

305 :param config: Advanced client configuration options. If region_name 

306 is specified in the client config, its value will take precedence 

307 over environment variables and configuration values, but not over 

308 a region_name value passed explicitly to the method. See 

309 `botocore config documentation 

310 <https://botocore.amazonaws.com/v1/documentation/api/latest/reference/config.html>`_ 

311 for more details. 

312 

313 :type aws_account_id: string 

314 :param aws_account_id: The account id to use when creating 

315 the client. Same semantics as aws_access_key_id above. 

316 

317 :return: Service client instance 

318 

319 """ 

320 create_client_kwargs = { 

321 'region_name': region_name, 

322 'api_version': api_version, 

323 'use_ssl': use_ssl, 

324 'verify': verify, 

325 'endpoint_url': endpoint_url, 

326 'aws_access_key_id': aws_access_key_id, 

327 'aws_secret_access_key': aws_secret_access_key, 

328 'aws_session_token': aws_session_token, 

329 'config': config, 

330 'aws_account_id': aws_account_id, 

331 } 

332 if aws_account_id is None: 

333 # Remove aws_account_id for arbitrary 

334 # botocore version mismatches in AWS Lambda. 

335 del create_client_kwargs['aws_account_id'] 

336 

337 return self._session.create_client( 

338 service_name, **create_client_kwargs 

339 ) 

340 

341 def resource( 

342 self, 

343 service_name, 

344 region_name=None, 

345 api_version=None, 

346 use_ssl=True, 

347 verify=None, 

348 endpoint_url=None, 

349 aws_access_key_id=None, 

350 aws_secret_access_key=None, 

351 aws_session_token=None, 

352 config=None, 

353 ): 

354 """ 

355 Create a resource service client by name. 

356 

357 :type service_name: string 

358 :param service_name: The name of a service, e.g. 's3' or 'ec2'. You 

359 can get a list of available services via 

360 :py:meth:`get_available_resources`. 

361 

362 :type region_name: string 

363 :param region_name: The name of the region associated with the client. 

364 A client is associated with a single region. 

365 

366 :type api_version: string 

367 :param api_version: The API version to use. By default, botocore will 

368 use the latest API version when creating a client. You only need 

369 to specify this parameter if you want to use a previous API version 

370 of the client. 

371 

372 :type use_ssl: boolean 

373 :param use_ssl: Whether or not to use SSL. By default, SSL is used. 

374 Note that not all services support non-ssl connections. 

375 

376 :type verify: boolean/string 

377 :param verify: Whether or not to verify SSL certificates. By default 

378 SSL certificates are verified. You can provide the following 

379 values: 

380 

381 * False - do not validate SSL certificates. SSL will still be 

382 used (unless use_ssl is False), but SSL certificates 

383 will not be verified. 

384 * path/to/cert/bundle.pem - A filename of the CA cert bundle to 

385 uses. You can specify this argument if you want to use a 

386 different CA cert bundle than the one used by botocore. 

387 

388 :type endpoint_url: string 

389 :param endpoint_url: The complete URL to use for the constructed 

390 client. Normally, botocore will automatically construct the 

391 appropriate URL to use when communicating with a service. You 

392 can specify a complete URL (including the "http/https" scheme) 

393 to override this behavior. If this value is provided, 

394 then ``use_ssl`` is ignored. 

395 

396 :type aws_access_key_id: string 

397 :param aws_access_key_id: The access key to use when creating 

398 the client. This is entirely optional, and if not provided, 

399 the credentials configured for the session will automatically 

400 be used. You only need to provide this argument if you want 

401 to override the credentials used for this specific client. 

402 

403 :type aws_secret_access_key: string 

404 :param aws_secret_access_key: The secret key to use when creating 

405 the client. Same semantics as aws_access_key_id above. 

406 

407 :type aws_session_token: string 

408 :param aws_session_token: The session token to use when creating 

409 the client. Same semantics as aws_access_key_id above. 

410 

411 :type config: botocore.client.Config 

412 :param config: Advanced client configuration options. If region_name 

413 is specified in the client config, its value will take precedence 

414 over environment variables and configuration values, but not over 

415 a region_name value passed explicitly to the method. If 

416 user_agent_extra is specified in the client config, it overrides 

417 the default user_agent_extra provided by the resource API. See 

418 `botocore config documentation 

419 <https://botocore.amazonaws.com/v1/documentation/api/latest/reference/config.html>`_ 

420 for more details. 

421 

422 :return: Subclass of :py:class:`~boto3.resources.base.ServiceResource` 

423 """ 

424 try: 

425 resource_model = self._loader.load_service_model( 

426 service_name, 'resources-1', api_version 

427 ) 

428 except UnknownServiceError: 

429 available = self.get_available_resources() 

430 has_low_level_client = ( 

431 service_name in self.get_available_services() 

432 ) 

433 raise ResourceNotExistsError( 

434 service_name, available, has_low_level_client 

435 ) 

436 except DataNotFoundError: 

437 # This is because we've provided an invalid API version. 

438 available_api_versions = self._loader.list_api_versions( 

439 service_name, 'resources-1' 

440 ) 

441 raise UnknownAPIVersionError( 

442 service_name, api_version, ', '.join(available_api_versions) 

443 ) 

444 

445 if api_version is None: 

446 # Even though botocore's load_service_model() can handle 

447 # using the latest api_version if not provided, we need 

448 # to track this api_version in boto3 in order to ensure 

449 # we're pairing a resource model with a client model 

450 # of the same API version. It's possible for the latest 

451 # API version of a resource model in boto3 to not be 

452 # the same API version as a service model in botocore. 

453 # So we need to look up the api_version if one is not 

454 # provided to ensure we load the same API version of the 

455 # client. 

456 # 

457 # Note: This is relying on the fact that 

458 # loader.load_service_model(..., api_version=None) 

459 # and loader.determine_latest_version(..., 'resources-1') 

460 # both load the same api version of the file. 

461 api_version = self._loader.determine_latest_version( 

462 service_name, 'resources-1' 

463 ) 

464 

465 # Creating a new resource instance requires the low-level client 

466 # and service model, the resource version and resource JSON data. 

467 # We pass these to the factory and get back a class, which is 

468 # instantiated on top of the low-level client. 

469 if config is not None: 

470 if config.user_agent_extra is None: 

471 config = copy.deepcopy(config) 

472 config.user_agent_extra = 'Resource' 

473 else: 

474 config = Config(user_agent_extra='Resource') 

475 client = self.client( 

476 service_name, 

477 region_name=region_name, 

478 api_version=api_version, 

479 use_ssl=use_ssl, 

480 verify=verify, 

481 endpoint_url=endpoint_url, 

482 aws_access_key_id=aws_access_key_id, 

483 aws_secret_access_key=aws_secret_access_key, 

484 aws_session_token=aws_session_token, 

485 config=config, 

486 ) 

487 service_model = client.meta.service_model 

488 

489 # Create a ServiceContext object to serve as a reference to 

490 # important read-only information about the general service. 

491 service_context = boto3.utils.ServiceContext( 

492 service_name=service_name, 

493 service_model=service_model, 

494 resource_json_definitions=resource_model['resources'], 

495 service_waiter_model=boto3.utils.LazyLoadedWaiterModel( 

496 self._session, service_name, api_version 

497 ), 

498 ) 

499 

500 # Create the service resource class. 

501 cls = self.resource_factory.load_from_definition( 

502 resource_name=service_name, 

503 single_resource_json_definition=resource_model['service'], 

504 service_context=service_context, 

505 ) 

506 

507 return cls(client=client) 

508 

509 def _register_default_handlers(self): 

510 # S3 customizations 

511 self._session.register( 

512 'creating-client-class.s3', 

513 boto3.utils.lazy_call( 

514 'boto3.s3.inject.inject_s3_transfer_methods' 

515 ), 

516 ) 

517 self._session.register( 

518 'creating-resource-class.s3.Bucket', 

519 boto3.utils.lazy_call('boto3.s3.inject.inject_bucket_methods'), 

520 ) 

521 self._session.register( 

522 'creating-resource-class.s3.Object', 

523 boto3.utils.lazy_call('boto3.s3.inject.inject_object_methods'), 

524 ) 

525 self._session.register( 

526 'creating-resource-class.s3.ObjectSummary', 

527 boto3.utils.lazy_call( 

528 'boto3.s3.inject.inject_object_summary_methods' 

529 ), 

530 ) 

531 

532 # DynamoDb customizations 

533 self._session.register( 

534 'creating-resource-class.dynamodb', 

535 boto3.utils.lazy_call( 

536 'boto3.dynamodb.transform.register_high_level_interface' 

537 ), 

538 unique_id='high-level-dynamodb', 

539 ) 

540 self._session.register( 

541 'creating-resource-class.dynamodb.Table', 

542 boto3.utils.lazy_call( 

543 'boto3.dynamodb.table.register_table_methods' 

544 ), 

545 unique_id='high-level-dynamodb-table', 

546 ) 

547 

548 # EC2 Customizations 

549 self._session.register( 

550 'creating-resource-class.ec2.ServiceResource', 

551 boto3.utils.lazy_call('boto3.ec2.createtags.inject_create_tags'), 

552 ) 

553 

554 self._session.register( 

555 'creating-resource-class.ec2.Instance', 

556 boto3.utils.lazy_call( 

557 'boto3.ec2.deletetags.inject_delete_tags', 

558 event_emitter=self.events, 

559 ), 

560 ) 

561 

562 def _account_id_set_without_credentials( 

563 self, 

564 *, 

565 aws_account_id, 

566 aws_access_key_id, 

567 aws_secret_access_key, 

568 **kwargs, 

569 ): 

570 if aws_account_id is None: 

571 return False 

572 elif aws_access_key_id is None or aws_secret_access_key is None: 

573 return True 

574 return False