diff --git a/.github/workflows/pr_agent.yml b/.github/workflows/pr_agent.yml new file mode 100644 index 000000000..4f6d48de6 --- /dev/null +++ b/.github/workflows/pr_agent.yml @@ -0,0 +1,20 @@ +on: + pull_request: + types: [opened, reopened, ready_for_review] + issue_comment: +jobs: + pr_agent_job: + if: ${{ github.event.sender.type != 'Bot' }} + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + contents: write + name: Run pr agent on every pull request, respond to user comments + steps: + - name: PR Agent action step + id: pragent + uses: qodo-ai/pr-agent@main + env: + OPENAI_KEY: ${{ secrets.OPENAI_KEY }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/codeflash.code-workspace b/codeflash.code-workspace new file mode 100644 index 000000000..7f62bcc77 --- /dev/null +++ b/codeflash.code-workspace @@ -0,0 +1,80 @@ +{ + "folders": [ + { + "path": ".", + "name": "codeflash", + "extensions": [ + "charliermarsh.ruff", + "ms-python.python", + ] + } + ], + "settings": { + "python.defaultInterpreterPath": "~/miniforge3/envs/codeflash312/bin/python", + "python.terminal.activateEnvironment": true, + "python.testing.pytestEnabled": true, + "python.testing.pytestArgs": ["tests/", "-vv"], + }, + "launch": { + "version": "0.2.0", + "configurations": [ + { + "name": "bubble_sort", + "type": "debugpy", + "request": "launch", + "program": "${workspaceFolder:codeflash}/codeflash/main.py", + "args": [ + "--file", + "code_to_optimize/bubble_sort.py", + "--module-root", + "${workspaceFolder:codeflash}", + "--function", + "sorter", + "--test-framework", + "pytest", + "--tests-root", + "code_to_optimize/tests/pytest" + ], + "cwd": "${workspaceFolder:codeflash}", + "console": "integratedTerminal", + "env": { + "PYTHONUNBUFFERED": "1" + }, + }, + { + "name": "bubble_sort -all", + "type": "debugpy", + "request": "launch", + "program": "${workspaceFolder:codeflash}/codeflash/main.py", + "args": [ + "--all", + "--test-framework", + "pytest", + "--tests-root", + "code_to_optimize/tests/pytest", + "--module-root", + "code_to_optimize" + ], + "cwd": "${workspaceFolder:codeflash}", + "console": "integratedTerminal", + "env": { + "PYTHONUNBUFFERED": "1" + }, + }, + { + "name": "bubble_sort --file bubble_sort.py (MBR)", + "type": "debugpy", + "request": "launch", + "program": "${workspaceFolder:codeflash}/codeflash/main.py", + "args": [ + "--all", + ], + "cwd": "/Users/krrt7/Desktop/work/my-best-repo", + "console": "integratedTerminal", + "env": { + "PYTHONUNBUFFERED": "1" + }, + } + ] + } +} \ No newline at end of file diff --git a/codeflash/api/aiservice.py b/codeflash/api/aiservice.py index cacd15f3e..f1c6bcf9d 100644 --- a/codeflash/api/aiservice.py +++ b/codeflash/api/aiservice.py @@ -29,6 +29,7 @@ def __init__(self) -> None: def get_aiservice_base_url(self) -> str: if os.environ.get("CODEFLASH_AIS_SERVER", default="prod").lower() == "local": logger.info("Using local AI Service at http://localhost:8000") + console.rule() return "http://localhost:8000" return "https://app.codeflash.ai" diff --git a/codeflash/optimization/function_optimizer.py b/codeflash/optimization/function_optimizer.py index e62658dcb..88da7db47 100644 --- a/codeflash/optimization/function_optimizer.py +++ b/codeflash/optimization/function_optimizer.py @@ -1072,7 +1072,6 @@ def run_and_parse_tests( cwd=self.project_root, test_env=test_env, pytest_timeout=INDIVIDUAL_TESTCASE_TIMEOUT, - pytest_cmd=self.test_cfg.pytest_cmd, verbose=True, enable_coverage=enable_coverage, ) @@ -1081,8 +1080,8 @@ def run_and_parse_tests( test_files, cwd=self.project_root, test_env=test_env, - pytest_timeout=INDIVIDUAL_TESTCASE_TIMEOUT, pytest_cmd=self.test_cfg.pytest_cmd, + pytest_timeout=INDIVIDUAL_TESTCASE_TIMEOUT, pytest_target_runtime_seconds=testing_time, pytest_min_loops=pytest_min_loops, pytest_max_loops=pytest_max_loops, diff --git a/codeflash/verification/test_runner.py b/codeflash/verification/test_runner.py index fcac7e756..d00dd36e6 100644 --- a/codeflash/verification/test_runner.py +++ b/codeflash/verification/test_runner.py @@ -50,9 +50,12 @@ def run_behavioral_tests( ) else: test_files.append(str(file.instrumented_behavior_file_path)) + pytest_cmd_list = ( + shlex.split(f"{SAFE_SYS_EXECUTABLE} -m pytest", posix=IS_POSIX) + if pytest_cmd == "pytest" + else [SAFE_SYS_EXECUTABLE, "-m", *shlex.split(pytest_cmd, posix=IS_POSIX)] + ) test_files = list(set(test_files)) # remove multiple calls in the same test function - pytest_cmd_list = shlex.split(pytest_cmd, posix=IS_POSIX) - common_pytest_args = [ "--capture=tee-sys", f"--timeout={pytest_timeout}", @@ -77,17 +80,19 @@ def run_behavioral_tests( ) # this cleanup is necessary to avoid coverage data from previous runs, if there are any, # then the current run will be appended to the previous data, which skews the results logger.debug(cov_erase) + coverage_cmd = [SAFE_SYS_EXECUTABLE, "-m", "coverage", "run", f"--rcfile={coveragercfile.as_posix()}", "-m"] + + if pytest_cmd == "pytest": + coverage_cmd.extend(["pytest"]) + else: + coverage_cmd.extend(shlex.split(pytest_cmd, posix=IS_POSIX)[1:]) - coverage_cmd = f"{SAFE_SYS_EXECUTABLE} -m coverage run --rcfile={coveragercfile.as_posix()} -m" results = execute_test_subprocess( - shlex.split(coverage_cmd) + pytest_cmd_list + common_pytest_args + result_args + test_files, - cwd=cwd, - env=pytest_test_env, - timeout=600, + coverage_cmd + common_pytest_args + result_args + test_files, cwd=cwd, env=pytest_test_env, timeout=600 ) logger.debug( - f"Result return code: {results.returncode}" - + (f", Result stderr: {results.stderr}" if results.stderr else "") + f"Result return code: {results.returncode}, " + f"{'Result stderr:' + str(results.stderr) if results.stderr else ''}" ) else: results = execute_test_subprocess( @@ -97,8 +102,7 @@ def run_behavioral_tests( timeout=600, # TODO: Make this dynamic ) logger.debug( - f"Result return code: {results.returncode}" - + (f", Result stderr: {results.stderr}" if results.stderr else "") + f"""Result return code: {results.returncode}, {"Result stderr:" + str(results.stderr) if results.stderr else ""}""" ) elif test_framework == "unittest": if enable_coverage: @@ -110,8 +114,7 @@ def run_behavioral_tests( verbose=verbose, test_file_paths=test_files, test_env=test_env, cwd=cwd ) logger.debug( - f"Result return code: {results.returncode}" - + (f", Result stderr: {results.stderr}" if results.stderr else "") + f"""Result return code: {results.returncode}, {"Result stderr:" + str(results.stderr) if results.stderr else ""}""" ) else: msg = f"Unsupported test framework: {test_framework}" @@ -134,7 +137,11 @@ def run_benchmarking_tests( pytest_max_loops: int = 100_000, ) -> tuple[Path, subprocess.CompletedProcess]: if test_framework == "pytest": - pytest_cmd_list = shlex.split(pytest_cmd, posix=IS_POSIX) + pytest_cmd_list = ( + shlex.split(f"{SAFE_SYS_EXECUTABLE} -m pytest", posix=IS_POSIX) + if pytest_cmd == "pytest" + else shlex.split(pytest_cmd) + ) test_files: list[str] = [] for file in test_paths.test_files: if file.test_type in [TestType.REPLAY_TEST, TestType.EXISTING_UNIT_TEST] and file.tests_in_file: diff --git a/codeflash/verification/verification_utils.py b/codeflash/verification/verification_utils.py index 79f1b9656..c3a7e0718 100644 --- a/codeflash/verification/verification_utils.py +++ b/codeflash/verification/verification_utils.py @@ -6,6 +6,8 @@ from pydantic.dataclasses import dataclass +from codeflash.code_utils.compat import SAFE_SYS_EXECUTABLE + def get_test_file_path(test_dir: Path, function_name: str, iteration: int = 0, test_type: str = "unit") -> Path: assert test_type in ["unit", "inspired", "replay", "perf"] @@ -74,4 +76,4 @@ class TestConfig: # tests_project_rootdir corresponds to pytest rootdir, # or for unittest - project_root_from_module_root(args.tests_root, pyproject_file_path) concolic_test_root_dir: Optional[Path] = None - pytest_cmd: str = "pytest" + pytest_cmd: str = "pytest" \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index a4c023ed6..1a5e63f8e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -69,7 +69,7 @@ exclude = [ [tool.poetry.dependencies] python = ">=3.9" unidiff = ">=0.7.4" -pytest = ">=7.0.0" +pytest = ">=7.0.0,<8.3.4" gitpython = ">=3.1.31" libcst = ">=1.0.1" jedi = ">=0.19.1" @@ -120,6 +120,7 @@ types-greenlet = "^3.1.0.20241221" types-pexpect = "^4.9.0.20241208" types-unidiff = "^0.7.0.20240505" sqlalchemy = "^2.0.38" +uv = ">=0.6.2" [tool.poetry.build] script = "codeflash/update_license_version.py" @@ -221,8 +222,8 @@ module-root = "codeflash" tests-root = "tests" test-framework = "pytest" formatter-cmds = [ - "poetry run ruff check --exit-zero --fix $file", - "poetry run ruff format $file", + "uvx ruff check --exit-zero --fix $file", + "uvx ruff format $file", ]