Skip to content

Commit a7ff701

Browse files
eleminate the use of flat code for parsing
1 parent 6fc8926 commit a7ff701

File tree

9 files changed

+40
-33
lines changed

9 files changed

+40
-33
lines changed

codeflash/api/aiservice.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,6 @@ def make_ai_service_request(
7373
url = f"{self.base_url}/ai{endpoint}"
7474
if method.upper() == "POST":
7575
json_payload = json.dumps(payload, indent=None, default=pydantic_encoder)
76-
logger.debug(f"========JSON PAYLOAD FOR {url}==============")
77-
logger.debug(json_payload)
78-
logger.debug("======================")
7976
headers = {**self.headers, "Content-Type": "application/json"}
8077
response = requests.post(url, data=json_payload, headers=headers, timeout=timeout)
8178
else:

codeflash/context/code_context_extractor.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,14 +85,14 @@ def get_code_optimization_context(
8585
)
8686

8787
# Handle token limits
88-
final_read_writable_tokens = encoded_tokens_len(final_read_writable_code.flat)
88+
final_read_writable_tokens = encoded_tokens_len(final_read_writable_code.markdown)
8989
if final_read_writable_tokens > optim_token_limit:
9090
raise ValueError("Read-writable code has exceeded token limit, cannot proceed")
9191

9292
# Setup preexisting objects for code replacer
9393
preexisting_objects = set(
9494
chain(
95-
find_preexisting_objects(final_read_writable_code.flat),
95+
*(find_preexisting_objects(codestring.code) for codestring in final_read_writable_code.code_strings),
9696
*(find_preexisting_objects(codestring.code) for codestring in read_only_code_markdown.code_strings),
9797
)
9898
)

codeflash/context/unused_definition_remover.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import ast
44
from collections import defaultdict
55
from dataclasses import dataclass, field
6+
from itertools import chain
67
from pathlib import Path
78
from typing import TYPE_CHECKING, Optional
89

@@ -611,7 +612,9 @@ def _analyze_imports_in_optimized_code(
611612

612613

613614
def detect_unused_helper_functions(
614-
function_to_optimize: FunctionToOptimize, code_context: CodeOptimizationContext, optimized_code: str
615+
function_to_optimize: FunctionToOptimize,
616+
code_context: CodeOptimizationContext,
617+
optimized_code: str | CodeStringsMarkdown,
615618
) -> list[FunctionSource]:
616619
"""Detect helper functions that are no longer called by the optimized entrypoint function.
617620
@@ -624,6 +627,14 @@ def detect_unused_helper_functions(
624627
List of FunctionSource objects representing unused helper functions
625628
626629
"""
630+
if isinstance(optimized_code, CodeStringsMarkdown) and len(optimized_code.code_strings) > 0:
631+
return list(
632+
chain.from_iterable(
633+
detect_unused_helper_functions(function_to_optimize, code_context, code.code)
634+
for code in optimized_code.code_strings
635+
)
636+
)
637+
627638
try:
628639
# Parse the optimized code to analyze function calls and imports
629640
optimized_ast = ast.parse(optimized_code)

codeflash/lsp/beta.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ def generate_tests(server: CodeflashLanguageServer, params: FunctionOptimization
222222
generated_test.generated_original_test_source for generated_test in generated_tests_list.generated_tests
223223
]
224224
optimizations_dict = {
225-
candidate.optimization_id: {"source_code": candidate.source_code.flat, "explanation": candidate.explanation}
225+
candidate.optimization_id: {"source_code": candidate.source_code.markdown, "explanation": candidate.explanation}
226226
for candidate in optimizations_set.control + optimizations_set.experiment
227227
}
228228

@@ -330,7 +330,7 @@ def perform_function_optimization( # noqa: PLR0911
330330
"message": f"No best optimizations found for function {function_to_optimize_qualified_name}",
331331
}
332332

333-
optimized_source = best_optimization.candidate.source_code.flat
333+
optimized_source = best_optimization.candidate.source_code.markdown
334334
speedup = original_code_baseline.runtime / best_optimization.runtime
335335

336336
server.show_message_log(f"Optimization completed for {params.functionName} with {speedup:.2f}x speedup", "Info")

codeflash/models/models.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -157,12 +157,8 @@ class CodeString(BaseModel):
157157
file_path: Optional[Path] = None
158158

159159

160-
# Used to split files by adding a marker at the start of each file followed by the file path.
161-
LINE_SPLITTER_MARKER_PREFIX = "# --codeflash:file--"
162-
163-
164160
def get_code_block_splitter(file_path: Path) -> str:
165-
return f"{LINE_SPLITTER_MARKER_PREFIX}{file_path}"
161+
return f"# file: {file_path}"
166162

167163

168164
markdown_pattern = re.compile(r"```python:([^\n]+)\n(.*?)\n```", re.DOTALL)
@@ -182,6 +178,11 @@ def flat(self) -> str:
182178
Returns:
183179
str: The concatenated code of all blocks with file path annotations.
184180
181+
!! Important !!:
182+
Avoid parsing the flat code with multiple files,
183+
parsing may result in unexpected behavior.
184+
185+
185186
"""
186187
if self._cache.get("flat") is not None:
187188
return self._cache["flat"]

codeflash/optimization/function_optimizer.py

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@
6262
from codeflash.either import Failure, Success, is_successful
6363
from codeflash.models.ExperimentMetadata import ExperimentMetadata
6464
from codeflash.models.models import (
65-
LINE_SPLITTER_MARKER_PREFIX,
6665
BestOptimization,
6766
CodeOptimizationContext,
6867
GeneratedTests,
@@ -171,7 +170,10 @@ def can_be_optimized(self) -> Result[tuple[bool, CodeOptimizationContext, dict[P
171170
helper_code = f.read()
172171
original_helper_code[helper_function_path] = helper_code
173172

174-
if has_any_async_functions(code_context.read_writable_code.flat):
173+
async_code = any(
174+
has_any_async_functions(code_string.code) for code_string in code_context.read_writable_code.code_strings
175+
)
176+
if async_code:
175177
return Failure("Codeflash does not support async functions in the code to optimize.")
176178
# Random here means that we still attempt optimization with a fractional chance to see if
177179
# last time we could not find an optimization, maybe this time we do.
@@ -731,7 +733,7 @@ def replace_function_and_helpers_with_optimized_code(
731733
preexisting_objects=code_context.preexisting_objects,
732734
project_root_path=self.project_root,
733735
)
734-
unused_helpers = detect_unused_helper_functions(self.function_to_optimize, code_context, optimized_code.flat)
736+
unused_helpers = detect_unused_helper_functions(self.function_to_optimize, code_context, optimized_code)
735737

736738
# Revert unused helper functions to their original definitions
737739
if unused_helpers:
@@ -1165,15 +1167,10 @@ def process_review(
11651167
optimized_runtimes_all=optimized_runtime_by_test,
11661168
)
11671169
new_explanation_raw_str = self.aiservice_client.get_new_explanation(
1168-
source_code=code_context.read_writable_code.flat.replace(
1169-
LINE_SPLITTER_MARKER_PREFIX,
1170-
"# file: ", # for better readability
1171-
),
1170+
source_code=code_context.read_writable_code.flat,
11721171
dependency_code=code_context.read_only_context_code,
11731172
trace_id=self.function_trace_id[:-4] + exp_type if self.experiment_id else self.function_trace_id,
1174-
optimized_code=best_optimization.candidate.source_code.flat.replace(
1175-
LINE_SPLITTER_MARKER_PREFIX, "# file: "
1176-
),
1173+
optimized_code=best_optimization.candidate.source_code.flat,
11771174
original_line_profiler_results=original_code_baseline.line_profile_results["str_out"],
11781175
optimized_line_profiler_results=best_optimization.line_profiler_test_results["str_out"],
11791176
original_code_runtime=humanize_runtime(original_code_baseline.runtime),

tests/test_code_context_extractor.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import pytest
1010
from codeflash.context.code_context_extractor import get_code_optimization_context
1111
from codeflash.discovery.functions_to_optimize import FunctionToOptimize
12-
from codeflash.models.models import FunctionParent, get_code_block_splitter
12+
from codeflash.models.models import FunctionParent
1313
from codeflash.optimization.optimizer import Optimizer
1414
from codeflash.code_utils.code_replacer import replace_functions_and_add_imports
1515
from codeflash.code_utils.code_extractor import add_global_assignments

tests/test_code_replacement.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ def totally_new_function(value):
123123

124124
function_name: str = "NewClass.new_function"
125125
preexisting_objects: set[tuple[str, tuple[FunctionParent, ...]]] = find_preexisting_objects(original_code)
126+
print(f"Preexisting objects: {preexisting_objects}")
126127
new_code: str = replace_functions_and_add_imports(
127128
source_code=original_code,
128129
function_names=[function_name],

tests/test_unused_helper_revert.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ def helper_function_2(x):
9292
code_context = ctx_result.unwrap()
9393

9494
# Test unused helper detection
95-
unused_helpers = detect_unused_helper_functions(optimizer.function_to_optimize, code_context, CodeStringsMarkdown.parse_markdown_code(optimized_code).flat)
95+
unused_helpers = detect_unused_helper_functions(optimizer.function_to_optimize, code_context, CodeStringsMarkdown.parse_markdown_code(optimized_code))
9696

9797
# Should detect helper_function_2 as unused
9898
unused_names = {uh.qualified_name for uh in unused_helpers}
@@ -267,7 +267,7 @@ def helper_function_2(x):
267267
original_helper_code = {main_file: main_file.read_text()}
268268

269269
# Test detection - should find no unused helpers
270-
unused_helpers = detect_unused_helper_functions(optimizer.function_to_optimize, code_context, CodeStringsMarkdown.parse_markdown_code(optimized_code).flat)
270+
unused_helpers = detect_unused_helper_functions(optimizer.function_to_optimize, code_context, CodeStringsMarkdown.parse_markdown_code(optimized_code))
271271
assert len(unused_helpers) == 0, "No helpers should be detected as unused"
272272

273273
# Apply optimization
@@ -350,7 +350,7 @@ def entrypoint_function(n):
350350
code_context = ctx_result.unwrap()
351351

352352
# Test unused helper detection
353-
unused_helpers = detect_unused_helper_functions(optimizer.function_to_optimize, code_context, CodeStringsMarkdown.parse_markdown_code(optimized_code).flat)
353+
unused_helpers = detect_unused_helper_functions(optimizer.function_to_optimize, code_context, CodeStringsMarkdown.parse_markdown_code(optimized_code))
354354

355355
# Should detect helper_function_2 as unused
356356
unused_names = {uh.qualified_name for uh in unused_helpers}
@@ -538,7 +538,7 @@ def helper_method_2(self, x):
538538
code_context = ctx_result.unwrap()
539539

540540
# Test unused helper detection
541-
unused_helpers = detect_unused_helper_functions(optimizer.function_to_optimize, code_context, CodeStringsMarkdown.parse_markdown_code(optimized_code).flat)
541+
unused_helpers = detect_unused_helper_functions(optimizer.function_to_optimize, code_context, CodeStringsMarkdown.parse_markdown_code(optimized_code))
542542

543543
# Should detect Calculator.helper_method_2 as unused
544544
unused_names = {uh.qualified_name for uh in unused_helpers}
@@ -683,7 +683,7 @@ def process_data(self, n):
683683
code_context = ctx_result.unwrap()
684684

685685
# Test unused helper detection
686-
unused_helpers = detect_unused_helper_functions(optimizer.function_to_optimize, code_context, CodeStringsMarkdown.parse_markdown_code(optimized_code).flat)
686+
unused_helpers = detect_unused_helper_functions(optimizer.function_to_optimize, code_context, CodeStringsMarkdown.parse_markdown_code(optimized_code))
687687

688688
# Should detect external_helper_2 as unused
689689
unused_names = {uh.qualified_name for uh in unused_helpers}
@@ -889,7 +889,7 @@ def local_helper(self, x):
889889
]
890890
},
891891
)(),
892-
CodeStringsMarkdown.parse_markdown_code(optimized_code).flat,
892+
CodeStringsMarkdown.parse_markdown_code(optimized_code),
893893
)
894894

895895
# Should detect global_helper_2 as unused
@@ -1018,7 +1018,7 @@ def entrypoint_function(n):
10181018
code_context = ctx_result.unwrap()
10191019

10201020
# Test unused helper detection
1021-
unused_helpers = detect_unused_helper_functions(optimizer.function_to_optimize, code_context, CodeStringsMarkdown.parse_markdown_code(optimized_code).flat)
1021+
unused_helpers = detect_unused_helper_functions(optimizer.function_to_optimize, code_context, CodeStringsMarkdown.parse_markdown_code(optimized_code))
10221022

10231023
# Should detect multiply, process_data as unused (at minimum)
10241024
unused_names = {uh.qualified_name for uh in unused_helpers}
@@ -1178,7 +1178,7 @@ def entrypoint_function(n):
11781178
code_context = ctx_result.unwrap()
11791179

11801180
# Test unused helper detection
1181-
unused_helpers = detect_unused_helper_functions(optimizer.function_to_optimize, code_context, CodeStringsMarkdown.parse_markdown_code(optimized_code).flat)
1181+
unused_helpers = detect_unused_helper_functions(optimizer.function_to_optimize, code_context, CodeStringsMarkdown.parse_markdown_code(optimized_code))
11821182

11831183
# Should detect multiply_numbers and divide_numbers as unused
11841184
unused_names = {uh.qualified_name for uh in unused_helpers}
@@ -1400,7 +1400,7 @@ def calculate_class(cls, n):
14001400

14011401
# Test unused helper detection for static method
14021402
unused_helpers = detect_unused_helper_functions(
1403-
optimizer.function_to_optimize, code_context, CodeStringsMarkdown.parse_markdown_code(optimized_static_code).flat
1403+
optimizer.function_to_optimize, code_context, CodeStringsMarkdown.parse_markdown_code(optimized_static_code)
14041404
)
14051405

14061406
# Should detect utility_function_2 as unused

0 commit comments

Comments
 (0)