boris-behav-obs 8.16.5__py3-none-any.whl → 9.7.12__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- boris/__init__.py +1 -1
- boris/__main__.py +1 -1
- boris/about.py +28 -40
- boris/add_modifier.py +88 -80
- boris/add_modifier_ui.py +266 -144
- boris/advanced_event_filtering.py +23 -29
- boris/analysis_plugins/__init__.py +0 -0
- boris/analysis_plugins/_export_to_feral.py +225 -0
- boris/analysis_plugins/_latency.py +59 -0
- boris/analysis_plugins/irr_cohen_kappa.py +109 -0
- boris/analysis_plugins/irr_cohen_kappa_with_modifiers.py +112 -0
- boris/analysis_plugins/irr_weighted_cohen_kappa.py +157 -0
- boris/analysis_plugins/irr_weighted_cohen_kappa_with_modifiers.py +162 -0
- boris/analysis_plugins/list_of_dataframe_columns.py +22 -0
- boris/analysis_plugins/number_of_occurences.py +22 -0
- boris/analysis_plugins/number_of_occurences_by_independent_variable.py +54 -0
- boris/analysis_plugins/time_budget.py +61 -0
- boris/behav_coding_map_creator.py +235 -236
- boris/behavior_binary_table.py +33 -50
- boris/behaviors_coding_map.py +17 -18
- boris/boris_cli.py +6 -25
- boris/cmd_arguments.py +12 -1
- boris/coding_pad.py +19 -36
- boris/config.py +109 -50
- boris/config_file.py +58 -67
- boris/connections.py +105 -58
- boris/converters.py +13 -37
- boris/converters_ui.py +187 -110
- boris/cooccurence.py +250 -0
- boris/core.py +2174 -1303
- boris/core_qrc.py +15892 -10829
- boris/core_ui.py +941 -806
- boris/db_functions.py +17 -42
- boris/dev.py +27 -7
- boris/dialog.py +461 -242
- boris/duration_widget.py +9 -14
- boris/edit_event.py +61 -31
- boris/edit_event_ui.py +208 -97
- boris/event_operations.py +405 -281
- boris/events_cursor.py +25 -17
- boris/events_snapshots.py +36 -82
- boris/exclusion_matrix.py +4 -9
- boris/export_events.py +180 -203
- boris/export_observation.py +60 -73
- boris/external_processes.py +123 -98
- boris/geometric_measurement.py +427 -218
- boris/gui_utilities.py +91 -14
- boris/image_overlay.py +4 -4
- boris/import_observations.py +190 -98
- boris/ipc_mpv.py +325 -0
- boris/irr.py +20 -57
- boris/latency.py +31 -24
- boris/measurement_widget.py +14 -18
- boris/media_file.py +17 -19
- boris/menu_options.py +16 -6
- boris/modifier_coding_map_creator.py +1013 -0
- boris/modifiers_coding_map.py +7 -9
- boris/mpv2.py +128 -35
- boris/observation.py +501 -211
- boris/observation_operations.py +1037 -393
- boris/observation_ui.py +573 -363
- boris/observations_list.py +51 -58
- boris/otx_parser.py +74 -68
- boris/param_panel.py +45 -59
- boris/param_panel_ui.py +254 -138
- boris/player_dock_widget.py +91 -56
- boris/plot_data_module.py +20 -53
- boris/plot_events.py +56 -153
- boris/plot_events_rt.py +16 -30
- boris/plot_spectrogram_rt.py +83 -56
- boris/plot_waveform_rt.py +27 -49
- boris/plugins.py +468 -0
- boris/portion/__init__.py +18 -8
- boris/portion/const.py +35 -18
- boris/portion/dict.py +5 -5
- boris/portion/func.py +2 -2
- boris/portion/interval.py +21 -41
- boris/portion/io.py +41 -32
- boris/preferences.py +307 -123
- boris/preferences_ui.py +686 -227
- boris/project.py +294 -271
- boris/project_functions.py +626 -537
- boris/project_import_export.py +204 -213
- boris/project_ui.py +673 -441
- boris/qrc_boris.py +6 -3
- boris/qrc_boris5.py +6 -3
- boris/select_modifiers.py +62 -90
- boris/select_observations.py +19 -197
- boris/select_subj_behav.py +67 -39
- boris/state_events.py +51 -33
- boris/subjects_pad.py +7 -9
- boris/synthetic_time_budget.py +42 -26
- boris/time_budget_functions.py +169 -169
- boris/time_budget_widget.py +77 -89
- boris/transitions.py +41 -41
- boris/utilities.py +594 -226
- boris/version.py +3 -3
- boris/video_equalizer.py +16 -14
- boris/video_equalizer_ui.py +199 -130
- boris/video_operations.py +86 -28
- boris/view_df.py +104 -0
- boris/view_df_ui.py +75 -0
- boris/write_event.py +240 -136
- boris_behav_obs-9.7.12.dist-info/METADATA +139 -0
- boris_behav_obs-9.7.12.dist-info/RECORD +110 -0
- {boris_behav_obs-8.16.5.dist-info → boris_behav_obs-9.7.12.dist-info}/WHEEL +1 -1
- boris_behav_obs-9.7.12.dist-info/entry_points.txt +2 -0
- boris/README.TXT +0 -22
- boris/add_modifier.ui +0 -323
- boris/converters.ui +0 -289
- boris/core.qrc +0 -37
- boris/core.ui +0 -1571
- boris/edit_event.ui +0 -233
- boris/icons/logo_eye.ico +0 -0
- boris/map_creator.py +0 -982
- boris/observation.ui +0 -814
- boris/param_panel.ui +0 -379
- boris/preferences.ui +0 -537
- boris/project.ui +0 -1074
- boris/vlc_local.py +0 -90
- boris_behav_obs-8.16.5.dist-info/LICENSE.TXT +0 -674
- boris_behav_obs-8.16.5.dist-info/METADATA +0 -134
- boris_behav_obs-8.16.5.dist-info/RECORD +0 -107
- boris_behav_obs-8.16.5.dist-info/entry_points.txt +0 -2
- {boris → boris_behav_obs-9.7.12.dist-info/licenses}/LICENSE.TXT +0 -0
- {boris_behav_obs-8.16.5.dist-info → boris_behav_obs-9.7.12.dist-info}/top_level.txt +0 -0
boris/modifiers_coding_map.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
BORIS
|
|
3
3
|
Behavioral Observation Research Interactive Software
|
|
4
|
-
Copyright 2012-
|
|
4
|
+
Copyright 2012-2025 Olivier Friard
|
|
5
5
|
|
|
6
6
|
This file is part of BORIS.
|
|
7
7
|
|
|
@@ -22,9 +22,9 @@ This file is part of BORIS.
|
|
|
22
22
|
|
|
23
23
|
import binascii
|
|
24
24
|
|
|
25
|
-
from
|
|
26
|
-
from
|
|
27
|
-
from
|
|
25
|
+
from PySide6.QtCore import Signal, QPoint, Qt
|
|
26
|
+
from PySide6.QtGui import QPen, QPixmap, QBrush, QMouseEvent, QPolygonF, QColor
|
|
27
|
+
from PySide6.QtWidgets import (
|
|
28
28
|
QDialog,
|
|
29
29
|
QGraphicsView,
|
|
30
30
|
QGraphicsScene,
|
|
@@ -39,10 +39,9 @@ from PyQt5.QtWidgets import (
|
|
|
39
39
|
)
|
|
40
40
|
|
|
41
41
|
|
|
42
|
-
class
|
|
42
|
+
class ModifiersCodingMapWindow(QDialog):
|
|
43
43
|
class View(QGraphicsView):
|
|
44
|
-
|
|
45
|
-
mousePress = pyqtSignal(QMouseEvent)
|
|
44
|
+
mousePress = Signal(QMouseEvent)
|
|
46
45
|
|
|
47
46
|
def mousePressEvent(self, event):
|
|
48
47
|
self.mousePress.emit(event)
|
|
@@ -57,7 +56,7 @@ class ModifiersCodingMapWindowClass(QDialog):
|
|
|
57
56
|
self.scene().update()
|
|
58
57
|
|
|
59
58
|
def __init__(self, modifiers_coding_map):
|
|
60
|
-
super(
|
|
59
|
+
super(ModifiersCodingMapWindow, self).__init__()
|
|
61
60
|
|
|
62
61
|
self.areasList = {}
|
|
63
62
|
self.polygonsList2 = {}
|
|
@@ -104,7 +103,6 @@ class ModifiersCodingMapWindowClass(QDialog):
|
|
|
104
103
|
|
|
105
104
|
for code in self.polygonsList2:
|
|
106
105
|
if self.polygonsList2[code].contains(test):
|
|
107
|
-
|
|
108
106
|
codes = self.leareaCode.text().split(self.codeSeparator)
|
|
109
107
|
if "" in codes:
|
|
110
108
|
codes.remove("")
|
boris/mpv2.py
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# vim: ts=4 sw=4 et
|
|
3
3
|
#
|
|
4
4
|
# Python MPV library module
|
|
5
|
-
# Copyright (C) 2017-
|
|
5
|
+
# Copyright (C) 2017-2024 Sebastian Götte <code@jaseg.net>
|
|
6
6
|
#
|
|
7
7
|
# python-mpv inherits the underlying libmpv's license, which can be either GPLv2 or later (default) or LGPLv2.1 or
|
|
8
8
|
# later. For details, see the mpv copyright page here: https://github.com/mpv-player/mpv/blob/master/Copyright
|
|
@@ -17,11 +17,14 @@
|
|
|
17
17
|
#
|
|
18
18
|
# You can find copies of the GPLv2 and LGPLv2.1 licenses in the project repository's LICENSE.GPL and LICENSE.LGPL files.
|
|
19
19
|
|
|
20
|
+
__version__ = '1.0.7'
|
|
21
|
+
|
|
20
22
|
from ctypes import *
|
|
21
23
|
import ctypes.util
|
|
22
24
|
import threading
|
|
23
25
|
import queue
|
|
24
26
|
import os
|
|
27
|
+
import os.path
|
|
25
28
|
import sys
|
|
26
29
|
from warnings import warn
|
|
27
30
|
from functools import partial, wraps
|
|
@@ -33,14 +36,30 @@ import traceback
|
|
|
33
36
|
|
|
34
37
|
if os.name == 'nt':
|
|
35
38
|
# Note: mpv-2.dll with API version 2 corresponds to mpv v0.35.0. Most things should work with the fallback, too.
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
names = ['mpv-2.dll', 'libmpv-2.dll', 'mpv-1.dll']
|
|
40
|
+
for name in names:
|
|
41
|
+
dll = ctypes.util.find_library(name)
|
|
42
|
+
if dll:
|
|
43
|
+
break
|
|
44
|
+
else:
|
|
45
|
+
for name in names:
|
|
46
|
+
dll = os.path.join(os.path.dirname(__file__), name)
|
|
47
|
+
if os.path.isfile(dll):
|
|
48
|
+
break
|
|
49
|
+
else:
|
|
50
|
+
raise OSError('Cannot find mpv-1.dll, mpv-2.dll or libmpv-2.dll in your system %PATH%. One way to deal with this is to ship the dll with your script and put the directory your script is in into %PATH% before "import mpv": os.environ["PATH"] = os.path.dirname(__file__) + os.pathsep + os.environ["PATH"] If mpv-1.dll is located elsewhere, you can add that path to os.environ["PATH"].')
|
|
51
|
+
|
|
52
|
+
try:
|
|
53
|
+
# flags argument: LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR
|
|
54
|
+
# cf. https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexa
|
|
55
|
+
backend = CDLL(dll, 0x00001000 | 0x00000100)
|
|
56
|
+
except Exception as e:
|
|
57
|
+
if not os.path.isabs(dll): # can only be find_library, not the "look next to mpv.py" thing
|
|
58
|
+
raise OSError(f'ctypes.find_library found mpv.dll at {dll}, but ctypes.CDLL could not load it. It looks like find_library found mpv.dll under a relative path entry in %PATH%. Please make sure all paths in %PATH% are absolute. Instead of trying to load mpv.dll from the current working directory, put it somewhere next to your script and add that path to %PATH% using os.environ["PATH"] = os.path.dirname(__file__) + os.pathsep + os.environ["PATH"]') from e
|
|
59
|
+
else:
|
|
60
|
+
raise OSError(f'ctypes.find_library found mpv.dll at {dll}, but ctypes.CDLL could not load it.') from e
|
|
43
61
|
fs_enc = 'utf-8'
|
|
62
|
+
|
|
44
63
|
else:
|
|
45
64
|
import locale
|
|
46
65
|
lc, enc = locale.getlocale(locale.LC_NUMERIC)
|
|
@@ -50,10 +69,7 @@ else:
|
|
|
50
69
|
|
|
51
70
|
sofile = ctypes.util.find_library('mpv')
|
|
52
71
|
if sofile is None:
|
|
53
|
-
raise OSError("Cannot find libmpv in the usual places. Depending on your distro, you may try installing an "
|
|
54
|
-
"mpv-devel or mpv-libs package. If you have libmpv around but this script can't find it, consult "
|
|
55
|
-
"the documentation for ctypes.util.find_library which this script uses to look up the library "
|
|
56
|
-
"filename.")
|
|
72
|
+
raise OSError("Cannot find libmpv in the usual places. Depending on your distro, you may try installing an mpv-devel or mpv-libs package. If you have libmpv around but this script can't find it, consult the documentation for ctypes.util.find_library which this script uses to look up the library filename.")
|
|
57
73
|
backend = CDLL(sofile)
|
|
58
74
|
fs_enc = sys.getfilesystemencoding()
|
|
59
75
|
|
|
@@ -441,9 +457,14 @@ class MpvEventLogMessage(Structure):
|
|
|
441
457
|
return lazy_decoder(self._text)
|
|
442
458
|
|
|
443
459
|
class MpvEventEndFile(Structure):
|
|
444
|
-
_fields_ = [
|
|
445
|
-
|
|
446
|
-
|
|
460
|
+
_fields_ = [
|
|
461
|
+
('reason', c_int),
|
|
462
|
+
('error', c_int),
|
|
463
|
+
('playlist_entry_id', c_ulonglong),
|
|
464
|
+
('playlist_insert_id', c_ulonglong),
|
|
465
|
+
('playlist_insert_num_entries', c_int),
|
|
466
|
+
]
|
|
467
|
+
|
|
447
468
|
EOF = 0
|
|
448
469
|
RESTARTED = 1
|
|
449
470
|
ABORTED = 2
|
|
@@ -892,6 +913,8 @@ class MPV(object):
|
|
|
892
913
|
self._event_thread.start()
|
|
893
914
|
else:
|
|
894
915
|
self._event_thread = None
|
|
916
|
+
if (m := re.search(r'(\d+)\.(\d+)\.(\d+)', self.mpv_version)):
|
|
917
|
+
self.mpv_version_tuple = tuple(map(int, m.groups()))
|
|
895
918
|
|
|
896
919
|
@contextmanager
|
|
897
920
|
def _enqueue_exceptions(self):
|
|
@@ -1033,30 +1056,38 @@ class MPV(object):
|
|
|
1033
1056
|
rv = cond(val)
|
|
1034
1057
|
if rv:
|
|
1035
1058
|
result.set_result(rv)
|
|
1059
|
+
|
|
1060
|
+
except InvalidStateError:
|
|
1061
|
+
pass
|
|
1062
|
+
|
|
1036
1063
|
except Exception as e:
|
|
1037
1064
|
try:
|
|
1038
1065
|
result.set_exception(e)
|
|
1039
|
-
except
|
|
1066
|
+
except:
|
|
1040
1067
|
pass
|
|
1041
|
-
except InvalidStateError:
|
|
1042
|
-
pass
|
|
1043
|
-
self.observe_property(name, observer)
|
|
1044
|
-
err_unregister = self._set_error_handler(result)
|
|
1045
1068
|
|
|
1046
1069
|
try:
|
|
1047
1070
|
result.set_running_or_notify_cancel()
|
|
1071
|
+
|
|
1072
|
+
self.observe_property(name, observer)
|
|
1073
|
+
err_unregister = self._set_error_handler(result)
|
|
1048
1074
|
if catch_errors:
|
|
1049
1075
|
self._exception_futures.add(result)
|
|
1050
1076
|
|
|
1051
1077
|
yield result
|
|
1052
1078
|
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1079
|
+
if level_sensitive:
|
|
1080
|
+
rv = cond(getattr(self, name.replace('-', '_')))
|
|
1081
|
+
if rv:
|
|
1082
|
+
result.set_result(rv)
|
|
1083
|
+
return
|
|
1084
|
+
|
|
1085
|
+
self.check_core_alive()
|
|
1086
|
+
result.result(timeout)
|
|
1087
|
+
|
|
1088
|
+
except InvalidStateError:
|
|
1089
|
+
pass
|
|
1056
1090
|
|
|
1057
|
-
else:
|
|
1058
|
-
self.check_core_alive()
|
|
1059
|
-
result.result(timeout)
|
|
1060
1091
|
finally:
|
|
1061
1092
|
err_unregister()
|
|
1062
1093
|
self.unobserve_property(name, observer)
|
|
@@ -1323,9 +1354,16 @@ class MPV(object):
|
|
|
1323
1354
|
def _encode_options(options):
|
|
1324
1355
|
return ','.join('{}={}'.format(_py_to_mpv(str(key)), str(val)) for key, val in options.items())
|
|
1325
1356
|
|
|
1326
|
-
def loadfile(self, filename, mode='replace', **options):
|
|
1357
|
+
def loadfile(self, filename, mode='replace', index=None, **options):
|
|
1327
1358
|
"""Mapped mpv loadfile command, see man mpv(1)."""
|
|
1328
|
-
self.
|
|
1359
|
+
if self.mpv_version_tuple >= (0, 38, 0):
|
|
1360
|
+
if index is None:
|
|
1361
|
+
index = -1
|
|
1362
|
+
self.command('loadfile', filename.encode(fs_enc), mode, index, MPV._encode_options(options))
|
|
1363
|
+
else:
|
|
1364
|
+
if index is not None:
|
|
1365
|
+
warn(f'The index argument to the loadfile command is only supported on mpv >= 0.38.0')
|
|
1366
|
+
self.command('loadfile', filename.encode(fs_enc), mode, MPV._encode_options(options))
|
|
1329
1367
|
|
|
1330
1368
|
def loadlist(self, playlist, mode='replace'):
|
|
1331
1369
|
"""Mapped mpv loadlist command, see man mpv(1)."""
|
|
@@ -1357,11 +1395,17 @@ class MPV(object):
|
|
|
1357
1395
|
|
|
1358
1396
|
def quit(self, code=None):
|
|
1359
1397
|
"""Mapped mpv quit command, see man mpv(1)."""
|
|
1360
|
-
|
|
1398
|
+
if code is not None:
|
|
1399
|
+
self.command('quit', code)
|
|
1400
|
+
else:
|
|
1401
|
+
self.command('quit')
|
|
1361
1402
|
|
|
1362
1403
|
def quit_watch_later(self, code=None):
|
|
1363
1404
|
"""Mapped mpv quit_watch_later command, see man mpv(1)."""
|
|
1364
|
-
|
|
1405
|
+
if code is not None:
|
|
1406
|
+
self.command('quit_watch_later', code)
|
|
1407
|
+
else:
|
|
1408
|
+
self.command('quit_watch_later')
|
|
1365
1409
|
|
|
1366
1410
|
def stop(self, keep_playlist=False):
|
|
1367
1411
|
"""Mapped mpv stop command, see man mpv(1)."""
|
|
@@ -1446,7 +1490,7 @@ class MPV(object):
|
|
|
1446
1490
|
"""Mapped mpv discnav command, see man mpv(1)."""
|
|
1447
1491
|
self.command('discnav', command)
|
|
1448
1492
|
|
|
1449
|
-
def mouse(x, y, button=None, mode='single'):
|
|
1493
|
+
def mouse(self, x, y, button=None, mode='single'):
|
|
1450
1494
|
"""Mapped mpv mouse command, see man mpv(1)."""
|
|
1451
1495
|
if button is None:
|
|
1452
1496
|
self.command('mouse', x, y, mode)
|
|
@@ -1811,9 +1855,6 @@ class MPV(object):
|
|
|
1811
1855
|
pass
|
|
1812
1856
|
else:
|
|
1813
1857
|
warnings.warn(f'Unhandled exception {e} inside stream open callback for URI {uri}\n{traceback.format_exc()}')
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
1858
|
return ErrorCode.LOADING_FAILED
|
|
1818
1859
|
|
|
1819
1860
|
cb_info.contents.cookie = None
|
|
@@ -1943,6 +1984,55 @@ class MPV(object):
|
|
|
1943
1984
|
return cb
|
|
1944
1985
|
return register
|
|
1945
1986
|
|
|
1987
|
+
@contextmanager
|
|
1988
|
+
def play_context(self):
|
|
1989
|
+
""" Context manager for streaming bytes straight into libmpv.
|
|
1990
|
+
|
|
1991
|
+
This is a convenience wrapper around python_stream. play_context returns a write method, which you can use in
|
|
1992
|
+
the body of the context manager to feed libmpv bytes. All bytes you feed in with write() in the body of a single
|
|
1993
|
+
call of this context manager are treated as one single file. A queue is used internally, so this function is
|
|
1994
|
+
thread-safe. The queue is unlimited, so it cannot block and is safe to call from async code. You can use this
|
|
1995
|
+
function to stream chunked data, e.g. from the network.
|
|
1996
|
+
|
|
1997
|
+
Use it like this:
|
|
1998
|
+
|
|
1999
|
+
with m.play_context() as write:
|
|
2000
|
+
with open(TESTVID, 'rb') as f:
|
|
2001
|
+
while (chunk := f.read(65536)): # Get some chunks of bytes
|
|
2002
|
+
write(chunk)
|
|
2003
|
+
"""
|
|
2004
|
+
q = queue.Queue()
|
|
2005
|
+
|
|
2006
|
+
frame = sys._getframe()
|
|
2007
|
+
stream_name = f'__python_mpv_play_generator_{hash(frame)}'
|
|
2008
|
+
EOF = frame # Get some unique object as EOF marker
|
|
2009
|
+
@self.python_stream(stream_name)
|
|
2010
|
+
def reader():
|
|
2011
|
+
while (chunk := q.get()) is not EOF:
|
|
2012
|
+
if chunk:
|
|
2013
|
+
yield chunk
|
|
2014
|
+
reader.unregister()
|
|
2015
|
+
|
|
2016
|
+
def write(chunk):
|
|
2017
|
+
q.put(chunk)
|
|
2018
|
+
|
|
2019
|
+
# Start playback before yielding, the first call to reader() will block until write is called at least once.
|
|
2020
|
+
self.play(f'python://{stream_name}')
|
|
2021
|
+
yield write
|
|
2022
|
+
q.put(EOF)
|
|
2023
|
+
|
|
2024
|
+
def play_bytes(self, data):
|
|
2025
|
+
""" Play the given bytes object as a single file. """
|
|
2026
|
+
frame = sys._getframe()
|
|
2027
|
+
stream_name = f'__python_mpv_play_generator_{hash(frame)}'
|
|
2028
|
+
|
|
2029
|
+
@self.python_stream(stream_name)
|
|
2030
|
+
def reader():
|
|
2031
|
+
yield data
|
|
2032
|
+
reader.unregister() # unregister itself
|
|
2033
|
+
|
|
2034
|
+
self.play(f'python://{stream_name}')
|
|
2035
|
+
|
|
1946
2036
|
def python_stream_catchall(self, cb):
|
|
1947
2037
|
""" Register a catch-all python stream to be called when no name matches can be found. Use this decorator on a
|
|
1948
2038
|
function that takes a name argument and returns a (generator, size) tuple (with size being None if unknown).
|
|
@@ -2000,7 +2090,10 @@ class MPV(object):
|
|
|
2000
2090
|
def _set_property(self, name, value):
|
|
2001
2091
|
self.check_core_alive()
|
|
2002
2092
|
ename = name.encode('utf-8')
|
|
2003
|
-
if isinstance(value,
|
|
2093
|
+
if isinstance(value, dict):
|
|
2094
|
+
_1, _2, _3, pointer = _make_node_str_map(value)
|
|
2095
|
+
_mpv_set_property(self.handle, ename, MpvFormat.NODE, pointer)
|
|
2096
|
+
elif isinstance(value, (list, set)):
|
|
2004
2097
|
_1, _2, _3, pointer = _make_node_str_list(value)
|
|
2005
2098
|
_mpv_set_property(self.handle, ename, MpvFormat.NODE, pointer)
|
|
2006
2099
|
else:
|