Skip to content

Conversation

@codeflash-ai
Copy link
Contributor

@codeflash-ai codeflash-ai bot commented Jun 5, 2025

⚡️ This pull request contains optimizations for PR #275

If you approve this dependent PR, these changes will be merged into the original PR branch dont-optimize-repeatedly-gh-actions.

This PR will be automatically closed if the original PR is merged.


📄 44% (0.44x) speedup for is_function_being_optimized_again in codeflash/api/cfapi.py

⏱️ Runtime : 2.79 milliseconds 1.94 milliseconds (best of 74 runs)

📝 Explanation and details

Here is the optimized version of your program, focusing on speeding up the slow path in make_cfapi_request, which is dominated by json.dumps(payload, indent=None, default=pydantic_encoder) and the use of requests.post(..., data=json_payload, ...).

Key optimizations.

  • Use requests.post(..., json=payload, ...): This lets requests do the JSON serialization more efficiently (internally uses json.dumps). Furthermore, requests will add the Content-Type: application/json header if you use the json argument.
  • Only use the custom encoder if really needed: Only pass default=pydantic_encoder if payload contains objects requiring it. If not, the standard encoder is much faster. You can try a direct serialization, and fallback if a TypeError is raised.
  • Avoid repeated .upper() inside the POST/GET dispatch by normalizing early.
  • Avoid unnecessary string interpolation.
  • Avoid updating headers dict when not needed.
  • Other micro-optimizations: Use local variables, merge dicts once, etc.
    with all comments preserved and only modified/added where code changed.

Explanation of biggest win:
The largest bottleneck was in JSON encoding and in manually setting the content-type header. Now, requests.post(..., json=payload) is used for the fastest path in the vast majority of requests, only falling back to a slower path if necessary. This should substantially speed up both serialization and POST.

This approach is backward-compatible and will produce exactly the same results as before.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 13 Passed
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 🔘 None Found
📊 Tests Coverage 100.0%
🌀 Generated Regression Tests Details
from __future__ import annotations

# We'll patch make_cfapi_request to avoid real HTTP requests.
import builtins
import json
import os
import types
from functools import lru_cache
from typing import Any, Dict

# imports
import pytest  # used for our unit tests
import requests
from codeflash.api.cfapi import is_function_being_optimized_again
from codeflash.code_utils.env_utils import get_codeflash_api_key
from codeflash.code_utils.shell_utils import read_api_key_from_shell_config
from pydantic.json import pydantic_encoder
from requests import Response

# --- UNIT TESTS ---


@pytest.fixture(autouse=True)
def patch_make_cfapi_request(monkeypatch):
    """
    This fixture automatically patches make_cfapi_request for all tests below.
    You can set patch_make_cfapi_request.mock_response to a function that will be called with the same args as make_cfapi_request.
    """
    def _default_mock(endpoint, method, payload=None, extra_headers=None):
        # Default: always return a dummy Response with .json() returning {}
        resp = types.SimpleNamespace()
        resp.raise_for_status = lambda: None
        resp.json = lambda: {}
        return resp
    patch_make_cfapi_request.mock_response = _default_mock

    def _mock_make_cfapi_request(endpoint, method, payload=None, extra_headers=None):
        return patch_make_cfapi_request.mock_response(endpoint, method, payload, extra_headers)

    monkeypatch.setattr(builtins, "make_cfapi_request", _mock_make_cfapi_request)
    monkeypatch.setattr(__name__, "make_cfapi_request", _mock_make_cfapi_request)
    yield

# Helper to build a fake Response object
def build_fake_response(json_data, status_code=200, raise_exc=None):
    resp = types.SimpleNamespace()
    resp.json = lambda: json_data
    if raise_exc is not None:
        resp.raise_for_status = lambda: (_ for _ in ()).throw(raise_exc)
    else:
        resp.raise_for_status = lambda: None
    resp.status_code = status_code
    return resp

# -------- BASIC TEST CASES --------



















from __future__ import annotations

