modal 1.0.5.dev13__tar.gz → 1.0.5.dev15__tar.gz

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 (184) hide show
  1. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/PKG-INFO +2 -2
  2. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_utils/blob_utils.py +52 -18
  3. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/client.pyi +2 -2
  4. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal.egg-info/PKG-INFO +2 -2
  5. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal.egg-info/requires.txt +1 -1
  6. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal_version/__init__.py +1 -1
  7. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/pyproject.toml +1 -1
  8. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/LICENSE +0 -0
  9. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/README.md +0 -0
  10. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/__init__.py +0 -0
  11. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/__main__.py +0 -0
  12. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_clustered_functions.py +0 -0
  13. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_clustered_functions.pyi +0 -0
  14. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_container_entrypoint.py +0 -0
  15. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_functions.py +0 -0
  16. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_ipython.py +0 -0
  17. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_location.py +0 -0
  18. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_object.py +0 -0
  19. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_output.py +0 -0
  20. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_partial_function.py +0 -0
  21. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_pty.py +0 -0
  22. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_resolver.py +0 -0
  23. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_resources.py +0 -0
  24. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_runtime/__init__.py +0 -0
  25. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_runtime/asgi.py +0 -0
  26. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_runtime/container_io_manager.py +0 -0
  27. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_runtime/container_io_manager.pyi +0 -0
  28. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_runtime/execution_context.py +0 -0
  29. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_runtime/execution_context.pyi +0 -0
  30. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_runtime/gpu_memory_snapshot.py +0 -0
  31. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_runtime/telemetry.py +0 -0
  32. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_runtime/user_code_imports.py +0 -0
  33. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_serialization.py +0 -0
  34. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_traceback.py +0 -0
  35. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_tunnel.py +0 -0
  36. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_tunnel.pyi +0 -0
  37. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_type_manager.py +0 -0
  38. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_utils/__init__.py +0 -0
  39. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_utils/app_utils.py +0 -0
  40. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_utils/async_utils.py +0 -0
  41. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_utils/bytes_io_segment_payload.py +0 -0
  42. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_utils/deprecation.py +0 -0
  43. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_utils/docker_utils.py +0 -0
  44. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_utils/function_utils.py +0 -0
  45. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_utils/git_utils.py +0 -0
  46. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_utils/grpc_testing.py +0 -0
  47. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_utils/grpc_utils.py +0 -0
  48. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_utils/hash_utils.py +0 -0
  49. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_utils/http_utils.py +0 -0
  50. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_utils/jwt_utils.py +0 -0
  51. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_utils/logger.py +0 -0
  52. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_utils/mount_utils.py +0 -0
  53. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_utils/name_utils.py +0 -0
  54. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_utils/package_utils.py +0 -0
  55. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_utils/pattern_utils.py +0 -0
  56. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_utils/rand_pb_testing.py +0 -0
  57. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_utils/shell_utils.py +0 -0
  58. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_utils/time_utils.py +0 -0
  59. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_vendor/__init__.py +0 -0
  60. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_vendor/a2wsgi_wsgi.py +0 -0
  61. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_vendor/cloudpickle.py +0 -0
  62. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_vendor/tblib.py +0 -0
  63. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/_watcher.py +0 -0
  64. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/app.py +0 -0
  65. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/app.pyi +0 -0
  66. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/call_graph.py +0 -0
  67. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/cli/__init__.py +0 -0
  68. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/cli/_download.py +0 -0
  69. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/cli/_traceback.py +0 -0
  70. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/cli/app.py +0 -0
  71. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/cli/cluster.py +0 -0
  72. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/cli/config.py +0 -0
  73. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/cli/container.py +0 -0
  74. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/cli/dict.py +0 -0
  75. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/cli/entry_point.py +0 -0
  76. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/cli/environment.py +0 -0
  77. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/cli/import_refs.py +0 -0
  78. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/cli/launch.py +0 -0
  79. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/cli/network_file_system.py +0 -0
  80. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/cli/profile.py +0 -0
  81. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/cli/programs/__init__.py +0 -0
  82. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/cli/programs/run_jupyter.py +0 -0
  83. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/cli/programs/vscode.py +0 -0
  84. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/cli/queues.py +0 -0
  85. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/cli/run.py +0 -0
  86. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/cli/secret.py +0 -0
  87. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/cli/token.py +0 -0
  88. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/cli/utils.py +0 -0
  89. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/cli/volume.py +0 -0
  90. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/client.py +0 -0
  91. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/cloud_bucket_mount.py +0 -0
  92. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/cloud_bucket_mount.pyi +0 -0
  93. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/cls.py +0 -0
  94. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/cls.pyi +0 -0
  95. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/config.py +0 -0
  96. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/container_process.py +0 -0
  97. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/container_process.pyi +0 -0
  98. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/dict.py +0 -0
  99. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/dict.pyi +0 -0
  100. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/environments.py +0 -0
  101. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/environments.pyi +0 -0
  102. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/exception.py +0 -0
  103. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/experimental/__init__.py +0 -0
  104. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/experimental/ipython.py +0 -0
  105. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/file_io.py +0 -0
  106. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/file_io.pyi +0 -0
  107. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/file_pattern_matcher.py +0 -0
  108. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/functions.py +0 -0
  109. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/functions.pyi +0 -0
  110. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/gpu.py +0 -0
  111. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/image.py +0 -0
  112. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/image.pyi +0 -0
  113. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/io_streams.py +0 -0
  114. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/io_streams.pyi +0 -0
  115. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/mount.py +0 -0
  116. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/mount.pyi +0 -0
  117. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/network_file_system.py +0 -0
  118. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/network_file_system.pyi +0 -0
  119. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/object.py +0 -0
  120. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/object.pyi +0 -0
  121. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/output.py +0 -0
  122. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/parallel_map.py +0 -0
  123. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/parallel_map.pyi +0 -0
  124. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/partial_function.py +0 -0
  125. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/partial_function.pyi +0 -0
  126. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/proxy.py +0 -0
  127. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/proxy.pyi +0 -0
  128. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/py.typed +0 -0
  129. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/queue.py +0 -0
  130. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/queue.pyi +0 -0
  131. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/requirements/2023.12.312.txt +0 -0
  132. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/requirements/2023.12.txt +0 -0
  133. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/requirements/2024.04.txt +0 -0
  134. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/requirements/2024.10.txt +0 -0
  135. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/requirements/PREVIEW.txt +0 -0
  136. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/requirements/README.md +0 -0
  137. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/requirements/base-images.json +0 -0
  138. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/retries.py +0 -0
  139. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/runner.py +0 -0
  140. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/runner.pyi +0 -0
  141. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/running_app.py +0 -0
  142. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/sandbox.py +0 -0
  143. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/sandbox.pyi +0 -0
  144. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/schedule.py +0 -0
  145. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/scheduler_placement.py +0 -0
  146. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/secret.py +0 -0
  147. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/secret.pyi +0 -0
  148. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/serving.py +0 -0
  149. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/serving.pyi +0 -0
  150. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/snapshot.py +0 -0
  151. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/snapshot.pyi +0 -0
  152. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/stream_type.py +0 -0
  153. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/token_flow.py +0 -0
  154. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/token_flow.pyi +0 -0
  155. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/volume.py +0 -0
  156. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal/volume.pyi +0 -0
  157. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal.egg-info/SOURCES.txt +0 -0
  158. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal.egg-info/dependency_links.txt +0 -0
  159. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal.egg-info/entry_points.txt +0 -0
  160. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal.egg-info/top_level.txt +0 -0
  161. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal_docs/__init__.py +0 -0
  162. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal_docs/gen_cli_docs.py +0 -0
  163. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal_docs/gen_reference_docs.py +0 -0
  164. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal_docs/mdmd/__init__.py +0 -0
  165. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal_docs/mdmd/mdmd.py +0 -0
  166. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal_docs/mdmd/signatures.py +0 -0
  167. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal_proto/__init__.py +0 -0
  168. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal_proto/api.proto +0 -0
  169. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal_proto/api_grpc.py +0 -0
  170. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal_proto/api_pb2.py +0 -0
  171. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal_proto/api_pb2.pyi +0 -0
  172. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal_proto/api_pb2_grpc.py +0 -0
  173. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal_proto/api_pb2_grpc.pyi +0 -0
  174. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal_proto/modal_api_grpc.py +0 -0
  175. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal_proto/modal_options_grpc.py +0 -0
  176. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal_proto/options.proto +0 -0
  177. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal_proto/options_grpc.py +0 -0
  178. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal_proto/options_pb2.py +0 -0
  179. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal_proto/options_pb2.pyi +0 -0
  180. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal_proto/options_pb2_grpc.py +0 -0
  181. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal_proto/options_pb2_grpc.pyi +0 -0
  182. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal_proto/py.typed +0 -0
  183. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/modal_version/__main__.py +0 -0
  184. {modal-1.0.5.dev13 → modal-1.0.5.dev15}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.0.5.dev13
