Add return type annotations to docker runtime (#8543)

Co-authored-by: openhands <openhands@all-hands.dev>
This commit is contained in:
Graham Neubig
2025-06-04 11:24:25 -04:00
committed by GitHub
parent 7652ccb000
commit c403973616

View File

@@ -41,7 +41,7 @@ APP_PORT_RANGE_1 = (50000, 54999)
APP_PORT_RANGE_2 = (55000, 59999)
def _is_retryablewait_until_alive_error(exception):
def _is_retryablewait_until_alive_error(exception: Exception) -> bool:
if isinstance(exception, tenacity.RetryError):
cause = exception.last_attempt.exception()
return _is_retryablewait_until_alive_error(cause)
@@ -140,10 +140,10 @@ class DockerRuntime(ActionExecutionClient):
)
@property
def action_execution_server_url(self):
def action_execution_server_url(self) -> str:
return self.api_url
async def connect(self):
async def connect(self) -> None:
self.send_status_message('STATUS$STARTING_RUNTIME')
try:
await call_sync_from_async(self._attach_to_container)
@@ -264,7 +264,7 @@ class DockerRuntime(ActionExecutionClient):
return volumes
def init_container(self):
def init_container(self) -> None:
self.log('debug', 'Preparing to start container...')
self.send_status_message('STATUS$PREPARING_CONTAINER')
self._host_port = self._find_available_port(EXECUTION_SERVER_PORT_RANGE)
@@ -317,15 +317,18 @@ class DockerRuntime(ActionExecutionClient):
)
# Combine environment variables
environment = {
'port': str(self._container_port),
'PYTHONUNBUFFERED': '1',
# Passing in the ports means nested runtimes do not come up with their own ports!
'VSCODE_PORT': str(self._vscode_port),
'APP_PORT_1': self._app_ports[0],
'APP_PORT_2': self._app_ports[1],
'PIP_BREAK_SYSTEM_PACKAGES': '1',
}
environment = dict(**self.initial_env_vars)
environment.update(
{
'port': str(self._container_port),
'PYTHONUNBUFFERED': '1',
# Passing in the ports means nested runtimes do not come up with their own ports!
'VSCODE_PORT': str(self._vscode_port),
'APP_PORT_1': str(self._app_ports[0]),
'APP_PORT_2': str(self._app_ports[1]),
'PIP_BREAK_SYSTEM_PACKAGES': '1',
}
)
if self.config.debug or DEBUG:
environment['DEBUG'] = 'true'
# also update with runtime_startup_env_vars
@@ -396,7 +399,7 @@ class DockerRuntime(ActionExecutionClient):
self.close()
raise e
def _attach_to_container(self):
def _attach_to_container(self) -> None:
self.container = self.docker_client.containers.get(self.container_name)
if self.container.status == 'exited':
self.container.start()
@@ -432,7 +435,7 @@ class DockerRuntime(ActionExecutionClient):
reraise=True,
wait=tenacity.wait_fixed(2),
)
def wait_until_alive(self):
def wait_until_alive(self) -> None:
try:
container = self.docker_client.containers.get(self.container_name)
if container.status == 'exited':
@@ -446,7 +449,7 @@ class DockerRuntime(ActionExecutionClient):
self.check_if_alive()
def close(self, rm_all_containers: bool | None = None):
def close(self, rm_all_containers: bool | None = None) -> None:
"""Closes the DockerRuntime and associated objects
Parameters:
@@ -466,7 +469,7 @@ class DockerRuntime(ActionExecutionClient):
)
stop_all_containers(close_prefix)
def _is_port_in_use_docker(self, port):
def _is_port_in_use_docker(self, port: int) -> bool:
containers = self.docker_client.containers.list()
for container in containers:
container_ports = container.ports
@@ -474,7 +477,9 @@ class DockerRuntime(ActionExecutionClient):
return True
return False
def _find_available_port(self, port_range, max_attempts=5):
def _find_available_port(
self, port_range: tuple[int, int], max_attempts: int = 5
) -> int:
port = port_range[1]
for _ in range(max_attempts):
port = find_available_tcp_port(port_range[0], port_range[1])
@@ -493,7 +498,7 @@ class DockerRuntime(ActionExecutionClient):
return vscode_url
@property
def web_hosts(self):
def web_hosts(self) -> dict[str, int]:
hosts: dict[str, int] = {}
host_addr = os.environ.get('DOCKER_HOST_ADDR', 'localhost')
@@ -502,7 +507,7 @@ class DockerRuntime(ActionExecutionClient):
return hosts
def pause(self):
def pause(self) -> None:
"""Pause the runtime by stopping the container.
This is different from container.stop() as it ensures environment variables are properly preserved."""
if not self.container:
@@ -515,7 +520,7 @@ class DockerRuntime(ActionExecutionClient):
self.container.stop()
self.log('debug', f'Container {self.container_name} paused')
def resume(self):
def resume(self) -> None:
"""Resume the runtime by starting the container.
This is different from container.start() as it ensures environment variables are properly restored."""
if not self.container:
@@ -529,7 +534,7 @@ class DockerRuntime(ActionExecutionClient):
self.wait_until_alive()
@classmethod
async def delete(cls, conversation_id: str):
async def delete(cls, conversation_id: str) -> None:
docker_client = cls._init_docker_client()
try:
container_name = CONTAINER_NAME_PREFIX + conversation_id
@@ -542,7 +547,7 @@ class DockerRuntime(ActionExecutionClient):
finally:
docker_client.close()
def get_action_execution_server_startup_command(self):
def get_action_execution_server_startup_command(self) -> list[str]:
return get_action_execution_server_startup_command(
server_port=self._container_port,
plugins=self.plugins,