Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/botocore/session.py: 53%

430 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2023-12-08 06:51 +0000

1# Copyright (c) 2012-2013 Mitch Garnaat http://garnaat.org/ 

2# Copyright 2012-2014 Amazon.com, Inc. or its affiliates. All Rights Reserved. 

3# 

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

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

6# the License is located at 

7# 

8# http://aws.amazon.com/apache2.0/ 

9# 

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

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

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

13# language governing permissions and limitations under the License. 

14""" 

15This module contains the main interface to the botocore package, the 

16Session object. 

17""" 

18 

19import copy 

20import logging 

21import os 

22import platform 

23import socket 

24import warnings 

25 

26import botocore.client 

27import botocore.configloader 

28import botocore.credentials 

29import botocore.tokens 

30from botocore import ( 

31 UNSIGNED, 

32 __version__, 

33 handlers, 

34 invoke_initializers, 

35 monitoring, 

36 paginate, 

37 retryhandler, 

38 translate, 

39 waiter, 

40) 

41from botocore.compat import HAS_CRT, MutableMapping 

42from botocore.configprovider import ( 

43 BOTOCORE_DEFAUT_SESSION_VARIABLES, 

44 ConfigChainFactory, 

45 ConfiguredEndpointProvider, 

46 ConfigValueStore, 

47 DefaultConfigResolver, 

48 SmartDefaultsConfigStoreFactory, 

49 create_botocore_default_config_mapping, 

50) 

51from botocore.errorfactory import ClientExceptionsFactory 

52from botocore.exceptions import ( 

53 ConfigNotFound, 

54 InvalidDefaultsMode, 

55 PartialCredentialsError, 

56 ProfileNotFound, 

57 UnknownServiceError, 

58) 

59from botocore.hooks import ( 

60 EventAliaser, 

61 HierarchicalEmitter, 

62 first_non_none_response, 

63) 

64from botocore.loaders import create_loader 

65from botocore.model import ServiceModel 

66from botocore.parsers import ResponseParserFactory 

67from botocore.regions import EndpointResolver 

68from botocore.useragent import UserAgentString 

69from botocore.utils import ( 

70 EVENT_ALIASES, 

71 IMDSRegionProvider, 

72 validate_region_name, 

73) 

74 

75from botocore.compat import HAS_CRT # noqa 

76 

77 

78logger = logging.getLogger(__name__) 

79 

80 

81class Session: 

82 """ 

83 The Session object collects together useful functionality 

84 from `botocore` as well as important data such as configuration 

85 information and credentials into a single, easy-to-use object. 

86 

87 :ivar available_profiles: A list of profiles defined in the config 

88 file associated with this session. 

89 :ivar profile: The current profile. 

90 """ 

91 

92 SESSION_VARIABLES = copy.copy(BOTOCORE_DEFAUT_SESSION_VARIABLES) 

93 

94 #: The default format string to use when configuring the botocore logger. 

95 LOG_FORMAT = '%(asctime)s - %(name)s - %(levelname)s - %(message)s' 

96 

97 def __init__( 

98 self, 

99 session_vars=None, 

100 event_hooks=None, 

101 include_builtin_handlers=True, 

102 profile=None, 

103 ): 

104 """ 

105 Create a new Session object. 

106 

107 :type session_vars: dict 

108 :param session_vars: A dictionary that is used to override some or all 

109 of the environment variables associated with this session. The 

110 key/value pairs defined in this dictionary will override the 

111 corresponding variables defined in ``SESSION_VARIABLES``. 

112 

113 :type event_hooks: BaseEventHooks 

114 :param event_hooks: The event hooks object to use. If one is not 

115 provided, an event hooks object will be automatically created 

116 for you. 

117 

118 :type include_builtin_handlers: bool 

119 :param include_builtin_handlers: Indicates whether or not to 

120 automatically register builtin handlers. 

121 

122 :type profile: str 

123 :param profile: The name of the profile to use for this 

124 session. Note that the profile can only be set when 

125 the session is created. 

126 

127 """ 

128 if event_hooks is None: 

129 self._original_handler = HierarchicalEmitter() 

130 else: 

131 self._original_handler = event_hooks 

132 self._events = EventAliaser(self._original_handler) 

133 if include_builtin_handlers: 

134 self._register_builtin_handlers(self._events) 

135 self.user_agent_name = 'Botocore' 

136 self.user_agent_version = __version__ 

137 self.user_agent_extra = '' 

138 # The _profile attribute is just used to cache the value 

139 # of the current profile to avoid going through the normal 

140 # config lookup process each access time. 

141 self._profile = None 

142 self._config = None 

143 self._credentials = None 

144 self._auth_token = None 

145 self._profile_map = None 

146 # This is a dict that stores per session specific config variable 

147 # overrides via set_config_variable(). 

148 self._session_instance_vars = {} 

149 if profile is not None: 

150 self._session_instance_vars['profile'] = profile 

151 self._client_config = None 

152 self._last_client_region_used = None 

153 self._components = ComponentLocator() 

154 self._internal_components = ComponentLocator() 

155 self._register_components() 

156 self.session_var_map = SessionVarDict(self, self.SESSION_VARIABLES) 

157 if session_vars is not None: 

158 self.session_var_map.update(session_vars) 

159 invoke_initializers(self) 

160 

161 def _register_components(self): 

162 self._register_credential_provider() 

163 self._register_token_provider() 

164 self._register_data_loader() 

165 self._register_endpoint_resolver() 

