modal 1.0.6.dev10__tar.gz → 1.0.6.dev12__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.

Potentially problematic release.


This version of modal might be problematic. Click here for more details.

Files changed (184) hide show
  1. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/PKG-INFO +1 -1
  2. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_functions.py +19 -1
  3. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_utils/function_utils.py +4 -3
  4. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/client.pyi +2 -2
  5. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/image.py +108 -0
  6. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/image.pyi +60 -0
  7. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/parallel_map.py +8 -1
  8. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal.egg-info/PKG-INFO +1 -1
  9. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal_proto/api.proto +2 -0
  10. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal_proto/api_pb2.py +510 -510
  11. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal_proto/api_pb2.pyi +8 -2
  12. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal_version/__init__.py +1 -1
  13. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/LICENSE +0 -0
  14. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/README.md +0 -0
  15. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/__init__.py +0 -0
  16. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/__main__.py +0 -0
  17. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_clustered_functions.py +0 -0
  18. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_clustered_functions.pyi +0 -0
  19. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_container_entrypoint.py +0 -0
  20. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_ipython.py +0 -0
  21. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_location.py +0 -0
  22. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_object.py +0 -0
  23. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_output.py +0 -0
  24. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_partial_function.py +0 -0
  25. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_pty.py +0 -0
  26. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_resolver.py +0 -0
  27. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_resources.py +0 -0
  28. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_runtime/__init__.py +0 -0
  29. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_runtime/asgi.py +0 -0
  30. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_runtime/container_io_manager.py +0 -0
  31. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_runtime/container_io_manager.pyi +0 -0
  32. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_runtime/execution_context.py +0 -0
  33. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_runtime/execution_context.pyi +0 -0
  34. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_runtime/gpu_memory_snapshot.py +0 -0
  35. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_runtime/telemetry.py +0 -0
  36. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_runtime/user_code_imports.py +0 -0
  37. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_serialization.py +0 -0
  38. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_traceback.py +0 -0
  39. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_tunnel.py +0 -0
  40. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_tunnel.pyi +0 -0
  41. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_type_manager.py +0 -0
  42. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_utils/__init__.py +0 -0
  43. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_utils/app_utils.py +0 -0
  44. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_utils/async_utils.py +0 -0
  45. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_utils/blob_utils.py +0 -0
  46. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_utils/bytes_io_segment_payload.py +0 -0
  47. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_utils/deprecation.py +0 -0
  48. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_utils/docker_utils.py +0 -0
  49. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_utils/git_utils.py +0 -0
  50. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_utils/grpc_testing.py +0 -0
  51. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_utils/grpc_utils.py +0 -0
  52. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_utils/hash_utils.py +0 -0
  53. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_utils/http_utils.py +0 -0
  54. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_utils/jwt_utils.py +0 -0
  55. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_utils/logger.py +0 -0
  56. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_utils/mount_utils.py +0 -0
  57. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_utils/name_utils.py +0 -0
  58. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_utils/package_utils.py +0 -0
  59. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_utils/pattern_utils.py +0 -0
  60. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_utils/rand_pb_testing.py +0 -0
  61. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_utils/shell_utils.py +0 -0
  62. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_utils/time_utils.py +0 -0
  63. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_vendor/__init__.py +0 -0
  64. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_vendor/a2wsgi_wsgi.py +0 -0
  65. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_vendor/cloudpickle.py +0 -0
  66. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_vendor/tblib.py +0 -0
  67. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/_watcher.py +0 -0
  68. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/app.py +0 -0
  69. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/app.pyi +0 -0
  70. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/call_graph.py +0 -0
  71. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/cli/__init__.py +0 -0
  72. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/cli/_download.py +0 -0
  73. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/cli/_traceback.py +0 -0
  74. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/cli/app.py +0 -0
  75. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/cli/cluster.py +0 -0
  76. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/cli/config.py +0 -0
  77. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/cli/container.py +0 -0
  78. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/cli/dict.py +0 -0
  79. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/cli/entry_point.py +0 -0
  80. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/cli/environment.py +0 -0
  81. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/cli/import_refs.py +0 -0
  82. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/cli/launch.py +0 -0
  83. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/cli/network_file_system.py +0 -0
  84. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/cli/profile.py +0 -0
  85. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/cli/programs/__init__.py +0 -0
  86. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/cli/programs/run_jupyter.py +0 -0
  87. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/cli/programs/vscode.py +0 -0
  88. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/cli/queues.py +0 -0
  89. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/cli/run.py +0 -0
  90. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/cli/secret.py +0 -0
  91. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/cli/token.py +0 -0
  92. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/cli/utils.py +0 -0
  93. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/cli/volume.py +0 -0
  94. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/client.py +0 -0
  95. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/cloud_bucket_mount.py +0 -0
  96. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/cloud_bucket_mount.pyi +0 -0
  97. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/cls.py +0 -0
  98. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/cls.pyi +0 -0
  99. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/config.py +0 -0
  100. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/container_process.py +0 -0
  101. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/container_process.pyi +0 -0
  102. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/dict.py +0 -0
  103. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/dict.pyi +0 -0
  104. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/environments.py +0 -0
  105. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/environments.pyi +0 -0
  106. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/exception.py +0 -0
  107. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/experimental/__init__.py +0 -0
  108. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/experimental/ipython.py +0 -0
  109. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/file_io.py +0 -0
  110. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/file_io.pyi +0 -0
  111. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/file_pattern_matcher.py +0 -0
  112. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/functions.py +0 -0
  113. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/functions.pyi +0 -0
  114. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/gpu.py +0 -0
  115. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/io_streams.py +0 -0
  116. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/io_streams.pyi +0 -0
  117. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/mount.py +0 -0
  118. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/mount.pyi +0 -0
  119. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/network_file_system.py +0 -0
  120. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/network_file_system.pyi +0 -0
  121. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/object.py +0 -0
  122. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/object.pyi +0 -0
  123. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/output.py +0 -0
  124. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/parallel_map.pyi +0 -0
  125. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/partial_function.py +0 -0
  126. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/partial_function.pyi +0 -0
  127. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/proxy.py +0 -0
  128. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/proxy.pyi +0 -0
  129. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/py.typed +0 -0
  130. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/queue.py +0 -0
  131. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/queue.pyi +0 -0
  132. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/requirements/2023.12.312.txt +0 -0
  133. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/requirements/2023.12.txt +0 -0
  134. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/requirements/2024.04.txt +0 -0
  135. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/requirements/2024.10.txt +0 -0
  136. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/requirements/PREVIEW.txt +0 -0
  137. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/requirements/README.md +0 -0
  138. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/requirements/base-images.json +0 -0
  139. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/retries.py +0 -0
  140. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/runner.py +0 -0
  141. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/runner.pyi +0 -0
  142. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/running_app.py +0 -0
  143. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/sandbox.py +0 -0
  144. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/sandbox.pyi +0 -0
  145. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/schedule.py +0 -0
  146. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/scheduler_placement.py +0 -0
  147. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/secret.py +0 -0
  148. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/secret.pyi +0 -0
  149. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/serving.py +0 -0
  150. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/serving.pyi +0 -0
  151. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/snapshot.py +0 -0
  152. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/snapshot.pyi +0 -0
  153. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/stream_type.py +0 -0
  154. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/token_flow.py +0 -0
  155. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/token_flow.pyi +0 -0
  156. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/volume.py +0 -0
  157. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal/volume.pyi +0 -0
  158. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal.egg-info/SOURCES.txt +0 -0
  159. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal.egg-info/dependency_links.txt +0 -0
  160. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal.egg-info/entry_points.txt +0 -0
  161. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal.egg-info/requires.txt +0 -0
  162. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal.egg-info/top_level.txt +0 -0
  163. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal_docs/__init__.py +0 -0
  164. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal_docs/gen_cli_docs.py +0 -0
  165. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal_docs/gen_reference_docs.py +0 -0
  166. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal_docs/mdmd/__init__.py +0 -0
  167. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal_docs/mdmd/mdmd.py +0 -0
  168. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal_docs/mdmd/signatures.py +0 -0
  169. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal_proto/__init__.py +0 -0
  170. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal_proto/api_grpc.py +0 -0
  171. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal_proto/api_pb2_grpc.py +0 -0
  172. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal_proto/api_pb2_grpc.pyi +0 -0
  173. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal_proto/modal_api_grpc.py +0 -0
  174. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal_proto/modal_options_grpc.py +0 -0
  175. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal_proto/options.proto +0 -0
  176. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal_proto/options_grpc.py +0 -0
  177. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal_proto/options_pb2.py +0 -0
  178. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal_proto/options_pb2.pyi +0 -0
  179. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal_proto/options_pb2_grpc.py +0 -0
  180. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal_proto/options_pb2_grpc.pyi +0 -0
  181. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal_proto/py.typed +0 -0
  182. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/modal_version/__main__.py +0 -0
  183. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/pyproject.toml +0 -0
  184. {modal-1.0.6.dev10 → modal-1.0.6.dev12}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.0.6.dev10
3
+ Version: 1.0.6.dev12
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -40,6 +40,7 @@ from ._utils.async_utils import (
40
40
  synchronizer,
41
41
  warn_if_generator_is_not_consumed,
42
42
  )
43
+ from ._utils.blob_utils import MAX_OBJECT_SIZE_BYTES
43
44
  from ._utils.deprecation import deprecation_warning, warn_if_passing_namespace
44
45
  from ._utils.function_utils import (
45
46
  ATTEMPT_TIMEOUT_GRACE_PERIOD,
@@ -145,6 +146,7 @@ class _Invocation:
145
146
  args,
146
147
  kwargs,
147
148
  stub,
149
+ max_object_size_bytes=function._max_object_size_bytes,
148
150
  method_name=function._use_method_name,
149
151
  function_call_invocation_type=function_call_invocation_type,
150
152
  )
@@ -386,7 +388,13 @@ class _InputPlaneInvocation:
386
388
  function_id = function.object_id
387
389
  control_plane_stub = client.stub
388
390
  # Note: Blob upload is done on the control plane stub, not the input plane stub!
389
- input_item = await _create_input(args, kwargs, control_plane_stub, method_name=function._use_method_name)
391
+ input_item = await _create_input(
392
+ args,
393
+ kwargs,
394
+ control_plane_stub,
395
+ max_object_size_bytes=function._max_object_size_bytes,
396
+ method_name=function._use_method_name,
397
+ )
390
398
 