import json
import os
from functools import lru_cache
from typing import Any, Dict
from unittest.mock import MagicMock, patch

# imports
import pytest  # used for our unit tests
import requests
from codeflash.api.cfapi import is_function_being_optimized_again
from codeflash.code_utils.env_utils import get_codeflash_api_key
from codeflash.code_utils.shell_utils import read_api_key_from_shell_config
from pydantic.json import pydantic_encoder
from requests import Response

# unit tests

# -------------------
# Basic Test Cases
# -------------------

def make_mock_response(json_data, status_code=200):
    """Helper to create a mock Response with .json() and .raise_for_status()."""
    mock_resp = MagicMock(spec=Response)
    mock_resp.json.return_value = json_data
    mock_resp.status_code = status_code
    if status_code == 200:
        mock_resp.raise_for_status.side_effect = None
    else:
        mock_resp.raise_for_status.side_effect = requests.HTTPError(f"Status: {status_code}")
    return mock_resp

@patch("codeflash.code_utils.env_utils.get_codeflash_api_key", return_value="cf-FAKEKEY")
@patch("requests.post")
def test_basic_function_optimized(mock_post, mock_get_key):
    """Test: Function is already optimized, should return expected dict."""
    # Setup
    owner = "octocat"
    repo = "Hello-World"
    pr_number = 42
    code_contexts = {"foo.py": "def foo(): pass"}
    expected_response = {"already_optimized": True, "details": "Function foo already optimized."}
    mock_post.return_value = make_mock_response(expected_response)
    # Test
    codeflash_output = is_function_being_optimized_again(owner, repo, pr_number, code_contexts); result = codeflash_output

@patch("codeflash.code_utils.env_utils.get_codeflash_api_key", return_value="cf-FAKEKEY")
@patch("requests.post")
def test_basic_function_not_optimized(mock_post, mock_get_key):
    """Test: Function is not optimized, should return expected dict."""
    owner = "octocat"
    repo = "Hello-World"
    pr_number = 43
    code_contexts = {"bar.py": "def bar(): pass"}
    expected_response = {"already_optimized": False, "details": "Function bar not optimized yet."}
    mock_post.return_value = make_mock_response(expected_response)
    codeflash_output = is_function_being_optimized_again(owner, repo, pr_number, code_contexts); result = codeflash_output

@patch("codeflash.code_utils.env_utils.get_codeflash_api_key", return_value="cf-FAKEKEY")
@patch("requests.post")
def test_basic_multiple_files(mock_post, mock_get_key):
    """Test: Multiple files in code_contexts."""
    owner = "octocat"
    repo = "Hello-World"
    pr_number = 44
    code_contexts = {
        "foo.py": "def foo(): pass",
        "bar.py": "def bar(): pass"
    }
    expected_response = {
        "already_optimized": False,
        "details": "No functions optimized yet."
    }
    mock_post.return_value = make_mock_response(expected_response)
    codeflash_output = is_function_being_optimized_again(owner, repo, pr_number, code_contexts); result = codeflash_output

# -------------------
# Edge Test Cases
# -------------------

@patch("codeflash.code_utils.env_utils.get_codeflash_api_key", return_value="cf-FAKEKEY")
@patch("requests.post")
def test_edge_empty_code_contexts(mock_post, mock_get_key):
    """Test: Empty code_contexts dict."""
    owner = "octocat"
    repo = "Hello-World"
    pr_number = 45
    code_contexts = {}
    expected_response = {"already_optimized": False, "details": "No code provided."}
    mock_post.return_value = make_mock_response(expected_response)
    codeflash_output = is_function_being_optimized_again(owner, repo, pr_number, code_contexts); result = codeflash_output

@patch("codeflash.code_utils.env_utils.get_codeflash_api_key", return_value="cf-FAKEKEY")
@patch("requests.post")
def test_edge_empty_strings(mock_post, mock_get_key):
    """Test: Empty strings for owner, repo, and code_contexts values."""
    owner = ""
    repo = ""
    pr_number = 0
    code_contexts = {"": ""}
    expected_response = {"already_optimized": False, "details": "Invalid input."}
    mock_post.return_value = make_mock_response(expected_response)
    codeflash_output = is_function_being_optimized_again(owner, repo, pr_number, code_contexts); result = codeflash_output

@patch("codeflash.code_utils.env_utils.get_codeflash_api_key", return_value="cf-FAKEKEY")
@patch("requests.post")
def test_edge_special_characters(mock_post, mock_get_key):
    """Test: Special characters in owner, repo, and code_contexts."""
    owner = "octo!@#"
    repo = "Hello-World$%^"
    pr_number = 99
    code_contexts = {"foo.py": "def foo():\n    return '©®™✓🚀'"}
    expected_response = {"already_optimized": False, "details": "Special characters detected."}
    mock_post.return_value = make_mock_response(expected_response)
    codeflash_output = is_function_being_optimized_again(owner, repo, pr_number, code_contexts); result = codeflash_output

@patch("codeflash.code_utils.env_utils.get_codeflash_api_key", return_value="cf-FAKEKEY")
@patch("requests.post")
def test_edge_nonexistent_pr(mock_post, mock_get_key):
    """Test: Nonexistent PR number (negative)."""
    owner = "octocat"
    repo = "Hello-World"
    pr_number = -1
    code_contexts = {"foo.py": "def foo(): pass"}
    expected_response = {"already_optimized": False, "details": "Invalid PR number."}
    mock_post.return_value = make_mock_response(expected_response)
    codeflash_output = is_function_being_optimized_again(owner, repo, pr_number, code_contexts); result = codeflash_output

@patch("codeflash.code_utils.env_utils.get_codeflash_api_key", return_value="cf-FAKEKEY")
@patch("requests.post")
def test_edge_large_code_string(mock_post, mock_get_key):
    """Test: Very large code string in code_contexts."""
    owner = "octocat"
    repo = "Hello-World"
    pr_number = 46
    large_code = "def foo():\n    pass\n" * 500  # ~1000 lines
    code_contexts = {"foo.py": large_code}
    expected_response = {"already_optimized": False, "details": "Large code processed."}
    mock_post.return_value = make_mock_response(expected_response)
    codeflash_output = is_function_being_optimized_again(owner, repo, pr_number, code_contexts); result = codeflash_output

# -------------------
# Large Scale Test Cases
# -------------------

@patch("codeflash.code_utils.env_utils.get_codeflash_api_key", return_value="cf-FAKEKEY")
@patch("requests.post")
def test_large_scale_many_files(mock_post, mock_get_key):
    """Test: code_contexts with 1000 files."""
    owner = "octocat"
    repo = "Hello-World"
    pr_number = 47
    code_contexts = {f"file_{i}.py": f"def func_{i}(): pass" for i in range(1000)}
    expected_response = {"already_optimized": False, "details": "Processed 1000 files."}
    mock_post.return_value = make_mock_response(expected_response)
    codeflash_output = is_function_being_optimized_again(owner, repo, pr_number, code_contexts); result = codeflash_output

@patch("codeflash.code_utils.env_utils.get_codeflash_api_key", return_value="cf-FAKEKEY")
@patch("requests.post")
def test_large_scale_long_file_names(mock_post, mock_get_key):
    """Test: code_contexts with very long file names."""
    owner = "octocat"
    repo = "Hello-World"
    pr_number = 48
    long_name = "a" * 200 + ".py"
    code_contexts = {long_name: "def foo(): pass"}
    expected_response = {"already_optimized": False, "details": "Long filename processed."}
    mock_post.return_value = make_mock_response(expected_response)
    codeflash_output = is_function_being_optimized_again(owner, repo, pr_number, code_contexts); result = codeflash_output

@patch("codeflash.code_utils.env_utils.get_codeflash_api_key", return_value="cf-FAKEKEY")
@patch("requests.post")
def test_large_scale_large_code_and_files(mock_post, mock_get_key):
    """Test: code_contexts with 100 files, each with a large code string."""
    owner = "octocat"
    repo = "Hello-World"
    pr_number = 49
    large_code = "def foo():\n    pass\n" * 100  # ~200 lines per file
    code_contexts = {f"file_{i}.py": large_code for i in range(100)}
    expected_response = {"already_optimized": False, "details": "Processed 100 files with large code."}
    mock_post.return_value = make_mock_response(expected_response)
    codeflash_output = is_function_being_optimized_again(owner, repo, pr_number, code_contexts); result = codeflash_output

# -------------------
# Error Handling Test Cases
# -------------------

@patch("codeflash.code_utils.env_utils.get_codeflash_api_key", return_value="cf-FAKEKEY")
@patch("requests.post")
def test_http_error_raises(mock_post, mock_get_key):
    """Test: HTTP error from API raises requests.HTTPError."""
    owner = "octocat"
    repo = "Hello-World"
    pr_number = 50
    code_contexts = {"foo.py": "def foo(): pass"}
    mock_post.return_value = make_mock_response({"error": "Forbidden"}, status_code=403)
    with pytest.raises(requests.HTTPError):
        is_function_being_optimized_again(owner, repo, pr_number, code_contexts)

@patch("codeflash.code_utils.env_utils.get_codeflash_api_key", return_value="cf-FAKEKEY")
@patch("requests.post")
def test_non_json_response_raises(mock_post, mock_get_key):
    """Test: Non-JSON response from API raises ValueError when .json() called."""
    owner = "octocat"
    repo = "Hello-World"
    pr_number = 51
    code_contexts = {"foo.py": "def foo(): pass"}
    mock_resp = MagicMock(spec=Response)
    mock_resp.status_code = 200
    mock_resp.raise_for_status.side_effect = None
    mock_resp.json.side_effect = ValueError("No JSON object could be decoded")
    mock_post.return_value = mock_resp
    with pytest.raises(ValueError):
        is_function_being_optimized_again(owner, repo, pr_number, code_contexts)
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.

To edit these changes git checkout codeflash/optimize-pr275-2025-06-05T20.35.24 and push.

Codeflash

…275 (`dont-optimize-repeatedly-gh-actions`)

Here is the optimized version of your program, focusing on speeding up the slow path in `make_cfapi_request`, which is dominated by `json.dumps(payload, indent=None, default=pydantic_encoder)` and the use of `requests.post(..., data=json_payload, ...)`. 

Key optimizations.

- **Use `requests.post(..., json=payload, ...)`:** This lets `requests` do the JSON serialization more efficiently (internally uses `json.dumps`). Furthermore, `requests` will add the `Content-Type: application/json` header if you use the `json` argument.
- **Only use the custom encoder if really needed:** Only pass `default=pydantic_encoder` if payload contains objects requiring it. If not, the standard encoder is much faster. You can try a direct serialization, and fallback if a `TypeError` is raised.
- **Avoid repeated `.upper()`** inside the POST/GET dispatch by normalizing early.
- **Avoid unnecessary string interpolation.**
- **Avoid updating headers dict when not needed.**
- **Other micro-optimizations:** Use local variables, merge dicts once, etc.
with all comments preserved and only modified/added where code changed.



**Explanation of biggest win:**  
The largest bottleneck was in JSON encoding and in manually setting the content-type header. Now, `requests.post(..., json=payload)` is used for the fastest path in the vast majority of requests, only falling back to a slower path if necessary. This should substantially speed up both serialization and POST.

This approach is backward-compatible and will produce exactly the same results as before.
@codeflash-ai codeflash-ai bot added the ⚡️ codeflash Optimization PR opened by Codeflash AI label Jun 5, 2025
@misrasaurabh1
Copy link
Contributor

we shouldn't change this code

@codeflash-ai codeflash-ai bot deleted the codeflash/optimize-pr275-2025-06-05T20.35.24 branch June 5, 2025 20:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

⚡️ codeflash Optimization PR opened by Codeflash AI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants