boris-behav-obs 9.7.12__py3-none-any.whl → 9.8.2__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.
Files changed (84) hide show
  1. boris/__init__.py +1 -1
  2. boris/__main__.py +1 -1
  3. boris/about.py +4 -3
  4. boris/add_modifier.py +1 -1
  5. boris/advanced_event_filtering.py +1 -1
  6. boris/analysis_plugins/export_to_feral.py +336 -0
  7. boris/analysis_plugins/irr_weighted_cohen_kappa.py +2 -2
  8. boris/behav_coding_map_creator.py +1 -1
  9. boris/behavior_binary_table.py +1 -1
  10. boris/behaviors_coding_map.py +1 -1
  11. boris/boris_cli.py +1 -1
  12. boris/cmd_arguments.py +1 -1
  13. boris/coding_pad.py +1 -1
  14. boris/config.py +15 -3
  15. boris/config_file.py +18 -19
  16. boris/connections.py +12 -13
  17. boris/converters.py +1 -1
  18. boris/converters_ui.py +2 -3
  19. boris/cooccurence.py +1 -1
  20. boris/core.py +168 -166
  21. boris/core_qrc.py +1830 -1967
  22. boris/core_ui.py +1 -1
  23. boris/db_functions.py +5 -14
  24. boris/dialog.py +24 -24
  25. boris/edit_event.py +1 -1
  26. boris/event_operations.py +1 -1
  27. boris/events_cursor.py +1 -1
  28. boris/events_snapshots.py +133 -78
  29. boris/exclusion_matrix.py +1 -1
  30. boris/export_events.py +49 -43
  31. boris/export_observation.py +1 -1
  32. boris/external_processes.py +1 -1
  33. boris/geometric_measurement.py +1 -1
  34. boris/gui_utilities.py +1 -1
  35. boris/image_overlay.py +1 -1
  36. boris/import_observations.py +1 -1
  37. boris/ipc_mpv.py +1 -1
  38. boris/irr.py +1 -1
  39. boris/latency.py +1 -1
  40. boris/measurement_widget.py +1 -1
  41. boris/media_file.py +1 -1
  42. boris/menu_options.py +14 -12
  43. boris/modifier_coding_map_creator.py +1 -1
  44. boris/modifiers_coding_map.py +1 -1
  45. boris/observation.py +13 -14
  46. boris/observation_operations.py +1 -1
  47. boris/observations_list.py +1 -1
  48. boris/otx_parser.py +1 -1
  49. boris/param_panel.py +1 -1
  50. boris/player_dock_widget.py +1 -1
  51. boris/plot_data_module.py +1 -1
  52. boris/plot_events.py +1 -1
  53. boris/plot_events_rt.py +1 -1
  54. boris/plot_spectrogram_rt.py +42 -73
  55. boris/plot_waveform_rt.py +1 -1
  56. boris/plugins.py +1 -1
  57. boris/preferences.py +35 -4
  58. boris/preferences_ui.py +48 -18
  59. boris/project.py +1 -1
  60. boris/project_functions.py +19 -22
  61. boris/project_import_export.py +1 -1
  62. boris/select_modifiers.py +1 -1
  63. boris/select_observations.py +22 -23
  64. boris/select_subj_behav.py +4 -4
  65. boris/state_events.py +1 -1
  66. boris/subjects_pad.py +1 -1
  67. boris/synthetic_time_budget.py +1 -1
  68. boris/time_budget_functions.py +1 -1
  69. boris/time_budget_widget.py +1 -1
  70. boris/transitions.py +1 -1
  71. boris/utilities.py +1 -1
  72. boris/version.py +3 -3
  73. boris/video_equalizer.py +1 -1
  74. boris/video_operations.py +1 -1
  75. boris/view_df.py +28 -4
  76. boris/write_event.py +1 -1
  77. {boris_behav_obs-9.7.12.dist-info → boris_behav_obs-9.8.2.dist-info}/METADATA +2 -2
  78. boris_behav_obs-9.8.2.dist-info/RECORD +110 -0
  79. {boris_behav_obs-9.7.12.dist-info → boris_behav_obs-9.8.2.dist-info}/WHEEL +1 -1
  80. boris/analysis_plugins/_export_to_feral.py +0 -225
  81. boris_behav_obs-9.7.12.dist-info/RECORD +0 -110
  82. {boris_behav_obs-9.7.12.dist-info → boris_behav_obs-9.8.2.dist-info}/entry_points.txt +0 -0
  83. {boris_behav_obs-9.7.12.dist-info → boris_behav_obs-9.8.2.dist-info}/licenses/LICENSE.TXT +0 -0
  84. {boris_behav_obs-9.7.12.dist-info → boris_behav_obs-9.8.2.dist-info}/top_level.txt +0 -0
boris/core.py CHANGED
@@ -1,7 +1,7 @@
1
1
  """
2
2
  BORIS
3
3
  Behavioral Observation Research Interactive Software
4
- Copyright 2012-2025 Olivier Friard
4
+ Copyright 2012-2026 Olivier Friard
5
5
 
6
6
  This file is part of BORIS.
7
7
 
@@ -25,37 +25,36 @@ import os
25
25
  import sys
26
26
  from pathlib import Path
27
27
 
28
- # os.environ["PATH"] = os.path.dirname(__file__) + os.sep + "misc" + os.pathsep + os.environ["PATH"]
29
-
30
28
  os.environ["PATH"] = str(Path(__file__).parent / "misc") + os.pathsep + os.environ["PATH"]
31
29
  sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".")))
32
30
 
33
31
  import datetime
32
+ import gzip
34
33
  import json
34
+ import locale
35
35
  import logging
36
+ import math
36
37
  import platform
37
38
  import re
38
- import PIL.Image
39
- import PIL.ImageEnhance
40
- from PIL.ImageQt import Image
39
+ import shutil
41
40
  import subprocess
42
- import locale
43
41
  import tempfile
44
- import math
45
42
  import time
46
43
  import urllib.request
47
- from decimal import Decimal as dec
48
- from decimal import ROUND_DOWN
49
- import gzip
44
+ import zipfile
50
45
  from collections import deque
46
+ from decimal import ROUND_DOWN
47
+ from decimal import Decimal as dec
48
+
51
49
  import matplotlib
52
- import zipfile
53
- import shutil
50
+ import PIL.Image
51
+ import PIL.ImageEnhance
52
+ from PIL.ImageQt import Image
54
53
 
55
54
  matplotlib.use("QtAgg")
56
55
 
57
- from PySide6.QtCore import Qt, QPoint, Signal, QEvent, QDateTime, QUrl, QAbstractTableModel, QElapsedTimer, QSettings, QTimer
58
- from PySide6.QtGui import QIcon, QPixmap, QFont, QKeyEvent, QDesktopServices, QColor, QPainter, QPolygon, QAction
56
+ from PySide6.QtCore import QAbstractTableModel, QDateTime, QElapsedTimer, QEvent, QPoint, QSettings, Qt, QUrl, Signal
57
+ from PySide6.QtGui import QAction, QColor, QDesktopServices, QFont, QIcon, QKeyEvent, QPainter, QPixmap, QPolygon
59
58
  from PySide6.QtMultimedia import QSoundEffect
60
59
  from PySide6.QtWidgets import (
61
60
  QAbstractItemView,
@@ -74,7 +73,6 @@ from PySide6.QtWidgets import (
74
73
  QTableWidgetItem,
75
74
  )
76
75
 
77
-
78
76
  from . import cmd_arguments
79
77
 
80
78
  # parse command line arguments
@@ -94,39 +92,39 @@ else:
94
92
  level=logging.INFO,
95
93
  )
96
94
 
97
- from . import utilities as util
98
-
99
- from . import dialog
100
- from . import gui_utilities
101
- from . import events_cursor
102
- from . import modifier_coding_map_creator
103
- from . import geometric_measurement
104
- from . import modifiers_coding_map
105
- from . import advanced_event_filtering
106
- from . import otx_parser
107
- from . import param_panel
108
- from . import plot_events
109
- from . import plot_spectrogram_rt
110
- from . import plot_waveform_rt
111
- from . import plot_events_rt
112
- from . import plugins
113
- from . import project_functions
114
- from . import select_observations
115
- from . import subjects_pad
116
- from . import version
117
- from . import event_operations
118
- from . import core_qrc
119
- from .core_ui import Ui_MainWindow
95
+ from . import (
96
+ advanced_event_filtering,
97
+ config_file,
98
+ core_qrc,
99
+ dialog,
100
+ event_operations,
101
+ events_cursor,
102
+ geometric_measurement,
103
+ gui_utilities,
104
+ modifier_coding_map_creator,
105
+ modifiers_coding_map,
106
+ observation_operations,
107
+ otx_parser,
108
+ param_panel,
109
+ plot_events,
110
+ plot_events_rt,
111
+ plot_spectrogram_rt,
112
+ plot_waveform_rt,
113
+ plugins,
114
+ project,
115
+ project_functions,
116
+ select_observations,
117
+ select_subj_behav,
118
+ subjects_pad,
119
+ version,
120
+ video_operations,
121
+ write_event,
122
+ )
120
123
  from . import config as cfg
121
- from . import video_operations
122
- from . import project
123
- from . import menu_options as menu_options
124
124
  from . import connections as connections
125
- from . import config_file
126
- from . import select_subj_behav
127
- from . import observation_operations
128
- from . import write_event
129
-
125
+ from . import menu_options as menu_options
126
+ from . import utilities as util
127
+ from .core_ui import Ui_MainWindow
130
128
 
131
129
  logging.debug("test")
132
130
 
@@ -177,8 +175,8 @@ class TableModel(QAbstractTableModel):
177
175
  self.observation_type = observation_type
178
176
 
179
177
  def headerData(self, section: int, orientation: Qt.Orientation, role: int):
180
- if role == Qt.DisplayRole:
181
- if orientation == Qt.Horizontal:
178
+ if role == Qt.ItemDataRole.DisplayRole:
179
+ if orientation == Qt.Orientation.Horizontal:
182
180
  return self.header[section]
183
181
  else:
184
182
  return str(section + 1)
@@ -189,8 +187,8 @@ class TableModel(QAbstractTableModel):
189
187
  def columnCount(self, parent=None):
190
188
  return len(self._data[0]) if self.rowCount() else 0
191
189
 
192
- def data(self, index, role=Qt.DisplayRole):
193
- if role == Qt.DisplayRole:
190
+ def data(self, index, role=Qt.ItemDataRole.DisplayRole):
191
+ if role == Qt.ItemDataRole.DisplayRole:
194
192
  row = index.row()
195
193
  if 0 <= row < self.rowCount():
196
194
  column = index.column()
@@ -348,7 +346,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
348
346
  super(MainWindow, self).__init__(parent)
349
347
  self.setupUi(self)
350
348
 
351
- self.pb_live_obs.setFocusPolicy(Qt.NoFocus)
349
+ self.pb_live_obs.setFocusPolicy(Qt.FocusPolicy.NoFocus)
352
350
 
353
351
  self.ffmpeg_bin = ffmpeg_bin
354
352
  # set icons
@@ -379,7 +377,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
379
377
 
380
378
  self.lbLogoBoris.setPixmap(QPixmap(":/logo"))
381
379
  self.lbLogoBoris.setScaledContents(False)
382
- self.lbLogoBoris.setAlignment(Qt.AlignCenter)
380
+ self.lbLogoBoris.setAlignment(Qt.AlignmentFlag.AlignCenter)
383
381
 
384
382
  self.toolBar.setEnabled(True)
385
383
 
@@ -413,13 +411,13 @@ class MainWindow(QMainWindow, Ui_MainWindow):
413
411
 
414
412
  # observation time interval
415
413
  self.lb_obs_time_interval = QLabel()
416
- self.lb_obs_time_interval.setFrameStyle(QFrame.StyledPanel)
414
+ self.lb_obs_time_interval.setFrameStyle(QFrame.Shape.StyledPanel)
417
415
  self.lb_obs_time_interval.setMinimumWidth(160)
418
416
  self.statusbar.addPermanentWidget(self.lb_obs_time_interval)
419
417
 
420
418
  # time offset
421
419
  self.lbTimeOffset = QLabel()
422
- self.lbTimeOffset.setFrameStyle(QFrame.StyledPanel)
420
+ self.lbTimeOffset.setFrameStyle(QFrame.Shape.StyledPanel)
423
421
  self.lbTimeOffset.setMinimumWidth(160)
424
422
  self.statusbar.addPermanentWidget(self.lbTimeOffset)
425
423
 
@@ -431,7 +429,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
431
429
  self.tv_events.setItemDelegate(events_cursor.StyledItemDelegateTriangle(self.events_current_row))
432
430
 
433
431
  connections.connections(self)
434
- self.config_param = cfg.INIT_PARAM
432
+ self.config_param = dict(cfg.INIT_PARAM)
435
433
  config_file.read(self)
436
434
  menu_options.update_menu(self)
437
435
 
@@ -450,9 +448,9 @@ class MainWindow(QMainWindow, Ui_MainWindow):
450
448
  for w in (self.dwEvents, self.dwEthogram, self.dwSubjects):
451
449
  if self.action_block_dockwidgets.isChecked():
452
450
  w.setFloating(False)
453
- w.setFeatures(QDockWidget.NoDockWidgetFeatures)
451
+ w.setFeatures(QDockWidget.DockWidgetFeature.NoDockWidgetFeatures)
454
452
  else:
455
- w.setFeatures(QDockWidget.DockWidgetMovable | QDockWidget.DockWidgetFloatable)
453
+ w.setFeatures(QDockWidget.DockWidgetFeature.DockWidgetMovable | QDockWidget.DockWidgetFeature.DockWidgetFloatable)
456
454
 
457
455
  def advanced_event_filtering(self):
458
456
  """
