snowflake-sandbox-python 0.2.1a1__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.
- snowflake/cli_sandbox/__init__.py +13 -0
- snowflake/cli_sandbox/_adapter.py +170 -0
- snowflake/cli_sandbox/_common.py +77 -0
- snowflake/cli_sandbox/_egress_flags.py +121 -0
- snowflake/cli_sandbox/_get_command.py +109 -0
- snowflake/cli_sandbox/_run_command.py +1091 -0
- snowflake/cli_sandbox/_shell_command.py +666 -0
- snowflake/cli_sandbox/_upload_plan.py +187 -0
- snowflake/cli_sandbox/commands.py +556 -0
- snowflake/cli_sandbox/plugin_spec.py +28 -0
- snowflake/cli_sandbox/py.typed +0 -0
- snowflake/sandbox/__init__.py +317 -0
- snowflake/sandbox/__main__.py +225 -0
- snowflake/sandbox/_ansi.py +206 -0
- snowflake/sandbox/_args.py +208 -0
- snowflake/sandbox/_assemble.py +256 -0
- snowflake/sandbox/_bundle.py +240 -0
- snowflake/sandbox/_connection_resolve.py +328 -0
- snowflake/sandbox/_deploy_spec.py +56 -0
- snowflake/sandbox/_diagnostics.py +501 -0
- snowflake/sandbox/_env.py +143 -0
- snowflake/sandbox/_files_mixin.py +280 -0
- snowflake/sandbox/_fs_ops.py +304 -0
- snowflake/sandbox/_globs.py +176 -0
- snowflake/sandbox/_hosts.py +110 -0
- snowflake/sandbox/_mcp_discovery.py +288 -0
- snowflake/sandbox/_mcp_status.py +183 -0
- snowflake/sandbox/_retry.py +94 -0
- snowflake/sandbox/_runtime/__init__.py +42 -0
- snowflake/sandbox/_runtime/_fs_helper.py +93 -0
- snowflake/sandbox/_runtime/_job_runner.py +111 -0
- snowflake/sandbox/_runtime/_protocol.py +53 -0
- snowflake/sandbox/_runtime/_shims.py +267 -0
- snowflake/sandbox/_sandbox_state.py +303 -0
- snowflake/sandbox/_session_registry.py +222 -0
- snowflake/sandbox/_sse.py +160 -0
- snowflake/sandbox/_stage.py +270 -0
- snowflake/sandbox/_sync_files_mixin.py +272 -0
- snowflake/sandbox/_sync_fs_ops.py +185 -0
- snowflake/sandbox/_sync_transport.py +737 -0
- snowflake/sandbox/_sync_watch.py +99 -0
- snowflake/sandbox/_transport.py +1366 -0
- snowflake/sandbox/_transport_errors.py +270 -0
- snowflake/sandbox/_upload_plan.py +497 -0
- snowflake/sandbox/_version.py +37 -0
- snowflake/sandbox/_watch.py +164 -0
- snowflake/sandbox/_wire.py +348 -0
- snowflake/sandbox/app.py +256 -0
- snowflake/sandbox/client.py +2356 -0
- snowflake/sandbox/config.py +1133 -0
- snowflake/sandbox/connect.py +288 -0
- snowflake/sandbox/deploy.py +499 -0
- snowflake/sandbox/egress.py +388 -0
- snowflake/sandbox/exceptions.py +253 -0
- snowflake/sandbox/exec_stream.py +264 -0
- snowflake/sandbox/files.py +547 -0
- snowflake/sandbox/function.py +567 -0
- snowflake/sandbox/image.py +46 -0
- snowflake/sandbox/jobs.py +649 -0
- snowflake/sandbox/lifecycle.py +67 -0
- snowflake/sandbox/log_stream.py +219 -0
- snowflake/sandbox/mcp.py +480 -0
- snowflake/sandbox/mount.py +161 -0
- snowflake/sandbox/py.typed +0 -0
- snowflake/sandbox/secret.py +244 -0
- snowflake/sandbox/session_app.py +244 -0
- snowflake/sandbox/shell.py +556 -0
- snowflake/sandbox/sync_client.py +2245 -0
- snowflake/sandbox/sync_exec_stream.py +238 -0
- snowflake/sandbox/sync_files.py +377 -0
- snowflake/sandbox/sync_log_stream.py +142 -0
- snowflake/sandbox/sync_shell.py +413 -0
- snowflake/sandbox/types.py +193 -0
- snowflake/sandbox/warm_session.py +700 -0
- snowflake_sandbox_python-0.2.1a1.dist-info/METADATA +339 -0
- snowflake_sandbox_python-0.2.1a1.dist-info/RECORD +80 -0
- snowflake_sandbox_python-0.2.1a1.dist-info/WHEEL +5 -0
- snowflake_sandbox_python-0.2.1a1.dist-info/entry_points.txt +2 -0
- snowflake_sandbox_python-0.2.1a1.dist-info/licenses/LICENSE +202 -0
- snowflake_sandbox_python-0.2.1a1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"""Sync filesystem change notifications — for ``Sandbox``.
|
|
2
|
+
|
|
3
|
+
Synchronous counterpart to `_watch`: the same ctypes ``inotify(7)`` monitor in the
|
|
4
|
+
container, streamed over the synchronous ``exec_stream``. See `_watch` for the
|
|
5
|
+
mechanism and its caveats.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import json
|
|
11
|
+
from typing import TYPE_CHECKING
|
|
12
|
+
|
|
13
|
+
# The in-container half is shared with the async side via _runtime; both modes
|
|
14
|
+
# ship the same program text and parse the same sentinel.
|
|
15
|
+
from snowflake.sandbox._runtime._fs_helper import _watch_program
|
|
16
|
+
from snowflake.sandbox._runtime._protocol import _WATCH_SENTINEL
|
|
17
|
+
from snowflake.sandbox._sync_transport import SyncTransport
|
|
18
|
+
from snowflake.sandbox._watch import _WATCH_WINDOW_S, _mask_to_event_type
|
|
19
|
+
from snowflake.sandbox.files import _require_absolute
|
|
20
|
+
from snowflake.sandbox.types import FileWatchEvent, FileWatchEventType
|
|
21
|
+
|
|
22
|
+
if TYPE_CHECKING:
|
|
23
|
+
from collections.abc import Iterator, Sequence
|
|
24
|
+
|
|
25
|
+
from snowflake.sandbox.sync_client import Sandbox
|
|
26
|
+
|
|
27
|
+
__all__ = ["watch"]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def watch(
|
|
31
|
+
sandbox: Sandbox,
|
|
32
|
+
path: str,
|
|
33
|
+
*,
|
|
34
|
+
filter: Sequence[FileWatchEventType] | None = None,
|
|
35
|
+
recursive: bool = False,
|
|
36
|
+
timeout: float | None = None,
|
|
37
|
+
transport: SyncTransport | None = None,
|
|
38
|
+
) -> Iterator[FileWatchEvent]:
|
|
39
|
+
"""Stream filesystem-change events under ``path`` — synchronous counterpart of
|
|
40
|
+
``_watch.watch``. A generator: ``for ev in sb.watch(...)``.
|
|
41
|
+
|
|
42
|
+
``path`` must be absolute. ``filter`` restricts the yielded
|
|
43
|
+
`FileWatchEventType`\\ s (``None`` = all). ``recursive`` also watches nested
|
|
44
|
+
subdirectories (and directories created later). ``timeout`` bounds the watch in
|
|
45
|
+
seconds; ``None`` watches until the caller stops iterating.
|
|
46
|
+
|
|
47
|
+
Runs the same ctypes ``inotify(7)`` monitor in the container as the async
|
|
48
|
+
version, over the synchronous ``exec_stream``, so the two clients behave the
|
|
49
|
+
same.
|
|
50
|
+
|
|
51
|
+
Caveats are the async ones, unchanged: one logical save commonly yields a
|
|
52
|
+
`Modify`, while atomic save-by-rename editors surface `Create`/`Delete` of a
|
|
53
|
+
temp plus a move; a large ``recursive`` watch consumes one kernel watch
|
|
54
|
+
descriptor per directory; and ``timeout=None`` is realised as a relaunch loop
|
|
55
|
+
of bounded windows, so events during the sub-second relaunch gap can be missed
|
|
56
|
+
(a bounded ``timeout`` runs as one stream and has no such gap).
|
|
57
|
+
"""
|
|
58
|
+
p = _require_absolute(path)
|
|
59
|
+
allowed = frozenset(filter) if filter else None
|
|
60
|
+
prog = _watch_program()
|
|
61
|
+
|
|
62
|
+
def _one_window(window_timeout: float | None) -> Iterator[FileWatchEvent]:
|
|
63
|
+
argv = [
|
|
64
|
+
"python3",
|
|
65
|
+
"-c",
|
|
66
|
+
prog,
|
|
67
|
+
p,
|
|
68
|
+
"1" if recursive else "0",
|
|
69
|
+
"" if window_timeout is None else repr(window_timeout),
|
|
70
|
+
]
|
|
71
|
+
stream = sandbox.exec_stream(argv, timeout=window_timeout)
|
|
72
|
+
for line in stream:
|
|
73
|
+
if line.stream != "stdout":
|
|
74
|
+
continue
|
|
75
|
+
idx = line.data.find(_WATCH_SENTINEL)
|
|
76
|
+
if idx == -1:
|
|
77
|
+
continue
|
|
78
|
+
payload = line.data[idx + len(_WATCH_SENTINEL) :]
|
|
79
|
+
if payload.startswith("READY"):
|
|
80
|
+
continue
|
|
81
|
+
try:
|
|
82
|
+
obj = json.loads(payload)
|
|
83
|
+
except ValueError:
|
|
84
|
+
continue
|
|
85
|
+
etype = _mask_to_event_type(int(obj.get("mask", 0)))
|
|
86
|
+
if allowed is not None and etype not in allowed:
|
|
87
|
+
continue
|
|
88
|
+
yield FileWatchEvent(paths=[str(obj.get("path", p))], type=etype)
|
|
89
|
+
|
|
90
|
+
if timeout is not None:
|
|
91
|
+
# Bounded: one stream, kept alive across GOAWAYs by exec_stream's resume.
|
|
92
|
+
yield from _one_window(timeout)
|
|
93
|
+
return
|
|
94
|
+
|
|
95
|
+
# Indefinite: relaunch bounded windows until the caller stops iterating.
|
|
96
|
+
# Breaking the for-loop closes this generator, which closes the stream and
|
|
97
|
+
# kills the in-container monitor.
|
|
98
|
+
while True:
|
|
99
|
+
yield from _one_window(_WATCH_WINDOW_S)
|