66
77logger = logging .getLogger (__name__ )
88
9+ # Default locations (used for tests and as fallback). Actual resolution is dynamic via _get_auth_ini_file().
910FIREWORKS_CONFIG_DIR = Path .home () / ".fireworks"
1011AUTH_INI_FILE = FIREWORKS_CONFIG_DIR / "auth.ini"
1112
1213
14+ def _get_profile_base_dir () -> Path :
15+ """
16+ Resolve the Fireworks configuration base directory following firectl behavior:
17+ - Default: ~/.fireworks
18+ - If FIREWORKS_PROFILE is set and non-empty: ~/.fireworks/profiles/<profile>
19+ """
20+ profile_name = os .environ .get ("FIREWORKS_PROFILE" , "" ).strip ()
21+ base_dir = Path .home () / ".fireworks"
22+ if profile_name :
23+ base_dir = base_dir / "profiles" / profile_name
24+ return base_dir
25+
26+
27+ def _get_auth_ini_file () -> Path :
28+ """
29+ Determine the auth.ini file path.
30+ Priority:
31+ 1) FIREWORKS_AUTH_FILE env var when set
32+ 2) ~/.fireworks[/profiles/<profile>]/auth.ini (profile driven)
33+ """
34+ auth_file_env = os .environ .get ("FIREWORKS_AUTH_FILE" )
35+ if auth_file_env :
36+ return Path (auth_file_env )
37+ return _get_profile_base_dir () / "auth.ini"
38+
39+
40+ def _is_profile_active () -> bool :
41+ """
42+ Returns True if a specific profile or explicit auth file is active.
43+ In this case, profile-based credentials should take precedence over env vars.
44+ """
45+ if os .environ .get ("FIREWORKS_AUTH_FILE" ):
46+ return True
47+ prof = os .environ .get ("FIREWORKS_PROFILE" , "" ).strip ()
48+ return bool (prof )
49+
50+
1351def _parse_simple_auth_file (file_path : Path ) -> Dict [str , str ]:
1452 """
1553 Parses an auth file with simple key=value lines.
@@ -20,7 +58,7 @@ def _parse_simple_auth_file(file_path: Path) -> Dict[str, str]:
2058 if not file_path .exists ():
2159 return creds
2260 try :
23- with open (file_path , "r" ) as f :
61+ with open (file_path , "r" , encoding = "utf-8" ) as f :
2462 for line in f :
2563 line = line .strip ()
2664 if not line or line .startswith ("#" ) or line .startswith (";" ):
@@ -39,7 +77,7 @@ def _parse_simple_auth_file(file_path: Path) -> Dict[str, str]:
3977 if key in ["api_key" , "account_id" ] and value :
4078 creds [key ] = value
4179 except Exception as e :
42- logger .warning (f "Error during simple parsing of { file_path } : { e } " )
80+ logger .warning ("Error during simple parsing of %s: %s" , str ( file_path ), e )
4381 return creds
4482
4583
@@ -48,44 +86,50 @@ def _get_credential_from_config_file(key_name: str) -> Optional[str]:
4886 Helper to get a specific credential (api_key or account_id) from auth.ini.
4987 Tries simple parsing first, then configparser.
5088 """
51- if not AUTH_INI_FILE .exists ():
89+ auth_ini_path = _get_auth_ini_file ()
90+ if not auth_ini_path .exists ():
5291 return None
5392
5493 # 1. Try simple key-value parsing first
55- simple_creds = _parse_simple_auth_file (AUTH_INI_FILE )
94+ simple_creds = _parse_simple_auth_file (auth_ini_path )
5695 if key_name in simple_creds :
57- logger .debug (f "Using { key_name } from simple key-value parsing of { AUTH_INI_FILE } ." )
96+ logger .debug ("Using %s from simple key-value parsing of %s." , key_name , str ( auth_ini_path ) )
5897 return simple_creds [key_name ]
5998
6099 # 2. Fallback to configparser if not found via simple parsing or if simple parsing failed
61100 # This path will also generate the "no section headers" warning if applicable,
62101 # but only if simple parsing didn't yield the key.
63102 try :
64103 config = configparser .ConfigParser ()
65- config .read (AUTH_INI_FILE )
104+ config .read (auth_ini_path )
66105
67106 # Try [fireworks] section
68107 if "fireworks" in config and config .has_option ("fireworks" , key_name ):
69108 value_from_file = config .get ("fireworks" , key_name )
70109 if value_from_file :
71- logger .debug (f "Using { key_name } from [fireworks] section in { AUTH_INI_FILE } ." )
110+ logger .debug ("Using %s from [fireworks] section in %s." , key_name , str ( auth_ini_path ) )
72111 return value_from_file
73112
74113 # Try default section (configparser might place items without section header here)
75114 if config .has_option (config .default_section , key_name ):
76115 value_from_default = config .get (config .default_section , key_name )
77116 if value_from_default :
78- logger .debug (f"Using { key_name } from default section [{ config .default_section } ] in { AUTH_INI_FILE } ." )
117+ logger .debug (
118+ "Using %s from default section [%s] in %s." ,
119+ key_name ,
120+ config .default_section ,
121+ str (auth_ini_path ),
122+ )
79123 return value_from_default
80124
81125 except configparser .MissingSectionHeaderError :
82126 # This error implies the file is purely key-value, which simple parsing should have handled.
83127 # If simple parsing failed to get the key, then it's likely not there or malformed.
84- logger .debug (f" { AUTH_INI_FILE } has no section headers, and simple parsing did not find { key_name } ." )
128+ logger .debug ("%s has no section headers, and simple parsing did not find %s." , str ( auth_ini_path ), key_name )
85129 except configparser .Error as e_config :
86- logger .warning (f "Configparser error reading { AUTH_INI_FILE } for { key_name } : { e_config } " )
130+ logger .warning ("Configparser error reading %s for %s: %s" , str ( auth_ini_path ), key_name , e_config )
87131 except Exception as e_general :
88- logger .warning (f "Unexpected error reading { AUTH_INI_FILE } for { key_name } : { e_general } " )
132+ logger .warning ("Unexpected error reading %s for %s: %s" , str ( auth_ini_path ), key_name , e_general )
89133
90134 return None
91135
@@ -101,14 +145,24 @@ def get_fireworks_api_key() -> Optional[str]:
101145 Returns:
102146 The API key if found, otherwise None.
103147 """
104- api_key = os .environ .get ("FIREWORKS_API_KEY" )
105- if api_key :
106- logger .debug ("Using FIREWORKS_API_KEY from environment variable." )
107- return api_key
108-
109- api_key_from_file = _get_credential_from_config_file ("api_key" )
110- if api_key_from_file :
111- return api_key_from_file
148+ # If a profile is active, prefer profile file first, then env
149+ if _is_profile_active ():
150+ api_key_from_file = _get_credential_from_config_file ("api_key" )
151+ if api_key_from_file :
152+ return api_key_from_file
153+ api_key = os .environ .get ("FIREWORKS_API_KEY" )
154+ if api_key :
155+ logger .debug ("Using FIREWORKS_API_KEY from environment variable (profile active but file missing)." )
156+ return api_key
157+ else :
158+ # Default behavior: env overrides file
159+ api_key = os .environ .get ("FIREWORKS_API_KEY" )
160+ if api_key :
161+ logger .debug ("Using FIREWORKS_API_KEY from environment variable." )
162+ return api_key
163+ api_key_from_file = _get_credential_from_config_file ("api_key" )
164+ if api_key_from_file :
165+ return api_key_from_file
112166
113167 logger .debug ("Fireworks API key not found in environment variables or auth.ini." )
114168 return None
@@ -125,14 +179,24 @@ def get_fireworks_account_id() -> Optional[str]:
125179 Returns:
126180 The Account ID if found, otherwise None.
127181 """
128- account_id = os .environ .get ("FIREWORKS_ACCOUNT_ID" )
129- if account_id :
130- logger .debug ("Using FIREWORKS_ACCOUNT_ID from environment variable." )
131- return account_id
132-
133- account_id_from_file = _get_credential_from_config_file ("account_id" )
134- if account_id_from_file :
135- return account_id_from_file
182+ # If a profile is active, prefer profile file first, then env
183+ if _is_profile_active ():
184+ account_id_from_file = _get_credential_from_config_file ("account_id" )
185+ if account_id_from_file :
186+ return account_id_from_file
187+ account_id = os .environ .get ("FIREWORKS_ACCOUNT_ID" )
188+ if account_id :
189+ logger .debug ("Using FIREWORKS_ACCOUNT_ID from environment variable (profile active but file missing)." )
190+ return account_id
191+ else :
192+ # Default behavior: env overrides file
193+ account_id = os .environ .get ("FIREWORKS_ACCOUNT_ID" )
194+ if account_id :
195+ logger .debug ("Using FIREWORKS_ACCOUNT_ID from environment variable." )
196+ return account_id
197+ account_id_from_file = _get_credential_from_config_file ("account_id" )
198+ if account_id_from_file :
199+ return account_id_from_file
136200
137201 logger .debug ("Fireworks Account ID not found in environment variables or auth.ini." )
138202 return None
@@ -152,5 +216,5 @@ def get_fireworks_api_base() -> str:
152216 if os .environ .get ("FIREWORKS_API_BASE" ):
153217 logger .debug ("Using FIREWORKS_API_BASE from environment variable." )
154218 else :
155- logger .debug (f "FIREWORKS_API_BASE not set in environment, defaulting to { api_base } ." )
219+ logger .debug ("FIREWORKS_API_BASE not set in environment, defaulting to %s." , api_base )
156220 return api_base
0 commit comments