166 self._register_event_emitter() 

167 self._register_response_parser_factory() 

168 self._register_exceptions_factory() 

169 self._register_config_store() 

170 self._register_monitor() 

171 self._register_default_config_resolver() 

172 self._register_smart_defaults_factory() 

173 self._register_user_agent_creator() 

174 

175 def _register_event_emitter(self): 

176 self._components.register_component('event_emitter', self._events) 

177 

178 def _register_token_provider(self): 

179 self._components.lazy_register_component( 

180 'token_provider', self._create_token_resolver 

181 ) 

182 

183 def _create_token_resolver(self): 

184 return botocore.tokens.create_token_resolver(self) 

185 

186 def _register_credential_provider(self): 

187 self._components.lazy_register_component( 

188 'credential_provider', self._create_credential_resolver 

189 ) 

190 

191 def _create_credential_resolver(self): 

192 return botocore.credentials.create_credential_resolver( 

193 self, region_name=self._last_client_region_used 

194 ) 

195 

196 def _register_data_loader(self): 

197 self._components.lazy_register_component( 

198 'data_loader', 

199 lambda: create_loader(self.get_config_variable('data_path')), 

200 ) 

201 

202 def _register_endpoint_resolver(self): 

203 def create_default_resolver(): 

204 loader = self.get_component('data_loader') 

205 endpoints, path = loader.load_data_with_path('endpoints') 

206 uses_builtin = loader.is_builtin_path(path) 

207 return EndpointResolver(endpoints, uses_builtin_data=uses_builtin) 

208 

209 self._internal_components.lazy_register_component( 

210 'endpoint_resolver', create_default_resolver 

211 ) 

212 

213 def _register_default_config_resolver(self): 

214 def create_default_config_resolver(): 

215 loader = self.get_component('data_loader') 

216 defaults = loader.load_data('sdk-default-configuration') 

217 return DefaultConfigResolver(defaults) 

218 

219 self._internal_components.lazy_register_component( 

220 'default_config_resolver', create_default_config_resolver 

221 ) 

222 

223 def _register_smart_defaults_factory(self): 

224 def create_smart_defaults_factory(): 

225 default_config_resolver = self._get_internal_component( 

226 'default_config_resolver' 

227 ) 

228 imds_region_provider = IMDSRegionProvider(session=self) 

229 return SmartDefaultsConfigStoreFactory( 

230 default_config_resolver, imds_region_provider 

231 ) 

232 

233 self._internal_components.lazy_register_component( 

234 'smart_defaults_factory', create_smart_defaults_factory 

235 ) 

236 

237 def _register_response_parser_factory(self): 

238 self._components.register_component( 

239 'response_parser_factory', ResponseParserFactory() 

240 ) 

241 

242 def _register_exceptions_factory(self): 

243 self._internal_components.register_component( 

244 'exceptions_factory', ClientExceptionsFactory() 

245 ) 

246 

247 def _register_builtin_handlers(self, events): 

248 for spec in handlers.BUILTIN_HANDLERS: 

249 if len(spec) == 2: 

250 event_name, handler = spec 

251 self.register(event_name, handler) 

252 else: 

253 event_name, handler, register_type = spec 

254 if register_type is handlers.REGISTER_FIRST: 

255 self._events.register_first(event_name, handler) 

256 elif register_type is handlers.REGISTER_LAST: 

257 self._events.register_last(event_name, handler) 

258 

259 def _register_config_store(self): 

260 config_store_component = ConfigValueStore( 

261 mapping=create_botocore_default_config_mapping(self) 

262 ) 

263 self._components.register_component( 

264 'config_store', config_store_component 

265 ) 

266 

267 def _register_monitor(self): 

268 self._internal_components.lazy_register_component( 

269 'monitor', self._create_csm_monitor 

270 ) 

271 

272 def _register_user_agent_creator(self): 

273 uas = UserAgentString.from_environment() 

274 self._components.register_component('user_agent_creator', uas) 

275 

276 def _create_csm_monitor(self): 

277 if self.get_config_variable('csm_enabled'): 

278 client_id = self.get_config_variable('csm_client_id') 

279 host = self.get_config_variable('csm_host') 

280 port = self.get_config_variable('csm_port') 

281 handler = monitoring.Monitor( 

282 adapter=monitoring.MonitorEventAdapter(), 

283 publisher=monitoring.SocketPublisher( 

284 socket=socket.socket(socket.AF_INET, socket.SOCK_DGRAM), 

285 host=host, 

286 port=port, 

287 serializer=monitoring.CSMSerializer( 

288 csm_client_id=client_id 

289 ), 

290 ), 

291 ) 

292 return handler 

293 return None 

294 

295 def _get_crt_version(self): 

296 user_agent_creator = self.get_component('user_agent_creator') 

297 return user_agent_creator._crt_version or 'Unknown' 

298 

299 @property 

300 def available_profiles(self): 

301 return list(self._build_profile_map().keys()) 

302 

303 def _build_profile_map(self): 

304 # This will build the profile map if it has not been created, 

305 # otherwise it will return the cached value. The profile map 

306 # is a list of profile names, to the config values for the profile. 

307 if self._profile_map is None: 

308 self._profile_map = self.full_config['profiles'] 

309 return self._profile_map 

310 

311 @property 

312 def profile(self): 

313 if self._profile is None: 

314 profile = self.get_config_variable('profile') 

315 self._profile = profile 

316 return self._profile 

317 

