modal 0.77.0__py3-none-any.whl → 1.0.0__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.

Potentially problematic release.


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

Files changed (51) hide show
  1. modal/__init__.py +10 -4
  2. modal/_functions.py +15 -90
  3. modal/_object.py +0 -14
  4. modal/_partial_function.py +4 -14
  5. modal/_serialization.py +2 -2
  6. modal/_utils/function_utils.py +3 -6
  7. modal/_utils/grpc_utils.py +6 -1
  8. modal/app.py +1 -104
  9. modal/app.pyi +0 -127
  10. modal/cli/app.py +0 -19
  11. modal/cli/programs/run_jupyter.py +1 -1
  12. modal/cli/programs/vscode.py +1 -1
  13. modal/client.pyi +2 -2
  14. modal/cls.py +9 -14
  15. modal/cls.pyi +2 -17
  16. modal/config.py +5 -16
  17. modal/container_process.py +1 -9
  18. modal/container_process.pyi +3 -3
  19. modal/dict.py +3 -5
  20. modal/environments.py +1 -3
  21. modal/exception.py +1 -1
  22. modal/functions.pyi +8 -29
  23. modal/image.py +12 -36
  24. modal/image.pyi +2 -5
  25. modal/mount.py +2 -65
  26. modal/mount.pyi +0 -1
  27. modal/network_file_system.py +3 -5
  28. modal/object.pyi +0 -6
  29. modal/queue.py +3 -5
  30. modal/runner.py +2 -19
  31. modal/runner.pyi +0 -5
  32. modal/sandbox.py +78 -32
  33. modal/sandbox.pyi +102 -7
  34. modal/secret.py +1 -3
  35. modal/serving.py +0 -6
  36. modal/serving.pyi +0 -3
  37. modal/volume.py +8 -17
  38. {modal-0.77.0.dist-info → modal-1.0.0.dist-info}/METADATA +1 -1
  39. {modal-0.77.0.dist-info → modal-1.0.0.dist-info}/RECORD +51 -51
  40. modal_proto/api.proto +29 -1
  41. modal_proto/api_grpc.py +32 -0
  42. modal_proto/api_pb2.py +788 -756
  43. modal_proto/api_pb2.pyi +86 -9
  44. modal_proto/api_pb2_grpc.py +66 -0
  45. modal_proto/api_pb2_grpc.pyi +20 -0
  46. modal_proto/modal_api_grpc.py +2 -0
  47. modal_version/__init__.py +1 -1
  48. {modal-0.77.0.dist-info → modal-1.0.0.dist-info}/WHEEL +0 -0
  49. {modal-0.77.0.dist-info → modal-1.0.0.dist-info}/entry_points.txt +0 -0
  50. {modal-0.77.0.dist-info → modal-1.0.0.dist-info}/licenses/LICENSE +0 -0
  51. {modal-0.77.0.dist-info → modal-1.0.0.dist-info}/top_level.txt +0 -0
modal/__init__.py CHANGED
@@ -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, Stub
14
+ from .app import App
15
15
  from .client import Client
16
16
  from .cloud_bucket_mount import CloudBucketMount
17
17
  from .cls import Cls, parameter
@@ -20,7 +20,6 @@ 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
24
23
  from .network_file_system import NetworkFileSystem
25
24
  from .output import enable_output
26
25
  from .partial_function import (
@@ -54,6 +53,7 @@ except Exception:
54
53
  print()
55
54
  raise
56
55
 
56
+
57
57
  __all__ = [
58
58
  "__version__",
59
59
  "App",
@@ -66,7 +66,6 @@ __all__ = [
66
66
  "Function",
67
67
  "FunctionCall",
68
68
  "Image",
69
- "Mount",
70
69
  "NetworkFileSystem",
71
70
  "Period",
72
71
  "Proxy",
@@ -77,7 +76,6 @@ __all__ = [
77
76
  "SandboxSnapshot",
78
77
  "SchedulerPlacement",
79
78
  "Secret",
80
- "Stub",
81
79
  "Tunnel",
82
80
  "Volume",
83
81
  "asgi_app",
@@ -99,3 +97,11 @@ __all__ = [
99
97
  "web_server",
100
98
  "wsgi_app",
101
99
  ]
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}'")
modal/_functions.py CHANGED
@@ -6,7 +6,7 @@ import textwrap
6
6
  import time
7
7
  import typing
8
8
  import warnings
9
- from collections.abc import AsyncGenerator, Collection, Sequence, Sized
9
+ from collections.abc import AsyncGenerator, 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_error, deprecation_warning, renamed_parameter
44
+ from ._utils.deprecation import deprecation_warning
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, get_sys_modules_mounts
74
+ from .mount import _get_client_mount, _Mount
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,12 +405,6 @@ 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
-
414
408
 
415
409
  def _parse_retries(
416
410
  retries: Optional[Union[int, Retries]],
@@ -511,7 +505,6 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
511
505
  is_generator: bool = False,
512
506
  gpu: Union[GPU_T, list[GPU_T]] = None,
513
507
  # TODO: maybe break this out into a separate decorator for notebooks.
514
- mounts: Collection[_Mount] = (),
515
508
  network_file_systems: dict[Union[str, PurePosixPath], _NetworkFileSystem] = {},
516
509
  volumes: dict[Union[str, PurePosixPath], Union[_Volume, _CloudBucketMount]] = {},
517
510
  webhook_config: Optional[api_pb2.WebhookConfig] = None,
@@ -567,8 +560,6 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
567
560
  assert not webhook_config
568
561
  assert not schedule
569
562
 
570
- explicit_mounts = mounts
571
-
572
563
  include_source_mode = get_include_source_mode(include_source)
573
564
  if include_source_mode != IncludeSourceMode.INCLUDE_NOTHING:
574
565
  entrypoint_mounts = info.get_entrypoint_mount()
@@ -577,34 +568,9 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
577
568
 
578
569
  all_mounts = [
579
570
  _get_client_mount(),
580
- *explicit_mounts,
581
571
  *entrypoint_mounts.values(),
582
572
  ]
583
573
 
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
-
608
574
  retry_policy = _parse_retries(
609
575
  retries, f"Function '{info.get_tag()}'" if info.raw_f else f"Class '{info.get_tag()}'"
610
576
  )
@@ -641,7 +607,6 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
641
607
  image=image,
642
608
  secrets=secrets,
643
609
  gpu=gpu,
644
- mounts=mounts,
645
610
  network_file_systems=network_file_systems,
646
611
  volumes=volumes,
647
612
  memory=memory,
@@ -749,16 +714,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
749
714
 
750
715
  def _deps(only_explicit_mounts=False) -> list[_Object]:
751
716
  deps: list[_Object] = list(secrets)
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:
717
+ if not only_explicit_mounts:
762
718
  deps += list(all_mounts)
763
719
  if proxy:
764
720
  deps.append(proxy)
@@ -1026,7 +982,6 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
1026
982
  obj._build_args = dict( # See get_build_def
1027
983
  secrets=repr(secrets),
1028
984
  gpu_config=repr([parse_gpu_config(_gpu) for _gpu in gpus]),
1029
- mounts=repr(mounts),
1030
985
  network_file_systems=repr(network_file_systems),
1031
986
  )
1032
987
  # these key are excluded if empty to avoid rebuilds on client upgrade
@@ -1190,7 +1145,8 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
1190
1145
 
1191
1146
  @live_method
1192
1147
  async def keep_warm(self, warm_pool_size: int) -> None:
1193
- """Set the warm pool size for the Function.
1148
+ """mdmd:hidden
1149
+ Set the warm pool size for the Function.
1194
1150
 
1195
1151
  DEPRECATED: Please adapt your code to use the more general `update_autoscaler` method instead:
1196
1152
 
@@ -1255,7 +1211,6 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
1255
1211
  return cls._from_loader(_load_remote, rep, is_another_app=True, hydrate_lazily=True)
1256
1212
 
1257
1213
  @classmethod
1258
- @renamed_parameter((2024, 12, 18), "tag", "name")
1259
1214
  def from_name(
1260
1215
  cls: type["_Function"],
1261
1216
  app_name: str,
@@ -1288,7 +1243,6 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
1288
1243
  return cls._from_name(app_name, name, namespace, environment_name)
1289
1244
 
1290
1245
  @staticmethod
1291
- @renamed_parameter((2024, 12, 18), "tag", "name")
1292
1246
  async def lookup(
1293
1247
  app_name: str,
1294
1248
  name: str,
@@ -1296,7 +1250,8 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
1296
1250
  client: Optional[_Client] = None,
1297
1251
  environment_name: Optional[str] = None,
1298
1252
  ) -> "_Function":
1299
- """Lookup a Function from a deployed App by its name.
1253
+ """mdmd:hidden
1254
+ Lookup a Function from a deployed App by its name.
1300
1255
 
1301
1256
  DEPRECATED: This method is deprecated in favor of `modal.Function.from_name`.
1302
1257
 
@@ -1420,7 +1375,8 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
1420
1375
  @property
1421
1376
  @live_method
1422
1377
  async def web_url(self) -> Optional[str]:
1423
- """Deprecated. Use the `Function.get_web_url()` method instead.
1378
+ """mdmd:hidden
1379
+ Deprecated. Use the `Function.get_web_url()` method instead.
1424
1380
 
1425
1381
  URL of a Function running as a web endpoint.
1426
1382
  """
@@ -1537,20 +1493,6 @@ Use the `Function.get_web_url()` method instead.
1537
1493
  async for res in invocation.run_generator():
1538
1494
  yield res
1539
1495
 
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
-
1554
1496
  @synchronizer.no_io_translation
1555
1497
  @live_method
1556
1498
  async def remote(self, *args: P.args, **kwargs: P.kwargs) -> ReturnType:
@@ -1663,7 +1605,7 @@ Use the `Function.get_web_url()` method instead.
1663
1605
  """
1664
1606
  self._check_no_web_url("_experimental_spawn")
1665
1607
  if self._is_generator:
1666
- invocation = await self._call_generator_nowait(args, kwargs)
1608
+ raise InvalidError("Cannot `spawn` a generator function.")
1667
1609
  else:
1668
1610
  invocation = await self._call_function_nowait(
1669
1611
  args, kwargs, function_call_invocation_type=api_pb2.FUNCTION_CALL_INVOCATION_TYPE_ASYNC
@@ -1695,14 +1637,13 @@ Use the `Function.get_web_url()` method instead.
1695
1637
  """
1696
1638
  self._check_no_web_url("spawn")
1697
1639
  if self._is_generator:
1698
- invocation = await self._call_generator_nowait(args, kwargs)
1640
+ raise InvalidError("Cannot `spawn` a generator function.")
1699
1641
  else:
1700
1642
  invocation = await self._call_function_nowait(args, kwargs, api_pb2.FUNCTION_CALL_INVOCATION_TYPE_ASYNC)
1701
1643
 
1702
1644
  fc: _FunctionCall[ReturnType] = _FunctionCall._new_hydrated(
1703
1645
  invocation.function_call_id, invocation.client, None
1704
1646
  )
1705
- fc._is_generator = self._is_generator if self._is_generator else False
1706
1647
  return fc
1707
1648
 
1708
1649
  def get_raw_f(self) -> Callable[..., Any]:
@@ -1761,22 +1702,8 @@ class _FunctionCall(typing.Generic[ReturnType], _Object, type_prefix="fc"):
1761
1702
 
1762
1703
  The returned coroutine is not cancellation-safe.
1763
1704
  """
1764
-
1765
- if self._is_generator:
1766
- raise Exception("Cannot get the result of a generator function call. Use `get_gen` instead.")
1767
-
1768
1705
  return await self._invocation().poll_function(timeout=timeout)
1769
1706
 
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
-
1780
1707
  async def get_call_graph(self) -> list[InputInfo]:
1781
1708
  """Returns a structure representing the call graph from a given root
1782
1709
  call ID, along with the status of execution for each node.
@@ -1807,9 +1734,7 @@ class _FunctionCall(typing.Generic[ReturnType], _Object, type_prefix="fc"):
1807
1734
  await retry_transient_errors(self._client.stub.FunctionCallCancel, request)
1808
1735
 
1809
1736
  @staticmethod
1810
- async def from_id(
1811
- function_call_id: str, client: Optional[_Client] = None, is_generator: bool = False
1812
- ) -> "_FunctionCall[Any]":
1737
+ async def from_id(function_call_id: str, client: Optional[_Client] = None) -> "_FunctionCall[Any]":
1813
1738
  """Instantiate a FunctionCall object from an existing ID.
1814
1739
 
1815
1740
  Examples:
@@ -1832,7 +1757,6 @@ class _FunctionCall(typing.Generic[ReturnType], _Object, type_prefix="fc"):
1832
1757
  client = await _Client.from_env()
1833
1758
 
1834
1759
  fc: _FunctionCall[Any] = _FunctionCall._new_hydrated(function_call_id, client, None)
1835
- fc._is_generator = is_generator
1836
1760
  return fc
1837
1761
 
1838
1762
  @staticmethod
@@ -1863,7 +1787,8 @@ class _FunctionCall(typing.Generic[ReturnType], _Object, type_prefix="fc"):
1863
1787
 
1864
1788
 
1865
1789
  async def _gather(*function_calls: _FunctionCall[T]) -> typing.Sequence[T]:
1866
- """Deprecated: Please use `modal.FunctionCall.gather()` instead."""
1790
+ """mdmd:hidden
1791
+ Deprecated: Please use `modal.FunctionCall.gather()` instead."""
1867
1792
  deprecation_warning(
1868
1793
  (2025, 2, 24),
1869
1794
  "`modal.functions.gather()` is deprecated; please use `modal.FunctionCall.gather()` instead.",
modal/_object.py CHANGED
@@ -10,7 +10,6 @@ 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
14
13
  from .client import _Client
15
14
  from .config import config, logger
16
15
  from .exception import ExecutionError, InvalidError
@@ -237,19 +236,6 @@ class _Object:
237
236
 
238
237
  return self._deps if self._deps is not None else default_deps
239
238
 
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
-
253
239
  async def hydrate(self, client: Optional[_Client] = None) -> Self:
254
240
  """Synchronize the local object with its identity on the Modal server.
255
241
 
@@ -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_non_default_params, callable_has_non_self_params
21
+ from ._utils.function_utils import callable_has_non_self_params
22
22
  from .config import logger
23
23
  from .exception import InvalidError
24
24
 
@@ -181,21 +181,11 @@ 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"`@modal.{decorator_name}` can't be applied to an async function.")
184
+ raise InvalidError(f"The `@modal.{decorator_name}` decorator 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
- 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
- )
188
+ raise InvalidError(f"Functions decorated by `@modal.{decorator_name}` can't have parameters.")
199
189
 
200
190
  def _get_raw_f(self) -> Callable[P, ReturnType]:
201
191
  assert self.raw_f is not None
@@ -659,7 +649,7 @@ def _web_server(
659
649
  def _build(
660
650
  _warn_parentheses_missing=None, *, force: bool = False, timeout: int = 86400
661
651
  ) -> Callable[[Union[_PartialFunction, NullaryMethod]], _PartialFunction]:
662
- """
652
+ """mdmd:hidden
663
653
  Decorator for methods that execute at _build time_ to create a new Image layer.
664
654
 
665
655
  **Deprecated**: This function is deprecated. We recommend using `modal.Volume`
modal/_serialization.py CHANGED
@@ -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 None,
328
- "text": asgi.websocket_send.text if asgi.websocket_send.HasField("text") else None,
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 {}),
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 config, logger
26
+ from ..config import logger
27
27
  from ..exception import (
28
28
  DeserializationError,
29
29
  ExecutionError,
@@ -627,8 +627,7 @@ 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 # 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
630
+ INCLUDE_MAIN_PACKAGE = True # Default behavior
632
631
 
633
632
 
634
633
  def get_include_source_mode(function_or_app_specific) -> IncludeSourceMode:
@@ -650,6 +649,4 @@ def get_include_source_mode(function_or_app_specific) -> IncludeSourceMode:
650
649
  # explicitly set in app/function
651
650
  return IncludeSourceMode(function_or_app_specific)
652
651
 
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
652
+ return IncludeSourceMode.INCLUDE_MAIN_PACKAGE
@@ -148,15 +148,20 @@ def create_channel(
148
148
 
149
149
  logger.debug(f"Sending request to {event.method_name}")
150
150
 
151
- async def recv_trailing_metadata(trailing_metadata: grpclib.events.RecvTrailingMetadata) -> None:
151
+ async def recv_initial_metadata(initial_metadata: grpclib.events.RecvInitialMetadata) -> 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:
156
160
  if token := trailing_metadata.metadata.get("x-modal-auth-token"):
157
161
  metadata["x-modal-auth-token"] = str(token)
158
162
 
159
163
  grpclib.events.listen(channel, grpclib.events.SendRequest, send_request)
164
+ grpclib.events.listen(channel, grpclib.events.RecvInitialMetadata, recv_initial_metadata)
160
165
  grpclib.events.listen(channel, grpclib.events.RecvTrailingMetadata, recv_trailing_metadata)
161
166
 
162
167
  return channel