Add tests and fix error handling for stream callbacks

This commit is contained in:
jaseg 2023-02-26 20:15:27 +01:00
parent f9a655e7ca
commit 7343604f10
2 changed files with 128 additions and 9 deletions

28
mpv.py
View file

@ -898,10 +898,13 @@ class MPV(object):
try:
yield
except Exception as e:
try:
fut = next(iter(self._exception_futures))
fut.set_exception(e)
except StopIteration:
for fut in self._exception_futures:
try:
fut.set_exception(e)
break
except InvalidStateError:
pass
else:
warn(f'Unhandled exception on python-mpv event loop: {e}\n{traceback.format_exc()}', RuntimeWarning)
def _loop(self):
@ -1087,7 +1090,6 @@ class MPV(object):
@self.event_callback(*event_types)
def target_handler(evt):
try:
rv = cond(evt)
if rv:
@ -1801,12 +1803,17 @@ class MPV(object):
except ValueError:
return ErrorCode.LOADING_FAILED
except Exception as e:
try:
fut = next(iter(self._exception_futures))
fut.set_exception(e)
except StopIteration:
for fut in self._exception_futures:
try:
fut.set_exception(e)
break
except InvalidStateError:
pass
else:
warnings.warn(f'Unhandled exception {e} inside stream open callback for URI {uri}\n{traceback.format_exc()}')
return ErrorCode.LOADING_FAILED
cb_info.contents.cookie = None
@ -1817,6 +1824,7 @@ class MPV(object):
for i in range(len(data)):
buf[i] = data[i]
return len(data)
return -1
read = cb_info.contents.read = StreamReadFn(read_backend)
def close_backend(_userdata):
@ -1832,12 +1840,14 @@ class MPV(object):
def seek_backend(_userdata, offx):
with self._enqueue_exceptions():
return frontend.seek(offx)
return ErrorCode.GENERIC
seek = cb_info.contents.seek = StreamSeekFn(seek_backend)
if hasattr(frontend, 'size') and frontend.size is not None:
def size_backend(_userdata):
with self._enqueue_exceptions():
return frontend.size
return 0
size = cb_info.contents.size = StreamSizeFn(size_backend)
if hasattr(frontend, 'cancel'):

View file

@ -535,6 +535,115 @@ class TestStreams(unittest.TestCase):
m.terminate()
disp.stop()
def test_stream_open_exception(self):
disp = Xvfb()
disp.start()
m = mpv.MPV(vo=testvo, video=False)
@m.register_stream_protocol('raiseerror')
def open_fn(uri):
raise SystemError()
waiting = threading.Semaphore()
result = Future()
def run():
result.set_running_or_notify_cancel()
try:
waiting.release()
m.wait_for_playback()
result.set_result(False)
except SystemError:
result.set_result(True)
except Exception:
result.set_result(False)
t = threading.Thread(target=run, daemon=True)
t.start()
with waiting:
time.sleep(0.2)
m.play('raiseerror://foo')
m.wait_for_playback(catch_errors=False)
try:
assert result.result()
finally:
m.terminate()
disp.stop()
def test_python_stream_exception(self):
disp = Xvfb()
disp.start()
m = mpv.MPV(vo=testvo)
@m.python_stream('foo')
def foo_gen():
with open(TESTVID, 'rb') as f:
yield f.read(100)
raise SystemError()
waiting = threading.Semaphore()
result = Future()
def run():
result.set_running_or_notify_cancel()
try:
waiting.release()
m.wait_for_playback()
result.set_result(False)
except SystemError:
result.set_result(True)
except Exception:
result.set_result(False)
t = threading.Thread(target=run, daemon=True)
t.start()
with waiting:
time.sleep(0.2)
m.play('python://foo')
m.wait_for_playback(catch_errors=False)
try:
assert result.result()
finally:
m.terminate()
disp.stop()
def test_stream_open_forward(self):
disp = Xvfb()
disp.start()
m = mpv.MPV(vo=testvo, video=False)
@m.register_stream_protocol('raiseerror')
def open_fn(uri):
raise ValueError()
waiting = threading.Semaphore()
result = Future()
def run():
result.set_running_or_notify_cancel()
try:
waiting.release()
m.wait_for_playback()
result.set_result(True)
except Exception:
result.set_result(False)
t = threading.Thread(target=run, daemon=True)
t.start()
with waiting:
time.sleep(0.2)
m.play('raiseerror://foo')
m.wait_for_playback(catch_errors=False)
try:
assert result.result()
finally:
m.terminate()
disp.stop()
class TestLifecycle(unittest.TestCase):
def test_create_destroy(self):