BREAKING: Move property observation API to NODE format

This commit is contained in:
jaseg 2017-05-10 18:25:31 +02:00
parent 303eedbb3b
commit c47bd2a2c6
2 changed files with 25 additions and 44 deletions

View file

@ -151,7 +151,7 @@ class ObservePropertyTest(unittest.TestCase):
m.loop = 'no' m.loop = 'no'
m.loop = 'inf' m.loop = 'inf'
m.terminate() # needed for synchronization of event thread m.terminate() # needed for synchronization of event thread
handler.assert_has_calls([mock.call('no'), mock.call('inf')]) handler.assert_has_calls([mock.call('loop', False), mock.call('loop', 'inf')])
class TestLifecycle(unittest.TestCase): class TestLifecycle(unittest.TestCase):

67
mpv.py
View file

@ -228,17 +228,13 @@ class MpvEventProperty(Structure):
_fields_ = [('name', c_char_p), _fields_ = [('name', c_char_p),
('format', MpvFormat), ('format', MpvFormat),
('data', c_void_p)] ('data', c_void_p)]
def as_dict(self): def as_dict(self, decode_str=False):
if self.format.value == MpvFormat.STRING: proptype, _access = ALL_PROPERTIES.get(self.name, (str, None))
proptype, _access = ALL_PROPERTIES.get(self.name, (str, None)) value = MpvNode.node_cast_value(self.data, self.format.value, decode_str or proptype in (str, _commalist))
return {'name': self.name.decode('utf-8'), return {'name': self.name.decode('utf-8'),
'format': self.format, 'format': self.format,
'data': self.data, 'data': self.data,
'value': proptype(cast(self.data, POINTER(c_char_p)).contents.value.decode('utf-8'))} 'value': value}
else:
return {'name': self.name.decode('utf-8'),
'format': self.format,
'data': self.data}
class MpvEventLogMessage(Structure): class MpvEventLogMessage(Structure):
_fields_ = [('prefix', c_char_p), _fields_ = [('prefix', c_char_p),
@ -394,21 +390,10 @@ def _event_loop(event_handle, playback_cond, event_callbacks, message_handlers,
playback_cond.notify_all() playback_cond.notify_all()
if eid == MpvEventID.PROPERTY_CHANGE: if eid == MpvEventID.PROPERTY_CHANGE:
pc = devent['event'] pc = devent['event']
name = pc['name'] name, value = pc['name'], pc['value']
if 'value' in pc:
proptype, _access = ALL_PROPERTIES[name]
if proptype is bytes:
args = (pc['value'],)
else:
args = (proptype(_ensure_encoding(pc['value'])),)
elif pc['format'] == MpvFormat.NONE:
args = (None,)
else:
args = (pc['data'], pc['format'])
for handler in property_handlers[name]: for handler in property_handlers[name]:
handler(*args) handler(name, value)
if eid == MpvEventID.LOG_MESSAGE and log_handler is not None: if eid == MpvEventID.LOG_MESSAGE and log_handler is not None:
ev = devent['event'] ev = devent['event']
log_handler(ev['level'], ev['prefix'], ev['text']) log_handler(ev['level'], ev['prefix'], ev['text'])
@ -479,7 +464,7 @@ class MPV(object):
```idle_active``` indicating the player is done with regular playback ```idle_active``` indicating the player is done with regular playback
and just idling around """ and just idling around """
sema = threading.Semaphore(value=0) sema = threading.Semaphore(value=0)
def observer(val): def observer(name, val):
if cond(val): if cond(val):
sema.release() sema.release()
self.observe_property(name, observer) self.observe_property(name, observer)
@ -655,37 +640,33 @@ class MPV(object):
""" Mapped mpv seek command, see man mpv(1). """ """ Mapped mpv seek command, see man mpv(1). """
self.command('script_message_to', target, *args) self.command('script_message_to', target, *args)
def observe_property(self, name, handler=None): def observe_property(self, name, handler):
""" Register an observer on the named property. An observer is a """ Register an observer on the named property. An observer is a function that is called with the new property
function that is called with the new property value every time the value every time the property's value is changed. The basic function signature is ```fun(property_name,
property's value is changed. The basic function signature is new_value)``` with new_value being the decoded property value as a python object. This function can be used as a
```fun(new_value)``` with new_value being the decoded property value as function decorator if no handler is given.
a python object. This function can be used as a function decorator if
no handler is given.
To uunregister the observer, call either of ```mpv.unobserve_property(name, handler)```, To uunregister the observer, call either of ```mpv.unobserve_property(name, handler)```,
```mpv.unobserve_all_properties(handler)``` or the handler's ```unregister_mpv_properties``` attribute: ```mpv.unobserve_all_properties(handler)``` or the handler's ```unregister_mpv_properties``` attribute:
``` ```
@player.observe_property('volume') @player.observe_property('volume')
def my_handler(new_volume): def my_handler(new_volume, *):
print("It's loud!", volume) print("It's loud!", volume)
my_handler.unregister_mpv_properties() my_handler.unregister_mpv_properties()
``` """ ``` """
if handler is None:
def wrapper(fun):
self._observe_property_internal(name, handler)
return fun
return wrapper
else:
self._observe_property_internal(name, handler)
def _observe_property_internal(self, name, handler):
handler.observed_mpv_properties = getattr(handler, 'observed_mpv_properties', []) + [name] handler.observed_mpv_properties = getattr(handler, 'observed_mpv_properties', []) + [name]
handler.unregister_mpv_properties = lambda: self.unobserve_property(None, handler) handler.unregister_mpv_properties = lambda: self.unobserve_property(None, handler)
self._property_handlers[name].append(handler) self._property_handlers[name].append(handler)
_mpv_observe_property(self._event_handle, hash(name)&0xffffffffffffffff, name.encode('utf-8'), MpvFormat.STRING) _mpv_observe_property(self._event_handle, hash(name)&0xffffffffffffffff, name.encode('utf-8'), MpvFormat.NODE)
def property_observer(self, name):
""" Function decorator to register a property observer. See ```MPV.observe_property``` for details. """
def wrapper(fun):
self.observe_property(name, fun)
return fun
return wrapper
def unobserve_property(self, name, handler): def unobserve_property(self, name, handler):
""" Unregister a property observer. This requires both the observed property's name and the handler function """ Unregister a property observer. This requires both the observed property's name and the handler function