porcelain: Add fancy wait_for_event/property future handling

This commit is contained in:
jaseg 2022-04-17 22:37:10 +02:00
parent 3d956b91f8
commit c12e1ed8a1

66
mpv.py
View file

@ -24,7 +24,7 @@ import sys
from warnings import warn from warnings import warn
from functools import partial, wraps from functools import partial, wraps
from contextlib import contextmanager from contextlib import contextmanager
from concurrent.futures import Future from concurrent.futures import Future, InvalidStateError
import collections import collections
import re import re
import traceback import traceback
@ -925,25 +925,16 @@ class MPV(object):
properties such as ``idle_active`` indicating the player is done with regular playback and just idling around. properties such as ``idle_active`` indicating the player is done with regular playback and just idling around.
Raises a ShutdownError when the core is shutdown while waiting. Raises a ShutdownError when the core is shutdown while waiting.
""" """
with self.prepare_and_wait_for_property(name, cond, level_sensitive, timeout=timeout): with self.prepare_and_wait_for_property(name, cond, level_sensitive, timeout=timeout) as result:
pass pass
return result.result()
def wait_for_shutdown(self, timeout=None): def wait_for_shutdown(self, timeout=None):
'''Wait for core to shutdown (e.g. through quit() or terminate()).''' '''Wait for core to shutdown (e.g. through quit() or terminate()).'''
result = Future()
@self.event_callback('shutdown')
def shutdown_handler(event):
result.set_result(None)
try: try:
if self._core_shutdown: self.wait_for_event(None, timeout=timeout)
return except ShutdownError:
return
result.set_running_or_notify_cancel()
return result.result(timeout)
finally:
shutdown_handler.unregister_mpv_events()
@contextmanager @contextmanager
def prepare_and_wait_for_property(self, name, cond=lambda val: val, level_sensitive=True, timeout=None): def prepare_and_wait_for_property(self, name, cond=lambda val: val, level_sensitive=True, timeout=None):
@ -959,20 +950,32 @@ class MPV(object):
if rv: if rv:
result.set_result(rv) result.set_result(rv)
except Exception as e: except Exception as e:
result.set_exception(e) try:
result.set_exception(e)
except InvalidStateError:
pass
except InvalidStateError:
pass
self.observe_property(name, observer) self.observe_property(name, observer)
@self.event_callback('shutdown') @self.event_callback('shutdown')
def shutdown_handler(event): def shutdown_handler(event):
result.set_exception(ShutdownError('libmpv core has been shutdown')) try:
result.set_exception(ShutdownError('libmpv core has been shutdown'))
except InvalidStateError:
pass
try: try:
yield result.set_running_or_notify_cancel()
yield result
if not level_sensitive or not cond(getattr(self, name.replace('-', '_'))): rv = cond(getattr(self, name.replace('-', '_')))
if level_sensitive and rv:
result.set_result(rv)
else:
self.check_core_alive() self.check_core_alive()
result.set_running_or_notify_cancel() result.result(timeout)
return result.result(timeout)
finally: finally:
shutdown_handler.unregister_mpv_events() shutdown_handler.unregister_mpv_events()
self.unobserve_property(name, observer) self.unobserve_property(name, observer)
@ -982,8 +985,9 @@ class MPV(object):
if the core is shutdown while waiting. This also happens when 'shutdown' is in event_types. Re-raises any error if the core is shutdown while waiting. This also happens when 'shutdown' is in event_types. Re-raises any error
inside ``cond``. inside ``cond``.
""" """
with self.prepare_and_wait_for_event(*event_types, cond=cond, timeout=timeout): with self.prepare_and_wait_for_event(*event_types, cond=cond, timeout=timeout) as result:
pass pass
return result.result()
@contextmanager @contextmanager
def prepare_and_wait_for_event(self, *event_types, cond=lambda evt: True, timeout=None): def prepare_and_wait_for_event(self, *event_types, cond=lambda evt: True, timeout=None):
@ -1004,7 +1008,10 @@ class MPV(object):
@self.event_callback('shutdown') @self.event_callback('shutdown')
def shutdown_handler(event): def shutdown_handler(event):
result.set_exception(ShutdownError('libmpv core has been shutdown')) try:
result.set_exception(ShutdownError('libmpv core has been shutdown'))
except InvalidStateError:
pass
@self.event_callback(*event_types) @self.event_callback(*event_types)
def target_handler(evt): def target_handler(evt):
@ -1014,13 +1021,18 @@ class MPV(object):
if rv: if rv:
result.set_result(rv) result.set_result(rv)
except Exception as e: except Exception as e:
result.set_exception(e) try:
result.set_exception(e)
except InvalidStateError:
pass
except InvalidStateError:
pass
try: try:
yield
self.check_core_alive()
result.set_running_or_notify_cancel() result.set_running_or_notify_cancel()
return result.result(timeout) yield result
self.check_core_alive()
result.result(timeout)
finally: finally:
shutdown_handler.unregister_mpv_events() shutdown_handler.unregister_mpv_events()