modal 1.1.2.dev2__py3-none-any.whl → 1.1.2.dev4__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.

modal/__main__.py CHANGED
@@ -37,7 +37,6 @@ def main():
37
37
 
38
38
  from grpclib import GRPCError, Status
39
39
  from rich.panel import Panel
40
- from rich.text import Text
41
40
 
42
41
  if isinstance(exc, GRPCError):
43
42
  status_map = {
@@ -69,7 +68,7 @@ def main():
69
68
  content = f"{content}\n\nNote: {' '.join(notes)}"
70
69
 
71
70
  console = make_console(stderr=True)
72
- panel = Panel(Text(content), title=title, title_align="left", border_style="red")
71
+ panel = Panel(content, title=title, title_align="left", border_style="red")
73
72
  console.print(panel, highlight=False)
74
73
  sys.exit(1)
75
74
 
modal/client.pyi CHANGED
@@ -33,7 +33,7 @@ class _Client:
33
33
  server_url: str,
34
34
  client_type: int,
35
35
  credentials: typing.Optional[tuple[str, str]],
36
- version: str = "1.1.2.dev2",
36
+ version: str = "1.1.2.dev4",
37
37
  ):
38
38
  """mdmd:hidden
39
39
  The Modal client object is not intended to be instantiated directly by users.
@@ -164,7 +164,7 @@ class Client:
164
164
  server_url: str,
165
165
  client_type: int,
166
166
  credentials: typing.Optional[tuple[str, str]],
167
- version: str = "1.1.2.dev2",
167
+ version: str = "1.1.2.dev4",
168
168
  ):
169
169
  """mdmd:hidden
170
170
  The Modal client object is not intended to be instantiated directly by users.
modal/config.py CHANGED
@@ -94,7 +94,7 @@ from google.protobuf.empty_pb2 import Empty
94
94
  from modal_proto import api_pb2
95
95
 
96
96
  from ._utils.logger import configure_logger
97
- from .exception import InvalidError
97
+ from .exception import InvalidError, NotFoundError
98
98
 
99
99
  DEFAULT_SERVER_URL = "https://api.modal.com"
100
100
 
@@ -158,15 +158,15 @@ def _config_active_profile() -> str:
158
158
  return "default"
159
159
 
160
160
 
161
- def config_set_active_profile(env: str) -> None:
161
+ def config_set_active_profile(profile: str) -> None:
162
162
  """Set the user's active modal profile by writing it to the `.modal.toml` file."""
163
- if env not in _user_config:
164
- raise KeyError(env)
163
+ if profile not in _user_config:
164
+ raise NotFoundError(f"No profile named '{profile}' found in {user_config_path}")
165
165
 
166
- for key, values in _user_config.items():
167
- values.pop("active", None)
166
+ for profile_data in _user_config.values():
167
+ profile_data.pop("active", None)
168
168
 
169
- _user_config[env]["active"] = True
169
+ _user_config[profile]["active"] = True # type: ignore
170
170
  _write_user_config(_user_config)
171
171
 
172
172
 
@@ -11,6 +11,7 @@ then asking it whether file paths match any of its patterns.
11
11
 
12
12
  import os
13
13
  from abc import abstractmethod
14
+ from functools import cached_property
14
15
  from pathlib import Path
15
16
  from typing import Callable, Optional, Sequence, Union
16
17
 
@@ -99,11 +100,11 @@ class FilePatternMatcher(_AbstractPatternMatcher):
99
100
  ```
100
101
  """
101
102
 
102
- patterns: list[Pattern]
103
- _delayed_init: Callable[[], None] = None
103
+ _file_path: Optional[Union[str, Path]]
104
+ _pattern_strings: Optional[Sequence[str]]
104
105
 
105
- def _set_patterns(self, patterns: Sequence[str]) -> None:
106
- self.patterns = []
106
+ def _parse_patterns(self, patterns: Sequence[str]) -> list[Pattern]:
107
+ parsed_patterns = []
107
108
  for pattern in list(patterns):
108
109
  pattern = pattern.strip().strip(os.path.sep)
109
110
  if not pattern:
@@ -118,7 +119,8 @@ class FilePatternMatcher(_AbstractPatternMatcher):
118
119
  # In Python, we can proceed without explicit syntax checking
119
120
  new_pattern.cleaned_pattern = pattern
120
121
  new_pattern.dirs = pattern.split(os.path.sep)
121
- self.patterns.append(new_pattern)
122
+ parsed_patterns.append(new_pattern)
123
+ return parsed_patterns
122
124
 
123
125
  def __init__(self, *pattern: str) -> None:
124
126
  """Initialize a new FilePatternMatcher instance.
@@ -129,7 +131,8 @@ class FilePatternMatcher(_AbstractPatternMatcher):
129
131
  Raises:
130
132
  ValueError: If an illegal exclusion pattern is provided.
131
133
  """
132
- self._set_patterns(pattern)
134
+ self._pattern_strings = pattern
135
+ self._file_path = None
133
136
 
134
137
  @classmethod
135
138
  def from_file(cls, file_path: Union[str, Path]) -> "FilePatternMatcher":
@@ -148,14 +151,10 @@ class FilePatternMatcher(_AbstractPatternMatcher):
148
151
  ```