@@ -524,7 +522,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
524
522
  "Removing the path of media files and image directories from the project file is irreversible.<br>"
525
523
  "Are you sure to continue?"
526
524
  ),
527
- [cfg.YES, cfg.NO],
525
+ (cfg.YES, cfg.NO),
528
526
  )
529
527
  == cfg.NO
530
528
  ):
@@ -542,13 +540,13 @@ class MainWindow(QMainWindow, Ui_MainWindow):
542
540
  dialog.MessageDialog(
543
541
  cfg.programName,
544
542
  ("Removing the path of external data files is irreversible.<br>Are you sure to continue?"),
545
- [cfg.YES, cfg.NO],
543
+ (cfg.YES, cfg.NO),
546
544
  )
547
545
  == cfg.NO
548
546
  ):
549
547
  return
550
548
 
551
- if project_functions.remove_data_files_path(self.pj, self.projectFileName):
549
+ if project_functions.remove_data_files_path(self.pj):
552
550
  self.project_changed()
553
551
 
554
552
  def set_media_files_path_relative_to_project_dir(self):
@@ -560,7 +558,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
560
558
  dialog.MessageDialog(
561
559
  cfg.programName,
562
560
  ("Are you sure to continue?"),
563
- [cfg.YES, cfg.NO],
561
+ (cfg.YES, cfg.NO),
564
562
  )
565
563
  == cfg.NO
566
564
  ):
@@ -577,7 +575,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
577
575
  dialog.MessageDialog(
578
576
  cfg.programName,
579
577
  ("Are you sure to continue?"),
580
- [cfg.YES, cfg.NO],
578
+ (cfg.YES, cfg.NO),
581
579
  )
582
580
  == cfg.NO
583
581
  ):
@@ -697,7 +695,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
697
695
  QMessageBox.warning(self, cfg.programName, "No subjects to show")
698
696
  return
699
697
  self.subjects_pad = subjects_pad.SubjectsPad(self.pj, filtered_subjects)
700
- self.subjects_pad.setWindowFlags(Qt.WindowStaysOnTopHint)
698
+ self.subjects_pad.setWindowFlags(Qt.WindowType.WindowStaysOnTopHint)
701
699
  self.subjects_pad.sendEventSignal.connect(self.signal_from_subjects_pad)
702
700
  self.subjects_pad.click_signal.connect(self.click_signal_from_subjects_pad)
703
701
  self.subjects_pad.close_signal.connect(self.close_signal_from_subjects_pad)
@@ -918,7 +916,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
918
916
  w = dialog.Info_widget()
919
917
  w.lwi.setVisible(False)
920
918
  w.resize(350, 100)
921
- w.setWindowFlags(Qt.WindowStaysOnTopHint)
919
+ w.setWindowFlags(Qt.WindowType.WindowStaysOnTopHint)
922
920
  w.setWindowTitle(cfg.programName)
923
921
  w.label.setText("Extracting WAV from media files...")
924
922
 
@@ -1000,7 +998,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
1000
998
  f"You choose to visualize the {plot_type} during this observation.<br>"
1001
999
  f"{plot_type} generation can take some time for long media, be patient"
1002
1000
  ),
1003
- [cfg.YES, cfg.NO],
1001
+ (cfg.YES, cfg.NO),
1004
1002
  )
1005
1003
  == cfg.NO
1006
1004
  ):
@@ -1018,8 +1016,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
1018
1016
 
1019
1017
  self.spectro = plot_spectrogram_rt.Plot_spectrogram_RT()
1020
1018
 
1021
- self.spectro.setWindowFlags(Qt.WindowStaysOnTopHint)
1022
- self.spectro.setWindowFlags(self.spectro.windowFlags() & ~Qt.WindowMinimizeButtonHint)
1019
+ self.spectro.setWindowFlags(Qt.WindowType.WindowStaysOnTopHint)
1020
+ self.spectro.setWindowFlags(self.spectro.windowFlags() & ~Qt.WindowType.WindowMinimizeButtonHint)
1023
1021
 
1024
1022
  self.spectro.interval = self.spectrogram_time_interval
1025
1023
  self.spectro.cursor_color = cfg.REALTIME_PLOT_CURSOR_COLOR
@@ -1039,8 +1037,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
1039
1037
  self,
1040
1038
  cfg.programName,
1041
1039
  f"Error in spectrogram generation: {r['error']}",
1042
- QMessageBox.Ok | QMessageBox.Default,
1043
- QMessageBox.NoButton,
1040
+ QMessageBox.StandardButton.Ok,
1041
+ QMessageBox.StandardButton.NoButton,
1044
1042
  )
1045
1043
  del self.spectro
1046
1044
  return
@@ -1091,7 +1089,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
1091
1089
  "You choose to visualize the waveform during this observation.<br>"
1092
1090
  "The waveform generation can take some time for long media, be patient"
1093
1091
  ),
1094
- [cfg.YES, cfg.NO],
1092
+ (cfg.YES, cfg.NO),
1095
1093
  )
1096
1094
  == cfg.NO
1097
1095
  ):
@@ -1109,7 +1107,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
1109
1107
 
1110
1108
  self.waveform = plot_waveform_rt.Plot_waveform_RT()
1111
1109
 
1112
- self.waveform.setWindowFlags(Qt.WindowStaysOnTopHint)
1110
+ self.waveform.setWindowFlags(Qt.WindowType.WindowStaysOnTopHint)
1113
1111
  self.waveform.setWindowFlags(self.waveform.windowFlags() & ~Qt.WindowMinimizeButtonHint)
1114
1112
 
1115
1113
  self.waveform.interval = self.spectrogram_time_interval
@@ -1122,8 +1120,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
1122
1120
  self,
1123
1121
  cfg.programName,
1124
1122
  f"Error in waveform generation: {r['error']}",
1125
- QMessageBox.Ok | QMessageBox.Default,
1126
- QMessageBox.NoButton,
1123
+ QMessageBox.StandardButton.Ok,
1124
+ QMessageBox.StandardButton.NoButton,
1127
1125
  )
1128
1126
  del self.waveform
1129
1127
  return
@@ -1146,7 +1144,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
1146
1144
 
1147
1145
  self.plot_events = plot_events_rt.Plot_events_RT()
1148
1146
 
1149
- self.plot_events.setWindowFlags(Qt.WindowStaysOnTopHint)
1147
+ self.plot_events.setWindowFlags(Qt.WindowType.WindowStaysOnTopHint)
1150
1148
  self.plot_events.setWindowFlags(self.plot_events.windowFlags() & ~Qt.WindowMinimizeButtonHint)
1151
1149
 
1152
1150
  self.plot_events.groupby = "behaviors"
@@ -1285,8 +1283,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
1285
1283
  self,
1286
1284
  cfg.programName,
1287
1285
  "No project found",
1288
- QMessageBox.Ok | QMessageBox.Default,
1289
- QMessageBox.NoButton,
1286
+ QMessageBox.StandardButton.Ok,
1287
+ QMessageBox.StandardButton.NoButton,
1290
1288
  )
1291
1289
  return
1292
1290
 
@@ -1301,7 +1299,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
1301
1299
  f"with the same name (<b>{behav_coding_map['name']}</b>).<br>"
1302
1300
  "What do you want to do?"
1303
1301
  ),
1304
- ["Replace the coding map", cfg.CANCEL],
1302
+ ("Replace the coding map", cfg.CANCEL),
1305
1303
  )
1306
1304
  if response == cfg.CANCEL:
1307
1305
  return
@@ -1626,7 +1624,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
1626
1624
  self.currentSubject = subject
1627
1625
  self.lbFocalSubject.setText(f" Focal subject: <b>{self.currentSubject}</b>")
1628
1626
 
1629
- def getCurrentMediaByFrame(self, player: str, requiredFrame: int, fps: float):
1627
+ def getCurrentMediaByFrame(self, player: str, requiredFrame: int, fps: float) -> tuple[str, int]:
1630
1628
  """
1631
1629
  Args:
1632
1630
  player (str): player
@@ -1637,7 +1635,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
1637
1635
  currentMedia
1638
1636
  frameCurrentMedia
1639
1637
  """
1640
- currentMedia, frameCurrentMedia = "", 0
1638
+ currentMedia: str = ""
1639
+ frameCurrentMedia: int = 0
1641
1640
  frameMs = 1000 / fps
1642
1641
  for idx, media in enumerate(self.pj[cfg.OBSERVATIONS][self.observationId][cfg.FILE][player]):
1643
1642
  if requiredFrame * frameMs < sum(self.dw_player[int(player) - 1].media_durations[0 : idx + 1]):
@@ -1646,7 +1645,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
1646
1645
  break
1647
1646
  return currentMedia, round(frameCurrentMedia)
1648
1647
 
1649
- def extract_frame(self, dw):
1648
+ def extract_frame(self, dw) -> None:
1650
1649
  """
1651
1650
  for MEDIA obs: extract frame from video and visualize it in frame_viewer
1652
1651
  for IMAGES obs: load picture and visualize it in frame_viewer, extract EXIF Date/Time Original tag if available
@@ -1658,7 +1657,9 @@ class MainWindow(QMainWindow, Ui_MainWindow):
1658
1657
  time.sleep(0.3) # required for correct frame number
1659
1658
 
1660
1659
  dw.frame_viewer.setPixmap(
1661
- util.pil2pixmap(dw.player.screenshot_raw()).scaled(dw.frame_viewer.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation)
1660
+ util.pil2pixmap(dw.player.screenshot_raw()).scaled(
1661
+ dw.frame_viewer.size(), Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation
1662
+ )
1662
1663
  )
1663
1664
 
1664
1665
  if self.playerType == cfg.IMAGES:
@@ -1667,8 +1668,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
1667
1668
  None,
1668
1669
  cfg.programName,
1669
1670
  ("The picture directory has changed since the creation of observation."),
1670
- QMessageBox.Ok | QMessageBox.Default,
1671
- QMessageBox.NoButton,
1671
+ QMessageBox.StandardButton.Ok,
1672
+ QMessageBox.StandardButton.NoButton,
1672
1673
  )
1673
1674
  return
1674
1675
 
@@ -1727,23 +1728,23 @@ class MainWindow(QMainWindow, Ui_MainWindow):
1727
1728
  # show current states in subjects table
1728
1729
  self.show_current_states_in_subjects_table()
1729
1730
 
1730
- def frame_image_clicked(self, n_player, event):
1731
+ def frame_image_clicked(self, n_player, event) -> None:
1731
1732
  geometric_measurement.image_clicked(self, n_player, event)
1732
1733
 
1733
- def timer_plot_data_out(self, w):
1734
+ def timer_plot_data_out(self, w) -> None:
1734
1735
  """
1735
1736
  update plot in w (Plot_data class)
1736
1737
  triggered by timers in self.ext_data_timer_list
1737
1738
  """
1738
1739
  w.update_plot(self.getLaps())
1739
1740
 
1740
- def signal_from_widget(self, event):
1741
+ def signal_from_widget(self, event) -> None:
1741
1742
  """
1742
1743
  receive signal from widget
1743
1744
  """
1744
1745
  self.keyPressEvent(event)
1745
1746
 
1746
- def reload_frame(self):
1747
+ def reload_frame(self) -> None:
1747
1748
  """
1748
1749
  receive signal to reload frames from geometric measurements
1749
1750
  """
@@ -1759,7 +1760,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
1759
1760
 
1760
1761
  geometric_measurement.redraw_measurements(self)
1761
1762
 
1762
- def save_picture_with_measurements(self, mode: str):
1763
+ def save_picture_with_measurements(self, mode: str) -> None:
1763
1764
  """
1764
1765
  receive signal to save picture from geometric measurements
1765
1766
  """
@@ -1806,7 +1807,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
1806
1807
  self,
1807
1808
  "Select a directory to save the frames",
1808
1809
  os.path.expanduser("~"),
1809
- options=QFileDialog.ShowDirsOnly,
1810
+ options=QFileDialog.Option.ShowDirsOnly,
1810
1811
  )
1811
1812
  if not output_dir:
1812
1813
  return
@@ -1944,7 +1945,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
1944
1945
 
1945
1946
  pixmap.save(str(Path(output_dir) / file_name.with_suffix(".jpg")), "JPG")
1946
1947
 
1947
- def resize_dw(self, dw_id):
1948
+ def resize_dw(self, dw_id) -> None:
1948
1949
  """
1949
1950
  dockwidget was resized. Adapt overlay if any
1950
1951
  """
@@ -2188,8 +2189,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
2188
2189
  None,
2189
2190
  cfg.programName,
2190
2191
  ("This function is not yet implemented"),
2191
- QMessageBox.Ok | QMessageBox.Default,
2192
- QMessageBox.NoButton,
2192
+ QMessageBox.StandardButton.Ok,
2193
+ QMessageBox.StandardButton.NoButton,
2193
2194
  )
2194
2195
 
2195
2196
  return
@@ -2280,7 +2281,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
2280
2281
  self.tv_events.setModel(model)
2281
2282
 
2282
2283
  # column width
2283
- self.tv_events.horizontalHeader().setSectionResizeMode(QHeaderView.Interactive)
2284
+ self.tv_events.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Interactive)
2284
2285
 
2285
2286
  def load_tw_events(self, obs_id) -> None:
2286
2287
  """
@@ -2544,8 +2545,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
2544
2545
  None,
2545
2546
  cfg.programName,
2546
2547
  ("This function is not available for observations with events that do not have timestamp"),
2547
- QMessageBox.Ok | QMessageBox.Default,
2548
- QMessageBox.NoButton,
2548
+ QMessageBox.StandardButton.Ok,
2549
+ QMessageBox.StandardButton.NoButton,
2549
2550
  )
2550
2551
  return
2551
2552
 
@@ -2557,7 +2558,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
2557
2558
  self,
2558
2559
  "Choose a directory to save the plots",
2559
2560
  os.path.expanduser("~"),
2560
- options=QFileDialog.ShowDirsOnly,
2561
+ options=QFileDialog.Option.ShowDirsOnly,
2561
2562
  )
2562
2563
 
2563
2564
  if not plot_directory:
@@ -2660,8 +2661,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
2660
2661
  None,
2661
2662
  cfg.programName,
2662
2663
  ("The duration of one or more observation is not available"),
2663
- QMessageBox.Ok | QMessageBox.Default,
2664
- QMessageBox.NoButton,
2664
+ QMessageBox.StandardButton.Ok,
2665
+ QMessageBox.StandardButton.NoButton,
2665
2666
  )
2666
2667
  return
2667
2668
 
@@ -2673,8 +2674,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
2673
2674
  None,
2674
2675
  cfg.programName,
2675
2676
  ("This function is not available for observations with events that do not have timestamp"),
2676
- QMessageBox.Ok | QMessageBox.Default,
2677
- QMessageBox.NoButton,
2677
+ QMessageBox.StandardButton.Ok,
2678
+ QMessageBox.StandardButton.NoButton,
2678
2679
  )
2679
2680
  return
2680
2681
 
@@ -2709,7 +2710,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
2709
2710
  self,
2710
2711
  "Choose a directory to save the plots",
2711
2712
  os.path.expanduser("~"),
2712
- options=QFileDialog.ShowDirsOnly,
2713
+ options=QFileDialog.Option.ShowDirsOnly,
2713
2714
  )
2714
2715
  if not plot_directory:
2715
2716
  return
@@ -2777,7 +2778,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
2777
2778
  dialog.MessageDialog(
2778
2779
  cfg.programName,
2779
2780
  "There is a current observation. What do you want to do?",
2780
- ["Close observation", "Continue observation"],
2781
+ ("Close observation", "Continue observation"),
2781
2782
  )
2782
2783
  == "Close observation"
2783
2784
  ):
@@ -2789,7 +2790,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
2789
2790
  response = dialog.MessageDialog(
2790
2791
  cfg.programName,
2791
2792
  "What to do about the current unsaved project?",
2792
- [cfg.SAVE, cfg.DISCARD, cfg.CANCEL],
2793
+ (cfg.SAVE, cfg.DISCARD, cfg.CANCEL),
2793
2794
  )
2794
2795
 
2795
2796
  if response == cfg.SAVE:
@@ -2849,7 +2850,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
2849
2850
  "In this project all the behavior and subject keys are upper case.<br>"
2850
2851
  "Do you want to convert them in lower case?"
2851
2852
  ),
2852
- [cfg.YES, cfg.NO],
2853
+ (cfg.YES, cfg.NO),
2853
2854
  )
2854
2855
  == cfg.YES
2855
2856
  ):
@@ -2901,7 +2902,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
2901
2902
  dialog.MessageDialog(
2902
2903
  cfg.programName,
2903
2904
  "There is a current observation. What do you want to do?",
2904
- ["Close observation", "Continue observation"],
2905
+ ("Close observation", "Continue observation"),
2905
2906
  )
2906
2907
  == "Close observation"
2907
2908
  ):
@@ -2913,7 +2914,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
2913
2914
  response = dialog.MessageDialog(
2914
2915
  cfg.programName,
2915
2916
  "What to do about the current unsaved project?",
2916
- [cfg.SAVE, cfg.DISCARD, cfg.CANCEL],
2917
+ (cfg.SAVE, cfg.DISCARD, cfg.CANCEL),
2917
2918
  )
2918
2919
 
2919
2920
  if response == cfg.SAVE:
@@ -2964,7 +2965,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
2964
2965
  response = dialog.MessageDialog(
2965
2966
  cfg.programName,
2966
2967
  "There is a current observation. What do you want to do?",
2967
- ["Close observation", "Continue observation"],
2968
+ ("Close observation", "Continue observation"),
2968
2969
  )
2969
2970
  if response == "Close observation":
2970
2971
  observation_operations.close_observation(self)
@@ -2975,7 +2976,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
2975
2976
  response = dialog.MessageDialog(
2976
2977
  cfg.programName,
2977
2978
  "What to do about the current unsaved project?",
2978
- [cfg.SAVE, cfg.DISCARD, cfg.CANCEL],
2979
+ (cfg.SAVE, cfg.DISCARD, cfg.CANCEL),
2979
2980
  )
2980
2981
  if response == cfg.SAVE:
2981
2982
  if self.save_project_activated() == "not saved":
@@ -3019,7 +3020,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
3019
3020
  response = dialog.MessageDialog(
3020
3021
  cfg.programName,
3021
3022
  "The current observation will be closed. Do you want to continue?",
3022
- [cfg.YES, cfg.NO],
3023
+ (cfg.YES, cfg.NO),
3023
3024
  )
3024
3025
  if response == cfg.NO:
3025
3026
  self.show_data_files()
@@ -3032,7 +3033,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
3032
3033
  response = dialog.MessageDialog(
3033
3034
  cfg.programName,
3034
3035
  "What to do with the current unsaved project?",
3035
- [cfg.SAVE, cfg.DISCARD, cfg.CANCEL],
3036
+ (cfg.SAVE, cfg.DISCARD, cfg.CANCEL),
3036
3037
  )
3037
3038
 
3038
3039
  if response == cfg.SAVE:
@@ -3233,7 +3234,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
3233
3234
 
3234
3235
  del newProjectWindow
3235
3236
 
3236
- def save_project_json(self, project_file_name: str) -> int:
3237
+ def save_project_json(self, project_file_name: str) -> int | None:
3237
3238
  """
3238
3239
  save project to JSON file
3239
3240
  convert Decimal type in float
@@ -3299,21 +3300,21 @@ class MainWindow(QMainWindow, Ui_MainWindow):
3299
3300
  None,
3300
3301
  cfg.programName,
3301
3302
  "Permission denied to save the project file. Try another directory",
3302
- QMessageBox.Ok | QMessageBox.Default,
3303
- QMessageBox.NoButton,
3303
+ QMessageBox.StandardButton.Ok,
3304
+ QMessageBox.StandardButton.NoButton,
3304
3305
  )
3305
3306
  self.save_project_json_started = False
3306
3307
  return 1
3307
3308
 
3308
3309
  except OSError:
3309
3310
  _, value, _ = sys.exc_info()
3310
- QMessageBox.critical(None, cfg.programName, f"Error saving the project file: {value}", QMessageBox.Ok)
3311
+ QMessageBox.critical(None, cfg.programName, f"Error saving the project file: {value}", QMessageBox.StandardButton.Ok)
3311
3312
  self.save_project_json_started = False
3312
3313
  return 4
3313
3314
 
3314
3315
  except Exception:
3315
3316
  _, value, _ = sys.exc_info()
3316
- QMessageBox.critical(None, cfg.programName, f"Error saving the project file: {value}", QMessageBox.Ok)
3317
+ QMessageBox.critical(None, cfg.programName, f"Error saving the project file: {value}", QMessageBox.StandardButton.Ok)
3317
3318
  self.save_project_json_started = False
3318
3319
  return 2
3319
3320
 
@@ -3344,7 +3345,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
3344
3345
  dialog.MessageDialog(
3345
3346
  cfg.programName,
3346
3347
  f"The file {project_new_file_name} already exists.",
3347
- [cfg.CANCEL, cfg.OVERWRITE],
3348
+ (cfg.CANCEL, cfg.OVERWRITE),
3348
3349
  )
3349
3350
  == cfg.CANCEL
3350
3351
  ):
@@ -3360,7 +3361,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
3360
3361
  dialog.MessageDialog(
3361
3362
  cfg.programName,
3362
3363
  f"The file {project_new_file_name} already exists.",
3363
- [cfg.CANCEL, cfg.OVERWRITE],
3364
+ (cfg.CANCEL, cfg.OVERWRITE),
3364
3365
  )
3365
3366
  == cfg.CANCEL
3366
3367
  ):
@@ -3440,7 +3441,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
3440
3441
  dialog.MessageDialog(
3441
3442
  cfg.programName,
3442
3443
  f"The file {self.projectFileName} already exists.",
3443
- [cfg.CANCEL, cfg.OVERWRITE],
3444
+ (cfg.CANCEL, cfg.OVERWRITE),
3444
3445
  )
3445
3446
  == cfg.CANCEL
3446
3447
  ):
@@ -3459,7 +3460,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
3459
3460
  dialog.MessageDialog(
3460
3461
  cfg.programName,
3461
3462
  f"The file {self.projectFileName} already exists.",
3462
- [cfg.CANCEL, cfg.OVERWRITE],
3463
+ (cfg.CANCEL, cfg.OVERWRITE),
3463
3464
  )
3464
3465
  == cfg.CANCEL
3465
3466
  ):
@@ -3622,8 +3623,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
3622
3623
  None,
3623
3624
  cfg.programName,
3624
3625
  ("This function is not available for observations with events that do not have timestamp"),
3625
- QMessageBox.Ok | QMessageBox.Default,
3626
- QMessageBox.NoButton,
3626
+ QMessageBox.StandardButton.Ok,
3627
+ QMessageBox.StandardButton.NoButton,
3627
3628
  )
3628
3629
  return
3629
3630
 
@@ -3656,7 +3657,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
3656
3657
  self,
3657
3658
  "Choose a directory to save subtitles",
3658
3659
  os.path.expanduser("~"),
3659
- options=QFileDialog.ShowDirsOnly,
3660
+ options=QFileDialog.Option.ShowDirsOnly,
3660
3661
  )
3661
3662
  if not export_dir:
3662
3663
  return
@@ -3667,8 +3668,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
3667
3668
  None,
3668
3669
  cfg.programName,
3669
3670
  f"Error creating subtitles: {msg}",
3670
- QMessageBox.Ok | QMessageBox.Default,
3671
- QMessageBox.NoButton,
3671
+ QMessageBox.StandardButton.Ok,
3672
+ QMessageBox.StandardButton.NoButton,
3672
3673
  )
3673
3674
 
3674
3675
  def next_frame(self) -> None:
@@ -3900,7 +3901,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
3900
3901
  msg_box = QMessageBox(
3901
3902
  QMessageBox.Critical, cfg.programName, f"The code <b>{code}</b> of behavior coding map does not exist in ethogram."
3902
3903
  )
3903
- msg_box.setWindowFlags(msg_box.windowFlags() | Qt.WindowStaysOnTopHint)
3904
+ msg_box.setWindowFlags(msg_box.windowFlags() | Qt.WindowType.WindowStaysOnTopHint)
3904
3905
  msg_box.exec()
3905
3906
  return
3906
3907
 
@@ -4062,17 +4063,18 @@ class MainWindow(QMainWindow, Ui_MainWindow):
4062
4063
 
4063
4064
  Args:
4064
4065
  n_player (int): player
4065
- new_time (int): new time in ms
4066
+ new_time (float): new time in ms
4066
4067
  """
4068
+ new_time_dec = dec(new_time)
4067
4069
 
4068
4070
  if self.dw_player[n_player].player.playlist_count == 1:
4069
4071
  if self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.OFFSET][str(n_player + 1)]:
4070
4072
  if self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.OFFSET][str(n_player + 1)] > 0:
4071
- if new_time < self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.OFFSET][str(n_player + 1)]:
4073
+ if new_time_dec < self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.OFFSET][str(n_player + 1)]:
4072
4074
  # hide video and mute audio if time < offset
4073
4075
  self.media_player_enabled(n_player, enable=False)
4074
4076
  else:
4075
- if new_time - dec(
4077
+ if new_time_dec - dec(
4076
4078
  self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.OFFSET][str(n_player + 1)]
4077
4079
  ) > sum(self.dw_player[n_player].media_durations):
4078
4080
  # hide video and mute audio if required time > video time + offset
@@ -4081,26 +4083,27 @@ class MainWindow(QMainWindow, Ui_MainWindow):
4081
4083
  # show video and enable audio
4082
4084
  self.media_player_enabled(n_player, enable=True)
4083
4085
  self.seek_mediaplayer(
4084
- new_time
4086
+ new_time_dec
4085
4087
  - dec(self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.OFFSET][str(n_player + 1)]),
4086
4088
  player=n_player,
4087
4089
  )
4088
4090
 
4089
4091
  elif self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.OFFSET][str(n_player + 1)] < 0:
4090
- if new_time - dec(self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.OFFSET][str(n_player + 1)]) > sum(
4091
- self.dw_player[n_player].media_durations
4092
- ):
4092
+ if new_time_dec - dec(
4093
+ self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.OFFSET][str(n_player + 1)]
4094
+ ) > sum(self.dw_player[n_player].media_durations):
4093
4095
  # hide video and mute audio if required time > video time + offset
4094
4096
  self.media_player_enabled(n_player, enable=False)
4095
4097
  else:
4096
4098
  self.media_player_enabled(n_player, enable=True)
4097
4099
  self.seek_mediaplayer(
4098
- new_time - dec(self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.OFFSET][str(n_player + 1)]),
4100
+ new_time_dec
4101
+ - dec(self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.OFFSET][str(n_player + 1)]),
4099
4102
  player=n_player,
4100
4103
  )
4101
4104
 
4102
4105
  else: # no offset
4103
- self.seek_mediaplayer(new_time, player=n_player)
4106
+ self.seek_mediaplayer(new_time_dec, player=n_player)
4104
4107
 
4105
4108
  elif self.dw_player[n_player].player.playlist_count > 1:
4106
4109
  # check if new time is before the end of last video
@@ -4297,9 +4300,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
4297
4300
  self.mem_media_name = current_media_name
4298
4301
  self.mem_playlist_index = current_playlist_index
4299
4302
 
4300
- playlist_length = len(self.dw_player[0].player.playlist)
4301
-
4302
4303
  # update observation info
4304
+ playlist_length = len(playlist) if playlist else 0
4303
4305
  msg = ""
4304
4306
  if self.dw_player[0].player.time_pos is not None: # check if video
4305
4307
  msg = f"Current media name: <b>{current_media_name}</b> (#{self.dw_player[0].player.playlist_pos + 1} / {playlist_length})<br>"
@@ -4920,21 +4922,21 @@ class MainWindow(QMainWindow, Ui_MainWindow):
4920
4922
  self.update_project_zoom_pan_values()
4921
4923
 
4922
4924
  # frame-by-frame mode
4923
- if ek == 47 or (ek == Qt.Key_Left and modifier != cfg.CTRL_KEY): # / one frame back
4925
+ if ek == 47 or (ek == Qt.Key.Key_Left and modifier != cfg.CTRL_KEY): # / one frame back
4924
4926
  self.previous_frame()
4925
4927
  return
4926
4928
 
4927
- if ek == 42 or (ek == Qt.Key_Right and modifier != cfg.CTRL_KEY): # * read next frame
4929
+ if ek == 42 or (ek == Qt.Key.Key_Right and modifier != cfg.CTRL_KEY): # * read next frame
4928
4930
  self.next_frame()
4929
4931
  return
4930
4932
 
4931
4933
  if self.playerType in (cfg.MEDIA, cfg.IMAGES):
4932
4934
  # next media file (page up)
4933
- if ek == Qt.Key_PageUp:
4935
+ if ek == Qt.Key.Key_PageUp:
4934
4936
  self.next_media_file()
4935
4937
 
4936
4938
  # previous media file (page down)
4937
- if ek == Qt.Key_PageDown:
4939
+ if ek == Qt.Key.Key_PageDown:
4938
4940
  self.previous_media_file()
4939
4941
 
4940
4942
  if not self.pj[cfg.ETHOGRAM]:
@@ -4977,20 +4979,20 @@ class MainWindow(QMainWindow, Ui_MainWindow):
4977
4979
  return
4978
4980
 
4979
4981
  if (
4980
- ((ek in range(33, 256)) and (ek not in [Qt.Key_Plus, Qt.Key_Minus]))
4982
+ ((ek in range(33, 256)) and (ek not in [Qt.Key.Key_Plus, Qt.Key.Key_Minus]))
4981
4983
  or (ek in cfg.function_keys)
4982
- or (ek == Qt.Key_Enter and event.text())
4984
+ or (ek == Qt.Key.Key_Enter and event.text())
4983
4985
  ): # click from coding pad or subjects pad
4984
4986
  if ek in cfg.function_keys:
4985
4987
  ek_unichr = cfg.function_keys[ek]
4986
- elif ek != Qt.Key_Enter:
4988
+ elif ek != Qt.Key.Key_Enter:
4987
4989
  ek_unichr = ek_text
4988
- elif ek == Qt.Key_Enter and event.text(): # click from coding pad or subjects pad
4990
+ elif ek == Qt.Key.Key_Enter and event.text(): # click from coding pad or subjects pad
4989
4991
  ek_unichr = ek_text
4990
4992
 
4991
4993
  logging.debug(f"{ek_unichr = }")
4992
4994
 
4993
- if ek == Qt.Key_Enter and event.text(): # click from coding pad or subjects pad
4995
+ if ek == Qt.Key.Key_Enter and event.text(): # click from coding pad or subjects pad
4994
4996
  ek_unichr = ""
4995
4997
 
4996
4998
  if "#subject#" in event.text():
@@ -5032,7 +5034,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
5032
5034
  r = dialog.MessageDialog(
5033
5035
  cfg.programName,
5034
5036
  "This key defines a behavior and a subject. Choose one",
5035
- ["&Behavior", "&Subject", cfg.CANCEL],
5037
+ ("&Behavior", "&Subject", cfg.CANCEL),
5036
5038
  )
5037
5039
  if r == cfg.CANCEL:
5038
5040
  return
@@ -5085,7 +5087,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
5085
5087
  "The focal subject is not defined. Do you want to continue?\n"
5086
5088
  "Use Preferences menu option to modify this behaviour."
5087
5089
  ),
5088
- [cfg.YES, cfg.NO],
5090
+ (cfg.YES, cfg.NO),
5089
5091
  )
5090
5092
 
5091
5093
  if self.pj[cfg.OBSERVATIONS][self.observationId][cfg.TYPE] == cfg.MEDIA and flagPlayerPlaying:
@@ -5257,7 +5259,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
5257
5259
  dialog.MessageDialog(
5258
5260
  cfg.programName,
5259
5261
  f"<b>{self.find_dialog.findText.text()}</b> not found. Search from beginning?",
5260
- [cfg.YES, cfg.NO],
5262
+ (cfg.YES, cfg.NO),
5261
5263
  )
5262
5264
  == cfg.YES
5263
5265
  ):
@@ -5278,15 +5280,15 @@ class MainWindow(QMainWindow, Ui_MainWindow):
5278
5280
  self.find_replace_dialog.close()
5279
5281
  return