318 def get_config_variable(self, logical_name, methods=None): 

319 if methods is not None: 

320 return self._get_config_variable_with_custom_methods( 

321 logical_name, methods 

322 ) 

323 return self.get_component('config_store').get_config_variable( 

324 logical_name 

325 ) 

326 

327 def _get_config_variable_with_custom_methods(self, logical_name, methods): 

328 # If a custom list of methods was supplied we need to perserve the 

329 # behavior with the new system. To do so a new chain that is a copy of 

330 # the old one will be constructed, but only with the supplied methods 

331 # being added to the chain. This chain will be consulted for a value 

332 # and then thrown out. This is not efficient, nor is the methods arg 

333 # used in botocore, this is just for backwards compatibility. 

334 chain_builder = SubsetChainConfigFactory(session=self, methods=methods) 

335 mapping = create_botocore_default_config_mapping(self) 

336 for name, config_options in self.session_var_map.items(): 

337 config_name, env_vars, default, typecast = config_options 

338 build_chain_config_args = { 

339 'conversion_func': typecast, 

340 'default': default, 

341 } 

342 if 'instance' in methods: 

343 build_chain_config_args['instance_name'] = name 

344 if 'env' in methods: 

345 build_chain_config_args['env_var_names'] = env_vars 

346 if 'config' in methods: 

347 build_chain_config_args['config_property_name'] = config_name 

348 mapping[name] = chain_builder.create_config_chain( 

349 **build_chain_config_args 

350 ) 

351 config_store_component = ConfigValueStore(mapping=mapping) 

352 value = config_store_component.get_config_variable(logical_name) 

353 return value 

354 

355 def set_config_variable(self, logical_name, value): 

356 """Set a configuration variable to a specific value. 

357 

358 By using this method, you can override the normal lookup 

359 process used in ``get_config_variable`` by explicitly setting 

360 a value. Subsequent calls to ``get_config_variable`` will 

361 use the ``value``. This gives you per-session specific 

362 configuration values. 

363 

364 :: 

365 >>> # Assume logical name 'foo' maps to env var 'FOO' 

366 >>> os.environ['FOO'] = 'myvalue' 

367 >>> s.get_config_variable('foo') 

368 'myvalue' 

369 >>> s.set_config_variable('foo', 'othervalue') 

370 >>> s.get_config_variable('foo') 

371 'othervalue' 

372 

373 :type logical_name: str 

374 :param logical_name: The logical name of the session variable 

375 you want to set. These are the keys in ``SESSION_VARIABLES``. 

376 :param value: The value to associate with the config variable. 

377 

378 """ 

379 logger.debug( 

380 "Setting config variable for %s to %r", 

381 logical_name, 

382 value, 

383 ) 

384 self._session_instance_vars[logical_name] = value 

385 

386 def instance_variables(self): 

387 return copy.copy(self._session_instance_vars) 

388 

389 def get_scoped_config(self): 

390 """ 

391 Returns the config values from the config file scoped to the current 

392 profile. 

393 

394 The configuration data is loaded **only** from the config file. 

395 It does not resolve variables based on different locations 

396 (e.g. first from the session instance, then from environment 

397 variables, then from the config file). If you want this lookup 

398 behavior, use the ``get_config_variable`` method instead. 

399 

400 Note that this configuration is specific to a single profile (the 

401 ``profile`` session variable). 

402 

403 If the ``profile`` session variable is set and the profile does 

404 not exist in the config file, a ``ProfileNotFound`` exception 

405 will be raised. 

406 

407 :raises: ConfigNotFound, ConfigParseError, ProfileNotFound 

408 :rtype: dict 

409 

410 """ 

411 profile_name = self.get_config_variable('profile') 

412 profile_map = self._build_profile_map() 

413 # If a profile is not explicitly set return the default 

414 # profile config or an empty config dict if we don't have 

415 # a default profile. 

416 if profile_name is None: 

417 return profile_map.get('default', {}) 

418 elif profile_name not in profile_map: 

419 # Otherwise if they specified a profile, it has to 

420 # exist (even if it's the default profile) otherwise 

421 # we complain. 

422 raise ProfileNotFound(profile=profile_name) 

423 else: 

424 return profile_map[profile_name] 

425 

426 @property 

427 def full_config(self): 

428 """Return the parsed config file. 

429 

430 The ``get_config`` method returns the config associated with the 

431 specified profile. This property returns the contents of the 

432 **entire** config file. 

433 

434 :rtype: dict 

435 """ 

436 if self._config is None: 

437 try: 

438 config_file = self.get_config_variable('config_file') 

439 self._config = botocore.configloader.load_config(config_file) 

440 except ConfigNotFound: 

441 self._config = {'profiles': {}} 

442 try: 

443 # Now we need to inject the profiles from the 

444 # credentials file. We don't actually need the values 

445 # in the creds file, only the profile names so that we 

446 # can validate the user is not referring to a nonexistent 

447 # profile. 

448 cred_file = self.get_config_variable('credentials_file') 

449 cred_profiles = botocore.configloader.raw_config_parse( 

450 cred_file 

451 ) 

452 for profile in cred_profiles: 

453 cred_vars = cred_profiles[profile] 

454 if profile not in self._config['profiles']: 

455 self._config['profiles'][profile] = cred_vars 

456 else: 

457 self._config['profiles'][profile].update(cred_vars) 

458 except ConfigNotFound: 

459 pass 

460 return self._config 

461 

462 def get_default_client_config(self): 

