Skip to content

Conversation

@codeflash-ai
Copy link

@codeflash-ai codeflash-ai bot commented Apr 29, 2025

📄 19% (0.19x) speedup for ResourceTemplate.from_function in src/mcp/server/fastmcp/resources/templates.py

⏱️ Runtime : 420 milliseconds 351 milliseconds (best of 19 runs)

📝 Explanation and details

Here is an optimized version of your ResourceTemplate.from_function method.
Key optimizations.

  • Avoid calling fn.__doc__ and "text/plain" repeatedly inside the return statement by computing all needed default/fallback values before the object construction.
  • Only call validate_call(fn) if needed, assigning directly otherwise.
  • Use local variables to minimize attribute lookup (which can slightly help, though recent Pythons are better).
  • Assign the lambda check to a local variable for speed.
  • Avoid unnecessary string concatenation; defaults are computed with simple short-circuit logic.
  • The most expensive line is the TypeAdapter(fn).json_schema(), which is intrinsic to extracting the schema; there's no faster way using Pydantic v2, so this is kept but put as early as possible to fail fast.

All comments are preserved (except where lines have been improved/clarified).

Net result:

  • Reduced repeated lookups and conditionals in the return statement.
  • Branching/casting is “flattened” for best interpreter throughput.
  • Calls stay single-pass; main logic flow is not changed.
  • All side effects/return values remain exactly the same.

If you need further runtime gains, consider caching the result of TypeAdapter(fn) at a higher level if you'll be constructing many templates for the same function object(s). Otherwise, this is already approaching the limits given the dependence on Pydantic's dynamic typing machinery.

Correctness verification report:

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

from collections.abc import Callable
from typing import Any

# imports
import pytest  # used for our unit tests
from pydantic import BaseModel, Field, TypeAdapter, validate_call
from src.mcp.server.fastmcp.resources.templates import ResourceTemplate

# unit tests

def test_basic_named_function():
    """Test creating a resource template from a basic named function."""
    def example_function(a: int, b: str) -> str:
        """Example function docstring."""
        return b * a

    codeflash_output = ResourceTemplate.from_function(
        fn=example_function,
        uri_template="example://{a}/{b}",
    ); template = codeflash_output

def test_function_with_default_parameters():
    """Test creating a resource template from a function with default parameters."""
    def example_function(a: int, b: str = "default") -> str:
        return b * a

    codeflash_output = ResourceTemplate.from_function(
        fn=example_function,
        uri_template="example://{a}/{b}",
    ); template = codeflash_output

def test_lambda_function_with_name():
    """Test creating a resource template from a lambda function with a provided name."""
    example_lambda = lambda x: x * 2
    codeflash_output = ResourceTemplate.from_function(
        fn=example_lambda,
        uri_template="example://{x}",
        name="example_lambda"
    ); template = codeflash_output

def test_lambda_function_without_name_raises():
    """Test that using a lambda function without a name raises a ValueError."""
    example_lambda = lambda x: x * 2
    with pytest.raises(ValueError, match="You must provide a name for lambda functions"):
        ResourceTemplate.from_function(
            fn=example_lambda,
            uri_template="example://{x}"
        )

def test_function_with_complex_parameters():
    """Test creating a resource template from a function with complex parameters."""
    def example_function(data: dict[str, list[int]]) -> None:
        pass

    codeflash_output = ResourceTemplate.from_function(
        fn=example_function,
        uri_template="example://{data}",
    ); template = codeflash_output


def test_large_number_of_parameters():
    """Test creating a resource template from a function with a large number of parameters."""
    def example_function(**kwargs: int) -> int:
        return sum(kwargs.values())

    codeflash_output = ResourceTemplate.from_function(
        fn=example_function,
        uri_template="example://{params}",
    ); template = codeflash_output

def test_complex_uri_template():
    """Test creating a resource template with a complex URI template."""
    def example_function(a: int, b: str) -> str:
        return b * a

    codeflash_output = ResourceTemplate.from_function(
        fn=example_function,
        uri_template="example://{a}/{b}/details/{a}-{b}",
    ); template = codeflash_output


def test_large_data_set_handling():
    """Test handling of functions that operate on large data sets."""
    def example_function(data: list[int]) -> int:
        return sum(data)

    codeflash_output = ResourceTemplate.from_function(
        fn=example_function,
        uri_template="example://{data}",
    ); template = codeflash_output
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.

from __future__ import annotations

from collections.abc import Callable
from typing import Any

# imports
import pytest  # used for our unit tests
from pydantic import BaseModel, Field, TypeAdapter, validate_call
from src.mcp.server.fastmcp.resources.templates import ResourceTemplate

# unit tests

def test_simple_named_function():
    """Test creating a template from a simple named function."""
    def sample_function(x: int, y: int) -> int:
        return x + y

    codeflash_output = ResourceTemplate.from_function(
        fn=sample_function,
        uri_template="math://add/{x}/{y}",
    ); template = codeflash_output

def test_function_with_default_values():
    """Test a function with default parameter values."""
    def sample_function(x: int, y: int = 10) -> int:
        return x + y

    codeflash_output = ResourceTemplate.from_function(
        fn=sample_function,
        uri_template="math://add/{x}/{y}",
    ); template = codeflash_output

def test_lambda_function_with_name():
    """Test creating a template from a lambda function with a provided name."""
    lambda_fn = lambda x: x * 2
    codeflash_output = ResourceTemplate.from_function(
        fn=lambda_fn,
        uri_template="math://double/{x}",
        name="double_function",
    ); template = codeflash_output

