11import inspect
22from functools import wraps
33from inspect import Parameter , Signature
4+ from pathlib import PurePath
45from typing import Any , Callable , Dict , Optional , Tuple , Type , Union
56
67from flask import current_app , make_response , request
78from msgspec import EncodeError , ValidationError , convert
9+ from msgspec .json import Encoder
810from msgspec .json import decode as msgspec_json_decode
9- from msgspec .json import encode as msgspec_json_encode
1011from werkzeug .wrappers import Response
1112
1213Empty = Signature .empty
2021def _dec_hook (type_ : Type [Any ], value : Any ) -> Any :
2122 if isinstance (value , type_ ):
2223 return value
23- raise TypeError (f"Type `{ type (value )} ` is not supported." )
24+ if issubclass (type_ , PurePath ):
25+ return type_ (value )
26+ raise NotImplementedError (f"Objects of type { type_ } are not supported" )
27+
28+
29+ def _enc_hook (obj : Any ) -> Any :
30+ if isinstance (obj , PurePath ):
31+ return str (obj )
32+ raise NotImplementedError (f"Objects of type { type (obj )!r} are not supported" )
33+
34+
35+ encoder = Encoder (enc_hook = _enc_hook )
2436
2537
2638def _build_param_type_map (
@@ -34,7 +46,7 @@ def _build_param_type_map(
3446 if param .kind not in ACCEPTED_PARAMS_KINDS :
3547 continue
3648 if param .annotation is Empty :
37- raise TypeError (f"Type annonation is missing for `{ name } ` parameter. " )
49+ raise TypeError (f"Type annonation is missing for `{ name } ` parameter" )
3850
3951 if name not in kwargs :
4052 kwargs [name ] = param .default
@@ -44,10 +56,10 @@ def _build_param_type_map(
4456 if type_ is None :
4557 if namespace is None :
4658 raise KeyError (
47- f"Unable to resolve type annotation `{ param .annotation } `. "
48- f"Consider supplying a signature namespace. "
59+ f"Unable to resolve type annotation `{ param .annotation } `, "
60+ f"consider supplying a signature namespace"
4961 )
50- raise KeyError (f"Unable to resolve type annotation `{ param .annotation } `. " )
62+ raise KeyError (f"Unable to resolve type annotation `{ param .annotation } `" )
5163 param_type_map [name ] = type_
5264 else :
5365 param_type_map [name ] = param .annotation
@@ -85,15 +97,15 @@ def _validate_path_params(
8597 for name , value in view_args .items ():
8698 kwargs [name ] = convert (value , type = param_type_map [name ], strict = False , dec_hook = _dec_hook )
8799 except ValidationError as ex :
88- return {"error" : ValidationError .__name__ , "detail" : {"key" : name , "msg" : "" .join (ex .args )}}
100+ return {"error" : ValidationError .__name__ , "detail" : {"key" : name , "msg" : "" .join (ex .args )}} # type: ignore
89101
90102
91103def _validate_body (
92104 body_data : Union [bytes , Dict [str , str ]], kwargs : Dict [str , Any ], param_type_map : Dict [str , Type [Any ]]
93105) -> Optional [Dict [str , Union [str , Dict [str , Any ]]]]:
94106 body_model = param_type_map .get ("body" , Empty )
95107 if body_model is Empty :
96- raise ValueError ("Expected a body model type. " )
108+ raise ValueError ("Expected a body model type" )
97109
98110 try :
99111 if isinstance (body_data , bytes ):
@@ -121,7 +133,7 @@ def _unpack_result(result: Any) -> Tuple[Any, Optional[int], Any]:
121133 elif len (result ) == 3 :
122134 response_value , status_code , headers = result
123135 else :
124- raise ValueError (f"Unhandled return type: { type (result )!r} . " )
136+ raise ValueError (f"Unhandled return type: { type (result )!r} " )
125137
126138 return response_value , status_code , headers
127139
@@ -137,7 +149,7 @@ def wrapper(*args, **kwargs):
137149 sig = inspect .signature (func )
138150 _return_model = return_model or sig .return_annotation
139151 if _return_model is Empty :
140- raise TypeError ("Missing return type. " )
152+ raise TypeError ("Missing return type" )
141153
142154 param_type_map = _build_param_type_map (sig , kwargs , signature_namespace )
143155
@@ -162,7 +174,7 @@ def wrapper(*args, **kwargs):
162174
163175 try :
164176 response_value = convert (response_value , type = _return_model , strict = False , dec_hook = _dec_hook )
165- json_data = msgspec_json_encode (response_value )
177+ json_data = encoder . encode (response_value )
166178 except (ValidationError , EncodeError ) as ex :
167179 return {"error" : type (ex ).__name__ , "detail" : {"msg" : "" .join (ex .args )}}, 422
168180
0 commit comments