modAL 1.2.6.dev4__py3-none-any.whl → 1.2.7.dev0__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.
modal/cli/launch.py CHANGED
@@ -3,8 +3,6 @@ import asyncio
3
3
  import inspect
4
4
  import json
5
5
  import os
6
- import subprocess
7
- import tempfile
8
6
  from pathlib import Path
9
7
  from typing import Any, Optional
10
8
 
@@ -120,75 +118,3 @@ def vscode(
120
118
  "volume": volume,
121
119
  }
122
120
  _launch_program("vscode", "vscode.py", detach, args)
123
-
124
-
125
- @launch_cli.command(name="machine", help="Start an instance on Modal, with direct SSH access.", hidden=True)
126
- def machine(
127
- name: str, # Name of the machine App.
128
- cpu: int = 8, # Reservation of CPU cores (can burst above this value).
129
- memory: int = 32768, # Reservation of memory in MiB (can burst above this value).
130
- gpu: Optional[str] = None, # GPU type and count, e.g. "t4" or "h100:2".
131
- image: Optional[str] = None, # Image tag to use from registry. Defaults to the notebook base image.
132
- timeout: int = 3600 * 24, # Timeout in seconds for the instance.
133
- volume: str = "machine-vol", # Attach a persisted `modal.Volume` at /workspace (created if missing).
134
- ):
135
- tempdir = Path(tempfile.gettempdir())
136
- key_path = tempdir / "modal-machine-keyfile.pem"
137
- # Generate a new SSH key pair for this machine instance.
138
- if not key_path.exists():
139
- subprocess.run(
140
- ["ssh-keygen", "-t", "ed25519", "-f", str(key_path), "-N", ""],
141
- check=True,
142
- stdout=subprocess.DEVNULL,
143
- )
144
- # Add the key with expiry 1d to ssh agent.
145
- subprocess.run(
146
- ["ssh-add", "-t", "1d", str(key_path)],
147
- check=True,
148
- stdout=subprocess.DEVNULL,
149
- stderr=subprocess.DEVNULL,
150
- )
151
-
152
- os.environ["SSH_PUBLIC_KEY"] = Path(str(key_path) + ".pub").read_text()
153
- os.environ["MODAL_LOGS_TIMEOUT"] = "0" # hack to work with --detach
154
-
155
- args = {
156
- "cpu": cpu,
157
- "memory": memory,
158
- "gpu": gpu,
159
- "image": image,
160
- "timeout": timeout,
161
- "volume": volume,
162
- }
163
- _launch_program(
164
- "machine",
165
- "launch_instance_ssh.py",
166
- True,
167
- args,
168
- description=name,
169
- )
170
-
171
-
172
- @launch_cli.command(name="marimo", help="Start a remote Marimo notebook on Modal.", hidden=True)
173
- def marimo(
174
- cpu: int = 8,
175
- memory: int = 32768,
176
- gpu: Optional[str] = None,
177
- image: str = "debian:12",
178
- timeout: int = 3600,
179
- add_python: Optional[str] = "3.12",
180
- mount: Optional[str] = None, # Create a `modal.Mount` from a local directory.
181
- volume: Optional[str] = None, # Attach a persisted `modal.Volume` by name (creating if missing).
182
- detach: bool = False, # Run the app in "detached" mode to persist after local client disconnects
183
- ):
184
- args = {
185
- "cpu": cpu,
186
- "memory": memory,
187
- "gpu": gpu,
188
- "timeout": timeout,
189
- "image": image,
190
- "add_python": add_python,
191
- "mount": mount,
192
- "volume": volume,
193
- }
194
- _launch_program("marimo", "run_marimo.py", detach, args)
modal/client.pyi CHANGED
@@ -32,7 +32,7 @@ class _Client:
32
32
  server_url: str,
33
33
  client_type: int,
34
34
  credentials: typing.Optional[tuple[str, str]],
35
- version: str = "1.2.6.dev4",
35
+ version: str = "1.2.7.dev0",
36
36
  ):
37
37
  """mdmd:hidden
38
38
  The Modal client object is not intended to be instantiated directly by users.
@@ -163,7 +163,7 @@ class Client:
163
163
  server_url: str,
164
164
  client_type: int,
165
165
  credentials: typing.Optional[tuple[str, str]],
166
- version: str = "1.2.6.dev4",
166
+ version: str = "1.2.7.dev0",
167
167
  ):
168
168
  """mdmd:hidden
169
169
  The Modal client object is not intended to be instantiated directly by users.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.2.6.dev4
3
+ Version: 1.2.7.dev0
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -26,7 +26,7 @@ modal/app.pyi,sha256=nI_Tibj-rI5I7dJFJnczbHvcmVzCvvCih0tMzoQlr_Y,50835
26
26
  modal/billing.py,sha256=zmQ3bcCJlwa4KD1IA_QgdWpm1pn13c-7qfy79iEauYI,195
27
27
  modal/call_graph.py,sha256=1g2DGcMIJvRy-xKicuf63IVE98gJSnQsr8R_NVMptNc,2581
28
28
  modal/client.py,sha256=k1CqQ_0t4-vHylkqYZgYCnClg-FT0QrTPAKivL01A_k,14354
29
- modal/client.pyi,sha256=5Jwlh9gkgM1TCBe1LuIA4tAQio2D7I8v2TMg09H5kKo,13146
29
+ modal/client.pyi,sha256=WfEaqcFNyrabfN7MXf14lnobpOLciP3xidRdSCN8FjM,13146
30
30
  modal/cloud_bucket_mount.py,sha256=cvVj5Rt4nDHoQbTneoJPTaAcnl_Ab_mrsjnnzd0v9OI,6013
31
31
  modal/cloud_bucket_mount.pyi,sha256=vXusGMOUk9HjCs4lhxteuCK4xLQclPfugGWKo7LECEA,7539
32
32
  modal/cls.py,sha256=4T__mtYlQUnkatif1Wnr8Ld9DN_ySydHj2UwhRg89ok,41984
@@ -141,7 +141,7 @@ modal/cli/dict.py,sha256=8aVWjxdmsPznYNMNYYkKHtrJSEREGc_H21g1hTHa0FM,4686
141
141
  modal/cli/entry_point.py,sha256=nz7dBaGbt5I3TqVu7595vzvSQItTts3vmmORlYHn3x8,4841
142
142
  modal/cli/environment.py,sha256=LGBq8RVQjfBH3EWz8QgmYe19UO66JKSDNxOXMUjw7JM,4285
143
143
  modal/cli/import_refs.py,sha256=X59Z5JwgliRO6C-cIFto2Pr7o3SwlZMKQPKA0aI4ZK4,13927
144
- modal/cli/launch.py,sha256=oJKGWjTJiXQTdw-SUiCmCQ76bY_8nlzJMUMu0zew0zs,6435
144
+ modal/cli/launch.py,sha256=1inePjuiqV3HHwk0H-Lk-UAxhkoodCwFoRswD_dat2U,3840
145
145
  modal/cli/network_file_system.py,sha256=S6cgyq3hVKKTpfOwlsT68Zs7uXYCXLJEm7-SuhhZnbo,8043
146
146
  modal/cli/profile.py,sha256=g8X6tFFK9ccKyu2he9Yu19WLSLNdztzECgmIV__XJFs,3257
147
147
  modal/cli/queues.py,sha256=S5dqk6lEd_2fJolHqoN9iRs6EkeTa0k7KqJWBBGS23k,6170
@@ -152,15 +152,13 @@ modal/cli/token.py,sha256=NAmQzKBfEHkcldWKeFxAVIqQBoo1RTp7_A4yc7-8qM0,1911
152
152
  modal/cli/utils.py,sha256=aUXDU9_VgcJrGaGRy4bGf4dqwKYXHCpoO27x4m_bpuo,3293
