boris-behav-obs 9.4.1__py2.py3-none-any.whl → 9.5__py2.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/preferences_ui.py CHANGED
@@ -3,7 +3,7 @@
3
3
  ################################################################################
4
4
  ## Form generated from reading UI file 'preferences.ui'
5
5
  ##
6
- ## Created by: Qt User Interface Compiler version 6.8.0
6
+ ## Created by: Qt User Interface Compiler version 6.9.0
7
7
  ##
8
8
  ## WARNING! All changes made in this file will be lost when recompiling UI file!
9
9
  ################################################################################
@@ -16,10 +16,11 @@ from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
16
16
  QImage, QKeySequence, QLinearGradient, QPainter,
17
17
  QPalette, QPixmap, QRadialGradient, QTransform)
18
18
  from PySide6.QtWidgets import (QApplication, QCheckBox, QComboBox, QDialog,
19
- QDoubleSpinBox, QFormLayout, QGridLayout, QHBoxLayout,
19
+ QDoubleSpinBox, QFormLayout, QGroupBox, QHBoxLayout,
20
20
  QLabel, QLineEdit, QListWidget, QListWidgetItem,
21
21
  QPlainTextEdit, QPushButton, QSizePolicy, QSpacerItem,
22
- QSpinBox, QTabWidget, QVBoxLayout, QWidget)
22
+ QSpinBox, QSplitter, QTabWidget, QVBoxLayout,
23
+ QWidget)
23
24
 
24
25
  class Ui_prefDialog(object):
25
26
  def setupUi(self, prefDialog):
@@ -27,8 +28,8 @@ class Ui_prefDialog(object):
27
28
  prefDialog.setObjectName(u"prefDialog")
28
29
  prefDialog.setWindowModality(Qt.WindowModality.WindowModal)
29
30
  prefDialog.resize(904, 554)
30
- self.gridLayout = QGridLayout(prefDialog)
31
- self.gridLayout.setObjectName(u"gridLayout")
31
+ self.horizontalLayout_17 = QHBoxLayout(prefDialog)
32
+ self.horizontalLayout_17.setObjectName(u"horizontalLayout_17")
32
33
  self.verticalLayout_2 = QVBoxLayout()
33
34
  self.verticalLayout_2.setObjectName(u"verticalLayout_2")
34
35
  self.tabWidget = QTabWidget(prefDialog)
@@ -250,34 +251,40 @@ class Ui_prefDialog(object):
250
251
  self.tabWidget.addTab(self.tab_observations, "")
251
252
  self.tab_analysis_plugins = QWidget()
252
253
  self.tab_analysis_plugins.setObjectName(u"tab_analysis_plugins")
253
- self.horizontalLayout_17 = QHBoxLayout(self.tab_analysis_plugins)
254
- self.horizontalLayout_17.setObjectName(u"horizontalLayout_17")
255
- self.verticalLayout_11 = QVBoxLayout()
254
+ self.verticalLayout_15 = QVBoxLayout(self.tab_analysis_plugins)
255
+ self.verticalLayout_15.setObjectName(u"verticalLayout_15")
256
+ self.splitter_2 = QSplitter(self.tab_analysis_plugins)
257
+ self.splitter_2.setObjectName(u"splitter_2")
258
+ self.splitter_2.setOrientation(Qt.Orientation.Horizontal)
259
+ self.widget = QWidget(self.splitter_2)
260
+ self.widget.setObjectName(u"widget")
261
+ self.verticalLayout_11 = QVBoxLayout(self.widget)
256
262
  self.verticalLayout_11.setObjectName(u"verticalLayout_11")
257
- self.label_13 = QLabel(self.tab_analysis_plugins)
263
+ self.verticalLayout_11.setContentsMargins(0, 0, 0, 0)
264
+ self.label_13 = QLabel(self.widget)
258
265
  self.label_13.setObjectName(u"label_13")
259
266
 
260
267
  self.verticalLayout_11.addWidget(self.label_13)
261
268
 
262
- self.lv_all_plugins = QListWidget(self.tab_analysis_plugins)
269
+ self.lv_all_plugins = QListWidget(self.widget)
263
270
  self.lv_all_plugins.setObjectName(u"lv_all_plugins")
