From 0ac6bc4e9d02adef6461baa4804238d612b87230 Mon Sep 17 00:00:00 2001 From: Asankhaya Sharma Date: Tue, 16 Sep 2025 13:50:16 +0800 Subject: [PATCH 1/4] Update process_parallel.py --- openevolve/process_parallel.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openevolve/process_parallel.py b/openevolve/process_parallel.py index 04aa0db3..2c9e934c 100644 --- a/openevolve/process_parallel.py +++ b/openevolve/process_parallel.py @@ -274,11 +274,12 @@ def _run_iteration_worker( class ProcessParallelController: """Controller for process-based parallel evolution""" - def __init__(self, config: Config, evaluation_file: str, database: ProgramDatabase, evolution_tracer=None): + def __init__(self, config: Config, evaluation_file: str, database: ProgramDatabase, evolution_tracer=None, file_suffix: str = ".py"): self.config = config self.evaluation_file = evaluation_file self.database = database self.evolution_tracer = evolution_tracer + self.file_suffix = file_suffix self.executor: Optional[ProcessPoolExecutor] = None self.shutdown_event = mp.Event() @@ -326,6 +327,7 @@ def _serialize_config(self, config: Config) -> dict: "diff_based_evolution": config.diff_based_evolution, "max_code_length": config.max_code_length, "language": config.language, + "file_suffix": self.file_suffix, } def start(self) -> None: From 579a3bc4d6f078751fc02c70bdede95f339ca3e3 Mon Sep 17 00:00:00 2001 From: Asankhaya Sharma Date: Tue, 16 Sep 2025 13:54:57 +0800 Subject: [PATCH 2/4] fxies --- openevolve/controller.py | 3 +- openevolve/process_parallel.py | 1 + tests/test_file_extension_preservation.py | 150 ++++++++++++++++++++++ 3 files changed, 153 insertions(+), 1 deletion(-) create mode 100644 tests/test_file_extension_preservation.py diff --git a/openevolve/controller.py b/openevolve/controller.py index 2e1d67c0..69c2b16f 100644 --- a/openevolve/controller.py +++ b/openevolve/controller.py @@ -300,7 +300,8 @@ async def run( # Initialize improved parallel processing try: self.parallel_controller = ProcessParallelController( - self.config, self.evaluation_file, self.database, self.evolution_tracer + self.config, self.evaluation_file, self.database, self.evolution_tracer, + file_suffix=self.file_extension ) # Set up signal handlers for graceful shutdown diff --git a/openevolve/process_parallel.py b/openevolve/process_parallel.py index 2c9e934c..d5eaa04f 100644 --- a/openevolve/process_parallel.py +++ b/openevolve/process_parallel.py @@ -125,6 +125,7 @@ def _lazy_init_worker_components(): evaluator_llm, evaluator_prompt, database=None, # No shared database in worker + suffix=getattr(_worker_config, 'file_suffix', '.py'), ) diff --git a/tests/test_file_extension_preservation.py b/tests/test_file_extension_preservation.py new file mode 100644 index 00000000..108959d1 --- /dev/null +++ b/tests/test_file_extension_preservation.py @@ -0,0 +1,150 @@ +""" +Test file extension preservation across iterations +""" + +import os +import tempfile +import unittest +from pathlib import Path +from unittest.mock import patch, MagicMock + +from openevolve.config import Config, EvaluatorConfig, DatabaseConfig, LLMConfig, PromptConfig +from openevolve.controller import OpenEvolve +from openevolve.evaluator import Evaluator +from openevolve.process_parallel import ProcessParallelController, _worker_init, _lazy_init_worker_components + + +class TestFileExtensionPreservation(unittest.TestCase): + """Test that file extensions are preserved across iterations""" + + def setUp(self): + """Set up test fixtures""" + self.temp_dir = tempfile.mkdtemp() + + # Create test config + self.config = Config( + max_iterations=5, + language="cpp", + llm=LLMConfig(models=[]), + database=DatabaseConfig(population_size=10, num_islands=2), + evaluator=EvaluatorConfig(parallel_evaluations=1), + prompt=PromptConfig(), + ) + + def tearDown(self): + """Clean up test fixtures""" + import shutil + shutil.rmtree(self.temp_dir, ignore_errors=True) + + def test_controller_preserves_file_extension(self): + """Test that the controller properly extracts and stores file extension""" + # Test Path extraction directly + test_files = [ + "test.cpp", + "test.rs", + "test.py", + "test.r" + ] + + for filename in test_files: + with self.subTest(filename=filename): + expected_ext = Path(filename).suffix + actual_ext = os.path.splitext(filename)[1] + self.assertEqual(actual_ext, expected_ext) + + def test_evaluator_uses_correct_suffix(self): + """Test that the evaluator uses the correct file suffix""" + # Test with different file extensions + test_cases = [ + (".py", "python"), + (".cpp", "cpp"), + (".rs", "rust"), + (".r", "r"), + (".js", "javascript"), + (".metal", "metal") + ] + + for suffix, language in test_cases: + with self.subTest(suffix=suffix, language=language): + # Create a temp evaluator file for this test + temp_eval = os.path.join(self.temp_dir, f"eval_{language}.py") + with open(temp_eval, "w") as f: + f.write("def evaluate(path): return {'score': 0.5}") + + # Create evaluator with specific suffix + config = EvaluatorConfig() + evaluator = Evaluator(config, temp_eval, suffix=suffix) + + # Check that the suffix is correctly stored + self.assertEqual(evaluator.program_suffix, suffix) + + def test_worker_suffix_access(self): + """Test that worker can access file suffix from config""" + # Create a mock config object with file_suffix + mock_config = MagicMock() + mock_config.file_suffix = ".cpp" + + # Test getattr access pattern used in the code + suffix = getattr(mock_config, 'file_suffix', '.py') + self.assertEqual(suffix, ".cpp") + + # Test default fallback + mock_config_no_suffix = MagicMock() + del mock_config_no_suffix.file_suffix + suffix_default = getattr(mock_config_no_suffix, 'file_suffix', '.py') + self.assertEqual(suffix_default, ".py") + + def test_process_parallel_controller_passes_suffix(self): + """Test that ProcessParallelController correctly passes file suffix""" + # Create a mock database + mock_database = MagicMock() + + # Create ProcessParallelController with specific file suffix + controller = ProcessParallelController( + self.config, + "dummy_evaluator.py", + mock_database, + file_suffix=".rs" + ) + + # Check that file suffix is stored + self.assertEqual(controller.file_suffix, ".rs") + + def test_file_extension_mapping(self): + """Test that different file extensions are handled correctly""" + test_files = [ + ("test.py", ".py"), + ("test.cpp", ".cpp"), + ("test.rs", ".rs"), + ("test.r", ".r"), + ("test.js", ".js"), + ("test.metal", ".metal") + ] + + for filename, expected_extension in test_files: + with self.subTest(filename=filename): + # Test Path suffix extraction + actual_extension = Path(filename).suffix + self.assertEqual(actual_extension, expected_extension) + + def test_evaluator_temp_file_creation(self): + """Test that evaluator creates temp files with correct suffix""" + # Create a temp evaluator file + temp_eval = os.path.join(self.temp_dir, "eval_test.py") + with open(temp_eval, "w") as f: + f.write("def evaluate(path): return {'score': 0.5}") + + # Test different suffixes + test_suffixes = [".py", ".cpp", ".rs", ".r", ".js"] + + for suffix in test_suffixes: + with self.subTest(suffix=suffix): + config = EvaluatorConfig() + evaluator = Evaluator(config, temp_eval, suffix=suffix) + + # Verify suffix is stored correctly + self.assertEqual(evaluator.program_suffix, suffix) + + +if __name__ == "__main__": + unittest.main() \ No newline at end of file From 3f544a5024e850e7bd0f6369e33c1d77de4bff8b Mon Sep 17 00:00:00 2001 From: Asankhaya Sharma Date: Tue, 16 Sep 2025 14:32:51 +0800 Subject: [PATCH 3/4] fixes --- examples/r_robust_regression/config.yaml | 1 + examples/rust_adaptive_sort/config.yaml | 1 + openevolve/config.py | 1 + openevolve/controller.py | 6 +++++- 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/examples/r_robust_regression/config.yaml b/examples/r_robust_regression/config.yaml index 4cba3040..0ad01011 100644 --- a/examples/r_robust_regression/config.yaml +++ b/examples/r_robust_regression/config.yaml @@ -4,6 +4,7 @@ max_iterations: 100 checkpoint_interval: 10 log_level: "INFO" +file_suffix: ".r" # LLM configuration llm: diff --git a/examples/rust_adaptive_sort/config.yaml b/examples/rust_adaptive_sort/config.yaml index 49794289..2d48e94d 100644 --- a/examples/rust_adaptive_sort/config.yaml +++ b/examples/rust_adaptive_sort/config.yaml @@ -4,6 +4,7 @@ max_iterations: 150 checkpoint_interval: 15 log_level: "INFO" +file_suffix: ".rs" # LLM configuration llm: diff --git a/openevolve/config.py b/openevolve/config.py index 4a31f8d0..affc1e25 100644 --- a/openevolve/config.py +++ b/openevolve/config.py @@ -337,6 +337,7 @@ class Config: log_dir: Optional[str] = None random_seed: Optional[int] = 42 language: str = None + file_suffix: str = ".py" # Component configurations llm: LLMConfig = field(default_factory=LLMConfig) diff --git a/openevolve/controller.py b/openevolve/controller.py index 69c2b16f..521659a9 100644 --- a/openevolve/controller.py +++ b/openevolve/controller.py @@ -138,6 +138,10 @@ def __init__( if not self.file_extension.startswith("."): self.file_extension = f".{self.file_extension}" + # Set the file_suffix in config (can be overridden in YAML) + if not hasattr(self.config, 'file_suffix') or self.config.file_suffix == ".py": + self.config.file_suffix = self.file_extension + # Initialize components self.llm_ensemble = LLMEnsemble(self.config.llm.models) self.llm_evaluator_ensemble = LLMEnsemble(self.config.llm.evaluator_models) @@ -301,7 +305,7 @@ async def run( try: self.parallel_controller = ProcessParallelController( self.config, self.evaluation_file, self.database, self.evolution_tracer, - file_suffix=self.file_extension + file_suffix=self.config.file_suffix ) # Set up signal handlers for graceful shutdown From a2eea2f1b8923f213cf9673ff9543e53bad94e62 Mon Sep 17 00:00:00 2001 From: Asankhaya Sharma Date: Wed, 17 Sep 2025 06:50:42 +0800 Subject: [PATCH 4/4] Update _version.py --- openevolve/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openevolve/_version.py b/openevolve/_version.py index c94b685f..d68ffb7b 100644 --- a/openevolve/_version.py +++ b/openevolve/_version.py @@ -1,3 +1,3 @@ """Version information for openevolve package.""" -__version__ = "0.2.14" +__version__ = "0.2.15"