149
152
 
150
153
  """
151
- uninitialized = cls.__new__(cls)
152
-
153
- def _delayed_init():
154
- uninitialized._set_patterns(Path(file_path).read_text("utf8").splitlines())
155
- uninitialized._delayed_init = None
156
-
157
- uninitialized._delayed_init = _delayed_init
158
- return uninitialized
154
+ instance = cls.__new__(cls)
155
+ instance._file_path = file_path
156
+ instance._pattern_strings = None
157
+ return instance
159
158
 
160
159
  def _matches(self, file_path: str) -> bool:
161
160
  """Check if the file path or any of its parent directories match the patterns.
@@ -194,6 +193,18 @@ class FilePatternMatcher(_AbstractPatternMatcher):
194
193
 
195
194
  return matched
196
195
 
196
+ @cached_property
197
+ def patterns(self) -> list[Pattern]:
198
+ """Get the patterns, loading from file if necessary."""
199
+ if self._file_path is not None:
200
+ # Lazy load from file
201
+ pattern_strings = Path(self._file_path).read_text("utf8").splitlines()
202
+ else:
203
+ # Use patterns provided in __init__
204
+ pattern_strings = list(self._pattern_strings)
205
+
206
+ return self._parse_patterns(pattern_strings)
207
+
197
208
  def can_prune_directories(self) -> bool:
198
209
  """
199
210
  Returns True if this pattern matcher allows safe early directory pruning.
@@ -205,8 +216,6 @@ class FilePatternMatcher(_AbstractPatternMatcher):
205
216
  return not any(pattern.exclusion for pattern in self.patterns)
206
217
 
207
218
  def __call__(self, file_path: Path) -> bool:
208
- if self._delayed_init:
209
- self._delayed_init()
210
219
  return self._matches(str(file_path))
211
220
 
212
221
 
modal/functions.pyi CHANGED
@@ -427,7 +427,7 @@ class Function(
427
427
 
428
428
  _call_generator: ___call_generator_spec[typing_extensions.Self]
429
429
 
430
- class __remote_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
430
+ class __remote_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
431
431
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER:
432
432
  """Calls the function remotely, executing it with the given arguments and returning the execution's result."""
433
433
  ...
@@ -436,7 +436,7 @@ class Function(
436
436
  """Calls the function remotely, executing it with the given arguments and returning the execution's result."""
437
437
  ...
438
438
 
439
- remote: __remote_spec[modal._functions.ReturnType, modal._functions.P, typing_extensions.Self]
439
+ remote: __remote_spec[modal._functions.P, modal._functions.ReturnType, typing_extensions.Self]
440
440
 
441
441
  class __remote_gen_spec(typing_extensions.Protocol[SUPERSELF]):
442
442
  def __call__(self, /, *args, **kwargs) -> typing.Generator[typing.Any, None, None]:
@@ -463,7 +463,7 @@ class Function(
463
463
  """
464
464
  ...
465
465
 
466
- class ___experimental_spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
466
+ class ___experimental_spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
467
467
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
468
468
  """[Experimental] Calls the function with the given arguments, without waiting for the results.
469
469
 
@@ -487,7 +487,7 @@ class Function(
487
487
  ...
488
488
 
489
489
  _experimental_spawn: ___experimental_spawn_spec[
490
- modal._functions.ReturnType, modal._functions.P, typing_extensions.Self
490
+ modal._functions.P, modal._functions.ReturnType, typing_extensions.Self
491
491
  ]
492
492
 
493
493
  class ___spawn_map_inner_spec(typing_extensions.Protocol[P_INNER, SUPERSELF]):
@@ -496,7 +496,7 @@ class Function(
496
496
 
497
497
  _spawn_map_inner: ___spawn_map_inner_spec[modal._functions.P, typing_extensions.Self]
498
498
 
499
- class __spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
499
+ class __spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
500
500
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
501
501
  """Calls the function with the given arguments, without waiting for the results.
502
502
 
@@ -517,7 +517,7 @@ class Function(
517
517
  """
518
518
  ...
519
519
 
520
- spawn: __spawn_spec[modal._functions.ReturnType, modal._functions.P, typing_extensions.Self]
520
+ spawn: __spawn_spec[modal._functions.P, modal._functions.ReturnType, typing_extensions.Self]
521
521
 
522
522
  def get_raw_f(self) -> collections.abc.Callable[..., typing.Any]:
523
523
  """Return the inner Python object wrapped by this Modal Function."""
modal/image.pyi CHANGED
@@ -91,7 +91,7 @@ def _create_context_mount_function(
91
91
  dockerfile_cmds: list[str] = [],
92
92
  dockerfile_path: typing.Optional[pathlib.Path] = None,
93
93
  context_mount: typing.Optional[modal.mount._Mount] = None,
94
- context_dir: typing.Union[pathlib.Path, str, None] = None,
94
+ context_dir: typing.Union[str, pathlib.Path, None] = None,
95
95
  ): ...
96
96
 
97
97
  class _ImageRegistryConfig:
@@ -537,7 +537,7 @@ class _Image(modal._object._Object):
537
537
  secrets: collections.abc.Sequence[modal.secret._Secret] = [],
538
538
  gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
539
539
  context_mount: typing.Optional[modal.mount._Mount] = None,
540
- context_dir: typing.Union[pathlib.Path, str, None] = None,
540
+ context_dir: typing.Union[str, pathlib.Path, None] = None,
541
541
  force_build: bool = False,
542
542
  ignore: typing.Union[
543
543
  collections.abc.Sequence[str], collections.abc.Callable[[pathlib.Path], bool]
@@ -748,7 +748,7 @@ class _Image(modal._object._Object):
748
748
  *,
749
749
  context_mount: typing.Optional[modal.mount._Mount] = None,
750
750
  force_build: bool = False,
751
- context_dir: typing.Union[pathlib.Path, str, None] = None,
751
+ context_dir: typing.Union[str, pathlib.Path, None] = None,
752
752
  secrets: collections.abc.Sequence[modal.secret._Secret] = [],
753
753
  gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
754
754
  add_python: typing.Optional[str] = None,
@@ -1381,7 +1381,7 @@ class Image(modal.object.Object):
1381
1381
  secrets: collections.abc.Sequence[modal.secret.Secret] = [],
1382
1382
  gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
1383
1383
  context_mount: typing.Optional[modal.mount.Mount] = None,
1384
- context_dir: typing.Union[pathlib.Path, str, None] = None,
1384
+ context_dir: typing.Union[str, pathlib.Path, None] = None,
1385
1385
  force_build: bool = False,
1386
1386
  ignore: typing.Union[
1387
1387
  collections.abc.Sequence[str], collections.abc.Callable[[pathlib.Path], bool]
@@ -1592,7 +1592,7 @@ class Image(modal.object.Object):
1592
1592
  *,
1593
1593
  context_mount: typing.Optional[modal.mount.Mount] = None,
1594
1594
  force_build: bool = False,
1595
- context_dir: typing.Union[pathlib.Path, str, None] = None,
1595
+ context_dir: typing.Union[str, pathlib.Path, None] = None,
1596
1596
  secrets: collections.abc.Sequence[modal.secret.Secret] = [],
1597
1597
  gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
1598
1598
  add_python: typing.Optional[str] = None,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.1.2.dev2
3
+ Version: 1.1.2.dev4
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -1,5 +1,5 @@
1
1
  modal/__init__.py,sha256=WMaRW-2IJRGA9ioNAaBhJYuyLvu-GS01L8wQD90fKBs,2682
2
- modal/__main__.py,sha256=uBjSb_5cdlxmr9AwLkznYsW2tGEJRBjEcCGILvgR_1s,2844
2
+ modal/__main__.py,sha256=45H-GtwzaDfN-1nP4_HYvzN3s7AG_HXR4-ynrsjO_OI,2803
3
3
  modal/_clustered_functions.py,sha256=zmrKbptRbqp4euS3LWncKaLXb8Kjj4YreusOzpEpRMk,2856
4
4
  modal/_clustered_functions.pyi,sha256=_wtFjWocGf1WgI-qYBpbJPArNkg2H9JV7BVaGgMesEQ,1103
5
5
  modal/_container_entrypoint.py,sha256=1qBMNY_E9ICC_sRCtillMxmKPsmxJl1J0_qOAG8rH-0,28288
@@ -22,12 +22,12 @@ modal/app.py,sha256=kpq4kXp7pch688y6g55QYAC10wqPTU5FXKoWPMirA3E,47899
22
22
  modal/app.pyi,sha256=-jKXlGDBWRPVsuenBhdMRqawK-L2eiJ7gHbmSblhltg,43525
23
23
  modal/call_graph.py,sha256=1g2DGcMIJvRy-xKicuf63IVE98gJSnQsr8R_NVMptNc,2581
24
24
  modal/client.py,sha256=kyAIVB3Ay-XKJizQ_1ufUFB__EagV0MLmHJpyYyJ7J0,18636
25
- modal/client.pyi,sha256=O_opOIciInt5mBb0ny1KqtrKbpsvG4xtb_1m2eF5djI,15829
25
+ modal/client.pyi,sha256=KYf_JhcAa0jiSBqLmH5-v6AIgDHG4nWsJ55FBNv0H4I,15829
26
26
  modal/cloud_bucket_mount.py,sha256=YOe9nnvSr4ZbeCn587d7_VhE9IioZYRvF9VYQTQux08,5914
27
27
  modal/cloud_bucket_mount.pyi,sha256=-qSfYAQvIoO_l2wsCCGTG5ZUwQieNKXdAO00yP1-LYU,7394
28
28
  modal/cls.py,sha256=7A0xGnugQzm8dOfnKMjLjtqekRlRtQ0jPFRYgq6xdUM,40018
29
29
  modal/cls.pyi,sha256=_tZ5qrlL-ZDEcD-mf9BZkkNH5XPr4SmGTEQ-RVmqF3I,27772
30
- modal/config.py,sha256=FqVewLPVVR4feq_46JBENiCzqTuXKpnvQZxaeWbS39g,12009
30
+ modal/config.py,sha256=tW-SEGjVvAt3D_MNi3LhxXnFKIA9fjLd3UIgbW8uSJE,12121
31
31
  modal/container_process.py,sha256=XkPwNIW-iD_GB9u9yqv9q8y-i5cQ8eBbLZZ_GvEw9t8,6858
32
32
  modal/container_process.pyi,sha256=9m-st3hCUlNN1GOTctfPPvIvoLtEl7FbuGWwif5-7YU,6037
33
33
  modal/dict.py,sha256=IWpPQtBwR96TJN7ogpIZvL9Ge9rxY4KJ2CjkUKfWr6g,15864
@@ -37,12 +37,12 @@ modal/environments.pyi,sha256=9-KtrzAcUe55cCP4020lSUD7-fWS7OPakAHssq4-bro,4219
37
37
  modal/exception.py,sha256=o0V93PK8Hcg2YQ2aeOB1Y-qWBw4Gz5ATfyokR8GapuQ,5634
38
38
  modal/file_io.py,sha256=BVqAJ0sgPUfN8QsYztWiGB4j56he60TncM02KsylnCw,21449
39
39
  modal/file_io.pyi,sha256=cPT_hsplE5iLCXhYOLn1Sp9eDdk7DxdFmicQHanJZyg,15918
40
- modal/file_pattern_matcher.py,sha256=urAue8es8jxqX94k9EYoZxxhtfgOlsEES8lbFHOorzc,7734
40
+ modal/file_pattern_matcher.py,sha256=A_Kdkej6q7YQyhM_2-BvpFmPqJ0oHb54B6yf9VqvPVE,8116
41
41
  modal/functions.py,sha256=kcNHvqeGBxPI7Cgd57NIBBghkfbeFJzXO44WW0jSmao,325
42
- modal/functions.pyi,sha256=VYPnfnCLfHRDAl6t5AaVHmZEz0T5f2igjTeMOtHPie8,34766
42
+ modal/functions.pyi,sha256=cS7QYPHcFD_p95hrAU-TWxBIraIzzG-uO9KyPAwfxdw,34766
43
43
  modal/gpu.py,sha256=Fe5ORvVPDIstSq1xjmM6OoNgLYFWvogP9r5BgmD3hYg,6769
44
44
  modal/image.py,sha256=A83nmo0zfCUwgvJh0LZ7Yc1sYvDnZLl_phbKxN-9HIw,103144
45
- modal/image.pyi,sha256=mlGwmpkKdwNK_VRrCa0WMDURmQPSOohm7hgiiFTfdXI,68541
45
+ modal/image.pyi,sha256=oH-GCHVEwD5fOX0K_IaWN5RKZlYwX82z-K4wxx8aN3c,68541
46
46
  modal/io_streams.py,sha256=ut9tY_yEtiBsgQ40u_72Ns87IZHfbMxfnh8t6U9RSGA,16204
47
47
  modal/io_streams.pyi,sha256=aOun_jUFKHSJyUY6-7gKvNoxzcULsa8_hxdtEO7v-gk,13980
48
48
  modal/mount.py,sha256=EHttd7D0HNtGUDyB3DS26dJMdabG-SlIaD5c52dJnbE,36729
@@ -151,7 +151,7 @@ modal/experimental/__init__.py,sha256=nuc7AL4r_Fs08DD5dciWFZhrV1nanwoClOfdTcudU0
151
151
  modal/experimental/flash.py,sha256=viXQumCIFp5VFsPFURdFTBTjP_QnsAi8nSWXAMmfjeQ,19744
152
152
  modal/experimental/flash.pyi,sha256=A8_qJGtGoXEzKDdHbvhmCw7oqfneFEvJQK3ZdTOvUdU,10830
153
153
  modal/experimental/ipython.py,sha256=TrCfmol9LGsRZMeDoeMPx3Hv3BFqQhYnmD_iH0pqdhk,2904
154
- modal-1.1.2.dev2.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
154
+ modal-1.1.2.dev4.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
155
155
  modal_docs/__init__.py,sha256=svYKtV8HDwDCN86zbdWqyq5T8sMdGDj0PVlzc2tIxDM,28
156
156
  modal_docs/gen_cli_docs.py,sha256=c1yfBS_x--gL5bs0N4ihMwqwX8l3IBWSkBAKNNIi6bQ,3801
157
157
  modal_docs/gen_reference_docs.py,sha256=d_CQUGQ0rfw28u75I2mov9AlS773z9rG40-yq5o7g2U,6359
@@ -174,10 +174,10 @@ modal_proto/options_pb2.pyi,sha256=l7DBrbLO7q3Ir-XDkWsajm0d0TQqqrfuX54i4BMpdQg,1
174
174
  modal_proto/options_pb2_grpc.py,sha256=1oboBPFxaTEXt9Aw7EAj8gXHDCNMhZD2VXqocC9l_gk,159
175
175
  modal_proto/options_pb2_grpc.pyi,sha256=CImmhxHsYnF09iENPoe8S4J-n93jtgUYD2JPAc0yJSI,247
176
176
  modal_proto/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
177
- modal_version/__init__.py,sha256=hOG9XSpVA8Hwq28bn-O79Wlydcw4G4mHAkfa1OWURC0,120
177
+ modal_version/__init__.py,sha256=L6Oc5vDt_IFbv38rvmkAYFIS-UpJfEQVuW_ZZleRr84,120
178
178
  modal_version/__main__.py,sha256=2FO0yYQQwDTh6udt1h-cBnGd1c4ZyHnHSI4BksxzVac,105
179
- modal-1.1.2.dev2.dist-info/METADATA,sha256=DDAmQxVo5C2mGPxv9uaDbrxmSMo-FYwPOOhDG8Pfyg4,2459
180
- modal-1.1.2.dev2.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
181
- modal-1.1.2.dev2.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
182
- modal-1.1.2.dev2.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
183
- modal-1.1.2.dev2.dist-info/RECORD,,
179
+ modal-1.1.2.dev4.dist-info/METADATA,sha256=pijwhCE0wHh33Jj8-YJGP4_NROx3Xtp7nx-g8mCM3GY,2459
180
+ modal-1.1.2.dev4.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
181
+ modal-1.1.2.dev4.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
182
+ modal-1.1.2.dev4.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
183
+ modal-1.1.2.dev4.dist-info/RECORD,,
modal_version/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
1
  # Copyright Modal Labs 2025
2
2
  """Supplies the current version of the modal client library."""
3
3
 
4
- __version__ = "1.1.2.dev2"
4
+ __version__ = "1.1.2.dev4"