Skip to content

Commit 5cb0ab5

Browse files
authored
Merge branch 'main' into chore/asyncio-optimization
2 parents ba7e248 + 32e85ee commit 5cb0ab5

File tree

12 files changed

+130
-68
lines changed

12 files changed

+130
-68
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ How to use Codeflash -
1717
- Automate optimizing all __future__ code you will write by installing Codeflash as a GitHub action.
1818
- Optimize a Python workflow `python myscript.py` end-to-end by running `codeflash optimize myscript.py`
1919

20-
Codeflash is used by top engineering teams at [Pydantic](https://github.com/pydantic/pydantic/pulls?q=is%3Apr+author%3Amisrasaurabh1+is%3Amerged), [Langflow](https://github.com/langflow-ai/langflow/issues?q=state%3Aclosed%20is%3Apr%20author%3Amisrasaurabh1), [Roboflow](https://github.com/roboflow/inference/pulls?q=is%3Apr+is%3Amerged+codeflash+sort%3Acreated-asc), [Albumentations](https://github.com/albumentations-team/albumentations/issues?q=state%3Amerged%20is%3Apr%20author%3Akrrt7%20OR%20state%3Amerged%20is%3Apr%20author%3Aaseembits93%20) and many others to ship performant, expert level code.
20+
Codeflash is used by top engineering teams at **Pydantic** [(PRs Merged)](https://github.com/pydantic/pydantic/pulls?q=is%3Apr+author%3Amisrasaurabh1+is%3Amerged), **Roboflow** [(PRs Merged 1](https://github.com/roboflow/inference/issues?q=state%3Aclosed%20is%3Apr%20author%3Amisrasaurabh1%20is%3Amerged), [PRs Merged 2)](https://github.com/roboflow/inference/issues?q=state%3Amerged%20is%3Apr%20author%3Acodeflash-ai%5Bbot%5D), **Unstructured** [(PRs Merged 1](https://github.com/Unstructured-IO/unstructured/pulls?q=is%3Apr+Explanation+and+details+in%3Abody+is%3Amerged), [PRs Merged 2)](https://github.com/Unstructured-IO/unstructured-ingest/pulls?q=is%3Apr+Explanation+and+details+in%3Abody+is%3Amerged), **Langflow** [(PRs Merged)](https://github.com/langflow-ai/langflow/issues?q=state%3Aclosed%20is%3Apr%20author%3Amisrasaurabh1) and many others to ship performant, expert level code.
2121

2222
Codeflash is great at optimizing AI Agents, Computer Vision algorithms, PyTorch code, numerical code, backend code or anything else you might write with Python.
2323

codeflash/LICENSE

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ Business Source License 1.1
33
Parameters
44

55
Licensor: CodeFlash Inc.
6-
Licensed Work: Codeflash Client version 0.16.x
6+
Licensed Work: Codeflash Client version 0.17.x
77
The Licensed Work is (c) 2024 CodeFlash Inc.
88

99
Additional Use Grant: None. Production use of the Licensed Work is only permitted
@@ -13,7 +13,7 @@ Additional Use Grant: None. Production use of the Licensed Work is only permitte
1313
Platform. Please visit codeflash.ai for further
1414
information.
1515

16-
Change Date: 2029-08-14
16+
Change Date: 2029-09-23
1717

1818
Change License: MIT
1919

codeflash/api/aiservice.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from pydantic.json import pydantic_encoder
1111

1212
from codeflash.cli_cmds.console import console, logger
13+
from codeflash.code_utils.config_consts import N_CANDIDATES_EFFECTIVE, N_CANDIDATES_LP_EFFECTIVE
1314
from codeflash.code_utils.env_utils import get_codeflash_api_key
1415
from codeflash.code_utils.git_utils import get_last_commit_author_if_pr_exists, get_repo_owner_and_name
1516
from codeflash.lsp.helpers import is_LSP_enabled
@@ -131,6 +132,7 @@ def optimize_python_code( # noqa: D417
131132
"current_username": get_last_commit_author_if_pr_exists(None),
132133
"repo_owner": git_repo_owner,
133134
"repo_name": git_repo_name,
135+
"n_candidates": N_CANDIDATES_EFFECTIVE,
134136
}
135137

136138
logger.info("!lsp|Generating optimized candidates…")
@@ -192,6 +194,7 @@ def optimize_python_code_line_profiler( # noqa: D417
192194
"experiment_metadata": experiment_metadata,
193195
"codeflash_version": codeflash_version,
194196
"lsp_mode": is_LSP_enabled(),
197+
"n_candidates_lp": N_CANDIDATES_LP_EFFECTIVE,
195198
}
196199

197200
console.rule()

codeflash/code_utils/config_consts.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,25 @@
1111
MIN_TESTCASE_PASSED_THRESHOLD = 6
1212
REPEAT_OPTIMIZATION_PROBABILITY = 0.1
1313
DEFAULT_IMPORTANCE_THRESHOLD = 0.001
14+
N_CANDIDATES_LP = 6
15+
16+
# LSP-specific
17+
N_CANDIDATES_LSP = 3
18+
N_TESTS_TO_GENERATE_LSP = 2
19+
TOTAL_LOOPING_TIME_LSP = 10.0 # Kept same timing for LSP mode to avoid in increase in performance reporting
20+
N_CANDIDATES_LP_LSP = 3
21+
22+
MAX_N_CANDIDATES = 5
23+
MAX_N_CANDIDATES_LP = 6
24+
25+
try:
26+
from codeflash.lsp.helpers import is_LSP_enabled
27+
28+
_IS_LSP_ENABLED = is_LSP_enabled()
29+
except ImportError:
30+
_IS_LSP_ENABLED = False
31+
32+
N_CANDIDATES_EFFECTIVE = min(N_CANDIDATES_LSP if _IS_LSP_ENABLED else N_CANDIDATES, MAX_N_CANDIDATES)
33+
N_CANDIDATES_LP_EFFECTIVE = min(N_CANDIDATES_LP_LSP if _IS_LSP_ENABLED else N_CANDIDATES_LP, MAX_N_CANDIDATES_LP)
34+
N_TESTS_TO_GENERATE_EFFECTIVE = N_TESTS_TO_GENERATE_LSP if _IS_LSP_ENABLED else N_TESTS_TO_GENERATE
35+
TOTAL_LOOPING_TIME_EFFECTIVE = TOTAL_LOOPING_TIME_LSP if _IS_LSP_ENABLED else TOTAL_LOOPING_TIME

codeflash/code_utils/env_utils.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ def get_codeflash_api_key() -> str:
4242
if env_api_key and not shell_api_key:
4343
try:
4444
from codeflash.either import is_successful
45+
4546
result = save_api_key_to_rc(env_api_key)
4647
if is_successful(result):
4748
logger.debug(f"Automatically saved API key from environment to shell config: {result.unwrap()}")

codeflash/code_utils/git_utils.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from unidiff import PatchSet
1717

1818
from codeflash.cli_cmds.console import logger
19-
from codeflash.code_utils.config_consts import N_CANDIDATES
19+
from codeflash.code_utils.config_consts import N_CANDIDATES_EFFECTIVE
2020

2121
if TYPE_CHECKING:
2222
from git import Repo
@@ -164,7 +164,7 @@ def create_git_worktrees(
164164
) -> tuple[Path | None, list[Path]]:
165165
if git_root and worktree_root_dir:
166166
worktree_root = Path(tempfile.mkdtemp(dir=worktree_root_dir))
167-
worktrees = [Path(tempfile.mkdtemp(dir=worktree_root)) for _ in range(N_CANDIDATES + 1)]
167+
worktrees = [Path(tempfile.mkdtemp(dir=worktree_root)) for _ in range(N_CANDIDATES_EFFECTIVE + 1)]
168168
for worktree in worktrees:
169169
subprocess.run(["git", "worktree", "add", "-d", worktree], cwd=module_root, check=True)
170170
else:

codeflash/lsp/beta.py

Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from codeflash.lsp.server import CodeflashLanguageServer, CodeflashLanguageServerProtocol
2222
from codeflash.lsp.service.perform_optimization import sync_perform_optimization
2323

24+
2425
if TYPE_CHECKING:
2526
from argparse import Namespace
2627

@@ -45,6 +46,13 @@ class ProvideApiKeyParams:
4546
api_key: str
4647

4748

49+
@dataclass
50+
class ValidateProjectParams:
51+
root_path_abs: str
52+
config_file: Optional[str] = None
53+
skip_validation: bool = False
54+
55+
4856
@dataclass
4957
class OnPatchAppliedParams:
5058
patch_id: str
@@ -55,7 +63,8 @@ class OptimizableFunctionsInCommitParams:
5563
commit_hash: str
5664

5765

58-
server = CodeflashLanguageServer("codeflash-language-server", "v1.0", protocol_cls=CodeflashLanguageServerProtocol)
66+
# server = CodeflashLanguageServer("codeflash-language-server", "v1.0", protocol_cls=CodeflashLanguageServerProtocol)
67+
server = CodeflashLanguageServer("codeflash-language-server", "v1.0")
5968

6069

6170
@server.feature("getOptimizableFunctionsInCurrentDiff")
@@ -155,17 +164,60 @@ def initialize_function_optimization(
155164
return {"functionName": params.functionName, "status": "success"}
156165

157166

158-
@server.feature("validateProject")
159-
def validate_project(server: CodeflashLanguageServer, _params: FunctionOptimizationParams) -> dict[str, str]:
167+
def _find_pyproject_toml(workspace_path: str) -> Path | None:
168+
workspace_path_obj = Path(workspace_path)
169+
max_depth = 2
170+
base_depth = len(workspace_path_obj.parts)
171+
172+
for root, dirs, files in os.walk(workspace_path_obj):
173+
depth = len(Path(root).parts) - base_depth
174+
if depth > max_depth:
175+
# stop going deeper into this branch
176+
dirs.clear()
177+
continue
178+
179+
if "pyproject.toml" in files:
180+
file_path = Path(root) / "pyproject.toml"
181+
with file_path.open("r", encoding="utf-8", errors="ignore") as f:
182+
for line in f:
183+
if line.strip() == "[tool.codeflash]":
184+
return file_path.resolve()
185+
return None
186+
187+
188+
# should be called the first thing to initialize and validate the project
189+
@server.feature("initProject")
190+
def init_project(server: CodeflashLanguageServer, params: ValidateProjectParams) -> dict[str, str]:
160191
from codeflash.cli_cmds.cmd_init import is_valid_pyproject_toml
161192

193+
pyproject_toml_path: Path | None = getattr(params, "config_file", None)
194+
195+
if server.args is None:
196+
if pyproject_toml_path is not None:
197+
# if there is a config file provided use it
198+
server.prepare_optimizer_arguments(pyproject_toml_path)
199+
else:
200+
# otherwise look for it
201+
pyproject_toml_path = _find_pyproject_toml(params.root_path_abs)
202+
server.show_message_log(f"Found pyproject.toml at: {pyproject_toml_path}", "Info")
203+
if pyproject_toml_path:
204+
server.prepare_optimizer_arguments(pyproject_toml_path)
205+
else:
206+
return {
207+
"status": "error",
208+
"message": "No pyproject.toml found in workspace.",
209+
} # TODO: enhancec this message to say there is not tool.codeflash in pyproject.toml or smth
210+
211+
if getattr(params, "skip_validation", False):
212+
return {"status": "success", "moduleRoot": server.args.module_root, "pyprojectPath": pyproject_toml_path}
213+
162214
server.show_message_log("Validating project...", "Info")
163-
config = is_valid_pyproject_toml(server.args.config_file)
215+
config = is_valid_pyproject_toml(pyproject_toml_path)
164216
if config is None:
165217
server.show_message_log("pyproject.toml is not valid", "Error")
166218
return {
167219
"status": "error",
168-
"message": "pyproject.toml is not valid", # keep the error message the same, the extension is matching "pyproject.toml" in the error message to show the codeflash init instructions
220+
"message": "pyproject.toml is not valid", # keep the error message the same, the extension is matching "pyproject.toml" in the error message to show the codeflash init instructions,
169221
}
170222

171223
args = process_args(server)
@@ -178,7 +230,7 @@ def validate_project(server: CodeflashLanguageServer, _params: FunctionOptimizat
178230
except Exception:
179231
return {"status": "error", "message": "Repository has no commits (unborn HEAD)"}
180232

181-
return {"status": "success", "moduleRoot": args.module_root}
233+
return {"status": "success", "moduleRoot": args.module_root, "pyprojectPath": pyproject_toml_path}
182234

183235

184236
def _initialize_optimizer_if_api_key_is_valid(

codeflash/lsp/lsp_logger.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ def setup_logging() -> logging.Logger:
124124
logger = logging.getLogger()
125125
logger.handlers.clear()
126126

127-
# Set up stderr handler for VS Code output channel with [LSP-Server] prefix
127+
# Set up stderr handler for VS Code output channel
128128
handler = logging.StreamHandler(sys.stderr)
129129
handler.setLevel(logging.DEBUG)
130130

codeflash/lsp/server.py

Lines changed: 3 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,20 @@
11
from __future__ import annotations
22

3-
from pathlib import Path
43
from typing import TYPE_CHECKING, Any
54

6-
from lsprotocol.types import INITIALIZE, LogMessageParams, MessageType
7-
from pygls import uris
8-
from pygls.protocol import LanguageServerProtocol, lsp_method
5+
from lsprotocol.types import LogMessageParams, MessageType
6+
from pygls.protocol import LanguageServerProtocol
97
from pygls.server import LanguageServer
108

119
if TYPE_CHECKING:
12-
from lsprotocol.types import InitializeParams, InitializeResult
10+
from pathlib import Path
1311

1412
from codeflash.optimization.optimizer import Optimizer
1513

1614

1715
class CodeflashLanguageServerProtocol(LanguageServerProtocol):
1816
_server: CodeflashLanguageServer
1917

20-
@lsp_method(INITIALIZE)
21-
def lsp_initialize(self, params: InitializeParams) -> InitializeResult:
22-
server = self._server
23-
initialize_result: InitializeResult = super().lsp_initialize(params)
24-
25-
workspace_uri = params.root_uri
26-
if workspace_uri:
27-
workspace_path = uris.to_fs_path(workspace_uri)
28-
pyproject_toml_path = self._find_pyproject_toml(workspace_path)
29-
if pyproject_toml_path:
30-
server.prepare_optimizer_arguments(pyproject_toml_path)
31-
else:
32-
server.show_message("No pyproject.toml found in workspace.")
33-
else:
34-
server.show_message("No workspace URI provided.")
35-
36-
return initialize_result
37-
38-
def _find_pyproject_toml(self, workspace_path: str) -> Path | None:
39-
workspace_path_obj = Path(workspace_path)
40-
for file_path in workspace_path_obj.rglob("pyproject.toml"):
41-
return file_path.resolve()
42-
return None
43-
4418

4519
class CodeflashLanguageServer(LanguageServer):
4620
def __init__(self, *args: Any, **kwargs: Any) -> None: # noqa: ANN401

0 commit comments

Comments
 (0)