Skip to content

Conversation

@codeflash-ai
Copy link

@codeflash-ai codeflash-ai bot commented Nov 4, 2025

📄 35% (0.35x) speedup for create_exception_from_response in mem0/exceptions.py

⏱️ Runtime : 4.91 milliseconds 3.63 milliseconds (best of 179 runs)

📝 Explanation and details

The optimized code achieves a 35% speedup by eliminating the repeated creation of the suggestions dictionary on every function call.

Key optimization:

  • Moved the suggestions dictionary outside the function as a module-level constant _SUGGESTIONS
  • Eliminated dictionary recreation overhead - the original code created a 13-entry dictionary with string values on every function call, which involved repeated memory allocation and object creation

Performance impact:
The line profiler shows the original code spent ~29% of its time (lines with dictionary entries) just creating the suggestions dictionary. The optimized version eliminates this entirely, reducing total runtime from 26.8ms to 15.8ms.

Why this works:

  • Dictionary creation in Python involves memory allocation and hash table setup
  • String literals in dictionaries still need to be processed and stored as objects
  • Moving to a module-level constant means the dictionary is created once at import time rather than on every function call
  • The suggestion lookup _SUGGESTIONS.get(status_code, "Please try again later") is now just a single hash table lookup

Test case performance:
All test cases show consistent 17-40% speedups, with particularly strong gains for:

  • Bulk operations (36-40% faster) - where the dictionary recreation overhead compounds
  • Edge cases with unknown status codes (35-40% faster) - still benefit from eliminating dictionary creation
  • Basic single calls (17-35% faster) - benefit from removing the creation overhead

This optimization is especially effective for applications that handle many HTTP errors or exceptions in tight loops.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 3854 Passed
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 🔘 None Found
📊 Tests Coverage 100.0%
🌀 Generated Regression Tests and Runtime
from typing import Any, Dict, Optional

# imports
import pytest
from mem0.exceptions import create_exception_from_response


# Dummy exception classes to simulate actual exception hierarchy
class MemoryError(Exception):
    def __init__(self, message, error_code=None, details=None, suggestion=None, debug_info=None):
        super().__init__(message)
        self.message = message
        self.error_code = error_code
        self.details = details or {}
        self.suggestion = suggestion
        self.debug_info = debug_info or {}

class ValidationError(MemoryError): pass
class AuthenticationError(MemoryError): pass
class MemoryNotFoundError(MemoryError): pass
class NetworkError(MemoryError): pass
class MemoryQuotaExceededError(MemoryError): pass
class RateLimitError(MemoryError): pass


HTTP_STATUS_TO_EXCEPTION = {
    400: ValidationError,
    401: AuthenticationError,
    403: AuthenticationError,
    404: MemoryNotFoundError,
    408: NetworkError,
    409: ValidationError,
    413: MemoryQuotaExceededError,
    422: ValidationError,
    429: RateLimitError,
    500: MemoryError,
    502: NetworkError,
    503: NetworkError,
    504: NetworkError,
}
from mem0.exceptions import create_exception_from_response

# unit tests

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

def test_returns_validation_error_for_400():
    """Should return ValidationError for status code 400."""
    codeflash_output = create_exception_from_response(400, "Bad Request"); exc = codeflash_output # 3.65μs -> 2.95μs (24.0% faster)

def test_returns_authentication_error_for_401():
    """Should return AuthenticationError for status code 401."""
    codeflash_output = create_exception_from_response(401, "Unauthorized", error_code="AUTH_FAIL"); exc = codeflash_output # 3.68μs -> 3.02μs (21.8% faster)

def test_returns_memory_not_found_error_for_404():
    """Should return MemoryNotFoundError for status code 404."""
    codeflash_output = create_exception_from_response(404, "Not Found"); exc = codeflash_output # 3.79μs -> 2.81μs (34.7% faster)

def test_returns_network_error_for_408():
    """Should return NetworkError for status code 408."""
    codeflash_output = create_exception_from_response(408, "Timeout"); exc = codeflash_output # 4.32μs -> 3.38μs (27.6% faster)

def test_returns_memory_error_for_500():
    """Should return MemoryError for status code 500."""
    codeflash_output = create_exception_from_response(500, "Internal Error"); exc = codeflash_output # 3.69μs -> 2.93μs (25.7% faster)

def test_returns_default_memory_error_for_unknown_status():
    """Should return MemoryError for unknown status code."""
    codeflash_output = create_exception_from_response(599, "Unknown Error"); exc = codeflash_output # 3.69μs -> 2.73μs (35.3% faster)

def test_response_text_empty_uses_default_message():
    """Should use default message if response_text is empty."""
    codeflash_output = create_exception_from_response(404, ""); exc = codeflash_output # 4.10μs -> 3.17μs (29.3% faster)
    # Even if empty, message is as passed (no fallback)

def test_details_and_debug_info_are_passed():
    """Should pass details and debug_info to exception."""
    details = {"field": "name", "error": "missing"}
    debug_info = {"trace_id": "abc123"}
    codeflash_output = create_exception_from_response(422, "Invalid data", details=details, debug_info=debug_info); exc = codeflash_output # 4.25μs -> 3.34μs (27.1% faster)

def test_returns_rate_limit_error_for_429():
    """Should return RateLimitError for status code 429."""
    codeflash_output = create_exception_from_response(429, "Rate limit exceeded"); exc = codeflash_output # 4.01μs -> 2.95μs (35.9% faster)

def test_returns_memory_quota_exceeded_error_for_413():
    """Should return MemoryQuotaExceededError for status code 413."""
    codeflash_output = create_exception_from_response(413, "Too Large"); exc = codeflash_output # 4.21μs -> 3.42μs (23.1% faster)

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

def test_none_response_text():
    """Should handle None response_text gracefully."""
    codeflash_output = create_exception_from_response(404, None); exc = codeflash_output # 3.67μs -> 2.97μs (23.7% faster)

def test_none_details_and_debug_info():
    """Should set details and debug_info to empty dict if None."""
    codeflash_output = create_exception_from_response(400, "Bad Request", details=None, debug_info=None); exc = codeflash_output # 4.04μs -> 3.03μs (33.3% faster)

def test_empty_details_and_debug_info():
    """Should preserve empty dicts for details and debug_info."""
    codeflash_output = create_exception_from_response(400, "Bad Request", details={}, debug_info={}); exc = codeflash_output # 3.90μs -> 3.05μs (28.1% faster)

def test_custom_error_code_is_used():
    """Should use provided error_code over default."""
    codeflash_output = create_exception_from_response(400, "Bad Request", error_code="CUSTOM_ERR"); exc = codeflash_output # 3.56μs -> 2.84μs (25.3% faster)

def test_unknown_status_code_suggestion():
    """Should use default suggestion for unknown status code."""
    codeflash_output = create_exception_from_response(599, "Unknown Error"); exc = codeflash_output # 3.91μs -> 2.97μs (31.7% faster)


def test_negative_status_code():
    """Should treat negative status code as unknown."""
    codeflash_output = create_exception_from_response(-1, "Negative code"); exc = codeflash_output # 5.22μs -> 3.77μs (38.4% faster)

def test_zero_status_code():
    """Should treat status code 0 as unknown."""
    codeflash_output = create_exception_from_response(0, "Zero code"); exc = codeflash_output # 4.10μs -> 3.20μs (28.1% faster)

def test_large_status_code():
    """Should treat large status code as unknown."""
    codeflash_output = create_exception_from_response(999, "Large code"); exc = codeflash_output # 4.14μs -> 3.06μs (35.3% faster)

def test_none_error_code_generates_default():
    """Should generate default error_code if None is passed."""
    codeflash_output = create_exception_from_response(400, "Bad Request", error_code=None); exc = codeflash_output # 4.61μs -> 3.83μs (20.2% faster)

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

def test_many_different_status_codes():
    """Should handle a large number of status codes efficiently."""
    # Test all codes from 400 to 504 (inclusive)
    for code in range(400, 505):
        codeflash_output = create_exception_from_response(code, f"Error {code}"); exc = codeflash_output # 133μs -> 99.3μs (34.0% faster)
        # Check exception class
        expected_class = HTTP_STATUS_TO_EXCEPTION.get(code, MemoryError)
        # Check suggestion
        if code in HTTP_STATUS_TO_EXCEPTION:
            pass
        else:
            pass

def test_large_details_and_debug_info():
    """Should handle large details and debug_info dicts."""
    large_details = {str(i): i for i in range(1000)}
    large_debug_info = {str(i): f"debug{i}" for i in range(1000)}
    codeflash_output = create_exception_from_response(422, "Large payload", details=large_details, debug_info=large_debug_info); exc = codeflash_output # 4.21μs -> 3.32μs (26.7% faster)

def test_bulk_create_exceptions_performance():
    """Should efficiently create many exceptions in a loop."""
    # Not a performance benchmark, but checks for memory/logic errors
    for i in range(1000):
        code = 400 + (i % 10)
        codeflash_output = create_exception_from_response(code, f"Bulk {i}", details={"idx": i}); exc = codeflash_output # 1.28ms -> 941μs (36.0% faster)

