@@ -261,18 +261,19 @@ class Config(object):
261261 max_retries = 5
262262
263263 ## Creating a singleton
264- def __new__ (self , configfile = None , access_key = None , secret_key = None , access_token = None ):
264+ def __new__ (self , configfile = None , access_key = None , secret_key = None , access_token = None , profile = None ):
265265 if self ._instance is None :
266266 self ._instance = object .__new__ (self )
267267 return self ._instance
268268
269- def __init__ (self , configfile = None , access_key = None , secret_key = None , access_token = None ):
269+ def __init__ (self , configfile = None , access_key = None , secret_key = None , access_token = None , profile = None ):
270270 if configfile :
271+ debug ("Config: Initializing with config file '%s', profile '%s'" % (configfile , profile ))
271272 try :
272- self .read_config_file (configfile )
273+ self .read_config_file (configfile , profile )
273274 except IOError :
274275 if 'AWS_SHARED_CREDENTIALS_FILE' in os .environ or 'AWS_CREDENTIAL_FILE' in os .environ or 'AWS_PROFILE' in os .environ :
275- self .aws_credential_file ()
276+ self .aws_credential_file (profile )
276277
277278 # override these if passed on the command-line
278279 # Allow blank secret_key
@@ -335,7 +336,7 @@ def role_config(self):
335336 '%s=%s' % (k , s3_quote (v , unicode_output = True ))
336337 for k , v in params .items ()
337338 ])
338- sts_endpoint = os .environ .get ("AWS_STS_ENDPOINT" , sts_endpoint )
339+ sts_endpoint = os .environ .get ("AWS_STS_ENDPOINT" , sts_endpoint )
339340 if os .environ .get ("AWS_STS_REGIONAL_ENDPOINTS" ) == "regional" :
340341 # Check if the AWS_REGION variable is available to use as a region.
341342 region = os .environ .get ("AWS_REGION" )
@@ -441,7 +442,7 @@ def role_refresh(self):
441442 except Exception :
442443 warning ("Could not refresh role" )
443444
444- def aws_credential_file (self ):
445+ def aws_credential_file (self , profile = None ):
445446 try :
446447 aws_credential_file = os .path .expanduser ('~/.aws/credentials' )
447448 credential_file_from_env = os .environ .get ('AWS_SHARED_CREDENTIALS_FILE' ) \
@@ -450,6 +451,7 @@ def aws_credential_file(self):
450451 os .path .isfile (credential_file_from_env ):
451452 aws_credential_file = base_unicodise (credential_file_from_env )
452453 elif not os .path .isfile (aws_credential_file ):
454+ debug ("AWS credentials file not found at %s" % aws_credential_file )
453455 return
454456
455457 config = PyConfigParser ()
@@ -482,7 +484,8 @@ def aws_credential_file(self):
482484 "Error reading aws_credential_file "
483485 "(%s): %s" % (aws_credential_file , str (exc )))
484486
485- profile = base_unicodise (os .environ .get ('AWS_PROFILE' , "default" ))
487+ # Use the profile from the parameter if provided, otherwise use the environment variable or default
488+ profile = profile or base_unicodise (os .environ .get ('AWS_PROFILE' , "default" ))
486489 debug ("Using AWS profile '%s'" % (profile ))
487490
488491 # get_key - helper function to read the aws profile credentials
@@ -559,8 +562,16 @@ def option_list(self):
559562 retval .append (option )
560563 return retval
561564
562- def read_config_file (self , configfile ):
563- cp = ConfigParser (configfile )
565+ def read_config_file (self , configfile , profile = None ):
566+ # If profile is specified, use it as the section name
567+ sections = [profile ] if profile else []
568+ cp = ConfigParser (configfile , sections )
569+
570+ # If no profile is specified or the profile section doesn't exist,
571+ # fall back to the default section
572+ if not profile or not cp .cfg :
573+ cp = ConfigParser (configfile , [])
574+
564575 for option in self .option_list ():
565576 _option = cp .get (option )
566577 if _option is not None :
@@ -655,20 +666,29 @@ def parse_file(self, file, sections = []):
655666 debug ("ConfigParser: Reading file '%s'" % file )
656667 if type (sections ) != type ([]):
657668 sections = [sections ]
658- in_our_section = True
669+
670+ if sections :
671+ debug ("ConfigParser: Looking for sections: %s" % sections )
672+ else :
673+ debug ("ConfigParser: Reading default section" )
674+
675+ in_our_section = len (sections ) == 0 # If no sections specified, read all
676+ current_section = "default"
659677 r_comment = re .compile (r'^\s*#.*' )
660678 r_empty = re .compile (r'^\s*$' )
661679 r_section = re .compile (r'^\[([^\]]+)\]' )
662680 r_data = re .compile (r'^\s*(?P<key>\w+)\s*=\s*(?P<value>.*)' )
663681 r_quotes = re .compile (r'^"(.*)"\s*$' )
682+
664683 with io .open (file , "r" , encoding = self .get ('encoding' , 'UTF-8' )) as fp :
665684 for line in fp :
666685 if r_comment .match (line ) or r_empty .match (line ):
667686 continue
668687 is_section = r_section .match (line )
669688 if is_section :
670- section = is_section .groups ()[0 ]
671- in_our_section = (section in sections ) or (len (sections ) == 0 )
689+ current_section = is_section .groups ()[0 ]
690+ in_our_section = (current_section in sections ) or (len (sections ) == 0 )
691+ debug ("ConfigParser: Found section '%s', reading: %s" % (current_section , in_our_section ))
672692 continue
673693 is_data = r_data .match (line )
674694 if is_data and in_our_section :
@@ -682,6 +702,9 @@ def parse_file(self, file, sections = []):
682702 print_value = data ["value" ]
683703 debug ("ConfigParser: %s->%s" % (data ["key" ], print_value ))
684704 continue
705+ if is_data and not in_our_section :
706+ # Skip data in sections we're not interested in
707+ continue
685708 warning ("Ignoring invalid line in '%s': %s" % (file , line ))
686709
687710 def __getitem__ (self , name ):
0 commit comments