modAL 1.0.1__tar.gz → 1.0.1.dev0__tar.gz
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-1.0.1 → modal-1.0.1.dev0}/PKG-INFO +1 -1
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_output.py +6 -15
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/cli/app.py +2 -4
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/cli/cluster.py +1 -2
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/cli/container.py +1 -2
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/cli/dict.py +1 -2
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/cli/network_file_system.py +1 -2
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/cli/queues.py +1 -2
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/cli/secret.py +1 -2
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/cli/utils.py +15 -5
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/cli/volume.py +3 -4
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/client.py +2 -3
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/client.pyi +10 -2
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/functions.pyi +6 -6
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/image.py +0 -3
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/image.pyi +0 -2
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/sandbox.py +4 -1
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/snapshot.py +3 -9
- {modal-1.0.1 → modal-1.0.1.dev0}/modal.egg-info/PKG-INFO +1 -1
- {modal-1.0.1 → modal-1.0.1.dev0}/modal.egg-info/SOURCES.txt +0 -1
- {modal-1.0.1 → modal-1.0.1.dev0}/modal_version/__init__.py +1 -1
- modal-1.0.1/modal/_utils/time_utils.py +0 -15
- {modal-1.0.1 → modal-1.0.1.dev0}/LICENSE +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/README.md +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/__init__.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/__main__.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_clustered_functions.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_clustered_functions.pyi +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_container_entrypoint.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_functions.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_ipython.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_location.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_object.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_partial_function.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_pty.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_resolver.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_resources.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_runtime/__init__.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_runtime/asgi.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_runtime/container_io_manager.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_runtime/container_io_manager.pyi +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_runtime/execution_context.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_runtime/execution_context.pyi +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_runtime/gpu_memory_snapshot.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_runtime/telemetry.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_runtime/user_code_imports.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_serialization.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_traceback.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_tunnel.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_tunnel.pyi +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_type_manager.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_utils/__init__.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_utils/app_utils.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_utils/async_utils.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_utils/blob_utils.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_utils/bytes_io_segment_payload.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_utils/deprecation.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_utils/docker_utils.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_utils/function_utils.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_utils/git_utils.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_utils/grpc_testing.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_utils/grpc_utils.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_utils/hash_utils.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_utils/http_utils.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_utils/jwt_utils.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_utils/logger.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_utils/mount_utils.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_utils/name_utils.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_utils/package_utils.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_utils/pattern_utils.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_utils/rand_pb_testing.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_utils/shell_utils.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_vendor/__init__.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_vendor/a2wsgi_wsgi.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_vendor/cloudpickle.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_vendor/tblib.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/_watcher.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/app.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/app.pyi +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/call_graph.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/cli/__init__.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/cli/_download.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/cli/_traceback.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/cli/config.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/cli/entry_point.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/cli/environment.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/cli/import_refs.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/cli/launch.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/cli/profile.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/cli/programs/__init__.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/cli/programs/run_jupyter.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/cli/programs/vscode.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/cli/run.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/cli/token.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/cloud_bucket_mount.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/cloud_bucket_mount.pyi +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/cls.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/cls.pyi +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/config.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/container_process.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/container_process.pyi +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/dict.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/dict.pyi +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/environments.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/environments.pyi +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/exception.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/experimental/__init__.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/experimental/ipython.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/file_io.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/file_io.pyi +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/file_pattern_matcher.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/functions.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/gpu.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/io_streams.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/io_streams.pyi +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/mount.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/mount.pyi +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/network_file_system.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/network_file_system.pyi +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/object.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/object.pyi +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/output.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/parallel_map.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/parallel_map.pyi +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/partial_function.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/partial_function.pyi +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/proxy.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/proxy.pyi +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/py.typed +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/queue.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/queue.pyi +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/requirements/2023.12.312.txt +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/requirements/2023.12.txt +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/requirements/2024.04.txt +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/requirements/2024.10.txt +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/requirements/PREVIEW.txt +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/requirements/README.md +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/requirements/base-images.json +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/retries.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/runner.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/runner.pyi +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/running_app.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/sandbox.pyi +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/schedule.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/scheduler_placement.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/secret.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/secret.pyi +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/serving.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/serving.pyi +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/snapshot.pyi +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/stream_type.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/token_flow.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/token_flow.pyi +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/volume.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal/volume.pyi +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal.egg-info/dependency_links.txt +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal.egg-info/entry_points.txt +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal.egg-info/requires.txt +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal.egg-info/top_level.txt +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal_docs/__init__.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal_docs/gen_cli_docs.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal_docs/gen_reference_docs.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal_docs/mdmd/__init__.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal_docs/mdmd/mdmd.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal_docs/mdmd/signatures.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal_proto/__init__.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal_proto/api.proto +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal_proto/api_grpc.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal_proto/api_pb2.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal_proto/api_pb2.pyi +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal_proto/api_pb2_grpc.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal_proto/api_pb2_grpc.pyi +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal_proto/modal_api_grpc.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal_proto/modal_options_grpc.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal_proto/options.proto +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal_proto/options_grpc.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal_proto/options_pb2.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal_proto/options_pb2.pyi +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal_proto/options_pb2_grpc.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal_proto/options_pb2_grpc.pyi +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal_proto/py.typed +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/modal_version/__main__.py +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/pyproject.toml +0 -0
- {modal-1.0.1 → modal-1.0.1.dev0}/setup.cfg +0 -0
|
@@ -32,7 +32,6 @@ from rich.progress import (
|
|
|
32
32
|
from rich.spinner import Spinner
|
|
33
33
|
from rich.text import Text
|
|
34
34
|
|
|
35
|
-
from modal._utils.time_utils import timestamp_to_local
|
|
36
35
|
from modal_proto import api_pb2
|
|
37
36
|
|
|
38
37
|
from ._utils.grpc_utils import RETRYABLE_GRPC_STATUS_CODES, retry_transient_errors
|
|
@@ -82,27 +81,22 @@ def download_progress_bar() -> Progress:
|
|
|
82
81
|
)
|
|
83
82
|
|
|
84
83
|
|
|
85
|
-
class LineBufferedOutput:
|
|
84
|
+
class LineBufferedOutput(io.StringIO):
|
|
86
85
|
"""Output stream that buffers lines and passes them to a callback."""
|
|
87
86
|
|
|
88
87
|
LINE_REGEX = re.compile("(\r\n|\r|\n)")
|
|
89
88
|
|
|
90
|
-
def __init__(self, callback: Callable[[str], None]
|
|
89
|
+
def __init__(self, callback: Callable[[str], None]):
|
|
91
90
|
self._callback = callback
|
|
92
91
|
self._buf = ""
|
|
93
|
-
self._show_timestamps = show_timestamps
|
|
94
92
|
|
|
95
|
-
def write(self,
|
|
96
|
-
chunks = self.LINE_REGEX.split(self._buf +
|
|
93
|
+
def write(self, data: str):
|
|
94
|
+
chunks = self.LINE_REGEX.split(self._buf + data)
|
|
97
95
|
|
|
98
96
|
# re.split("(<exp>)") returns the matched groups, and also the separators.
|
|
99
97
|
# e.g. re.split("(+)", "a+b") returns ["a", "+", "b"].
|
|
100
98
|
# This means that chunks is guaranteed to be odd in length.
|
|
101
99
|
|
|
102
|
-
if self._show_timestamps:
|
|
103
|
-
for i in range(0, len(chunks) - 1, 2):
|
|
104
|
-
chunks[i] = f"{timestamp_to_local(log.timestamp)} {chunks[i]}"
|
|
105
|
-
|
|
106
100
|
completed_lines = "".join(chunks[:-1])
|
|
107
101
|
remainder = chunks[-1]
|
|
108
102
|
|
|
@@ -142,14 +136,12 @@ class OutputManager:
|
|
|
142
136
|
_app_page_url: str | None
|
|
143
137
|
_show_image_logs: bool
|
|
144
138
|
_status_spinner_live: Live | None
|
|
145
|
-
_show_timestamps: bool
|
|
146
139
|
|
|
147
140
|
def __init__(
|
|
148
141
|
self,
|
|
149
142
|
*,
|
|
150
143
|
stdout: io.TextIOWrapper | None = None,
|
|
151
144
|
status_spinner_text: str = "Running app...",
|
|
152
|
-
show_timestamps: bool = False,
|
|
153
145
|
):
|
|
154
146
|
self._stdout = stdout or sys.stdout
|
|
155
147
|
self._console = Console(file=stdout, highlight=False)
|
|
@@ -164,7 +156,6 @@ class OutputManager:
|
|
|
164
156
|
self._app_page_url = None
|
|
165
157
|
self._show_image_logs = False
|
|
166
158
|
self._status_spinner_live = None
|
|
167
|
-
self._show_timestamps = show_timestamps
|
|
168
159
|
|
|
169
160
|
@classmethod
|
|
170
161
|
def disable(cls):
|
|
@@ -364,9 +355,9 @@ class OutputManager:
|
|
|
364
355
|
async def put_log_content(self, log: api_pb2.TaskLogs):
|
|
365
356
|
stream = self._line_buffers.get(log.file_descriptor)
|
|
366
357
|
if stream is None:
|
|
367
|
-
stream = LineBufferedOutput(functools.partial(self._print_log, log.file_descriptor)
|
|
358
|
+
stream = LineBufferedOutput(functools.partial(self._print_log, log.file_descriptor))
|
|
368
359
|
self._line_buffers[log.file_descriptor] = stream
|
|
369
|
-
stream.write(log)
|
|
360
|
+
stream.write(log.data)
|
|
370
361
|
|
|
371
362
|
def flush_lines(self):
|
|
372
363
|
for stream in self._line_buffers.values():
|
|
@@ -15,8 +15,7 @@ from modal.client import _Client
|
|
|
15
15
|
from modal.environments import ensure_env
|
|
16
16
|
from modal_proto import api_pb2
|
|
17
17
|
|
|
18
|
-
from
|
|
19
|
-
from .utils import ENV_OPTION, display_table, get_app_id_from_name, stream_app_logs
|
|
18
|
+
from .utils import ENV_OPTION, display_table, get_app_id_from_name, stream_app_logs, timestamp_to_local
|
|
20
19
|
|
|
21
20
|
APP_IDENTIFIER = Argument("", help="App name or ID")
|
|
22
21
|
NAME_OPTION = typer.Option("", "-n", "--name", help="Deprecated: Pass App name as a positional argument")
|
|
@@ -85,7 +84,6 @@ def logs(
|
|
|
85
84
|
app_identifier: str = APP_IDENTIFIER,
|
|
86
85
|
*,
|
|
87
86
|
env: Optional[str] = ENV_OPTION,
|
|
88
|
-
timestamps: bool = typer.Option(False, "--timestamps", help="Show timestamps for each log line"),
|
|
89
87
|
):
|
|
90
88
|
"""Show App logs, streaming while active.
|
|
91
89
|
|
|
@@ -105,7 +103,7 @@ def logs(
|
|
|
105
103
|
|
|
106
104
|
"""
|
|
107
105
|
app_id = get_app_id(app_identifier, env)
|
|
108
|
-
stream_app_logs(app_id
|
|
106
|
+
stream_app_logs(app_id)
|
|
109
107
|
|
|
110
108
|
|
|
111
109
|
@app_cli.command("rollback", no_args_is_help=True, context_settings={"ignore_unknown_options": True})
|
|
@@ -8,8 +8,7 @@ from rich.text import Text
|
|
|
8
8
|
from modal._object import _get_environment_name
|
|
9
9
|
from modal._pty import get_pty_info
|
|
10
10
|
from modal._utils.async_utils import synchronizer
|
|
11
|
-
from modal.
|
|
12
|
-
from modal.cli.utils import ENV_OPTION, display_table, is_tty
|
|
11
|
+
from modal.cli.utils import ENV_OPTION, display_table, is_tty, timestamp_to_local
|
|
13
12
|
from modal.client import _Client
|
|
14
13
|
from modal.config import config
|
|
15
14
|
from modal.container_process import _ContainerProcess
|
|
@@ -8,8 +8,7 @@ from modal._object import _get_environment_name
|
|
|
8
8
|
from modal._pty import get_pty_info
|
|
9
9
|
from modal._utils.async_utils import synchronizer
|
|
10
10
|
from modal._utils.grpc_utils import retry_transient_errors
|
|
11
|
-
from modal.
|
|
12
|
-
from modal.cli.utils import ENV_OPTION, display_table, is_tty, stream_app_logs
|
|
11
|
+
from modal.cli.utils import ENV_OPTION, display_table, is_tty, stream_app_logs, timestamp_to_local
|
|
13
12
|
from modal.client import _Client
|
|
14
13
|
from modal.config import config
|
|
15
14
|
from modal.container_process import _ContainerProcess
|
|
@@ -8,8 +8,7 @@ from typer import Argument, Option, Typer
|
|
|
8
8
|
from modal._resolver import Resolver
|
|
9
9
|
from modal._utils.async_utils import synchronizer
|
|
10
10
|
from modal._utils.grpc_utils import retry_transient_errors
|
|
11
|
-
from modal.
|
|
12
|
-
from modal.cli.utils import ENV_OPTION, YES_OPTION, display_table
|
|
11
|
+
from modal.cli.utils import ENV_OPTION, YES_OPTION, display_table, timestamp_to_local
|
|
13
12
|
from modal.client import _Client
|
|
14
13
|
from modal.dict import _Dict
|
|
15
14
|
from modal.environments import ensure_env
|
|
@@ -17,9 +17,8 @@ from modal._location import display_location
|
|
|
17
17
|
from modal._output import OutputManager, ProgressHandler
|
|
18
18
|
from modal._utils.async_utils import synchronizer
|
|
19
19
|
from modal._utils.grpc_utils import retry_transient_errors
|
|
20
|
-
from modal._utils.time_utils import timestamp_to_local
|
|
21
20
|
from modal.cli._download import _volume_download
|
|
22
|
-
from modal.cli.utils import ENV_OPTION, YES_OPTION, display_table
|
|
21
|
+
from modal.cli.utils import ENV_OPTION, YES_OPTION, display_table, timestamp_to_local
|
|
23
22
|
from modal.client import _Client
|
|
24
23
|
from modal.environments import ensure_env
|
|
25
24
|
from modal.network_file_system import _NetworkFileSystem
|
|
@@ -8,8 +8,7 @@ from typer import Argument, Option, Typer
|
|
|
8
8
|
from modal._resolver import Resolver
|
|
9
9
|
from modal._utils.async_utils import synchronizer
|
|
10
10
|
from modal._utils.grpc_utils import retry_transient_errors
|
|
11
|
-
from modal.
|
|
12
|
-
from modal.cli.utils import ENV_OPTION, YES_OPTION, display_table
|
|
11
|
+
from modal.cli.utils import ENV_OPTION, YES_OPTION, display_table, timestamp_to_local
|
|
13
12
|
from modal.client import _Client
|
|
14
13
|
from modal.environments import ensure_env
|
|
15
14
|
from modal.queue import _Queue
|
|
@@ -13,8 +13,7 @@ from typer import Argument
|
|
|
13
13
|
|
|
14
14
|
from modal._utils.async_utils import synchronizer
|
|
15
15
|
from modal._utils.grpc_utils import retry_transient_errors
|
|
16
|
-
from modal.
|
|
17
|
-
from modal.cli.utils import ENV_OPTION, YES_OPTION, display_table
|
|
16
|
+
from modal.cli.utils import ENV_OPTION, YES_OPTION, display_table, timestamp_to_local
|
|
18
17
|
from modal.client import _Client
|
|
19
18
|
from modal.environments import ensure_env
|
|
20
19
|
from modal.secret import _Secret
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# Copyright Modal Labs 2022
|
|
2
2
|
import asyncio
|
|
3
3
|
from collections.abc import Sequence
|
|
4
|
+
from datetime import datetime
|
|
4
5
|
from json import dumps
|
|
5
6
|
from typing import Optional, Union
|
|
6
7
|
|
|
@@ -22,13 +23,10 @@ from ..exception import NotFoundError
|
|
|
22
23
|
|
|
23
24
|
@synchronizer.create_blocking
|
|
24
25
|
async def stream_app_logs(
|
|
25
|
-
app_id: Optional[str] = None,
|
|
26
|
-
task_id: Optional[str] = None,
|
|
27
|
-
app_logs_url: Optional[str] = None,
|
|
28
|
-
show_timestamps: bool = False,
|
|
26
|
+
app_id: Optional[str] = None, task_id: Optional[str] = None, app_logs_url: Optional[str] = None
|
|
29
27
|
):
|
|
30
28
|
client = await _Client.from_env()
|
|
31
|
-
output_mgr = OutputManager(status_spinner_text=f"Tailing logs for {app_id}"
|
|
29
|
+
output_mgr = OutputManager(status_spinner_text=f"Tailing logs for {app_id}")
|
|
32
30
|
try:
|
|
33
31
|
with output_mgr.show_status_spinner():
|
|
34
32
|
await get_app_logs_loop(client, output_mgr, app_id=app_id, task_id=task_id, app_logs_url=app_logs_url)
|
|
@@ -63,6 +61,18 @@ async def get_app_id_from_name(name: str, env: Optional[str], client: Optional[_
|
|
|
63
61
|
return resp.app_id
|
|
64
62
|
|
|
65
63
|
|
|
64
|
+
def timestamp_to_local(ts: float, isotz: bool = True) -> str:
|
|
65
|
+
if ts > 0:
|
|
66
|
+
locale_tz = datetime.now().astimezone().tzinfo
|
|
67
|
+
dt = datetime.fromtimestamp(ts, tz=locale_tz)
|
|
68
|
+
if isotz:
|
|
69
|
+
return dt.isoformat(sep=" ", timespec="seconds")
|
|
70
|
+
else:
|
|
71
|
+
return f"{datetime.strftime(dt, '%Y-%m-%d %H:%M')} {locale_tz.tzname(dt)}"
|
|
72
|
+
else:
|
|
73
|
+
return None
|
|
74
|
+
|
|
75
|
+
|
|
66
76
|
def _plain(text: Union[Text, str]) -> str:
|
|
67
77
|
return text.plain if isinstance(text, Text) else text
|
|
68
78
|
|
|
@@ -15,9 +15,8 @@ import modal
|
|
|
15
15
|
from modal._output import OutputManager, ProgressHandler
|
|
16
16
|
from modal._utils.async_utils import synchronizer
|
|
17
17
|
from modal._utils.grpc_utils import retry_transient_errors
|
|
18
|
-
from modal._utils.time_utils import timestamp_to_local
|
|
19
18
|
from modal.cli._download import _volume_download
|
|
20
|
-
from modal.cli.utils import ENV_OPTION, YES_OPTION, display_table
|
|
19
|
+
from modal.cli.utils import ENV_OPTION, YES_OPTION, display_table, timestamp_to_local
|
|
21
20
|
from modal.client import _Client
|
|
22
21
|
from modal.environments import ensure_env
|
|
23
22
|
from modal.volume import _AbstractVolumeUploadContextManager, _Volume
|
|
@@ -204,7 +203,7 @@ async def put(
|
|
|
204
203
|
vol.object_id,
|
|
205
204
|
vol._client,
|
|
206
205
|
progress_cb=progress_handler.progress,
|
|
207
|
-
force=force
|
|
206
|
+
force=force
|
|
208
207
|
) as batch:
|
|
209
208
|
batch.put_directory(local_path, remote_path)
|
|
210
209
|
except FileExistsError as exc:
|
|
@@ -220,7 +219,7 @@ async def put(
|
|
|
220
219
|
vol.object_id,
|
|
221
220
|
vol._client,
|
|
222
221
|
progress_cb=progress_handler.progress,
|
|
223
|
-
force=force
|
|
222
|
+
force=force
|
|
224
223
|
) as batch:
|
|
225
224
|
batch.put_file(local_path, remote_path)
|
|
226
225
|
|
|
@@ -3,7 +3,6 @@ import asyncio
|
|
|
3
3
|
import os
|
|
4
4
|
import platform
|
|
5
5
|
import sys
|
|
6
|
-
import urllib.parse
|
|
7
6
|
import warnings
|
|
8
7
|
from collections.abc import AsyncGenerator, AsyncIterator, Collection, Mapping
|
|
9
8
|
from typing import (
|
|
@@ -51,8 +50,8 @@ def _get_metadata(client_type: int, credentials: Optional[tuple[str, str]], vers
|
|
|
51
50
|
"x-modal-client-version": version,
|
|
52
51
|
"x-modal-client-type": str(client_type),
|
|
53
52
|
"x-modal-python-version": python_version,
|
|
54
|
-
"x-modal-node":
|
|
55
|
-
"x-modal-platform":
|
|
53
|
+
"x-modal-node": platform.node(),
|
|
54
|
+
"x-modal-platform": platform_str,
|
|
56
55
|
}
|
|
57
56
|
if credentials and client_type == api_pb2.CLIENT_TYPE_CLIENT:
|
|
58
57
|
token_id, token_secret = credentials
|
|
@@ -27,7 +27,11 @@ class _Client:
|
|
|
27
27
|
_snapshotted: bool
|
|
28
28
|
|
|
29
29
|
def __init__(
|
|
30
|
-
self,
|
|
30
|
+
self,
|
|
31
|
+
server_url: str,
|
|
32
|
+
client_type: int,
|
|
33
|
+
credentials: typing.Optional[tuple[str, str]],
|
|
34
|
+
version: str = "1.0.1.dev0",
|
|
31
35
|
): ...
|
|
32
36
|
def is_closed(self) -> bool: ...
|
|
33
37
|
@property
|
|
@@ -86,7 +90,11 @@ class Client:
|
|
|
86
90
|
_snapshotted: bool
|
|
87
91
|
|
|
88
92
|
def __init__(
|
|
89
|
-
self,
|
|
93
|
+
self,
|
|
94
|
+
server_url: str,
|
|
95
|
+
client_type: int,
|
|
96
|
+
credentials: typing.Optional[tuple[str, str]],
|
|
97
|
+
version: str = "1.0.1.dev0",
|
|
90
98
|
): ...
|
|
91
99
|
def is_closed(self) -> bool: ...
|
|
92
100
|
@property
|
|
@@ -227,11 +227,11 @@ class Function(
|
|
|
227
227
|
|
|
228
228
|
_call_generator: ___call_generator_spec[typing_extensions.Self]
|
|
229
229
|
|
|
230
|
-
class __remote_spec(typing_extensions.Protocol[
|
|
230
|
+
class __remote_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
|
|
231
231
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER: ...
|
|
232
232
|
async def aio(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER: ...
|
|
233
233
|
|
|
234
|
-
remote: __remote_spec[modal._functions.
|
|
234
|
+
remote: __remote_spec[modal._functions.ReturnType, modal._functions.P, typing_extensions.Self]
|
|
235
235
|
|
|
236
236
|
class __remote_gen_spec(typing_extensions.Protocol[SUPERSELF]):
|
|
237
237
|
def __call__(self, /, *args, **kwargs) -> typing.Generator[typing.Any, None, None]: ...
|
|
@@ -246,12 +246,12 @@ class Function(
|
|
|
246
246
|
self, *args: modal._functions.P.args, **kwargs: modal._functions.P.kwargs
|
|
247
247
|
) -> modal._functions.OriginalReturnType: ...
|
|
248
248
|
|
|
249
|
-
class ___experimental_spawn_spec(typing_extensions.Protocol[
|
|
249
|
+
class ___experimental_spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
|
|
250
250
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]: ...
|
|
251
251
|
async def aio(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]: ...
|
|
252
252
|
|
|
253
253
|
_experimental_spawn: ___experimental_spawn_spec[
|
|
254
|
-
modal._functions.
|
|
254
|
+
modal._functions.ReturnType, modal._functions.P, typing_extensions.Self
|
|
255
255
|
]
|
|
256
256
|
|
|
257
257
|
class ___spawn_map_inner_spec(typing_extensions.Protocol[P_INNER, SUPERSELF]):
|
|
@@ -260,11 +260,11 @@ class Function(
|
|
|
260
260
|
|
|
261
261
|
_spawn_map_inner: ___spawn_map_inner_spec[modal._functions.P, typing_extensions.Self]
|
|
262
262
|
|
|
263
|
-
class __spawn_spec(typing_extensions.Protocol[
|
|
263
|
+
class __spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
|
|
264
264
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]: ...
|
|
265
265
|
async def aio(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]: ...
|
|
266
266
|
|
|
267
|
-
spawn: __spawn_spec[modal._functions.
|
|
267
|
+
spawn: __spawn_spec[modal._functions.ReturnType, modal._functions.P, typing_extensions.Self]
|
|
268
268
|
|
|
269
269
|
def get_raw_f(self) -> collections.abc.Callable[..., typing.Any]: ...
|
|
270
270
|
|
|
@@ -423,9 +423,6 @@ class _Image(_Object, type_prefix="im"):
|
|
|
423
423
|
self._deferred_mounts = other._deferred_mounts
|
|
424
424
|
self._added_python_source_set = other._added_python_source_set
|
|
425
425
|
|
|
426
|
-
def _get_metadata(self) -> Optional[Message]:
|
|
427
|
-
return self._metadata
|
|
428
|
-
|
|
429
426
|
def _hydrate_metadata(self, metadata: Optional[Message]):
|
|
430
427
|
env_image_id = config.get("image_id") # set as an env var in containers
|
|
431
428
|
if env_image_id == self.object_id:
|
|
@@ -96,7 +96,6 @@ class _Image(modal._object._Object):
|
|
|
96
96
|
|
|
97
97
|
def _initialize_from_empty(self): ...
|
|
98
98
|
def _initialize_from_other(self, other: _Image): ...
|
|
99
|
-
def _get_metadata(self) -> typing.Optional[google.protobuf.message.Message]: ...
|
|
100
99
|
def _hydrate_metadata(self, metadata: typing.Optional[google.protobuf.message.Message]): ...
|
|
101
100
|
def _add_mount_layer_or_copy(self, mount: modal.mount._Mount, copy: bool = False): ...
|
|
102
101
|
@property
|
|
@@ -353,7 +352,6 @@ class Image(modal.object.Object):
|
|
|
353
352
|
def __init__(self, *args, **kwargs): ...
|
|
354
353
|
def _initialize_from_empty(self): ...
|
|
355
354
|
def _initialize_from_other(self, other: Image): ...
|
|
356
|
-
def _get_metadata(self) -> typing.Optional[google.protobuf.message.Message]: ...
|
|
357
355
|
def _hydrate_metadata(self, metadata: typing.Optional[google.protobuf.message.Message]): ...
|
|
358
356
|
def _add_mount_layer_or_copy(self, mount: modal.mount.Mount, copy: bool = False): ...
|
|
359
357
|
@property
|
|
@@ -738,7 +738,10 @@ class _Sandbox(_Object, type_prefix="sb"):
|
|
|
738
738
|
recursive: Optional[bool] = None,
|
|
739
739
|
timeout: Optional[int] = None,
|
|
740
740
|
) -> AsyncIterator[FileWatchEvent]:
|
|
741
|
-
"""Watch a file or directory in the Sandbox for changes.
|
|
741
|
+
"""Watch a file or directory in the Sandbox for changes.
|
|
742
|
+
|
|
743
|
+
See the [guide](/docs/guide/sandbox-files#file-watching) for usage information.
|
|
744
|
+
"""
|
|
742
745
|
task_id = await self._get_task_id()
|
|
743
746
|
async for event in _FileIO.watch(path, self._client, task_id, filter, recursive, timeout):
|
|
744
747
|
yield event
|
|
@@ -11,19 +11,13 @@ from .client import _Client
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
class _SandboxSnapshot(_Object, type_prefix="sn"):
|
|
14
|
-
"""
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
A `SandboxSnapshot` object lets you interact with a stored Sandbox snapshot that was created by calling
|
|
18
|
-
`._experimental_snapshot()` on a Sandbox instance. This includes both the filesystem and memory state of
|
|
19
|
-
the original Sandbox at the time the snapshot was taken.
|
|
14
|
+
"""A `SandboxSnapshot` object lets you interact with a stored Sandbox snapshot that was created by calling
|
|
15
|
+
.snapshot() on a Sandbox instance. This includes both the filesystem and memory state of the original Sandbox at the
|
|
16
|
+
time the snapshot was taken.
|
|
20
17
|
"""
|
|
21
18
|
|
|
22
19
|
@staticmethod
|
|
23
20
|
async def from_id(sandbox_snapshot_id: str, client: Optional[_Client] = None):
|
|
24
|
-
"""
|
|
25
|
-
Construct a `SandboxSnapshot` object from a sandbox snapshot ID.
|
|
26
|
-
"""
|
|
27
21
|
if client is None:
|
|
28
22
|
client = await _Client.from_env()
|
|
29
23
|
|
|
@@ -119,7 +119,6 @@ modal/_utils/package_utils.py
|
|
|
119
119
|
modal/_utils/pattern_utils.py
|
|
120
120
|
modal/_utils/rand_pb_testing.py
|
|
121
121
|
modal/_utils/shell_utils.py
|
|
122
|
-
modal/_utils/time_utils.py
|
|
123
122
|
modal/_vendor/__init__.py
|
|
124
123
|
modal/_vendor/a2wsgi_wsgi.py
|
|
125
124
|
modal/_vendor/cloudpickle.py
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
# Copyright Modal Labs 2025
|
|
2
|
-
from datetime import datetime
|
|
3
|
-
from typing import Optional
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def timestamp_to_local(ts: float, isotz: bool = True) -> Optional[str]:
|
|
7
|
-
if ts > 0:
|
|
8
|
-
locale_tz = datetime.now().astimezone().tzinfo
|
|
9
|
-
dt = datetime.fromtimestamp(ts, tz=locale_tz)
|
|
10
|
-
if isotz:
|
|
11
|
-
return dt.isoformat(sep=" ", timespec="seconds")
|
|
12
|
-
else:
|
|
13
|
-
return f"{datetime.strftime(dt, '%Y-%m-%d %H:%M')} {locale_tz.tzname(dt)}"
|
|
14
|
-
else:
|
|
15
|
-
return None
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|