22
33import json
44import logging
5+ import math
56import queue
67import threading
78import uuid
@@ -87,47 +88,43 @@ def _parse_float_param(
8788 Returns:
8889 Кортеж ``(parsed, None)`` при успехе или ``(None, JsonResponse)`` при ошибке.
8990 """
91+ bad = JsonResponse (
92+ {"error" : f"'{ param_name } ' must be a float between 0.0 and 1.0." },
93+ status = 400 ,
94+ )
95+ out : Optional [float ] = None
96+ err : Optional [JsonResponse ] = None
97+
9098 if value is None or value == "" :
91- return default , None
92- if isinstance (value , bool ):
93- return None , JsonResponse (
94- {"error" : f"'{ param_name } ' must be a float between 0.0 and 1.0." },
95- status = 400 ,
96- )
97- if isinstance (value , (int , float )):
98- parsed = float (value )
99+ out = default
100+ elif isinstance (value , bool ):
101+ err = bad
102+ elif isinstance (value , (int , float )):
103+ out = float (value )
99104 elif isinstance (value , str ):
100105 stripped = value .strip ()
101106 if not stripped :
102- return default , None
103- try :
104- parsed = float (stripped )
105- except ValueError :
106- return None , JsonResponse (
107- {"error" : f"'{ param_name } ' must be a float between 0.0 and 1.0." },
108- status = 400 ,
109- )
107+ out = default
108+ else :
109+ try :
110+ out = float (stripped )
111+ except ValueError :
112+ err = bad
110113 else :
111- return None , JsonResponse (
112- {"error" : f"'{ param_name } ' must be a float between 0.0 and 1.0." },
113- status = 400 ,
114- )
115- if parsed != parsed : # NaN
116- return None , JsonResponse (
117- {"error" : f"'{ param_name } ' must be a float between 0.0 and 1.0." },
118- status = 400 ,
119- )
120- if min_value is not None and parsed < min_value :
121- return None , JsonResponse (
122- {"error" : f"'{ param_name } ' must be a float between 0.0 and 1.0." },
123- status = 400 ,
124- )
125- if max_value is not None and parsed > max_value :
126- return None , JsonResponse (
127- {"error" : f"'{ param_name } ' must be a float between 0.0 and 1.0." },
128- status = 400 ,
129- )
130- return parsed , None
114+ err = bad
115+
116+ if err is None and out is not None :
117+ if math .isnan (out ):
118+ err = bad
119+ out = None
120+ elif min_value is not None and out < min_value :
121+ err = bad
122+ out = None
123+ elif max_value is not None and out > max_value :
124+ err = bad
125+ out = None
126+
127+ return out , err
131128
132129
133130def _stringify_numeric_param (
@@ -144,31 +141,32 @@ def _stringify_numeric_param(
144141 Returns:
145142 ``(строка_цифр_или_None, None)`` либо ``(None, JsonResponse)``.
146143 """
147- if value is None or value == "" :
148- return None , None
149- if isinstance (value , bool ):
150- return None , JsonResponse (
151- {"error" : f"'{ param_name } ' must be a positive integer." },
152- status = 400 ,
153- )
154- if isinstance (value , int ):
155- return str (value ), None
156- if isinstance (value , float ):
157- if not value .is_integer ():
158- return None , JsonResponse (
159- {"error" : f"'{ param_name } ' must be a positive integer." },
160- status = 400 ,
161- )
162- return str (int (value )), None
163- if isinstance (value , str ):
164- stripped = value .strip ()
165- if not stripped :
166- return None , None
167- return stripped , None
168- return None , JsonResponse (
144+ invalid = JsonResponse (
169145 {"error" : f"'{ param_name } ' must be a positive integer." },
170146 status = 400 ,
171147 )
148+ out : Optional [str ] = None
149+ err : Optional [JsonResponse ] = None
150+
151+ if value is None or value == "" :
152+ pass
153+ elif isinstance (value , bool ):
154+ err = invalid
155+ elif isinstance (value , int ):
156+ out = str (value )
157+ elif isinstance (value , float ):
158+ if not value .is_integer ():
159+ err = invalid
160+ else :
161+ out = str (int (value ))
162+ elif isinstance (value , str ):
163+ stripped = value .strip ()
164+ if stripped :
165+ out = stripped
166+ else :
167+ err = invalid
168+
169+ return out , err
172170
173171
174172class SearchPermissionMixin :
@@ -442,10 +440,20 @@ class StreamingSearchAPIView(SearchPermissionMixin, View):
442440 marker.
443441 """
444442
445- def get (self , request : HttpRequest , * args : Any , ** kwargs : Any ) -> StreamingHttpResponse | JsonResponse :
443+ def get (
444+ self ,
445+ request : HttpRequest ,
446+ * args : Any ,
447+ ** kwargs : Any ,
448+ ) -> StreamingHttpResponse | JsonResponse :
446449 return self ._handle (request )
447450
448- def post (self , request : HttpRequest , * args : Any , ** kwargs : Any ) -> StreamingHttpResponse | JsonResponse :
451+ def post (
452+ self ,
453+ request : HttpRequest ,
454+ * args : Any ,
455+ ** kwargs : Any ,
456+ ) -> StreamingHttpResponse | JsonResponse :
449457 return self ._handle (request )
450458
451459 def _handle (self , request : HttpRequest ) -> StreamingHttpResponse | JsonResponse :
@@ -557,12 +565,24 @@ def _extract_payload(request: HttpRequest) -> Dict[str, Any]:
557565def _format_event (event : Dict [str , Any ], fmt : str ) -> bytes :
558566 payload = json .dumps (event , ensure_ascii = False , default = str )
559567 if fmt == "sse" :
560- return f"event: { event .get ('type' , 'message' )} \n data: { payload } \n \n " .encode ("utf-8" )
568+ event_type = event .get ("type" , "message" )
569+ lines = (
570+ f"event: { event_type } \n "
571+ f"data: { payload } \n \n "
572+ )
573+ return lines .encode ("utf-8" )
561574 return (payload + "\n " ).encode ("utf-8" )
562575
563576
564577class SimilarAPIView (View ):
565- def get (self , request : HttpRequest , model : str , pk : str , * args : Any , ** kwargs : Any ) -> JsonResponse :
578+ def get (
579+ self ,
580+ request : HttpRequest ,
581+ model : str ,
582+ pk : str ,
583+ * args : Any ,
584+ ** kwargs : Any ,
585+ ) -> JsonResponse :
566586 if "." not in model :
567587 return JsonResponse ({"error" : "Model must be in 'app.Model' format." }, status = 400 )
568588 app_label , model_name = model .split ("." , 1 )
0 commit comments