Skip to content

Commit 6402506

Browse files
committed
Support encoding/decoding Path objects
1 parent 946db01 commit 6402506

File tree

2 files changed

+89
-77
lines changed

2 files changed

+89
-77
lines changed

flask_msgspec/core.py

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import inspect
22
from functools import wraps
33
from inspect import Parameter, Signature
4+
from pathlib import PurePath
45
from typing import Any, Callable, Dict, Optional, Tuple, Type, Union
56

67
from flask import current_app, make_response, request
78
from msgspec import EncodeError, ValidationError, convert
9+
from msgspec.json import Encoder
810
from msgspec.json import decode as msgspec_json_decode
9-
from msgspec.json import encode as msgspec_json_encode
1011
from werkzeug.wrappers import Response
1112

1213
Empty = Signature.empty
@@ -20,7 +21,18 @@
2021
def _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

2638
def _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

91103
def _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

Comments
 (0)