@@ -89,7 +89,7 @@ def from_function(
8989 required_params , optional_params = cls ._analyze_function_params (original_fn )
9090
9191 # Extract path parameters from URI template
92- path_params : set [str ] = set (re .findall (r"{(\w+)} " , re .sub (r"{( \?.+?) }" , "" , uri_template )))
92+ path_params : set [str ] = set (re .findall (r"{\s* (\w+)(?::[^}]+)?\s*} " , re .sub (r"{\?.+?}" , "" , uri_template )))
9393
9494 # Extract query parameters from the URI template if present
9595 query_param_match = re .search (r"{(\?(?:\w+,)*\w+)}" , uri_template )
@@ -100,12 +100,12 @@ def from_function(
100100 query_params = set (query_str [1 :].split ("," )) # Remove the leading '?' and split
101101
102102 if context_kwarg :
103- required_params = required_params .remove (context_kwarg )
103+ required_params .remove (context_kwarg )
104104
105105 # Validate path parameters match required function parameters
106106 if path_params != required_params :
107107 raise ValueError (
108- f"Mismatch between URI path parameters { path_params } and required function parameters { required_params } "
108+ f"Mismatch between URI path parameters { path_params } and required function parameters { required_params } with context parameters { context_kwarg } "
109109 )
110110
111111 # Validate query parameters are a subset of optional function parameters
@@ -133,7 +133,8 @@ def from_function(
133133
134134 def _generate_pattern (self ) -> tuple [re .Pattern [str ], dict [str , Convertor [Any ]]]:
135135 """Compile the URI template into a regex pattern and associated converters."""
136- parts = self .uri_template .strip ("/" ).split ("/" )
136+ path_template = re .sub (r"\{\?.*?\}" , "" , self .uri_template )
137+ parts = path_template .strip ("/" ).split ("/" )
137138 pattern_parts : list [str ] = []
138139 converters : dict [str , Convertor [Any ]] = {}
139140 # generate the regex pattern
@@ -223,26 +224,23 @@ async def create_resource(
223224 ) -> Resource :
224225 """Create a resource from the template with the given parameters."""
225226 try :
226- # Add context to params if needed
227- params = inject_context (self .fn , params , context , self .context_kwarg ) #type: ignore
228-
229227 # Prepare parameters for function call
230228 # For optional parameters not in URL, use their default values
231-
232229 # First add extracted parameters
233230 fn_params = {
234231 name : value
235232 for name , value in params .items ()
236233 if name in self .required_params or name in self .optional_params
237234 }
238-
235+ # Add context to params
236+ fn_params = inject_context (self .fn , fn_params , context , self .context_kwarg ) #type: ignore
239237 # self.fn is now multiply-decorated:
240238 # 1. validate_call for coercion/validation
241239 # 2. our new decorator for default fallback on optional param validation err
242240 result = self .fn (** fn_params )
243241 if inspect .iscoroutine (result ):
244242 result = await result
245-
243+
246244 return FunctionResource (
247245 uri = uri , # type: ignore
248246 name = self .name ,
0 commit comments