modal 0.62.115__py3-none-any.whl → 0.72.11__py3-none-any.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.
Files changed (220) hide show
  1. modal/__init__.py +13 -9
  2. modal/__main__.py +41 -3
  3. modal/_clustered_functions.py +80 -0
  4. modal/_clustered_functions.pyi +22 -0
  5. modal/_container_entrypoint.py +407 -398
  6. modal/_ipython.py +3 -13
  7. modal/_location.py +17 -10
  8. modal/_output.py +243 -99
  9. modal/_pty.py +2 -2
  10. modal/_resolver.py +55 -60
  11. modal/_resources.py +26 -7
  12. modal/_runtime/__init__.py +1 -0
  13. modal/_runtime/asgi.py +519 -0
  14. modal/_runtime/container_io_manager.py +1036 -0
  15. modal/{execution_context.py → _runtime/execution_context.py} +11 -2
  16. modal/_runtime/telemetry.py +169 -0
  17. modal/_runtime/user_code_imports.py +356 -0
  18. modal/_serialization.py +123 -6
  19. modal/_traceback.py +47 -187
  20. modal/_tunnel.py +50 -14
  21. modal/_tunnel.pyi +19 -36
  22. modal/_utils/app_utils.py +3 -17
  23. modal/_utils/async_utils.py +386 -104
  24. modal/_utils/blob_utils.py +157 -186
  25. modal/_utils/bytes_io_segment_payload.py +97 -0
  26. modal/_utils/deprecation.py +89 -0
  27. modal/_utils/docker_utils.py +98 -0
  28. modal/_utils/function_utils.py +299 -98
  29. modal/_utils/grpc_testing.py +47 -34
  30. modal/_utils/grpc_utils.py +54 -21
  31. modal/_utils/hash_utils.py +51 -10
  32. modal/_utils/http_utils.py +39 -9
  33. modal/_utils/logger.py +2 -1
  34. modal/_utils/mount_utils.py +34 -16
  35. modal/_utils/name_utils.py +58 -0
  36. modal/_utils/package_utils.py +14 -1
  37. modal/_utils/pattern_utils.py +205 -0
  38. modal/_utils/rand_pb_testing.py +3 -3
  39. modal/_utils/shell_utils.py +15 -49
  40. modal/_vendor/a2wsgi_wsgi.py +62 -72
  41. modal/_vendor/cloudpickle.py +1 -1
  42. modal/_watcher.py +12 -10
  43. modal/app.py +561 -323
  44. modal/app.pyi +474 -262
  45. modal/call_graph.py +7 -6
  46. modal/cli/_download.py +22 -6
  47. modal/cli/_traceback.py +200 -0
  48. modal/cli/app.py +203 -42
  49. modal/cli/config.py +12 -5
  50. modal/cli/container.py +61 -13
  51. modal/cli/dict.py +128 -0
  52. modal/cli/entry_point.py +26 -13
  53. modal/cli/environment.py +40 -9
  54. modal/cli/import_refs.py +21 -48
  55. modal/cli/launch.py +28 -14
  56. modal/cli/network_file_system.py +57 -21
  57. modal/cli/profile.py +1 -1
  58. modal/cli/programs/run_jupyter.py +34 -9
  59. modal/cli/programs/vscode.py +58 -8
  60. modal/cli/queues.py +131 -0
  61. modal/cli/run.py +199 -96
  62. modal/cli/secret.py +5 -4
  63. modal/cli/token.py +7 -2
  64. modal/cli/utils.py +74 -8
  65. modal/cli/volume.py +97 -56
  66. modal/client.py +248 -144
  67. modal/client.pyi +156 -124
  68. modal/cloud_bucket_mount.py +43 -30
  69. modal/cloud_bucket_mount.pyi +32 -25
  70. modal/cls.py +528 -141
  71. modal/cls.pyi +189 -145
  72. modal/config.py +32 -15
  73. modal/container_process.py +177 -0
  74. modal/container_process.pyi +82 -0
  75. modal/dict.py +50 -54
  76. modal/dict.pyi +120 -164
  77. modal/environments.py +106 -5
  78. modal/environments.pyi +77 -25
  79. modal/exception.py +30 -43
  80. modal/experimental.py +62 -2
  81. modal/file_io.py +537 -0
  82. modal/file_io.pyi +235 -0
  83. modal/file_pattern_matcher.py +197 -0
  84. modal/functions.py +846 -428
  85. modal/functions.pyi +446 -387
  86. modal/gpu.py +57 -44
  87. modal/image.py +946 -417
  88. modal/image.pyi +584 -245
  89. modal/io_streams.py +434 -0
  90. modal/io_streams.pyi +122 -0
  91. modal/mount.py +223 -90
  92. modal/mount.pyi +241 -243
  93. modal/network_file_system.py +85 -86
  94. modal/network_file_system.pyi +151 -110
  95. modal/object.py +66 -36
  96. modal/object.pyi +166 -143
  97. modal/output.py +63 -0
  98. modal/parallel_map.py +73 -47
  99. modal/parallel_map.pyi +51 -63
  100. modal/partial_function.py +272 -107
  101. modal/partial_function.pyi +219 -120
  102. modal/proxy.py +15 -12
  103. modal/proxy.pyi +3 -8
  104. modal/queue.py +96 -72
  105. modal/queue.pyi +210 -135
  106. modal/requirements/2024.04.txt +2 -1
  107. modal/requirements/2024.10.txt +16 -0
  108. modal/requirements/README.md +21 -0
  109. modal/requirements/base-images.json +22 -0
  110. modal/retries.py +45 -4
  111. modal/runner.py +325 -203
  112. modal/runner.pyi +124 -110
  113. modal/running_app.py +27 -4
  114. modal/sandbox.py +509 -231
  115. modal/sandbox.pyi +396 -169
  116. modal/schedule.py +2 -2
  117. modal/scheduler_placement.py +20 -3
  118. modal/secret.py +41 -25
  119. modal/secret.pyi +62 -42
  120. modal/serving.py +39 -49
  121. modal/serving.pyi +37 -43
  122. modal/stream_type.py +15 -0
  123. modal/token_flow.py +5 -3
  124. modal/token_flow.pyi +37 -32
  125. modal/volume.py +123 -137
  126. modal/volume.pyi +228 -221
  127. {modal-0.62.115.dist-info → modal-0.72.11.dist-info}/METADATA +5 -5
  128. modal-0.72.11.dist-info/RECORD +174 -0
  129. {modal-0.62.115.dist-info → modal-0.72.11.dist-info}/top_level.txt +0 -1
  130. modal_docs/gen_reference_docs.py +3 -1
  131. modal_docs/mdmd/mdmd.py +0 -1
  132. modal_docs/mdmd/signatures.py +1 -2
  133. modal_global_objects/images/base_images.py +28 -0
  134. modal_global_objects/mounts/python_standalone.py +2 -2
  135. modal_proto/__init__.py +1 -1
  136. modal_proto/api.proto +1231 -531
  137. modal_proto/api_grpc.py +750 -430
  138. modal_proto/api_pb2.py +2102 -1176
  139. modal_proto/api_pb2.pyi +8859 -0
  140. modal_proto/api_pb2_grpc.py +1329 -675
  141. modal_proto/api_pb2_grpc.pyi +1416 -0
  142. modal_proto/modal_api_grpc.py +149 -0
  143. modal_proto/modal_options_grpc.py +3 -0
  144. modal_proto/options_pb2.pyi +20 -0
  145. modal_proto/options_pb2_grpc.pyi +7 -0
  146. modal_proto/py.typed +0 -0
  147. modal_version/__init__.py +1 -1
  148. modal_version/_version_generated.py +2 -2
  149. modal/_asgi.py +0 -370
  150. modal/_container_exec.py +0 -128
  151. modal/_container_io_manager.py +0 -646
  152. modal/_container_io_manager.pyi +0 -412
  153. modal/_sandbox_shell.py +0 -49
  154. modal/app_utils.py +0 -20
  155. modal/app_utils.pyi +0 -17
  156. modal/execution_context.pyi +0 -37
  157. modal/shared_volume.py +0 -23
  158. modal/shared_volume.pyi +0 -24
  159. modal-0.62.115.dist-info/RECORD +0 -207
  160. modal_global_objects/images/conda.py +0 -15
  161. modal_global_objects/images/debian_slim.py +0 -15
  162. modal_global_objects/images/micromamba.py +0 -15
  163. test/__init__.py +0 -1
  164. test/aio_test.py +0 -12
  165. test/async_utils_test.py +0 -279
  166. test/blob_test.py +0 -67
  167. test/cli_imports_test.py +0 -149
  168. test/cli_test.py +0 -674
  169. test/client_test.py +0 -203
  170. test/cloud_bucket_mount_test.py +0 -22
  171. test/cls_test.py +0 -636
  172. test/config_test.py +0 -149
  173. test/conftest.py +0 -1485
  174. test/container_app_test.py +0 -50
  175. test/container_test.py +0 -1405
  176. test/cpu_test.py +0 -23
  177. test/decorator_test.py +0 -85
  178. test/deprecation_test.py +0 -34
  179. test/dict_test.py +0 -51
  180. test/e2e_test.py +0 -68
  181. test/error_test.py +0 -7
  182. test/function_serialization_test.py +0 -32
  183. test/function_test.py +0 -791
  184. test/function_utils_test.py +0 -101
  185. test/gpu_test.py +0 -159
  186. test/grpc_utils_test.py +0 -82
  187. test/helpers.py +0 -47
  188. test/image_test.py +0 -814
  189. test/live_reload_test.py +0 -80
  190. test/lookup_test.py +0 -70
  191. test/mdmd_test.py +0 -329
  192. test/mount_test.py +0 -162
  193. test/mounted_files_test.py +0 -327
  194. test/network_file_system_test.py +0 -188
  195. test/notebook_test.py +0 -66
  196. test/object_test.py +0 -41
  197. test/package_utils_test.py +0 -25
  198. test/queue_test.py +0 -115
  199. test/resolver_test.py +0 -59
  200. test/retries_test.py +0 -67
  201. test/runner_test.py +0 -85
  202. test/sandbox_test.py +0 -191
  203. test/schedule_test.py +0 -15
  204. test/scheduler_placement_test.py +0 -57
  205. test/secret_test.py +0 -89
  206. test/serialization_test.py +0 -50
  207. test/stub_composition_test.py +0 -10
  208. test/stub_test.py +0 -361
  209. test/test_asgi_wrapper.py +0 -234
  210. test/token_flow_test.py +0 -18
  211. test/traceback_test.py +0 -135
  212. test/tunnel_test.py +0 -29
  213. test/utils_test.py +0 -88
  214. test/version_test.py +0 -14
  215. test/volume_test.py +0 -397
  216. test/watcher_test.py +0 -58
  217. test/webhook_test.py +0 -145
  218. {modal-0.62.115.dist-info → modal-0.72.11.dist-info}/LICENSE +0 -0
  219. {modal-0.62.115.dist-info → modal-0.72.11.dist-info}/WHEEL +0 -0
  220. {modal-0.62.115.dist-info → modal-0.72.11.dist-info}/entry_points.txt +0 -0
