Skip to content

Commit b6f40eb

Browse files
authored
Merge branch 'main' into fix/revert-code-issue
2 parents e6391d2 + 45b42a4 commit b6f40eb

File tree

19 files changed

+604
-199
lines changed

19 files changed

+604
-199
lines changed

SECURITY.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Security Policy
2+
3+
This document outlines Codeflash's vulnerability disclosure policy. For more information about Codeflash's approach to security, please visit [codeflash.ai/security](https://www.codeflash.ai/security).
4+
5+
## Supported Versions
6+
7+
Since Codeflash is moving quickly, we can only commit to fixing security issues for the latest version of codeflash client.
8+
If a vulnerability is discovered in our backend, we will release the fix for all the users.
9+
10+
## Reporting a Vulnerability
11+
12+
13+
Please do not report security vulnerabilities through public GitHub issues.
14+
15+
Instead, please report them to our [GitHub Security page](https://github.com/codeflash-ai/codeflash/security). If you prefer to submit one without using GitHub, you can also email us at [email protected].
16+
17+
We commit to acknowledging vulnerability reports immediately, and will work to fix active vulnerabilities as soon as we can. We will publish resolved vulnerabilities in the form of security advisories on our GitHub security page. Critical incidents will be communicated both on the GitHub security page and via email to all affected users.
18+
19+
We appreciate your help in making Codeflash more secure for everyone. Thank you for your support and responsible disclosure.
Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,2 @@
11
DEFAULT_API_URL = "https://api.galileo.ai/"
22
DEFAULT_APP_URL = "https://app.galileo.ai/"
3-
4-
5-
# function_names: GalileoApiClient.get_console_url
6-
# module_abs_path : /home/mohammed/Work/galileo-python/src/galileo/api_client.py
7-
# preexisting_objects: {('GalileoApiClient', ()), ('_set_destination', ()), ('get_console_url', (FunctionParent(name='GalileoApiClient', type='ClassDef'),))}
8-
# project_root_path: /home/mohammed/Work/galileo-python/src

codeflash-benchmark/codeflash_benchmark/plugin.py

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,54 @@
88

99
PYTEST_BENCHMARK_INSTALLED = importlib.util.find_spec("pytest_benchmark") is not None
1010

11+
benchmark_options = [
12+
("--benchmark-columns", "store", None, "Benchmark columns"),
13+
("--benchmark-group-by", "store", None, "Benchmark group by"),
14+
("--benchmark-name", "store", None, "Benchmark name pattern"),
15+
("--benchmark-sort", "store", None, "Benchmark sort column"),
16+
("--benchmark-json", "store", None, "Benchmark JSON output file"),
17+
("--benchmark-save", "store", None, "Benchmark save name"),
18+
("--benchmark-warmup", "store", None, "Benchmark warmup"),
19+
("--benchmark-warmup-iterations", "store", None, "Benchmark warmup iterations"),
20+
("--benchmark-min-time", "store", None, "Benchmark minimum time"),
21+
("--benchmark-max-time", "store", None, "Benchmark maximum time"),
22+
("--benchmark-min-rounds", "store", None, "Benchmark minimum rounds"),
23+
("--benchmark-timer", "store", None, "Benchmark timer"),
24+
("--benchmark-calibration-precision", "store", None, "Benchmark calibration precision"),
25+
("--benchmark-disable", "store_true", False, "Disable benchmarks"),
26+
("--benchmark-skip", "store_true", False, "Skip benchmarks"),
27+
("--benchmark-only", "store_true", False, "Only run benchmarks"),
28+
("--benchmark-verbose", "store_true", False, "Verbose benchmark output"),
29+
("--benchmark-histogram", "store", None, "Benchmark histogram"),
30+
("--benchmark-compare", "store", None, "Benchmark compare"),
31+
("--benchmark-compare-fail", "store", None, "Benchmark compare fail threshold"),
32+
]
33+
1134

1235
def pytest_configure(config: pytest.Config) -> None:
1336
"""Register the benchmark marker and disable conflicting plugins."""
1437
config.addinivalue_line("markers", "benchmark: mark test as a benchmark that should be run with codeflash tracing")
1538

16-
if config.getoption("--codeflash-trace") and PYTEST_BENCHMARK_INSTALLED:
17-
config.option.benchmark_disable = True
18-
config.pluginmanager.set_blocked("pytest_benchmark")
19-
config.pluginmanager.set_blocked("pytest-benchmark")
39+
if config.getoption("--codeflash-trace"):
40+
# When --codeflash-trace is used, ignore all benchmark options by resetting them to defaults
41+
for option, _, default, _ in benchmark_options:
42+
option_name = option.replace("--", "").replace("-", "_")
43+
if hasattr(config.option, option_name):
44+
setattr(config.option, option_name, default)
45+
46+
if PYTEST_BENCHMARK_INSTALLED:
47+
config.pluginmanager.set_blocked("pytest_benchmark")
48+
config.pluginmanager.set_blocked("pytest-benchmark")
2049

2150

2251
def pytest_addoption(parser: pytest.Parser) -> None:
2352
parser.addoption(
2453
"--codeflash-trace", action="store_true", default=False, help="Enable CodeFlash tracing for benchmarks"
2554
)
55+
# These options are ignored when --codeflash-trace is used
56+
for option, action, default, help_text in benchmark_options:
57+
help_suffix = " (ignored when --codeflash-trace is used)"
58+
parser.addoption(option, action=action, default=default, help=help_text + help_suffix)
2659

2760

2861
@pytest.fixture
@@ -37,7 +70,7 @@ def benchmark(request: pytest.FixtureRequest) -> object:
3770
# If pytest-benchmark is installed and --codeflash-trace is not enabled,
3871
# return the normal pytest-benchmark fixture
3972
if PYTEST_BENCHMARK_INSTALLED:
40-
from pytest_benchmark.fixture import BenchmarkFixture as BSF # noqa: N814
73+
from pytest_benchmark.fixture import BenchmarkFixture as BSF # pyright: ignore[reportMissingImports] # noqa: I001, N814
4174

4275
bs = getattr(config, "_benchmarksession", None)
4376
if bs and bs.skip:

codeflash-benchmark/pyproject.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "codeflash-benchmark"
3-
version = "0.1.0"
3+
version = "0.2.0"
44
description = "Pytest benchmarking plugin for codeflash.ai - automatic code performance optimization"
55
authors = [{ name = "CodeFlash Inc.", email = "[email protected]" }]
66
requires-python = ">=3.9"
@@ -25,8 +25,8 @@ Repository = "https://github.com/codeflash-ai/codeflash-benchmark"
2525
codeflash-benchmark = "codeflash_benchmark.plugin"
2626

2727
[build-system]
28-
requires = ["setuptools>=45", "wheel", "setuptools_scm"]
28+
requires = ["setuptools>=45", "wheel"]
2929
build-backend = "setuptools.build_meta"
3030

3131
[tool.setuptools]
32-
packages = ["codeflash_benchmark"]
32+
packages = ["codeflash_benchmark"]

codeflash/api/aiservice.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from codeflash.code_utils.env_utils import get_codeflash_api_key, is_LSP_enabled
1414
from codeflash.code_utils.git_utils import get_last_commit_author_if_pr_exists, get_repo_owner_and_name
1515
from codeflash.models.ExperimentMetadata import ExperimentMetadata
16-
from codeflash.models.models import AIServiceRefinerRequest, OptimizedCandidate
16+
from codeflash.models.models import AIServiceRefinerRequest, CodeStringsMarkdown, OptimizedCandidate
1717
from codeflash.telemetry.posthog_cf import ph
1818
from codeflash.version import __version__ as codeflash_version
1919

@@ -136,7 +136,7 @@ def optimize_python_code( # noqa: D417
136136
logger.debug(f"Generating optimizations took {end_time - start_time:.2f} seconds.")
137137
return [
138138
OptimizedCandidate(
139-
source_code=opt["source_code"],
139+
source_code=CodeStringsMarkdown.parse_markdown_code(opt["source_code"]),
140140
explanation=opt["explanation"],
141141
optimization_id=opt["optimization_id"],
142142
)
@@ -206,7 +206,7 @@ def optimize_python_code_line_profiler( # noqa: D417
206206
console.rule()
207207
return [
208208
OptimizedCandidate(
209-
source_code=opt["source_code"],
209+
source_code=CodeStringsMarkdown.parse_markdown_code(opt["source_code"]),
210210
explanation=opt["explanation"],
211211
optimization_id=opt["optimization_id"],
212212
)
@@ -263,7 +263,7 @@ def optimize_python_code_refinement(self, request: list[AIServiceRefinerRequest]
263263
console.rule()
264264
return [
265265
OptimizedCandidate(
266-
source_code=opt["source_code"],
266+
source_code=CodeStringsMarkdown.parse_markdown_code(opt["source_code"]),
267267
explanation=opt["explanation"],
268268
optimization_id=opt["optimization_id"][:-4] + "refi",
269269
)

codeflash/code_utils/code_replacer.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from pathlib import Path
2020

2121
from codeflash.discovery.functions_to_optimize import FunctionToOptimize
22-
from codeflash.models.models import CodeOptimizationContext, OptimizedCandidate, ValidCode
22+
from codeflash.models.models import CodeOptimizationContext, CodeStringsMarkdown, OptimizedCandidate, ValidCode
2323

2424
ASTNodeT = TypeVar("ASTNodeT", bound=ast.AST)
2525

@@ -408,16 +408,17 @@ def replace_functions_and_add_imports(
408408

409409
def replace_function_definitions_in_module(
410410
function_names: list[str],
411-
optimized_code: str,
411+
optimized_code: CodeStringsMarkdown,
412412
module_abspath: Path,
413413
preexisting_objects: set[tuple[str, tuple[FunctionParent, ...]]],
414414
project_root_path: Path,
415415
) -> bool:
416416
source_code: str = module_abspath.read_text(encoding="utf8")
417+
code_to_apply = get_optimized_code_for_module(module_abspath.relative_to(project_root_path), optimized_code)
417418
new_code: str = replace_functions_and_add_imports(
418-
add_global_assignments(optimized_code, source_code),
419+
add_global_assignments(code_to_apply, source_code),
419420
function_names,
420-
optimized_code,
421+
code_to_apply,
421422
module_abspath,
422423
preexisting_objects,
423424
project_root_path,
@@ -428,6 +429,19 @@ def replace_function_definitions_in_module(
428429
return True
429430

430431

432+
def get_optimized_code_for_module(relative_path: Path, optimized_code: CodeStringsMarkdown) -> str:
433+
file_to_code_context = optimized_code.file_to_path()
434+
module_optimized_code = file_to_code_context.get(str(relative_path))
435+
if module_optimized_code is None:
436+
logger.warning(
437+
f"Optimized code not found for {relative_path} In the context\n-------\n{optimized_code}\n-------\n"
438+
"re-check your 'markdown code structure'"
439+
f"existing files are {file_to_code_context.keys()}"
440+
)
441+
module_optimized_code = ""
442+
return module_optimized_code
443+
444+
431445
def is_zero_diff(original_code: str, new_code: str) -> bool:
432446
return normalize_code(original_code) == normalize_code(new_code)
433447

codeflash/code_utils/formatter.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ def is_diff_line(line: str) -> bool:
104104
def format_code(
105105
formatter_cmds: list[str],
106106
path: Union[str, Path],
107-
optimized_function: str = "",
107+
optimized_code: str = "",
108108
check_diff: bool = False, # noqa
109109
print_status: bool = True, # noqa
110110
exit_on_failure: bool = True, # noqa
@@ -121,7 +121,7 @@ def format_code(
121121

122122
if check_diff and original_code_lines > 50:
123123
# we dont' count the formatting diff for the optimized function as it should be well-formatted
124-
original_code_without_opfunc = original_code.replace(optimized_function, "")
124+
original_code_without_opfunc = original_code.replace(optimized_code, "")
125125

126126
original_temp = Path(test_dir_str) / "original_temp.py"
127127
original_temp.write_text(original_code_without_opfunc, encoding="utf8")

codeflash/context/code_context_extractor.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,14 @@ def get_code_optimization_context(
6161
)
6262

6363
# Extract code context for optimization
64-
final_read_writable_code = extract_code_string_context_from_files(
64+
final_read_writable_code = extract_code_markdown_context_from_files(
6565
helpers_of_fto_dict,
6666
{},
6767
project_root_path,
6868
remove_docstrings=False,
6969
code_context_type=CodeContextType.READ_WRITABLE,
70-
).code
70+
)
71+
7172
read_only_code_markdown = extract_code_markdown_context_from_files(
7273
helpers_of_fto_dict,
7374
helpers_of_helpers_dict,
@@ -84,14 +85,14 @@ def get_code_optimization_context(
8485
)
8586

8687
# Handle token limits
87-
final_read_writable_tokens = encoded_tokens_len(final_read_writable_code)
88+
final_read_writable_tokens = encoded_tokens_len(final_read_writable_code.markdown)
8889
if final_read_writable_tokens > optim_token_limit:
8990
raise ValueError("Read-writable code has exceeded token limit, cannot proceed")
9091

9192
# Setup preexisting objects for code replacer
9293
preexisting_objects = set(
9394
chain(
94-
find_preexisting_objects(final_read_writable_code),
95+
*(find_preexisting_objects(codestring.code) for codestring in final_read_writable_code.code_strings),
9596
*(find_preexisting_objects(codestring.code) for codestring in read_only_code_markdown.code_strings),
9697
)
9798
)

codeflash/context/unused_definition_remover.py

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,15 @@
33
import ast
44
from collections import defaultdict
55
from dataclasses import dataclass, field
6-
from typing import TYPE_CHECKING
7-
8-
if TYPE_CHECKING:
9-
from pathlib import Path
6+
from itertools import chain
7+
from pathlib import Path
108
from typing import TYPE_CHECKING, Optional
119

1210
import libcst as cst
1311

1412
from codeflash.cli_cmds.console import logger
1513
from codeflash.code_utils.code_replacer import replace_function_definitions_in_module
14+
from codeflash.models.models import CodeString, CodeStringsMarkdown
1615

1716
if TYPE_CHECKING:
1817
from codeflash.discovery.functions_to_optimize import FunctionToOptimize
@@ -530,7 +529,11 @@ def revert_unused_helper_functions(
530529
helper_names = [helper.qualified_name for helper in helpers_in_file]
531530
reverted_code = replace_function_definitions_in_module(
532531
function_names=helper_names,
533-
optimized_code=original_code, # Use original code as the "optimized" code to revert
532+
optimized_code=CodeStringsMarkdown(
533+
code_strings=[
534+
CodeString(code=original_code, file_path=Path(file_path).relative_to(project_root))
535+
]
536+
), # Use original code as the "optimized" code to revert
534537
module_abspath=file_path,
535538
preexisting_objects=set(), # Empty set since we're reverting
536539
project_root_path=project_root,
@@ -609,7 +612,9 @@ def _analyze_imports_in_optimized_code(
609612

610613

611614
def detect_unused_helper_functions(
612-
function_to_optimize: FunctionToOptimize, code_context: CodeOptimizationContext, optimized_code: str
615+
function_to_optimize: FunctionToOptimize,
616+
code_context: CodeOptimizationContext,
617+
optimized_code: str | CodeStringsMarkdown,
613618
) -> list[FunctionSource]:
614619
"""Detect helper functions that are no longer called by the optimized entrypoint function.
615620
@@ -622,6 +627,14 @@ def detect_unused_helper_functions(
622627
List of FunctionSource objects representing unused helper functions
623628
624629
"""
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+
625638
try:
626639
# Parse the optimized code to analyze function calls and imports
627640
optimized_ast = ast.parse(optimized_code)

codeflash/discovery/pytest_new_process_discovery.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ def parse_pytest_collection_results(pytest_tests: list[Any]) -> list[dict[str, s
4141

4242
try:
4343
exitcode = pytest.main(
44-
[tests_root, "-p no:logging", "--collect-only", "-m", "not skip"], plugins=[PytestCollectionPlugin()]
44+
[tests_root, "-p no:logging", "--collect-only", "-m", "not skip", "-p", "no:codeflash-benchmark"],
45+
plugins=[PytestCollectionPlugin()],
4546
)
4647
except Exception as e:
4748
print(f"Failed to collect tests: {e!s}")

0 commit comments

Comments
 (0)