def test_bulk_custom_error_codes():
    """Should handle many custom error codes."""
    for i in range(1000):
        codeflash_output = create_exception_from_response(400, f"Bulk {i}", error_code=f"CUSTOM_{i}"); exc = codeflash_output # 1.19ms -> 869μs (36.7% faster)

def test_bulk_none_response_text():
    """Should handle many None response_texts."""
    for i in range(1000):
        codeflash_output = create_exception_from_response(404, None); exc = codeflash_output # 1.26ms -> 949μs (33.1% faster)
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.
#------------------------------------------------
from typing import Any, Dict, Optional

# imports
import pytest
from mem0.exceptions import create_exception_from_response


# Dummy exception classes to allow the function to work for testing
class MemoryError(Exception):
    def __init__(self, message, error_code=None, details=None, suggestion=None, debug_info=None):
        super().__init__(message)
        self.message = message
        self.error_code = error_code
        self.details = details or {}
        self.suggestion = suggestion
        self.debug_info = debug_info or {}

class ValidationError(MemoryError): pass
class AuthenticationError(MemoryError): pass
class MemoryNotFoundError(MemoryError): pass
class NetworkError(MemoryError): pass
class MemoryQuotaExceededError(MemoryError): pass
class RateLimitError(MemoryError): pass


HTTP_STATUS_TO_EXCEPTION = {
    400: ValidationError,
    401: AuthenticationError,
    403: AuthenticationError,
    404: MemoryNotFoundError,
    408: NetworkError,
    409: ValidationError,
    413: MemoryQuotaExceededError,
    422: ValidationError,
    429: RateLimitError,
    500: MemoryError,
    502: NetworkError,
    503: NetworkError,
    504: NetworkError,
}
from mem0.exceptions import create_exception_from_response

# unit tests

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

def test_basic_400_validation_error():
    # 400 should map to ValidationError
    codeflash_output = create_exception_from_response(400, "Bad Request"); ex = codeflash_output # 3.85μs -> 3.01μs (28.1% faster)

def test_basic_401_authentication_error():
    # 401 should map to AuthenticationError
    codeflash_output = create_exception_from_response(401, "Unauthorized", error_code="AUTH_FAIL"); ex = codeflash_output # 3.83μs -> 3.26μs (17.4% faster)

def test_basic_404_memory_not_found_error():
    # 404 should map to MemoryNotFoundError
    codeflash_output = create_exception_from_response(404, "Not Found"); ex = codeflash_output # 3.59μs -> 2.65μs (35.6% faster)

def test_basic_429_rate_limit_error():
    # 429 should map to RateLimitError
    codeflash_output = create_exception_from_response(429, "Rate limit exceeded", debug_info={"retry_after": 60}); ex = codeflash_output # 4.35μs -> 3.21μs (35.5% faster)

def test_basic_500_memory_error():
    # 500 should map to MemoryError
    codeflash_output = create_exception_from_response(500, "Internal Error", details={"trace_id": "abc"}); ex = codeflash_output # 4.26μs -> 3.31μs (28.7% faster)

# ------------------ EDGE TEST CASES ------------------

def test_edge_unknown_status_code():
    # Unknown status code should map to MemoryError
    codeflash_output = create_exception_from_response(599, "Unknown Error", error_code="CUSTOM_ERR"); ex = codeflash_output # 3.68μs -> 2.85μs (28.8% faster)

def test_edge_empty_response_text():
    # Empty response_text should fallback to HTTP error message
    codeflash_output = create_exception_from_response(404, "", details={"info": "missing"}); ex = codeflash_output # 4.42μs -> 3.29μs (34.5% faster)

def test_edge_none_details_and_debug_info():
    # None details/debug_info should default to empty dict
    codeflash_output = create_exception_from_response(408, "Timeout", details=None, debug_info=None); ex = codeflash_output # 4.91μs -> 3.70μs (32.6% faster)

def test_edge_custom_error_code_and_debug_info():
    # Custom error_code and debug_info should be used
    dbg = {"step": "connect", "timeout": 30}
    codeflash_output = create_exception_from_response(504, "Gateway Timeout", error_code="GW_TIMEOUT", debug_info=dbg); ex = codeflash_output # 4.47μs -> 3.21μs (39.1% faster)

def test_edge_nonstandard_status_code():
    # Non-standard but valid status code
    codeflash_output = create_exception_from_response(418, "I'm a teapot"); ex = codeflash_output # 3.83μs -> 2.94μs (30.4% faster)

def test_edge_details_are_mutable():
    # Ensure details is copied (not shared between calls)
    details = {"foo": "bar"}
    codeflash_output = create_exception_from_response(400, "Bad", details=details); ex1 = codeflash_output # 4.05μs -> 3.33μs (21.9% faster)
    details["foo"] = "baz"
    codeflash_output = create_exception_from_response(400, "Bad", details=None); ex2 = codeflash_output # 2.24μs -> 1.71μs (30.8% faster)

def test_edge_debug_info_are_mutable():
    # Ensure debug_info is copied (not shared between calls)
    debug_info = {"x": 1}
    codeflash_output = create_exception_from_response(400, "Bad", debug_info=debug_info); ex1 = codeflash_output # 3.90μs -> 2.94μs (32.9% faster)
    debug_info["x"] = 2
    codeflash_output = create_exception_from_response(400, "Bad", debug_info=None); ex2 = codeflash_output # 2.11μs -> 1.59μs (32.2% faster)

def test_edge_suggestion_for_unmapped_code():
    # Suggestion should be default for unmapped code
    codeflash_output = create_exception_from_response(777, "Mystery"); ex = codeflash_output # 3.49μs -> 2.78μs (25.6% faster)

# ------------------ LARGE SCALE TEST CASES ------------------

def test_large_scale_many_status_codes():
    # Test all mapped status codes with unique messages
    for status_code, exc_class in HTTP_STATUS_TO_EXCEPTION.items():
        msg = f"Error {status_code}"
        codeflash_output = create_exception_from_response(status_code, msg); ex = codeflash_output # 21.0μs -> 15.9μs (31.7% faster)

def test_large_scale_bulk_creation():
    # Create 500 exceptions with different codes and messages
    for i in range(500):
        code = 400 + (i % 20)  # cycle through 400-419
        msg = f"Bulk error {i}"
        codeflash_output = create_exception_from_response(code, msg); ex = codeflash_output # 608μs -> 445μs (36.5% faster)

def test_large_scale_details_and_debug_info():
    # Test with large details/debug_info dicts
    details = {f"key{i}": i for i in range(100)}
    debug_info = {f"dbg{i}": str(i) for i in range(100)}
    codeflash_output = create_exception_from_response(413, "Too Large", details=details, debug_info=debug_info); ex = codeflash_output # 4.36μs -> 3.44μs (26.7% faster)

def test_large_scale_random_status_codes():
    # Test with many random status codes
    for code in range(600, 700):
        codeflash_output = create_exception_from_response(code, f"Code {code}"); ex = codeflash_output # 126μs -> 90.3μs (40.0% faster)

def test_large_scale_none_and_empty_values():
    # Test with None and empty values repeatedly
    for i in range(100):
        codeflash_output = create_exception_from_response(404, "", error_code=None, details=None, debug_info=None); ex = codeflash_output # 144μs -> 110μs (30.2% faster)
# 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-create_exception_from_response-mhk3hfoc and push.

Codeflash Static Badge

The optimized code achieves a **35% speedup** by eliminating the repeated creation of the `suggestions` dictionary on every function call.

**Key optimization:**
- **Moved the suggestions dictionary outside the function** as a module-level constant `_SUGGESTIONS`
- **Eliminated dictionary recreation overhead** - the original code created a 13-entry dictionary with string values on every function call, which involved repeated memory allocation and object creation

**Performance impact:**
The line profiler shows the original code spent ~29% of its time (lines with dictionary entries) just creating the suggestions dictionary. The optimized version eliminates this entirely, reducing total runtime from 26.8ms to 15.8ms.

**Why this works:**
- Dictionary creation in Python involves memory allocation and hash table setup
- String literals in dictionaries still need to be processed and stored as objects
- Moving to a module-level constant means the dictionary is created once at import time rather than on every function call
- The suggestion lookup `_SUGGESTIONS.get(status_code, "Please try again later")` is now just a single hash table lookup

**Test case performance:**
All test cases show consistent 17-40% speedups, with particularly strong gains for:
- Bulk operations (36-40% faster) - where the dictionary recreation overhead compounds
- Edge cases with unknown status codes (35-40% faster) - still benefit from eliminating dictionary creation
- Basic single calls (17-35% faster) - benefit from removing the creation overhead

This optimization is especially effective for applications that handle many HTTP errors or exceptions in tight loops.
@codeflash-ai codeflash-ai bot requested a review from mashraf-222 November 4, 2025 04:54
@codeflash-ai codeflash-ai bot added ⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: High Optimization Quality according to Codeflash labels Nov 4, 2025
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 🎯 Quality: High Optimization Quality according to Codeflash

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant