@@ -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,12 @@ 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+ # Determine which profile to use based on priority:
488+ # 1. Command-line option (profile parameter)
489+ # 2. Environment variable (AWS_PROFILE)
490+ # 3. Default to 'default' if neither is specified
491+ if profile is None :
492+ profile = base_unicodise (os .environ .get ('AWS_PROFILE' , "default" ))
486493 debug ("Using AWS profile '%s'" % (profile ))
487494
488495 # get_key - helper function to read the aws profile credentials
@@ -559,8 +566,23 @@ def option_list(self):
559566 retval .append (option )
560567 return retval
561568
562- def read_config_file (self , configfile ):
563- cp = ConfigParser (configfile )
569+ def read_config_file (self , configfile , profile = None ):
570+ # Determine which profile to use based on priority:
571+ # 1. Command-line option (profile parameter)
572+ # 2. Environment variable (AWS_PROFILE)
573+ # 3. Default to 'default' if neither is specified
574+ if profile is None :
575+ profile = os .environ .get ('AWS_PROFILE' , 'default' )
576+
577+ # Use the determined profile as the section name
578+ sections = [profile ]
579+ cp = ConfigParser (configfile , sections )
580+
581+ # If the specified profile section doesn't exist,
582+ # fall back to the default section
583+ if not cp .cfg :
584+ cp = ConfigParser (configfile , ["default" ])
585+
564586 for option in self .option_list ():
565587 _option = cp .get (option )
566588 if _option is not None :
@@ -655,20 +677,29 @@ def parse_file(self, file, sections = []):
655677 debug ("ConfigParser: Reading file '%s'" % file )
656678 if type (sections ) != type ([]):
657679 sections = [sections ]
658- in_our_section = True
680+
681+ if sections :
682+ debug ("ConfigParser: Looking for sections: %s" % sections )
683+ else :
684+ debug ("ConfigParser: Reading default section" )
685+
686+ in_our_section = len (sections ) == 0 # If no sections specified, read all
687+ current_section = "default"
659688 r_comment = re .compile (r'^\s*#.*' )
660689 r_empty = re .compile (r'^\s*$' )
661690 r_section = re .compile (r'^\[([^\]]+)\]' )
662691 r_data = re .compile (r'^\s*(?P<key>\w+)\s*=\s*(?P<value>.*)' )
663692 r_quotes = re .compile (r'^"(.*)"\s*$' )
693+
664694 with io .open (file , "r" , encoding = self .get ('encoding' , 'UTF-8' )) as fp :
665695 for line in fp :
666696 if r_comment .match (line ) or r_empty .match (line ):
667697 continue
668698 is_section = r_section .match (line )
669699 if is_section :
670- section = is_section .groups ()[0 ]
671- in_our_section = (section in sections ) or (len (sections ) == 0 )
700+ current_section = is_section .groups ()[0 ]
701+ in_our_section = (current_section in sections ) or (len (sections ) == 0 )
702+ debug ("ConfigParser: Found section '%s', reading: %s" % (current_section , in_our_section ))
672703 continue
673704 is_data = r_data .match (line )
674705 if is_data and in_our_section :
@@ -682,6 +713,9 @@ def parse_file(self, file, sections = []):
682713 print_value = data ["value" ]
683714 debug ("ConfigParser: %s->%s" % (data ["key" ], print_value ))
684715 continue
716+ if is_data and not in_our_section :
717+ # Skip data in sections we're not interested in
718+ continue
685719 warning ("Ignoring invalid line in '%s': %s" % (file , line ))
686720
687721 def __getitem__ (self , name ):
0 commit comments