Skip to content

Conversation

@codeflash-ai
Copy link
Contributor

@codeflash-ai codeflash-ai bot commented Aug 6, 2025

⚡️ This pull request contains optimizations for PR #533

If you approve this dependent PR, these changes will be merged into the original PR branch feat/verify-and-submit-api-key-in-lsp.

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


📄 11% (0.11x) speedup for get_user_id in codeflash/api/cfapi.py

⏱️ Runtime : 126 milliseconds 114 milliseconds (best of 11 runs)

📝 Explanation and details

The optimized code achieves a 10% speedup through several key improvements:

1. Added Module-Level Import Fallback for CFAPI_BASE_URL
The optimized version imports CFAPI_BASE_URL at module load time with a try/except fallback, avoiding repeated import resolution during function calls. This eliminates the overhead of dynamic URL construction that was present in the original code.

2. Streamlined JSON Error Message Parsing
In the make_cfapi_request function, the error handling was simplified from:

if "error" in json_response:
    error_message = json_response["error"]
elif "message" in json_response:
    error_message = json_response["message"]

to:

error_message = json_response.get("error") or json_response.get("message", "")

This reduces dictionary lookups and conditional branching.

3. Enhanced Response Handling in get_user_id
The optimized version adds explicit exception handling around response.json() parsing and caches response.text to avoid multiple property access. It also uses more descriptive variable names (min_version_str) to improve code clarity.

Performance Benefits by Test Case:

  • API key missing scenarios: 12% faster (115ms → 102ms) - benefits most from the import optimization
  • Basic success cases: 1-2% faster - benefits from streamlined error handling
  • Error response handling: Minimal but consistent 0.2% improvements

The optimizations are most effective for scenarios involving missing API keys or repeated function calls, where the module-level import resolution provides the largest performance gain.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 140 Passed
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 🔘 None Found
📊 Tests Coverage 72.7%
🌀 Generated Regression Tests and Runtime
from __future__ import annotations

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

# imports
import pytest  # used for our unit tests
import requests
from codeflash.api.cfapi import get_user_id
from packaging import version


# Mocks for dependencies used in get_user_id
class DummyConsole:
    quiet = False
    def print(self, msg):
        pass

class DummyLogger:
    def error(self, msg): pass
    def debug(self, msg): pass
def read_api_key_from_shell_config(): return None

console = DummyConsole()
logger = DummyLogger()
__version__ = "1.2.3"

# --- Functions under test and their dependencies (minimally mocked for testability) ---

@lru_cache(maxsize=1)
def get_codeflash_api_key() -> str:
    if console.quiet:  # lsp
        api_key = read_api_key_from_shell_config()
    else:
        api_key = os.environ.get("CODEFLASH_API_KEY") or read_api_key_from_shell_config()
    api_secret_docs_message = "For more information, refer to the documentation at [https://docs.codeflash.ai/getting-started/codeflash-github-actions#add-your-api-key-to-your-repository-secrets]."  # noqa
    if not api_key:
        msg = (
            "I didn't find a Codeflash API key in your environment.\nYou can generate one at "
            "https://app.codeflash.ai/app/apikeys ,\nthen set it as a CODEFLASH_API_KEY environment variable.\n"
            f"{api_secret_docs_message}"
        )
        raise OSError(msg)
    if not api_key.startswith("cf-"):
        msg = (
            f"Your Codeflash API key seems to be invalid. It should start with a 'cf-' prefix; I found '{api_key}' "
            f"instead.\nYou can generate one at https://app.codeflash.ai/app/apikeys ,\nthen set it as a "
            f"CODEFLASH_API_KEY environment variable."
        )
        raise OSError(msg)
    return api_key
from codeflash.api.cfapi import get_user_id

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















#------------------------------------------------
from __future__ import annotations

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

# imports
import pytest  # used for our unit tests
import requests
from codeflash.api.cfapi import get_user_id


# Dummy classes and functions to allow the test to run in isolation
class DummyConsole:
    quiet = False
    def print(self, msg): pass

class DummyLogger:
    def error(self, msg): pass
    def debug(self, msg): pass

def exit_with_message(msg):
    raise SystemExit(msg)

def read_api_key_from_shell_config():
    return os.environ.get("SHELL_CODEFLASH_API_KEY")

def is_repo_a_fork():
    return False

console = DummyConsole()
logger = DummyLogger()

__version__ = "1.2.3"

class DummyVersion:
    @staticmethod
    def parse(v):
        return tuple(map(int, v.split('.')))

version = DummyVersion()

