@@ -1157,48 +1157,53 @@ def _check_colab_location(gcp_region: Optional[str]):
11571157def _check_types (f ):
11581158 """Decorator to provide runtime checking of parameter types.
11591159
1160- Uses Pydantic v2's TypeAdapter for parameter validation.
1161- Validates input types without coercing arguments — the original
1162- function is called with the original unmodified arguments.
1160+ Uses Pydantic v2's validate_call() for parameter validation.
1161+ Validates input types in strict mode without coercing arguments.
11631162
11641163 """
1165- from pydantic import ConfigDict , TypeAdapter , ValidationError
1164+ from pydantic import ConfigDict , ValidationError , validate_call
11661165
1167- type_hints = get_type_hints (f )
1168- config = ConfigDict (arbitrary_types_allowed = True )
1166+ config = ConfigDict (strict = True , arbitrary_types_allowed = True )
11691167
1170- # Build a TypeAdapter for each annotated parameter (skip 'return').
1171- adapters : dict = {}
1172- for k , t in type_hints . items () :
1173- if k == "return" :
1174- continue
1175- try :
1176- adapters [ k ] = TypeAdapter ( t , config = config )
1177- except Exception :
1178- pass # Skip types pydantic cannot handle
1168+ try :
1169+ validated_f = validate_call ( config = config , validate_return = False )( f )
1170+ except Exception as exc :
1171+ warnings . warn (
1172+ f"Could not apply validate_call to { f . __name__ !r } : { exc } . "
1173+ "Type validation will be skipped for this function." ,
1174+ stacklevel = 2 ,
1175+ )
1176+ return f
11791177
11801178 @wraps (f )
11811179 def wrapper (* args , ** kwargs ):
1182- call_args = getcallargs (f , * args , ** kwargs )
1183- for k , adapter in adapters .items ():
1184- if k in call_args :
1185- v = call_args [k ]
1186- try :
1187- adapter .validate_python (v , strict = True )
1188- except ValidationError as e :
1189- expected_type = humanize_type (type_hints [k ])
1190- actual_type = humanize_type (type (v ))
1191- message = fill (
1192- dedent (
1193- f"""
1194- Parameter { k !r} with value { v !r} in call to function { f .__name__ !r} has incorrect type:
1195- found { actual_type } , expected { expected_type } . See below for further information.
1196- """
1180+ try :
1181+ return validated_f (* args , ** kwargs )
1182+ except ValidationError as e :
1183+ type_hints = get_type_hints (f )
1184+ call_args = getcallargs (f , * args , ** kwargs )
1185+ errors = e .errors ()
1186+ if errors :
1187+ err = errors [0 ]
1188+ loc = err .get ("loc" , ())
1189+ if loc :
1190+ k = str (loc [0 ])
1191+ v = call_args .get (k )
1192+ t = type_hints .get (k )
1193+ if t is not None :
1194+ expected_type = humanize_type (t )
1195+ actual_type = humanize_type (type (v ))
1196+ message = fill (
1197+ dedent (
1198+ f"""\
1199+ Parameter { k !r} with value { v !r} in call to function { f .__name__ !r} has incorrect type:
1200+ found { actual_type } , expected { expected_type } . See below for further information.
1201+ """
1202+ )
11971203 )
1198- )
1199- message += f"\n \n { e } "
1200- raise TypeError (message ) from None
1201- return f (* args , ** kwargs )
1204+ message += f"\n \n { e } "
1205+ raise TypeError (message ) from None
1206+ raise TypeError (str (e )) from None
12021207
12031208 return wrapper
12041209
0 commit comments