@@ -1,207 +0,0 @@
1
- modal/__init__.py,sha256=NBneFs9SID4d9fX3Q9FLdr1-pburBBP1mFXlRauxmRo,2095
2
- modal/__main__.py,sha256=EKalcwy_6N0L5iqIvlYpXihi3zxy9HNuUMvnbraoTrk,1141
3
- modal/_asgi.py,sha256=pumwIq8Sk5bXpaZpNRmo5QLykRwH0yCqPzlMkB9eCfs,15484
4
- modal/_container_entrypoint.py,sha256=pNwBSY3piJ1kwTNbxJXm5oSlHqaCU4UdjdTpp7vIPpE,28456
5
- modal/_container_exec.py,sha256=FiaSBUD0UkQRF8hW0AFf0rbqC8lb87f3EGeg7Mr5dx4,4349
6
- modal/_container_io_manager.py,sha256=W2CSjRcvDGL4oePRvLx0Ymogy8-M5qJcitwkIHw_FwA,28110
7
- modal/_container_io_manager.pyi,sha256=G5qC3Vy2Sh7Z_q1zlRvCxH-Cw06lGLBcTRl__I90UXY,12406
8
- modal/_ipython.py,sha256=HF_DYy0e0qM9WnGDmTY30s1RxzGya9GeORCauCEpRaE,450
9
- modal/_location.py,sha256=_SdCPzVOl7HRwLWIxzTJjhdpOo1sIl4flfEJ-bAbiDE,929
10
- modal/_output.py,sha256=1GXKp-Qr-C5oe0e4A5epTgcIFhcp5Cko3HG_ircLFWg,20565
11
- modal/_proxy_tunnel.py,sha256=gnKyCfmVB7x2d1A6c-JDysNIP3kEFxmXzhcXhPrzPn0,1906
12
- modal/_pty.py,sha256=GhzrHKZpoI-YHMDN7LoySlSYLpoJ4yGPSF-fqiNsFrM,1336
13
- modal/_resolver.py,sha256=FAkA_3_VK74MEiNOmYH9s2mThD38Z7QNWhNNY3r7qcI,7077
14
- modal/_resources.py,sha256=4pOUFIgF2nwiKm744Q49fU4ZBZABywOAScttxUhGAgs,1142
15
- modal/_sandbox_shell.py,sha256=OtkeMqOymFVqDBWt3kmT6_4mslPu0ZCfjqYjwUb6cGE,1658
16
- modal/_serialization.py,sha256=sDVn7q1YMmTyNW-LKRoYmDs3Cyq8pQ0nbfuT0LqbTHo,12833
17
- modal/_traceback.py,sha256=l6y-flU7rQK3YelSthHv4Paurw3rA5q9KofBRRVHCVM,10029
18
- modal/_tunnel.py,sha256=L3ojxnKMMslYXN5_HFclCLGjOEIxKif8UUa0nAjrnYM,5171
19
- modal/_tunnel.pyi,sha256=MhcFhkpt-Fo9dA59qhXtoNA9ktyJzwtmGj0vWaUdFiM,1337
20
- modal/_watcher.py,sha256=WFnaF5npnkFb-gGG9X4Tc5DZDVqXDU-STSvfJKg7SOs,3605
21
- modal/app.py,sha256=JF-_Bf4bc6fVVQtZd1o-54C1lqupF4pE0V4fjV8YeJc,36315
22
- modal/app.pyi,sha256=3kCxWzHat6__uZzkjJ44X_NfKySfVy-TfldmR0BnvFg,19403
23
- modal/app_utils.py,sha256=EuRot0Xhrq5m7bQgM8yVZkRxiKfnBMJSFguu-lsJ5Vs,748
24
- modal/app_utils.pyi,sha256=9u0YQMoIt158Uh-HxUGrnuBeMFdBLdi_DLHHZNSGU-M,613
25
- modal/call_graph.py,sha256=KhqmbJPlcpL-PO0N_lrK8VHoXK_xAHq5IhZ9A9rW9Zk,2524
26
- modal/client.py,sha256=MdXWbQla4hIQFyB9pqgS5Nonq6r9NxyOx6covnvHepQ,10930
27
- modal/client.pyi,sha256=zC7j10hwLcFqc27m14IK00LSxKjxRh8fOSdPZ3nOpOs,4048
28
- modal/cloud_bucket_mount.py,sha256=5BXwNCF51V2EX0rbVAltRoPaBsTqdjJPC_IkUI0uRPs,5700
29
- modal/cloud_bucket_mount.pyi,sha256=HQy0m3uXIziIrTbftNY_tja5m0tlYro1Q5vQ2fQq2lM,1217
30
- modal/cls.py,sha256=6WXC5lvxFJi1QVAYMMAOq7cLAia0nP-Tp1ljhDQPUdo,12734
31
- modal/cls.pyi,sha256=2gjM9x08Hs9wsdxWmFGdAt4W_hB_jBzqyBAecQ31mNo,6521
32
- modal/config.py,sha256=_5PGiL2HsxDAL1THv1-FpZXvaiFIaNnT0xd1vGjBhTI,9980
33
- modal/dict.py,sha256=91zpSn7O1ofrEyHBy8_yqD727C3oAnUx2ACwlSg4q0Y,12642
34
- modal/dict.pyi,sha256=FvyO-otgDFPmYD3b-u09ROkP4Fw4bBFhZy79Q_r0M4s,7268
35
- modal/environments.py,sha256=xOsBpVpjyBwA-0PVYAQAV_qUtEMxnYzu3Qpmkcqsbeo,2452
36
- modal/environments.pyi,sha256=HMSB6AeWCXeQcrsEyNiWwSzou3lD0G6h6R_4-AFU3gg,1439
37
- modal/exception.py,sha256=4AdUkT0uya5c4QDkO9mlpwfvu9C2SfpmjsbUNlfJH2k,5999
38
- modal/execution_context.py,sha256=Rt_nJ6jI0nGtK_6hO7r_78OzlC1fnfwuOX3OhAqr9k4,2324
39
- modal/execution_context.pyi,sha256=PZ-qh_AkmksTC7vJOA1HEzVsP1B9GI3yP2novHu1dUA,653
40
- modal/experimental.py,sha256=-nXs5bQoFlQHsJWf6YfIO41BrMoYJuVKr1Pil-EUOOU,316
41
- modal/functions.py,sha256=0ye39wcnKUTOF3KeVGM5-HHnm2G65BD4eoK_J-jUTaA,47804
42
- modal/functions.pyi,sha256=84BhAt_MIE2yShcGj8BJO4FWpHb50Mo5S6oeV6Jjy_4,19891
43
- modal/gpu.py,sha256=hZc8qWwp1iDsUwuilNjDWwL1ci4NINhMlUxPfKgn7Zs,8037
44
- modal/image.py,sha256=nSn-kCY9SocWiauGrXbK4kPa8GBeDFmwecHcpe4tHcg,68296
45
- modal/image.pyi,sha256=hA0O-YEJKOyyUo3ie9AaNpCgnkjUBXhTIfx0xcfSlMo,18339
46
- modal/mount.py,sha256=kVOnSODWbGmCuxOKkoDX9Jt5Y4oQHXutgRQJWauYzlc,26212
47
- modal/mount.pyi,sha256=Rwxg6Mxml1jXOLz9Kl8b-SQeJqM73gdHkzAgx_1LrBA,9710
48
- modal/network_file_system.py,sha256=hc14g2eYejkfIDDmR-i00EMNVxpxGMpXbYkqheCb0N0,14428
49
- modal/network_file_system.pyi,sha256=TI04zO5AUG58HwPIGCD0aB3G53DjUx-XdZy3EkbxvDo,6280
50
- modal/object.py,sha256=Ja5F9kJlATJvJM7WGBG26cQwW--DICSq8N0aSJL2oTA,8329
51
- modal/object.pyi,sha256=NVYTuTldnB5j8724Qx-dd0R8tWeuXBfh9IGSBMaw2aw,7573
52
- modal/parallel_map.py,sha256=3Jvm-SfAeKyqfi_2081UQWB1InVrKHcVz7E-nL7IXjA,15151
53
- modal/parallel_map.pyi,sha256=dYuVV0z1dniz9gt4iksCAkVKTggoml4Y5xjSloqIYE8,2400
54
- modal/partial_function.py,sha256=yErY8Mh9O0OLlJKrV2bsTpRtSG9VuQGdZJE80wjwKM8,19975
55
- modal/partial_function.pyi,sha256=1nfByULFi2rNIiCaFQR3YTv-FwD76aHpN_7iiO1o30E,6172
56
- modal/proxy.py,sha256=ey5IlDkPfb0zHGSsIQjgtFsLZwdjCoCp-ecIJlbDo5w,1307
57
- modal/proxy.pyi,sha256=Db8boRetc0K7sAUuKw-mg4eoRAX0GB7vyHOHlwuCEs8,428
58
- modal/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
59
- modal/queue.py,sha256=t8FuWHIxYzQKIn_kHPgCoMaa2mTx70AS3R2WGwv26vo,17461
60
- modal/queue.pyi,sha256=JP4sUI9HZYlqZCG0aLBggVSMXbjyBfwBPGbMXCZxwlM,7881
61
- modal/retries.py,sha256=n0tCmWPzOhKCXlTZn4gFaD4UWLbB3sbLzERXJsKUCY4,3768
62
- modal/runner.py,sha256=eDn9r9jiAr3BS43MkiLpUZcbllCCz2e2J3kr0_WA34o,19436
63
- modal/runner.pyi,sha256=YnCe8B4rvRb4CSK1EleZXaGTy3aLszp1SlFz4MQ8Kf8,5791
64
- modal/running_app.py,sha256=MRLSMzdAryNbDTI9ox0KbY4X8WBsCxZnhdYje9PP6Ts,461
65
- modal/sandbox.py,sha256=VFWn3MpTHcOqNey5tc7n3aqTgCABkeBxHw0y33EO5Ds,15449
66
- modal/sandbox.pyi,sha256=eCuMVSakb8NIpA10NC_Eq0HtCU319MnJBQIK2P9efWE,6841
67
- modal/schedule.py,sha256=_XVhLzsJXsqNs4uDO9E5P6HQsf2DF4DakjbRJnHUJ34,2721
68
- modal/scheduler_placement.py,sha256=15NhfoI1W6qklc8BabM5t19oVNhx9ZbPByaQO7YWSYw,662
69
- modal/secret.py,sha256=Xg3r6fRX3kjUDik-uGM0T_Pu4QeRfwjWWsLZbwp2ZDQ,9212
70
- modal/secret.pyi,sha256=1oh_skH9R-PmM7XqI6udQny75f1FmNNyZwrsgtrxPmM,2265
71
- modal/serving.py,sha256=p7QbGicoPVigCdBdqK52WPJ71TaRPsPabD9-FZDUUwc,4799
72
- modal/serving.pyi,sha256=Sr_7eADe4cCg3cZqnKj0HsDgeytsWqh9KJk2XXMtt9c,2977
73
- modal/shared_volume.py,sha256=vB-QLl7EMeusFWT91bVxsmYhzlBNYYYJukLmbF_5Rgk,888
74
- modal/shared_volume.pyi,sha256=JSrQyY3M0nn6cbhEV_Xd8AqN7VdzWr2_jsHEGH7HYOQ,405
75
- modal/token_flow.py,sha256=M28JpcN2KCeIaXmlGqtj6NBPcb8qvjEd59_ojR3tMDo,6742
76
- modal/token_flow.pyi,sha256=F5_ty7M18ulmLG9I-DJoqcg7CrbEgLDndEWvL_p9708,1890
77
- modal/volume.py,sha256=6NPxfsTURzozVJH-jXCS33mEF8B4WVdRTYSdJGraRNw,30272
78
- modal/volume.pyi,sha256=RsaoCzk7SUiGvW0MeDOV964h67dpDZUcumJSCV4Q7hk,10361
79
- modal/_utils/__init__.py,sha256=waLjl5c6IPDhSsdWAm9Bji4e2PVxamYABKAze6CHVXY,28
80
- modal/_utils/app_utils.py,sha256=Uf9oNKcC6wJg3wcHNygWxMlkXuIMVRYIE5nutDSafkQ,465
81
- modal/_utils/async_utils.py,sha256=xV63AKgDUc0gahAD8RIZj5oH1Oq27H2ClC3NT5PjNtU,16336
82
- modal/_utils/blob_utils.py,sha256=oHWcx13W9NNXx0Das_x50jvVbA29jpGnLJM7c74WfxQ,15054
83
- modal/_utils/function_utils.py,sha256=Kz8P8wIH5R1cYiQ3ruPIkoiBDMEqdoVGyUIXmOJZgqg,17084
84
- modal/_utils/grpc_testing.py,sha256=n_HsO6pkTx2CStvGvLCl2-Rrj25X35wQ8Jln83QUySM,7927
85
- modal/_utils/grpc_utils.py,sha256=udeRxwUVLGKwLdrWdItQ8BxxFn0JFmjp6kChB2U9Djk,6422
86
- modal/_utils/hash_utils.py,sha256=HefF7zPQPxFxyx3fpz-AdSm4QsHZNNvgL9-iQHY-_F4,1790
87
- modal/_utils/http_utils.py,sha256=DGKvrSQxAHjP_LNdM6EaL-TIQPGDX5vt3gcMGg2xkz4,1426
88
- modal/_utils/logger.py,sha256=0QvxZpyhhZwKZ5xOcMC9btS_XBE1wAKhtQmISU3gdd0,1311
89
- modal/_utils/mount_utils.py,sha256=f2q_tlDLVHcttJBkuoGfy99G-krZ-s5vZARi-bYzv-E,2341
90
- modal/_utils/package_utils.py,sha256=mh5zRXmY9wSmvqaCqFBAdPntLP1EmSkDWJt3GB4ey4s,1640
91
- modal/_utils/rand_pb_testing.py,sha256=_dRz09XhVoY9ZO7SN7xqi0MDVT22sY_ONnS0ts_3sUg,3857
92
- modal/_utils/shell_utils.py,sha256=_nQIZb4jbwcfjg-qCLgtlXEx2I9TCsmY1G0IQY8fFg4,3633
93
- modal/_vendor/__init__.py,sha256=MIEP8jhXUeGq_eCjYFcqN5b1bxBM4fdk0VESpjWR0fc,28
94
- modal/_vendor/a2wsgi_wsgi.py,sha256=2AnQcS5VhLZxod0trVNxnIYGH1SRbzT3dmJ4owVXzxA,22144
95
- modal/_vendor/cloudpickle.py,sha256=CcpkVlNqP3rtFiPK1Ffpub_i0bc7EThN8kU7nC0WXlc,55225
96
- modal/_vendor/tblib.py,sha256=g1O7QUDd3sDoLd8YPFltkXkih7r_fyZOjgmGuligv3s,9722
97
- modal/cli/__init__.py,sha256=waLjl5c6IPDhSsdWAm9Bji4e2PVxamYABKAze6CHVXY,28
98
- modal/cli/_download.py,sha256=sZL19eungg6P9ytUMivn16-dk-kVaIOi3rbr6Rszgwc,3007
99
- modal/cli/app.py,sha256=GIdFVSFMS5T4blraH9As5JeIANR5rU4tNpSVOvOsVbc,3053
100
- modal/cli/config.py,sha256=cSTH2oy0HTT-8GgH0tMvjqMKk_zYi_UcRGqRXkqCH3w,1294
101
- modal/cli/container.py,sha256=6OObgXtCF1WsEVQYTqPvzbCP8NiMMTx8Dux9bJCfzVg,1771
102
- modal/cli/entry_point.py,sha256=aUB_UYJeqbapCBN0bX4SyCagk1PIm94-oPan2PIsAwk,3538
103
- modal/cli/environment.py,sha256=Jgen64Wu6MUdvX8iDoqE3aJtiCD8PiHVjd3dfDOjT_U,3414
104
- modal/cli/import_refs.py,sha256=hmkMHywgBKoEfexUrmd9V32dw0GFMsgmG6YwP_KRoCk,10363
105
- modal/cli/launch.py,sha256=uySnUipRpEWzN5nITAXM63_xmtKanpyLvN3VcKrBPAA,2135
106
- modal/cli/network_file_system.py,sha256=y5UrCsXvcA1guD1KuywZ-xn45DljR12DKzrjjFlU-HU,6879
107
- modal/cli/profile.py,sha256=s4jCYHwriOorEFCKxeGZoSWX8rXTR_hDTNFZhOA565s,3109
108
- modal/cli/run.py,sha256=4MW1KN_U63rV0VS3Gp3FWFwqlicHUtrL7xmoX0VYmwo,13760
109
- modal/cli/secret.py,sha256=4qcrCd-3alNPzzoNWTtM5ZQY4SDBkL5weD5gvx8wMWU,4192
110
- modal/cli/token.py,sha256=Vsxy1ViEfuauWgPnpV8R3mRtKFQUtNmmTc2FYOY82Tg,1875
111
- modal/cli/utils.py,sha256=UI8dfKlzbWaKPr0nz2H-SvrhbV7IKV7uIwAt_aiQIbU,1473
112
- modal/cli/volume.py,sha256=ckvf6AsG8LpUZRBtNl7disKrcvRB3MlaIVUVWZY2VZM,9493
113
- modal/cli/programs/__init__.py,sha256=svYKtV8HDwDCN86zbdWqyq5T8sMdGDj0PVlzc2tIxDM,28
114
- modal/cli/programs/run_jupyter.py,sha256=gYqMUBxi837XRSCtxfUSZYWi_0eIQhH2ES_g8AeMddE,2137
115
- modal/cli/programs/vscode.py,sha256=OwiYwpuBSa6FcUkiRKv5dVNyuApTdtu0IPdpbIBnraM,1892
116
- modal/extensions/__init__.py,sha256=waLjl5c6IPDhSsdWAm9Bji4e2PVxamYABKAze6CHVXY,28
117
- modal/extensions/ipython.py,sha256=Xvzy-A7cvwMSDa9p4c4CEMLOX2_Xsg9DkM1J9uyu7jc,983
118
- modal/requirements/2023.12.312.txt,sha256=zWWUVgVQ92GXBKNYYr2-5vn9rlnXcmkqlwlX5u1eTYw,400
119
- modal/requirements/2023.12.txt,sha256=OjsbXFkCSdkzzryZP82Q73osr5wxQ6EUzmGcK7twfkA,502
120
- modal/requirements/2024.04.txt,sha256=ahcvUgDTsw7slMDPneAX6rZdeIc6fsW00ZzODccAC4A,520
121
- modal_docs/__init__.py,sha256=svYKtV8HDwDCN86zbdWqyq5T8sMdGDj0PVlzc2tIxDM,28
122
- modal_docs/gen_cli_docs.py,sha256=c1yfBS_x--gL5bs0N4ihMwqwX8l3IBWSkBAKNNIi6bQ,3801
123
- modal_docs/gen_reference_docs.py,sha256=g37KpE5P5ZxZl-vj0ie3Ewx1waTRMKCGIXQ_iYSy0e0,6555
124
- modal_docs/mdmd/__init__.py,sha256=svYKtV8HDwDCN86zbdWqyq5T8sMdGDj0PVlzc2tIxDM,28
125
- modal_docs/mdmd/mdmd.py,sha256=F9J0KdYVz8WmdLDnInTIlm8SmNZJLAiu3ZAZcxVIZ0k,6268
126
- modal_docs/mdmd/signatures.py,sha256=Jqy5AosHsQLAQJJe5cgYbciyFvb8xVwPIYwyBn-6RzU,3243
127
- modal_global_objects/__init__.py,sha256=waLjl5c6IPDhSsdWAm9Bji4e2PVxamYABKAze6CHVXY,28
128
- modal_global_objects/images/__init__.py,sha256=MIEP8jhXUeGq_eCjYFcqN5b1bxBM4fdk0VESpjWR0fc,28
129
- modal_global_objects/images/conda.py,sha256=5Tqd_62p7zGwVezJj1Qp2Vcxtt2WHWVBMzMNbjuNW-M,324
130
- modal_global_objects/images/debian_slim.py,sha256=9iB8L0tuEDWas3Mge1jyGvfBXiKsJpcjqJT5M1fWRos,330
131
- modal_global_objects/images/micromamba.py,sha256=k5m5P4xSBzliiTrdMITHx6iLhdQGIBuhPnP65JlBdG0,329
132
- modal_global_objects/mounts/__init__.py,sha256=MIEP8jhXUeGq_eCjYFcqN5b1bxBM4fdk0VESpjWR0fc,28
133
- modal_global_objects/mounts/modal_client_package.py,sha256=W0E_yShsRojPzWm6LtIQqNVolapdnrZkm2hVEQuZK_4,767
134
- modal_global_objects/mounts/python_standalone.py,sha256=_vTEX3PECUsatzhDs8lyJmDK0LbFetT1sJB6MIDfFAo,1870
135
- modal_proto/__init__.py,sha256=waLjl5c6IPDhSsdWAm9Bji4e2PVxamYABKAze6CHVXY,28
136
- modal_proto/api.proto,sha256=3tZrpYTIoXjWR3X7b5R8ZW7SMPWIflQd9BIS_SYRYwg,57567
137
- modal_proto/api_grpc.py,sha256=scZIz8gmSRXULKpVxwo2NIaOq0C9-WV5qCw_wMG6_QY,88101
138
- modal_proto/api_pb2.py,sha256=t1EqYn71_RjRfDZqdLIu3tK_oULrnrphxDRDr_qOfiw,222646
139
- modal_proto/api_pb2_grpc.py,sha256=2gvpCJ8T0WEsTkWwXv85fixrmFgJ63M5tQm_9aM0pgk,190583
140
- modal_proto/options.proto,sha256=a-siq4swVbZPfaFRXAipRZzGP2bq8OsdUvjlyzAeodQ,488
141
- modal_proto/options_grpc.py,sha256=M18X3d-8F_cNYSVM3I25dUTO5rZ0rd-vCCfynfh13Nc,125
142
- modal_proto/options_pb2.py,sha256=OC2Oob8Yz_3Gs58hwpS_jSFWpGsWMcxlgXbJCyw3gMk,1827
143
- modal_proto/options_pb2_grpc.py,sha256=1oboBPFxaTEXt9Aw7EAj8gXHDCNMhZD2VXqocC9l_gk,159
144
- modal_version/__init__.py,sha256=HTM4O90gT-ndgKJIFiD8JRMsdauRAWxc9TDGhBuhkYI,470
145
- modal_version/__main__.py,sha256=2FO0yYQQwDTh6udt1h-cBnGd1c4ZyHnHSI4BksxzVac,105
146
- modal_version/_version_generated.py,sha256=Rt-8vRt_Cfl6-FGpFfOVotOVbFQbZXC9eWbH8vu5x30,150
147
- test/__init__.py,sha256=waLjl5c6IPDhSsdWAm9Bji4e2PVxamYABKAze6CHVXY,28
148
- test/aio_test.py,sha256=u8nTraWcjAxPU7mV5w3m5hI2Xi9U1rXEEYyBnXTIEVs,199
149
- test/async_utils_test.py,sha256=T4HJlfMNe1cL5cEzFxv2e4rJoaJkqygvZYSgS75FAo4,7247
150
- test/blob_test.py,sha256=72LpqPJreb0mtLlkS14IN6rsvsQUWr1yrM97uTANUQo,2539
151
- test/cli_imports_test.py,sha256=U2JGz759LUSA-k1sbUmx3ALD6DPmVFthfodpeg9bXPM,4635
152
- test/cli_test.py,sha256=giu2W4yWLtrRu6rGFgsOrrOZeNZCjw27ZobggGlkka0,27254
153
- test/client_test.py,sha256=BFt0JCaCRjqt-xtGnSOdta4uFrWlGcXTL2293DVy6Qk,6887
154
- test/cloud_bucket_mount_test.py,sha256=5BwaEZbiWaDQ-9rzifhB7Uq6vzaqgTI6sL17SnAZqHA,530
155
- test/cls_test.py,sha256=TdRZJ614LWw8-5B08GAON0H8_GiBWNDsDLicsEUmbFE,16132
156
- test/config_test.py,sha256=oQgLnKLMZYTLxz_LNvE_Re99gYrAjR0DcfivI-U1btc,5121
157
- test/conftest.py,sha256=kdUio4X_Oo5_4S-1piy0YtOGeHnkdL27bGYVz29gXng,62804
158
- test/container_app_test.py,sha256=MDFTc_J9R1i4nXWD-k2Rk9SRiyGhxaBLFB6SwbG2GGs,1506
159
- test/container_test.py,sha256=5GUaYgofWbcr8JFrlNepsefxeMmBEJCYONtA86dQNBM,50375
160
- test/cpu_test.py,sha256=36StHgZlfblNGYxzwRvqL137x1Dk6C7oEb6y6cDWQi0,398
161
- test/decorator_test.py,sha256=ec0oAO-oBE0fMVehr83Gj7gnRtqL4pz8jN6vwMDYXaw,1850
162
- test/deprecation_test.py,sha256=IS_pracoNgt0vuEdLThukZpBkPBX4LUCQP5sAUMhjiY,1055
163
- test/dict_test.py,sha256=MmPaR1fzsN0lR-c3piPL4ylkBcSnfdjRIZ6ICUViTF4,1622
164
- test/e2e_test.py,sha256=OBBTB8p422PBD0iCoOfNTQQsIs_sX6_SkT1dNv3DiY4,2152
165
- test/error_test.py,sha256=bDxKUwE4WJ1qwAfm0Jlzqkb3WetF0YLxplrgjevAv4U,165
166
- test/function_serialization_test.py,sha256=4SJM8EdH9YXJ1woBla5L2VdnxWqSkOiL_EzDUU85KKY,966
167
- test/function_test.py,sha256=kVY5dxup6dR2Ictak_1loOT7aexSdnfSHawF8O5LkM8,23769
168
- test/function_utils_test.py,sha256=AZr8ZPh2h152epv-kn0rWZXwhM8MbPcaVSsOa5thzhY,1892
169
- test/gpu_test.py,sha256=lwL0nvQfcMHzS1tld9Pj3ElsujI6GaZTRA09Ik85lWA,4571
170
- test/grpc_utils_test.py,sha256=idjbD9XFiR4Tike8iiu_60nUX5iSv731_F40HXg8Jrs,2959
171
- test/helpers.py,sha256=2yL3YNC6xAa4kOiZeRX8yz1z4EbkLJuNfPvgZ9xvmu8,1716
172
- test/image_test.py,sha256=NUTBREVJlohusHCpwZBqtiNGiceYwbCRC1cwOvF9P1M,32798
173
- test/live_reload_test.py,sha256=iP3TdMu4JjkS6rI7oaIPfgNqDBRpkg2v9OQD9iae5mA,2722
174
- test/lookup_test.py,sha256=uGauFaxUBNJPl3unMgqM8lHhQMWDAGM8W_r_aBotZgQ,2160
175
- test/mdmd_test.py,sha256=G3B0986QneKtIrui34hu95h09No9mM06O7mPp2sTm50,5118
176
- test/mount_test.py,sha256=n7Qar7sDVMl1kTKfN2Je0kXbQ8DWPsAQ5q_v-VbrE3o,5475
177
- test/mounted_files_test.py,sha256=ssgPZIqAjALks7TKNS5OSuTsu1AhXrbdiRHgJ12ukhs,12409
178
- test/network_file_system_test.py,sha256=EBg_Tqtg0ryZeGANjSvwSeRFy1FGDdP29b6XTxNJGYM,6265
179
- test/notebook_test.py,sha256=IkOFP9Tat8pEazSOV73OU7QMGgOlw3sU_5vTzOigrZU,2157
180
- test/object_test.py,sha256=jyLxikU4quvVnDhdhIC9-rKRie1WOnB3hjaD-u383BM,1291
181
- test/package_utils_test.py,sha256=ic3cJqwVbe7p2jOwnnTuGTwP9aDduz9QueqVwcA8r9I,795
182
- test/queue_test.py,sha256=xtSVjCSv3sRvPsrra204muHE1OfSxF77nmGRE0X2H2I,3859
183
- test/resolver_test.py,sha256=YlwYPYZO6ZNBH9lQ8ynABwMUfvIs0Mg1h3lKz3PsmAs,1782
184
- test/retries_test.py,sha256=4x43pJc0Xt6VoPbk9ScnO2Xo_qFVX8QdtuoemO-prLk,1806
185
- test/runner_test.py,sha256=DG0WVFKidX0KGIIOxn3AEiYRbNDge7wiu7lOISJytt0,2909
186
- test/sandbox_test.py,sha256=SRsZbZdZjaQwv7VfsUu2MjT7P23m4YmaVMNlvDm77mA,5254
187
- test/schedule_test.py,sha256=ZDFaaG7WAA6mx6qwlYPNlcf0LHE96uvGFcxfmrnqi78,354
188
- test/scheduler_placement_test.py,sha256=f5AbbFldweCs-49zhcLq9HqYSAd_f-jDK8659pd1BVE,1610
189
- test/secret_test.py,sha256=awmf8De5W81n7-XtbIth3lX_a9IUzH8RbzHfliuQJQI,2949
190
- test/serialization_test.py,sha256=IaVZA3OVraHV6GqsKdbkVkcfjTiHVvwRf9b7dsRLgZM,2281
191
- test/stub_composition_test.py,sha256=yMW7P0JqqwvKP_cP6kj7GTRiJl3dUjOd-nSED9mQItk,555
192
- test/stub_test.py,sha256=E9ErL1ovO5n1wSy3Nl667QH83jMQLGduRvTgb-2KKEs,10906
193
- test/test_asgi_wrapper.py,sha256=FPkh8FnZ1lEo4Y0fyCuCUZ85wf5U4nPNtwORBTE6OR0,7328
194
- test/token_flow_test.py,sha256=tbxqsDFzRiMCkxfexDzxbbEomrmNlqJjOpPm8ndPE_c,614
195
- test/traceback_test.py,sha256=3FNfnb00ek1gMVj8xcT8veAcyF4j4Fdrz3G9_giljsc,4747
196
- test/tunnel_test.py,sha256=5v3FGmYS3VAcQB1xMjoXnmU1jLGvKu27TgFkH42N09w,768
197
- test/utils_test.py,sha256=VRBxxpIAl3TvvY8X_rumvqCR-5ZozV2tfm_1Gy4ok6M,2679
198
- test/version_test.py,sha256=lii24csueJzXzv0HM0fvHD83N_9FOOFRl-VRmDQZnDA,403
199
- test/volume_test.py,sha256=AfjsB-aF-4oC4Ga-FtfScF8VIXRm8LgMn6ETsj-wicQ,14550
200
- test/watcher_test.py,sha256=SJUAVLTJS_Fs5DsEM3VUCwq7nDCNtwRHihvMu93hfj4,2001
201
- test/webhook_test.py,sha256=jxf5-Vz2ECedwNWS7a506T7jJTEMfcJZ-NQPEet6kmI,4171
202
- modal-0.62.115.dist-info/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
203
- modal-0.62.115.dist-info/METADATA,sha256=eIx8_MlgCVhS1lRzvJyJCMQeYz1DNkRRb1R41wdaXhU,2301
204
- modal-0.62.115.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
205
- modal-0.62.115.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
206
- modal-0.62.115.dist-info/top_level.txt,sha256=AfUN7pr_AWNHp5av5c2h5ntw_83jrhQ2-ytzdC-S4Z0,69
207
- modal-0.62.115.dist-info/RECORD,,
@@ -1,15 +0,0 @@
1
- # Copyright Modal Labs 2022
2
- import asyncio
3
- import sys
4
-
5
- from modal import Image, Stub
6
-
7
-
8
- async def main(client=None, python_version=None):
9
- stub = Stub(image=Image.conda(python_version))
10
- async with stub.run.aio(client=client):
11
- pass
12
-
13
-
14
- if __name__ == "__main__":
15
- asyncio.run(main(python_version=sys.argv[1]))
@@ -1,15 +0,0 @@
1
- # Copyright Modal Labs 2022
2
- import asyncio
3
- import sys
4
-
5
- from modal import Image, Stub
6
-
7
-
8
- async def main(client=None, python_version=None):
9
- stub = Stub(image=Image.debian_slim(python_version))
10
- async with stub.run.aio(client=client):
11
- pass
12
-
13
-
14
- if __name__ == "__main__":
15
- asyncio.run(main(python_version=sys.argv[1]))
@@ -1,15 +0,0 @@
1
- # Copyright Modal Labs 2022
2
- import asyncio
3
- import sys
4
-
5
- from modal import Image, Stub
6
-
7
-
8
- async def main(client=None, python_version=None):
9
- stub = Stub(image=Image.micromamba(python_version))
10
- async with stub.run.aio(client=client):
11
- pass
12
-
13
-
14
- if __name__ == "__main__":
15
- asyncio.run(main(python_version=sys.argv[1]))
test/__init__.py DELETED
@@ -1 +0,0 @@
1
- # Copyright Modal Labs 2022
test/aio_test.py DELETED
@@ -1,12 +0,0 @@
1
- # Copyright Modal Labs 2023
2
- import pytest
3
-
4
-
5
- @pytest.mark.asyncio
6
- async def test_new(servicer, client):
7
- from modal import App
8
-
9
- app = App()
10
-
11
- async with app.run(client=client):
12
- pass
test/async_utils_test.py DELETED
@@ -1,279 +0,0 @@
1
- # Copyright Modal Labs 2022
2
- import asyncio
3
- import logging
4
- import os
5
- import platform
6
- import pytest
7
-
8
- from synchronicity import Synchronizer
9
-
10
- from modal._utils import async_utils
11
- from modal._utils.async_utils import (
12
- ConcurrencyPool,
13
- TaskContext,
14
- queue_batch_iterator,
15
- retry,
16
- warn_if_generator_is_not_consumed,
17
- )
18
-
19
- skip_github_non_linux = pytest.mark.skipif(
20
- (os.environ.get("GITHUB_ACTIONS") == "true" and platform.system() != "Linux"),
21
- reason="sleep is inaccurate on GitHub Actions runners.",
22
- )
23
-
24
-
25
- class SampleException(Exception):
26
- pass
27
-
28
-
29
- class FailNTimes:
30
- def __init__(self, n_failures, exc=SampleException("Something bad happened")):
31
- self.n_failures = n_failures
32
- self.n_calls = 0
33
- self.exc = exc
34
-
35
- async def __call__(self, x):
36
- self.n_calls += 1
37
- if self.n_calls <= self.n_failures:
38
- raise self.exc
39
- else:
40
- return x + 1
41
-
42
-
43
- @pytest.mark.asyncio
44
- async def test_retry():
45
- f_retry = retry(FailNTimes(2))
46
- assert await f_retry(42) == 43
47
-
48
- with pytest.raises(SampleException):
49
- f_retry = retry(FailNTimes(3))
50
- assert await f_retry(42) == 43
51
-
52
- f_retry = retry(n_attempts=5)(FailNTimes(4))
53
- assert await f_retry(42) == 43
54
-
55
- with pytest.raises(SampleException):
56
- f_retry = retry(n_attempts=5)(FailNTimes(5))
57
- assert await f_retry(42) == 43
58
-
59
-
60
- @pytest.mark.asyncio
61
- async def test_task_context():
62
- async with TaskContext() as task_context:
63
- t = task_context.create_task(asyncio.sleep(0.1))
64
- assert not t.done()
65
- # await asyncio.sleep(0.0)
66
- await asyncio.sleep(0.0) # just waste a loop step for the cancellation to go through
67
- assert t.cancelled()
68
-
69
-
70
- @pytest.mark.asyncio
71
- async def test_task_context_grace():
72
- async with TaskContext(grace=0.2) as task_context:
73
- u = task_context.create_task(asyncio.sleep(0.1))
74
- v = task_context.create_task(asyncio.sleep(0.3))
75
- assert not u.done()
76
- assert not v.done()
77
- await asyncio.sleep(0.0)
78
- assert u.done()
79
- assert v.cancelled()
80
-
81
-
82
- async def raise_exception():
83
- raise SampleException("foo")
84
-
85
-
86
- @skip_github_non_linux
87
- @pytest.mark.asyncio
88
- async def test_task_context_wait():
89
- async with TaskContext(grace=0.1) as task_context:
90
- u = task_context.create_task(asyncio.sleep(1.1))
91
- v = task_context.create_task(asyncio.sleep(1.3))
92
- await task_context.wait(u)
93
-
94
- assert u.done()
95
- assert v.cancelled()
96
-
97
- with pytest.raises(SampleException):
98
- async with TaskContext(grace=0.2) as task_context:
99
- u = task_context.create_task(asyncio.sleep(1.1))
100
- v = task_context.create_task(raise_exception())
101
- await task_context.wait(u)
102
-
103
- assert u.cancelled()
104
- assert v.done()
105
-
106
-
107
- @skip_github_non_linux
108
- @pytest.mark.asyncio
109
- async def test_task_context_infinite_loop():
110
- async with TaskContext(grace=0.01) as task_context:
111
- counter = 0
112
-
113
- async def f():
114
- nonlocal counter
115
- counter += 1
116
-
117
- t = task_context.infinite_loop(f, sleep=0.1)
118
- assert not t.done()
119
- await asyncio.sleep(0.35)
120
- assert counter == 4 # at 0.00, 0.10, 0.20, 0.30
121
- await asyncio.sleep(0.0) # just waste a loop step for the cancellation to go through
122
- assert not t.cancelled()
123
- assert t.done()
124
- assert counter == 4 # should be exited immediately
125
-
126
-
127
- DEBOUNCE_TIME = 0.1
128
-
129
-
130
- @pytest.mark.asyncio
131
- async def test_queue_batch_iterator():
132
- queue: asyncio.Queue = asyncio.Queue()
133
- await queue.put(1)
134
- drained_items = []
135
-
136
- async def drain_queue(logs_queue):
137
- async for batch in queue_batch_iterator(logs_queue, debounce_time=DEBOUNCE_TIME):
138
- drained_items.extend(batch)
139
-
140
- async with TaskContext(grace=0.0) as tc:
141
- tc.create_task(drain_queue(queue))
142
-
143
- # Make sure the queue gets drained.
144
- await asyncio.sleep(0.001)
145
-
146
- assert len(drained_items) == 1
147
-
148
- # Add items to the queue and a sentinel while it's still waiting for DEBOUNCE_TIME.
149
- await queue.put(2)
150
- await queue.put(3)
151
- await queue.put(None)
152
-
153
- await asyncio.sleep(DEBOUNCE_TIME + 0.001)
154
-
155
- assert len(drained_items) == 3
156
-
157
-
158
- @pytest.mark.asyncio
159
- async def test_warn_if_generator_is_not_consumed(caplog):
160
- @warn_if_generator_is_not_consumed()
161
- async def my_generator():
162
- yield 42
163
-
164
- with caplog.at_level(logging.WARNING):
165
- g = my_generator()
166
- assert "my_generator" in repr(g)
167
- del g # Force destructor
168
-
169
- assert len(caplog.records) == 1
170
- assert "my_generator" in caplog.text
171
- assert "for" in caplog.text
172
- assert "list" in caplog.text
173
-
174
-
175
- @pytest.mark.asyncio
176
- def test_warn_if_generator_is_not_consumed_sync(caplog):
177
- @warn_if_generator_is_not_consumed()
178
- def my_generator():
179
- yield 42
180
-
181
- with caplog.at_level(logging.WARNING):
182
- g = my_generator()
183
- assert "my_generator" in repr(g)
184
- del g # Force destructor
185
-
186
- assert len(caplog.records) == 1
187
- assert "my_generator" in caplog.text
188
- assert "for" in caplog.text
189
- assert "list" in caplog.text
190
-
191
-
192
- @pytest.mark.asyncio
193
- async def test_no_warn_if_generator_is_consumed(caplog):
194
- @warn_if_generator_is_not_consumed()
195
- async def my_generator():
196
- yield 42
197
-
198
- with caplog.at_level(logging.WARNING):
199
- g = my_generator()
200
- async for _ in g:
201
- pass
202
- del g # Force destructor
203
-
204
- assert len(caplog.records) == 0
205
-
206
-
207
- def test_exit_handler():
208
- result = None
209
- sync = Synchronizer()
210
-
211
- async def cleanup():
212
- nonlocal result
213
- result = "bye"
214
-
215
- async def _setup_code():
216
- async_utils.on_shutdown(cleanup())
217
-
218
- setup_code = sync.create_blocking(_setup_code)
219
- setup_code()
220
-
221
- sync._close_loop() # this is called on exit by synchronicity, which shuts down the event loop
222
- assert result == "bye"
223
-
224
-
225
- @pytest.mark.asyncio
226
- async def test_concurrency_pool():
227
- max_running = 0
228
- running = 0
229
-
230
- async def f():
231
- nonlocal running, max_running
232
- running += 1
233
- max_running = max(max_running, running)
234
- await asyncio.sleep(0.1)
235
- running -= 1
236
-
237
- def gen():
238
- for i in range(100):
239
- yield f()
240
-
241
- await asyncio.wait_for(ConcurrencyPool(50).run_coros(gen()), 0.3)
242
- assert max_running == 50
243
-
244
-
245
- @pytest.mark.asyncio
246
- async def test_concurrency_pool_cancels_non_started():
247
- counter = 0
248
-
249
- async def f():
250
- nonlocal counter
251
- counter += 1
252
- raise RuntimeError("some error")
253
-
254
- def gen():
255
- for i in range(100):
256
- yield f()
257
-
258
- with pytest.raises(RuntimeError):
259
- await ConcurrencyPool(2).run_coros(gen(), return_exceptions=False)
260
- await asyncio.sleep(0.1)
261
- assert counter == 2
262
-
263
-
264
- @pytest.mark.asyncio
265
- async def test_concurrency_pool_return_exceptions():
266
- async def f(x):
267
- if x % 2:
268
- raise RuntimeError("some error")
269
- else:
270
- return 42
271
-
272
- def gen():
273
- for x in range(4):
274
- yield f(x)
275
-
276
- res = await asyncio.wait_for(ConcurrencyPool(2).run_coros(gen(), return_exceptions=True), 0.1)
277
- assert res[0] == res[2] == 42
278
- assert isinstance(res[1], RuntimeError)
279
- assert isinstance(res[3], RuntimeError)
test/blob_test.py DELETED
@@ -1,67 +0,0 @@
1
- # Copyright Modal Labs 2022
2
- import pytest
3
- import random
4
-
5
- from modal._utils.async_utils import synchronize_api
6
- from modal._utils.blob_utils import (
7
- blob_download as _blob_download,
8
- blob_upload as _blob_upload,
9
- blob_upload_file as _blob_upload_file,
10
- )
11
- from modal.exception import ExecutionError
12
-
13
- from .supports.skip import skip_old_py
14
-
15
- blob_upload = synchronize_api(_blob_upload)
16
- blob_download = synchronize_api(_blob_download)
17
- blob_upload_file = synchronize_api(_blob_upload_file)
18
-
19
-
20
- @pytest.mark.asyncio
21
- async def test_blob_put_get(servicer, blob_server, client):
22
- # Upload
23
- blob_id = await blob_upload.aio(b"Hello, world", client.stub)
24
-
25
- # Download
26
- data = await blob_download.aio(blob_id, client.stub)
27
- assert data == b"Hello, world"
28
-
29
-
30
- @pytest.mark.asyncio
31
- async def test_blob_put_failure(servicer, blob_server, client):
32
- with pytest.raises(ExecutionError):
33
- await blob_upload.aio(b"FAILURE", client.stub)
34
-
35
-
36
- @pytest.mark.asyncio
37
- async def test_blob_get_failure(servicer, blob_server, client):
38
- with pytest.raises(ExecutionError):
39
- await blob_download.aio("bl-failure", client.stub)
40
-
41
-
42
- @pytest.mark.asyncio
43
- async def test_blob_large(servicer, blob_server, client):
44
- data = b"*" * 10_000_000
45
- blob_id = await blob_upload.aio(data, client.stub)
46
- assert await blob_download.aio(blob_id, client.stub) == data
47
-
48
-
49
- @skip_old_py("random.randbytes() was introduced in python 3.9", (3, 9))
50
- @pytest.mark.asyncio
51
- async def test_blob_multipart(servicer, blob_server, client, monkeypatch, tmp_path):
52
- monkeypatch.setattr("modal._utils.blob_utils.DEFAULT_SEGMENT_CHUNK_SIZE", 128)
53
- multipart_threshold = 1024
54
- servicer.blob_multipart_threshold = multipart_threshold
55
- # - set high # of parts, to test concurrency correctness
56
- # - make last part significantly shorter than rest, creating uneven upload time.
57
- data_len = (256 * multipart_threshold) + (multipart_threshold // 2)
58
- data = random.randbytes(data_len) # random data will not hide byte re-ordering corruption
59
- blob_id = await blob_upload.aio(data, client.stub)
60
- assert await blob_download.aio(blob_id, client.stub) == data
61
-
62
- data_len = (256 * multipart_threshold) + (multipart_threshold // 2)
63
- data = random.randbytes(data_len) # random data will not hide byte re-ordering corruption
64
- data_filepath = tmp_path / "temp.bin"
65
- data_filepath.write_bytes(data)
66
- blob_id = await blob_upload_file.aio(data_filepath.open("rb"), client.stub)
67
- assert await blob_download.aio(blob_id, client.stub) == data