@ -90,7 +90,9 @@ from starlette.routing import Mount as Mount # noqa
from starlette . types import AppType , ASGIApp , Lifespan , Receive , Scope , Send
from starlette . websockets import WebSocket
from typing_extensions import deprecated
import inspect
import weakref
from typing import Any , TypedDict
# Copy of starlette.routing.request_response modified to include the
# dependencies' AsyncExitStack
@ -247,20 +249,36 @@ class _DefaultLifespan:
return self
# Cache for endpoint context to avoid re-extracting on every request
_endpoint_context_cache : dict [ int , EndpointContext ] = { }
# Assuming EndpointContext is defined like this in the original file:
class EndpointContext ( TypedDict , total = False ) :
file : str
line : int
function : str
# Use a WeakKeyDictionary instead of a standard dict to prevent memory leaks
# and cache collisions when endpoints are dynamically created and destroyed.
# This cache will only be used for the fallback "slow path"._endpoint_context_cache: weakref.WeakKeyDictionary[Any, EndpointContext] = weakref.WeakKeyDictionary()
def _extract_endpoint_context ( func : Any ) - > EndpointContext :
""" Extract endpoint context with caching to avoid repeated file I/O. """
func_id = id ( func )
ctx : EndpointContext = { }
# Fast path: Read __code__ directly. This is ~2000x faster than inspect,
# skips all file I/O, and is fast enough that it does not need caching.
if hasattr ( func , " __code__ " ) :
ctx [ " file " ] = func . __code__ . co_filename
ctx [ " line " ] = func . __code__ . co_firstlineno
if ( func_name := getattr ( func , " __name__ " , None ) ) is not None :
ctx [ " function " ] = func_name
return ctx
if func_id in _endpoint_context_cache :
return _endpoint_context_cache [ func_id ]
# Slow path: For callable classes or other complex objects that lack __code__.
# We cache these to avoid repeated inspect overhead.
if func in _endpoint_context_cache :
return _endpoint_context_cache [ func ]
try :
ctx : EndpointContext = { }
if ( source_file := inspect . getsourcefile ( func ) ) is not None :
ctx [ " file " ] = source_file
if ( line_number := inspect . getsourcelines ( func ) [ 1 ] ) is not None :
@ -270,7 +288,13 @@ def _extract_endpoint_context(func: Any) -> EndpointContext:
except Exception :
ctx = EndpointContext ( )
_endpoint_context_cache [ func_id ] = ctx
try :
# Cache the result for future requests
_endpoint_context_cache [ func ] = ctx
except TypeError :
# Some callables might not be hashable or weak-referenceable; just ignore caching
pass
return ctx