# Implementation of get_codeflash_api_key and ensure_codeflash_api_key
@lru_cache(maxsize=1)
def get_codeflash_api_key() -> str:
    if getattr(console, "quiet", False):
        api_key = read_api_key_from_shell_config()
    else:
        api_key = os.environ.get("CODEFLASH_API_KEY") or read_api_key_from_shell_config()

    api_secret_docs_message = "For more information, refer to the documentation at [https://docs.codeflash.ai/getting-started/codeflash-github-actions#add-your-api-key-to-your-repository-secrets]."  # noqa
    if not api_key:
        msg = (
            "I didn't find a Codeflash API key in your environment.\nYou can generate one at "
            "https://app.codeflash.ai/app/apikeys ,\nthen set it as a CODEFLASH_API_KEY environment variable.\n"
            f"{api_secret_docs_message}"
        )
        if is_repo_a_fork():
            msg = (
                "Codeflash API key not detected in your environment. It appears you're running Codeflash from a GitHub fork.\n"
                "For external contributors, please ensure you've added your own API key to your fork's repository secrets and set it as the CODEFLASH_API_KEY environment variable.\n"
                f"{api_secret_docs_message}"
            )
            exit_with_message(msg)
        raise OSError(msg)
    if not api_key.startswith("cf-"):
        msg = (
            f"Your Codeflash API key seems to be invalid. It should start with a 'cf-' prefix; I found '{api_key}' "
            f"instead.\nYou can generate one at https://app.codeflash.ai/app/apikeys ,\nthen set it as a "
            f"CODEFLASH_API_KEY environment variable."
        )
        raise OSError(msg)
    return api_key
from codeflash.api.cfapi import get_user_id


@pytest.fixture
def patch_env(monkeypatch):
    # Helper fixture to patch environment variables
    def _set_env(key, value):
        monkeypatch.setenv(key, value)
    return _set_env

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

def test_get_user_id_returns_userid_on_success(monkeypatch, patch_env):
    """Basic: Should return userId string if API returns 200 and userId present."""
    patch_env("CODEFLASH_API_KEY", "cf-123456")
    # Mock API response
    mock_response = MagicMock()
    mock_response.status_code = 200
    mock_response.text = '{"userId":"abc123"}'
    mock_response.json.return_value = {"userId": "abc123"}
    with patch("requests.get", return_value=mock_response):
        codeflash_output = get_user_id() # 270μs -> 265μs (2.21% faster)

def test_get_user_id_returns_userid_if_text_is_id(monkeypatch, patch_env):
    """Basic: Should return response.text directly if 'min_version' not in text."""
    patch_env("CODEFLASH_API_KEY", "cf-abcdef")
    mock_response = MagicMock()
    mock_response.status_code = 200
    mock_response.text = "user-xyz"
    mock_response.json.side_effect = Exception("Should not be called")
    with patch("requests.get", return_value=mock_response):
        codeflash_output = get_user_id() # 249μs -> 248μs (0.218% faster)

def test_get_user_id_returns_none_on_api_401(monkeypatch, patch_env):
    """Basic: Should return None if API returns 401 Unauthorized."""
    patch_env("CODEFLASH_API_KEY", "cf-abcdef")
    mock_response = MagicMock()
    mock_response.status_code = 401
    mock_response.reason = "Unauthorized"
    with patch("requests.get", return_value=mock_response):
        codeflash_output = get_user_id() # 1.00ms -> 982μs (2.14% faster)

def test_get_user_id_returns_none_if_no_api_key(monkeypatch):
    """Basic: Should return None if no API key is present in env or shell config."""
    # Remove env var and shell config
    monkeypatch.delenv("CODEFLASH_API_KEY", raising=False)
    monkeypatch.delenv("SHELL_CODEFLASH_API_KEY", raising=False)
    codeflash_output = get_user_id() # 115ms -> 102ms (12.0% faster)

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


def test_get_user_id_min_version_too_high(monkeypatch, patch_env):
    """Edge: Should exit if min_version in response is higher than __version__."""
    patch_env("CODEFLASH_API_KEY", "cf-abcdef")
    mock_response = MagicMock()
    mock_response.status_code = 200
    mock_response.text = '{"userId":"abc123","min_version":"9.9.9"}'
    mock_response.json.return_value = {"userId": "abc123", "min_version": "9.9.9"}
    # Patch sys.exit to raise SystemExit so we can catch it
    with patch("requests.get", return_value=mock_response), \
         patch("sys.exit", side_effect=SystemExit) as mock_exit:
        with pytest.raises(SystemExit):
            get_user_id()
        mock_exit.assert_called_once_with(1)


def test_get_user_id_returns_none_if_userid_missing(monkeypatch, patch_env):
    """Edge: Should return None if API returns 200 but no userId in response."""
    patch_env("CODEFLASH_API_KEY", "cf-abcdef")
    mock_response = MagicMock()
    mock_response.status_code = 200
    mock_response.text = '{"foo":"bar"}'
    mock_response.json.return_value = {"foo": "bar"}
    with patch("requests.get", return_value=mock_response):
        codeflash_output = get_user_id() # 261μs -> 256μs (1.72% faster)

