modal 1.0.5.dev9__tar.gz → 1.0.5.dev10__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.dev9 → modal-1.0.5.dev10}/PKG-INFO +1 -1
  2. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/client.pyi +2 -2
  3. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/experimental/__init__.py +71 -0
  4. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal.egg-info/PKG-INFO +1 -1
  5. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal_proto/api.proto +20 -0
  6. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal_proto/api_grpc.py +32 -0
  7. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal_proto/api_pb2.py +617 -587
  8. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal_proto/api_pb2.pyi +54 -0
  9. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal_proto/api_pb2_grpc.py +67 -0
  10. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal_proto/api_pb2_grpc.pyi +22 -0
  11. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal_proto/modal_api_grpc.py +2 -0
  12. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal_version/__init__.py +1 -1
  13. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/LICENSE +0 -0
  14. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/README.md +0 -0
  15. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/__init__.py +0 -0
  16. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/__main__.py +0 -0
  17. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_clustered_functions.py +0 -0
  18. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_clustered_functions.pyi +0 -0
  19. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_container_entrypoint.py +0 -0
  20. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_functions.py +0 -0
  21. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_ipython.py +0 -0
  22. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_location.py +0 -0
  23. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_object.py +0 -0
  24. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_output.py +0 -0
  25. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_partial_function.py +0 -0
  26. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_pty.py +0 -0
  27. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_resolver.py +0 -0
  28. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_resources.py +0 -0
  29. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_runtime/__init__.py +0 -0
  30. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_runtime/asgi.py +0 -0
  31. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_runtime/container_io_manager.py +0 -0
  32. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_runtime/container_io_manager.pyi +0 -0
  33. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_runtime/execution_context.py +0 -0
  34. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_runtime/execution_context.pyi +0 -0
  35. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_runtime/gpu_memory_snapshot.py +0 -0
  36. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_runtime/telemetry.py +0 -0
  37. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_runtime/user_code_imports.py +0 -0
  38. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_serialization.py +0 -0
  39. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_traceback.py +0 -0
  40. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_tunnel.py +0 -0
  41. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_tunnel.pyi +0 -0
  42. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_type_manager.py +0 -0
  43. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_utils/__init__.py +0 -0
  44. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_utils/app_utils.py +0 -0
  45. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_utils/async_utils.py +0 -0
  46. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_utils/blob_utils.py +0 -0
  47. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_utils/bytes_io_segment_payload.py +0 -0
  48. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_utils/deprecation.py +0 -0
  49. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_utils/docker_utils.py +0 -0
  50. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_utils/function_utils.py +0 -0
  51. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_utils/git_utils.py +0 -0
  52. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_utils/grpc_testing.py +0 -0
  53. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_utils/grpc_utils.py +0 -0
  54. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_utils/hash_utils.py +0 -0
  55. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_utils/http_utils.py +0 -0
  56. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_utils/jwt_utils.py +0 -0
  57. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_utils/logger.py +0 -0
  58. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_utils/mount_utils.py +0 -0
  59. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_utils/name_utils.py +0 -0
  60. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_utils/package_utils.py +0 -0
  61. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_utils/pattern_utils.py +0 -0
  62. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_utils/rand_pb_testing.py +0 -0
  63. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_utils/shell_utils.py +0 -0
  64. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_utils/time_utils.py +0 -0
  65. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_vendor/__init__.py +0 -0
  66. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_vendor/a2wsgi_wsgi.py +0 -0
  67. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_vendor/cloudpickle.py +0 -0
  68. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_vendor/tblib.py +0 -0
  69. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/_watcher.py +0 -0
  70. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/app.py +0 -0
  71. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/app.pyi +0 -0
  72. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/call_graph.py +0 -0
  73. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/cli/__init__.py +0 -0
  74. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/cli/_download.py +0 -0
  75. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/cli/_traceback.py +0 -0
  76. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/cli/app.py +0 -0
  77. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/cli/cluster.py +0 -0
  78. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/cli/config.py +0 -0
  79. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/cli/container.py +0 -0
  80. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/cli/dict.py +0 -0
  81. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/cli/entry_point.py +0 -0
  82. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/cli/environment.py +0 -0
  83. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/cli/import_refs.py +0 -0
  84. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/cli/launch.py +0 -0
  85. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/cli/network_file_system.py +0 -0
  86. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/cli/profile.py +0 -0
  87. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/cli/programs/__init__.py +0 -0
  88. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/cli/programs/run_jupyter.py +0 -0
  89. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/cli/programs/vscode.py +0 -0
  90. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/cli/queues.py +0 -0
  91. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/cli/run.py +0 -0
  92. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/cli/secret.py +0 -0
  93. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/cli/token.py +0 -0
  94. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/cli/utils.py +0 -0
  95. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/cli/volume.py +0 -0
  96. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/client.py +0 -0
  97. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/cloud_bucket_mount.py +0 -0
  98. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/cloud_bucket_mount.pyi +0 -0
  99. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/cls.py +0 -0
  100. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/cls.pyi +0 -0
  101. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/config.py +0 -0
  102. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/container_process.py +0 -0
  103. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/container_process.pyi +0 -0
  104. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/dict.py +0 -0
  105. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/dict.pyi +0 -0
  106. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/environments.py +0 -0
  107. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/environments.pyi +0 -0
  108. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/exception.py +0 -0
  109. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/experimental/ipython.py +0 -0
  110. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/file_io.py +0 -0
  111. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/file_io.pyi +0 -0
  112. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/file_pattern_matcher.py +0 -0
  113. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/functions.py +0 -0
  114. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/functions.pyi +0 -0
  115. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/gpu.py +0 -0
  116. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/image.py +0 -0
  117. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/image.pyi +0 -0
  118. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/io_streams.py +0 -0
  119. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/io_streams.pyi +0 -0
  120. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/mount.py +0 -0
  121. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/mount.pyi +0 -0
  122. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/network_file_system.py +0 -0
  123. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/network_file_system.pyi +0 -0
  124. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/object.py +0 -0
  125. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/object.pyi +0 -0
  126. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/output.py +0 -0
  127. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/parallel_map.py +0 -0
  128. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/parallel_map.pyi +0 -0
  129. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/partial_function.py +0 -0
  130. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/partial_function.pyi +0 -0
  131. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/proxy.py +0 -0
  132. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/proxy.pyi +0 -0
  133. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/py.typed +0 -0
  134. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/queue.py +0 -0
  135. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/queue.pyi +0 -0
  136. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/requirements/2023.12.312.txt +0 -0
  137. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/requirements/2023.12.txt +0 -0
  138. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/requirements/2024.04.txt +0 -0
  139. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/requirements/2024.10.txt +0 -0
  140. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/requirements/PREVIEW.txt +0 -0
  141. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/requirements/README.md +0 -0
  142. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/requirements/base-images.json +0 -0
  143. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/retries.py +0 -0
  144. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/runner.py +0 -0
  145. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/runner.pyi +0 -0
  146. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/running_app.py +0 -0
  147. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/sandbox.py +0 -0
  148. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/sandbox.pyi +0 -0
  149. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/schedule.py +0 -0
  150. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/scheduler_placement.py +0 -0
  151. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/secret.py +0 -0
  152. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/secret.pyi +0 -0
  153. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/serving.py +0 -0
  154. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/serving.pyi +0 -0
  155. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/snapshot.py +0 -0
  156. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/snapshot.pyi +0 -0
  157. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/stream_type.py +0 -0
  158. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/token_flow.py +0 -0
  159. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/token_flow.pyi +0 -0
  160. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/volume.py +0 -0
  161. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal/volume.pyi +0 -0
  162. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal.egg-info/SOURCES.txt +0 -0
  163. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal.egg-info/dependency_links.txt +0 -0
  164. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal.egg-info/entry_points.txt +0 -0
  165. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal.egg-info/requires.txt +0 -0
  166. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal.egg-info/top_level.txt +0 -0
  167. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal_docs/__init__.py +0 -0
  168. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal_docs/gen_cli_docs.py +0 -0
  169. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal_docs/gen_reference_docs.py +0 -0
  170. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal_docs/mdmd/__init__.py +0 -0
  171. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal_docs/mdmd/mdmd.py +0 -0
  172. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal_docs/mdmd/signatures.py +0 -0
  173. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal_proto/__init__.py +0 -0
  174. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal_proto/modal_options_grpc.py +0 -0
  175. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal_proto/options.proto +0 -0
  176. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal_proto/options_grpc.py +0 -0
  177. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal_proto/options_pb2.py +0 -0
  178. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal_proto/options_pb2.pyi +0 -0
  179. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal_proto/options_pb2_grpc.py +0 -0
  180. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal_proto/options_pb2_grpc.pyi +0 -0
  181. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal_proto/py.typed +0 -0
  182. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/modal_version/__main__.py +0 -0
  183. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/pyproject.toml +0 -0
  184. {modal-1.0.5.dev9 → modal-1.0.5.dev10}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.0.5.dev9
