modal 1.0.2.dev7__tar.gz → 1.0.3.dev1__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.2.dev7 → modal-1.0.3.dev1}/PKG-INFO +1 -1
  2. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_utils/bytes_io_segment_payload.py +17 -3
  3. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/client.pyi +2 -2
  4. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/sandbox.py +2 -3
  5. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/sandbox.pyi +6 -6
  6. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/schedule.py +17 -4
  7. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal.egg-info/PKG-INFO +1 -1
  8. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal_version/__init__.py +1 -1
  9. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/LICENSE +0 -0
  10. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/README.md +0 -0
  11. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/__init__.py +0 -0
  12. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/__main__.py +0 -0
  13. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_clustered_functions.py +0 -0
  14. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_clustered_functions.pyi +0 -0
  15. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_container_entrypoint.py +0 -0
  16. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_functions.py +0 -0
  17. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_ipython.py +0 -0
  18. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_location.py +0 -0
  19. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_object.py +0 -0
  20. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_output.py +0 -0
  21. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_partial_function.py +0 -0
  22. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_pty.py +0 -0
  23. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_resolver.py +0 -0
  24. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_resources.py +0 -0
  25. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_runtime/__init__.py +0 -0
  26. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_runtime/asgi.py +0 -0
  27. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_runtime/container_io_manager.py +0 -0
  28. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_runtime/container_io_manager.pyi +0 -0
  29. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_runtime/execution_context.py +0 -0
  30. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_runtime/execution_context.pyi +0 -0
  31. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_runtime/gpu_memory_snapshot.py +0 -0
  32. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_runtime/telemetry.py +0 -0
  33. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_runtime/user_code_imports.py +0 -0
  34. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_serialization.py +0 -0
  35. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_traceback.py +0 -0
  36. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_tunnel.py +0 -0
  37. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_tunnel.pyi +0 -0
  38. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_type_manager.py +0 -0
  39. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_utils/__init__.py +0 -0
  40. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_utils/app_utils.py +0 -0
  41. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_utils/async_utils.py +0 -0
  42. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_utils/blob_utils.py +0 -0
  43. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_utils/deprecation.py +0 -0
  44. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_utils/docker_utils.py +0 -0
  45. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_utils/function_utils.py +0 -0
  46. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_utils/git_utils.py +0 -0
  47. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_utils/grpc_testing.py +0 -0
  48. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_utils/grpc_utils.py +0 -0
  49. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_utils/hash_utils.py +0 -0
  50. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_utils/http_utils.py +0 -0
  51. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_utils/jwt_utils.py +0 -0
  52. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_utils/logger.py +0 -0
  53. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_utils/mount_utils.py +0 -0
  54. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_utils/name_utils.py +0 -0
  55. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_utils/package_utils.py +0 -0
  56. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_utils/pattern_utils.py +0 -0
  57. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_utils/rand_pb_testing.py +0 -0
  58. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_utils/shell_utils.py +0 -0
  59. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_utils/time_utils.py +0 -0
  60. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_vendor/__init__.py +0 -0
  61. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_vendor/a2wsgi_wsgi.py +0 -0
  62. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_vendor/cloudpickle.py +0 -0
  63. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_vendor/tblib.py +0 -0
  64. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/_watcher.py +0 -0
  65. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/app.py +0 -0
  66. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/app.pyi +0 -0
  67. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/call_graph.py +0 -0
  68. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/cli/__init__.py +0 -0
  69. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/cli/_download.py +0 -0
  70. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/cli/_traceback.py +0 -0
  71. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/cli/app.py +0 -0
  72. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/cli/cluster.py +0 -0
  73. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/cli/config.py +0 -0
  74. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/cli/container.py +0 -0
  75. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/cli/dict.py +0 -0
  76. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/cli/entry_point.py +0 -0
  77. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/cli/environment.py +0 -0
  78. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/cli/import_refs.py +0 -0
  79. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/cli/launch.py +0 -0
  80. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/cli/network_file_system.py +0 -0
  81. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/cli/profile.py +0 -0
  82. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/cli/programs/__init__.py +0 -0
  83. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/cli/programs/run_jupyter.py +0 -0
  84. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/cli/programs/vscode.py +0 -0
  85. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/cli/queues.py +0 -0
  86. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/cli/run.py +0 -0
  87. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/cli/secret.py +0 -0
  88. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/cli/token.py +0 -0
  89. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/cli/utils.py +0 -0
  90. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/cli/volume.py +0 -0
  91. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/client.py +0 -0
  92. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/cloud_bucket_mount.py +0 -0
  93. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/cloud_bucket_mount.pyi +0 -0
  94. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/cls.py +0 -0
  95. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/cls.pyi +0 -0
  96. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/config.py +0 -0
  97. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/container_process.py +0 -0
  98. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/container_process.pyi +0 -0
  99. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/dict.py +0 -0
  100. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/dict.pyi +0 -0
  101. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/environments.py +0 -0
  102. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/environments.pyi +0 -0
  103. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/exception.py +0 -0
  104. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/experimental/__init__.py +0 -0
  105. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/experimental/ipython.py +0 -0
  106. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/file_io.py +0 -0
  107. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/file_io.pyi +0 -0
  108. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/file_pattern_matcher.py +0 -0
  109. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/functions.py +0 -0
  110. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/functions.pyi +0 -0
  111. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/gpu.py +0 -0
  112. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/image.py +0 -0
  113. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/image.pyi +0 -0
  114. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/io_streams.py +0 -0
  115. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/io_streams.pyi +0 -0
  116. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/mount.py +0 -0
  117. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/mount.pyi +0 -0
  118. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/network_file_system.py +0 -0
  119. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/network_file_system.pyi +0 -0
  120. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/object.py +0 -0
  121. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/object.pyi +0 -0
  122. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/output.py +0 -0
  123. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/parallel_map.py +0 -0
  124. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/parallel_map.pyi +0 -0
  125. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/partial_function.py +0 -0
  126. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/partial_function.pyi +0 -0
  127. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/proxy.py +0 -0
  128. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/proxy.pyi +0 -0
  129. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/py.typed +0 -0
  130. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/queue.py +0 -0
  131. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/queue.pyi +0 -0
  132. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/requirements/2023.12.312.txt +0 -0
  133. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/requirements/2023.12.txt +0 -0
  134. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/requirements/2024.04.txt +0 -0
  135. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/requirements/2024.10.txt +0 -0
  136. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/requirements/PREVIEW.txt +0 -0
  137. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/requirements/README.md +0 -0
  138. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/requirements/base-images.json +0 -0
  139. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/retries.py +0 -0
  140. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/runner.py +0 -0
  141. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/runner.pyi +0 -0
  142. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/running_app.py +0 -0
  143. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/scheduler_placement.py +0 -0
  144. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/secret.py +0 -0
  145. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/secret.pyi +0 -0
  146. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/serving.py +0 -0
  147. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/serving.pyi +0 -0
  148. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/snapshot.py +0 -0
  149. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/snapshot.pyi +0 -0
  150. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/stream_type.py +0 -0
  151. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/token_flow.py +0 -0
  152. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/token_flow.pyi +0 -0
  153. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/volume.py +0 -0
  154. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal/volume.pyi +0 -0
  155. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal.egg-info/SOURCES.txt +0 -0
  156. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal.egg-info/dependency_links.txt +0 -0
  157. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal.egg-info/entry_points.txt +0 -0
  158. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal.egg-info/requires.txt +0 -0
  159. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal.egg-info/top_level.txt +0 -0
  160. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal_docs/__init__.py +0 -0
  161. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal_docs/gen_cli_docs.py +0 -0
  162. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal_docs/gen_reference_docs.py +0 -0
  163. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal_docs/mdmd/__init__.py +0 -0
  164. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal_docs/mdmd/mdmd.py +0 -0
  165. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal_docs/mdmd/signatures.py +0 -0
  166. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal_proto/__init__.py +0 -0
  167. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal_proto/api.proto +0 -0
  168. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal_proto/api_grpc.py +0 -0
  169. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal_proto/api_pb2.py +0 -0
  170. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal_proto/api_pb2.pyi +0 -0
  171. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal_proto/api_pb2_grpc.py +0 -0
  172. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal_proto/api_pb2_grpc.pyi +0 -0
  173. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal_proto/modal_api_grpc.py +0 -0
  174. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal_proto/modal_options_grpc.py +0 -0
  175. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal_proto/options.proto +0 -0
  176. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal_proto/options_grpc.py +0 -0
  177. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal_proto/options_pb2.py +0 -0
  178. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal_proto/options_pb2.pyi +0 -0
  179. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal_proto/options_pb2_grpc.py +0 -0
  180. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal_proto/options_pb2_grpc.pyi +0 -0
  181. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal_proto/py.typed +0 -0
  182. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/modal_version/__main__.py +0 -0
  183. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/pyproject.toml +0 -0
  184. {modal-1.0.2.dev7 → modal-1.0.3.dev1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.0.2.dev7
3
+ Version: 1.0.3.dev1
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -8,14 +8,14 @@ from typing import BinaryIO, Callable, Optional
8
8
  # Note: this module needs to import aiohttp in global scope
9
9
  # This takes about 50ms and isn't needed in many cases for Modal execution
10
10
  # To avoid this, we import it in local scope when needed (blob_utils.py)
11
- from aiohttp import BytesIOPayload
11
+ from aiohttp import Payload
12
12
  from aiohttp.abc import AbstractStreamWriter
13
13
 
14
14
  # read ~16MiB chunks by default
15
15
  DEFAULT_SEGMENT_CHUNK_SIZE = 2**24
16
16
 
17
17
 
18
- class BytesIOSegmentPayload(BytesIOPayload):
18
+ class BytesIOSegmentPayload(Payload):
19
19
  """Modified bytes payload for concurrent sends of chunks from the same file.
20
20
 
21
21
  Adds:
@@ -26,6 +26,8 @@ class BytesIOSegmentPayload(BytesIOPayload):
26
26
  Feels like this should be in some standard lib...
27
27
  """
28
28
 
29
+ _value: BinaryIO
30
+
29
31
  def __init__(
30
32
  self,
31
33
  bytes_io: BinaryIO, # should *not* be shared as IO position modification is not locked
@@ -36,6 +38,7 @@ class BytesIOSegmentPayload(BytesIOPayload):
36
38
  ):
37
39
  # not thread safe constructor!
38
40
  super().__init__(bytes_io)
41
+ self._size = segment_length
39
42
  self.initial_seek_pos = bytes_io.tell()
40
43
  self.segment_start = segment_start
41
44
  self.segment_length = segment_length
@@ -46,6 +49,10 @@ class BytesIOSegmentPayload(BytesIOPayload):
46
49
  self.progress_report_cb = progress_report_cb or (lambda *_, **__: None)
47
50
  self.reset_state()
48
51
 
52
+ def decode(self, encoding: str = "utf-8", errors: str = "strict") -> str:
53
+ self._value.seek(self.initial_seek_pos)
54
+ return self._value.read().decode(encoding, errors)
55
+
49
56
  def reset_state(self):
50
57
  self._md5_checksum = hashlib.md5()
51
58
  self.num_bytes_read = 0
@@ -76,14 +83,21 @@ class BytesIOSegmentPayload(BytesIOPayload):
76
83
  return self._md5_checksum
77
84
 
78
85
  async def write(self, writer: "AbstractStreamWriter"):
86
+ # On aiohttp < 3.12.0 - this is the method that's being called on a custom payload,
87
+ # but on aiohttp 3.12+ `write_with_length` is called directly.
88
+ await self.write_with_length(writer, None)
89
+
90
+ async def write_with_length(self, writer: AbstractStreamWriter, content_length: Optional[int]):
79
91
  loop = asyncio.get_event_loop()
80
92
 
81
93
  async def safe_read():
82
94
  read_start = self.initial_seek_pos + self.segment_start + self.num_bytes_read
83
95
  self._value.seek(read_start)
84
96
  num_bytes = min(self.chunk_size, self.remaining_bytes())
85
- chunk = await loop.run_in_executor(None, self._value.read, num_bytes)
97
+ if content_length is not None:
98
+ num_bytes = min(num_bytes, content_length)
86
99
 
100
+ chunk = await loop.run_in_executor(None, self._value.read, num_bytes)
87
101
  await loop.run_in_executor(None, self._md5_checksum.update, chunk)
88
102
  self.num_bytes_read += len(chunk)
89
103
  return chunk
@@ -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.2.dev7",
34
+ version: str = "1.0.3.dev1",
35
35
  ): ...
36
36
  def is_closed(self) -> bool: ...
37
37
  @property
@@ -94,7 +94,7 @@ class Client:
94
94
  server_url: str,
95
95
  client_type: int,
96
96
  credentials: typing.Optional[tuple[str, str]],
97
- version: str = "1.0.2.dev7",
97
+ version: str = "1.0.3.dev1",
98
98
  ): ...
99
99
  def is_closed(self) -> bool: ...
100
100
  @property
@@ -517,7 +517,7 @@ class _Sandbox(_Object, type_prefix="sb"):
517
517
 
518
518
  return self._tunnels
519
519
 
520
- async def terminate(self):
520
+ async def terminate(self) -> None:
521
521
  """Terminate Sandbox execution.
522
522
 
523
523
  This is a no-op if the Sandbox has already finished running."""
@@ -525,7 +525,6 @@ class _Sandbox(_Object, type_prefix="sb"):
525
525
  await retry_transient_errors(
526
526
  self._client.stub.SandboxTerminate, api_pb2.SandboxTerminateRequest(sandbox_id=self.object_id)
527
527
  )
528
- await self.wait(raise_on_termination=False)
529
528
 
530
529
  async def poll(self) -> Optional[int]:
531
530
  """Check if the Sandbox has finished running.
@@ -541,7 +540,7 @@ class _Sandbox(_Object, type_prefix="sb"):
541
540
 
542
541
  return self.returncode
543
542
 
544
- async def _get_task_id(self):
543
+ async def _get_task_id(self) -> str:
545
544
  while not self._task_id:
546
545
  resp = await self._client.stub.SandboxGetTaskId(api_pb2.SandboxGetTaskIdRequest(sandbox_id=self.object_id))
547
546
  self._task_id = resp.task_id
@@ -129,9 +129,9 @@ class _Sandbox(modal._object._Object):
129
129
  async def snapshot_filesystem(self, timeout: int = 55) -> modal.image._Image: ...
130
130
  async def wait(self, raise_on_termination: bool = True): ...
131
131
  async def tunnels(self, timeout: int = 50) -> dict[int, modal._tunnel.Tunnel]: ...
132
- async def terminate(self): ...
132
+ async def terminate(self) -> None: ...
133
133
  async def poll(self) -> typing.Optional[int]: ...
134
- async def _get_task_id(self): ...
134
+ async def _get_task_id(self) -> str: ...
135
135
  @typing.overload
136
136
  async def exec(
137
137
  self,
@@ -405,8 +405,8 @@ class Sandbox(modal.object.Object):
405
405
  tunnels: __tunnels_spec[typing_extensions.Self]
406
406
 
407
407
  class __terminate_spec(typing_extensions.Protocol[SUPERSELF]):
408
- def __call__(self, /): ...
409
- async def aio(self, /): ...
408
+ def __call__(self, /) -> None: ...
409
+ async def aio(self, /) -> None: ...
410
410
 
411
411
  terminate: __terminate_spec[typing_extensions.Self]
412
412
 
@@ -417,8 +417,8 @@ class Sandbox(modal.object.Object):
417
417
  poll: __poll_spec[typing_extensions.Self]
418
418
 
419
419
  class ___get_task_id_spec(typing_extensions.Protocol[SUPERSELF]):
420
- def __call__(self, /): ...
421
- async def aio(self, /): ...
420
+ def __call__(self, /) -> str: ...
421
+ async def aio(self, /) -> str: ...
422
422
 
423
423
  _get_task_id: ___get_task_id_spec[typing_extensions.Self]
424
424
 
@@ -30,15 +30,28 @@ class Cron(Schedule):
30
30
  We can specify different schedules with cron strings, for example:
31
31
 
32
32
  ```python
33
- modal.Cron("5 4 * * *") # run at 4:05am every night
34
- modal.Cron("0 9 * * 4") # runs every Thursday 9am
33
+ modal.Cron("5 4 * * *") # run at 4:05am UTC every night
34
+ modal.Cron("0 9 * * 4") # runs every Thursday at 9am UTC
35
35
  ```
36
36
 
37
+ We can also optionally specify a timezone, for example:
38
+
39
+ ```python
40
+ # Run daily at 6am New York time, regardless of whether daylight saving
41
+ # is in effect (i.e. at 11am UTC in the winter, and 10am UTC in the summer):
42
+ modal.Cron("0 6 * * *", timezone="America/New_York")
43
+ ```
44
+
45
+ If no timezone is specified, the default is UTC.
37
46
  """
38
47
 
39
- def __init__(self, cron_string: str) -> None:
48
+ def __init__(
49
+ self,
50
+ cron_string: str,
51
+ timezone: str = "UTC",
52
+ ) -> None:
40
53
  """Construct a schedule that runs according to a cron expression string."""
41
- cron = api_pb2.Schedule.Cron(cron_string=cron_string)
54
+ cron = api_pb2.Schedule.Cron(cron_string=cron_string, timezone=timezone)
42
55
  super().__init__(api_pb2.Schedule(cron=cron))
43
56
 
44
57
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.0.2.dev7
3
+ Version: 1.0.3.dev1
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -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.2.dev7"
4
+ __version__ = "1.0.3.dev1"
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
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