463 """Retrieves the default config for creating clients 

464 

465 :rtype: botocore.client.Config 

466 :returns: The default client config object when creating clients. If 

467 the value is ``None`` then there is no default config object 

468 attached to the session. 

469 """ 

470 return self._client_config 

471 

472 def set_default_client_config(self, client_config): 

473 """Sets the default config for creating clients 

474 

475 :type client_config: botocore.client.Config 

476 :param client_config: The default client config object when creating 

477 clients. If the value is ``None`` then there is no default config 

478 object attached to the session. 

479 """ 

480 self._client_config = client_config 

481 

482 def set_credentials(self, access_key, secret_key, token=None): 

483 """ 

484 Manually create credentials for this session. If you would 

485 prefer to use botocore without a config file, environment variables, 

486 or IAM roles, you can pass explicit credentials into this 

487 method to establish credentials for this session. 

488 

489 :type access_key: str 

490 :param access_key: The access key part of the credentials. 

491 

492 :type secret_key: str 

493 :param secret_key: The secret key part of the credentials. 

494 

495 :type token: str 

496 :param token: An option session token used by STS session 

497 credentials. 

498 """ 

499 self._credentials = botocore.credentials.Credentials( 

500 access_key, secret_key, token 

501 ) 

502 

503 def get_credentials(self): 

504 """ 

505 Return the :class:`botocore.credential.Credential` object 

506 associated with this session. If the credentials have not 

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

508 have already been loaded, this will return the cached 

509 credentials. 

510 

511 """ 

512 if self._credentials is None: 

513 self._credentials = self._components.get_component( 

514 'credential_provider' 

515 ).load_credentials() 

516 return self._credentials 

517 

518 def get_auth_token(self): 

519 """ 

520 Return the :class:`botocore.tokens.AuthToken` object associated with 

521 this session. If the authorization token has not yet been loaded, this 

522 will attempt to load it. If it has already been loaded, this will 

523 return the cached authorization token. 

524 

525 """ 

526 if self._auth_token is None: 

527 provider = self._components.get_component('token_provider') 

528 self._auth_token = provider.load_token() 

529 return self._auth_token 

530 

531 def user_agent(self): 

532 """ 

533 Return a string suitable for use as a User-Agent header. 

534 The string will be of the form: 

535 

536 <agent_name>/<agent_version> Python/<py_ver> <plat_name>/<plat_ver> <exec_env> 

537 

538 Where: 

539 

540 - agent_name is the value of the `user_agent_name` attribute 

541 of the session object (`Botocore` by default). 

542 - agent_version is the value of the `user_agent_version` 

543 attribute of the session object (the botocore version by default). 

544 by default. 

545 - py_ver is the version of the Python interpreter beng used. 

546 - plat_name is the name of the platform (e.g. Darwin) 

547 - plat_ver is the version of the platform 

548 - exec_env is exec-env/$AWS_EXECUTION_ENV 

549 

550 If ``user_agent_extra`` is not empty, then this value will be 

551 appended to the end of the user agent string. 

552 

553 """ 

554 base = ( 

555 f'{self.user_agent_name}/{self.user_agent_version} ' 

556 f'Python/{platform.python_version()} ' 

557 f'{platform.system()}/{platform.release()}' 

558 ) 

559 if HAS_CRT: 

560 base += ' awscrt/%s' % self._get_crt_version() 

561 if os.environ.get('AWS_EXECUTION_ENV') is not None: 

562 base += ' exec-env/%s' % os.environ.get('AWS_EXECUTION_ENV') 

563 if self.user_agent_extra: 

564 base += ' %s' % self.user_agent_extra 

565 

566 return base 

567 

568 def get_data(self, data_path): 

569 """ 

570 Retrieve the data associated with `data_path`. 

571 

572 :type data_path: str 

573 :param data_path: The path to the data you wish to retrieve. 

574 """ 

575 return self.get_component('data_loader').load_data(data_path) 

576 

577 def get_service_model(self, service_name, api_version=None): 

578 """Get the service model object. 

579 

580 :type service_name: string 

581 :param service_name: The service name 

582 

583 :type api_version: string 

584 :param api_version: The API version of the service. If none is 

585 provided, then the latest API version will be used. 

586 

587 :rtype: L{botocore.model.ServiceModel} 

588 :return: The botocore service model for the service. 

589 

590 """ 

591 service_description = self.get_service_data(service_name, api_version) 

592 return ServiceModel(service_description, service_name=service_name) 

593 

594 def get_waiter_model(self, service_name, api_version=None): 

595 loader = self.get_component('data_loader') 

596 waiter_config = loader.load_service_model( 

597 service_name, 'waiters-2', api_version 

598 ) 

599 return waiter.WaiterModel(waiter_config) 

600 

601 def get_paginator_model(self, service_name, api_version=None): 

602 loader = self.get_component('data_loader') 

603 paginator_config = loader.load_service_model( 

604 service_name, 'paginators-1', api_version 

605 ) 

606 return paginate.PaginatorModel(paginator_config) 

607 

608 def get_service_data(self, service_name, api_version=None): 

609 """ 

610 Retrieve the fully merged data associated with a service. 

611 """ 

612 data_path = service_name 

613 service_data = self.get_component('data_loader').load_service_model( 

614 data_path, type_name='service-2', api_version=api_version 

615 ) 

616 service_id = EVENT_ALIASES.get(service_name, service_name) 

