Skip to content

Commit b615fc4

Browse files
authored
More accurate error handling when streaming stdout and stderr (#703)
This aims to fix the bug raised in this [issue](#647) The only code change is to lift the exception decoding into its own function so that `run` and `stream_stdout_and_stderr` can use the same logic when decoding error cases for consistency.
1 parent ee87a94 commit b615fc4

File tree

1 file changed

+31
-56
lines changed

1 file changed

+31
-56
lines changed

python_on_whales/utils.py

Lines changed: 31 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from __future__ import annotations
2+
13
import logging
24
import os
35
import shlex
@@ -100,6 +102,29 @@ class DockerCamelModel(pydantic.BaseModel):
100102
)
101103

102104

105+
def get_docker_exception_type(output: Optional[bytes]) -> type[DockerException]:
106+
if not output:
107+
return DockerException
108+
decoded = output.decode().lower()
109+
if "no such image" in decoded or "image not known" in decoded:
110+
return NoSuchImage
111+
if "no such service" in decoded or (
112+
"service" in decoded and "not found" in decoded
113+
):
114+
return NoSuchService
115+
if "no such container" in decoded:
116+
return NoSuchContainer
117+
if "no such pod" in decoded:
118+
return NoSuchPod
119+
if "this node is not a swarm manager" in decoded:
120+
return NotASwarmManager
121+
if "no such volume" in decoded:
122+
return NoSuchVolume
123+
if "network" in decoded and "not found" in decoded:
124+
return NoSuchNetwork
125+
return DockerException
126+
127+
103128
@overload
104129
def run(
105130
args: List[Any],
@@ -169,61 +194,8 @@ def run(
169194
)
170195

171196
if completed_process.returncode != 0:
172-
if completed_process.stderr is not None:
173-
decoded_stderr = completed_process.stderr.decode().lower()
174-
if "no such image" in decoded_stderr or "image not known" in decoded_stderr:
175-
raise NoSuchImage(
176-
args,
177-
completed_process.returncode,
178-
completed_process.stdout,
179-
completed_process.stderr,
180-
)
181-
if "no such service" in decoded_stderr or (
182-
"service" in decoded_stderr and "not found" in decoded_stderr
183-
):
184-
raise NoSuchService(
185-
args,
186-
completed_process.returncode,
187-
completed_process.stdout,
188-
completed_process.stderr,
189-
)
190-
if "no such container" in decoded_stderr:
191-
raise NoSuchContainer(
192-
args,
193-
completed_process.returncode,
194-
completed_process.stdout,
195-
completed_process.stderr,
196-
)
197-
if "no such pod" in decoded_stderr:
198-
raise NoSuchPod(
199-
args,
200-
completed_process.returncode,
201-
completed_process.stdout,
202-
completed_process.stderr,
203-
)
204-
if "this node is not a swarm manager" in decoded_stderr:
205-
raise NotASwarmManager(
206-
args,
207-
completed_process.returncode,
208-
completed_process.stdout,
209-
completed_process.stderr,
210-
)
211-
if "no such volume" in decoded_stderr:
212-
raise NoSuchVolume(
213-
args,
214-
completed_process.returncode,
215-
completed_process.stdout,
216-
completed_process.stderr,
217-
)
218-
if "network" in decoded_stderr and "not found" in decoded_stderr:
219-
raise NoSuchNetwork(
220-
args,
221-
completed_process.returncode,
222-
completed_process.stdout,
223-
completed_process.stderr,
224-
)
225-
226-
raise DockerException(
197+
exception_type = get_docker_exception_type(completed_process.stderr)
198+
raise exception_type(
227199
args,
228200
completed_process.returncode,
229201
completed_process.stdout,
@@ -321,7 +293,10 @@ def stream_stdout_and_stderr(
321293

322294
exit_code = process.wait()
323295
if exit_code != 0:
324-
raise DockerException(full_cmd, exit_code, stderr=full_stderr)
296+
exception_type = get_docker_exception_type(full_stderr)
297+
raise exception_type(
298+
command_launched=full_cmd, return_code=exit_code, stderr=full_stderr
299+
)
325300

326301

327302
def format_mapping_for_cli(mapping: Mapping[str, str], separator="="):

0 commit comments

Comments
 (0)