def test_lambda_function_without_name():
    """Test lambda function without a name should raise ValueError."""
    lambda_fn = lambda x: x * 2
    with pytest.raises(ValueError, match="You must provide a name for lambda functions"):
        ResourceTemplate.from_function(
            fn=lambda_fn,
            uri_template="math://double/{x}",
        )

def test_function_with_complex_parameter_types():
    """Test a function with complex parameter types."""
    def complex_function(data: list[int], config: dict[str, Any]) -> str:
        return "processed"

    codeflash_output = ResourceTemplate.from_function(
        fn=complex_function,
        uri_template="process://data",
    ); template = codeflash_output


def test_invalid_uri_template():
    """Test an invalid URI template format."""
    def sample_function(x: int) -> int:
        return x

    codeflash_output = ResourceTemplate.from_function(
        fn=sample_function,
        uri_template="invalid-uri-template",
    ); template = codeflash_output

def test_large_data_function():
    """Test a function processing large data."""
    def large_data_function(data: list[int]) -> int:
        return sum(data)

    large_data = list(range(1000))
    codeflash_output = ResourceTemplate.from_function(
        fn=large_data_function,
        uri_template="data://sum",
    ); template = codeflash_output



from src.mcp.server.fastmcp.resources.templates import ResourceTemplate
import pytest

def test_ResourceTemplate_from_function():
    with pytest.raises(ValueError, match='You\\ must\\ provide\\ a\\ name\\ for\\ lambda\\ functions'):
        ResourceTemplate.from_function(ResourceTemplate, (x:=['', ''], lambda *a: x.pop(0) if len(x) > 1 else x[0])[1], '', name='<lambda>', description=None, mime_type='')

def test_ResourceTemplate_from_function_2():
    with pytest.raises(AttributeError, match="'SymbolicCallable'\\ object\\ has\\ no\\ attribute\\ '__name__'"):
        ResourceTemplate.from_function(ResourceTemplate, lambda *a: , '', name=None, description=None, mime_type=None)

def test_ResourceTemplate_from_function_3():
    with pytest.raises(PydanticSchemaGenerationError, match="Unable\\ to\\ generate\\ pydantic\\-core\\ schema\\ for\\ \\(x:=\\['',\\ ''\\],\\ lambda\\ \\*a:\\ x\\.pop\\(0\\)\\ if\\ len\\(x\\)\\ >\\ 1\\ else\\ x\\[0\\]\\)\\[1\\]\\.\\ Set\\ `arbitrary_types_allowed=True`\\ in\\ the\\ model_config\\ to\\ ignore\\ this\\ error\\ or\\ implement\\ `__get_pydantic_core_schema__`\\ on\\ your\\ type\\ to\\ fully\\ support\\ it\\.\\\n\\\nIf\\ you\\ got\\ this\\ error\\ by\\ calling\\ handler\\(<some\\ type>\\)\\ within\\ `__get_pydantic_core_schema__`\\ then\\ you\\ likely\\ need\\ to\\ call\\ `handler\\.generate_schema\\(<some\\ type>\\)`\\ since\\ we\\ do\\ not\\ call\\ `__get_pydantic_core_schema__`\\ on\\ `<some\\ type>`\\ otherwise\\ to\\ avoid\\ infinite\\ recursion\\.\\\n\\\nFor\\ further\\ information\\ visit\\ https://errors\\.pydantic\\.dev/2\\.11/u/schema\\-for\\-unknown\\-type"):
        ResourceTemplate.from_function(ResourceTemplate, (x:=['', ''], lambda *a: x.pop(0) if len(x) > 1 else x[0])[1], '', name='\x00\x00\x00\x00\x00\x00\x00\x00', description='', mime_type='')

To edit these changes git checkout codeflash/optimize-ResourceTemplate.from_function-ma2x6cyc and push.

Codeflash

Here is an optimized version of your `ResourceTemplate.from_function` method.  
Key optimizations.
- Avoid calling `fn.__doc__` and `"text/plain"` repeatedly inside the return statement by computing all needed default/fallback values before the object construction.  
- Only call `validate_call(fn)` if needed, assigning directly otherwise.
- Use local variables to minimize attribute lookup (which can slightly help, though recent Pythons are better).
- Assign the lambda check to a local variable for speed.
- Avoid unnecessary string concatenation; defaults are computed with simple short-circuit logic.
- The most expensive line is the `TypeAdapter(fn).json_schema()`, which is intrinsic to extracting the schema; there's no faster way using Pydantic v2, so this is kept but put as early as possible to fail fast.

**All comments are preserved (except where lines have been improved/clarified).**



**Net result:**  
- Reduced repeated lookups and conditionals in the return statement.
- Branching/casting is “flattened” for best interpreter throughput.
- Calls stay single-pass; main logic flow is not changed.
- All side effects/return values remain exactly the same.

If you need further runtime gains, consider caching the result of `TypeAdapter(fn)` at a higher level if you'll be constructing many templates for the same function object(s). Otherwise, this is already approaching the limits given the dependence on Pydantic's dynamic typing machinery.
@codeflash-ai codeflash-ai bot added the ⚡️ codeflash Optimization PR opened by Codeflash AI label Apr 29, 2025
@codeflash-ai codeflash-ai bot requested a review from Saga4 April 29, 2025 19:48
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.

1 participant