chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,170 @@
|
||||
import httpx
|
||||
import json
|
||||
|
||||
from typing import Callable, Optional
|
||||
|
||||
from e2b.envd.rpc import format_terminated_exception
|
||||
from e2b.exceptions import (
|
||||
SandboxException,
|
||||
NotFoundException,
|
||||
AuthenticationException,
|
||||
InvalidArgumentException,
|
||||
NotEnoughSpaceException,
|
||||
RateLimitException,
|
||||
format_sandbox_timeout_exception,
|
||||
)
|
||||
|
||||
|
||||
ENVD_API_FILES_ROUTE = "/files"
|
||||
ENVD_API_HEALTH_ROUTE = "/health"
|
||||
|
||||
_DEFAULT_API_ERROR_MAP: dict[int, Callable[[str], Exception]] = {
|
||||
400: InvalidArgumentException,
|
||||
401: AuthenticationException,
|
||||
404: NotFoundException,
|
||||
429: lambda message: RateLimitException(
|
||||
f"{message}: The requests are being rate limited."
|
||||
),
|
||||
502: format_sandbox_timeout_exception,
|
||||
507: NotEnoughSpaceException,
|
||||
}
|
||||
|
||||
|
||||
HEALTH_CHECK_TIMEOUT = 5 # seconds
|
||||
|
||||
|
||||
def check_sandbox_health(envd_api: httpx.Client) -> Optional[bool]:
|
||||
"""Probe the sandbox's envd health endpoint.
|
||||
|
||||
:return: ``True`` if the sandbox is running, ``False`` if it is not, ``None`` if its state could not be determined.
|
||||
"""
|
||||
try:
|
||||
r = envd_api.get(ENVD_API_HEALTH_ROUTE, timeout=HEALTH_CHECK_TIMEOUT)
|
||||
if r.status_code == 502:
|
||||
return False
|
||||
if r.is_success:
|
||||
return True
|
||||
return None
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
async def acheck_sandbox_health(envd_api: httpx.AsyncClient) -> Optional[bool]:
|
||||
"""Async version of :func:`check_sandbox_health`."""
|
||||
try:
|
||||
r = await envd_api.get(ENVD_API_HEALTH_ROUTE, timeout=HEALTH_CHECK_TIMEOUT)
|
||||
if r.status_code == 502:
|
||||
return False
|
||||
if r.is_success:
|
||||
return True
|
||||
return None
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def handle_envd_api_transport_exception(
|
||||
e: Exception,
|
||||
sandbox_running: Optional[bool] = None,
|
||||
) -> Exception:
|
||||
"""Handle transport-level errors from envd API requests.
|
||||
|
||||
:param e: The caught exception, expected to be a transport-level ``httpx`` error.
|
||||
:param sandbox_running: Result of a sandbox health probe (``None`` when unknown), used to disambiguate a connection dropped mid-request.
|
||||
:return: A ``TimeoutException`` when the connection dropped mid-request and the sandbox is confirmed gone, or the original exception unchanged otherwise.
|
||||
"""
|
||||
# A remote protocol error (e.g. an HTTP/2 stream reset) means the connection to the
|
||||
# sandbox was dropped mid-request — either the sandbox died or the network failed
|
||||
if isinstance(e, httpx.RemoteProtocolError):
|
||||
return format_terminated_exception(e, sandbox_running)
|
||||
|
||||
return e
|
||||
|
||||
|
||||
def handle_envd_api_transport_exception_with_health(
|
||||
e: Exception,
|
||||
envd_api: httpx.Client,
|
||||
) -> Exception:
|
||||
"""Like :func:`handle_envd_api_transport_exception`, but when the connection to the
|
||||
sandbox was dropped mid-request it probes the sandbox health to tell apart the sandbox
|
||||
being killed from a transient network failure (e.g. a load balancer dropping the connection).
|
||||
"""
|
||||
sandbox_running = (
|
||||
check_sandbox_health(envd_api)
|
||||
if isinstance(e, httpx.RemoteProtocolError)
|
||||
else None
|
||||
)
|
||||
return handle_envd_api_transport_exception(e, sandbox_running)
|
||||
|
||||
|
||||
async def ahandle_envd_api_transport_exception_with_health(
|
||||
e: Exception,
|
||||
envd_api: httpx.AsyncClient,
|
||||
) -> Exception:
|
||||
"""Async version of :func:`handle_envd_api_transport_exception_with_health`."""
|
||||
sandbox_running = (
|
||||
await acheck_sandbox_health(envd_api)
|
||||
if isinstance(e, httpx.RemoteProtocolError)
|
||||
else None
|
||||
)
|
||||
return handle_envd_api_transport_exception(e, sandbox_running)
|
||||
|
||||
|
||||
def get_message(e: httpx.Response) -> str:
|
||||
try:
|
||||
message = e.json().get("message", e.text)
|
||||
except json.JSONDecodeError:
|
||||
message = e.text
|
||||
|
||||
return message
|
||||
|
||||
|
||||
def handle_envd_api_exception(
|
||||
res: httpx.Response,
|
||||
error_map: Optional[dict[int, Callable[[str], Exception]]] = None,
|
||||
):
|
||||
"""Handle errors from envd API responses by mapping HTTP status codes to specific exception types.
|
||||
|
||||
:param res: The HTTP response.
|
||||
:param error_map: Optional map of HTTP status codes to exception factories that override the defaults.
|
||||
:return: The corresponding exception, or ``None`` if the response is successful.
|
||||
"""
|
||||
if res.is_success:
|
||||
return
|
||||
|
||||
res.read()
|
||||
|
||||
return format_envd_api_exception(res.status_code, get_message(res), error_map)
|
||||
|
||||
|
||||
async def ahandle_envd_api_exception(
|
||||
res: httpx.Response,
|
||||
error_map: Optional[dict[int, Callable[[str], Exception]]] = None,
|
||||
):
|
||||
"""Async version of :func:`handle_envd_api_exception`."""
|
||||
if res.is_success:
|
||||
return
|
||||
|
||||
await res.aread()
|
||||
|
||||
return format_envd_api_exception(res.status_code, get_message(res), error_map)
|
||||
|
||||
|
||||
def format_envd_api_exception(
|
||||
status_code: int,
|
||||
message: str,
|
||||
error_map: Optional[dict[int, Callable[[str], Exception]]] = None,
|
||||
):
|
||||
"""Map an HTTP status code and message to the appropriate exception.
|
||||
|
||||
:param status_code: The HTTP status code.
|
||||
:param message: The error message from the response body.
|
||||
:param error_map: Optional map of HTTP status codes to exception factories that override the defaults.
|
||||
:return: The corresponding exception.
|
||||
"""
|
||||
if error_map and status_code in error_map:
|
||||
return error_map[status_code](message)
|
||||
|
||||
if status_code in _DEFAULT_API_ERROR_MAP:
|
||||
return _DEFAULT_API_ERROR_MAP[status_code](message)
|
||||
|
||||
return SandboxException(f"{status_code}: {message}")
|
||||
@@ -0,0 +1,193 @@
|
||||
# Code generated by protoc-gen-connect-python 0.1.0.dev2, DO NOT EDIT.
|
||||
from typing import Any, Generator, Coroutine, AsyncGenerator, Optional
|
||||
from httpcore import ConnectionPool, AsyncConnectionPool
|
||||
|
||||
import e2b_connect as connect
|
||||
|
||||
from e2b.envd.filesystem import filesystem_pb2 as filesystem_dot_filesystem__pb2
|
||||
|
||||
FilesystemName = "filesystem.Filesystem"
|
||||
|
||||
|
||||
class FilesystemClient:
|
||||
def __init__(
|
||||
self,
|
||||
base_url: str,
|
||||
*,
|
||||
pool: Optional[ConnectionPool] = None,
|
||||
async_pool: Optional[AsyncConnectionPool] = None,
|
||||
compressor=None,
|
||||
json=False,
|
||||
**opts,
|
||||
):
|
||||
self._stat = connect.Client(
|
||||
pool=pool,
|
||||
async_pool=async_pool,
|
||||
url=f"{base_url}/{FilesystemName}/Stat",
|
||||
response_type=filesystem_dot_filesystem__pb2.StatResponse,
|
||||
compressor=compressor,
|
||||
json=json,
|
||||
**opts,
|
||||
)
|
||||
self._make_dir = connect.Client(
|
||||
pool=pool,
|
||||
async_pool=async_pool,
|
||||
url=f"{base_url}/{FilesystemName}/MakeDir",
|
||||
response_type=filesystem_dot_filesystem__pb2.MakeDirResponse,
|
||||
compressor=compressor,
|
||||
json=json,
|
||||
**opts,
|
||||
)
|
||||
self._move = connect.Client(
|
||||
pool=pool,
|
||||
async_pool=async_pool,
|
||||
url=f"{base_url}/{FilesystemName}/Move",
|
||||
response_type=filesystem_dot_filesystem__pb2.MoveResponse,
|
||||
compressor=compressor,
|
||||
json=json,
|
||||
**opts,
|
||||
)
|
||||
self._list_dir = connect.Client(
|
||||
pool=pool,
|
||||
async_pool=async_pool,
|
||||
url=f"{base_url}/{FilesystemName}/ListDir",
|
||||
response_type=filesystem_dot_filesystem__pb2.ListDirResponse,
|
||||
compressor=compressor,
|
||||
json=json,
|
||||
**opts,
|
||||
)
|
||||
self._remove = connect.Client(
|
||||
pool=pool,
|
||||
async_pool=async_pool,
|
||||
url=f"{base_url}/{FilesystemName}/Remove",
|
||||
response_type=filesystem_dot_filesystem__pb2.RemoveResponse,
|
||||
compressor=compressor,
|
||||
json=json,
|
||||
**opts,
|
||||
)
|
||||
self._watch_dir = connect.Client(
|
||||
pool=pool,
|
||||
async_pool=async_pool,
|
||||
url=f"{base_url}/{FilesystemName}/WatchDir",
|
||||
response_type=filesystem_dot_filesystem__pb2.WatchDirResponse,
|
||||
compressor=compressor,
|
||||
json=json,
|
||||
**opts,
|
||||
)
|
||||
self._create_watcher = connect.Client(
|
||||
pool=pool,
|
||||
async_pool=async_pool,
|
||||
url=f"{base_url}/{FilesystemName}/CreateWatcher",
|
||||
response_type=filesystem_dot_filesystem__pb2.CreateWatcherResponse,
|
||||
compressor=compressor,
|
||||
json=json,
|
||||
**opts,
|
||||
)
|
||||
self._get_watcher_events = connect.Client(
|
||||
pool=pool,
|
||||
async_pool=async_pool,
|
||||
url=f"{base_url}/{FilesystemName}/GetWatcherEvents",
|
||||
response_type=filesystem_dot_filesystem__pb2.GetWatcherEventsResponse,
|
||||
compressor=compressor,
|
||||
json=json,
|
||||
**opts,
|
||||
)
|
||||
self._remove_watcher = connect.Client(
|
||||
pool=pool,
|
||||
async_pool=async_pool,
|
||||
url=f"{base_url}/{FilesystemName}/RemoveWatcher",
|
||||
response_type=filesystem_dot_filesystem__pb2.RemoveWatcherResponse,
|
||||
compressor=compressor,
|
||||
json=json,
|
||||
**opts,
|
||||
)
|
||||
|
||||
def stat(
|
||||
self, req: filesystem_dot_filesystem__pb2.StatRequest, **opts
|
||||
) -> filesystem_dot_filesystem__pb2.StatResponse:
|
||||
return self._stat.call_unary(req, **opts)
|
||||
|
||||
def astat(
|
||||
self, req: filesystem_dot_filesystem__pb2.StatRequest, **opts
|
||||
) -> Coroutine[Any, Any, filesystem_dot_filesystem__pb2.StatResponse]:
|
||||
return self._stat.acall_unary(req, **opts)
|
||||
|
||||
def make_dir(
|
||||
self, req: filesystem_dot_filesystem__pb2.MakeDirRequest, **opts
|
||||
) -> filesystem_dot_filesystem__pb2.MakeDirResponse:
|
||||
return self._make_dir.call_unary(req, **opts)
|
||||
|
||||
def amake_dir(
|
||||
self, req: filesystem_dot_filesystem__pb2.MakeDirRequest, **opts
|
||||
) -> Coroutine[Any, Any, filesystem_dot_filesystem__pb2.MakeDirResponse]:
|
||||
return self._make_dir.acall_unary(req, **opts)
|
||||
|
||||
def move(
|
||||
self, req: filesystem_dot_filesystem__pb2.MoveRequest, **opts
|
||||
) -> filesystem_dot_filesystem__pb2.MoveResponse:
|
||||
return self._move.call_unary(req, **opts)
|
||||
|
||||
def amove(
|
||||
self, req: filesystem_dot_filesystem__pb2.MoveRequest, **opts
|
||||
) -> Coroutine[Any, Any, filesystem_dot_filesystem__pb2.MoveResponse]:
|
||||
return self._move.acall_unary(req, **opts)
|
||||
|
||||
def list_dir(
|
||||
self, req: filesystem_dot_filesystem__pb2.ListDirRequest, **opts
|
||||
) -> filesystem_dot_filesystem__pb2.ListDirResponse:
|
||||
return self._list_dir.call_unary(req, **opts)
|
||||
|
||||
def alist_dir(
|
||||
self, req: filesystem_dot_filesystem__pb2.ListDirRequest, **opts
|
||||
) -> Coroutine[Any, Any, filesystem_dot_filesystem__pb2.ListDirResponse]:
|
||||
return self._list_dir.acall_unary(req, **opts)
|
||||
|
||||
def remove(
|
||||
self, req: filesystem_dot_filesystem__pb2.RemoveRequest, **opts
|
||||
) -> filesystem_dot_filesystem__pb2.RemoveResponse:
|
||||
return self._remove.call_unary(req, **opts)
|
||||
|
||||
def aremove(
|
||||
self, req: filesystem_dot_filesystem__pb2.RemoveRequest, **opts
|
||||
) -> Coroutine[Any, Any, filesystem_dot_filesystem__pb2.RemoveResponse]:
|
||||
return self._remove.acall_unary(req, **opts)
|
||||
|
||||
def watch_dir(
|
||||
self, req: filesystem_dot_filesystem__pb2.WatchDirRequest, **opts
|
||||
) -> Generator[filesystem_dot_filesystem__pb2.WatchDirResponse, Any, None]:
|
||||
return self._watch_dir.call_server_stream(req, **opts)
|
||||
|
||||
def awatch_dir(
|
||||
self, req: filesystem_dot_filesystem__pb2.WatchDirRequest, **opts
|
||||
) -> AsyncGenerator[filesystem_dot_filesystem__pb2.WatchDirResponse, Any]:
|
||||
return self._watch_dir.acall_server_stream(req, **opts)
|
||||
|
||||
def create_watcher(
|
||||
self, req: filesystem_dot_filesystem__pb2.CreateWatcherRequest, **opts
|
||||
) -> filesystem_dot_filesystem__pb2.CreateWatcherResponse:
|
||||
return self._create_watcher.call_unary(req, **opts)
|
||||
|
||||
def acreate_watcher(
|
||||
self, req: filesystem_dot_filesystem__pb2.CreateWatcherRequest, **opts
|
||||
) -> Coroutine[Any, Any, filesystem_dot_filesystem__pb2.CreateWatcherResponse]:
|
||||
return self._create_watcher.acall_unary(req, **opts)
|
||||
|
||||
def get_watcher_events(
|
||||
self, req: filesystem_dot_filesystem__pb2.GetWatcherEventsRequest, **opts
|
||||
) -> filesystem_dot_filesystem__pb2.GetWatcherEventsResponse:
|
||||
return self._get_watcher_events.call_unary(req, **opts)
|
||||
|
||||
def aget_watcher_events(
|
||||
self, req: filesystem_dot_filesystem__pb2.GetWatcherEventsRequest, **opts
|
||||
) -> Coroutine[Any, Any, filesystem_dot_filesystem__pb2.GetWatcherEventsResponse]:
|
||||
return self._get_watcher_events.acall_unary(req, **opts)
|
||||
|
||||
def remove_watcher(
|
||||
self, req: filesystem_dot_filesystem__pb2.RemoveWatcherRequest, **opts
|
||||
) -> filesystem_dot_filesystem__pb2.RemoveWatcherResponse:
|
||||
return self._remove_watcher.call_unary(req, **opts)
|
||||
|
||||
def aremove_watcher(
|
||||
self, req: filesystem_dot_filesystem__pb2.RemoveWatcherRequest, **opts
|
||||
) -> Coroutine[Any, Any, filesystem_dot_filesystem__pb2.RemoveWatcherResponse]:
|
||||
return self._remove_watcher.acall_unary(req, **opts)
|
||||
@@ -0,0 +1,80 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: filesystem/filesystem.proto
|
||||
# Protobuf Python Version: 5.26.1
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf.internal import builder as _builder
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1b\x66ilesystem/filesystem.proto\x12\nfilesystem\x1a\x1fgoogle/protobuf/timestamp.proto\"G\n\x0bMoveRequest\x12\x16\n\x06source\x18\x01 \x01(\tR\x06source\x12 \n\x0b\x64\x65stination\x18\x02 \x01(\tR\x0b\x64\x65stination\";\n\x0cMoveResponse\x12+\n\x05\x65ntry\x18\x01 \x01(\x0b\x32\x15.filesystem.EntryInfoR\x05\x65ntry\"$\n\x0eMakeDirRequest\x12\x12\n\x04path\x18\x01 \x01(\tR\x04path\">\n\x0fMakeDirResponse\x12+\n\x05\x65ntry\x18\x01 \x01(\x0b\x32\x15.filesystem.EntryInfoR\x05\x65ntry\"#\n\rRemoveRequest\x12\x12\n\x04path\x18\x01 \x01(\tR\x04path\"\x10\n\x0eRemoveResponse\"!\n\x0bStatRequest\x12\x12\n\x04path\x18\x01 \x01(\tR\x04path\";\n\x0cStatResponse\x12+\n\x05\x65ntry\x18\x01 \x01(\x0b\x32\x15.filesystem.EntryInfoR\x05\x65ntry\"\xd1\x03\n\tEntryInfo\x12\x12\n\x04name\x18\x01 \x01(\tR\x04name\x12(\n\x04type\x18\x02 \x01(\x0e\x32\x14.filesystem.FileTypeR\x04type\x12\x12\n\x04path\x18\x03 \x01(\tR\x04path\x12\x12\n\x04size\x18\x04 \x01(\x03R\x04size\x12\x12\n\x04mode\x18\x05 \x01(\rR\x04mode\x12 \n\x0bpermissions\x18\x06 \x01(\tR\x0bpermissions\x12\x14\n\x05owner\x18\x07 \x01(\tR\x05owner\x12\x14\n\x05group\x18\x08 \x01(\tR\x05group\x12?\n\rmodified_time\x18\t \x01(\x0b\x32\x1a.google.protobuf.TimestampR\x0cmodifiedTime\x12*\n\x0esymlink_target\x18\n \x01(\tH\x00R\rsymlinkTarget\x88\x01\x01\x12?\n\x08metadata\x18\x0b \x03(\x0b\x32#.filesystem.EntryInfo.MetadataEntryR\x08metadata\x1a;\n\rMetadataEntry\x12\x10\n\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n\x05value\x18\x02 \x01(\tR\x05value:\x02\x38\x01\x42\x11\n\x0f_symlink_target\":\n\x0eListDirRequest\x12\x12\n\x04path\x18\x01 \x01(\tR\x04path\x12\x14\n\x05\x64\x65pth\x18\x02 \x01(\rR\x05\x64\x65pth\"B\n\x0fListDirResponse\x12/\n\x07\x65ntries\x18\x01 \x03(\x0b\x32\x15.filesystem.EntryInfoR\x07\x65ntries\"\x9a\x01\n\x0fWatchDirRequest\x12\x12\n\x04path\x18\x01 \x01(\tR\x04path\x12\x1c\n\trecursive\x18\x02 \x01(\x08R\trecursive\x12#\n\rinclude_entry\x18\x03 \x01(\x08R\x0cincludeEntry\x12\x30\n\x14\x61llow_network_mounts\x18\x04 \x01(\x08R\x12\x61llowNetworkMounts\"\x8c\x01\n\x0f\x46ilesystemEvent\x12\x12\n\x04name\x18\x01 \x01(\tR\x04name\x12)\n\x04type\x18\x02 \x01(\x0e\x32\x15.filesystem.EventTypeR\x04type\x12\x30\n\x05\x65ntry\x18\x03 \x01(\x0b\x32\x15.filesystem.EntryInfoH\x00R\x05\x65ntry\x88\x01\x01\x42\x08\n\x06_entry\"\xfe\x01\n\x10WatchDirResponse\x12?\n\x05start\x18\x01 \x01(\x0b\x32\'.filesystem.WatchDirResponse.StartEventH\x00R\x05start\x12=\n\nfilesystem\x18\x02 \x01(\x0b\x32\x1b.filesystem.FilesystemEventH\x00R\nfilesystem\x12\x46\n\tkeepalive\x18\x03 \x01(\x0b\x32&.filesystem.WatchDirResponse.KeepAliveH\x00R\tkeepalive\x1a\x0c\n\nStartEvent\x1a\x0b\n\tKeepAliveB\x07\n\x05\x65vent\"\x9f\x01\n\x14\x43reateWatcherRequest\x12\x12\n\x04path\x18\x01 \x01(\tR\x04path\x12\x1c\n\trecursive\x18\x02 \x01(\x08R\trecursive\x12#\n\rinclude_entry\x18\x03 \x01(\x08R\x0cincludeEntry\x12\x30\n\x14\x61llow_network_mounts\x18\x04 \x01(\x08R\x12\x61llowNetworkMounts\"6\n\x15\x43reateWatcherResponse\x12\x1d\n\nwatcher_id\x18\x01 \x01(\tR\twatcherId\"8\n\x17GetWatcherEventsRequest\x12\x1d\n\nwatcher_id\x18\x01 \x01(\tR\twatcherId\"O\n\x18GetWatcherEventsResponse\x12\x33\n\x06\x65vents\x18\x01 \x03(\x0b\x32\x1b.filesystem.FilesystemEventR\x06\x65vents\"5\n\x14RemoveWatcherRequest\x12\x1d\n\nwatcher_id\x18\x01 \x01(\tR\twatcherId\"\x17\n\x15RemoveWatcherResponse*R\n\x08\x46ileType\x12\x19\n\x15\x46ILE_TYPE_UNSPECIFIED\x10\x00\x12\x12\n\x0e\x46ILE_TYPE_FILE\x10\x01\x12\x17\n\x13\x46ILE_TYPE_DIRECTORY\x10\x02*\x98\x01\n\tEventType\x12\x1a\n\x16\x45VENT_TYPE_UNSPECIFIED\x10\x00\x12\x15\n\x11\x45VENT_TYPE_CREATE\x10\x01\x12\x14\n\x10\x45VENT_TYPE_WRITE\x10\x02\x12\x15\n\x11\x45VENT_TYPE_REMOVE\x10\x03\x12\x15\n\x11\x45VENT_TYPE_RENAME\x10\x04\x12\x14\n\x10\x45VENT_TYPE_CHMOD\x10\x05\x32\x9f\x05\n\nFilesystem\x12\x39\n\x04Stat\x12\x17.filesystem.StatRequest\x1a\x18.filesystem.StatResponse\x12\x42\n\x07MakeDir\x12\x1a.filesystem.MakeDirRequest\x1a\x1b.filesystem.MakeDirResponse\x12\x39\n\x04Move\x12\x17.filesystem.MoveRequest\x1a\x18.filesystem.MoveResponse\x12\x42\n\x07ListDir\x12\x1a.filesystem.ListDirRequest\x1a\x1b.filesystem.ListDirResponse\x12?\n\x06Remove\x12\x19.filesystem.RemoveRequest\x1a\x1a.filesystem.RemoveResponse\x12G\n\x08WatchDir\x12\x1b.filesystem.WatchDirRequest\x1a\x1c.filesystem.WatchDirResponse0\x01\x12T\n\rCreateWatcher\x12 .filesystem.CreateWatcherRequest\x1a!.filesystem.CreateWatcherResponse\x12]\n\x10GetWatcherEvents\x12#.filesystem.GetWatcherEventsRequest\x1a$.filesystem.GetWatcherEventsResponse\x12T\n\rRemoveWatcher\x12 .filesystem.RemoveWatcherRequest\x1a!.filesystem.RemoveWatcherResponseBi\n\x0e\x63om.filesystemB\x0f\x46ilesystemProtoP\x01\xa2\x02\x03\x46XX\xaa\x02\nFilesystem\xca\x02\nFilesystem\xe2\x02\x16\x46ilesystem\\GPBMetadata\xea\x02\nFilesystemb\x06proto3')
|
||||
|
||||
_globals = globals()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'filesystem.filesystem_pb2', _globals)
|
||||
if not _descriptor._USE_C_DESCRIPTORS:
|
||||
_globals['DESCRIPTOR']._loaded_options = None
|
||||
_globals['DESCRIPTOR']._serialized_options = b'\n\016com.filesystemB\017FilesystemProtoP\001\242\002\003FXX\252\002\nFilesystem\312\002\nFilesystem\342\002\026Filesystem\\GPBMetadata\352\002\nFilesystem'
|
||||
_globals['_ENTRYINFO_METADATAENTRY']._loaded_options = None
|
||||
_globals['_ENTRYINFO_METADATAENTRY']._serialized_options = b'8\001'
|
||||
_globals['_FILETYPE']._serialized_start=2053
|
||||
_globals['_FILETYPE']._serialized_end=2135
|
||||
_globals['_EVENTTYPE']._serialized_start=2138
|
||||
_globals['_EVENTTYPE']._serialized_end=2290
|
||||
_globals['_MOVEREQUEST']._serialized_start=76
|
||||
_globals['_MOVEREQUEST']._serialized_end=147
|
||||
_globals['_MOVERESPONSE']._serialized_start=149
|
||||
_globals['_MOVERESPONSE']._serialized_end=208
|
||||
_globals['_MAKEDIRREQUEST']._serialized_start=210
|
||||
_globals['_MAKEDIRREQUEST']._serialized_end=246
|
||||
_globals['_MAKEDIRRESPONSE']._serialized_start=248
|
||||
_globals['_MAKEDIRRESPONSE']._serialized_end=310
|
||||
_globals['_REMOVEREQUEST']._serialized_start=312
|
||||
_globals['_REMOVEREQUEST']._serialized_end=347
|
||||
_globals['_REMOVERESPONSE']._serialized_start=349
|
||||
_globals['_REMOVERESPONSE']._serialized_end=365
|
||||
_globals['_STATREQUEST']._serialized_start=367
|
||||
_globals['_STATREQUEST']._serialized_end=400
|
||||
_globals['_STATRESPONSE']._serialized_start=402
|
||||
_globals['_STATRESPONSE']._serialized_end=461
|
||||
_globals['_ENTRYINFO']._serialized_start=464
|
||||
_globals['_ENTRYINFO']._serialized_end=929
|
||||
_globals['_ENTRYINFO_METADATAENTRY']._serialized_start=851
|
||||
_globals['_ENTRYINFO_METADATAENTRY']._serialized_end=910
|
||||
_globals['_LISTDIRREQUEST']._serialized_start=931
|
||||
_globals['_LISTDIRREQUEST']._serialized_end=989
|
||||
_globals['_LISTDIRRESPONSE']._serialized_start=991
|
||||
_globals['_LISTDIRRESPONSE']._serialized_end=1057
|
||||
_globals['_WATCHDIRREQUEST']._serialized_start=1060
|
||||
_globals['_WATCHDIRREQUEST']._serialized_end=1214
|
||||
_globals['_FILESYSTEMEVENT']._serialized_start=1217
|
||||
_globals['_FILESYSTEMEVENT']._serialized_end=1357
|
||||
_globals['_WATCHDIRRESPONSE']._serialized_start=1360
|
||||
_globals['_WATCHDIRRESPONSE']._serialized_end=1614
|
||||
_globals['_WATCHDIRRESPONSE_STARTEVENT']._serialized_start=1580
|
||||
_globals['_WATCHDIRRESPONSE_STARTEVENT']._serialized_end=1592
|
||||
_globals['_WATCHDIRRESPONSE_KEEPALIVE']._serialized_start=1594
|
||||
_globals['_WATCHDIRRESPONSE_KEEPALIVE']._serialized_end=1605
|
||||
_globals['_CREATEWATCHERREQUEST']._serialized_start=1617
|
||||
_globals['_CREATEWATCHERREQUEST']._serialized_end=1776
|
||||
_globals['_CREATEWATCHERRESPONSE']._serialized_start=1778
|
||||
_globals['_CREATEWATCHERRESPONSE']._serialized_end=1832
|
||||
_globals['_GETWATCHEREVENTSREQUEST']._serialized_start=1834
|
||||
_globals['_GETWATCHEREVENTSREQUEST']._serialized_end=1890
|
||||
_globals['_GETWATCHEREVENTSRESPONSE']._serialized_start=1892
|
||||
_globals['_GETWATCHEREVENTSRESPONSE']._serialized_end=1971
|
||||
_globals['_REMOVEWATCHERREQUEST']._serialized_start=1973
|
||||
_globals['_REMOVEWATCHERREQUEST']._serialized_end=2026
|
||||
_globals['_REMOVEWATCHERRESPONSE']._serialized_start=2028
|
||||
_globals['_REMOVEWATCHERRESPONSE']._serialized_end=2051
|
||||
_globals['_FILESYSTEM']._serialized_start=2293
|
||||
_globals['_FILESYSTEM']._serialized_end=2964
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
@@ -0,0 +1,272 @@
|
||||
from google.protobuf import timestamp_pb2 as _timestamp_pb2
|
||||
from google.protobuf.internal import containers as _containers
|
||||
from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from typing import (
|
||||
ClassVar as _ClassVar,
|
||||
Iterable as _Iterable,
|
||||
Mapping as _Mapping,
|
||||
Optional as _Optional,
|
||||
Union as _Union,
|
||||
)
|
||||
|
||||
DESCRIPTOR: _descriptor.FileDescriptor
|
||||
|
||||
class FileType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
|
||||
__slots__ = ()
|
||||
FILE_TYPE_UNSPECIFIED: _ClassVar[FileType]
|
||||
FILE_TYPE_FILE: _ClassVar[FileType]
|
||||
FILE_TYPE_DIRECTORY: _ClassVar[FileType]
|
||||
|
||||
class EventType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
|
||||
__slots__ = ()
|
||||
EVENT_TYPE_UNSPECIFIED: _ClassVar[EventType]
|
||||
EVENT_TYPE_CREATE: _ClassVar[EventType]
|
||||
EVENT_TYPE_WRITE: _ClassVar[EventType]
|
||||
EVENT_TYPE_REMOVE: _ClassVar[EventType]
|
||||
EVENT_TYPE_RENAME: _ClassVar[EventType]
|
||||
EVENT_TYPE_CHMOD: _ClassVar[EventType]
|
||||
|
||||
FILE_TYPE_UNSPECIFIED: FileType
|
||||
FILE_TYPE_FILE: FileType
|
||||
FILE_TYPE_DIRECTORY: FileType
|
||||
EVENT_TYPE_UNSPECIFIED: EventType
|
||||
EVENT_TYPE_CREATE: EventType
|
||||
EVENT_TYPE_WRITE: EventType
|
||||
EVENT_TYPE_REMOVE: EventType
|
||||
EVENT_TYPE_RENAME: EventType
|
||||
EVENT_TYPE_CHMOD: EventType
|
||||
|
||||
class MoveRequest(_message.Message):
|
||||
__slots__ = ("source", "destination")
|
||||
SOURCE_FIELD_NUMBER: _ClassVar[int]
|
||||
DESTINATION_FIELD_NUMBER: _ClassVar[int]
|
||||
source: str
|
||||
destination: str
|
||||
def __init__(
|
||||
self, source: _Optional[str] = ..., destination: _Optional[str] = ...
|
||||
) -> None: ...
|
||||
|
||||
class MoveResponse(_message.Message):
|
||||
__slots__ = ("entry",)
|
||||
ENTRY_FIELD_NUMBER: _ClassVar[int]
|
||||
entry: EntryInfo
|
||||
def __init__(self, entry: _Optional[_Union[EntryInfo, _Mapping]] = ...) -> None: ...
|
||||
|
||||
class MakeDirRequest(_message.Message):
|
||||
__slots__ = ("path",)
|
||||
PATH_FIELD_NUMBER: _ClassVar[int]
|
||||
path: str
|
||||
def __init__(self, path: _Optional[str] = ...) -> None: ...
|
||||
|
||||
class MakeDirResponse(_message.Message):
|
||||
__slots__ = ("entry",)
|
||||
ENTRY_FIELD_NUMBER: _ClassVar[int]
|
||||
entry: EntryInfo
|
||||
def __init__(self, entry: _Optional[_Union[EntryInfo, _Mapping]] = ...) -> None: ...
|
||||
|
||||
class RemoveRequest(_message.Message):
|
||||
__slots__ = ("path",)
|
||||
PATH_FIELD_NUMBER: _ClassVar[int]
|
||||
path: str
|
||||
def __init__(self, path: _Optional[str] = ...) -> None: ...
|
||||
|
||||
class RemoveResponse(_message.Message):
|
||||
__slots__ = ()
|
||||
def __init__(self) -> None: ...
|
||||
|
||||
class StatRequest(_message.Message):
|
||||
__slots__ = ("path",)
|
||||
PATH_FIELD_NUMBER: _ClassVar[int]
|
||||
path: str
|
||||
def __init__(self, path: _Optional[str] = ...) -> None: ...
|
||||
|
||||
class StatResponse(_message.Message):
|
||||
__slots__ = ("entry",)
|
||||
ENTRY_FIELD_NUMBER: _ClassVar[int]
|
||||
entry: EntryInfo
|
||||
def __init__(self, entry: _Optional[_Union[EntryInfo, _Mapping]] = ...) -> None: ...
|
||||
|
||||
class EntryInfo(_message.Message):
|
||||
__slots__ = (
|
||||
"name",
|
||||
"type",
|
||||
"path",
|
||||
"size",
|
||||
"mode",
|
||||
"permissions",
|
||||
"owner",
|
||||
"group",
|
||||
"modified_time",
|
||||
"symlink_target",
|
||||
"metadata",
|
||||
)
|
||||
class MetadataEntry(_message.Message):
|
||||
__slots__ = ("key", "value")
|
||||
KEY_FIELD_NUMBER: _ClassVar[int]
|
||||
VALUE_FIELD_NUMBER: _ClassVar[int]
|
||||
key: str
|
||||
value: str
|
||||
def __init__(
|
||||
self, key: _Optional[str] = ..., value: _Optional[str] = ...
|
||||
) -> None: ...
|
||||
|
||||
NAME_FIELD_NUMBER: _ClassVar[int]
|
||||
TYPE_FIELD_NUMBER: _ClassVar[int]
|
||||
PATH_FIELD_NUMBER: _ClassVar[int]
|
||||
SIZE_FIELD_NUMBER: _ClassVar[int]
|
||||
MODE_FIELD_NUMBER: _ClassVar[int]
|
||||
PERMISSIONS_FIELD_NUMBER: _ClassVar[int]
|
||||
OWNER_FIELD_NUMBER: _ClassVar[int]
|
||||
GROUP_FIELD_NUMBER: _ClassVar[int]
|
||||
MODIFIED_TIME_FIELD_NUMBER: _ClassVar[int]
|
||||
SYMLINK_TARGET_FIELD_NUMBER: _ClassVar[int]
|
||||
METADATA_FIELD_NUMBER: _ClassVar[int]
|
||||
name: str
|
||||
type: FileType
|
||||
path: str
|
||||
size: int
|
||||
mode: int
|
||||
permissions: str
|
||||
owner: str
|
||||
group: str
|
||||
modified_time: _timestamp_pb2.Timestamp
|
||||
symlink_target: str
|
||||
metadata: _containers.ScalarMap[str, str]
|
||||
def __init__(
|
||||
self,
|
||||
name: _Optional[str] = ...,
|
||||
type: _Optional[_Union[FileType, str]] = ...,
|
||||
path: _Optional[str] = ...,
|
||||
size: _Optional[int] = ...,
|
||||
mode: _Optional[int] = ...,
|
||||
permissions: _Optional[str] = ...,
|
||||
owner: _Optional[str] = ...,
|
||||
group: _Optional[str] = ...,
|
||||
modified_time: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ...,
|
||||
symlink_target: _Optional[str] = ...,
|
||||
metadata: _Optional[_Mapping[str, str]] = ...,
|
||||
) -> None: ...
|
||||
|
||||
class ListDirRequest(_message.Message):
|
||||
__slots__ = ("path", "depth")
|
||||
PATH_FIELD_NUMBER: _ClassVar[int]
|
||||
DEPTH_FIELD_NUMBER: _ClassVar[int]
|
||||
path: str
|
||||
depth: int
|
||||
def __init__(
|
||||
self, path: _Optional[str] = ..., depth: _Optional[int] = ...
|
||||
) -> None: ...
|
||||
|
||||
class ListDirResponse(_message.Message):
|
||||
__slots__ = ("entries",)
|
||||
ENTRIES_FIELD_NUMBER: _ClassVar[int]
|
||||
entries: _containers.RepeatedCompositeFieldContainer[EntryInfo]
|
||||
def __init__(
|
||||
self, entries: _Optional[_Iterable[_Union[EntryInfo, _Mapping]]] = ...
|
||||
) -> None: ...
|
||||
|
||||
class WatchDirRequest(_message.Message):
|
||||
__slots__ = ("path", "recursive", "include_entry", "allow_network_mounts")
|
||||
PATH_FIELD_NUMBER: _ClassVar[int]
|
||||
RECURSIVE_FIELD_NUMBER: _ClassVar[int]
|
||||
INCLUDE_ENTRY_FIELD_NUMBER: _ClassVar[int]
|
||||
ALLOW_NETWORK_MOUNTS_FIELD_NUMBER: _ClassVar[int]
|
||||
path: str
|
||||
recursive: bool
|
||||
include_entry: bool
|
||||
allow_network_mounts: bool
|
||||
def __init__(
|
||||
self,
|
||||
path: _Optional[str] = ...,
|
||||
recursive: bool = ...,
|
||||
include_entry: bool = ...,
|
||||
allow_network_mounts: bool = ...,
|
||||
) -> None: ...
|
||||
|
||||
class FilesystemEvent(_message.Message):
|
||||
__slots__ = ("name", "type", "entry")
|
||||
NAME_FIELD_NUMBER: _ClassVar[int]
|
||||
TYPE_FIELD_NUMBER: _ClassVar[int]
|
||||
ENTRY_FIELD_NUMBER: _ClassVar[int]
|
||||
name: str
|
||||
type: EventType
|
||||
entry: EntryInfo
|
||||
def __init__(
|
||||
self,
|
||||
name: _Optional[str] = ...,
|
||||
type: _Optional[_Union[EventType, str]] = ...,
|
||||
entry: _Optional[_Union[EntryInfo, _Mapping]] = ...,
|
||||
) -> None: ...
|
||||
|
||||
class WatchDirResponse(_message.Message):
|
||||
__slots__ = ("start", "filesystem", "keepalive")
|
||||
class StartEvent(_message.Message):
|
||||
__slots__ = ()
|
||||
def __init__(self) -> None: ...
|
||||
|
||||
class KeepAlive(_message.Message):
|
||||
__slots__ = ()
|
||||
def __init__(self) -> None: ...
|
||||
|
||||
START_FIELD_NUMBER: _ClassVar[int]
|
||||
FILESYSTEM_FIELD_NUMBER: _ClassVar[int]
|
||||
KEEPALIVE_FIELD_NUMBER: _ClassVar[int]
|
||||
start: WatchDirResponse.StartEvent
|
||||
filesystem: FilesystemEvent
|
||||
keepalive: WatchDirResponse.KeepAlive
|
||||
def __init__(
|
||||
self,
|
||||
start: _Optional[_Union[WatchDirResponse.StartEvent, _Mapping]] = ...,
|
||||
filesystem: _Optional[_Union[FilesystemEvent, _Mapping]] = ...,
|
||||
keepalive: _Optional[_Union[WatchDirResponse.KeepAlive, _Mapping]] = ...,
|
||||
) -> None: ...
|
||||
|
||||
class CreateWatcherRequest(_message.Message):
|
||||
__slots__ = ("path", "recursive", "include_entry", "allow_network_mounts")
|
||||
PATH_FIELD_NUMBER: _ClassVar[int]
|
||||
RECURSIVE_FIELD_NUMBER: _ClassVar[int]
|
||||
INCLUDE_ENTRY_FIELD_NUMBER: _ClassVar[int]
|
||||
ALLOW_NETWORK_MOUNTS_FIELD_NUMBER: _ClassVar[int]
|
||||
path: str
|
||||
recursive: bool
|
||||
include_entry: bool
|
||||
allow_network_mounts: bool
|
||||
def __init__(
|
||||
self,
|
||||
path: _Optional[str] = ...,
|
||||
recursive: bool = ...,
|
||||
include_entry: bool = ...,
|
||||
allow_network_mounts: bool = ...,
|
||||
) -> None: ...
|
||||
|
||||
class CreateWatcherResponse(_message.Message):
|
||||
__slots__ = ("watcher_id",)
|
||||
WATCHER_ID_FIELD_NUMBER: _ClassVar[int]
|
||||
watcher_id: str
|
||||
def __init__(self, watcher_id: _Optional[str] = ...) -> None: ...
|
||||
|
||||
class GetWatcherEventsRequest(_message.Message):
|
||||
__slots__ = ("watcher_id",)
|
||||
WATCHER_ID_FIELD_NUMBER: _ClassVar[int]
|
||||
watcher_id: str
|
||||
def __init__(self, watcher_id: _Optional[str] = ...) -> None: ...
|
||||
|
||||
class GetWatcherEventsResponse(_message.Message):
|
||||
__slots__ = ("events",)
|
||||
EVENTS_FIELD_NUMBER: _ClassVar[int]
|
||||
events: _containers.RepeatedCompositeFieldContainer[FilesystemEvent]
|
||||
def __init__(
|
||||
self, events: _Optional[_Iterable[_Union[FilesystemEvent, _Mapping]]] = ...
|
||||
) -> None: ...
|
||||
|
||||
class RemoveWatcherRequest(_message.Message):
|
||||
__slots__ = ("watcher_id",)
|
||||
WATCHER_ID_FIELD_NUMBER: _ClassVar[int]
|
||||
watcher_id: str
|
||||
def __init__(self, watcher_id: _Optional[str] = ...) -> None: ...
|
||||
|
||||
class RemoveWatcherResponse(_message.Message):
|
||||
__slots__ = ()
|
||||
def __init__(self) -> None: ...
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
# Code generated by protoc-gen-connect-python 0.1.0.dev2, DO NOT EDIT.
|
||||
from typing import Any, Generator, Coroutine, AsyncGenerator, Optional
|
||||
from httpcore import ConnectionPool, AsyncConnectionPool
|
||||
|
||||
import e2b_connect as connect
|
||||
|
||||
from e2b.envd.process import process_pb2 as process_dot_process__pb2
|
||||
|
||||
ProcessName = "process.Process"
|
||||
|
||||
|
||||
class ProcessClient:
|
||||
def __init__(
|
||||
self,
|
||||
base_url: str,
|
||||
*,
|
||||
pool: Optional[ConnectionPool] = None,
|
||||
async_pool: Optional[AsyncConnectionPool] = None,
|
||||
compressor=None,
|
||||
json=False,
|
||||
**opts,
|
||||
):
|
||||
self._list = connect.Client(
|
||||
pool=pool,
|
||||
async_pool=async_pool,
|
||||
url=f"{base_url}/{ProcessName}/List",
|
||||
response_type=process_dot_process__pb2.ListResponse,
|
||||
compressor=compressor,
|
||||
json=json,
|
||||
**opts,
|
||||
)
|
||||
self._connect = connect.Client(
|
||||
pool=pool,
|
||||
async_pool=async_pool,
|
||||
url=f"{base_url}/{ProcessName}/Connect",
|
||||
response_type=process_dot_process__pb2.ConnectResponse,
|
||||
compressor=compressor,
|
||||
json=json,
|
||||
**opts,
|
||||
)
|
||||
self._start = connect.Client(
|
||||
pool=pool,
|
||||
async_pool=async_pool,
|
||||
url=f"{base_url}/{ProcessName}/Start",
|
||||
response_type=process_dot_process__pb2.StartResponse,
|
||||
compressor=compressor,
|
||||
json=json,
|
||||
**opts,
|
||||
)
|
||||
self._update = connect.Client(
|
||||
pool=pool,
|
||||
async_pool=async_pool,
|
||||
url=f"{base_url}/{ProcessName}/Update",
|
||||
response_type=process_dot_process__pb2.UpdateResponse,
|
||||
compressor=compressor,
|
||||
json=json,
|
||||
**opts,
|
||||
)
|
||||
self._stream_input = connect.Client(
|
||||
pool=pool,
|
||||
async_pool=async_pool,
|
||||
url=f"{base_url}/{ProcessName}/StreamInput",
|
||||
response_type=process_dot_process__pb2.StreamInputResponse,
|
||||
compressor=compressor,
|
||||
json=json,
|
||||
**opts,
|
||||
)
|
||||
self._send_input = connect.Client(
|
||||
pool=pool,
|
||||
async_pool=async_pool,
|
||||
url=f"{base_url}/{ProcessName}/SendInput",
|
||||
response_type=process_dot_process__pb2.SendInputResponse,
|
||||
compressor=compressor,
|
||||
json=json,
|
||||
**opts,
|
||||
)
|
||||
self._send_signal = connect.Client(
|
||||
pool=pool,
|
||||
async_pool=async_pool,
|
||||
url=f"{base_url}/{ProcessName}/SendSignal",
|
||||
response_type=process_dot_process__pb2.SendSignalResponse,
|
||||
compressor=compressor,
|
||||
json=json,
|
||||
**opts,
|
||||
)
|
||||
self._close_stdin = connect.Client(
|
||||
pool=pool,
|
||||
async_pool=async_pool,
|
||||
url=f"{base_url}/{ProcessName}/CloseStdin",
|
||||
response_type=process_dot_process__pb2.CloseStdinResponse,
|
||||
compressor=compressor,
|
||||
json=json,
|
||||
**opts,
|
||||
)
|
||||
|
||||
def list(
|
||||
self, req: process_dot_process__pb2.ListRequest, **opts
|
||||
) -> process_dot_process__pb2.ListResponse:
|
||||
return self._list.call_unary(req, **opts)
|
||||
|
||||
def alist(
|
||||
self, req: process_dot_process__pb2.ListRequest, **opts
|
||||
) -> Coroutine[Any, Any, process_dot_process__pb2.ListResponse]:
|
||||
return self._list.acall_unary(req, **opts)
|
||||
|
||||
def connect(
|
||||
self, req: process_dot_process__pb2.ConnectRequest, **opts
|
||||
) -> Generator[process_dot_process__pb2.ConnectResponse, Any, None]:
|
||||
return self._connect.call_server_stream(req, **opts)
|
||||
|
||||
def aconnect(
|
||||
self, req: process_dot_process__pb2.ConnectRequest, **opts
|
||||
) -> AsyncGenerator[process_dot_process__pb2.ConnectResponse, Any]:
|
||||
return self._connect.acall_server_stream(req, **opts)
|
||||
|
||||
def start(
|
||||
self, req: process_dot_process__pb2.StartRequest, **opts
|
||||
) -> Generator[process_dot_process__pb2.StartResponse, Any, None]:
|
||||
return self._start.call_server_stream(req, **opts)
|
||||
|
||||
def astart(
|
||||
self, req: process_dot_process__pb2.StartRequest, **opts
|
||||
) -> AsyncGenerator[process_dot_process__pb2.StartResponse, Any]:
|
||||
return self._start.acall_server_stream(req, **opts)
|
||||
|
||||
def update(
|
||||
self, req: process_dot_process__pb2.UpdateRequest, **opts
|
||||
) -> process_dot_process__pb2.UpdateResponse:
|
||||
return self._update.call_unary(req, **opts)
|
||||
|
||||
def aupdate(
|
||||
self, req: process_dot_process__pb2.UpdateRequest, **opts
|
||||
) -> Coroutine[Any, Any, process_dot_process__pb2.UpdateResponse]:
|
||||
return self._update.acall_unary(req, **opts)
|
||||
|
||||
def stream_input(
|
||||
self, req: process_dot_process__pb2.StreamInputRequest, **opts
|
||||
) -> process_dot_process__pb2.StreamInputResponse:
|
||||
return self._stream_input.call_client_stream(req, **opts)
|
||||
|
||||
def astream_input(
|
||||
self, req: process_dot_process__pb2.StreamInputRequest, **opts
|
||||
) -> Coroutine[Any, Any, process_dot_process__pb2.StreamInputResponse]:
|
||||
return self._stream_input.acall_client_stream(req, **opts)
|
||||
|
||||
def send_input(
|
||||
self, req: process_dot_process__pb2.SendInputRequest, **opts
|
||||
) -> process_dot_process__pb2.SendInputResponse:
|
||||
return self._send_input.call_unary(req, **opts)
|
||||
|
||||
def asend_input(
|
||||
self, req: process_dot_process__pb2.SendInputRequest, **opts
|
||||
) -> Coroutine[Any, Any, process_dot_process__pb2.SendInputResponse]:
|
||||
return self._send_input.acall_unary(req, **opts)
|
||||
|
||||
def send_signal(
|
||||
self, req: process_dot_process__pb2.SendSignalRequest, **opts
|
||||
) -> process_dot_process__pb2.SendSignalResponse:
|
||||
return self._send_signal.call_unary(req, **opts)
|
||||
|
||||
def asend_signal(
|
||||
self, req: process_dot_process__pb2.SendSignalRequest, **opts
|
||||
) -> Coroutine[Any, Any, process_dot_process__pb2.SendSignalResponse]:
|
||||
return self._send_signal.acall_unary(req, **opts)
|
||||
|
||||
def close_stdin(
|
||||
self, req: process_dot_process__pb2.CloseStdinRequest, **opts
|
||||
) -> process_dot_process__pb2.CloseStdinResponse:
|
||||
return self._close_stdin.call_unary(req, **opts)
|
||||
|
||||
def aclose_stdin(
|
||||
self, req: process_dot_process__pb2.CloseStdinRequest, **opts
|
||||
) -> Coroutine[Any, Any, process_dot_process__pb2.CloseStdinResponse]:
|
||||
return self._close_stdin.acall_unary(req, **opts)
|
||||
+96
File diff suppressed because one or more lines are too long
+316
@@ -0,0 +1,316 @@
|
||||
from google.protobuf.internal import containers as _containers
|
||||
from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from typing import (
|
||||
ClassVar as _ClassVar,
|
||||
Iterable as _Iterable,
|
||||
Mapping as _Mapping,
|
||||
Optional as _Optional,
|
||||
Union as _Union,
|
||||
)
|
||||
|
||||
DESCRIPTOR: _descriptor.FileDescriptor
|
||||
|
||||
class Signal(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
|
||||
__slots__ = ()
|
||||
SIGNAL_UNSPECIFIED: _ClassVar[Signal]
|
||||
SIGNAL_SIGTERM: _ClassVar[Signal]
|
||||
SIGNAL_SIGKILL: _ClassVar[Signal]
|
||||
|
||||
SIGNAL_UNSPECIFIED: Signal
|
||||
SIGNAL_SIGTERM: Signal
|
||||
SIGNAL_SIGKILL: Signal
|
||||
|
||||
class PTY(_message.Message):
|
||||
__slots__ = ("size",)
|
||||
class Size(_message.Message):
|
||||
__slots__ = ("cols", "rows")
|
||||
COLS_FIELD_NUMBER: _ClassVar[int]
|
||||
ROWS_FIELD_NUMBER: _ClassVar[int]
|
||||
cols: int
|
||||
rows: int
|
||||
def __init__(
|
||||
self, cols: _Optional[int] = ..., rows: _Optional[int] = ...
|
||||
) -> None: ...
|
||||
|
||||
SIZE_FIELD_NUMBER: _ClassVar[int]
|
||||
size: PTY.Size
|
||||
def __init__(self, size: _Optional[_Union[PTY.Size, _Mapping]] = ...) -> None: ...
|
||||
|
||||
class ProcessConfig(_message.Message):
|
||||
__slots__ = ("cmd", "args", "envs", "cwd")
|
||||
class EnvsEntry(_message.Message):
|
||||
__slots__ = ("key", "value")
|
||||
KEY_FIELD_NUMBER: _ClassVar[int]
|
||||
VALUE_FIELD_NUMBER: _ClassVar[int]
|
||||
key: str
|
||||
value: str
|
||||
def __init__(
|
||||
self, key: _Optional[str] = ..., value: _Optional[str] = ...
|
||||
) -> None: ...
|
||||
|
||||
CMD_FIELD_NUMBER: _ClassVar[int]
|
||||
ARGS_FIELD_NUMBER: _ClassVar[int]
|
||||
ENVS_FIELD_NUMBER: _ClassVar[int]
|
||||
CWD_FIELD_NUMBER: _ClassVar[int]
|
||||
cmd: str
|
||||
args: _containers.RepeatedScalarFieldContainer[str]
|
||||
envs: _containers.ScalarMap[str, str]
|
||||
cwd: str
|
||||
def __init__(
|
||||
self,
|
||||
cmd: _Optional[str] = ...,
|
||||
args: _Optional[_Iterable[str]] = ...,
|
||||
envs: _Optional[_Mapping[str, str]] = ...,
|
||||
cwd: _Optional[str] = ...,
|
||||
) -> None: ...
|
||||
|
||||
class ListRequest(_message.Message):
|
||||
__slots__ = ()
|
||||
def __init__(self) -> None: ...
|
||||
|
||||
class ProcessInfo(_message.Message):
|
||||
__slots__ = ("config", "pid", "tag")
|
||||
CONFIG_FIELD_NUMBER: _ClassVar[int]
|
||||
PID_FIELD_NUMBER: _ClassVar[int]
|
||||
TAG_FIELD_NUMBER: _ClassVar[int]
|
||||
config: ProcessConfig
|
||||
pid: int
|
||||
tag: str
|
||||
def __init__(
|
||||
self,
|
||||
config: _Optional[_Union[ProcessConfig, _Mapping]] = ...,
|
||||
pid: _Optional[int] = ...,
|
||||
tag: _Optional[str] = ...,
|
||||
) -> None: ...
|
||||
|
||||
class ListResponse(_message.Message):
|
||||
__slots__ = ("processes",)
|
||||
PROCESSES_FIELD_NUMBER: _ClassVar[int]
|
||||
processes: _containers.RepeatedCompositeFieldContainer[ProcessInfo]
|
||||
def __init__(
|
||||
self, processes: _Optional[_Iterable[_Union[ProcessInfo, _Mapping]]] = ...
|
||||
) -> None: ...
|
||||
|
||||
class StartRequest(_message.Message):
|
||||
__slots__ = ("process", "pty", "tag", "stdin")
|
||||
PROCESS_FIELD_NUMBER: _ClassVar[int]
|
||||
PTY_FIELD_NUMBER: _ClassVar[int]
|
||||
TAG_FIELD_NUMBER: _ClassVar[int]
|
||||
STDIN_FIELD_NUMBER: _ClassVar[int]
|
||||
process: ProcessConfig
|
||||
pty: PTY
|
||||
tag: str
|
||||
stdin: bool
|
||||
def __init__(
|
||||
self,
|
||||
process: _Optional[_Union[ProcessConfig, _Mapping]] = ...,
|
||||
pty: _Optional[_Union[PTY, _Mapping]] = ...,
|
||||
tag: _Optional[str] = ...,
|
||||
stdin: bool = ...,
|
||||
) -> None: ...
|
||||
|
||||
class UpdateRequest(_message.Message):
|
||||
__slots__ = ("process", "pty")
|
||||
PROCESS_FIELD_NUMBER: _ClassVar[int]
|
||||
PTY_FIELD_NUMBER: _ClassVar[int]
|
||||
process: ProcessSelector
|
||||
pty: PTY
|
||||
def __init__(
|
||||
self,
|
||||
process: _Optional[_Union[ProcessSelector, _Mapping]] = ...,
|
||||
pty: _Optional[_Union[PTY, _Mapping]] = ...,
|
||||
) -> None: ...
|
||||
|
||||
class UpdateResponse(_message.Message):
|
||||
__slots__ = ()
|
||||
def __init__(self) -> None: ...
|
||||
|
||||
class ProcessEvent(_message.Message):
|
||||
__slots__ = ("start", "data", "end", "keepalive")
|
||||
class StartEvent(_message.Message):
|
||||
__slots__ = ("pid",)
|
||||
PID_FIELD_NUMBER: _ClassVar[int]
|
||||
pid: int
|
||||
def __init__(self, pid: _Optional[int] = ...) -> None: ...
|
||||
|
||||
class DataEvent(_message.Message):
|
||||
__slots__ = ("stdout", "stderr", "pty")
|
||||
STDOUT_FIELD_NUMBER: _ClassVar[int]
|
||||
STDERR_FIELD_NUMBER: _ClassVar[int]
|
||||
PTY_FIELD_NUMBER: _ClassVar[int]
|
||||
stdout: bytes
|
||||
stderr: bytes
|
||||
pty: bytes
|
||||
def __init__(
|
||||
self,
|
||||
stdout: _Optional[bytes] = ...,
|
||||
stderr: _Optional[bytes] = ...,
|
||||
pty: _Optional[bytes] = ...,
|
||||
) -> None: ...
|
||||
|
||||
class EndEvent(_message.Message):
|
||||
__slots__ = ("exit_code", "exited", "status", "error")
|
||||
EXIT_CODE_FIELD_NUMBER: _ClassVar[int]
|
||||
EXITED_FIELD_NUMBER: _ClassVar[int]
|
||||
STATUS_FIELD_NUMBER: _ClassVar[int]
|
||||
ERROR_FIELD_NUMBER: _ClassVar[int]
|
||||
exit_code: int
|
||||
exited: bool
|
||||
status: str
|
||||
error: str
|
||||
def __init__(
|
||||
self,
|
||||
exit_code: _Optional[int] = ...,
|
||||
exited: bool = ...,
|
||||
status: _Optional[str] = ...,
|
||||
error: _Optional[str] = ...,
|
||||
) -> None: ...
|
||||
|
||||
class KeepAlive(_message.Message):
|
||||
__slots__ = ()
|
||||
def __init__(self) -> None: ...
|
||||
|
||||
START_FIELD_NUMBER: _ClassVar[int]
|
||||
DATA_FIELD_NUMBER: _ClassVar[int]
|
||||
END_FIELD_NUMBER: _ClassVar[int]
|
||||
KEEPALIVE_FIELD_NUMBER: _ClassVar[int]
|
||||
start: ProcessEvent.StartEvent
|
||||
data: ProcessEvent.DataEvent
|
||||
end: ProcessEvent.EndEvent
|
||||
keepalive: ProcessEvent.KeepAlive
|
||||
def __init__(
|
||||
self,
|
||||
start: _Optional[_Union[ProcessEvent.StartEvent, _Mapping]] = ...,
|
||||
data: _Optional[_Union[ProcessEvent.DataEvent, _Mapping]] = ...,
|
||||
end: _Optional[_Union[ProcessEvent.EndEvent, _Mapping]] = ...,
|
||||
keepalive: _Optional[_Union[ProcessEvent.KeepAlive, _Mapping]] = ...,
|
||||
) -> None: ...
|
||||
|
||||
class StartResponse(_message.Message):
|
||||
__slots__ = ("event",)
|
||||
EVENT_FIELD_NUMBER: _ClassVar[int]
|
||||
event: ProcessEvent
|
||||
def __init__(
|
||||
self, event: _Optional[_Union[ProcessEvent, _Mapping]] = ...
|
||||
) -> None: ...
|
||||
|
||||
class ConnectResponse(_message.Message):
|
||||
__slots__ = ("event",)
|
||||
EVENT_FIELD_NUMBER: _ClassVar[int]
|
||||
event: ProcessEvent
|
||||
def __init__(
|
||||
self, event: _Optional[_Union[ProcessEvent, _Mapping]] = ...
|
||||
) -> None: ...
|
||||
|
||||
class SendInputRequest(_message.Message):
|
||||
__slots__ = ("process", "input")
|
||||
PROCESS_FIELD_NUMBER: _ClassVar[int]
|
||||
INPUT_FIELD_NUMBER: _ClassVar[int]
|
||||
process: ProcessSelector
|
||||
input: ProcessInput
|
||||
def __init__(
|
||||
self,
|
||||
process: _Optional[_Union[ProcessSelector, _Mapping]] = ...,
|
||||
input: _Optional[_Union[ProcessInput, _Mapping]] = ...,
|
||||
) -> None: ...
|
||||
|
||||
class SendInputResponse(_message.Message):
|
||||
__slots__ = ()
|
||||
def __init__(self) -> None: ...
|
||||
|
||||
class ProcessInput(_message.Message):
|
||||
__slots__ = ("stdin", "pty")
|
||||
STDIN_FIELD_NUMBER: _ClassVar[int]
|
||||
PTY_FIELD_NUMBER: _ClassVar[int]
|
||||
stdin: bytes
|
||||
pty: bytes
|
||||
def __init__(
|
||||
self, stdin: _Optional[bytes] = ..., pty: _Optional[bytes] = ...
|
||||
) -> None: ...
|
||||
|
||||
class StreamInputRequest(_message.Message):
|
||||
__slots__ = ("start", "data", "keepalive")
|
||||
class StartEvent(_message.Message):
|
||||
__slots__ = ("process",)
|
||||
PROCESS_FIELD_NUMBER: _ClassVar[int]
|
||||
process: ProcessSelector
|
||||
def __init__(
|
||||
self, process: _Optional[_Union[ProcessSelector, _Mapping]] = ...
|
||||
) -> None: ...
|
||||
|
||||
class DataEvent(_message.Message):
|
||||
__slots__ = ("input",)
|
||||
INPUT_FIELD_NUMBER: _ClassVar[int]
|
||||
input: ProcessInput
|
||||
def __init__(
|
||||
self, input: _Optional[_Union[ProcessInput, _Mapping]] = ...
|
||||
) -> None: ...
|
||||
|
||||
class KeepAlive(_message.Message):
|
||||
__slots__ = ()
|
||||
def __init__(self) -> None: ...
|
||||
|
||||
START_FIELD_NUMBER: _ClassVar[int]
|
||||
DATA_FIELD_NUMBER: _ClassVar[int]
|
||||
KEEPALIVE_FIELD_NUMBER: _ClassVar[int]
|
||||
start: StreamInputRequest.StartEvent
|
||||
data: StreamInputRequest.DataEvent
|
||||
keepalive: StreamInputRequest.KeepAlive
|
||||
def __init__(
|
||||
self,
|
||||
start: _Optional[_Union[StreamInputRequest.StartEvent, _Mapping]] = ...,
|
||||
data: _Optional[_Union[StreamInputRequest.DataEvent, _Mapping]] = ...,
|
||||
keepalive: _Optional[_Union[StreamInputRequest.KeepAlive, _Mapping]] = ...,
|
||||
) -> None: ...
|
||||
|
||||
class StreamInputResponse(_message.Message):
|
||||
__slots__ = ()
|
||||
def __init__(self) -> None: ...
|
||||
|
||||
class SendSignalRequest(_message.Message):
|
||||
__slots__ = ("process", "signal")
|
||||
PROCESS_FIELD_NUMBER: _ClassVar[int]
|
||||
SIGNAL_FIELD_NUMBER: _ClassVar[int]
|
||||
process: ProcessSelector
|
||||
signal: Signal
|
||||
def __init__(
|
||||
self,
|
||||
process: _Optional[_Union[ProcessSelector, _Mapping]] = ...,
|
||||
signal: _Optional[_Union[Signal, str]] = ...,
|
||||
) -> None: ...
|
||||
|
||||
class SendSignalResponse(_message.Message):
|
||||
__slots__ = ()
|
||||
def __init__(self) -> None: ...
|
||||
|
||||
class CloseStdinRequest(_message.Message):
|
||||
__slots__ = ("process",)
|
||||
PROCESS_FIELD_NUMBER: _ClassVar[int]
|
||||
process: ProcessSelector
|
||||
def __init__(
|
||||
self, process: _Optional[_Union[ProcessSelector, _Mapping]] = ...
|
||||
) -> None: ...
|
||||
|
||||
class CloseStdinResponse(_message.Message):
|
||||
__slots__ = ()
|
||||
def __init__(self) -> None: ...
|
||||
|
||||
class ConnectRequest(_message.Message):
|
||||
__slots__ = ("process",)
|
||||
PROCESS_FIELD_NUMBER: _ClassVar[int]
|
||||
process: ProcessSelector
|
||||
def __init__(
|
||||
self, process: _Optional[_Union[ProcessSelector, _Mapping]] = ...
|
||||
) -> None: ...
|
||||
|
||||
class ProcessSelector(_message.Message):
|
||||
__slots__ = ("pid", "tag")
|
||||
PID_FIELD_NUMBER: _ClassVar[int]
|
||||
TAG_FIELD_NUMBER: _ClassVar[int]
|
||||
pid: int
|
||||
tag: str
|
||||
def __init__(
|
||||
self, pid: _Optional[int] = ..., tag: _Optional[str] = ...
|
||||
) -> None: ...
|
||||
@@ -0,0 +1,139 @@
|
||||
import base64
|
||||
|
||||
import httpcore
|
||||
from typing import Awaitable, Callable, Optional
|
||||
from packaging.version import Version
|
||||
from e2b_connect.client import Code, ConnectException
|
||||
|
||||
from e2b.exceptions import (
|
||||
SandboxException,
|
||||
InvalidArgumentException,
|
||||
NotFoundException,
|
||||
TimeoutException,
|
||||
format_sandbox_timeout_exception,
|
||||
AuthenticationException,
|
||||
RateLimitException,
|
||||
)
|
||||
from e2b.connection_config import Username, default_username
|
||||
from e2b.envd.versions import ENVD_DEFAULT_USER
|
||||
|
||||
_DEFAULT_RPC_ERROR_MAP: dict[Code, Callable[[str], Exception]] = {
|
||||
Code.invalid_argument: InvalidArgumentException,
|
||||
Code.unauthenticated: AuthenticationException,
|
||||
Code.not_found: NotFoundException,
|
||||
Code.unavailable: format_sandbox_timeout_exception,
|
||||
Code.resource_exhausted: lambda message: RateLimitException(
|
||||
f"{message}: Rate limit exceeded, please try again later."
|
||||
),
|
||||
Code.canceled: lambda message: TimeoutException(
|
||||
f"{message}: This error is likely due to exceeding 'request_timeout'. You can pass the request timeout value as an option when making the request."
|
||||
),
|
||||
Code.deadline_exceeded: lambda message: TimeoutException(
|
||||
f"{message}: This error is likely due to exceeding 'timeout' — the total time a long running request (like process or directory watch) can be active. It can be modified by passing 'timeout' when making the request. Use '0' to disable the timeout."
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
def format_terminated_exception(
|
||||
e: Exception,
|
||||
sandbox_running: Optional[bool],
|
||||
) -> Exception:
|
||||
"""Handle an exception for a connection to the sandbox dropped mid-request: when a
|
||||
sandbox health probe confirmed the sandbox is gone (``sandbox_running is False``),
|
||||
return a ``TimeoutException``; otherwise return the original error unchanged."""
|
||||
if sandbox_running is False:
|
||||
return TimeoutException(
|
||||
f"{e}: The sandbox was killed or reached its end of life while the request was in flight."
|
||||
)
|
||||
return e
|
||||
|
||||
|
||||
def handle_rpc_exception(
|
||||
e: Exception,
|
||||
error_map: Optional[dict[Code, Callable[[str], Exception]]] = None,
|
||||
sandbox_running: Optional[bool] = None,
|
||||
):
|
||||
"""Handle errors from envd RPC calls by mapping gRPC status codes to specific exception types.
|
||||
|
||||
:param e: The caught exception, expected to be a ``ConnectException`` or a transport-level ``httpcore`` error.
|
||||
:param error_map: Optional map of gRPC codes to exception factories that override the defaults.
|
||||
:param sandbox_running: Result of a sandbox health probe (``None`` when unknown), used to disambiguate a connection dropped mid-request.
|
||||
:return: The corresponding exception. A connection dropped mid-request with the sandbox confirmed gone becomes a ``TimeoutException``; non-``ConnectException`` errors are otherwise returned as-is.
|
||||
"""
|
||||
if isinstance(e, ConnectException):
|
||||
if error_map and e.status in error_map:
|
||||
return error_map[e.status](e.message)
|
||||
|
||||
if e.status in _DEFAULT_RPC_ERROR_MAP:
|
||||
return _DEFAULT_RPC_ERROR_MAP[e.status](e.message)
|
||||
|
||||
return SandboxException(f"{e.status}: {e.message}")
|
||||
|
||||
# A remote protocol error (e.g. an HTTP/2 stream reset) means the connection to the
|
||||
# sandbox was dropped mid-request — either the sandbox died or the network failed
|
||||
if isinstance(e, httpcore.RemoteProtocolError):
|
||||
return format_terminated_exception(e, sandbox_running)
|
||||
|
||||
# A transport-level timeout from httpcore means a configured timeout was exceeded
|
||||
# before the server responded: `request_timeout` on a unary call's read phase, or
|
||||
# `connect`/`pool`/`write` on a stream's setup/send phase. Streams have no read
|
||||
# timeout — the command `timeout` is enforced server-side and surfaces as a
|
||||
# `deadline_exceeded` ConnectException instead. Unlike the JS SDK, where the
|
||||
# request timeout is an `AbortSignal` that connect normalizes into a `Code.canceled`
|
||||
# ConnectError, httpcore raises this raw transport error outside the ConnectException
|
||||
# path, so we map it here to a `TimeoutException` for a consistent timeout error.
|
||||
if isinstance(e, httpcore.TimeoutException):
|
||||
return TimeoutException(
|
||||
f"{e}: This error is likely due to exceeding 'timeout' — the total time a long running request (like process or directory watch) can be active — or 'request_timeout'. You can modify these by passing 'timeout' or 'request_timeout' when making the request. Use '0' to disable the timeout."
|
||||
)
|
||||
|
||||
return e
|
||||
|
||||
|
||||
def handle_rpc_exception_with_health(
|
||||
e: Exception,
|
||||
check_health: Optional[Callable[[], Optional[bool]]] = None,
|
||||
error_map: Optional[dict[Code, Callable[[str], Exception]]] = None,
|
||||
):
|
||||
"""Like :func:`handle_rpc_exception`, but when the connection to the sandbox was
|
||||
dropped mid-request it probes the sandbox health to tell apart the sandbox being
|
||||
killed from a transient network failure (e.g. a load balancer dropping the connection).
|
||||
"""
|
||||
sandbox_running = None
|
||||
if check_health is not None and isinstance(e, httpcore.RemoteProtocolError):
|
||||
try:
|
||||
sandbox_running = check_health()
|
||||
except Exception:
|
||||
sandbox_running = None
|
||||
return handle_rpc_exception(e, error_map, sandbox_running)
|
||||
|
||||
|
||||
async def ahandle_rpc_exception_with_health(
|
||||
e: Exception,
|
||||
check_health: Optional[Callable[[], Awaitable[Optional[bool]]]] = None,
|
||||
error_map: Optional[dict[Code, Callable[[str], Exception]]] = None,
|
||||
):
|
||||
"""Async version of :func:`handle_rpc_exception_with_health`."""
|
||||
sandbox_running = None
|
||||
if check_health is not None and isinstance(e, httpcore.RemoteProtocolError):
|
||||
try:
|
||||
sandbox_running = await check_health()
|
||||
except Exception:
|
||||
sandbox_running = None
|
||||
return handle_rpc_exception(e, error_map, sandbox_running)
|
||||
|
||||
|
||||
def authentication_header(
|
||||
envd_version: Version, user: Optional[Username] = None
|
||||
) -> dict[str, str]:
|
||||
if user is None and envd_version < ENVD_DEFAULT_USER:
|
||||
user = default_username
|
||||
|
||||
if not user:
|
||||
return {}
|
||||
|
||||
value = f"{user}:"
|
||||
|
||||
encoded = base64.b64encode(value.encode("utf-8")).decode("utf-8")
|
||||
|
||||
return {"Authorization": f"Basic {encoded}"}
|
||||
@@ -0,0 +1,11 @@
|
||||
from packaging.version import Version
|
||||
|
||||
ENVD_VERSION_RECURSIVE_WATCH = Version("0.1.4")
|
||||
ENVD_DEBUG_FALLBACK = Version("99.99.99")
|
||||
ENVD_COMMANDS_STDIN = Version("0.3.0")
|
||||
ENVD_DEFAULT_USER = Version("0.4.0")
|
||||
ENVD_ENVD_CLOSE = Version("0.5.2")
|
||||
ENVD_OCTET_STREAM_UPLOAD = Version("0.5.7")
|
||||
ENVD_FILE_METADATA = Version("0.6.2")
|
||||
ENVD_VERSION_FS_EVENT_ENTRY_INFO = Version("0.6.3")
|
||||
ENVD_VERSION_WATCH_NETWORK_MOUNTS = Version("0.6.4")
|
||||
Reference in New Issue
Block a user