153
153
  modal/cli/volume.py,sha256=S0hZTamSHFuNBu_fCCYrnEDADCrxzDbPNtu0iEkFzxs,10891
154
154
  modal/cli/programs/__init__.py,sha256=svYKtV8HDwDCN86zbdWqyq5T8sMdGDj0PVlzc2tIxDM,28
155
- modal/cli/programs/launch_instance_ssh.py,sha256=GrwK_Vy8-7B4x5a6AqFaF7lqNVgu75JYZ2BtFV0_DOw,2660
156
155
  modal/cli/programs/run_jupyter.py,sha256=IJw8nds8Cjl9j4dxBqMGxhz-bIyVX0kle7jbt8HFOhM,2688
157
- modal/cli/programs/run_marimo.py,sha256=QlCGPkwQ0XLajt2LtujR_BGsRV1AZ3OCUgZxkkM1lug,2893
158
156
  modal/cli/programs/vscode.py,sha256=E1aJPU7b8RWWj-JX71DifsCoLYsCAnre7lATiBJjUms,3386
159
157
  modal/experimental/__init__.py,sha256=GOuo3t4-Le0ZVddiHIOw0MQxkdTJge-bVbhDvgnblmQ,14573
160
158
  modal/experimental/flash.py,sha256=GJZwSr-4OHlP6gCIZdcbsSb8D8WX9xJwMphjwcfsRoU,31262
161
159
  modal/experimental/flash.pyi,sha256=q4a3mdgL0jzATPL2tS7LpuyulYzF1vUSE453S9xc8n8,16965
162
160
  modal/experimental/ipython.py,sha256=TrCfmol9LGsRZMeDoeMPx3Hv3BFqQhYnmD_iH0pqdhk,2904
163
- modal-1.2.6.dev4.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
161
+ modal-1.2.7.dev0.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
164
162
  modal_docs/__init__.py,sha256=svYKtV8HDwDCN86zbdWqyq5T8sMdGDj0PVlzc2tIxDM,28
165
163
  modal_docs/gen_cli_docs.py,sha256=c1yfBS_x--gL5bs0N4ihMwqwX8l3IBWSkBAKNNIi6bQ,3801
166
164
  modal_docs/gen_reference_docs.py,sha256=d_CQUGQ0rfw28u75I2mov9AlS773z9rG40-yq5o7g2U,6359
@@ -182,10 +180,10 @@ modal_proto/task_command_router_pb2.py,sha256=2Y8wRvnq4_7RiQ-5ZAPIgXaxrHv_MXzgS5
182
180
  modal_proto/task_command_router_pb2.pyi,sha256=yI4tFteErLlonFA2HyaWtONfhY_VGSe7KCWFIspvmkE,16323
183
181
  modal_proto/task_command_router_pb2_grpc.py,sha256=q2VWfK2-4uDcPaPLhAqPZkgxhuQRYnWmwUcnEbPbGuk,13895
184
182
  modal_proto/task_command_router_pb2_grpc.pyi,sha256=e1MM10VGUgDkm041v53QeTglGQPzTpA0FUsFtezjp74,4536
185
- modal_version/__init__.py,sha256=mFsXOevjOHo5RGkFcC7zBVIU5LVwRggi9DX1Qy9VUy4,120
183
+ modal_version/__init__.py,sha256=yr8D6e9wvxWDoYcpT079wPlk6_TfzE-N4ipxeI_-0pc,120
186
184
  modal_version/__main__.py,sha256=nLUbubxKx7GXNzJIkTB7M7_u8080LyLM0IS0rzFkC_c,119
187
- modal-1.2.6.dev4.dist-info/METADATA,sha256=Usp7oYLxYLWkv6L6hfIeRibBWYaRFUv8XXh_UOmKYng,2489
188
- modal-1.2.6.dev4.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
189
- modal-1.2.6.dev4.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
190
- modal-1.2.6.dev4.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
191
- modal-1.2.6.dev4.dist-info/RECORD,,
185
+ modal-1.2.7.dev0.dist-info/METADATA,sha256=D3ZRf4VXIi6Ff_rdwciBhx84U-p24lKrRv_RyNXmb_k,2489
186
+ modal-1.2.7.dev0.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
187
+ modal-1.2.7.dev0.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
188
+ modal-1.2.7.dev0.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
189
+ modal-1.2.7.dev0.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.2.6.dev4"
4
+ __version__ = "1.2.7.dev0"
@@ -1,94 +0,0 @@
1
- # Copyright Modal Labs 2023
2
- # type: ignore
3
- import json
4
- import os
5
- import sys
6
- from typing import Any
7
-
8
- import rich
9
- import rich.panel
10
- import rich.rule
11
-
12
- import modal
13
- import modal.experimental
14
-
15
- # Passed by `modal launch` locally via CLI.
16
- args: dict[str, Any] = json.loads(os.environ.get("MODAL_LAUNCH_ARGS", "{}"))
17
-
18
- app = modal.App()
19
-
20
- image: modal.Image
21
- if args.get("image"):
22
- image = modal.Image.from_registry(args.get("image"))
23
- else:
24
- # Must be set to the same image builder version as the notebook base image.
25
- os.environ["MODAL_IMAGE_BUILDER_VERSION"] = "2024.10"
26
- image = modal.experimental.notebook_base_image(python_version="3.12")
27
-
28
- volume = (
29
- modal.Volume.from_name(
30
- args.get("volume"),
31
- create_if_missing=True,
32
- )
33
- if args.get("volume")
34
- else None
35
- )
36
- volumes = {"/workspace": volume} if volume else {}
37
-
38
-
39
- startup_script = """
40
- set -eu
41
- mkdir -p /run/sshd
42
-
43
- # Check if sshd is installed, install if not
44
- test -x /usr/sbin/sshd || (apt-get update && apt-get install -y openssh-server)
45
-
46
- # Change default working directory to /workspace
47
- echo "cd /workspace" >> /root/.profile
48
-
49
- mkdir -p /root/.ssh
50
- echo "$SSH_PUBLIC_KEY" >> /root/.ssh/authorized_keys
51
- /usr/sbin/sshd -D -e
52
- """
53
-
54
-
55
- @app.local_entrypoint()
56
- def main():
57
- if not os.environ.get("SSH_PUBLIC_KEY"):
58
- raise ValueError("SSH_PUBLIC_KEY environment variable is not set")
59
-
60
- sb = modal.Sandbox.create(
61
- *("sh", "-c", startup_script),
62
- app=app,
63
- image=image,
64
- cpu=args.get("cpu"),
65
- memory=args.get("memory"),
66
- gpu=args.get("gpu"),
67
- timeout=args.get("timeout"),
68
- volumes=volumes,
69
- unencrypted_ports=[22], # Forward SSH port
70
- secrets=[modal.Secret.from_dict({"SSH_PUBLIC_KEY": os.environ.get("SSH_PUBLIC_KEY")})],
71
- )
72
- hostname, port = sb.tunnels()[22].tcp_socket
73
- connection_cmd = f"ssh -A -p {port} root@{hostname}"
74
-
75
- rich.print(
76
- rich.rule.Rule(style="yellow"),
77
- rich.panel.Panel(
78
- f"""Your instance is ready! You can SSH into it using the following command:
79
-
80
- [dim gray]>[/dim gray] [bold cyan]{connection_cmd}[/bold cyan]
81
-
82
- [italic]Details:[/italic]
83
- • Name: [magenta]{app.description}[/magenta]
84
- • CPU: [yellow]{args.get("cpu")} cores[/yellow]
85
- • Memory: [yellow]{args.get("memory")} MiB[/yellow]
86
- • Timeout: [yellow]{args.get("timeout")} seconds[/yellow]
87
- • GPU: [green]{(args.get("gpu") or "N/A").upper()}[/green]""",
88
- title="SSH Connection",
89
- expand=False,
90
- ),
91
- rich.rule.Rule(style="yellow"),
92
- )
93
-
94
- sys.exit(0) # Exit immediately to prevent "Timed out waiting for final apps log."
@@ -1,95 +0,0 @@
1
- # Copyright Modal Labs 2025
2
- # type: ignore
3
- import json
4
- import os
5
- import secrets
6
- import socket
7
- import subprocess
8
- import threading
9
- import time
10
- import webbrowser
11
- from typing import Any
12
-
13
- from modal import App, Image, Queue, Secret, Volume, forward
14
-
15
- # Args injected by `modal launch` CLI.
16
- args: dict[str, Any] = json.loads(os.environ.get("MODAL_LAUNCH_ARGS", "{}"))
17
-
18
- app = App()
19
-
20
- image = Image.from_registry(args.get("image"), add_python=args.get("add_python")).uv_pip_install("marimo")
21
-
22
- # Optional host-filesystem mount (read-only snapshot of your project, useful for editing)
23
- if args.get("mount"):
24
- image = image.add_local_dir(args["mount"], remote_path="/root/marimo/mount")
25
-
26
- # Optional persistent Modal volume
27
- volume = Volume.from_name(args["volume"], create_if_missing=True) if args.get("volume") else None
28
- volumes = {"/root/marimo/volume": volume} if volume else {}
29
-
30
-
31
- def _wait_for_port(url: str, q: Queue) -> None:
32
- start = time.monotonic()
33
- while True:
34
- try:
35
- with socket.create_connection(("localhost", 8888), timeout=30):
36
- break
37
- except OSError as exc:
38
- if time.monotonic() - start > 30:
39
- raise TimeoutError("marimo server did not start within 30 s") from exc
40
- time.sleep(0.05)
41
- q.put(url)
42
-
43
-
44
- @app.function(
45
- image=image,
46
- cpu=args.get("cpu"),
47
- memory=args.get("memory"),
48
- gpu=args.get("gpu"),
49
- timeout=args.get("timeout", 3600),
50
- secrets=[Secret.from_dict({"MODAL_LAUNCH_ARGS": json.dumps(args)})],
51
- volumes=volumes,
52
- max_containers=1 if volume else None,
53
- )
54
- def run_marimo(q: Queue):
55
- os.makedirs("/root/marimo", exist_ok=True)
56
-
57
- # marimo supports token-based auth; generate one so only you can connect
58
- token = secrets.token_urlsafe(12)
59
-
60
- with forward(8888) as tunnel:
61
- url = f"{tunnel.url}/?access_token={token}"
62
- threading.Thread(target=_wait_for_port, args=(url, q), daemon=True).start()
63
-
64
- print("\nmarimo on Modal, opening in browser …")
65
- print(f" -> {url}\n")
66
-
67
- # Launch the headless edit server
68
- subprocess.run(
69
- [
70
- "marimo",
71
- "edit",
72
- "--headless", # don't open browser in container
73
- "--host",
74
- "0.0.0.0", # bind all interfaces
75
- "--port",
76
- "8888",
77
- "--token-password",
78
- token, # enable session-based auth
79
- "--skip-update-check",
80
- "/root/marimo", # workspace directory
81
- ],
82
- env={**os.environ, "SHELL": "/bin/bash"},
83
- )
84
-
85
- q.put("done")
86
-
87
-
88
- @app.local_entrypoint()
89
- def main():
90
- with Queue.ephemeral() as q:
91
- run_marimo.spawn(q)
92
- url = q.get() # first message = connect URL
93
- time.sleep(1) # give server a heartbeat
94
- webbrowser.open(url)
95
- assert q.get() == "done"