3
+ Version: 1.0.5.dev15
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -19,7 +19,7 @@ License-File: LICENSE
19
19
  Requires-Dist: aiohttp
20
20
  Requires-Dist: certifi
21
21
  Requires-Dist: click~=8.1.0
22
- Requires-Dist: grpclib==0.4.7
22
+ Requires-Dist: grpclib<0.4.9,>=0.4.7
23
23
  Requires-Dist: protobuf!=4.24.0,<7.0,>=3.19
24
24
  Requires-Dist: rich>=12.0.0
25
25
  Requires-Dist: synchronicity~=0.9.15
@@ -4,6 +4,7 @@ import dataclasses
4
4
  import hashlib
5
5
  import os
6
6
  import platform
7
+ import random
7
8
  import time
8
9
  from collections.abc import AsyncIterator
9
10
  from contextlib import AbstractContextManager, contextmanager
@@ -55,6 +56,8 @@ MULTIPART_UPLOAD_THRESHOLD = 1024**3
55
56
  # For block based storage like volumefs2: the size of a block
56
57
  BLOCK_SIZE: int = 8 * 1024 * 1024
57
58
 
59
+ HEALTHY_R2_UPLOAD_PERCENTAGE = 0.95
60
+
58
61
 
59
62
  @retry(n_attempts=5, base_delay=0.5, timeout=None)
60
63
  async def _upload_to_s3_url(
@@ -182,6 +185,22 @@ def get_content_length(data: BinaryIO) -> int:
182
185
  return content_length - pos
183
186
 
184
187
 
188
+ async def _blob_upload_with_fallback(items, blob_ids, callback):
189
+ for idx, (item, blob_id) in enumerate(zip(items, blob_ids)):
190
+ # We want to default to R2 95% of the time and S3 5% of the time.
191
+ # To ensure the failure path is continuously exercised.
192
+ if idx == 0 and len(items) > 1 and random.random() > HEALTHY_R2_UPLOAD_PERCENTAGE:
193
+ continue
194
+ try:
195
+ await callback(item)
196
+ return blob_id
197
+ except Exception as _:
198
+ # Ignore all errors except the last one, since we're out of fallback options.
199
+ if idx == len(items) - 1:
200
+ raise
201
+ raise ExecutionError("Failed to upload blob")
202
+
203
+
185
204
  async def _blob_upload(
186
205
  upload_hashes: UploadHashes, data: Union[bytes, BinaryIO], stub, progress_report_cb: Optional[Callable] = None
187
206
  ) -> str:
@@ -197,17 +216,23 @@ async def _blob_upload(
197
216
  )
198
217
  resp = await retry_transient_errors(stub.BlobCreate, req)
199
218
 
200
- blob_id = resp.blob_id
219
+ if resp.WhichOneof("upload_types_oneof") == "multiparts":
220
+
221
+ async def upload_multipart_upload(part):
222
+ return await perform_multipart_upload(
223
+ data,
224
+ content_length=content_length,
225
+ max_part_size=part.part_length,
226
+ part_urls=part.upload_urls,
227
+ completion_url=part.completion_url,
228
+ upload_chunk_size=DEFAULT_SEGMENT_CHUNK_SIZE,
229
+ progress_report_cb=progress_report_cb,
230
+ )
201
231
 
202
- if resp.WhichOneof("upload_type_oneof") == "multipart":
203
- await perform_multipart_upload(
204
- data,
205
- content_length=content_length,
206
- max_part_size=resp.multipart.part_length,
207
- part_urls=resp.multipart.upload_urls,
208
- completion_url=resp.multipart.completion_url,
209
- upload_chunk_size=DEFAULT_SEGMENT_CHUNK_SIZE,
210
- progress_report_cb=progress_report_cb,
232
+ blob_id = await _blob_upload_with_fallback(
233
+ resp.multiparts.items,
234
+ resp.blob_ids,
235
+ upload_multipart_upload,
211
236
  )
212
237
  else:
213
238
  from .bytes_io_segment_payload import BytesIOSegmentPayload
@@ -215,11 +240,19 @@ async def _blob_upload(
215
240
  payload = BytesIOSegmentPayload(
216
241
  data, segment_start=0, segment_length=content_length, progress_report_cb=progress_report_cb
217
242
  )
218
- await _upload_to_s3_url(
219
- resp.upload_url,
220
- payload,
221
- # for single part uploads, we use server side md5 checksums
222
- content_md5_b64=upload_hashes.md5_base64,
243
+
244
+ async def upload_to_s3_url(url):
245
+ return await _upload_to_s3_url(
246
+ url,
247
+ payload,
248
+ # for single part uploads, we use server side md5 checksums
249
+ content_md5_b64=upload_hashes.md5_base64,
250
+ )
251
+
252
+ blob_id = await _blob_upload_with_fallback(
253
+ resp.upload_urls.items,
254
+ resp.blob_ids,
255
+ upload_to_s3_url,
223
256
  )
224
257
 
225
258
  if progress_report_cb:
@@ -380,8 +413,10 @@ def get_file_upload_spec_from_fileobj(fp: BinaryIO, mount_filename: PurePosixPat
380
413
  mode,
381
414
  )
382
415
 
416
+
383
417
  _FileUploadSource2 = Callable[[], ContextManager[BinaryIO]]
384
418
 
419
+
385
420
  @dataclasses.dataclass
386
421
  class FileUploadSpec2:
387
422
  source: _FileUploadSource2
@@ -393,7 +428,6 @@ class FileUploadSpec2:
393
428
  mode: int # file permission bits (last 12 bits of st_mode)
394
429
  size: int
395
430
 
396
-
397
431
  @staticmethod
398
432
  async def from_path(
399
433
  filename: Path,
@@ -416,7 +450,6 @@ class FileUploadSpec2:
416
450
  hash_semaphore,
417
451
  )
418
452
 
419
-
420
453
  @staticmethod
421
454
  async def from_fileobj(
422
455
  source_fp: Union[BinaryIO, BytesIO],
@@ -426,6 +459,7 @@ class FileUploadSpec2:
426
459
  ) -> "FileUploadSpec2":
427
460
  try:
428
461
  fileno = source_fp.fileno()
462
+
429
463
  def source():
430
464
  new_fd = os.dup(fileno)
431
465
  fp = os.fdopen(new_fd, "rb")
@@ -436,6 +470,7 @@ class FileUploadSpec2:
436
470
  # `.fileno()` not available; assume BytesIO-like type
437
471
  source_fp = cast(BytesIO, source_fp)
438
472
  buffer = source_fp.getbuffer()
473
+
439
474
  def source():
440
475
  return BytesIO(buffer)
441
476
 
@@ -447,7 +482,6 @@ class FileUploadSpec2:
447
482
  hash_semaphore,
448
483
  )
449
484
 
450
-
451
485
  @staticmethod
452
486
  async def _create(
453
487
  source: _FileUploadSource2,
@@ -31,7 +31,7 @@ class _Client:
31
31
  server_url: str,
32
32
  client_type: int,
33
33
  credentials: typing.Optional[tuple[str, str]],
34
- version: str = "1.0.5.dev13",
34
+ version: str = "1.0.5.dev15",
35
35
  ):
36
36
  """mdmd:hidden
37
37
  The Modal client object is not intended to be instantiated directly by users.
@@ -160,7 +160,7 @@ class Client:
160
160
  server_url: str,
161
161
  client_type: int,
162
162
  credentials: typing.Optional[tuple[str, str]],
163
- version: str = "1.0.5.dev13",
163
+ version: str = "1.0.5.dev15",
164
164
  ):
165
165
  """mdmd:hidden
166
166
  The Modal client object is not intended to be instantiated directly by users.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.0.5.dev13
3
+ Version: 1.0.5.dev15
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -19,7 +19,7 @@ License-File: LICENSE
19
19
  Requires-Dist: aiohttp
20
20
  Requires-Dist: certifi
21
21
  Requires-Dist: click~=8.1.0
22
- Requires-Dist: grpclib==0.4.7
22
+ Requires-Dist: grpclib<0.4.9,>=0.4.7
23
23
  Requires-Dist: protobuf!=4.24.0,<7.0,>=3.19
24
24
  Requires-Dist: rich>=12.0.0
25
25
  Requires-Dist: synchronicity~=0.9.15
@@ -1,7 +1,7 @@
1
1
  aiohttp
2
2
  certifi
3
3
  click~=8.1.0
4
- grpclib==0.4.7
4
+ grpclib<0.4.9,>=0.4.7
5
5
  protobuf!=4.24.0,<7.0,>=3.19
6
6
  rich>=12.0.0
7
7
  synchronicity~=0.9.15
@@ -1,4 +1,4 @@
1
1
  # Copyright Modal Labs 2025
2
2
  """Supplies the current version of the modal client library."""
3
3
 
4
- __version__ = "1.0.5.dev13"
4
+ __version__ = "1.0.5.dev15"
@@ -17,7 +17,7 @@ dependencies = [
17
17
  "aiohttp",
18
18
  "certifi",
19
19
  "click~=8.1.0",
20
- "grpclib==0.4.7",
20
+ "grpclib>=0.4.7,<0.4.9",
21
21
  "protobuf>=3.19,<7.0,!=4.24.0",
22
22
  "rich>=12.0.0",
23
23
  "synchronicity~=0.9.15",
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes