turboapi 0.5.2__cp314-cp314-macosx_10_12_x86_64.whl → 0.5.21__cp314-cp314-macosx_10_12_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -229,9 +229,12 @@ class RequestBodyParser:
229
229
  """
230
230
  if not body:
231
231
  return {}
232
-
232
+
233
233
  try:
234
- json_data = json.loads(body.decode('utf-8'))
234
+ # CRITICAL: Make a defensive copy immediately using bytearray to force real copy
235
+ # Free-threaded Python with Metal/MLX can have concurrent memory access issues
236
+ body_copy = bytes(bytearray(body))
237
+ json_data = json.loads(body_copy.decode('utf-8'))
235
238
  except (json.JSONDecodeError, UnicodeDecodeError) as e:
236
239
  raise ValueError(f"Invalid JSON body: {e}")
237
240
 
@@ -348,9 +351,16 @@ class ResponseHandler:
348
351
  try:
349
352
  import json
350
353
  body = json.loads(body.decode('utf-8'))
351
- except (json.JSONDecodeError, UnicodeDecodeError):
352
- # Keep as string for HTML/Text responses
353
- body = body.decode('utf-8')
354
+ except json.JSONDecodeError:
355
+ # Not JSON, try as plain text
356
+ try:
357
+ body = body.decode('utf-8')
358
+ except UnicodeDecodeError:
359
+ # Binary data (audio, image, etc.) - keep as bytes
360
+ pass
361
+ except UnicodeDecodeError:
362
+ # Binary data (audio, image, etc.) - keep as bytes
363
+ pass
354
364
  return body, result.status_code
355
365
 
356
366
  # Handle tuple returns: (content, status_code)
@@ -394,6 +404,13 @@ class ResponseHandler:
394
404
  def make_serializable(obj):
395
405
  if isinstance(obj, Model):
396
406
  return obj.model_dump()
407
+ elif isinstance(obj, bytes):
408
+ # Binary data - try to decode as UTF-8, otherwise base64 encode
409
+ try:
410
+ return obj.decode('utf-8')
411
+ except UnicodeDecodeError:
412
+ import base64
413
+ return base64.b64encode(obj).decode('ascii')
397
414
  elif isinstance(obj, dict):
398
415
  return {k: make_serializable(v) for k, v in obj.items()}
399
416
  elif isinstance(obj, (list, tuple)):
@@ -491,7 +508,7 @@ def create_enhanced_handler(original_handler, route_definition):
491
508
 
492
509
  # Call original async handler and await it
493
510
  result = await original_handler(**filtered_kwargs)
494
-
511
+
495
512
  # Normalize response
496
513
  content, status_code = ResponseHandler.normalize_response(result)
497
514
 
@@ -43,6 +43,10 @@ def classify_handler(handler, route) -> tuple[str, dict[str, str], dict]:
43
43
  if BaseModel is not None and inspect.isclass(annotation) and issubclass(annotation, BaseModel):
44
44
  # Found a model parameter - use fast model path (sync only for now)
45
45
  model_info = {"param_name": param_name, "model_class": annotation}
46
+ # For async handlers, model parsing needs the enhanced path
47
+ # since Rust-side model parsing only supports sync handlers
48
+ if is_async:
49
+ needs_body = True
46
50
  continue # Don't add to param_types
47
51
  except TypeError:
48
52
  pass
Binary file
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: turboapi
3
- Version: 0.5.2
3
+ Version: 0.5.21
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -10,20 +10,20 @@ turboapi/main_app.py,sha256=5w6x1DX_XChPCcZf24b4CC8qe24XFyGY3BRuR71qkCM,13411
10
10
  turboapi/middleware.py,sha256=3G5zhPKiHm07b_xv_dOsO88W1PfO78SGMySJe4d9nb4,10737
11
11
  turboapi/models.py,sha256=OzyDTEl97zcXa6DTrsR_hZZjj8Lr9QwsD0BrC74BE5o,4476
12
12
  turboapi/openapi.py,sha256=wwS4akekFns-OYQUh7bjKBzRqdg9Z7z5MFo27LlFkEY,7281
13
- turboapi/request_handler.py,sha256=aADbJdFQp5f3zzWD5fv0Jrtk6W46RzG7rGhlZrFL5tA,23768
13
+ turboapi/request_handler.py,sha256=YHfJFqQJI_mZdczpARprOkpsNnCIojTrlW_vLgTdPQw,24593
14
14
  turboapi/responses.py,sha256=wiYkG53NNwXu1RDyRlZFF-8jxx51xL6LOTUj5TG__2c,6052
15
15
  turboapi/routing.py,sha256=-39IUSfsMswCLR-zJ6c4Ri0tYd7_UjYnQyioT4a1W_Q,7601
16
- turboapi/rust_integration.py,sha256=5ZXgwj2_3j6R9wRbsq9sZLJp35PPKlamuuufnaj9GCI,15324
16
+ turboapi/rust_integration.py,sha256=StR_4PHIzz1Qk9T-MG5veu3qerwKohoXFeOagk6Be6E,15543
17
17
  turboapi/security.py,sha256=U2ZQSMWK9a6YzSk5F39TgeZriJ7JtDNZo3RldVPphKI,17493
18
18
  turboapi/server_integration.py,sha256=cnyT4Eqrw3lkZjdVkDvN2qMH5yXh68LJhC2w9ccH9Qc,17904
19
19
  turboapi/staticfiles.py,sha256=MLSvPeYUQGPEL4_mVQ2z3ItREZxUTEN-awQrNxPAgsM,2861
20
20
  turboapi/status.py,sha256=7qVEXVQ3AVFcgEKbmdq6dTypCP275qIbk51hMUQztXA,3049
21
21
  turboapi/templating.py,sha256=YlZeesNAuAcqkdUhkE1xGzTY0w_-nhbG5bJWntYe2AM,2087
22
22
  turboapi/testclient.py,sha256=TBuRPms8G9MncARfwtvCKvqrtfthraTcy0TkPmweMao,10669
23
- turboapi/turbonet.cpython-314-darwin.so,sha256=9a_IPeq7Ag-6_h7nxAQTVDViCaJ0hKVGK-wwYdzoE7M,5656992
23
+ turboapi/turbonet.cpython-314-darwin.so,sha256=T9Atgr-WddXHxm-XlsGbJL-kA3bZN_LrUewK3Po3CCQ,5675720
24
24
  turboapi/version_check.py,sha256=NmKEt9Qloi5NrGYvVusjFTDhMhZzZfazuXyjcOPO2vc,9357
25
25
  turboapi/websockets.py,sha256=7Ao_dKfGWHu2nMU5pm9X20E9P0qnh4lJOykHFmzc5tc,4226
26
- turboapi-0.5.2.dist-info/METADATA,sha256=_BQjvO_FPVaC0jVi5aXAQ-BN6u1GKrjSmqjsfzXpdxU,17555
27
- turboapi-0.5.2.dist-info/WHEEL,sha256=jyP0hJCe-fSX_gEscesIqqW7KerDJw7iyldGx-__w10,107
28
- turboapi-0.5.2.dist-info/licenses/LICENSE,sha256=09pmQi_FlhCpUCJ8bMQQoax_oOooJS3FKezznBBU8OQ,1068
29
- turboapi-0.5.2.dist-info/RECORD,,
26
+ turboapi-0.5.21.dist-info/METADATA,sha256=8q-P0UJmWeRKs9E3YJpaOLNJeZc9OK_elGvCvNjcunM,17556
27
+ turboapi-0.5.21.dist-info/WHEEL,sha256=jyP0hJCe-fSX_gEscesIqqW7KerDJw7iyldGx-__w10,107
28
+ turboapi-0.5.21.dist-info/licenses/LICENSE,sha256=09pmQi_FlhCpUCJ8bMQQoax_oOooJS3FKezznBBU8OQ,1068
29
+ turboapi-0.5.21.dist-info/RECORD,,