Skip to content

Commit 4b93434

Browse files
authored
Merge pull request #128 from aaron-ang/redirect-stderr
fix: stderr redirection
2 parents 2b09b82 + 40df293 commit 4b93434

1 file changed

Lines changed: 44 additions & 37 deletions

File tree

pywhispercpp/utils.py

Lines changed: 44 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,25 @@
11
#!/usr/bin/env python
2-
# -*- coding: utf-8 -*-
32

43
"""
54
Helper functions
65
"""
6+
77
import contextlib
88
import logging
99
import os
1010
import sys
1111
from pathlib import Path
12+
from typing import TextIO
13+
1214
import requests
1315
from tqdm import tqdm
14-
from pywhispercpp.constants import MODELS_BASE_URL, MODELS_PREFIX_URL, AVAILABLE_MODELS, MODELS_DIR
1516

17+
from pywhispercpp.constants import (
18+
AVAILABLE_MODELS,
19+
MODELS_BASE_URL,
20+
MODELS_DIR,
21+
MODELS_PREFIX_URL,
22+
)
1623

1724
logger = logging.getLogger(__name__)
1825

@@ -185,7 +192,7 @@ def output_csv(segments: list, output_file_path: str) -> str:
185192

186193

187194
@contextlib.contextmanager
188-
def redirect_stderr(to=False) -> None:
195+
def redirect_stderr(to: bool | TextIO | str | None = False) -> None:
189196
"""
190197
Redirect stderr to the specified target.
191198
@@ -201,45 +208,45 @@ def redirect_stderr(to=False) -> None:
201208
yield
202209
return
203210

211+
def _resolve_target(target):
212+
opened_stream = None
213+
if target is None:
214+
opened_stream = open(os.devnull, "w")
215+
return opened_stream, True
216+
if isinstance(target, str):
217+
opened_stream = open(target, "w")
218+
return opened_stream, True
219+
if hasattr(target, "write"):
220+
return target, False
221+
raise ValueError(
222+
"Invalid `to` parameter; expected None, a filepath string, or a file-like object."
223+
)
224+
204225
sys.stderr.flush()
205226
try:
206-
original_stderr_fd = sys.stderr.fileno()
207-
has_fileno = True
227+
original_fd = sys.stderr.fileno()
208228
except (AttributeError, OSError):
209229
# Jupyter or non-standard stderr implementations
210-
has_fileno = False
211-
212-
if has_fileno:
213-
if to is None:
214-
target_fd = os.open(os.devnull, os.O_WRONLY)
215-
elif isinstance(to, str):
216-
file = open(to, 'w')
217-
target_fd = file.fileno()
218-
elif hasattr(to, 'fileno'):
219-
target_fd = to.fileno()
220-
else:
221-
raise ValueError("Invalid `to` parameter; must be None, a filepath string, or sys.stdout/sys.stderr.")
222-
os.dup2(target_fd, original_stderr_fd)
230+
original_fd = None
231+
232+
stream, should_close = _resolve_target(to)
233+
234+
if original_fd is not None and hasattr(stream, "fileno"):
235+
saved_fd = os.dup(original_fd)
223236
try:
237+
os.dup2(stream.fileno(), original_fd)
224238
yield
225239
finally:
226-
os.dup2(original_stderr_fd, original_stderr_fd)
227-
if isinstance(to, str):
228-
file.close()
229-
elif to is None:
230-
os.close(target_fd)
231-
else:
232-
# Replace sys.stderr directly
233-
original_stderr = sys.stderr
234-
if to is None:
235-
sys.stderr = open(os.devnull, 'w')
236-
elif isinstance(to, str):
237-
sys.stderr = open(to, 'w')
238-
elif hasattr(to, 'write'):
239-
sys.stderr = to
240-
try:
240+
os.dup2(saved_fd, original_fd)
241+
os.close(saved_fd)
242+
if should_close:
243+
stream.close()
244+
return
245+
246+
# Fallback: Python-level redirect
247+
try:
248+
with contextlib.redirect_stderr(stream):
241249
yield
242-
finally:
243-
sys.stderr = original_stderr
244-
if isinstance(to, str) or to is None:
245-
sys.stderr.close()
250+
finally:
251+
if should_close:
252+
stream.close()

0 commit comments

Comments
 (0)