Skip to content

Commit 908e29c

Browse files
authored
Merge branch 'main' into fix/git-diff-windows-path-case
2 parents 5c9d052 + bfc183f commit 908e29c

13 files changed

Lines changed: 106 additions & 43 deletions

File tree

codeflash/benchmarking/trace_benchmarks.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
from codeflash.cli_cmds.console import logger
99
from codeflash.code_utils.compat import SAFE_SYS_EXECUTABLE
10+
from codeflash.code_utils.shell_utils import get_cross_platform_subprocess_run_args
1011

1112

1213
def trace_benchmarks_pytest(
@@ -17,20 +18,18 @@ def trace_benchmarks_pytest(
1718
benchmark_env["PYTHONPATH"] = str(project_root)
1819
else:
1920
benchmark_env["PYTHONPATH"] += os.pathsep + str(project_root)
20-
result = subprocess.run(
21+
run_args = get_cross_platform_subprocess_run_args(
22+
cwd=project_root, env=benchmark_env, timeout=timeout, check=False, text=True, capture_output=True
23+
)
24+
result = subprocess.run( # noqa: PLW1510
2125
[
2226
SAFE_SYS_EXECUTABLE,
2327
Path(__file__).parent / "pytest_new_process_trace_benchmarks.py",
2428
benchmarks_root,
2529
tests_root,
2630
trace_file,
2731
],
28-
cwd=project_root,
29-
check=False,
30-
capture_output=True,
31-
text=True,
32-
env=benchmark_env,
33-
timeout=timeout,
32+
**run_args,
3433
)
3534
if result.returncode != 0:
3635
if "ERROR collecting" in result.stdout:

codeflash/cli_cmds/console.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,19 @@
5858
)
5959

6060

61+
class DummyTask:
62+
def __init__(self) -> None:
63+
self.id = 0
64+
65+
66+
class DummyProgress:
67+
def __init__(self) -> None:
68+
pass
69+
70+
def advance(self, task_id: TaskID, advance: int = 1) -> None:
71+
pass
72+
73+
6174
def lsp_log(message: LspMessage) -> None:
6275
if not is_LSP_enabled():
6376
return
@@ -120,10 +133,6 @@ def progress_bar(
120133
logger.info(message)
121134

122135
# Create a fake task ID since we still need to yield something
123-
class DummyTask:
124-
def __init__(self) -> None:
125-
self.id = 0
126-
127136
yield DummyTask().id
128137
else:
129138
progress = Progress(
@@ -141,6 +150,13 @@ def __init__(self) -> None:
141150
@contextmanager
142151
def test_files_progress_bar(total: int, description: str) -> Generator[tuple[Progress, TaskID], None, None]:
143152
"""Progress bar for test files."""
153+
if is_LSP_enabled():
154+
lsp_log(LspTextMessage(text=description, takes_time=True))
155+
dummy_progress = DummyProgress()
156+
dummy_task = DummyTask()
157+
yield dummy_progress, dummy_task.id
158+
return
159+
144160
with Progress(
145161
SpinnerColumn(next(spinners)),
146162
TextColumn("[progress.description]{task.description}"),

codeflash/code_utils/code_replacer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ def replace_function_definitions_in_module(
447447

448448
new_code: str = replace_functions_and_add_imports(
449449
# adding the global assignments before replacing the code, not after
450-
# becuase of an "edge case" where the optimized code intoduced a new import and a global assignment using that import
450+
# because of an "edge case" where the optimized code intoduced a new import and a global assignment using that import
451451
# and that import wasn't used before, so it was ignored when calling AddImportsVisitor.add_needed_import inside replace_functions_and_add_imports (because the global assignment wasn't added yet)
452452
# this was added at https://github.com/codeflash-ai/codeflash/pull/448
453453
add_global_assignments(code_to_apply, source_code) if should_add_global_assignments else source_code,

codeflash/code_utils/shell_utils.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import contextlib
44
import os
55
import re
6+
import subprocess
7+
import sys
68
from pathlib import Path
79
from typing import TYPE_CHECKING, Optional
810

@@ -11,8 +13,11 @@
1113
from codeflash.either import Failure, Success
1214

1315
if TYPE_CHECKING:
16+
from collections.abc import Mapping
17+
1418
from codeflash.either import Result
1519

20+
1621
# PowerShell patterns and prefixes
1722
POWERSHELL_RC_EXPORT_PATTERN = re.compile(
1823
r'^\$env:CODEFLASH_API_KEY\s*=\s*(?:"|\')?(cf-[^\s"\']+)(?:"|\')?\s*$', re.MULTILINE
@@ -231,3 +236,24 @@ def save_api_key_to_rc(api_key: str) -> Result[str, str]:
231236
f"To ensure your Codeflash API key is automatically loaded into your environment at startup, you can create {shell_rc_path} and add the following line:{LF}"
232237
f"{LF}{api_key_line}{LF}"
233238
)
239+
240+
241+
def get_cross_platform_subprocess_run_args(
242+
cwd: Path | str | None = None,
243+
env: Mapping[str, str] | None = None,
244+
timeout: Optional[float] = None,
245+
check: bool = False, # noqa: FBT001, FBT002
246+
text: bool = True, # noqa: FBT001, FBT002
247+
capture_output: bool = True, # noqa: FBT001, FBT002 (only for non-Windows)
248+
) -> dict[str, str]:
249+
run_args = {"cwd": cwd, "env": env, "text": text, "timeout": timeout, "check": check}
250+
if sys.platform == "win32":
251+
creationflags = subprocess.CREATE_NEW_PROCESS_GROUP
252+
run_args["creationflags"] = creationflags
253+
run_args["stdout"] = subprocess.PIPE
254+
run_args["stderr"] = subprocess.PIPE
255+
run_args["stdin"] = subprocess.DEVNULL
256+
else:
257+
run_args["capture_output"] = capture_output
258+
259+
return run_args

codeflash/discovery/discover_unit_tests.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
if TYPE_CHECKING:
1818
from codeflash.discovery.functions_to_optimize import FunctionToOptimize
19-
2019
from pydantic.dataclasses import dataclass
2120
from rich.panel import Panel
2221
from rich.text import Text
@@ -29,6 +28,7 @@
2928
module_name_from_file_path,
3029
)
3130
from codeflash.code_utils.compat import SAFE_SYS_EXECUTABLE, codeflash_cache_db
31+
from codeflash.code_utils.shell_utils import get_cross_platform_subprocess_run_args
3232
from codeflash.models.models import CodePosition, FunctionCalledInTest, TestsInFile, TestType
3333

3434
if TYPE_CHECKING:
@@ -331,7 +331,7 @@ def visit_ImportFrom(self, node: ast.ImportFrom) -> None:
331331
# Be conservative except when an alias is used (which requires exact method matching)
332332
for target_func in fnames:
333333
if "." in target_func:
334-
class_name, method_name = target_func.split(".", 1)
334+
class_name, _method_name = target_func.split(".", 1)
335335
if aname == class_name and not alias.asname:
336336
self.found_any_target_function = True
337337
self.found_qualified_name = target_func
@@ -585,18 +585,18 @@ def discover_tests_pytest(
585585

586586
tmp_pickle_path = get_run_tmp_file("collected_tests.pkl")
587587
with custom_addopts():
588-
result = subprocess.run(
588+
run_kwargs = get_cross_platform_subprocess_run_args(
589+
cwd=project_root, check=False, text=True, capture_output=True
590+
)
591+
result = subprocess.run( # noqa: PLW1510
589592
[
590593
SAFE_SYS_EXECUTABLE,
591594
Path(__file__).parent / "pytest_new_process_discovery.py",
592595
str(project_root),
593596
str(tests_root),
594597
str(tmp_pickle_path),
595598
],
596-
cwd=project_root,
597-
check=False,
598-
capture_output=True,
599-
text=True,
599+
**run_kwargs,
600600
)
601601
try:
602602
with tmp_pickle_path.open(mode="rb") as f:

codeflash/discovery/functions_to_optimize.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ def qualified_name_with_modules_from_root(self, project_root_path: Path) -> str:
175175
def get_functions_to_optimize(
176176
optimize_all: str | None,
177177
replay_test: list[Path] | None,
178-
file: Path | None,
178+
file: Path | str | None,
179179
only_get_this_function: str | None,
180180
test_cfg: TestConfig,
181181
ignore_paths: list[Path],
@@ -202,6 +202,7 @@ def get_functions_to_optimize(
202202
elif file is not None:
203203
logger.info("!lsp|Finding all functions in the file '%s'…", file)
204204
console.rule()
205+
file = Path(file) if isinstance(file, str) else file
205206
functions: dict[Path, list[FunctionToOptimize]] = find_all_functions_in_file(file)
206207
if only_get_this_function is not None:
207208
split_function = only_get_this_function.split(".")

codeflash/lsp/beta.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ def get_optimizable_functions(params: OptimizableFunctionsParams) -> dict[str, l
134134
document_uri = params.textDocument.uri
135135
document = server.workspace.get_text_document(document_uri)
136136

137-
file_path = Path(document.path)
137+
file_path = Path(document.path).resolve()
138138

139139
if not server.optimizer:
140140
return {"status": "error", "message": "optimizer not initialized"}
@@ -517,7 +517,7 @@ def initialize_function_optimization(params: FunctionOptimizationInitParams) ->
517517
files = [document.path]
518518

519519
_, _, original_helpers = server.current_optimization_init_result
520-
files.extend([str(helper_path) for helper_path in original_helpers])
520+
files.extend([str(helper_path.resolve()) for helper_path in original_helpers])
521521

522522
return {"functionName": params.functionName, "status": "success", "files_inside_context": files}
523523

codeflash/lsp/features/perform_optimization.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ def run_generate_optimizations(): # noqa: ANN202
6363
future_tests = function_optimizer.executor.submit(ctx_tests.run, run_generate_tests)
6464
future_optimizations = function_optimizer.executor.submit(ctx_opts.run, run_generate_optimizations)
6565

66-
logger.info(f"loading|Generating new tests and optimizations for function '{params.functionName}'...")
66+
logger.info(f"loading|Generating new tests and optimizations for function '{params.functionName}'")
6767
concurrent.futures.wait([future_tests, future_optimizations])
6868

6969
test_setup_result = future_tests.result()

codeflash/lsp/lsp_message.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
json_primitive_types = (str, float, int, bool)
1212
max_code_lines_before_collapse = 45
1313

14-
# \u241F is the message delimiter becuase it can be more than one message sent over the same message, so we need something to separate each message
15-
message_delimiter = "\u241f"
14+
# \\u241F is the message delimiter because it can be more than one message sent over the same message, so we need something to separate each message
15+
message_delimiter = "\\u241F"
1616

1717

1818
# allow the client to know which message it is receiving

codeflash/optimization/function_optimizer.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,7 @@ def __init__(
396396

397397
def can_be_optimized(self) -> Result[tuple[bool, CodeOptimizationContext, dict[Path, str]], str]:
398398
should_run_experiment = self.experiment_id is not None
399-
logger.info(f"Function Trace ID: {self.function_trace_id}")
399+
logger.info(f"!lsp|Function Trace ID: {self.function_trace_id}")
400400
ph("cli-optimize-function-start", {"function_trace_id": self.function_trace_id})
401401
self.cleanup_leftover_test_return_values()
402402
file_name_from_test_module_name.cache_clear()
@@ -1934,6 +1934,7 @@ def establish_original_code_baseline(
19341934
instrument_codeflash_capture(
19351935
self.function_to_optimize, file_path_to_helper_classes, self.test_cfg.tests_root
19361936
)
1937+
19371938
total_looping_time = TOTAL_LOOPING_TIME_EFFECTIVE
19381939
behavioral_results, coverage_results = self.run_and_parse_tests(
19391940
testing_type=TestingMode.BEHAVIOR,

0 commit comments

Comments
 (0)