391
399
  request = api_pb2.AttemptStartRequest(
392
400
  function_id=function_id,
@@ -1414,6 +1422,15 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
1414
1422
  self._definition_id = metadata.definition_id
1415
1423
  self._input_plane_url = metadata.input_plane_url
1416
1424
  self._input_plane_region = metadata.input_plane_region
1425
+ # The server may pass back a larger max object size for some input plane users. This applies to input plane
1426
+ # users only - anyone using the control plane will get the standard limit.
1427
+ # There are some cases like FunctionPrecreate where this value is not set at all. We expect that this field
1428
+ # will eventually be hydrated with the correct value, but just to be defensive, if the field is not set we use
1429
+ # MAX_OBJECT_SIZE_BYTES, otherwise it would get set to 0. Accidentally using 0 would cause us to blob upload
1430
+ # everything, so let's avoid that.
1431
+ self._max_object_size_bytes = (
1432
+ metadata.max_object_size_bytes if metadata.HasField("max_object_size_bytes") else MAX_OBJECT_SIZE_BYTES
1433
+ )
1417
1434
 
1418
1435
  def _get_metadata(self):
1419
1436
  # Overridden concrete implementation of base class method
@@ -1430,6 +1447,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
1430
1447
  function_schema=self._metadata.function_schema if self._metadata else None,
1431
1448
  input_plane_url=self._input_plane_url,
1432
1449
  input_plane_region=self._input_plane_region,
1450
+ max_object_size_bytes=self._max_object_size_bytes,
1433
1451
  )
1434
1452
 
1435
1453
  def _check_no_web_url(self, fn_name: str):
@@ -34,7 +34,6 @@ from ..exception import (
34
34
  from ..mount import ROOT_DIR, _is_modal_path, _Mount
35
35
  from .blob_utils import (
36
36
  MAX_ASYNC_OBJECT_SIZE_BYTES,
37
- MAX_OBJECT_SIZE_BYTES,
38
37
  blob_download,
39
38
  blob_upload_with_r2_failure_info,
40
39
  )
@@ -518,12 +517,13 @@ async def _process_result(result: api_pb2.GenericResult, data_format: int, stub,
518
517
 
519
518
  def should_upload(
520
519
  num_bytes: int,
520
+ max_object_size_bytes: int,
521
521
  function_call_invocation_type: Optional["api_pb2.FunctionCallInvocationType.ValueType"],
522
522
  ) -> bool:
523
523
  """
524
524
  Determine if the input should be uploaded to blob storage.
525
525
  """
526
- return num_bytes > MAX_OBJECT_SIZE_BYTES or (
526
+ return num_bytes > max_object_size_bytes or (
527
527
  function_call_invocation_type == api_pb2.FUNCTION_CALL_INVOCATION_TYPE_ASYNC
528
528
  and num_bytes > MAX_ASYNC_OBJECT_SIZE_BYTES
529
529
  )
@@ -534,6 +534,7 @@ async def _create_input(
534
534
  kwargs,
535
535
  stub: ModalClientModal,
536
536
  *,
537
+ max_object_size_bytes: int,
537
538
  idx: Optional[int] = None,
538
539
  method_name: Optional[str] = None,
539
540
  function_call_invocation_type: Optional["api_pb2.FunctionCallInvocationType.ValueType"] = None,
@@ -548,7 +549,7 @@ async def _create_input(
548
549
 
549
550
  args_serialized = serialize((args, kwargs))
550
551
 
551
- if should_upload(len(args_serialized), function_call_invocation_type):
552
+ if should_upload(len(args_serialized), max_object_size_bytes, function_call_invocation_type):
552
553
  args_blob_id, r2_failed, r2_latency_ms = await blob_upload_with_r2_failure_info(args_serialized, stub)
553
554
  return api_pb2.FunctionPutInputsItem(
554
555
  input=api_pb2.FunctionInput(
@@ -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.6.dev10",
34
+ version: str = "1.0.6.dev12",
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.6.dev10",
163
+ version: str = "1.0.6.dev12",
164
164
  ):
165
165
  """mdmd:hidden
166
166
  The Modal client object is not intended to be instantiated directly by users.
@@ -1222,6 +1222,114 @@ class _Image(_Object, type_prefix="im"):
1222
1222
  gpu_config=parse_gpu_config(gpu),
1223
1223
  )
1224
1224
 
1225
+ def uv_pip_install(
1226
+ self,
1227
+ *packages: Union[str, list[str]], # A list of Python packages, eg. ["numpy", "matplotlib>=3.5.0"]
1228
+ requirements: Optional[list[str]] = None, # Passes -r (--requirements) to uv pip install
1229
+ find_links: Optional[str] = None, # Passes -f (--find-links) to uv pip install
1230
+ index_url: Optional[str] = None, # Passes -i (--index-url) to uv pip install
1231
+ extra_index_url: Optional[str] = None, # Passes --extra-index-url to uv pip install
1232
+ pre: bool = False, # Allow pre-releases using uv pip install --prerelease allow
1233
+ extra_options: str = "", # Additional options to pass to pip install, e.g. "--no-build-isolation"
1234
+ force_build: bool = False, # Ignore cached builds, similar to 'docker build --no-cache'
1235
+ uv_version: Optional[str] = None, # uv version to use
1236
+ secrets: Sequence[_Secret] = [],
1237
+ gpu: GPU_T = None,
1238
+ ) -> "_Image":
1239
+ """Install a list of Python packages using uv pip install.
1240
+
1241
+ **Examples**
1242
+
1243
+ Simple installation:
1244
+ ```python
1245
+ image = modal.Image.debian_slim().uv_pip_install("torch==2.7.1", "numpy")
1246
+ ```
1247
+
1248
+ This method assumes that:
1249
+ - Python is on the `$PATH` and dependencies are installed with the first Python on the `$PATH`.
1250
+ - Shell supports backticks for substitution
1251
+ - `which` command is on the `$PATH`
1252
+ """
1253
+ pkgs = _flatten_str_args("uv_pip_install", "packages", packages)
1254
+
1255
+ if requirements is None or isinstance(requirements, list):
1256
+ requirements = requirements or []
1257
+ else:
1258
+ raise InvalidError("requirements must be None or a list of strings")
1259
+
1260
+ if not pkgs and not requirements:
1261
+ return self
1262
+ elif not _validate_packages(pkgs):
1263
+ raise InvalidError(
1264
+ "Package list for `Image.uv_pip_install` cannot contain other arguments;"
1265
+ " try the `extra_options` parameter instead."
1266
+ )
1267
+
1268
+ def build_dockerfile(version: ImageBuilderVersion) -> DockerfileSpec:
1269
+ commands = ["FROM base"]
1270
+ UV_ROOT = "/.uv"
1271
+ if uv_version is None:
1272
+ commands.append(f"COPY --from=ghcr.io/astral-sh/uv:latest /uv {UV_ROOT}/uv")
1273
+ else:
1274
+ commands.append(f"COPY --from=ghcr.io/astral-sh/uv:{uv_version} /uv {UV_ROOT}/uv")
1275
+
1276
+ # NOTE: Using `which python` assumes:
1277
+ # - python is on the PATH and uv is installing into the first python in the PATH
1278
+ # - the shell supports backticks for substitution
1279
+ # - `which` command is on the PATH
1280
+ uv_pip_args = ["--python `which python`", "--compile-bytecode"]
1281
+ context_files = {}
1282
+
1283
+ if find_links:
1284
+ uv_pip_args.append(f"--find-links {shlex.quote(find_links)}")
1285
+ if index_url:
1286
+ uv_pip_args.append(f"--index-url {shlex.quote(index_url)}")
1287
+ if extra_index_url:
1288
+ uv_pip_args.append(f"--extra-index-url {shlex.quote(extra_index_url)}")
1289
+ if pre:
1290
+ uv_pip_args.append("--prerelease allow")
1291
+ if extra_options:
1292
+ uv_pip_args.append(extra_options)
1293
+
1294
+ if requirements:
1295
+
1296
+ def _generate_paths(idx: int, req: str) -> dict:
1297
+ local_path = os.path.expanduser(req)
1298
+ basename = os.path.basename(req)
1299
+
1300
+ # The requirement files can have the same name but in different directories:
1301
+ # requirements=["test/requirements.txt", "a/b/c/requirements.txt"]
1302
+ # To uniquely identify these files, we add a `idx` prefix to every file's basename
1303
+ # - `test/requirements.txt` -> `/.0_requirements.txt` in context -> `/.uv/0/requirements.txt` to uv
1304
+ # - `a/b/c/requirements.txt` -> `/.1_requirements.txt` in context -> `/.uv/1/requirements.txt` to uv
1305
+ return {
1306
+ "local_path": local_path,
1307
+ "context_path": f"/.{idx}_{basename}",
1308
+ "dest_path": f"{UV_ROOT}/{idx}/{basename}",
1309
+ }
1310
+
1311
+ requirement_paths = [_generate_paths(idx, req) for idx, req in enumerate(requirements)]
1312
+ requirements_cli = " ".join(f"--requirements {req['dest_path']}" for req in requirement_paths)
1313
+ uv_pip_args.append(requirements_cli)
1314
+
1315
+ commands.extend([f"COPY {req['context_path']} {req['dest_path']}" for req in requirement_paths])
1316
+ context_files.update({req["context_path"]: req["local_path"] for req in requirement_paths})
1317
+
1318
+ uv_pip_args.extend(shlex.quote(p) for p in sorted(pkgs))
1319
+ uv_pip_args_joined = " ".join(uv_pip_args)
1320
+
1321
+ commands.append(f"RUN {UV_ROOT}/uv pip install {uv_pip_args_joined}")
1322
+
1323
+ return DockerfileSpec(commands=commands, context_files=context_files)
1324
+
1325
+ return _Image._from_args(
1326
+ base_images={"base": self},
1327
+ dockerfile_function=build_dockerfile,
1328
+ force_build=self.force_build or force_build,
1329
+ gpu_config=parse_gpu_config(gpu),
1330
+ secrets=secrets,
1331
+ )
1332
+
1225
1333
  def poetry_install_from_file(
1226
1334
  self,
1227
1335
  poetry_pyproject_toml: str,
@@ -505,6 +505,36 @@ class _Image(modal._object._Object):
505
505
  """
506
506
  ...
507
507
 
508
+ def uv_pip_install(
509
+ self,
510
+ *packages: typing.Union[str, list[str]],
511
+ requirements: typing.Optional[list[str]] = None,
512
+ find_links: typing.Optional[str] = None,
513
+ index_url: typing.Optional[str] = None,
514
+ extra_index_url: typing.Optional[str] = None,
515
+ pre: bool = False,
516
+ extra_options: str = "",
517
+ force_build: bool = False,
518
+ uv_version: typing.Optional[str] = None,
519
+ secrets: collections.abc.Sequence[modal.secret._Secret] = [],
520
+ gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
521
+ ) -> _Image:
522
+ """Install a list of Python packages using uv pip install.
523
+
524
+ **Examples**
525
+
526
+ Simple installation:
527
+ ```python
528
+ image = modal.Image.debian_slim().uv_pip_install("torch==2.7.1", "numpy")
529
+ ```
530
+
531
+ This method assumes that:
532
+ - Python is on the `$PATH` and dependencies are installed with the first Python on the `$PATH`.
533
+ - Shell supports backticks for substitution
534
+ - `which` command is on the `$PATH`
535
+ """
536
+ ...
537
+
508
538
  def poetry_install_from_file(
509
539
  self,
510
540
  poetry_pyproject_toml: str,
@@ -1348,6 +1378,36 @@ class Image(modal.object.Object):
1348
1378
  """
1349
1379
  ...
1350
1380
 
1381
+ def uv_pip_install(
1382
+ self,
1383
+ *packages: typing.Union[str, list[str]],
1384
+ requirements: typing.Optional[list[str]] = None,
1385
+ find_links: typing.Optional[str] = None,
1386
+ index_url: typing.Optional[str] = None,
1387
+ extra_index_url: typing.Optional[str] = None,
1388
+ pre: bool = False,
1389
+ extra_options: str = "",
1390
+ force_build: bool = False,
1391
+ uv_version: typing.Optional[str] = None,
1392
+ secrets: collections.abc.Sequence[modal.secret.Secret] = [],
1393
+ gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
1394
+ ) -> Image:
1395
+ """Install a list of Python packages using uv pip install.
1396
+
1397
+ **Examples**
1398
+
1399
+ Simple installation:
1400
+ ```python
1401
+ image = modal.Image.debian_slim().uv_pip_install("torch==2.7.1", "numpy")
1402
+ ```
1403
+
1404
+ This method assumes that:
1405
+ - Python is on the `$PATH` and dependencies are installed with the first Python on the `$PATH`.
1406
+ - Shell supports backticks for substitution
1407
+ - `which` command is on the `$PATH`
1408
+ """
1409
+ ...
1410
+
1351
1411
  def poetry_install_from_file(
1352
1412
  self,
1353
1413
  poetry_pyproject_toml: str,
@@ -139,7 +139,14 @@ async def _map_invocation(
139
139
  idx = inputs_created
140
140
  update_state(set_inputs_created=inputs_created + 1)
141
141
  (args, kwargs) = argskwargs
142
- return await _create_input(args, kwargs, client.stub, idx=idx, method_name=function._use_method_name)
142
+ return await _create_input(
143
+ args,
144
+ kwargs,
145
+ client.stub,
146
+ max_object_size_bytes=function._max_object_size_bytes,
147
+ idx=idx,
148
+ method_name=function._use_method_name,
149
+ )
143
150
 
144
151
  async def input_iter():
145
152
  while 1:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.0.6.dev10
3
+ Version: 1.0.6.dev12
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -1724,6 +1724,8 @@ message FunctionHandleMetadata {
1724
1724
  FunctionSchema function_schema = 45;
1725
1725
  optional string input_plane_url = 46;
1726
1726
  optional string input_plane_region = 47;
1727
+ // Use optional to ensure unset values default to None instead of 0
1728
+ optional uint64 max_object_size_bytes = 48;
1727
1729
  }
1728
1730
 
1729
1731
  message FunctionInput {