Skip to content

Commit 579a3bc

Browse files
committed
fxies
1 parent 0ac6bc4 commit 579a3bc

File tree

3 files changed

+153
-1
lines changed

3 files changed

+153
-1
lines changed

openevolve/controller.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,8 @@ async def run(
300300
# Initialize improved parallel processing
301301
try:
302302
self.parallel_controller = ProcessParallelController(
303-
self.config, self.evaluation_file, self.database, self.evolution_tracer
303+
self.config, self.evaluation_file, self.database, self.evolution_tracer,
304+
file_suffix=self.file_extension
304305
)
305306

306307
# Set up signal handlers for graceful shutdown

openevolve/process_parallel.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ def _lazy_init_worker_components():
125125
evaluator_llm,
126126
evaluator_prompt,
127127
database=None, # No shared database in worker
128+
suffix=getattr(_worker_config, 'file_suffix', '.py'),
128129
)
129130

130131

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
"""
2+
Test file extension preservation across iterations
3+
"""
4+
5+
import os
6+
import tempfile
7+
import unittest
8+
from pathlib import Path
9+
from unittest.mock import patch, MagicMock
10+
11+
from openevolve.config import Config, EvaluatorConfig, DatabaseConfig, LLMConfig, PromptConfig
12+
from openevolve.controller import OpenEvolve
13+
from openevolve.evaluator import Evaluator
14+
from openevolve.process_parallel import ProcessParallelController, _worker_init, _lazy_init_worker_components
15+
16+
17+
class TestFileExtensionPreservation(unittest.TestCase):
18+
"""Test that file extensions are preserved across iterations"""
19+
20+
def setUp(self):
21+
"""Set up test fixtures"""
22+
self.temp_dir = tempfile.mkdtemp()
23+
24+
# Create test config
25+
self.config = Config(
26+
max_iterations=5,
27+
language="cpp",
28+
llm=LLMConfig(models=[]),
29+
database=DatabaseConfig(population_size=10, num_islands=2),
30+
evaluator=EvaluatorConfig(parallel_evaluations=1),
31+
prompt=PromptConfig(),
32+
)
33+
34+
def tearDown(self):
35+
"""Clean up test fixtures"""
36+
import shutil
37+
shutil.rmtree(self.temp_dir, ignore_errors=True)
38+
39+
def test_controller_preserves_file_extension(self):
40+
"""Test that the controller properly extracts and stores file extension"""
41+
# Test Path extraction directly
42+
test_files = [
43+
"test.cpp",
44+
"test.rs",
45+
"test.py",
46+
"test.r"
47+
]
48+
49+
for filename in test_files:
50+
with self.subTest(filename=filename):
51+
expected_ext = Path(filename).suffix
52+
actual_ext = os.path.splitext(filename)[1]
53+
self.assertEqual(actual_ext, expected_ext)
54+
55+
def test_evaluator_uses_correct_suffix(self):
56+
"""Test that the evaluator uses the correct file suffix"""
57+
# Test with different file extensions
58+
test_cases = [
59+
(".py", "python"),
60+
(".cpp", "cpp"),
61+
(".rs", "rust"),
62+
(".r", "r"),
63+
(".js", "javascript"),
64+
(".metal", "metal")
65+
]
66+
67+
for suffix, language in test_cases:
68+
with self.subTest(suffix=suffix, language=language):
69+
# Create a temp evaluator file for this test
70+
temp_eval = os.path.join(self.temp_dir, f"eval_{language}.py")
71+
with open(temp_eval, "w") as f:
72+
f.write("def evaluate(path): return {'score': 0.5}")
73+
74+
# Create evaluator with specific suffix
75+
config = EvaluatorConfig()
76+
evaluator = Evaluator(config, temp_eval, suffix=suffix)
77+
78+
# Check that the suffix is correctly stored
79+
self.assertEqual(evaluator.program_suffix, suffix)
80+
81+
def test_worker_suffix_access(self):
82+
"""Test that worker can access file suffix from config"""
83+
# Create a mock config object with file_suffix
84+
mock_config = MagicMock()
85+
mock_config.file_suffix = ".cpp"
86+
87+
# Test getattr access pattern used in the code
88+
suffix = getattr(mock_config, 'file_suffix', '.py')
89+
self.assertEqual(suffix, ".cpp")
90+
91+
# Test default fallback
92+
mock_config_no_suffix = MagicMock()
93+
del mock_config_no_suffix.file_suffix
94+
suffix_default = getattr(mock_config_no_suffix, 'file_suffix', '.py')
95+
self.assertEqual(suffix_default, ".py")
96+
97+
def test_process_parallel_controller_passes_suffix(self):
98+
"""Test that ProcessParallelController correctly passes file suffix"""
99+
# Create a mock database
100+
mock_database = MagicMock()
101+
102+
# Create ProcessParallelController with specific file suffix
103+
controller = ProcessParallelController(
104+
self.config,
105+
"dummy_evaluator.py",
106+
mock_database,
107+
file_suffix=".rs"
108+
)
109+
110+
# Check that file suffix is stored
111+
self.assertEqual(controller.file_suffix, ".rs")
112+
113+
def test_file_extension_mapping(self):
114+
"""Test that different file extensions are handled correctly"""
115+
test_files = [
116+
("test.py", ".py"),
117+
("test.cpp", ".cpp"),
118+
("test.rs", ".rs"),
119+
("test.r", ".r"),
120+
("test.js", ".js"),
121+
("test.metal", ".metal")
122+
]
123+
124+
for filename, expected_extension in test_files:
125+
with self.subTest(filename=filename):
126+
# Test Path suffix extraction
127+
actual_extension = Path(filename).suffix
128+
self.assertEqual(actual_extension, expected_extension)
129+
130+
def test_evaluator_temp_file_creation(self):
131+
"""Test that evaluator creates temp files with correct suffix"""
132+
# Create a temp evaluator file
133+
temp_eval = os.path.join(self.temp_dir, "eval_test.py")
134+
with open(temp_eval, "w") as f:
135+
f.write("def evaluate(path): return {'score': 0.5}")
136+
137+
# Test different suffixes
138+
test_suffixes = [".py", ".cpp", ".rs", ".r", ".js"]
139+
140+
for suffix in test_suffixes:
141+
with self.subTest(suffix=suffix):
142+
config = EvaluatorConfig()
143+
evaluator = Evaluator(config, temp_eval, suffix=suffix)
144+
145+
# Verify suffix is stored correctly
146+
self.assertEqual(evaluator.program_suffix, suffix)
147+
148+
149+
if __name__ == "__main__":
150+
unittest.main()

0 commit comments

Comments
 (0)