CF-900 allow async optimizations by default (#938)

* remove --async

* include it by default

* don't crash for --async

* pre-commit
This commit is contained in:
Kevin Turcios 2025-11-23 16:36:13 -05:00 committed by GitHub
parent f7d97b2497
commit 321640cb60
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 17 additions and 63 deletions

View file

@ -1,4 +1,3 @@
import importlib.util
import logging
import sys
from argparse import SUPPRESS, ArgumentParser, Namespace
@ -104,7 +103,7 @@ def parse_args() -> Namespace:
"--async",
default=False,
action="store_true",
help="Enable optimization of async functions. By default, async functions are excluded from optimization.",
help="(Deprecated) Async function optimization is now enabled by default. This flag is ignored.",
)
args, unknown_args = parser.parse_known_args()
@ -155,13 +154,11 @@ def process_and_validate_cmd_args(args: Namespace) -> Namespace:
if env_utils.is_ci():
args.no_pr = True
if getattr(args, "async", False) and importlib.util.find_spec("pytest_asyncio") is None:
if getattr(args, "async", False):
logger.warning(
"Warning: The --async flag requires pytest-asyncio to be installed.\n"
"Please install it using:\n"
' pip install "codeflash[asyncio]"'
"The --async flag is deprecated and will be removed in a future version. "
"Async function optimization is now enabled by default."
)
raise SystemExit(1)
return args

View file

