modal 0.62.115__py3-none-any.whl → 0.72.13__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (220) hide show
  1. modal/__init__.py +13 -9
  2. modal/__main__.py +41 -3
  3. modal/_clustered_functions.py +80 -0
  4. modal/_clustered_functions.pyi +22 -0
  5. modal/_container_entrypoint.py +402 -398
  6. modal/_ipython.py +3 -13
  7. modal/_location.py +17 -10
  8. modal/_output.py +243 -99
  9. modal/_pty.py +2 -2
  10. modal/_resolver.py +55 -60
  11. modal/_resources.py +26 -7
  12. modal/_runtime/__init__.py +1 -0
  13. modal/_runtime/asgi.py +519 -0
  14. modal/_runtime/container_io_manager.py +1025 -0
  15. modal/{execution_context.py → _runtime/execution_context.py} +11 -2
  16. modal/_runtime/telemetry.py +169 -0
  17. modal/_runtime/user_code_imports.py +356 -0
  18. modal/_serialization.py +123 -6
  19. modal/_traceback.py +47 -187
  20. modal/_tunnel.py +50 -14
  21. modal/_tunnel.pyi +19 -36
  22. modal/_utils/app_utils.py +3 -17
  23. modal/_utils/async_utils.py +386 -104
  24. modal/_utils/blob_utils.py +157 -186
  25. modal/_utils/bytes_io_segment_payload.py +97 -0
  26. modal/_utils/deprecation.py +89 -0
  27. modal/_utils/docker_utils.py +98 -0
  28. modal/_utils/function_utils.py +299 -98
  29. modal/_utils/grpc_testing.py +47 -34
  30. modal/_utils/grpc_utils.py +54 -21
  31. modal/_utils/hash_utils.py +51 -10
  32. modal/_utils/http_utils.py +39 -9
  33. modal/_utils/logger.py +2 -1
  34. modal/_utils/mount_utils.py +34 -16
  35. modal/_utils/name_utils.py +58 -0
  36. modal/_utils/package_utils.py +14 -1
  37. modal/_utils/pattern_utils.py +205 -0
  38. modal/_utils/rand_pb_testing.py +3 -3
  39. modal/_utils/shell_utils.py +15 -49
  40. modal/_vendor/a2wsgi_wsgi.py +62 -72
  41. modal/_vendor/cloudpickle.py +1 -1
  42. modal/_watcher.py +12 -10
  43. modal/app.py +561 -323
  44. modal/app.pyi +474 -262
  45. modal/call_graph.py +7 -6
  46. modal/cli/_download.py +22 -6
  47. modal/cli/_traceback.py +200 -0
  48. modal/cli/app.py +203 -42
  49. modal/cli/config.py +12 -5
  50. modal/cli/container.py +61 -13
  51. modal/cli/dict.py +128 -0
  52. modal/cli/entry_point.py +26 -13
  53. modal/cli/environment.py +40 -9
  54. modal/cli/import_refs.py +21 -48
  55. modal/cli/launch.py +28 -14
  56. modal/cli/network_file_system.py +57 -21
  57. modal/cli/profile.py +1 -1
  58. modal/cli/programs/run_jupyter.py +34 -9
  59. modal/cli/programs/vscode.py +58 -8
  60. modal/cli/queues.py +131 -0
  61. modal/cli/run.py +199 -96
  62. modal/cli/secret.py +5 -4
  63. modal/cli/token.py +7 -2
  64. modal/cli/utils.py +74 -8
  65. modal/cli/volume.py +97 -56
  66. modal/client.py +248 -144
  67. modal/client.pyi +156 -124
  68. modal/cloud_bucket_mount.py +43 -30
  69. modal/cloud_bucket_mount.pyi +32 -25
  70. modal/cls.py +528 -141
  71. modal/cls.pyi +189 -145
  72. modal/config.py +32 -15
  73. modal/container_process.py +177 -0
  74. modal/container_process.pyi +82 -0
  75. modal/dict.py +50 -54
  76. modal/dict.pyi +120 -164
  77. modal/environments.py +106 -5
  78. modal/environments.pyi +77 -25
  79. modal/exception.py +30 -43
  80. modal/experimental.py +62 -2
  81. modal/file_io.py +537 -0
  82. modal/file_io.pyi +235 -0
  83. modal/file_pattern_matcher.py +196 -0
  84. modal/functions.py +846 -428
  85. modal/functions.pyi +446 -387
  86. modal/gpu.py +57 -44
  87. modal/image.py +943 -417
  88. modal/image.pyi +584 -245
  89. modal/io_streams.py +434 -0
  90. modal/io_streams.pyi +122 -0
  91. modal/mount.py +223 -90
  92. modal/mount.pyi +241 -243
  93. modal/network_file_system.py +85 -86
  94. modal/network_file_system.pyi +151 -110
  95. modal/object.py +66 -36
  96. modal/object.pyi +166 -143
  97. modal/output.py +63 -0
  98. modal/parallel_map.py +73 -47
  99. modal/parallel_map.pyi +51 -63
  100. modal/partial_function.py +272 -107
  101. modal/partial_function.pyi +219 -120
  102. modal/proxy.py +15 -12
  103. modal/proxy.pyi +3 -8
  104. modal/queue.py +96 -72
  105. modal/queue.pyi +210 -135
  106. modal/requirements/2024.04.txt +2 -1
  107. modal/requirements/2024.10.txt +16 -0
  108. modal/requirements/README.md +21 -0
  109. modal/requirements/base-images.json +22 -0
  110. modal/retries.py +45 -4
  111. modal/runner.py +325 -203
  112. modal/runner.pyi +124 -110
  113. modal/running_app.py +27 -4
  114. modal/sandbox.py +509 -231
  115. modal/sandbox.pyi +396 -169
  116. modal/schedule.py +2 -2
  117. modal/scheduler_placement.py +20 -3
  118. modal/secret.py +41 -25
  119. modal/secret.pyi +62 -42
  120. modal/serving.py +39 -49
  121. modal/serving.pyi +37 -43
  122. modal/stream_type.py +15 -0
  123. modal/token_flow.py +5 -3
  124. modal/token_flow.pyi +37 -32
  125. modal/volume.py +123 -137
  126. modal/volume.pyi +228 -221
  127. {modal-0.62.115.dist-info → modal-0.72.13.dist-info}/METADATA +5 -5
  128. modal-0.72.13.dist-info/RECORD +174 -0
  129. {modal-0.62.115.dist-info → modal-0.72.13.dist-info}/top_level.txt +0 -1
  130. modal_docs/gen_reference_docs.py +3 -1
  131. modal_docs/mdmd/mdmd.py +0 -1
  132. modal_docs/mdmd/signatures.py +1 -2
  133. modal_global_objects/images/base_images.py +28 -0
  134. modal_global_objects/mounts/python_standalone.py +2 -2
  135. modal_proto/__init__.py +1 -1
  136. modal_proto/api.proto +1231 -531
  137. modal_proto/api_grpc.py +750 -430
  138. modal_proto/api_pb2.py +2102 -1176
  139. modal_proto/api_pb2.pyi +8859 -0
  140. modal_proto/api_pb2_grpc.py +1329 -675
  141. modal_proto/api_pb2_grpc.pyi +1416 -0
  142. modal_proto/modal_api_grpc.py +149 -0
  143. modal_proto/modal_options_grpc.py +3 -0
  144. modal_proto/options_pb2.pyi +20 -0
  145. modal_proto/options_pb2_grpc.pyi +7 -0
  146. modal_proto/py.typed +0 -0
  147. modal_version/__init__.py +1 -1
  148. modal_version/_version_generated.py +2 -2
  149. modal/_asgi.py +0 -370
  150. modal/_container_exec.py +0 -128
  151. modal/_container_io_manager.py +0 -646
  152. modal/_container_io_manager.pyi +0 -412
  153. modal/_sandbox_shell.py +0 -49
  154. modal/app_utils.py +0 -20
  155. modal/app_utils.pyi +0 -17
  156. modal/execution_context.pyi +0 -37
  157. modal/shared_volume.py +0 -23
  158. modal/shared_volume.pyi +0 -24
  159. modal-0.62.115.dist-info/RECORD +0 -207
  160. modal_global_objects/images/conda.py +0 -15
  161. modal_global_objects/images/debian_slim.py +0 -15
  162. modal_global_objects/images/micromamba.py +0 -15
  163. test/__init__.py +0 -1
  164. test/aio_test.py +0 -12
  165. test/async_utils_test.py +0 -279
  166. test/blob_test.py +0 -67
  167. test/cli_imports_test.py +0 -149
  168. test/cli_test.py +0 -674
  169. test/client_test.py +0 -203
  170. test/cloud_bucket_mount_test.py +0 -22
  171. test/cls_test.py +0 -636
  172. test/config_test.py +0 -149
  173. test/conftest.py +0 -1485
  174. test/container_app_test.py +0 -50
  175. test/container_test.py +0 -1405
  176. test/cpu_test.py +0 -23
  177. test/decorator_test.py +0 -85
  178. test/deprecation_test.py +0 -34
  179. test/dict_test.py +0 -51
  180. test/e2e_test.py +0 -68
  181. test/error_test.py +0 -7
  182. test/function_serialization_test.py +0 -32
  183. test/function_test.py +0 -791
  184. test/function_utils_test.py +0 -101
  185. test/gpu_test.py +0 -159
  186. test/grpc_utils_test.py +0 -82
  187. test/helpers.py +0 -47
  188. test/image_test.py +0 -814
  189. test/live_reload_test.py +0 -80
  190. test/lookup_test.py +0 -70
  191. test/mdmd_test.py +0 -329
  192. test/mount_test.py +0 -162
  193. test/mounted_files_test.py +0 -327
  194. test/network_file_system_test.py +0 -188
  195. test/notebook_test.py +0 -66
  196. test/object_test.py +0 -41
  197. test/package_utils_test.py +0 -25
  198. test/queue_test.py +0 -115
  199. test/resolver_test.py +0 -59
  200. test/retries_test.py +0 -67
  201. test/runner_test.py +0 -85
  202. test/sandbox_test.py +0 -191
  203. test/schedule_test.py +0 -15
  204. test/scheduler_placement_test.py +0 -57
  205. test/secret_test.py +0 -89
  206. test/serialization_test.py +0 -50
  207. test/stub_composition_test.py +0 -10
  208. test/stub_test.py +0 -361
  209. test/test_asgi_wrapper.py +0 -234
  210. test/token_flow_test.py +0 -18
  211. test/traceback_test.py +0 -135
  212. test/tunnel_test.py +0 -29
  213. test/utils_test.py +0 -88
  214. test/version_test.py +0 -14
  215. test/volume_test.py +0 -397
  216. test/watcher_test.py +0 -58
  217. test/webhook_test.py +0 -145
  218. {modal-0.62.115.dist-info → modal-0.72.13.dist-info}/LICENSE +0 -0
  219. {modal-0.62.115.dist-info → modal-0.72.13.dist-info}/WHEEL +0 -0
  220. {modal-0.62.115.dist-info → modal-0.72.13.dist-info}/entry_points.txt +0 -0