617 self._events.emit( 

618 'service-data-loaded.%s' % service_id, 

619 service_data=service_data, 

620 service_name=service_name, 

621 session=self, 

622 ) 

623 return service_data 

624 

625 def get_available_services(self): 

626 """ 

627 Return a list of names of available services. 

628 """ 

629 return self.get_component('data_loader').list_available_services( 

630 type_name='service-2' 

631 ) 

632 

633 def set_debug_logger(self, logger_name='botocore'): 

634 """ 

635 Convenience function to quickly configure full debug output 

636 to go to the console. 

637 """ 

638 self.set_stream_logger(logger_name, logging.DEBUG) 

639 

640 def set_stream_logger( 

641 self, logger_name, log_level, stream=None, format_string=None 

642 ): 

643 """ 

644 Convenience method to configure a stream logger. 

645 

646 :type logger_name: str 

647 :param logger_name: The name of the logger to configure 

648 

649 :type log_level: str 

650 :param log_level: The log level to set for the logger. This 

651 is any param supported by the ``.setLevel()`` method of 

652 a ``Log`` object. 

653 

654 :type stream: file 

655 :param stream: A file like object to log to. If none is provided 

656 then sys.stderr will be used. 

657 

658 :type format_string: str 

659 :param format_string: The format string to use for the log 

660 formatter. If none is provided this will default to 

661 ``self.LOG_FORMAT``. 

662 

663 """ 

664 log = logging.getLogger(logger_name) 

665 log.setLevel(logging.DEBUG) 

666 

667 ch = logging.StreamHandler(stream) 

668 ch.setLevel(log_level) 

669 

670 # create formatter 

671 if format_string is None: 

672 format_string = self.LOG_FORMAT 

673 formatter = logging.Formatter(format_string) 

674 

675 # add formatter to ch 

676 ch.setFormatter(formatter) 

677 

678 # add ch to logger 

679 log.addHandler(ch) 

680 

681 def set_file_logger(self, log_level, path, logger_name='botocore'): 

682 """ 

683 Convenience function to quickly configure any level of logging 

684 to a file. 

685 

686 :type log_level: int 

687 :param log_level: A log level as specified in the `logging` module 

688 

689 :type path: string 

690 :param path: Path to the log file. The file will be created 

691 if it doesn't already exist. 

692 """ 

693 log = logging.getLogger(logger_name) 

694 log.setLevel(logging.DEBUG) 

695 

696 # create console handler and set level to debug 

697 ch = logging.FileHandler(path) 

698 ch.setLevel(log_level) 

699 

700 # create formatter 

701 formatter = logging.Formatter(self.LOG_FORMAT) 

702 

703 # add formatter to ch 

704 ch.setFormatter(formatter) 

705 

706 # add ch to logger 

707 log.addHandler(ch) 

708 

709 def register( 

710 self, event_name, handler, unique_id=None, unique_id_uses_count=False 

711 ): 

712 """Register a handler with an event. 

713 

714 :type event_name: str 

715 :param event_name: The name of the event. 

716 

717 :type handler: callable 

718 :param handler: The callback to invoke when the event 

719 is emitted. This object must be callable, and must 

720 accept ``**kwargs``. If either of these preconditions are 

721 not met, a ``ValueError`` will be raised. 

722 

723 :type unique_id: str 

724 :param unique_id: An optional identifier to associate with the 

725 registration. A unique_id can only be used once for 

726 the entire session registration (unless it is unregistered). 

727 This can be used to prevent an event handler from being 

728 registered twice. 

729 

730 :param unique_id_uses_count: boolean 

731 :param unique_id_uses_count: Specifies if the event should maintain 

732 a count when a ``unique_id`` is registered and unregisted. The 

733 event can only be completely unregistered once every register call 

734 using the unique id has been matched by an ``unregister`` call. 

735 If ``unique_id`` is specified, subsequent ``register`` 

736 calls must use the same value for ``unique_id_uses_count`` 

737 as the ``register`` call that first registered the event. 

738 

739 :raises ValueError: If the call to ``register`` uses ``unique_id`` 

740 but the value for ``unique_id_uses_count`` differs from the 

741 ``unique_id_uses_count`` value declared by the very first 

742 ``register`` call for that ``unique_id``. 

743 """ 

744 self._events.register( 

745 event_name, 

746 handler, 

747 unique_id, 

748 unique_id_uses_count=unique_id_uses_count, 

749 ) 

750 

751 def unregister( 

752 self, 

753 event_name, 

754 handler=None, 

755 unique_id=None, 

756 unique_id_uses_count=False, 

757 ): 

758 """Unregister a handler with an event. 

759 

760 :type event_name: str 

761 :param event_name: The name of the event. 

762 

763 :type handler: callable 

764 :param handler: The callback to unregister. 

765 

766 :type unique_id: str 

767 :param unique_id: A unique identifier identifying the callback 

768 to unregister. You can provide either the handler or the 

769 unique_id, you do not have to provide both. 

770 

771 :param unique_id_uses_count: boolean 

772 :param unique_id_uses_count: Specifies if the event should maintain 

773 a count when a ``unique_id`` is registered and unregisted. The 

774 event can only be completely unregistered once every ``register`` 

775 call using the ``unique_id`` has been matched by an ``unregister`` 

776 call. If the ``unique_id`` is specified, subsequent 

777 ``unregister`` calls must use the same value for 

778 ``unique_id_uses_count`` as the ``register`` call that first 

779 registered the event. 

780 

781 :raises ValueError: If the call to ``unregister`` uses ``unique_id`` 

782 but the value for ``unique_id_uses_count`` differs from the 

783 ``unique_id_uses_count`` value declared by the very first 

784 ``register`` call for that ``unique_id``. 

785 """ 

786 self._events.unregister( 

787 event_name, 

788 handler=handler, 

789 unique_id=unique_id, 

790 unique_id_uses_count=unique_id_uses_count, 

791 ) 

792 

793 def emit(self, event_name, **kwargs): 

794 return self._events.emit(event_name, **kwargs) 

795 

796 def emit_first_non_none_response(self, event_name, **kwargs): 

797 responses = self._events.emit(event_name, **kwargs) 

798 return first_non_none_response(responses) 

799 

800 def get_component(self, name): 

801 try: 

802 return self._components.get_component(name) 

803 except ValueError: 

804 if name in ['endpoint_resolver', 'exceptions_factory']: 

805 warnings.warn( 

806 'Fetching the %s component with the get_component() ' 

807 'method is deprecated as the component has always been ' 

808 'considered an internal interface of botocore' % name, 

809 DeprecationWarning, 

810 ) 

811 return self._internal_components.get_component(name) 

812 raise 

813 

814 def _get_internal_component(self, name): 

815 # While this method may be called by botocore classes outside of the 

816 # Session, this method should **never** be used by a class that lives 

817 # outside of botocore. 

818 return self._internal_components.get_component(name) 

819 

820 def _register_internal_component(self, name, component): 

821 # While this method may be called by botocore classes outside of the 

822 # Session, this method should **never** be used by a class that lives 

823 # outside of botocore. 

824 return self._internal_components.register_component(name, component) 

825 

826 def register_component(self, name, component): 

827 self._components.register_component(name, component) 

828 

829 def lazy_register_component(self, name, component): 

830 self._components.lazy_register_component(name, component) 

831 

832 def create_client( 

833 self, 

834 service_name, 

835 region_name=None, 

836 api_version=None, 

837 use_ssl=True, 

838 verify=None, 

839 endpoint_url=None, 

840 aws_access_key_id=None, 

841 aws_secret_access_key=None, 

842 aws_session_token=None, 

843 config=None, 

844 ): 

845 """Create a botocore client. 

846 

847 :type service_name: string 

848 :param service_name: The name of the service for which a client will 

849 be created. You can use the ``Session.get_available_services()`` 

850 method to get a list of all available service names. 

851 

852 :type region_name: string 

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

854 A client is associated with a single region. 

855 

856 :type api_version: string 

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

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

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

860 of the client. 

861 

862 :type use_ssl: boolean 

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

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

865 

866 :type verify: boolean/string 

867 :param verify: Whether or not to verify SSL certificates. 

868 By default SSL certificates are verified. You can provide the 

869 following values: 

870 

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

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

873 will not be verified. 

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

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

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

877 

878 :type endpoint_url: string 

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

880 client. Normally, botocore will automatically construct the 

881 appropriate URL to use when communicating with a service. You can 

882 specify a complete URL (including the "http/https" scheme) to 

883 override this behavior. If this value is provided, then 

884 ``use_ssl`` is ignored. 

885 

886 :type aws_access_key_id: string 

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

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

889 the credentials configured for the session will automatically 

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

891 to override the credentials used for this specific client. 

892 

893 :type aws_secret_access_key: string 

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

895 the client. Same semantics as aws_access_key_id above. 

896 

897 :type aws_session_token: string 

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

899 the client. Same semantics as aws_access_key_id above. 

900 

901 :type config: botocore.client.Config 

902 :param config: Advanced client configuration options. If a value 

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

904 over environment variables and configuration values, but not over 

905 a value passed explicitly to the method. If a default config 

906 object is set on the session, the config object used when creating 

907 the client will be the result of calling ``merge()`` on the 

908 default config with the config provided to this call. 

909 

910 :rtype: botocore.client.BaseClient 

911 :return: A botocore client instance 

912 

913 """ 

914 default_client_config = self.get_default_client_config() 

915 # If a config is provided and a default config is set, then 

916 # use the config resulting from merging the two. 

917 if config is not None and default_client_config is not None: 

918 config = default_client_config.merge(config) 

919 # If a config was not provided then use the default 

920 # client config from the session 

921 elif default_client_config is not None: 

922 config = default_client_config 

923 

924 region_name = self._resolve_region_name(region_name, config) 

925 

926 # Figure out the verify value base on the various 

927 # configuration options. 

928 if verify is None: 

929 verify = self.get_config_variable('ca_bundle') 

930 

931 if api_version is None: 

932 api_version = self.get_config_variable('api_versions').get( 

933 service_name, None 

934 ) 

935 

936 loader = self.get_component('data_loader') 

937 event_emitter = self.get_component('event_emitter') 

938 response_parser_factory = self.get_component('response_parser_factory') 

939 if config is not None and config.signature_version is UNSIGNED: 

940 credentials = None 

941 elif ( 

942 aws_access_key_id is not None and aws_secret_access_key is not None 

943 ): 

944 credentials = botocore.credentials.Credentials( 

945 access_key=aws_access_key_id, 

946 secret_key=aws_secret_access_key, 

947 token=aws_session_token, 

948 ) 

949 elif self._missing_cred_vars(aws_access_key_id, aws_secret_access_key): 

950 raise PartialCredentialsError( 

951 provider='explicit', 

952 cred_var=self._missing_cred_vars( 

953 aws_access_key_id, aws_secret_access_key 

954 ), 

955 ) 

956 else: 

957 credentials = self.get_credentials() 

958 auth_token = self.get_auth_token() 

959 endpoint_resolver = self._get_internal_component('endpoint_resolver') 

960 exceptions_factory = self._get_internal_component('exceptions_factory') 

961 config_store = copy.copy(self.get_component('config_store')) 

962 user_agent_creator = self.get_component('user_agent_creator') 

963 # Session configuration values for the user agent string are applied 

964 # just before each client creation because they may have been modified 

965 # at any time between session creation and client creation. 

966 user_agent_creator.set_session_config( 

967 session_user_agent_name=self.user_agent_name, 

968 session_user_agent_version=self.user_agent_version, 

969 session_user_agent_extra=self.user_agent_extra, 

970 ) 

971 defaults_mode = self._resolve_defaults_mode(config, config_store) 

972 if defaults_mode != 'legacy': 

973 smart_defaults_factory = self._get_internal_component( 

974 'smart_defaults_factory' 

975 ) 

976 smart_defaults_factory.merge_smart_defaults( 

977 config_store, defaults_mode, region_name 

978 ) 

979 

980 self._add_configured_endpoint_provider( 

981 client_name=service_name, 

982 config_store=config_store, 

983 ) 

984 

985 client_creator = botocore.client.ClientCreator( 

986 loader, 

987 endpoint_resolver, 

988 self.user_agent(), 

989 event_emitter, 

990 retryhandler, 

991 translate, 

992 response_parser_factory, 

993 exceptions_factory, 

994 config_store, 

995 user_agent_creator=user_agent_creator, 

996 ) 

997 client = client_creator.create_client( 

998 service_name=service_name, 

999 region_name=region_name, 

1000 is_secure=use_ssl, 

1001 endpoint_url=endpoint_url, 

1002 verify=verify, 

1003 credentials=credentials, 

1004 scoped_config=self.get_scoped_config(), 

1005 client_config=config, 

1006 api_version=api_version, 

1007 auth_token=auth_token, 

1008 ) 

1009 monitor = self._get_internal_component('monitor') 

1010 if monitor is not None: 

1011 monitor.register(client.meta.events) 

1012 return client 

1013 

1014 def _resolve_region_name(self, region_name, config): 

1015 # Figure out the user-provided region based on the various 

1016 # configuration options. 

1017 if region_name is None: 

1018 if config and config.region_name is not None: 

1019 region_name = config.region_name 

1020 else: 

1021 region_name = self.get_config_variable('region') 

1022 

1023 validate_region_name(region_name) 

1024 # For any client that we create in retrieving credentials 

1025 # we want to create it using the same region as specified in 

1026 # creating this client. It is important to note though that the 

1027 # credentials client is only created once per session. So if a new 

1028 # client is created with a different region, its credential resolver 

1029 # will use the region of the first client. However, that is not an 

1030 # issue as of now because the credential resolver uses only STS and 

1031 # the credentials returned at regional endpoints are valid across 

1032 # all regions in the partition. 

1033 self._last_client_region_used = region_name 

1034 return region_name 

1035 

1036 def _resolve_defaults_mode(self, client_config, config_store): 

1037 mode = config_store.get_config_variable('defaults_mode') 

1038 

1039 if client_config and client_config.defaults_mode: 

1040 mode = client_config.defaults_mode 

1041 

1042 default_config_resolver = self._get_internal_component( 

1043 'default_config_resolver' 

1044 ) 

1045 default_modes = default_config_resolver.get_default_modes() 

1046 lmode = mode.lower() 

1047 if lmode not in default_modes: 

1048 raise InvalidDefaultsMode( 

1049 mode=mode, valid_modes=', '.join(default_modes) 

1050 ) 

1051 

1052 return lmode 

1053 

1054 def _add_configured_endpoint_provider(self, client_name, config_store): 

1055 chain = ConfiguredEndpointProvider( 

1056 full_config=self.full_config, 

1057 scoped_config=self.get_scoped_config(), 

1058 client_name=client_name, 

1059 ) 

1060 config_store.set_config_provider( 

1061 logical_name='endpoint_url', 

1062 provider=chain, 

1063 ) 

1064 

1065 def _missing_cred_vars(self, access_key, secret_key): 

1066 if access_key is not None and secret_key is None: 

1067 return 'aws_secret_access_key' 

1068 if secret_key is not None and access_key is None: 

1069 return 'aws_access_key_id' 

1070 return None 

1071 

1072 def get_available_partitions(self): 

1073 """Lists the available partitions found on disk 

1074 

1075 :rtype: list 

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

1077 """ 

1078 resolver = self._get_internal_component('endpoint_resolver') 

1079 return resolver.get_available_partitions() 

1080 

1081 def get_partition_for_region(self, region_name): 

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

1083 

1084 :type region_name: string 

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

1086 us-east-1). 

1087 

1088 :rtype: string 

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

1090 """ 

1091 resolver = self._get_internal_component('endpoint_resolver') 

1092 return resolver.get_partition_for_region(region_name) 

1093 

1094 def get_available_regions( 

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

1096 ): 

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

1098 

1099 :type service_name: string 

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

1101 This parameter accepts a service name (e.g., "elb") or endpoint 

1102 prefix (e.g., "elasticloadbalancing"). 

1103 

1104 :type partition_name: string 

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

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

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

1108 

1109 :type allow_non_regional: bool 

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

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

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

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

1114 """ 

1115 resolver = self._get_internal_component('endpoint_resolver') 

1116 results = [] 

1117 try: 

1118 service_data = self.get_service_data(service_name) 

1119 endpoint_prefix = service_data['metadata'].get( 

1120 'endpointPrefix', service_name 

1121 ) 

1122 results = resolver.get_available_endpoints( 

1123 endpoint_prefix, partition_name, allow_non_regional 

1124 ) 

1125 except UnknownServiceError: 

1126 pass 

1127 return results 

1128 

1129 

1130class ComponentLocator: 

1131 """Service locator for session components.""" 

1132 

1133 def __init__(self): 

1134 self._components = {} 

1135 self._deferred = {} 

1136 

1137 def get_component(self, name): 

1138 if name in self._deferred: 

1139 factory = self._deferred[name] 

1140 self._components[name] = factory() 

1141 # Only delete the component from the deferred dict after 

1142 # successfully creating the object from the factory as well as 

1143 # injecting the instantiated value into the _components dict. 

1144 try: 

1145 del self._deferred[name] 

1146 except KeyError: 

1147 # If we get here, it's likely that get_component was called 

1148 # concurrently from multiple threads, and another thread 

1149 # already deleted the entry. This means the factory was 

1150 # probably called twice, but cleaning up the deferred entry 

1151 # should not crash outright. 

1152 pass 

1153 try: 

1154 return self._components[name] 

1155 except KeyError: 

1156 raise ValueError("Unknown component: %s" % name) 

1157 

1158 def register_component(self, name, component): 

1159 self._components[name] = component 

1160 try: 

1161 del self._deferred[name] 

1162 except KeyError: 

1163 pass 

1164 

1165 def lazy_register_component(self, name, no_arg_factory): 

1166 self._deferred[name] = no_arg_factory 

1167 try: 

1168 del self._components[name] 

1169 except KeyError: 

1170 pass 

1171 

1172 

1173class SessionVarDict(MutableMapping): 

1174 def __init__(self, session, session_vars): 

1175 self._session = session 

1176 self._store = copy.copy(session_vars) 

1177 

1178 def __getitem__(self, key): 

1179 return self._store[key] 

1180 

1181 def __setitem__(self, key, value): 

1182 self._store[key] = value 

1183 self._update_config_store_from_session_vars(key, value) 

1184 

1185 def __delitem__(self, key): 

1186 del self._store[key] 

1187 

1188 def __iter__(self): 

1189 return iter(self._store) 

1190 

1191 def __len__(self): 

1192 return len(self._store) 

1193 

1194 def _update_config_store_from_session_vars( 

1195 self, logical_name, config_options 

1196 ): 

1197 # This is for backwards compatibility. The new preferred way to 

1198 # modify configuration logic is to use the component system to get 

1199 # the config_store component from the session, and then update 

1200 # a key with a custom config provider(s). 

1201 # This backwards compatibility method takes the old session_vars 

1202 # list of tuples and and transforms that into a set of updates to 

1203 # the config_store component. 

1204 config_chain_builder = ConfigChainFactory(session=self._session) 

1205 config_name, env_vars, default, typecast = config_options 

1206 config_store = self._session.get_component('config_store') 

1207 config_store.set_config_provider( 

1208 logical_name, 

1209 config_chain_builder.create_config_chain( 

1210 instance_name=logical_name, 

1211 env_var_names=env_vars, 

1212 config_property_names=config_name, 

1213 default=default, 

1214 conversion_func=typecast, 

1215 ), 

1216 ) 

1217 

1218 

1219class SubsetChainConfigFactory: 

1220 """A class for creating backwards compatible configuration chains. 

1221 

1222 This class can be used instead of 

1223 :class:`botocore.configprovider.ConfigChainFactory` to make it honor the 

1224 methods argument to get_config_variable. This class can be used to filter 

1225 out providers that are not in the methods tuple when creating a new config 

1226 chain. 

1227 """ 

1228 

1229 def __init__(self, session, methods, environ=None): 

1230 self._factory = ConfigChainFactory(session, environ) 

1231 self._supported_methods = methods 

1232 

1233 def create_config_chain( 

1234 self, 

1235 instance_name=None, 

1236 env_var_names=None, 

1237 config_property_name=None, 

1238 default=None, 

1239 conversion_func=None, 

1240 ): 

1241 """Build a config chain following the standard botocore pattern. 

1242 

1243 This config chain factory will omit any providers not in the methods 

1244 tuple provided at initialization. For example if given the tuple 

1245 ('instance', 'config',) it will not inject the environment provider 

1246 into the standard config chain. This lets the botocore session support 

1247 the custom ``methods`` argument for all the default botocore config 

1248 variables when calling ``get_config_variable``. 

1249 """ 

1250 if 'instance' not in self._supported_methods: 

1251 instance_name = None 

1252 if 'env' not in self._supported_methods: 

1253 env_var_names = None 

1254 if 'config' not in self._supported_methods: 

1255 config_property_name = None 

1256 return self._factory.create_config_chain( 

1257 instance_name=instance_name, 

1258 env_var_names=env_var_names, 

1259 config_property_names=config_property_name, 

1260 default=default, 

1261 conversion_func=conversion_func, 

1262 ) 

1263 

1264 

1265def get_session(env_vars=None): 

1266 """ 

1267 Return a new session object. 

1268 """ 

1269 return Session(env_vars)