def test_get_user_id_returns_none_if_api_returns_error(monkeypatch, patch_env):
    """Edge: Should return None if API returns non-200 and error message in JSON."""
    patch_env("CODEFLASH_API_KEY", "cf-abcdef")
    mock_response = MagicMock()
    mock_response.status_code = 403
    mock_response.reason = "Forbidden"
    mock_response.json.return_value = {"error": "forbidden"}
    with patch("requests.get", return_value=mock_response):
        codeflash_output = get_user_id() # 856μs -> 854μs (0.200% faster)

def test_get_user_id_handles_non_json_response(monkeypatch, patch_env):
    """Edge: Should return None if API returns 500 and text is not JSON."""
    patch_env("CODEFLASH_API_KEY", "cf-abcdef")
    mock_response = MagicMock()
    mock_response.status_code = 500
    mock_response.reason = "Internal Server Error"
    mock_response.text = "Server error"
    mock_response.json.side_effect = ValueError("Not JSON")
    with patch("requests.get", return_value=mock_response):
        codeflash_output = get_user_id() # 844μs -> 842μs (0.195% faster)

def test_get_user_id_handles_shell_config(monkeypatch):
    """Edge: Should use shell config if CODEFLASH_API_KEY is missing and console.quiet is True."""
    monkeypatch.delenv("CODEFLASH_API_KEY", raising=False)
    monkeypatch.setenv("SHELL_CODEFLASH_API_KEY", "cf-shellkey")
    monkeypatch.setattr(console, "quiet", True)
    mock_response = MagicMock()
    mock_response.status_code = 200
    mock_response.text = "shell-userid"
    with patch("requests.get", return_value=mock_response):
        codeflash_output = get_user_id() # 251μs -> 257μs (2.08% slower)



def test_get_user_id_large_scale_many_different_users(monkeypatch):
    """Large Scale: Should handle different API keys and return correct userIds."""
    # Simulate up to 10 different users
    for i in range(10):
        key = f"cf-key-{i}"
        user_id = f"user-{i}"
        with patch.dict(os.environ, {"CODEFLASH_API_KEY": key}):
            get_codeflash_api_key.cache_clear()
            get_user_id.cache_clear()
            mock_response = MagicMock()
            mock_response.status_code = 200
            mock_response.text = user_id
            with patch("requests.get", return_value=mock_response):
                codeflash_output = get_user_id()


def test_get_user_id_large_scale_batch(monkeypatch, patch_env):
    """Large Scale: Should handle 1000 sequential calls with different userIds (simulate no cache)."""
    patch_env("CODEFLASH_API_KEY", "cf-abcdef")
    for i in range(20):  # keep under 1000 for test speed
        get_user_id.cache_clear()
        user_id = f"user-{i}"
        mock_response = MagicMock()
        mock_response.status_code = 200
        mock_response.text = user_id
        with patch("requests.get", return_value=mock_response):
            codeflash_output = get_user_id()
# 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-pr533-2025-08-06T13.18.19 and push.

Codeflash

…d-submit-api-key-in-lsp`)

The optimized code achieves a **10% speedup** through several key improvements:

**1. Added Module-Level Import Fallback for CFAPI_BASE_URL**
The optimized version imports `CFAPI_BASE_URL` at module load time with a try/except fallback, avoiding repeated import resolution during function calls. This eliminates the overhead of dynamic URL construction that was present in the original code.

**2. Streamlined JSON Error Message Parsing**
In the `make_cfapi_request` function, the error handling was simplified from:
```python
if "error" in json_response:
    error_message = json_response["error"]
elif "message" in json_response:
    error_message = json_response["message"]
```
to:
```python
error_message = json_response.get("error") or json_response.get("message", "")
```
This reduces dictionary lookups and conditional branching.

**3. Enhanced Response Handling in get_user_id**
The optimized version adds explicit exception handling around `response.json()` parsing and caches `response.text` to avoid multiple property access. It also uses more descriptive variable names (`min_version_str`) to improve code clarity.

**Performance Benefits by Test Case:**
- **API key missing scenarios**: 12% faster (115ms → 102ms) - benefits most from the import optimization
- **Basic success cases**: 1-2% faster - benefits from streamlined error handling
- **Error response handling**: Minimal but consistent 0.2% improvements

The optimizations are most effective for scenarios involving missing API keys or repeated function calls, where the module-level import resolution provides the largest performance gain.
@codeflash-ai codeflash-ai bot added the ⚡️ codeflash Optimization PR opened by Codeflash AI label Aug 6, 2025
@codeflash-ai codeflash-ai bot closed this Aug 6, 2025
@codeflash-ai
Copy link
Contributor Author

codeflash-ai bot commented Aug 6, 2025

This PR has been automatically closed because the original PR #533 by mohammedahmed18 was closed.

@codeflash-ai codeflash-ai bot deleted the codeflash/optimize-pr533-2025-08-06T13.18.19 branch August 6, 2025 13:36
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.

0 participants