modal 1.0.6.dev46__tar.gz → 1.0.6.dev50__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.
Potentially problematic release.
This version of modal might be problematic. Click here for more details.
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/PKG-INFO +1 -1
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/cli/run.py +12 -6
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/client.pyi +2 -2
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/container_process.py +2 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/io_streams.py +19 -3
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/io_streams.pyi +7 -1
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/sandbox.py +2 -1
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal.egg-info/PKG-INFO +1 -1
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal_version/__init__.py +1 -1
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/LICENSE +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/README.md +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/__init__.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/__main__.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_clustered_functions.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_clustered_functions.pyi +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_container_entrypoint.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_functions.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_ipython.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_location.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_object.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_output.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_partial_function.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_pty.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_resolver.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_resources.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_runtime/__init__.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_runtime/asgi.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_runtime/container_io_manager.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_runtime/container_io_manager.pyi +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_runtime/execution_context.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_runtime/execution_context.pyi +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_runtime/gpu_memory_snapshot.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_runtime/telemetry.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_runtime/user_code_imports.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_serialization.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_traceback.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_tunnel.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_tunnel.pyi +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_type_manager.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_utils/__init__.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_utils/app_utils.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_utils/async_utils.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_utils/auth_token_manager.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_utils/blob_utils.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_utils/bytes_io_segment_payload.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_utils/deprecation.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_utils/docker_utils.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_utils/function_utils.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_utils/git_utils.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_utils/grpc_testing.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_utils/grpc_utils.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_utils/hash_utils.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_utils/http_utils.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_utils/jwt_utils.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_utils/logger.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_utils/mount_utils.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_utils/name_utils.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_utils/package_utils.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_utils/pattern_utils.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_utils/rand_pb_testing.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_utils/shell_utils.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_utils/time_utils.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_vendor/__init__.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_vendor/a2wsgi_wsgi.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_vendor/cloudpickle.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_vendor/tblib.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/_watcher.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/app.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/app.pyi +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/call_graph.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/cli/__init__.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/cli/_download.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/cli/_traceback.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/cli/app.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/cli/cluster.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/cli/config.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/cli/container.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/cli/dict.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/cli/entry_point.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/cli/environment.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/cli/import_refs.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/cli/launch.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/cli/network_file_system.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/cli/profile.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/cli/programs/__init__.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/cli/programs/run_jupyter.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/cli/programs/vscode.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/cli/queues.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/cli/secret.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/cli/token.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/cli/utils.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/cli/volume.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/client.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/cloud_bucket_mount.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/cloud_bucket_mount.pyi +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/cls.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/cls.pyi +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/config.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/container_process.pyi +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/dict.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/dict.pyi +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/environments.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/environments.pyi +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/exception.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/experimental/__init__.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/experimental/flash.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/experimental/flash.pyi +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/experimental/ipython.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/file_io.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/file_io.pyi +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/file_pattern_matcher.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/functions.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/functions.pyi +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/gpu.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/image.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/image.pyi +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/mount.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/mount.pyi +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/network_file_system.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/network_file_system.pyi +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/object.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/object.pyi +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/output.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/parallel_map.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/parallel_map.pyi +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/partial_function.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/partial_function.pyi +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/proxy.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/proxy.pyi +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/py.typed +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/queue.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/queue.pyi +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/requirements/2023.12.312.txt +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/requirements/2023.12.txt +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/requirements/2024.04.txt +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/requirements/2024.10.txt +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/requirements/2025.06.txt +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/requirements/PREVIEW.txt +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/requirements/README.md +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/requirements/base-images.json +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/retries.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/runner.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/runner.pyi +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/running_app.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/sandbox.pyi +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/schedule.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/scheduler_placement.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/secret.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/secret.pyi +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/serving.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/serving.pyi +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/snapshot.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/snapshot.pyi +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/stream_type.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/token_flow.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/token_flow.pyi +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/volume.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal/volume.pyi +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal.egg-info/SOURCES.txt +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal.egg-info/dependency_links.txt +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal.egg-info/entry_points.txt +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal.egg-info/requires.txt +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal.egg-info/top_level.txt +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal_docs/__init__.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal_docs/gen_cli_docs.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal_docs/gen_reference_docs.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal_docs/mdmd/__init__.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal_docs/mdmd/mdmd.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal_docs/mdmd/signatures.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal_proto/__init__.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal_proto/api.proto +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal_proto/api_grpc.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal_proto/api_pb2.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal_proto/api_pb2.pyi +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal_proto/api_pb2_grpc.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal_proto/api_pb2_grpc.pyi +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal_proto/modal_api_grpc.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal_proto/modal_options_grpc.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal_proto/options.proto +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal_proto/options_grpc.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal_proto/options_pb2.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal_proto/options_pb2.pyi +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal_proto/options_pb2_grpc.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal_proto/options_pb2_grpc.pyi +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal_proto/py.typed +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/modal_version/__main__.py +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/pyproject.toml +0 -0
- {modal-1.0.6.dev46 → modal-1.0.6.dev50}/setup.cfg +0 -0
|
@@ -207,7 +207,7 @@ def _make_click_function(app, signature: CliRunnableSignature, inner: Callable[[
|
|
|
207
207
|
return f
|
|
208
208
|
|
|
209
209
|
|
|
210
|
-
def _get_click_command_for_function(app: App, function: Function):
|
|
210
|
+
def _get_click_command_for_function(app: App, function: Function, ctx: click.Context):
|
|
211
211
|
if function.is_generator:
|
|
212
212
|
raise InvalidError("`modal run` is not supported for generator functions")
|
|
213
213
|
|
|
@@ -216,7 +216,10 @@ def _get_click_command_for_function(app: App, function: Function):
|
|
|
216
216
|
signature: CliRunnableSignature = _get_cli_runnable_signature(sig, type_hints)
|
|
217
217
|
|
|
218
218
|
def _inner(args, click_kwargs):
|
|
219
|
-
|
|
219
|
+
if ctx.obj["detach"]:
|
|
220
|
+
return function.spawn(*args, **click_kwargs).get()
|
|
221
|
+
else:
|
|
222
|
+
return function.remote(*args, **click_kwargs)
|
|
220
223
|
|
|
221
224
|
f = _make_click_function(app, signature, _inner)
|
|
222
225
|
|
|
@@ -230,7 +233,7 @@ def _get_click_command_for_function(app: App, function: Function):
|
|
|
230
233
|
return click.command(with_click_options)
|
|
231
234
|
|
|
232
235
|
|
|
233
|
-
def _get_click_command_for_cls(app: App, method_ref: MethodReference):
|
|
236
|
+
def _get_click_command_for_cls(app: App, method_ref: MethodReference, ctx: click.Context):
|
|
234
237
|
parameters: dict[str, ParameterMetadata]
|
|
235
238
|
cls = method_ref.cls
|
|
236
239
|
method_name = method_ref.method_name
|
|
@@ -271,7 +274,10 @@ def _get_click_command_for_cls(app: App, method_ref: MethodReference):
|
|
|
271
274
|
|
|
272
275
|
instance = cls(**cls_kwargs)
|
|
273
276
|
method: Function = getattr(instance, method_name)
|
|
274
|
-
|
|
277
|
+
if ctx.obj["detach"]:
|
|
278
|
+
return method.spawn(*args, **fun_kwargs).get()
|
|
279
|
+
else:
|
|
280
|
+
return method.remote(*args, **fun_kwargs)
|
|
275
281
|
|
|
276
282
|
f = _make_click_function(app, fun_signature, _inner)
|
|
277
283
|
with_click_options = _add_click_options(f, parameters)
|
|
@@ -376,9 +382,9 @@ class RunGroup(click.Group):
|
|
|
376
382
|
if isinstance(runnable, LocalEntrypoint):
|
|
377
383
|
click_command = _get_click_command_for_local_entrypoint(app, runnable)
|
|
378
384
|
elif isinstance(runnable, Function):
|
|
379
|
-
click_command = _get_click_command_for_function(app, runnable)
|
|
385
|
+
click_command = _get_click_command_for_function(app, runnable, ctx)
|
|
380
386
|
elif isinstance(runnable, MethodReference):
|
|
381
|
-
click_command = _get_click_command_for_cls(app, runnable)
|
|
387
|
+
click_command = _get_click_command_for_cls(app, runnable, ctx)
|
|
382
388
|
else:
|
|
383
389
|
# This should be unreachable...
|
|
384
390
|
raise ValueError(f"{runnable} is neither function, local entrypoint or class/method")
|
|
@@ -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.0.6.
|
|
36
|
+
version: str = "1.0.6.dev50",
|
|
37
37
|
):
|
|
38
38
|
"""mdmd:hidden
|
|
39
39
|
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.0.6.
|
|
166
|
+
version: str = "1.0.6.dev50",
|
|
167
167
|
):
|
|
168
168
|
"""mdmd:hidden
|
|
169
169
|
The Modal client object is not intended to be instantiated directly by users.
|
|
@@ -50,6 +50,7 @@ class _ContainerProcess(Generic[T]):
|
|
|
50
50
|
stream_type=stdout,
|
|
51
51
|
text=text,
|
|
52
52
|
by_line=by_line,
|
|
53
|
+
deadline=exec_deadline,
|
|
53
54
|
)
|
|
54
55
|
self._stderr = _StreamReader[T](
|
|
55
56
|
api_pb2.FILE_DESCRIPTOR_STDERR,
|
|
@@ -59,6 +60,7 @@ class _ContainerProcess(Generic[T]):
|
|
|
59
60
|
stream_type=stderr,
|
|
60
61
|
text=text,
|
|
61
62
|
by_line=by_line,
|
|
63
|
+
deadline=exec_deadline,
|
|
62
64
|
)
|
|
63
65
|
self._stdin = _StreamWriter(process_id, "container_process", self._client)
|
|
64
66
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# Copyright Modal Labs 2022
|
|
2
2
|
import asyncio
|
|
3
|
+
import time
|
|
3
4
|
from collections.abc import AsyncGenerator, AsyncIterator
|
|
4
5
|
from typing import (
|
|
5
6
|
TYPE_CHECKING,
|
|
@@ -50,6 +51,7 @@ async def _container_process_logs_iterator(
|
|
|
50
51
|
file_descriptor: "api_pb2.FileDescriptor.ValueType",
|
|
51
52
|
client: _Client,
|
|
52
53
|
last_index: int,
|
|
54
|
+
deadline: Optional[float] = None,
|
|
53
55
|
) -> AsyncGenerator[tuple[Optional[bytes], int], None]:
|
|
54
56
|
req = api_pb2.ContainerExecGetOutputRequest(
|
|
55
57
|
exec_id=process_id,
|
|
@@ -58,7 +60,18 @@ async def _container_process_logs_iterator(
|
|
|
58
60
|
get_raw_bytes=True,
|
|
59
61
|
last_batch_index=last_index,
|
|
60
62
|
)
|
|
61
|
-
|
|
63
|
+
|
|
64
|
+
stream = client.stub.ContainerExecGetOutput.unary_stream(req)
|
|
65
|
+
while True:
|
|
66
|
+
# Check deadline before attempting to receive the next batch
|
|
67
|
+
try:
|
|
68
|
+
remaining = (deadline - time.monotonic()) if deadline else None
|
|
69
|
+
batch = await asyncio.wait_for(stream.__anext__(), timeout=remaining)
|
|
70
|
+
except asyncio.TimeoutError:
|
|
71
|
+
yield None, -1
|
|
72
|
+
break
|
|
73
|
+
except StopAsyncIteration:
|
|
74
|
+
break
|
|
62
75
|
if batch.HasField("exit_code"):
|
|
63
76
|
yield None, batch.batch_index
|
|
64
77
|
break
|
|
@@ -102,6 +115,7 @@ class _StreamReader(Generic[T]):
|
|
|
102
115
|
stream_type: StreamType = StreamType.PIPE,
|
|
103
116
|
text: bool = True,
|
|
104
117
|
by_line: bool = False,
|
|
118
|
+
deadline: Optional[float] = None,
|
|
105
119
|
) -> None:
|
|
106
120
|
"""mdmd:hidden"""
|
|
107
121
|
self._file_descriptor = file_descriptor
|
|
@@ -111,6 +125,7 @@ class _StreamReader(Generic[T]):
|
|
|
111
125
|
self._stream = None
|
|
112
126
|
self._last_entry_id: str = ""
|
|
113
127
|
self._line_buffer = b""
|
|
128
|
+
self._deadline = deadline
|
|
114
129
|
|
|
115
130
|
# Sandbox logs are streamed to the client as strings, so StreamReaders reading
|
|
116
131
|
# them must have text mode enabled.
|
|
@@ -187,11 +202,12 @@ class _StreamReader(Generic[T]):
|
|
|
187
202
|
retries_remaining = 10
|
|
188
203
|
last_index = 0
|
|
189
204
|
while not completed:
|
|
205
|
+
if self._deadline and time.monotonic() >= self._deadline:
|
|
206
|
+
break
|
|
190
207
|
try:
|
|
191
208
|
iterator = _container_process_logs_iterator(
|
|
192
|
-
self._object_id, self._file_descriptor, self._client, last_index
|
|
209
|
+
self._object_id, self._file_descriptor, self._client, last_index, self._deadline
|
|
193
210
|
)
|
|
194
|
-
|
|
195
211
|
async for message, batch_index in iterator:
|
|
196
212
|
if self._stream_type == StreamType.STDOUT and message:
|
|
197
213
|
print(message.decode("utf-8"), end="")
|
|
@@ -8,7 +8,11 @@ def _sandbox_logs_iterator(
|
|
|
8
8
|
sandbox_id: str, file_descriptor: int, last_entry_id: str, client: modal.client._Client
|
|
9
9
|
) -> collections.abc.AsyncGenerator[tuple[typing.Optional[bytes], str], None]: ...
|
|
10
10
|
def _container_process_logs_iterator(
|
|
11
|
-
process_id: str,
|
|
11
|
+
process_id: str,
|
|
12
|
+
file_descriptor: int,
|
|
13
|
+
client: modal.client._Client,
|
|
14
|
+
last_index: int,
|
|
15
|
+
deadline: typing.Optional[float] = None,
|
|
12
16
|
) -> collections.abc.AsyncGenerator[tuple[typing.Optional[bytes], int], None]: ...
|
|
13
17
|
|
|
14
18
|
T = typing.TypeVar("T")
|
|
@@ -46,6 +50,7 @@ class _StreamReader(typing.Generic[T]):
|
|
|
46
50
|
stream_type: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
|
|
47
51
|
text: bool = True,
|
|
48
52
|
by_line: bool = False,
|
|
53
|
+
deadline: typing.Optional[float] = None,
|
|
49
54
|
) -> None:
|
|
50
55
|
"""mdmd:hidden"""
|
|
51
56
|
...
|
|
@@ -211,6 +216,7 @@ class StreamReader(typing.Generic[T]):
|
|
|
211
216
|
stream_type: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
|
|
212
217
|
text: bool = True,
|
|
213
218
|
by_line: bool = False,
|
|
219
|
+
deadline: typing.Optional[float] = None,
|
|
214
220
|
) -> None:
|
|
215
221
|
"""mdmd:hidden"""
|
|
216
222
|
...
|
|
@@ -50,10 +50,11 @@ _default_image: _Image = _Image.debian_slim()
|
|
|
50
50
|
# e.g. 'runsc exec ...'. So we use 2**16 as the limit.
|
|
51
51
|
ARG_MAX_BYTES = 2**16
|
|
52
52
|
|
|
53
|
-
|
|
54
53
|
# This buffer extends the user-supplied timeout on ContainerExec-related RPCs. This was introduced to
|
|
55
54
|
# give any in-flight status codes/IO data more time to reach the client before the stream is closed.
|
|
56
55
|
CONTAINER_EXEC_TIMEOUT_BUFFER = 5
|
|
56
|
+
|
|
57
|
+
|
|
57
58
|
if TYPE_CHECKING:
|
|
58
59
|
import modal.app
|
|
59
60
|
|
|
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
|
|
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
|