3
+ Version: 1.0.5.dev10
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -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.dev9",
34
+ version: str = "1.0.5.dev10",
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.dev9",
163
+ version: str = "1.0.5.dev10",
164
164
  ):
165
165
  """mdmd:hidden
166
166
  The Modal client object is not intended to be instantiated directly by users.
@@ -1,5 +1,7 @@
1
1
  # Copyright Modal Labs 2025
2
+ import asyncio
2
3
  import os
4
+ import sys
3
5
  from dataclasses import dataclass
4
6
  from pathlib import Path
5
7
  from typing import Literal, Optional, Union
@@ -11,11 +13,13 @@ from .._functions import _Function
11
13
  from .._object import _get_environment_name
12
14
  from .._partial_function import _clustered
13
15
  from .._runtime.container_io_manager import _ContainerIOManager
16
+ from .._tunnel import _forward as _forward_tunnel
14
17
  from .._utils.async_utils import synchronize_api, synchronizer
15
18
  from .._utils.deprecation import deprecation_warning
16
19
  from .._utils.grpc_utils import retry_transient_errors
17
20
  from ..client import _Client
18
21
  from ..cls import _Obj
22
+ from ..config import logger
19
23
  from ..exception import InvalidError
20
24
  from ..image import DockerfileSpec, ImageBuilderVersion, _Image, _ImageRegistryConfig
21
25
  from ..secret import _Secret
@@ -209,3 +213,70 @@ async def update_autoscaler(
209
213
 
210
214
  request = api_pb2.FunctionUpdateSchedulingParamsRequest(function_id=f.object_id, settings=settings)
211
215
  await retry_transient_errors(client.stub.FunctionUpdateSchedulingParams, request)
216
+
217
+
218
+ class _FlashManager:
219
+ def __init__(self, client: _Client, port: int):
220
+ self.client = client
221
+ self.port = port
222
+ self.tunnel_manager = _forward_tunnel(port, client=client)
223
+
224
+ async def _start(self):
225
+ tunnel = await self.tunnel_manager.__aenter__()
226
+
227
+ host, port = tunnel.url.split("://")[1].split(":")
228
+ self.heartbeat_task = asyncio.create_task(self._run_heartbeat(host, int(port)))
229
+
230
+ async def _run_heartbeat(self, host: str, port: int):
231
+ first_registration = True
232
+ while True:
233
+ try:
234
+ resp = await self.client.stub.FlashContainerRegister(
235
+ api_pb2.FlashContainerRegisterRequest(
236
+ priority=10,
237
+ weight=5,
238
+ host=host,
239
+ port=port,
240
+ ),
241
+ timeout=1,
242
+ )
243
+ if first_registration:
244
+ logger.warning(f"[Modal Flash] Listening at {resp.url}")
245
+ first_registration = False
246
+ except asyncio.CancelledError:
247
+ logger.warning("[Modal Flash] Shutting down...")
248
+ break
249
+ except Exception as e:
250
+ logger.error(f"[Modal Flash] Heartbeat failed: {e}")
251
+
252
+ try:
253
+ await asyncio.sleep(1)
254
+ except asyncio.CancelledError:
255
+ logger.warning("[Modal Flash] Shutting down...")
256
+ break
257
+
258
+ async def stop(self):
259
+ self.heartbeat_task.cancel()
260
+ await retry_transient_errors(
261
+ self.client.stub.FlashContainerDeregister,
262
+ api_pb2.FlashContainerDeregisterRequest(),
263
+ )
264
+ await self.tunnel_manager.__aexit__(*sys.exc_info())
265
+
266
+
267
+ FlashManager = synchronize_api(_FlashManager)
268
+
269
+
270
+ @synchronizer.create_blocking
271
+ async def flash_forward(port: int) -> _FlashManager:
272
+ """
273
+ Forward a port to the Modal Flash service, exposing that port as a stable web endpoint.
274
+
275
+ This is a highly experimental method that can break or be removed at any time without warning.
276
+ Do not use this method unless explicitly instructed to do so by Modal support.
277
+ """
278
+ client = await _Client.from_env()
279
+
280
+ manager = _FlashManager(client, port)
281
+ await manager._start()
282
+ return manager
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.0.5.dev9
3
+ Version: 1.0.5.dev10
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -1242,6 +1242,22 @@ message FilesystemRuntimeOutputBatch {
1242
1242
  bool eof = 4;
1243
1243
  }
1244
1244
 
1245
+ message FlashContainerDeregisterRequest {
1246
+ string service_name = 1;
1247
+ }
1248
+
1249
+ message FlashContainerRegisterRequest {
1250
+ string service_name = 1;
1251
+ uint32 priority = 2;
1252
+ uint32 weight = 3;
1253
+ string host = 4;
1254
+ uint32 port = 5;
1255
+ }
1256
+
1257
+ message FlashContainerRegisterResponse {
1258
+ string url = 1;
1259
+ }
1260
+
1245
1261
  message Function {
1246
1262
  string module_name = 1;
1247
1263
  string function_name = 2;
@@ -3268,6 +3284,10 @@ service ModalClient {
3268
3284
  rpc EnvironmentList(google.protobuf.Empty) returns (EnvironmentListResponse);
3269
3285
  rpc EnvironmentUpdate(EnvironmentUpdateRequest) returns (EnvironmentListItem);
3270
3286
 
3287
+ // Modal Flash (experimental)
3288
+ rpc FlashContainerDeregister(FlashContainerDeregisterRequest) returns (google.protobuf.Empty);
3289
+ rpc FlashContainerRegister(FlashContainerRegisterRequest) returns (FlashContainerRegisterResponse);
3290
+
3271
3291
  // Functions
3272
3292
  rpc FunctionAsyncInvoke(FunctionAsyncInvokeRequest) returns (FunctionAsyncInvokeResponse);
3273
3293
  rpc FunctionBindParams(FunctionBindParamsRequest) returns (FunctionBindParamsResponse);
@@ -242,6 +242,14 @@ class ModalClientBase(abc.ABC):
242
242
  async def EnvironmentUpdate(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.EnvironmentUpdateRequest, modal_proto.api_pb2.EnvironmentListItem]') -> None:
243
243
  pass
244
244
 
245
+ @abc.abstractmethod
246
+ async def FlashContainerDeregister(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.FlashContainerDeregisterRequest, google.protobuf.empty_pb2.Empty]') -> None:
247
+ pass
248
+
249
+ @abc.abstractmethod
250
+ async def FlashContainerRegister(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.FlashContainerRegisterRequest, modal_proto.api_pb2.FlashContainerRegisterResponse]') -> None:
251
+ pass
252
+
245
253
  @abc.abstractmethod
246
254
  async def FunctionAsyncInvoke(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.FunctionAsyncInvokeRequest, modal_proto.api_pb2.FunctionAsyncInvokeResponse]') -> None:
247
255
  pass
@@ -968,6 +976,18 @@ class ModalClientBase(abc.ABC):
968
976
  modal_proto.api_pb2.EnvironmentUpdateRequest,
969
977
  modal_proto.api_pb2.EnvironmentListItem,
970
978
  ),
979
+ '/modal.client.ModalClient/FlashContainerDeregister': grpclib.const.Handler(
980
+ self.FlashContainerDeregister,
981
+ grpclib.const.Cardinality.UNARY_UNARY,
982
+ modal_proto.api_pb2.FlashContainerDeregisterRequest,
983
+ google.protobuf.empty_pb2.Empty,
984
+ ),
985
+ '/modal.client.ModalClient/FlashContainerRegister': grpclib.const.Handler(
986
+ self.FlashContainerRegister,
987
+ grpclib.const.Cardinality.UNARY_UNARY,
988
+ modal_proto.api_pb2.FlashContainerRegisterRequest,
989
+ modal_proto.api_pb2.FlashContainerRegisterResponse,
990
+ ),
971
991
  '/modal.client.ModalClient/FunctionAsyncInvoke': grpclib.const.Handler(
972
992
  self.FunctionAsyncInvoke,
973
993
  grpclib.const.Cardinality.UNARY_UNARY,
@@ -1892,6 +1912,18 @@ class ModalClientStub:
1892
1912
  modal_proto.api_pb2.EnvironmentUpdateRequest,
1893
1913
  modal_proto.api_pb2.EnvironmentListItem,
1894
1914
  )
1915
+ self.FlashContainerDeregister = grpclib.client.UnaryUnaryMethod(
1916
+ channel,
1917
+ '/modal.client.ModalClient/FlashContainerDeregister',
1918
+ modal_proto.api_pb2.FlashContainerDeregisterRequest,
1919
+ google.protobuf.empty_pb2.Empty,
1920
+ )
1921
+ self.FlashContainerRegister = grpclib.client.UnaryUnaryMethod(
1922
+ channel,
1923
+ '/modal.client.ModalClient/FlashContainerRegister',
1924
+ modal_proto.api_pb2.FlashContainerRegisterRequest,
1925
+ modal_proto.api_pb2.FlashContainerRegisterResponse,
1926
+ )
1895
1927
  self.FunctionAsyncInvoke = grpclib.client.UnaryUnaryMethod(
1896
1928
  channel,
1897
1929
  '/modal.client.ModalClient/FunctionAsyncInvoke',