264
271
 
265
272
  self.verticalLayout_11.addWidget(self.lv_all_plugins)
266
273
 
267
- self.label_15 = QLabel(self.tab_analysis_plugins)
274
+ self.label_15 = QLabel(self.widget)
268
275
  self.label_15.setObjectName(u"label_15")
269
276
 
270
277
  self.verticalLayout_11.addWidget(self.label_15)
271
278
 
272
279
  self.horizontalLayout_16 = QHBoxLayout()
273
280
  self.horizontalLayout_16.setObjectName(u"horizontalLayout_16")
274
- self.le_personal_plugins_dir = QLineEdit(self.tab_analysis_plugins)
281
+ self.le_personal_plugins_dir = QLineEdit(self.widget)
275
282
  self.le_personal_plugins_dir.setObjectName(u"le_personal_plugins_dir")
276
283
  self.le_personal_plugins_dir.setReadOnly(True)
277
284
 
278
285
  self.horizontalLayout_16.addWidget(self.le_personal_plugins_dir)
279
286
 
280
- self.pb_browse_plugins_dir = QPushButton(self.tab_analysis_plugins)
287
+ self.pb_browse_plugins_dir = QPushButton(self.widget)
281
288
  self.pb_browse_plugins_dir.setObjectName(u"pb_browse_plugins_dir")
282
289
 
283
290
  self.horizontalLayout_16.addWidget(self.pb_browse_plugins_dir)
@@ -285,29 +292,52 @@ class Ui_prefDialog(object):
285
292
 
286
293
  self.verticalLayout_11.addLayout(self.horizontalLayout_16)
287
294
 
288
- self.lw_personal_plugins = QListWidget(self.tab_analysis_plugins)
295
+ self.lw_personal_plugins = QListWidget(self.widget)
289
296
  self.lw_personal_plugins.setObjectName(u"lw_personal_plugins")
290
297
 
291
298
  self.verticalLayout_11.addWidget(self.lw_personal_plugins)
292
299
 
293
-
294
- self.horizontalLayout_17.addLayout(self.verticalLayout_11)
295
-
296
- self.verticalLayout_12 = QVBoxLayout()
300
+ self.splitter_2.addWidget(self.widget)
301
+ self.splitter = QSplitter(self.splitter_2)
302
+ self.splitter.setObjectName(u"splitter")
303
+ self.splitter.setOrientation(Qt.Orientation.Vertical)
304
+ self.widget1 = QWidget(self.splitter)
305
+ self.widget1.setObjectName(u"widget1")
306
+ self.verticalLayout_12 = QVBoxLayout(self.widget1)
297
307
  self.verticalLayout_12.setObjectName(u"verticalLayout_12")
298
- self.label_14 = QLabel(self.tab_analysis_plugins)
308
+ self.verticalLayout_12.setContentsMargins(0, 0, 0, 0)
309
+ self.label_14 = QLabel(self.widget1)
299
310
  self.label_14.setObjectName(u"label_14")
300
311
 
301
312
  self.verticalLayout_12.addWidget(self.label_14)
302
313
 
303
- self.pte_plugin_description = QPlainTextEdit(self.tab_analysis_plugins)
314
+ self.pte_plugin_description = QPlainTextEdit(self.widget1)
304
315
  self.pte_plugin_description.setObjectName(u"pte_plugin_description")
305
316
  self.pte_plugin_description.setReadOnly(True)
306
317
 
307
318
  self.verticalLayout_12.addWidget(self.pte_plugin_description)
308
319
 
320
+ self.splitter.addWidget(self.widget1)
321
+ self.widget2 = QWidget(self.splitter)
322
+ self.widget2.setObjectName(u"widget2")
323
+ self.verticalLayout_14 = QVBoxLayout(self.widget2)
324
+ self.verticalLayout_14.setObjectName(u"verticalLayout_14")
325
+ self.verticalLayout_14.setContentsMargins(0, 0, 0, 0)
326
+ self.label_23 = QLabel(self.widget2)
327
+ self.label_23.setObjectName(u"label_23")
328
+
329
+ self.verticalLayout_14.addWidget(self.label_23)
330
+
331
+ self.pte_plugin_code = QPlainTextEdit(self.widget2)
332
+ self.pte_plugin_code.setObjectName(u"pte_plugin_code")
333
+ self.pte_plugin_code.setLineWrapMode(QPlainTextEdit.LineWrapMode.NoWrap)
334
+
335
+ self.verticalLayout_14.addWidget(self.pte_plugin_code)
336
+
337
+ self.splitter.addWidget(self.widget2)
338
+ self.splitter_2.addWidget(self.splitter)
309
339
 
310
- self.horizontalLayout_17.addLayout(self.verticalLayout_12)
340
+ self.verticalLayout_15.addWidget(self.splitter_2)
311
341
 
312
342
  self.tabWidget.addTab(self.tab_analysis_plugins, "")
313
343
  self.tab_ffmpeg = QWidget()
@@ -358,31 +388,39 @@ class Ui_prefDialog(object):
358
388
  self.tabWidget.addTab(self.tab_ffmpeg, "")
359
389
  self.tab_spectro = QWidget()
360
390
  self.tab_spectro.setObjectName(u"tab_spectro")
361
- self.verticalLayout_8 = QVBoxLayout(self.tab_spectro)
391
+ self.verticalLayout_13 = QVBoxLayout(self.tab_spectro)
392
+ self.verticalLayout_13.setObjectName(u"verticalLayout_13")
393
+ self.groupBox = QGroupBox(self.tab_spectro)
394
+ self.groupBox.setObjectName(u"groupBox")
395
+ self.verticalLayout_8 = QVBoxLayout(self.groupBox)
362
396
  self.verticalLayout_8.setObjectName(u"verticalLayout_8")
363
397
  self.horizontalLayout_7 = QHBoxLayout()
364
398
  self.horizontalLayout_7.setObjectName(u"horizontalLayout_7")
365
- self.label_7 = QLabel(self.tab_spectro)
399
+ self.label_7 = QLabel(self.groupBox)
366
400
  self.label_7.setObjectName(u"label_7")
367
401
 
368
402
  self.horizontalLayout_7.addWidget(self.label_7)
369
403
 
370
- self.cbSpectrogramColorMap = QComboBox(self.tab_spectro)
404
+ self.cbSpectrogramColorMap = QComboBox(self.groupBox)
371
405
  self.cbSpectrogramColorMap.setObjectName(u"cbSpectrogramColorMap")
372
406
 
373
407
  self.horizontalLayout_7.addWidget(self.cbSpectrogramColorMap)
374
408
 
409
+ self.horizontalSpacer_2 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
410
+
411
+ self.horizontalLayout_7.addItem(self.horizontalSpacer_2)
412
+
375
413
 
376
414
  self.verticalLayout_8.addLayout(self.horizontalLayout_7)
377
415
 
378
416
  self.horizontalLayout_10 = QHBoxLayout()
379
417
  self.horizontalLayout_10.setObjectName(u"horizontalLayout_10")
380
- self.label_12 = QLabel(self.tab_spectro)
418
+ self.label_12 = QLabel(self.groupBox)
381
419
  self.label_12.setObjectName(u"label_12")
382
420
 
383
421
  self.horizontalLayout_10.addWidget(self.label_12)
384
422
 
385
- self.sb_time_interval = QSpinBox(self.tab_spectro)
423
+ self.sb_time_interval = QSpinBox(self.groupBox)
386
424
  self.sb_time_interval.setObjectName(u"sb_time_interval")
387
425
  self.sb_time_interval.setMinimum(2)
388
426
  self.sb_time_interval.setMaximum(360)
@@ -390,12 +428,140 @@ class Ui_prefDialog(object):
390
428
 
391
429
  self.horizontalLayout_10.addWidget(self.sb_time_interval)
392
430
 
431
+ self.horizontalSpacer_3 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
432
+
433
+ self.horizontalLayout_10.addItem(self.horizontalSpacer_3)
434
+
393
435
 
394
436
  self.verticalLayout_8.addLayout(self.horizontalLayout_10)
395
437
 
438
+ self.horizontalLayout_18 = QHBoxLayout()
439
+ self.horizontalLayout_18.setObjectName(u"horizontalLayout_18")
440
+ self.label_16 = QLabel(self.groupBox)
441
+ self.label_16.setObjectName(u"label_16")
442
+
443
+ self.horizontalLayout_18.addWidget(self.label_16)
444
+
445
+ self.cb_window_type = QComboBox(self.groupBox)
446
+ self.cb_window_type.addItem("")
447
+ self.cb_window_type.addItem("")
448
+ self.cb_window_type.addItem("")
449
+ self.cb_window_type.setObjectName(u"cb_window_type")
450
+
451
+ self.horizontalLayout_18.addWidget(self.cb_window_type)
452
+
453
+ self.horizontalSpacer_4 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
454
+
455
+ self.horizontalLayout_18.addItem(self.horizontalSpacer_4)
456
+
457
+
458
+ self.verticalLayout_8.addLayout(self.horizontalLayout_18)
459
+
460
+ self.horizontalLayout_19 = QHBoxLayout()
461
+ self.horizontalLayout_19.setObjectName(u"horizontalLayout_19")
462
+ self.label_17 = QLabel(self.groupBox)
463
+ self.label_17.setObjectName(u"label_17")
464
+
465
+ self.horizontalLayout_19.addWidget(self.label_17)
466
+
467
+ self.cb_NFFT = QComboBox(self.groupBox)
468
+ self.cb_NFFT.addItem("")
469
+ self.cb_NFFT.addItem("")
470
+ self.cb_NFFT.addItem("")
471
+ self.cb_NFFT.addItem("")
472
+ self.cb_NFFT.setObjectName(u"cb_NFFT")
473
+
474
+ self.horizontalLayout_19.addWidget(self.cb_NFFT)
475
+
476
+ self.horizontalSpacer_5 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
477
+
478
+ self.horizontalLayout_19.addItem(self.horizontalSpacer_5)
479
+
480
+
481
+ self.verticalLayout_8.addLayout(self.horizontalLayout_19)
482
+
483
+ self.horizontalLayout_20 = QHBoxLayout()
484
+ self.horizontalLayout_20.setObjectName(u"horizontalLayout_20")
485
+ self.label_18 = QLabel(self.groupBox)
486
+ self.label_18.setObjectName(u"label_18")
487
+
488
+ self.horizontalLayout_20.addWidget(self.label_18)
489
+
490
+ self.sb_noverlap = QSpinBox(self.groupBox)
491
+ self.sb_noverlap.setObjectName(u"sb_noverlap")
492
+ self.sb_noverlap.setMaximum(900)
493
+ self.sb_noverlap.setSingleStep(10)
494
+ self.sb_noverlap.setValue(128)
495
+
496
+ self.horizontalLayout_20.addWidget(self.sb_noverlap)
497
+
498
+ self.horizontalSpacer_6 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
499
+
500
+ self.horizontalLayout_20.addItem(self.horizontalSpacer_6)
501
+
502
+
503
+ self.verticalLayout_8.addLayout(self.horizontalLayout_20)
504
+
505
+ self.horizontalLayout_21 = QHBoxLayout()
506
+ self.horizontalLayout_21.setObjectName(u"horizontalLayout_21")
507
+ self.label_19 = QLabel(self.groupBox)
508
+ self.label_19.setObjectName(u"label_19")
509
+
510
+ self.horizontalLayout_21.addWidget(self.label_19)
511
+
512
+ self.sb_vmin = QSpinBox(self.groupBox)
513
+ self.sb_vmin.setObjectName(u"sb_vmin")
514
+ self.sb_vmin.setMinimum(-200)
515
+ self.sb_vmin.setMaximum(0)
516
+ self.sb_vmin.setValue(-100)
517
+
518
+ self.horizontalLayout_21.addWidget(self.sb_vmin)
519
+
520
+ self.label_21 = QLabel(self.groupBox)
521
+ self.label_21.setObjectName(u"label_21")
522
+
523
+ self.horizontalLayout_21.addWidget(self.label_21)
524
+
525
+ self.horizontalSpacer_7 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
526
+
527
+ self.horizontalLayout_21.addItem(self.horizontalSpacer_7)
528
+
529
+
530
+ self.verticalLayout_8.addLayout(self.horizontalLayout_21)
531
+
532
+ self.horizontalLayout_22 = QHBoxLayout()
533
+ self.horizontalLayout_22.setObjectName(u"horizontalLayout_22")
534
+ self.label_20 = QLabel(self.groupBox)
535
+ self.label_20.setObjectName(u"label_20")
536
+
537
+ self.horizontalLayout_22.addWidget(self.label_20)
538
+
539
+ self.sb_vmax = QSpinBox(self.groupBox)
540
+ self.sb_vmax.setObjectName(u"sb_vmax")
541
+ self.sb_vmax.setMinimum(-40)
542
+ self.sb_vmax.setMaximum(0)
543
+ self.sb_vmax.setValue(-20)
544
+
545
+ self.horizontalLayout_22.addWidget(self.sb_vmax)
546
+
547
+ self.label_22 = QLabel(self.groupBox)
548
+ self.label_22.setObjectName(u"label_22")
549
+
550
+ self.horizontalLayout_22.addWidget(self.label_22)
551
+
552
+ self.horizontalSpacer_8 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
553
+
554
+ self.horizontalLayout_22.addItem(self.horizontalSpacer_8)
555
+
556
+
557
+ self.verticalLayout_8.addLayout(self.horizontalLayout_22)
558
+
559
+
560
+ self.verticalLayout_13.addWidget(self.groupBox)
561
+
396
562
  self.verticalSpacer_3 = QSpacerItem(20, 319, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
397
563
 
398
- self.verticalLayout_8.addItem(self.verticalSpacer_3)
564
+ self.verticalLayout_13.addItem(self.verticalSpacer_3)
399
565
 
400
566
  self.tabWidget.addTab(self.tab_spectro, "")
401
567
  self.tab_colors = QWidget()
@@ -459,7 +625,7 @@ class Ui_prefDialog(object):
459
625
  self.label_9 = QLabel(self.tab_interface)
460
626
  self.label_9.setObjectName(u"label_9")
461
627
 
462
- self.formLayout.setWidget(0, QFormLayout.LabelRole, self.label_9)
628
+ self.formLayout.setWidget(0, QFormLayout.ItemRole.LabelRole, self.label_9)
463
629
 
464
630
  self.sb_toolbar_icon_size = QSpinBox(self.tab_interface)
465
631
  self.sb_toolbar_icon_size.setObjectName(u"sb_toolbar_icon_size")
@@ -467,7 +633,7 @@ class Ui_prefDialog(object):
467
633
  self.sb_toolbar_icon_size.setMaximum(128)
468
634
  self.sb_toolbar_icon_size.setValue(24)
469
635
 
470
- self.formLayout.setWidget(0, QFormLayout.FieldRole, self.sb_toolbar_icon_size)
636
+ self.formLayout.setWidget(0, QFormLayout.ItemRole.FieldRole, self.sb_toolbar_icon_size)
471
637
 
472
638
 
473
639
  self.verticalLayout_7.addLayout(self.formLayout)
@@ -505,12 +671,12 @@ class Ui_prefDialog(object):
505
671
  self.verticalLayout_2.addLayout(self.horizontalLayout_2)
506
672
 
507
673
 
508
- self.gridLayout.addLayout(self.verticalLayout_2, 0, 0, 1, 1)
674
+ self.horizontalLayout_17.addLayout(self.verticalLayout_2)
509
675
 
510
676
 
511
677
  self.retranslateUi(prefDialog)
512
678
 
513
- self.tabWidget.setCurrentIndex(0)
679
+ self.tabWidget.setCurrentIndex(2)
514
680
 
515
681
 
516
682
  QMetaObject.connectSlotsByName(prefDialog)
@@ -546,13 +712,31 @@ class Ui_prefDialog(object):
546
712
  self.label_15.setText(QCoreApplication.translate("prefDialog", u"Personal plugins", None))
547
713
  self.pb_browse_plugins_dir.setText(QCoreApplication.translate("prefDialog", u"Browse", None))
548
714
  self.label_14.setText(QCoreApplication.translate("prefDialog", u"Plugin info", None))
715
+ self.label_23.setText(QCoreApplication.translate("prefDialog", u"Plugin code", None))
549
716
  self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_analysis_plugins), QCoreApplication.translate("prefDialog", u"Analysis plugins", None))
550
717
  self.lbFFmpegPath.setText(QCoreApplication.translate("prefDialog", u"FFmpeg path:", None))
551
718
  self.lbFFmpegCacheDir.setText(QCoreApplication.translate("prefDialog", u"FFmpeg cache directory", None))
552
719
  self.pbBrowseFFmpegCacheDir.setText(QCoreApplication.translate("prefDialog", u"...", None))
553
720
  self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_ffmpeg), QCoreApplication.translate("prefDialog", u"FFmpeg framework", None))
554
- self.label_7.setText(QCoreApplication.translate("prefDialog", u"Spectrogram color map", None))
721
+ self.groupBox.setTitle(QCoreApplication.translate("prefDialog", u"Spectrogram", None))
722
+ self.label_7.setText(QCoreApplication.translate("prefDialog", u"Color map", None))
555
723
  self.label_12.setText(QCoreApplication.translate("prefDialog", u"Default time interval (s)", None))
724
+ self.label_16.setText(QCoreApplication.translate("prefDialog", u"Window type", None))
725
+ self.cb_window_type.setItemText(0, QCoreApplication.translate("prefDialog", u"hanning", None))
726
+ self.cb_window_type.setItemText(1, QCoreApplication.translate("prefDialog", u"hamming", None))
727
+ self.cb_window_type.setItemText(2, QCoreApplication.translate("prefDialog", u"blackmanharris", None))
728
+
729
+ self.label_17.setText(QCoreApplication.translate("prefDialog", u"NFFT", None))
730
+ self.cb_NFFT.setItemText(0, QCoreApplication.translate("prefDialog", u"256", None))
731
+ self.cb_NFFT.setItemText(1, QCoreApplication.translate("prefDialog", u"512", None))
732
+ self.cb_NFFT.setItemText(2, QCoreApplication.translate("prefDialog", u"1024", None))
733
+ self.cb_NFFT.setItemText(3, QCoreApplication.translate("prefDialog", u"2048", None))
734
+
735
+ self.label_18.setText(QCoreApplication.translate("prefDialog", u"noverlap", None))
736
+ self.label_19.setText(QCoreApplication.translate("prefDialog", u"vmin", None))
737
+ self.label_21.setText(QCoreApplication.translate("prefDialog", u"dBFS", None))
738
+ self.label_20.setText(QCoreApplication.translate("prefDialog", u"vmax", None))
739
+ self.label_22.setText(QCoreApplication.translate("prefDialog", u"dBFS", None))
556
740
  self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_spectro), QCoreApplication.translate("prefDialog", u"Spectrogram/Wave form", None))
