11"""
2- Tests for api_key from_env configuration feature
2+ Tests for api_key ${VAR} environment variable substitution in configuration.
33"""
44
55import os
66import tempfile
77import unittest
88
9- from openevolve .config import Config , LLMModelConfig
9+ from openevolve .config import Config , LLMModelConfig , _resolve_env_var
1010
1111
12- class TestApiKeyFromEnv (unittest .TestCase ):
13- """Tests for api_key from_env parameter handling in configuration """
12+ class TestEnvVarSubstitution (unittest .TestCase ):
13+ """Tests for ${VAR} environment variable substitution in api_key fields """
1414
1515 def setUp (self ):
1616 """Set up test environment variables"""
@@ -23,9 +23,32 @@ def tearDown(self):
2323 if self .test_env_var in os .environ :
2424 del os .environ [self .test_env_var ]
2525
26- def test_api_key_from_env_in_model_config (self ):
27- """Test that api_key can be loaded from environment variable via from_env"""
28- model_config = LLMModelConfig (name = "test-model" , api_key = {"from_env" : self .test_env_var })
26+ def test_resolve_env_var_with_match (self ):
27+ """Test that _resolve_env_var resolves ${VAR} syntax"""
28+ result = _resolve_env_var (f"${{{ self .test_env_var } }}" )
29+ self .assertEqual (result , self .test_api_key )
30+
31+ def test_resolve_env_var_no_match (self ):
32+ """Test that strings without ${VAR} are returned unchanged"""
33+ result = _resolve_env_var ("regular-api-key" )
34+ self .assertEqual (result , "regular-api-key" )
35+
36+ def test_resolve_env_var_none (self ):
37+ """Test that None is returned unchanged"""
38+ result = _resolve_env_var (None )
39+ self .assertIsNone (result )
40+
41+ def test_resolve_env_var_missing_var (self ):
42+ """Test that missing environment variable raises ValueError"""
43+ with self .assertRaises (ValueError ) as context :
44+ _resolve_env_var ("${NONEXISTENT_ENV_VAR_12345}" )
45+
46+ self .assertIn ("NONEXISTENT_ENV_VAR_12345" , str (context .exception ))
47+ self .assertIn ("is not set" , str (context .exception ))
48+
49+ def test_api_key_env_var_in_model_config (self ):
50+ """Test that api_key ${VAR} works in LLMModelConfig"""
51+ model_config = LLMModelConfig (name = "test-model" , api_key = f"${{{ self .test_env_var } }}" )
2952
3053 self .assertEqual (model_config .api_key , self .test_api_key )
3154
@@ -42,28 +65,13 @@ def test_api_key_none(self):
4265
4366 self .assertIsNone (model_config .api_key )
4467
45- def test_api_key_from_env_missing_env_var (self ):
46- """Test that missing environment variable raises ValueError"""
47- with self .assertRaises (ValueError ) as context :
48- LLMModelConfig (name = "test-model" , api_key = {"from_env" : "NONEXISTENT_ENV_VAR_12345" })
49-
50- self .assertIn ("NONEXISTENT_ENV_VAR_12345" , str (context .exception ))
51- self .assertIn ("is not set" , str (context .exception ))
52-
53- def test_api_key_dict_without_from_env_key (self ):
54- """Test that dict without from_env key raises ValueError"""
55- with self .assertRaises (ValueError ) as context :
56- LLMModelConfig (name = "test-model" , api_key = {"wrong_key" : "value" })
57-
58- self .assertIn ("from_env" , str (context .exception ))
59-
60- def test_api_key_from_env_in_llm_config (self ):
61- """Test that api_key from_env works at LLM config level"""
68+ def test_api_key_env_var_in_llm_config (self ):
69+ """Test that api_key ${VAR} works at LLM config level"""
6270 yaml_config = {
6371 "log_level" : "INFO" ,
6472 "llm" : {
6573 "api_base" : "https://api.openai.com/v1" ,
66- "api_key" : { "from_env" : self .test_env_var },
74+ "api_key" : f"${{ { self .test_env_var } }}" ,
6775 "models" : [{"name" : "test-model" , "weight" : 1.0 }],
6876 },
6977 }
@@ -74,8 +82,8 @@ def test_api_key_from_env_in_llm_config(self):
7482 # Models should inherit the resolved api_key
7583 self .assertEqual (config .llm .models [0 ].api_key , self .test_api_key )
7684
77- def test_api_key_from_env_per_model (self ):
78- """Test that api_key from_env can be specified per model"""
85+ def test_api_key_env_var_per_model (self ):
86+ """Test that api_key ${VAR} can be specified per model"""
7987 # Set up a second env var for testing
8088 second_env_var = "TEST_OPENEVOLVE_API_KEY_2"
8189 second_api_key = "second-secret-key-67890"
@@ -90,9 +98,13 @@ def test_api_key_from_env_per_model(self):
9098 {
9199 "name" : "model-1" ,
92100 "weight" : 1.0 ,
93- "api_key" : {"from_env" : self .test_env_var },
101+ "api_key" : f"${{{ self .test_env_var } }}" ,
102+ },
103+ {
104+ "name" : "model-2" ,
105+ "weight" : 0.5 ,
106+ "api_key" : f"${{{ second_env_var } }}" ,
94107 },
95- {"name" : "model-2" , "weight" : 0.5 , "api_key" : {"from_env" : second_env_var }},
96108 ],
97109 },
98110 }
@@ -105,8 +117,8 @@ def test_api_key_from_env_per_model(self):
105117 if second_env_var in os .environ :
106118 del os .environ [second_env_var ]
107119
108- def test_api_key_from_env_in_evaluator_models (self ):
109- """Test that api_key from_env works in evaluator_models"""
120+ def test_api_key_env_var_in_evaluator_models (self ):
121+ """Test that api_key ${VAR} works in evaluator_models"""
110122 yaml_config = {
111123 "log_level" : "INFO" ,
112124 "llm" : {
@@ -116,7 +128,7 @@ def test_api_key_from_env_in_evaluator_models(self):
116128 {
117129 "name" : "evaluator-model" ,
118130 "weight" : 1.0 ,
119- "api_key" : { "from_env" : self .test_env_var },
131+ "api_key" : f"${{ { self .test_env_var } }}" ,
120132 }
121133 ],
122134 },
@@ -126,14 +138,13 @@ def test_api_key_from_env_in_evaluator_models(self):
126138
127139 self .assertEqual (config .llm .evaluator_models [0 ].api_key , self .test_api_key )
128140
129- def test_yaml_file_loading_with_from_env (self ):
130- """Test loading api_key from_env from actual YAML file"""
141+ def test_yaml_file_loading_with_env_var (self ):
142+ """Test loading api_key ${VAR} from actual YAML file"""
131143 yaml_content = f"""
132144log_level: INFO
133145llm:
134146 api_base: https://api.openai.com/v1
135- api_key:
136- from_env: { self .test_env_var }
147+ api_key: ${{{ self .test_env_var } }}
137148 models:
138149 - name: test-model
139150 weight: 1.0
@@ -150,7 +161,7 @@ def test_yaml_file_loading_with_from_env(self):
150161 os .unlink (f .name )
151162
152163 def test_mixed_api_key_sources (self ):
153- """Test mixing direct api_key and from_env in same config"""
164+ """Test mixing direct api_key and ${VAR} in same config"""
154165 yaml_config = {
155166 "log_level" : "INFO" ,
156167 "llm" : {
@@ -160,9 +171,13 @@ def test_mixed_api_key_sources(self):
160171 {
161172 "name" : "model-with-env" ,
162173 "weight" : 1.0 ,
163- "api_key" : {"from_env" : self .test_env_var },
174+ "api_key" : f"${{{ self .test_env_var } }}" ,
175+ },
176+ {
177+ "name" : "model-with-direct" ,
178+ "weight" : 0.5 ,
179+ "api_key" : "model-direct-key" ,
164180 },
165- {"name" : "model-with-direct" , "weight" : 0.5 , "api_key" : "model-direct-key" },
166181 ],
167182 },
168183 }
0 commit comments