5280
5282
  if self.find_replace_dialog.combo_fields.currentIndex() == 0: # choose a field
5281
- dialog.MessageDialog(cfg.programName, "Choose a field.", ["OK"])
5283
+ dialog.MessageDialog(cfg.programName, "Choose a field.", (cfg.OK,))
5282
5284
  return
5283
5285
 
5284
5286
  if not self.find_replace_dialog.findText.text():
5285
- dialog.MessageDialog(cfg.programName, "There is nothing to find.", ["OK"])
5287
+ dialog.MessageDialog(cfg.programName, "There is nothing to find.", (cfg.OK,))
5286
5288
  return
5287
5289
 
5288
5290
  if self.find_replace_dialog.cbFindInSelectedEvents.isChecked() and not len(self.find_replace_dialog.rowsToFind):
5289
- dialog.MessageDialog(cfg.programName, "There are no selected events", [cfg.OK])
5291
+ dialog.MessageDialog(cfg.programName, "There are no selected events", (cfg.OK,))
5290
5292
  return
5291
5293
 
5292
5294
  fields_list: list = []
@@ -5294,7 +5296,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
5294
5296
  # check if find and replace contain valid behavior codes
5295
5297
  for bh in (self.find_replace_dialog.findText.text(), self.find_replace_dialog.replaceText.text()):
5296
5298
  if bh not in util.all_subjects(self.pj[cfg.SUBJECTS]):
5297
- dialog.MessageDialog(cfg.programName, f"<b>{bh}</b> is not a valid subject name", [cfg.OK])
5299
+ dialog.MessageDialog(cfg.programName, f"<b>{bh}</b> is not a valid subject name", (cfg.OK,))
5298
5300
  return
5299
5301
  fields_list.append(cfg.PJ_OBS_FIELDS[self.playerType][cfg.SUBJECT])
5300
5302
 
@@ -5302,7 +5304,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
5302
5304
  # check if find and replace contain valid behavior codes
5303
5305
  for bh in (self.find_replace_dialog.findText.text(), self.find_replace_dialog.replaceText.text()):
5304
5306
  if bh not in util.all_behaviors(self.pj[cfg.ETHOGRAM]):
5305
- dialog.MessageDialog(cfg.programName, f"<b>{bh}</b> is not a valid behavior code", [cfg.OK])
5307
+ dialog.MessageDialog(cfg.programName, f"<b>{bh}</b> is not a valid behavior code", (cfg.OK,))
5306
5308
  return
5307
5309
  fields_list.append(cfg.PJ_OBS_FIELDS[self.playerType][cfg.BEHAVIOR_CODE])
5308
5310
 
@@ -5400,7 +5402,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
5400
5402
  self.find_replace_dialog.close()
5401
5403
 
5402
5404
  if msg == "FIND_REPLACE_ALL":
5403
- dialog.MessageDialog(cfg.programName, f"{number_replacement} substitution(s).", [cfg.OK])
5405
+ dialog.MessageDialog(cfg.programName, f"{number_replacement} substitution(s).", (cfg.OK,))
5404
5406
  self.find_replace_dialog.close()
5405
5407
 
5406
5408
  def closeEvent(self, event):
@@ -5430,7 +5432,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
5430
5432
  dialog.MessageDialog(
5431
5433
  cfg.programName,
5432
5434
  "BORIS is doing some job. What do you want to do?",
5433
- ["Wait", "Quit BORIS"],
5435
+ ("Wait", "Quit BORIS"),
5434
5436
  )
5435
5437
  == "Wait"
5436
5438
  ):
@@ -5449,7 +5451,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
5449
5451
  response = dialog.MessageDialog(
5450
5452
  cfg.programName,
5451
5453
  "What to do about the current unsaved project?",
5452
- [cfg.SAVE, cfg.DISCARD, cfg.CANCEL],
5454
+ (cfg.SAVE, cfg.DISCARD, cfg.CANCEL),
5453
5455
  )
5454
5456
 
5455
5457
  if response == cfg.SAVE:
@@ -5776,8 +5778,8 @@ def main():
5776
5778
  None,
5777
5779
  cfg.programName,
5778
5780
  "FFmpeg is not available.<br>Go to http://www.ffmpeg.org to download it",
5779
- QMessageBox.Ok | QMessageBox.Default,
5780
- QMessageBox.NoButton,
5781
+ QMessageBox.StandardButton.Ok | QMessageBox.StandardButton.Default,
5782
+ QMessageBox.StandardButton.NoButton,
5781
5783
  )
5782
5784
  sys.exit(3)
5783
5785
 
@@ -5830,7 +5832,7 @@ def main():
5830
5832
  config_param: dict = {}
5831
5833
  ini_file_path = Path.home() / Path(".boris")
5832
5834
  if ini_file_path.is_file():
5833
- settings = QSettings(str(ini_file_path), QSettings.IniFormat)
5835
+ settings = QSettings(str(ini_file_path), QSettings.Format.IniFormat)
5834
5836
  try:
5835
5837
  config_param = settings.value("config")
5836
5838
  except Exception:
@@ -5863,8 +5865,8 @@ def main():
5863
5865
  None,
5864
5866
  cfg.programName,
5865
5867
  ("The mpv command is not available on the path"),
5866
- QMessageBox.Ok | QMessageBox.Default,
5867
- QMessageBox.NoButton,
5868
+ QMessageBox.StandardButton.Ok | QMessageBox.StandardButton.Default,
5869
+ QMessageBox.StandardButton.NoButton,
5868
5870
  )
5869
5871
  sys.exit()
5870
5872
 
@@ -5873,8 +5875,8 @@ def main():
5873
5875
  None,
5874
5876
  cfg.programName,
5875
5877
  ("This version of BORIS for macOS is still EXPERIMENTAL and should be used at your own risk."),
5876
- QMessageBox.Ok | QMessageBox.Default,
5877
- QMessageBox.NoButton,
5878
+ QMessageBox.StandardButton.Ok | QMessageBox.StandardButton.Default,
5879
+ QMessageBox.StandardButton.NoButton,
5878
5880
  )
5879
5881
 
5880
5882
  window.show()
@@ -5887,8 +5889,8 @@ def main():
5887
5889
  None,
5888
5890
  cfg.programName,
5889
5891
  (f"Error opening observation: <b>{observation_to_open}</b><br>{r.split(':')[1]}"),
5890
- QMessageBox.Ok | QMessageBox.Default,
5891
- QMessageBox.NoButton,
5892
+ QMessageBox.StandardButton.Ok | QMessageBox.StandardButton.Default,
5893
+ QMessageBox.StandardButton.NoButton,
5892
5894
  )
5893
5895
 
5894
5896
  if not options.nosplashscreen and (sys.platform != "darwin"):