557
741
  self.label_10.setText(QCoreApplication.translate("prefDialog", u"<html><head/><body><p>List of colors for behaviors. See <a href=\"https://matplotlib.org/api/colors_api.html\"><span style=\" text-decoration: underline; color:#0000ff;\">matplotlib colors</span></a></p></body></html>", None))
558
742
  self.pb_reset_behav_colors.setText(QCoreApplication.translate("prefDialog", u"Reset colors to default", None))
@@ -565,7 +565,7 @@ def check_project_integrity(
565
565
  for player in pj[cfg.OBSERVATIONS][obs_id][cfg.FILE]:
566
566
  for media_file in pj[cfg.OBSERVATIONS][obs_id][cfg.FILE][player]:
567
567
  for info in (cfg.LENGTH, cfg.FPS, cfg.HAS_AUDIO, cfg.HAS_VIDEO):
568
- if media_file not in pj[cfg.OBSERVATIONS][obs_id][cfg.MEDIA_INFO][info]:
568
+ if media_file not in pj[cfg.OBSERVATIONS][obs_id][cfg.MEDIA_INFO].get(info, {}):
569
569
  tmp_out += f"Observation <b>{obs_id}</b>:<br>"
570
570
  tmp_out += f"The media file {media_file} has no <b>{info}</b> info.<br>"
571
571
  if tmp_out:
@@ -1984,6 +1984,4 @@ def project2dataframe(pj: dict, observations_list: list = []) -> pd.DataFrame:
1984
1984
 
1985
1985
  pd.DataFrame(data).info()
1986
1986
 
1987
- # print(pd.DataFrame(data))
1988
-
1989
1987
  return pd.DataFrame(data)
boris/utilities.py CHANGED
@@ -23,7 +23,7 @@ from decimal import Decimal as dec
23
23
  from decimal import getcontext, ROUND_DOWN
24
24
  from hachoir.metadata import extractMetadata
25
25
  from hachoir.parser import createParser
26
- from shutil import copyfile
26
+ from shutil import copyfile, which
27
27
  from typing import Union, Tuple
28
28
  import csv
29
29
  import datetime
@@ -34,7 +34,7 @@ import logging
34
34
  import math
35
35
  import numpy as np
36
36
  import os
37
- import pathlib as pl
37
+ from pathlib import Path
38
38
  from PIL.ImageQt import Image
39
39
  import platform
40
40
  import re
@@ -71,7 +71,7 @@ except Exception:
71
71
  external_files_dir = ""
72
72
  # search where to download libmpv-2.dll
73
73
 
74
- external_files_dir = pl.Path(__file__).parent / "misc"
74
+ external_files_dir = Path(__file__).parent / "misc"
75
75
  if not external_files_dir.is_dir():
76
76
  logger.info(f"Creating {external_files_dir} directory")
77
77
  external_files_dir.mkdir(parents=True, exist_ok=True)
@@ -143,10 +143,10 @@ def extract_exif_DateTimeOriginal(file_path: str) -> int:
143
143
  else:
144
144
  try:
145
145
  # read from file name (YYYY-MM-DD_HHMMSS)
146
- return int(datetime.datetime.strptime(pl.Path(file_path).stem, "%Y-%m-%d_%H%M%S").timestamp())
146
+ return int(datetime.datetime.strptime(Path(file_path).stem, "%Y-%m-%d_%H%M%S").timestamp())
147
147
  except Exception:
148
148
  # read from file name (YYYY-MM-DD_HH:MM:SS)
149
- return int(datetime.datetime.strptime(pl.Path(file_path).stem, "%Y-%m-%d_%H:%M:%S").timestamp())
149
+ return int(datetime.datetime.strptime(Path(file_path).stem, "%Y-%m-%d_%H:%M:%S").timestamp())
150
150
 
151
151
  except Exception:
152
152
  return -1
@@ -159,7 +159,7 @@ def extract_video_creation_date(file_path: str) -> int | None:
159
159
 
160
160
  logger.debug(f"extract_video_creation_date for {file_path}")
161
161
 
162
- if not pl.Path(file_path).is_file():
162
+ if not Path(file_path).is_file():
163
163
  logger.debug(f"{file_path} not found")
164
164
  return None
165
165
  try:
@@ -839,7 +839,7 @@ def extract_wav(ffmpeg_bin: str, media_file_path: str, tmp_dir: str) -> str:
839
839
  str: wav file path or "" if error
840
840
  """
841
841
 
842
- wav_file_path = pl.Path(tmp_dir) / pl.Path(media_file_path + ".wav").name
842
+ wav_file_path = Path(tmp_dir) / Path(media_file_path + ".wav").name
843
843
 
844
844
  # check if media file is a wav file
845
845
  try:
@@ -1272,11 +1272,11 @@ def check_ffmpeg_path() -> Tuple[bool, str]:
1272
1272
 
1273
1273
  # search embedded ffmpeg
1274
1274
  if sys.platform.startswith("linux") or sys.platform.startswith("darwin"):
1275
- ffmpeg_executable = pl.Path("ffmpeg")
1275
+ ffmpeg_executable = Path("ffmpeg")
1276
1276
  elif sys.platform.startswith("win"):
1277
- ffmpeg_executable = pl.Path("ffmpeg.exe")
1277
+ ffmpeg_executable = Path("ffmpeg.exe")
1278
1278
 
1279
- ffmpeg_path = pl.Path(__file__).parent / "misc" / ffmpeg_executable
1279
+ ffmpeg_path = Path(__file__).parent / "misc" / ffmpeg_executable
1280
1280
 
1281
1281
  if not ffmpeg_path.is_file():
1282
1282
  # search global ffmpeg
@@ -1387,15 +1387,20 @@ def ffprobe_media_analysis(ffmpeg_bin: str, file_name: str) -> dict:
1387
1387
  Returns:
1388
1388
  dict
1389
1389
  """
1390
- # ffprobe -v quiet -print_format json -show_format -show_streams /tmp/ramdisk/video1.mp4
1390
+
1391
+ # check ffprobe executable in same place than ffmpeg
1391
1392
  ffprobe_bin = ffmpeg_bin.replace("ffmpeg", "ffprobe")
1393
+ if not Path(ffprobe_bin).is_file():
1394
+ if which(ffprobe_bin) is None:
1395
+ return {"error": "ffprobe not found"}
1392
1396
 
1393
1397
  command = f'"{ffprobe_bin}" -hide_banner -v error -print_format json -show_format -show_streams "{file_name}"'
1394
1398
 
1395
1399
  p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
1396
1400
  out, error = p.communicate()
1397
1401
  if error:
1398
- return {"error": f"{error}"}
1402
+ if b"invalid data" in error:
1403
+ return {"error": f"{error}"}
1399
1404
 
1400
1405
  try:
1401
1406
  hasVideo = False
@@ -1404,7 +1409,7 @@ def ffprobe_media_analysis(ffmpeg_bin: str, file_name: str) -> dict:
1404
1409
  video_bitrate = None
1405
1410
  audio_bitrate = []
1406
1411
  resolution = None
1407
- fps = 0
1412
+ fps: float = 0
1408
1413
  sample_rate = None
1409
1414
  duration = None
1410
1415
  audio_duration = cfg.NA
@@ -1447,6 +1452,8 @@ def ffprobe_media_analysis(ffmpeg_bin: str, file_name: str) -> dict:
1447
1452
  except Exception:
1448
1453
  pass
1449
1454
 
1455
+ fps = round(fps, 3)
1456
+
1450
1457
  if "duration" in stream:
1451
1458
  duration = float(stream["duration"])
1452
1459
  if "duration_ts" in stream:
@@ -1698,7 +1705,7 @@ def dir_images_number(dir_path_str: str) -> dict:
1698
1705
  return number of images in dir_path (see cfg.IMAGE_EXTENSIONS)
1699
1706
  """
1700
1707
 
1701
- dir_path = pl.Path(dir_path_str)
1708
+ dir_path = Path(dir_path_str)
1702
1709
  if not dir_path.is_dir():
1703
1710
  return {"error": f"The directory {dir_path_str} does not exists"}
1704
1711
  img_count = 0
boris/version.py CHANGED
@@ -20,5 +20,5 @@ This file is part of BORIS.
20
20
 
21
21
  """
22
22
 
23
- __version__ = "9.4.1"
24
- __version_date__ = "2025-05-28"
23
+ __version__ = "9.5"
24
+ __version_date__ = "2025-06-12"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boris-behav-obs
3
- Version: 9.4.1
3
+ Version: 9.5
4
4
  Summary: BORIS - Behavioral Observation Research Interactive Software
5
5
  Author-email: Olivier Friard <olivier.friard@unito.it>
6
6
  License-Expression: GPL-3.0-only
@@ -26,10 +26,13 @@ Requires-Dist: tablib[cli,html,ods,pandas,xls,xlsx]>=3
26
26
  Requires-Dist: pyreadr
27
27
  Requires-Dist: pyside6==6.9
28
28
  Requires-Dist: hachoir>=3.3.0
29
+ Requires-Dist: scipy>=1.15.3
29
30
  Provides-Extra: dev
30
31
  Requires-Dist: ruff; extra == "dev"
31
32
  Requires-Dist: pytest; extra == "dev"
32
33
  Requires-Dist: pytest-cov; extra == "dev"
34
+ Provides-Extra: r
35
+ Requires-Dist: rpy2>=3.6.1; extra == "r"
33
36
  Dynamic: license-file
34
37
 
35
38
  BORIS (Behavioral Observation Research Interactive Software)