test/config_test.py DELETED
@@ -1,149 +0,0 @@
1
- # Copyright Modal Labs 2022
2
- import os
3
- import pathlib
4
- import pytest
5
- import subprocess
6
- import sys
7
-
8
- import toml
9
-
10
- import modal
11
- from modal.config import Config, _lookup_workspace, config
12
-
13
-
14
- def _cli(args, env={}):
15
- lib_dir = pathlib.Path(modal.__file__).parent.parent
16
- args = [sys.executable, "-m", "modal.cli.entry_point"] + args
17
- env = {
18
- **os.environ,
19
- **env,
20
- # For windows
21
- "PYTHONUTF8": "1",
22
- }
23
- ret = subprocess.run(args, cwd=lib_dir, env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
24
- stdout = ret.stdout.decode()
25
- stderr = ret.stderr.decode()
26
- if ret.returncode != 0:
27
- raise Exception(f"Failed with {ret.returncode} stdout: {stdout} stderr: {stderr}")
28
- return stdout
29
-
30
-
31
- def _get_config(env={}):
32
- stdout = _cli(["config", "show"], env=env)
33
- return eval(stdout)
34
-
35
-
36
- def test_config():
37
- config = _get_config()
38
- assert config["server_url"]
39
-
40
-
41
- def test_config_env_override():
42
- config = _get_config(env={"MODAL_SERVER_URL": "xyz.corp"})
43
- assert config["server_url"] == "xyz.corp"
44
-
45
-
46
- def test_config_store_user(servicer, modal_config):
47
- with modal_config(show_on_error=True) as config_file_path:
48
- env = {"MODAL_SERVER_URL": servicer.remote_addr}
49
-
50
- # No token by default
51
- config = _get_config(env=env)
52
- assert config["token_id"] is None
53
-
54
- # Set creds to abc / xyz
55
- _cli(["token", "set", "--token-id", "abc", "--token-secret", "xyz"], env=env)
56
-
57
- # Set creds to foo / bar1 for the prof_1 profile
58
- _cli(
59
- ["token", "set", "--token-id", "foo", "--token-secret", "bar1", "--profile", "prof_1", "--no-activate"],
60
- env=env,
61
- )
62
-
63
- # Set creds to foo / bar2 for the prof_2 profile (given as an env var)
64
- _cli(
65
- ["token", "set", "--token-id", "foo", "--token-secret", "bar2", "--no-activate"],
66
- env={"MODAL_PROFILE": "prof_2", **env},
67
- )
68
-
69
- # Now these should be stored in the user's home directory
70
- config = _get_config(env=env)
71
- assert config["token_id"] == "abc"
72
- assert config["token_secret"] == "xyz"
73
-
74
- # Make sure it can be overridden too
75
- config = _get_config(env={"MODAL_TOKEN_ID": "foo", **env})
76
- assert config["token_id"] == "foo"
77
- assert config["token_secret"] == "xyz"
78
-
79
- # Check that the profile is named after the workspace username by default
80
- config = _get_config(env={"MODAL_PROFILE": "test-username", **env})
81
- assert config["token_id"] == "abc"
82
- assert config["token_secret"] == "xyz"
83
-
84
- # Check that we can get the prof_1 env creds too
85
- config = _get_config(env={"MODAL_PROFILE": "prof_1", **env})
86
- assert config["token_id"] == "foo"
87
- assert config["token_secret"] == "bar1"
88
-
89
- # Check that we can get the prof_2 env creds too
90
- config = _get_config(env={"MODAL_PROFILE": "prof_2", **env})
91
- assert config["token_id"] == "foo"
92
- assert config["token_secret"] == "bar2"
93
-
94
- # Check that an empty string falls back to the active profile
95
- config = _get_config(env={"MODAL_PROFILE": "", **env})
96
- assert config["token_secret"] == "xyz"
97
-
98
- # Test that only the first profile was explicitly activated
99
- for profile, profile_config in toml.load(config_file_path).items():
100
- if profile == "test-username":
101
- assert profile_config["active"] is True
102
- else:
103
- assert "active" not in profile_config
104
-
105
- # Check that we can overwrite the default profile
106
- _cli(["token", "set", "--token-id", "ABC", "--token-secret", "XYZ"], env=env)
107
- assert toml.load(config_file_path)["test-username"]["token_id"] == "ABC"
108
-
109
- # Check that we activate a profile by default while setting a token
110
- _cli(
111
- ["token", "set", "--token-id", "foo", "--token-secret", "bar3", "--profile", "prof_3"],
112
- env=env,
113
- )
114
- for profile, profile_config in toml.load(config_file_path).items():
115
- if profile == "prof_3":
116
- assert profile_config["active"] is True
117
- else:
118
- assert "active" not in profile_config
119
-
120
-
121
- def test_config_env_override_arbitrary_env():
122
- """config.override_locally() replaces existing env var if not part of config."""
123
- key = "NVIDIA_VISIBLE_DEVICES"
124
- value = "0,1"
125
-
126
- # Place old value in memory.
127
- os.environ[key] = "none"
128
-
129
- # Expect value to be overwritten.
130
- config.override_locally(key, value)
131
- assert os.getenv(key) == value
132
-
133
-
134
- @pytest.mark.asyncio
135
- async def test_workspace_lookup(servicer, server_url_env):
136
- resp = await _lookup_workspace(servicer.remote_addr, "ak-abc", "as-xyz")
137
- assert resp.username == "test-username"
138
-
139
-
140
- @pytest.mark.parametrize("automount", ["false", "'false'", "'False'", "'0'", 0, "''"])
141
- def test_config_boolean(modal_config, automount):
142
- modal_toml = f"""
143
- [prof-1]
144
- token_id = 'ak-abc'
145
- token_secret = 'as_xyz'
146
- automount = {automount}
147
- """
148
- with modal_config(modal_toml):
149
- assert not Config().get("automount", "prof-1")