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.
Files changed (80) hide show
  1. snowflake/cli_sandbox/__init__.py +13 -0
  2. snowflake/cli_sandbox/_adapter.py +170 -0
  3. snowflake/cli_sandbox/_common.py +77 -0
  4. snowflake/cli_sandbox/_egress_flags.py +121 -0
  5. snowflake/cli_sandbox/_get_command.py +109 -0
  6. snowflake/cli_sandbox/_run_command.py +1091 -0
  7. snowflake/cli_sandbox/_shell_command.py +666 -0
  8. snowflake/cli_sandbox/_upload_plan.py +187 -0
  9. snowflake/cli_sandbox/commands.py +556 -0
  10. snowflake/cli_sandbox/plugin_spec.py +28 -0
  11. snowflake/cli_sandbox/py.typed +0 -0
  12. snowflake/sandbox/__init__.py +317 -0
  13. snowflake/sandbox/__main__.py +225 -0
  14. snowflake/sandbox/_ansi.py +206 -0
  15. snowflake/sandbox/_args.py +208 -0
  16. snowflake/sandbox/_assemble.py +256 -0
  17. snowflake/sandbox/_bundle.py +240 -0
  18. snowflake/sandbox/_connection_resolve.py +328 -0
  19. snowflake/sandbox/_deploy_spec.py +56 -0
  20. snowflake/sandbox/_diagnostics.py +501 -0
  21. snowflake/sandbox/_env.py +143 -0
  22. snowflake/sandbox/_files_mixin.py +280 -0
  23. snowflake/sandbox/_fs_ops.py +304 -0
  24. snowflake/sandbox/_globs.py +176 -0
  25. snowflake/sandbox/_hosts.py +110 -0
  26. snowflake/sandbox/_mcp_discovery.py +288 -0
  27. snowflake/sandbox/_mcp_status.py +183 -0
  28. snowflake/sandbox/_retry.py +94 -0
  29. snowflake/sandbox/_runtime/__init__.py +42 -0
  30. snowflake/sandbox/_runtime/_fs_helper.py +93 -0
  31. snowflake/sandbox/_runtime/_job_runner.py +111 -0
  32. snowflake/sandbox/_runtime/_protocol.py +53 -0
  33. snowflake/sandbox/_runtime/_shims.py +267 -0
  34. snowflake/sandbox/_sandbox_state.py +303 -0
  35. snowflake/sandbox/_session_registry.py +222 -0
  36. snowflake/sandbox/_sse.py +160 -0
  37. snowflake/sandbox/_stage.py +270 -0
  38. snowflake/sandbox/_sync_files_mixin.py +272 -0
  39. snowflake/sandbox/_sync_fs_ops.py +185 -0
  40. snowflake/sandbox/_sync_transport.py +737 -0
  41. snowflake/sandbox/_sync_watch.py +99 -0
  42. snowflake/sandbox/_transport.py +1366 -0
  43. snowflake/sandbox/_transport_errors.py +270 -0
  44. snowflake/sandbox/_upload_plan.py +497 -0
  45. snowflake/sandbox/_version.py +37 -0
  46. snowflake/sandbox/_watch.py +164 -0
  47. snowflake/sandbox/_wire.py +348 -0
  48. snowflake/sandbox/app.py +256 -0
  49. snowflake/sandbox/client.py +2356 -0
  50. snowflake/sandbox/config.py +1133 -0
  51. snowflake/sandbox/connect.py +288 -0
  52. snowflake/sandbox/deploy.py +499 -0
  53. snowflake/sandbox/egress.py +388 -0
  54. snowflake/sandbox/exceptions.py +253 -0
  55. snowflake/sandbox/exec_stream.py +264 -0
  56. snowflake/sandbox/files.py +547 -0
  57. snowflake/sandbox/function.py +567 -0
  58. snowflake/sandbox/image.py +46 -0
  59. snowflake/sandbox/jobs.py +649 -0
  60. snowflake/sandbox/lifecycle.py +67 -0
  61. snowflake/sandbox/log_stream.py +219 -0
  62. snowflake/sandbox/mcp.py +480 -0
  63. snowflake/sandbox/mount.py +161 -0
  64. snowflake/sandbox/py.typed +0 -0
  65. snowflake/sandbox/secret.py +244 -0
  66. snowflake/sandbox/session_app.py +244 -0
  67. snowflake/sandbox/shell.py +556 -0
  68. snowflake/sandbox/sync_client.py +2245 -0
  69. snowflake/sandbox/sync_exec_stream.py +238 -0
  70. snowflake/sandbox/sync_files.py +377 -0
  71. snowflake/sandbox/sync_log_stream.py +142 -0
  72. snowflake/sandbox/sync_shell.py +413 -0
  73. snowflake/sandbox/types.py +193 -0
  74. snowflake/sandbox/warm_session.py +700 -0
  75. snowflake_sandbox_python-0.2.1a1.dist-info/METADATA +339 -0
  76. snowflake_sandbox_python-0.2.1a1.dist-info/RECORD +80 -0
  77. snowflake_sandbox_python-0.2.1a1.dist-info/WHEEL +5 -0
  78. snowflake_sandbox_python-0.2.1a1.dist-info/entry_points.txt +2 -0
  79. snowflake_sandbox_python-0.2.1a1.dist-info/licenses/LICENSE +202 -0
  80. 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)