modAL 1.0.0__tar.gz → 1.0.0.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 (183) hide show
  1. {modal-1.0.0 → modal-1.0.0.dev1}/PKG-INFO +1 -1
  2. {modal-1.0.0 → modal-1.0.0.dev1}/modal/__init__.py +4 -10
  3. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_functions.py +90 -15
  4. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_object.py +14 -0
  5. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_partial_function.py +14 -4
  6. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_serialization.py +2 -2
  7. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_utils/function_utils.py +6 -3
  8. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_utils/grpc_utils.py +1 -6
  9. {modal-1.0.0 → modal-1.0.0.dev1}/modal/app.py +104 -1
  10. {modal-1.0.0 → modal-1.0.0.dev1}/modal/app.pyi +127 -0
  11. {modal-1.0.0 → modal-1.0.0.dev1}/modal/cli/app.py +19 -0
  12. {modal-1.0.0 → modal-1.0.0.dev1}/modal/cli/programs/run_jupyter.py +1 -1
  13. {modal-1.0.0 → modal-1.0.0.dev1}/modal/cli/programs/vscode.py +1 -1
  14. {modal-1.0.0 → modal-1.0.0.dev1}/modal/client.pyi +10 -2
  15. {modal-1.0.0 → modal-1.0.0.dev1}/modal/cls.py +14 -9
  16. {modal-1.0.0 → modal-1.0.0.dev1}/modal/cls.pyi +17 -2
  17. {modal-1.0.0 → modal-1.0.0.dev1}/modal/config.py +16 -5
  18. {modal-1.0.0 → modal-1.0.0.dev1}/modal/container_process.py +9 -1
  19. {modal-1.0.0 → modal-1.0.0.dev1}/modal/container_process.pyi +3 -3
  20. {modal-1.0.0 → modal-1.0.0.dev1}/modal/dict.py +5 -3
  21. {modal-1.0.0 → modal-1.0.0.dev1}/modal/environments.py +3 -1
  22. {modal-1.0.0 → modal-1.0.0.dev1}/modal/exception.py +1 -1
  23. {modal-1.0.0 → modal-1.0.0.dev1}/modal/functions.pyi +23 -2
  24. {modal-1.0.0 → modal-1.0.0.dev1}/modal/image.py +36 -12
  25. {modal-1.0.0 → modal-1.0.0.dev1}/modal/image.pyi +5 -2
  26. {modal-1.0.0 → modal-1.0.0.dev1}/modal/mount.py +65 -2
  27. {modal-1.0.0 → modal-1.0.0.dev1}/modal/mount.pyi +1 -0
  28. {modal-1.0.0 → modal-1.0.0.dev1}/modal/network_file_system.py +5 -3
  29. {modal-1.0.0 → modal-1.0.0.dev1}/modal/object.pyi +6 -0
  30. {modal-1.0.0 → modal-1.0.0.dev1}/modal/queue.py +5 -3
  31. {modal-1.0.0 → modal-1.0.0.dev1}/modal/runner.py +19 -2
  32. {modal-1.0.0 → modal-1.0.0.dev1}/modal/runner.pyi +5 -0
  33. {modal-1.0.0 → modal-1.0.0.dev1}/modal/sandbox.py +32 -78
  34. {modal-1.0.0 → modal-1.0.0.dev1}/modal/sandbox.pyi +7 -102
  35. {modal-1.0.0 → modal-1.0.0.dev1}/modal/secret.py +3 -1
  36. {modal-1.0.0 → modal-1.0.0.dev1}/modal/serving.py +6 -0
  37. {modal-1.0.0 → modal-1.0.0.dev1}/modal/serving.pyi +3 -0
  38. {modal-1.0.0 → modal-1.0.0.dev1}/modal/volume.py +17 -8
  39. {modal-1.0.0 → modal-1.0.0.dev1}/modal.egg-info/PKG-INFO +1 -1
  40. {modal-1.0.0 → modal-1.0.0.dev1}/modal_proto/api.proto +2 -29
  41. {modal-1.0.0 → modal-1.0.0.dev1}/modal_proto/api_grpc.py +0 -32
  42. {modal-1.0.0 → modal-1.0.0.dev1}/modal_proto/api_pb2.py +756 -788
  43. {modal-1.0.0 → modal-1.0.0.dev1}/modal_proto/api_pb2.pyi +12 -86
  44. {modal-1.0.0 → modal-1.0.0.dev1}/modal_proto/api_pb2_grpc.py +0 -66
  45. {modal-1.0.0 → modal-1.0.0.dev1}/modal_proto/api_pb2_grpc.pyi +0 -20
  46. {modal-1.0.0 → modal-1.0.0.dev1}/modal_proto/modal_api_grpc.py +0 -2
  47. {modal-1.0.0 → modal-1.0.0.dev1}/modal_version/__init__.py +1 -1
  48. {modal-1.0.0 → modal-1.0.0.dev1}/LICENSE +0 -0
  49. {modal-1.0.0 → modal-1.0.0.dev1}/README.md +0 -0
  50. {modal-1.0.0 → modal-1.0.0.dev1}/modal/__main__.py +0 -0
  51. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_clustered_functions.py +0 -0
  52. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_clustered_functions.pyi +0 -0
  53. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_container_entrypoint.py +0 -0
  54. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_ipython.py +0 -0
  55. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_location.py +0 -0
  56. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_output.py +0 -0
  57. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_pty.py +0 -0
  58. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_resolver.py +0 -0
  59. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_resources.py +0 -0
  60. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_runtime/__init__.py +0 -0
  61. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_runtime/asgi.py +0 -0
  62. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_runtime/container_io_manager.py +0 -0
  63. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_runtime/container_io_manager.pyi +0 -0
  64. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_runtime/execution_context.py +0 -0
  65. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_runtime/execution_context.pyi +0 -0
  66. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_runtime/gpu_memory_snapshot.py +0 -0
  67. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_runtime/telemetry.py +0 -0
  68. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_runtime/user_code_imports.py +0 -0
  69. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_traceback.py +0 -0
  70. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_tunnel.py +0 -0
  71. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_tunnel.pyi +0 -0
  72. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_type_manager.py +0 -0
  73. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_utils/__init__.py +0 -0
  74. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_utils/app_utils.py +0 -0
  75. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_utils/async_utils.py +0 -0
  76. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_utils/blob_utils.py +0 -0
  77. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_utils/bytes_io_segment_payload.py +0 -0
  78. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_utils/deprecation.py +0 -0
  79. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_utils/docker_utils.py +0 -0
  80. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_utils/git_utils.py +0 -0
  81. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_utils/grpc_testing.py +0 -0
  82. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_utils/hash_utils.py +0 -0
  83. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_utils/http_utils.py +0 -0
  84. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_utils/jwt_utils.py +0 -0
  85. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_utils/logger.py +0 -0
  86. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_utils/mount_utils.py +0 -0
  87. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_utils/name_utils.py +0 -0
  88. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_utils/package_utils.py +0 -0
  89. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_utils/pattern_utils.py +0 -0
  90. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_utils/rand_pb_testing.py +0 -0
  91. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_utils/shell_utils.py +0 -0
  92. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_vendor/__init__.py +0 -0
  93. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_vendor/a2wsgi_wsgi.py +0 -0
  94. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_vendor/cloudpickle.py +0 -0
  95. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_vendor/tblib.py +0 -0
  96. {modal-1.0.0 → modal-1.0.0.dev1}/modal/_watcher.py +0 -0
  97. {modal-1.0.0 → modal-1.0.0.dev1}/modal/call_graph.py +0 -0
  98. {modal-1.0.0 → modal-1.0.0.dev1}/modal/cli/__init__.py +0 -0
  99. {modal-1.0.0 → modal-1.0.0.dev1}/modal/cli/_download.py +0 -0
  100. {modal-1.0.0 → modal-1.0.0.dev1}/modal/cli/_traceback.py +0 -0
  101. {modal-1.0.0 → modal-1.0.0.dev1}/modal/cli/cluster.py +0 -0
  102. {modal-1.0.0 → modal-1.0.0.dev1}/modal/cli/config.py +0 -0
  103. {modal-1.0.0 → modal-1.0.0.dev1}/modal/cli/container.py +0 -0
  104. {modal-1.0.0 → modal-1.0.0.dev1}/modal/cli/dict.py +0 -0
  105. {modal-1.0.0 → modal-1.0.0.dev1}/modal/cli/entry_point.py +0 -0
  106. {modal-1.0.0 → modal-1.0.0.dev1}/modal/cli/environment.py +0 -0
  107. {modal-1.0.0 → modal-1.0.0.dev1}/modal/cli/import_refs.py +0 -0
  108. {modal-1.0.0 → modal-1.0.0.dev1}/modal/cli/launch.py +0 -0
  109. {modal-1.0.0 → modal-1.0.0.dev1}/modal/cli/network_file_system.py +0 -0
  110. {modal-1.0.0 → modal-1.0.0.dev1}/modal/cli/profile.py +0 -0
  111. {modal-1.0.0 → modal-1.0.0.dev1}/modal/cli/programs/__init__.py +0 -0
  112. {modal-1.0.0 → modal-1.0.0.dev1}/modal/cli/queues.py +0 -0
  113. {modal-1.0.0 → modal-1.0.0.dev1}/modal/cli/run.py +0 -0
  114. {modal-1.0.0 → modal-1.0.0.dev1}/modal/cli/secret.py +0 -0
  115. {modal-1.0.0 → modal-1.0.0.dev1}/modal/cli/token.py +0 -0
  116. {modal-1.0.0 → modal-1.0.0.dev1}/modal/cli/utils.py +0 -0
  117. {modal-1.0.0 → modal-1.0.0.dev1}/modal/cli/volume.py +0 -0
  118. {modal-1.0.0 → modal-1.0.0.dev1}/modal/client.py +0 -0
  119. {modal-1.0.0 → modal-1.0.0.dev1}/modal/cloud_bucket_mount.py +0 -0
  120. {modal-1.0.0 → modal-1.0.0.dev1}/modal/cloud_bucket_mount.pyi +0 -0
  121. {modal-1.0.0 → modal-1.0.0.dev1}/modal/dict.pyi +0 -0
  122. {modal-1.0.0 → modal-1.0.0.dev1}/modal/environments.pyi +0 -0
  123. {modal-1.0.0 → modal-1.0.0.dev1}/modal/experimental/__init__.py +0 -0
  124. {modal-1.0.0 → modal-1.0.0.dev1}/modal/experimental/ipython.py +0 -0
  125. {modal-1.0.0 → modal-1.0.0.dev1}/modal/file_io.py +0 -0
  126. {modal-1.0.0 → modal-1.0.0.dev1}/modal/file_io.pyi +0 -0
  127. {modal-1.0.0 → modal-1.0.0.dev1}/modal/file_pattern_matcher.py +0 -0
  128. {modal-1.0.0 → modal-1.0.0.dev1}/modal/functions.py +0 -0
  129. {modal-1.0.0 → modal-1.0.0.dev1}/modal/gpu.py +0 -0
  130. {modal-1.0.0 → modal-1.0.0.dev1}/modal/io_streams.py +0 -0
  131. {modal-1.0.0 → modal-1.0.0.dev1}/modal/io_streams.pyi +0 -0
  132. {modal-1.0.0 → modal-1.0.0.dev1}/modal/network_file_system.pyi +0 -0
  133. {modal-1.0.0 → modal-1.0.0.dev1}/modal/object.py +0 -0
  134. {modal-1.0.0 → modal-1.0.0.dev1}/modal/output.py +0 -0
  135. {modal-1.0.0 → modal-1.0.0.dev1}/modal/parallel_map.py +0 -0
  136. {modal-1.0.0 → modal-1.0.0.dev1}/modal/parallel_map.pyi +0 -0
  137. {modal-1.0.0 → modal-1.0.0.dev1}/modal/partial_function.py +0 -0
  138. {modal-1.0.0 → modal-1.0.0.dev1}/modal/partial_function.pyi +0 -0
  139. {modal-1.0.0 → modal-1.0.0.dev1}/modal/proxy.py +0 -0
  140. {modal-1.0.0 → modal-1.0.0.dev1}/modal/proxy.pyi +0 -0
  141. {modal-1.0.0 → modal-1.0.0.dev1}/modal/py.typed +0 -0
  142. {modal-1.0.0 → modal-1.0.0.dev1}/modal/queue.pyi +0 -0
  143. {modal-1.0.0 → modal-1.0.0.dev1}/modal/requirements/2023.12.312.txt +0 -0
  144. {modal-1.0.0 → modal-1.0.0.dev1}/modal/requirements/2023.12.txt +0 -0
  145. {modal-1.0.0 → modal-1.0.0.dev1}/modal/requirements/2024.04.txt +0 -0
  146. {modal-1.0.0 → modal-1.0.0.dev1}/modal/requirements/2024.10.txt +0 -0
  147. {modal-1.0.0 → modal-1.0.0.dev1}/modal/requirements/PREVIEW.txt +0 -0
  148. {modal-1.0.0 → modal-1.0.0.dev1}/modal/requirements/README.md +0 -0
  149. {modal-1.0.0 → modal-1.0.0.dev1}/modal/requirements/base-images.json +0 -0
  150. {modal-1.0.0 → modal-1.0.0.dev1}/modal/retries.py +0 -0
  151. {modal-1.0.0 → modal-1.0.0.dev1}/modal/running_app.py +0 -0
  152. {modal-1.0.0 → modal-1.0.0.dev1}/modal/schedule.py +0 -0
  153. {modal-1.0.0 → modal-1.0.0.dev1}/modal/scheduler_placement.py +0 -0
  154. {modal-1.0.0 → modal-1.0.0.dev1}/modal/secret.pyi +0 -0
  155. {modal-1.0.0 → modal-1.0.0.dev1}/modal/snapshot.py +0 -0
  156. {modal-1.0.0 → modal-1.0.0.dev1}/modal/snapshot.pyi +0 -0
  157. {modal-1.0.0 → modal-1.0.0.dev1}/modal/stream_type.py +0 -0
  158. {modal-1.0.0 → modal-1.0.0.dev1}/modal/token_flow.py +0 -0
  159. {modal-1.0.0 → modal-1.0.0.dev1}/modal/token_flow.pyi +0 -0
  160. {modal-1.0.0 → modal-1.0.0.dev1}/modal/volume.pyi +0 -0
  161. {modal-1.0.0 → modal-1.0.0.dev1}/modal.egg-info/SOURCES.txt +0 -0
  162. {modal-1.0.0 → modal-1.0.0.dev1}/modal.egg-info/dependency_links.txt +0 -0
  163. {modal-1.0.0 → modal-1.0.0.dev1}/modal.egg-info/entry_points.txt +0 -0
  164. {modal-1.0.0 → modal-1.0.0.dev1}/modal.egg-info/requires.txt +0 -0
  165. {modal-1.0.0 → modal-1.0.0.dev1}/modal.egg-info/top_level.txt +0 -0
  166. {modal-1.0.0 → modal-1.0.0.dev1}/modal_docs/__init__.py +0 -0
  167. {modal-1.0.0 → modal-1.0.0.dev1}/modal_docs/gen_cli_docs.py +0 -0
  168. {modal-1.0.0 → modal-1.0.0.dev1}/modal_docs/gen_reference_docs.py +0 -0
  169. {modal-1.0.0 → modal-1.0.0.dev1}/modal_docs/mdmd/__init__.py +0 -0
  170. {modal-1.0.0 → modal-1.0.0.dev1}/modal_docs/mdmd/mdmd.py +0 -0
  171. {modal-1.0.0 → modal-1.0.0.dev1}/modal_docs/mdmd/signatures.py +0 -0
  172. {modal-1.0.0 → modal-1.0.0.dev1}/modal_proto/__init__.py +0 -0
  173. {modal-1.0.0 → modal-1.0.0.dev1}/modal_proto/modal_options_grpc.py +0 -0
  174. {modal-1.0.0 → modal-1.0.0.dev1}/modal_proto/options.proto +0 -0
  175. {modal-1.0.0 → modal-1.0.0.dev1}/modal_proto/options_grpc.py +0 -0
  176. {modal-1.0.0 → modal-1.0.0.dev1}/modal_proto/options_pb2.py +0 -0
  177. {modal-1.0.0 → modal-1.0.0.dev1}/modal_proto/options_pb2.pyi +0 -0
  178. {modal-1.0.0 → modal-1.0.0.dev1}/modal_proto/options_pb2_grpc.py +0 -0
  179. {modal-1.0.0 → modal-1.0.0.dev1}/modal_proto/options_pb2_grpc.pyi +0 -0
  180. {modal-1.0.0 → modal-1.0.0.dev1}/modal_proto/py.typed +0 -0
  181. {modal-1.0.0 → modal-1.0.0.dev1}/modal_version/__main__.py +0 -0
  182. {modal-1.0.0 → modal-1.0.0.dev1}/pyproject.toml +0 -0
  183. {modal-1.0.0 → modal-1.0.0.dev1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.0.0
3
+ Version: 1.0.0.dev1
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -11,7 +11,7 @@ from modal_version import __version__
11
11
  try:
12
12
  from ._runtime.execution_context import current_function_call_id, current_input_id, interact, is_local
13
13
  from ._tunnel import Tunnel, forward
14
- from .app import App
14
+ from .app import App, Stub
15
15
  from .client import Client
16
16
  from .cloud_bucket_mount import CloudBucketMount
17
17
  from .cls import Cls, parameter
@@ -20,6 +20,7 @@ try:
20
20
  from .file_pattern_matcher import FilePatternMatcher
21
21
  from .functions import Function, FunctionCall
22
22
  from .image import Image
23
+ from .mount import Mount
23
24
  from .network_file_system import NetworkFileSystem
24
25
  from .output import enable_output
25
26
  from .partial_function import (
@@ -53,7 +54,6 @@ except Exception:
53
54
  print()
54
55
  raise
55
56
 
56
-
57
57
  __all__ = [
58
58
  "__version__",
59
59
  "App",
@@ -66,6 +66,7 @@ __all__ = [
66
66
  "Function",
67
67
  "FunctionCall",
68
68
  "Image",
69
+ "Mount",
69
70
  "NetworkFileSystem",
70
71
  "Period",
71
72
  "Proxy",
@@ -76,6 +77,7 @@ __all__ = [
76
77
  "SandboxSnapshot",
77
78
  "SchedulerPlacement",
78
79
  "Secret",
80
+ "Stub",
79
81
  "Tunnel",
80
82
  "Volume",
81
83
  "asgi_app",
@@ -97,11 +99,3 @@ __all__ = [
97
99
  "web_server",
98
100
  "wsgi_app",
99
101
  ]
100
-
101
-
102
- def __getattr__(name):
103
- if name == "Stub":
104
- raise AttributeError(
105
- "Module 'modal' has no attribute 'Stub'. Use `modal.App` instead. This is a simple name change."
106
- )
107
- raise AttributeError(f"module 'modal' has no attribute '{name}'")
@@ -6,7 +6,7 @@ import textwrap
6
6
  import time
7
7
  import typing
8
8
  import warnings
9
- from collections.abc import AsyncGenerator, Sequence, Sized
9
+ from collections.abc import AsyncGenerator, Collection, Sequence, Sized
10
10
  from dataclasses import dataclass
11
11
  from pathlib import PurePosixPath
12
12
  from typing import TYPE_CHECKING, Any, Callable, Optional, Union
@@ -41,7 +41,7 @@ from ._utils.async_utils import (
41
41
  synchronizer,
42
42
  warn_if_generator_is_not_consumed,
43
43
  )
44
- from ._utils.deprecation import deprecation_warning
44
+ from ._utils.deprecation import deprecation_error, deprecation_warning, renamed_parameter
45
45
  from ._utils.function_utils import (
46
46
  ATTEMPT_TIMEOUT_GRACE_PERIOD,
47
47
  OUTPUTS_TIMEOUT,
@@ -71,7 +71,7 @@ from .exception import (
71
71
  )
72
72
  from .gpu import GPU_T, parse_gpu_config
73
73
  from .image import _Image
74
- from .mount import _get_client_mount, _Mount
74
+ from .mount import _get_client_mount, _Mount, get_sys_modules_mounts
75
75
  from .network_file_system import _NetworkFileSystem, network_file_system_mount_protos
76
76
  from .output import _get_output_manager
77
77
  from .parallel_map import (
@@ -405,6 +405,12 @@ class FunctionStats:
405
405
  backlog: int
406
406
  num_total_runners: int
407
407
 
408
+ def __getattr__(self, name):
409
+ if name == "num_active_runners":
410
+ msg = "'FunctionStats.num_active_runners' is no longer available."
411
+ deprecation_error((2024, 6, 14), msg)
412
+ raise AttributeError(f"'FunctionStats' object has no attribute '{name}'")
413
+
408
414
 
409
415
  def _parse_retries(
410
416
  retries: Optional[Union[int, Retries]],
@@ -505,6 +511,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
505
511
  is_generator: bool = False,
506
512
  gpu: Union[GPU_T, list[GPU_T]] = None,
507
513
  # TODO: maybe break this out into a separate decorator for notebooks.
514
+ mounts: Collection[_Mount] = (),
508
515
  network_file_systems: dict[Union[str, PurePosixPath], _NetworkFileSystem] = {},
509
516
  volumes: dict[Union[str, PurePosixPath], Union[_Volume, _CloudBucketMount]] = {},
510
517
  webhook_config: Optional[api_pb2.WebhookConfig] = None,
@@ -560,6 +567,8 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
560
567
  assert not webhook_config
561
568
  assert not schedule
562
569
 
570
+ explicit_mounts = mounts
571
+
563
572
  include_source_mode = get_include_source_mode(include_source)
564
573
  if include_source_mode != IncludeSourceMode.INCLUDE_NOTHING:
565
574
  entrypoint_mounts = info.get_entrypoint_mount()
@@ -568,9 +577,34 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
568
577
 
569
578
  all_mounts = [
570
579
  _get_client_mount(),
580
+ *explicit_mounts,
571
581
  *entrypoint_mounts.values(),
572
582
  ]
573
583
 
584
+ if include_source_mode is IncludeSourceMode.INCLUDE_FIRST_PARTY and is_local():
585
+ auto_mounts = get_sys_modules_mounts()
586
+ # don't need to add entrypoint modules to automounts:
587
+ for entrypoint_module in entrypoint_mounts:
588
+ auto_mounts.pop(entrypoint_module, None)
589
+
590
+ warn_missing_modules = set(auto_mounts.keys()) - image._added_python_source_set
591
+
592
+ if warn_missing_modules:
593
+ python_stringified_modules = ", ".join(f'"{mod}"' for mod in sorted(warn_missing_modules))
594
+ deprecation_warning(
595
+ (2025, 2, 3),
596
+ (
597
+ 'Modal will stop implicitly adding local Python modules to the Image ("automounting") in a '
598
+ "future update. The following modules need to be explicitly added for future "
599
+ "compatibility:\n"
600
+ )
601
+ + "\n".join(sorted([f"* {m}" for m in warn_missing_modules]))
602
+ + "\n\n"
603
+ + (f"e.g.:\nimage_with_source = my_image.add_local_python_source({python_stringified_modules})\n\n")
604
+ + "For more information, see https://modal.com/docs/guide/modal-1-0-migration",
605
+ )
606
+ all_mounts += auto_mounts.values()
607
+
574
608
  retry_policy = _parse_retries(
575
609
  retries, f"Function '{info.get_tag()}'" if info.raw_f else f"Class '{info.get_tag()}'"
576
610
  )
@@ -607,6 +641,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
607
641
  image=image,
608
642
  secrets=secrets,
609
643
  gpu=gpu,
644
+ mounts=mounts,
610
645
  network_file_systems=network_file_systems,
611
646
  volumes=volumes,
612
647
  memory=memory,
@@ -714,7 +749,16 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
714
749
 
715
750
  def _deps(only_explicit_mounts=False) -> list[_Object]:
716
751
  deps: list[_Object] = list(secrets)
717
- if not only_explicit_mounts:
752
+ if only_explicit_mounts:
753
+ # TODO: this is a bit hacky, but all_mounts may differ in the container vs locally
754
+ # We don't want the function dependencies to change, so we have this way to force it to
755
+ # only include its declared dependencies.
756
+ # Only objects that need interaction within a user's container actually need to be
757
+ # included when only_explicit_mounts=True, so omitting auto mounts here
758
+ # wouldn't be a problem as long as Mounts are "passive" and only loaded by the
759
+ # worker runtime
760
+ deps += list(explicit_mounts)
761
+ else:
718
762
  deps += list(all_mounts)
719
763
  if proxy:
720
764
  deps.append(proxy)
@@ -982,6 +1026,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
982
1026
  obj._build_args = dict( # See get_build_def
983
1027
  secrets=repr(secrets),
984
1028
  gpu_config=repr([parse_gpu_config(_gpu) for _gpu in gpus]),
1029
+ mounts=repr(mounts),
985
1030
  network_file_systems=repr(network_file_systems),
986
1031
  )
987
1032
  # these key are excluded if empty to avoid rebuilds on client upgrade
@@ -1145,8 +1190,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
1145
1190
 
1146
1191
  @live_method
1147
1192
  async def keep_warm(self, warm_pool_size: int) -> None:
1148
- """mdmd:hidden
1149
- Set the warm pool size for the Function.
1193
+ """Set the warm pool size for the Function.
1150
1194
 
1151
1195
  DEPRECATED: Please adapt your code to use the more general `update_autoscaler` method instead:
1152
1196
 
@@ -1211,6 +1255,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
1211
1255
  return cls._from_loader(_load_remote, rep, is_another_app=True, hydrate_lazily=True)
1212
1256
 
1213
1257
  @classmethod
1258
+ @renamed_parameter((2024, 12, 18), "tag", "name")
1214
1259
  def from_name(
1215
1260
  cls: type["_Function"],
1216
1261
  app_name: str,
@@ -1243,6 +1288,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
1243
1288
  return cls._from_name(app_name, name, namespace, environment_name)
1244
1289
 
1245
1290
  @staticmethod
1291
+ @renamed_parameter((2024, 12, 18), "tag", "name")
1246
1292
  async def lookup(
1247
1293
  app_name: str,
1248
1294
  name: str,
@@ -1250,8 +1296,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
1250
1296
  client: Optional[_Client] = None,
1251
1297
  environment_name: Optional[str] = None,
1252
1298
  ) -> "_Function":
1253
- """mdmd:hidden
1254
- Lookup a Function from a deployed App by its name.
1299
+ """Lookup a Function from a deployed App by its name.
1255
1300
 
1256
1301
  DEPRECATED: This method is deprecated in favor of `modal.Function.from_name`.
1257
1302
 
@@ -1375,8 +1420,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
1375
1420
  @property
1376
1421
  @live_method
1377
1422
  async def web_url(self) -> Optional[str]:
1378
- """mdmd:hidden
1379
- Deprecated. Use the `Function.get_web_url()` method instead.
1423
+ """Deprecated. Use the `Function.get_web_url()` method instead.
1380
1424
 
1381
1425
  URL of a Function running as a web endpoint.
1382
1426
  """
@@ -1493,6 +1537,20 @@ Use the `Function.get_web_url()` method instead.
1493
1537
  async for res in invocation.run_generator():
1494
1538
  yield res
1495
1539
 
1540
+ @synchronizer.no_io_translation
1541
+ async def _call_generator_nowait(self, args, kwargs):
1542
+ deprecation_warning(
1543
+ (2024, 12, 11),
1544
+ "Calling spawn on a generator function is deprecated and will soon raise an exception.",
1545
+ )
1546
+ return await _Invocation.create(
1547
+ self,
1548
+ args,
1549
+ kwargs,
1550
+ client=self.client,
1551
+ function_call_invocation_type=api_pb2.FUNCTION_CALL_INVOCATION_TYPE_ASYNC,
1552
+ )
1553
+
1496
1554
  @synchronizer.no_io_translation
1497
1555
  @live_method
1498
1556
  async def remote(self, *args: P.args, **kwargs: P.kwargs) -> ReturnType:
@@ -1605,7 +1663,7 @@ Use the `Function.get_web_url()` method instead.
1605
1663
  """
1606
1664
  self._check_no_web_url("_experimental_spawn")
1607
1665
  if self._is_generator:
1608
- raise InvalidError("Cannot `spawn` a generator function.")
1666
+ invocation = await self._call_generator_nowait(args, kwargs)
1609
1667
  else:
1610
1668
  invocation = await self._call_function_nowait(
1611
1669
  args, kwargs, function_call_invocation_type=api_pb2.FUNCTION_CALL_INVOCATION_TYPE_ASYNC
@@ -1637,13 +1695,14 @@ Use the `Function.get_web_url()` method instead.
1637
1695
  """
1638
1696
  self._check_no_web_url("spawn")
1639
1697
  if self._is_generator:
1640
- raise InvalidError("Cannot `spawn` a generator function.")
1698
+ invocation = await self._call_generator_nowait(args, kwargs)
1641
1699
  else:
1642
1700
  invocation = await self._call_function_nowait(args, kwargs, api_pb2.FUNCTION_CALL_INVOCATION_TYPE_ASYNC)
1643
1701
 
1644
1702
  fc: _FunctionCall[ReturnType] = _FunctionCall._new_hydrated(
1645
1703
  invocation.function_call_id, invocation.client, None
1646
1704
  )
1705
+ fc._is_generator = self._is_generator if self._is_generator else False
1647
1706
  return fc
1648
1707
 
1649
1708
  def get_raw_f(self) -> Callable[..., Any]:
@@ -1702,8 +1761,22 @@ class _FunctionCall(typing.Generic[ReturnType], _Object, type_prefix="fc"):
1702
1761
 
1703
1762
  The returned coroutine is not cancellation-safe.
1704
1763
  """
1764
+
1765
+ if self._is_generator:
1766
+ raise Exception("Cannot get the result of a generator function call. Use `get_gen` instead.")
1767
+
1705
1768
  return await self._invocation().poll_function(timeout=timeout)
1706
1769
 
1770
+ async def get_gen(self) -> AsyncGenerator[Any, None]:
1771
+ """
1772
+ Calls the generator remotely, executing it with the given arguments and returning the execution's result.
1773
+ """
1774
+ if not self._is_generator:
1775
+ raise Exception("Cannot iterate over a non-generator function call. Use `get` instead.")
1776
+
1777
+ async for res in self._invocation().run_generator():
1778
+ yield res
1779
+
1707
1780
  async def get_call_graph(self) -> list[InputInfo]:
1708
1781
  """Returns a structure representing the call graph from a given root
1709
1782
  call ID, along with the status of execution for each node.
@@ -1734,7 +1807,9 @@ class _FunctionCall(typing.Generic[ReturnType], _Object, type_prefix="fc"):
1734
1807
  await retry_transient_errors(self._client.stub.FunctionCallCancel, request)
1735
1808
 
1736
1809
  @staticmethod
1737
- async def from_id(function_call_id: str, client: Optional[_Client] = None) -> "_FunctionCall[Any]":
1810
+ async def from_id(
1811
+ function_call_id: str, client: Optional[_Client] = None, is_generator: bool = False
1812
+ ) -> "_FunctionCall[Any]":
1738
1813
  """Instantiate a FunctionCall object from an existing ID.
1739
1814
 
1740
1815
  Examples:
@@ -1757,6 +1832,7 @@ class _FunctionCall(typing.Generic[ReturnType], _Object, type_prefix="fc"):
1757
1832
  client = await _Client.from_env()
1758
1833
 
1759
1834
  fc: _FunctionCall[Any] = _FunctionCall._new_hydrated(function_call_id, client, None)
1835
+ fc._is_generator = is_generator
1760
1836
  return fc
1761
1837
 
1762
1838
  @staticmethod
@@ -1787,8 +1863,7 @@ class _FunctionCall(typing.Generic[ReturnType], _Object, type_prefix="fc"):
1787
1863
 
1788
1864
 
1789
1865
  async def _gather(*function_calls: _FunctionCall[T]) -> typing.Sequence[T]:
1790
- """mdmd:hidden
1791
- Deprecated: Please use `modal.FunctionCall.gather()` instead."""
1866
+ """Deprecated: Please use `modal.FunctionCall.gather()` instead."""
1792
1867
  deprecation_warning(
1793
1868
  (2025, 2, 24),
1794
1869
  "`modal.functions.gather()` is deprecated; please use `modal.FunctionCall.gather()` instead.",
@@ -10,6 +10,7 @@ from typing_extensions import Self
10
10
 
11
11
  from ._resolver import Resolver
12
12
  from ._utils.async_utils import aclosing
13
+ from ._utils.deprecation import deprecation_warning
13
14
  from .client import _Client
14
15
  from .config import config, logger
15
16
  from .exception import ExecutionError, InvalidError
@@ -236,6 +237,19 @@ class _Object:
236
237
 
237
238
  return self._deps if self._deps is not None else default_deps
238
239
 
240
+ async def resolve(self, client: Optional[_Client] = None):
241
+ """mdmd:hidden"""
242
+ obj = self.__class__.__name__.strip("_")
243
+ deprecation_warning(
244
+ (2025, 1, 16),
245
+ f"The `{obj}.resolve` method is deprecated and will be removed in a future release."
246
+ f" Please use `{obj}.hydrate()` or `await {obj}.hydrate.aio()` instead."
247
+ "\n\nNote that it is rarely necessary to explicitly hydrate objects, as most methods"
248
+ " will lazily hydrate when needed.",
249
+ show_source=False, # synchronicity interferes with attributing source correctly
250
+ )
251
+ await self.hydrate(client)
252
+
239
253
  async def hydrate(self, client: Optional[_Client] = None) -> Self:
240
254
  """Synchronize the local object with its identity on the Modal server.
241
255
 
@@ -18,7 +18,7 @@ from modal_proto import api_pb2
18
18
  from ._functions import _Function
19
19
  from ._utils.async_utils import synchronizer
20
20
  from ._utils.deprecation import deprecation_warning
21
- from ._utils.function_utils import callable_has_non_self_params
21
+ from ._utils.function_utils import callable_has_non_self_non_default_params, callable_has_non_self_params
22
22
  from .config import logger
23
23
  from .exception import InvalidError
24
24
 
@@ -181,11 +181,21 @@ class _PartialFunction(typing.Generic[P, ReturnType, OriginalReturnType]):
181
181
 
182
182
  if require_sync and inspect.iscoroutinefunction(self.raw_f):
183
183
  self.registered = True # Hacky, avoid false-positive warning
184
- raise InvalidError(f"The `@modal.{decorator_name}` decorator can't be applied to an async function.")
184
+ raise InvalidError(f"`@modal.{decorator_name}` can't be applied to an async function.")
185
185
 
186
186
  if require_nullary and callable_has_non_self_params(self.raw_f):
187
187
  self.registered = True # Hacky, avoid false-positive warning
188
- raise InvalidError(f"Functions decorated by `@modal.{decorator_name}` can't have parameters.")
188
+ if callable_has_non_self_non_default_params(self.raw_f):
189
+ raise InvalidError(f"Functions obj by `@modal.{decorator_name}` can't have parameters.")
190
+ else:
191
+ # TODO(michael): probably fine to just make this an error at this point
192
+ # but best to do it in a separate PR
193
+ deprecation_warning(
194
+ (2024, 9, 4),
195
+ f"The function obj by `@modal.{decorator_name}` has default parameters, "
196
+ "but shouldn't have any parameters - Modal will drop support for "
197
+ "default parameters in a future release.",
198
+ )
189
199
 
190
200
  def _get_raw_f(self) -> Callable[P, ReturnType]:
191
201
  assert self.raw_f is not None
@@ -649,7 +659,7 @@ def _web_server(
649
659
  def _build(
650
660
  _warn_parentheses_missing=None, *, force: bool = False, timeout: int = 86400
651
661
  ) -> Callable[[Union[_PartialFunction, NullaryMethod]], _PartialFunction]:
652
- """mdmd:hidden
662
+ """
653
663
  Decorator for methods that execute at _build time_ to create a new Image layer.
654
664
 
655
665
  **Deprecated**: This function is deprecated. We recommend using `modal.Volume`
@@ -324,8 +324,8 @@ def _deserialize_asgi(asgi: api_pb2.Asgi) -> Any:
324
324
  elif msg_type == "websocket_send":
325
325
  return {
326
326
  "type": "websocket.send",
327
- **({"bytes": asgi.websocket_send.bytes} if asgi.websocket_send.HasField("bytes") else {}),
328
- **({"text": asgi.websocket_send.text} if asgi.websocket_send.HasField("text") else {}),
327
+ "bytes": asgi.websocket_send.bytes if asgi.websocket_send.HasField("bytes") else None,
328
+ "text": asgi.websocket_send.text if asgi.websocket_send.HasField("text") else None,
329
329
  }
330
330
  elif msg_type == "websocket_disconnect":
331
331
  return {
@@ -23,7 +23,7 @@ from .._serialization import (
23
23
  signature_to_parameter_specs,
24
24
  )
25
25
  from .._traceback import append_modal_tb
26
- from ..config import logger
26
+ from ..config import config, logger
27
27
  from ..exception import (
28
28
  DeserializationError,
29
29
  ExecutionError,
@@ -627,7 +627,8 @@ class FunctionCreationStatus:
627
627
 
628
628
  class IncludeSourceMode(enum.Enum):
629
629
  INCLUDE_NOTHING = False # can only be set in source, can't be set in config
630
- INCLUDE_MAIN_PACKAGE = True # Default behavior
630
+ INCLUDE_MAIN_PACKAGE = True # also represented by AUTOMOUNT=0 in config
631
+ INCLUDE_FIRST_PARTY = "legacy" # mounts all "local" modules in sys.modules - represented by AUTOMOUNT=1 in config
631
632
 
632
633
 
633
634
  def get_include_source_mode(function_or_app_specific) -> IncludeSourceMode:
@@ -649,4 +650,6 @@ def get_include_source_mode(function_or_app_specific) -> IncludeSourceMode:
649
650
  # explicitly set in app/function
650
651
  return IncludeSourceMode(function_or_app_specific)
651
652
 
652
- return IncludeSourceMode.INCLUDE_MAIN_PACKAGE
653
+ # note that the automount config boolean isn't a 1-1 mapping with include_source!
654
+ legacy_automount_mode: bool = config.get("automount")
655
+ return IncludeSourceMode.INCLUDE_FIRST_PARTY if legacy_automount_mode else IncludeSourceMode.INCLUDE_MAIN_PACKAGE
@@ -148,20 +148,15 @@ def create_channel(
148
148
 
149
149
  logger.debug(f"Sending request to {event.method_name}")
150
150
 
151
- async def recv_initial_metadata(initial_metadata: grpclib.events.RecvInitialMetadata) -> None:
151
+ async def recv_trailing_metadata(trailing_metadata: grpclib.events.RecvTrailingMetadata) -> None:
152
152
  # If we receive an auth token from the server, include it in all future requests.
153
153
  # TODO(nathan): This isn't perfect because the metadata isn't propagated when the
154
154
  # process is forked and a new channel is created. This is OK for now since this
155
155
  # token is only used by the experimental input plane
156
- if token := initial_metadata.metadata.get("x-modal-auth-token"):
157
- metadata["x-modal-auth-token"] = str(token)
158
-
159
- async def recv_trailing_metadata(trailing_metadata: grpclib.events.RecvTrailingMetadata) -> None:
160
156
  if token := trailing_metadata.metadata.get("x-modal-auth-token"):
161
157
  metadata["x-modal-auth-token"] = str(token)
162
158
 
163
159
  grpclib.events.listen(channel, grpclib.events.SendRequest, send_request)
164
- grpclib.events.listen(channel, grpclib.events.RecvInitialMetadata, recv_initial_metadata)
165
160
  grpclib.events.listen(channel, grpclib.events.RecvTrailingMetadata, recv_trailing_metadata)
166
161
 
167
162
  return channel