@ -179,8 +179,6 @@ def get_functions_to_optimize(
project_root: Path,
module_root: Path,
previous_checkpoint_functions: dict[str, dict[str, str]] | None = None,
*,
enable_async: bool = False,
) -> tuple[dict[Path, list[FunctionToOptimize]], int, Path | None]:
assert sum([bool(optimize_all), bool(replay_test), bool(file)]) <= 1, (
"Only one of optimize_all, replay_test, or file should be provided"
@ -242,13 +240,7 @@ def get_functions_to_optimize(
ph("cli-optimizing-git-diff")
functions = get_functions_within_git_diff(uncommitted_changes=False)
filtered_modified_functions, functions_count = filter_functions(
functions,
test_cfg.tests_root,
ignore_paths,
project_root,
module_root,
previous_checkpoint_functions,
enable_async=enable_async,
functions, test_cfg.tests_root, ignore_paths, project_root, module_root, previous_checkpoint_functions
)
logger.info(f"!lsp|Found {functions_count} function{'s' if functions_count > 1 else ''} to optimize")
@ -658,7 +650,6 @@ def filter_functions(
previous_checkpoint_functions: dict[Path, dict[str, Any]] | None = None,
*,
disable_logs: bool = False,
enable_async: bool = False,
) -> tuple[dict[Path, list[FunctionToOptimize]], int]:
filtered_modified_functions: dict[str, list[FunctionToOptimize]] = {}
blocklist_funcs = get_blocklisted_functions()
@ -678,7 +669,6 @@ def filter_functions(
submodule_ignored_paths_count: int = 0
blocklist_funcs_removed_count: int = 0
previous_checkpoint_functions_removed_count: int = 0
async_functions_removed_count: int = 0
tests_root_str = str(tests_root)
module_root_str = str(module_root)
@ -734,15 +724,6 @@ def filter_functions(
functions_tmp.append(function)
_functions = functions_tmp
if not enable_async:
functions_tmp = []
for function in _functions:
if function.is_async:
async_functions_removed_count += 1
continue
functions_tmp.append(function)
_functions = functions_tmp
filtered_modified_functions[file_path] = _functions
functions_count += len(_functions)
@ -756,7 +737,6 @@ def filter_functions(
"Files from ignored submodules": (submodule_ignored_paths_count, "bright_black"),
"Blocklisted functions removed": (blocklist_funcs_removed_count, "bright_red"),
"Functions skipped from checkpoint": (previous_checkpoint_functions_removed_count, "green"),
"Async functions removed": (async_functions_removed_count, "bright_magenta"),
}
tree = Tree(Text("Ignored functions and files", style="bold"))
for label, (count, color) in log_info.items():

View file

@ -134,7 +134,6 @@ class Optimizer:
project_root=self.args.project_root,
module_root=self.args.module_root,
previous_checkpoint_functions=self.args.previous_checkpoint_functions,
enable_async=getattr(self.args, "async", False),
)
def create_function_optimizer(

View file

@ -44,6 +44,7 @@ dependencies = [
"pygls>=2.0.0,<3.0.0",
"codeflash-benchmark",
"filelock",
"pytest-asyncio>=1.2.0",
]
[project.urls]
@ -53,13 +54,9 @@ Homepage = "https://codeflash.ai"
codeflash = "codeflash.main:main"
[project.optional-dependencies]
asyncio = [
"pytest-asyncio>=1.2.0",
]
[dependency-groups]
dev = [
{include-group = "asyncio"},
"ipython>=8.12.0",
"mypy>=1.13",
"ruff>=0.7.0",
@ -82,9 +79,6 @@ dev = [
"uv>=0.6.2",
"pre-commit>=4.2.0,<5",
]
asyncio = [
"pytest-asyncio>=1.2.0",
]
tests = [
"black>=25.9.0",
"jax>=0.4.30",

View file

@ -8,7 +8,6 @@ def run_test(expected_improvement_pct: int) -> bool:
config = TestConfig(
file_path="main.py",
min_improvement_x=0.1,
enable_async=True,
coverage_expectations=[
CoverageExpectation(
function_name="retry_with_backoff",

View file

@ -27,7 +27,6 @@ class TestConfig:
trace_mode: bool = False
coverage_expectations: list[CoverageExpectation] = field(default_factory=list)
benchmarks_root: Optional[pathlib.Path] = None
enable_async: bool = False
use_worktree: bool = False
@ -136,8 +135,6 @@ def build_command(
)
if benchmarks_root:
base_command.extend(["--benchmark", "--benchmarks-root", str(benchmarks_root)])
if config.enable_async:
base_command.append("--async")
if config.use_worktree:
base_command.append("--worktree")
return base_command

View file

@ -244,7 +244,6 @@ class MixedClass:
ignore_paths=[],
project_root=file_path.parent,
module_root=file_path.parent,
enable_async=True,
)
assert functions_count == 4
@ -259,7 +258,8 @@ class MixedClass:
@pytest.mark.skipif(sys.platform == "win32", reason="pending support for asyncio on windows")
def test_no_async_functions_finding(temp_dir):
def test_async_functions_always_included(temp_dir):
"""Test that async functions are always included now (no longer filtered out)."""
mixed_code = """
async def async_func_one():
return await operation_one()
@ -297,16 +297,17 @@ class MixedClass:
ignore_paths=[],
project_root=file_path.parent,
module_root=file_path.parent,
enable_async=False,
)
assert functions_count == 2
# Now async functions are always included, so we expect 4 functions (not 2)
assert functions_count == 4
function_names = [fn.function_name for fn in functions[file_path]]
assert "sync_func_one" in function_names
assert "sync_method" in function_names
assert "async_func_one" not in function_names
assert "async_method" not in function_names
# Async functions are now included by default
assert "async_func_one" in function_names
assert "async_method" in function_names
@pytest.mark.skipif(sys.platform == "win32", reason="pending support for asyncio on windows")

21
uv.lock
View file

@ -335,6 +335,8 @@ dependencies = [
{ name = "pygls" },
{ name = "pytest", version = "8.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
{ name = "pytest", version = "9.0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
{ name = "pytest-asyncio", version = "1.2.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
{ name = "pytest-asyncio", version = "1.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
{ name = "pytest-timeout" },
{ name = "rich" },
{ name = "sentry-sdk" },
@ -344,17 +346,7 @@ dependencies = [
{ name = "unittest-xml-reporting" },
]
[package.optional-dependencies]
asyncio = [
{ name = "pytest-asyncio", version = "1.2.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
{ name = "pytest-asyncio", version = "1.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
]
[package.dev-dependencies]
asyncio = [
{ name = "pytest-asyncio", version = "1.2.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
{ name = "pytest-asyncio", version = "1.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
]
dev = [
{ name = "ipython", version = "8.18.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
{ name = "ipython", version = "8.37.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" },
@ -365,8 +357,6 @@ dev = [
{ name = "pandas-stubs", version = "2.2.2.240909", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
{ name = "pre-commit", version = "4.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
{ name = "pre-commit", version = "4.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
{ name = "pytest-asyncio", version = "1.2.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
{ name = "pytest-asyncio", version = "1.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
{ name = "ruff" },
{ name = "types-cffi" },
{ name = "types-colorama" },
@ -428,7 +418,7 @@ requires-dist = [
{ name = "pydantic", specifier = ">=1.10.1" },
{ name = "pygls", specifier = ">=2.0.0,<3.0.0" },
{ name = "pytest", specifier = ">=7.0.0" },
{ name = "pytest-asyncio", marker = "extra == 'asyncio'", specifier = ">=1.2.0" },
{ name = "pytest-asyncio", specifier = ">=1.2.0" },
{ name = "pytest-timeout", specifier = ">=2.1.0" },
{ name = "rich", specifier = ">=13.8.1" },
{ name = "sentry-sdk", specifier = ">=1.40.6,<3.0.0" },
@ -437,17 +427,14 @@ requires-dist = [
{ name = "unidiff", specifier = ">=0.7.4" },
{ name = "unittest-xml-reporting", specifier = ">=3.2.0" },
]
provides-extras = ["asyncio"]
[package.metadata.requires-dev]
asyncio = [{ name = "pytest-asyncio", specifier = ">=1.2.0" }]
dev = [
{ name = "ipython", specifier = ">=8.12.0" },
{ name = "lxml-stubs", specifier = ">=0.5.1" },
{ name = "mypy", specifier = ">=1.13" },
{ name = "pandas-stubs", specifier = ">=2.2.2.240807,<2.2.3.241009" },
{ name = "pre-commit", specifier = ">=4.2.0,<5" },
{ name = "pytest-asyncio", specifier = ">=1.2.0" },
{ name = "ruff", specifier = ">=0.7.0" },
{ name = "types-cffi", specifier = ">=1.16.0.20240331" },
{ name = "types-colorama", specifier = ">=0.4.15.20240311" },
@ -841,7 +828,7 @@ name = "exceptiongroup"
version = "1.3.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/0b/9f/a65090624ecf468cdca03533906e7c69ed7588582240cfe7cc9e770b50eb/exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88", size = 29749, upload-time = "2025-05-10T17:42:51.123Z" }
wheels = [