boris-behav-obs 8.16.5__py3-none-any.whl → 9.7.1__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 (125) hide show
  1. boris/__init__.py +1 -1
  2. boris/__main__.py +1 -1
  3. boris/about.py +24 -36
  4. boris/add_modifier.py +88 -80
  5. boris/add_modifier_ui.py +235 -131
  6. boris/advanced_event_filtering.py +23 -29
  7. boris/analysis_plugins/__init__.py +0 -0
  8. boris/analysis_plugins/_latency.py +59 -0
  9. boris/analysis_plugins/irr_cohen_kappa.py +109 -0
  10. boris/analysis_plugins/irr_cohen_kappa_with_modifiers.py +112 -0
  11. boris/analysis_plugins/irr_weighted_cohen_kappa.py +157 -0
  12. boris/analysis_plugins/irr_weighted_cohen_kappa_with_modifiers.py +162 -0
  13. boris/analysis_plugins/list_of_dataframe_columns.py +22 -0
  14. boris/analysis_plugins/number_of_occurences.py +22 -0
  15. boris/analysis_plugins/number_of_occurences_by_independent_variable.py +54 -0
  16. boris/analysis_plugins/time_budget.py +61 -0
  17. boris/behav_coding_map_creator.py +228 -229
  18. boris/behavior_binary_table.py +33 -50
  19. boris/behaviors_coding_map.py +17 -18
  20. boris/boris_cli.py +6 -25
  21. boris/cmd_arguments.py +12 -1
  22. boris/coding_pad.py +16 -34
  23. boris/config.py +102 -50
  24. boris/config_file.py +55 -64
  25. boris/connections.py +105 -58
  26. boris/converters.py +13 -37
  27. boris/converters_ui.py +187 -110
  28. boris/cooccurence.py +250 -0
  29. boris/core.py +2108 -1275
  30. boris/core_qrc.py +15892 -10829
  31. boris/core_ui.py +941 -806
  32. boris/db_functions.py +17 -42
  33. boris/dev.py +27 -7
  34. boris/dialog.py +461 -242
  35. boris/duration_widget.py +9 -14
  36. boris/edit_event.py +61 -31
  37. boris/edit_event_ui.py +208 -97
  38. boris/event_operations.py +405 -281
  39. boris/events_cursor.py +25 -17
  40. boris/events_snapshots.py +36 -82
  41. boris/exclusion_matrix.py +4 -9
  42. boris/export_events.py +180 -203
  43. boris/export_observation.py +60 -73
  44. boris/external_processes.py +123 -98
  45. boris/geometric_measurement.py +427 -218
  46. boris/gui_utilities.py +91 -14
  47. boris/image_overlay.py +4 -4
  48. boris/import_observations.py +190 -98
  49. boris/ipc_mpv.py +304 -0
  50. boris/irr.py +20 -57
  51. boris/latency.py +31 -24
  52. boris/measurement_widget.py +14 -18
  53. boris/media_file.py +17 -19
  54. boris/menu_options.py +16 -6
  55. boris/modifier_coding_map_creator.py +1013 -0
  56. boris/modifiers_coding_map.py +7 -9
  57. boris/mpv2.py +128 -35
  58. boris/observation.py +493 -210
  59. boris/observation_operations.py +1010 -391
  60. boris/observation_ui.py +573 -363
  61. boris/observations_list.py +51 -58
  62. boris/otx_parser.py +74 -68
  63. boris/param_panel.py +45 -59
  64. boris/param_panel_ui.py +254 -138
  65. boris/player_dock_widget.py +91 -56
  66. boris/plot_data_module.py +18 -53
  67. boris/plot_events.py +56 -153
  68. boris/plot_events_rt.py +16 -30
  69. boris/plot_spectrogram_rt.py +80 -56
  70. boris/plot_waveform_rt.py +23 -48
  71. boris/plugins.py +431 -0
  72. boris/portion/__init__.py +18 -8
  73. boris/portion/const.py +35 -18
  74. boris/portion/dict.py +5 -5
  75. boris/portion/func.py +2 -2
  76. boris/portion/interval.py +21 -41
  77. boris/portion/io.py +41 -32
  78. boris/preferences.py +298 -123
  79. boris/preferences_ui.py +664 -225
  80. boris/project.py +293 -270
  81. boris/project_functions.py +610 -537
  82. boris/project_import_export.py +204 -213
  83. boris/project_ui.py +673 -441
  84. boris/qrc_boris.py +6 -3
  85. boris/qrc_boris5.py +6 -3
  86. boris/select_modifiers.py +62 -90
  87. boris/select_observations.py +19 -197
  88. boris/select_subj_behav.py +67 -39
  89. boris/state_events.py +51 -33
  90. boris/subjects_pad.py +6 -8
  91. boris/synthetic_time_budget.py +42 -26
  92. boris/time_budget_functions.py +169 -169
  93. boris/time_budget_widget.py +77 -89
  94. boris/transitions.py +41 -41
  95. boris/utilities.py +562 -222
  96. boris/version.py +3 -3
  97. boris/video_equalizer.py +16 -14
  98. boris/video_equalizer_ui.py +199 -130
  99. boris/video_operations.py +78 -28
  100. boris/view_df.py +104 -0
  101. boris/view_df_ui.py +75 -0
  102. boris/write_event.py +240 -136
  103. boris_behav_obs-9.7.1.dist-info/METADATA +140 -0
  104. boris_behav_obs-9.7.1.dist-info/RECORD +109 -0
  105. {boris_behav_obs-8.16.5.dist-info → boris_behav_obs-9.7.1.dist-info}/WHEEL +1 -1
  106. boris_behav_obs-9.7.1.dist-info/entry_points.txt +2 -0
  107. boris/README.TXT +0 -22
  108. boris/add_modifier.ui +0 -323
  109. boris/converters.ui +0 -289
  110. boris/core.qrc +0 -37
  111. boris/core.ui +0 -1571
  112. boris/edit_event.ui +0 -233
  113. boris/icons/logo_eye.ico +0 -0
  114. boris/map_creator.py +0 -982
  115. boris/observation.ui +0 -814
  116. boris/param_panel.ui +0 -379
  117. boris/preferences.ui +0 -537
  118. boris/project.ui +0 -1074
  119. boris/vlc_local.py +0 -90
  120. boris_behav_obs-8.16.5.dist-info/LICENSE.TXT +0 -674
  121. boris_behav_obs-8.16.5.dist-info/METADATA +0 -134
  122. boris_behav_obs-8.16.5.dist-info/RECORD +0 -107
  123. boris_behav_obs-8.16.5.dist-info/entry_points.txt +0 -2
  124. {boris → boris_behav_obs-9.7.1.dist-info/licenses}/LICENSE.TXT +0 -0
  125. {boris_behav_obs-8.16.5.dist-info → boris_behav_obs-9.7.1.dist-info}/top_level.txt +0 -0
boris/config.py CHANGED
@@ -1,7 +1,7 @@
1
1
  """
2
2
  BORIS
3
3
  Behavioral Observation Research Interactive Software
4
- Copyright 2012-2023 Olivier Friard
4
+ Copyright 2012-2025 Olivier Friard
5
5
 
6
6
  This file is part of BORIS.
7
7
 
@@ -22,8 +22,23 @@ This file is part of BORIS.
22
22
 
23
23
  programName: str = "BORIS"
24
24
 
25
+ # socket for MPV IPC mode
26
+ MPV_SOCKET = "/tmp/mpvsocket"
27
+
28
+
29
+ ETHOGRAM_REPOSITORY_URL = "https://www.boris.unito.it/static/ethograms"
30
+
25
31
  project_format_version: str = "7.0"
26
32
 
33
+ SECONDS_PER_DAY: int = 86_400
34
+
35
+ # cutoff value for displaying HH:MM:SS.zzz or YYYY-mm-DD HH:MM:SS:ZZZ
36
+ HOUR_CUTOFF: int = 7 * 24
37
+ DATE_CUTOFF: int = HOUR_CUTOFF * 60 * 60 # 1 week
38
+
39
+ # cutoff for displaying time in HH:MM:SS.zzz format
40
+ SMART_TIME_CUTOFF_DEFAULT: int = 300
41
+
27
42
  # minimal project version for handling observations from images
28
43
  IMAGES_OBS_PROJECT_MIN_VERSION: tuple = (8, 6)
29
44
 
@@ -37,11 +52,12 @@ MAX_UNDO_QUEUE: int = 25
37
52
 
38
53
  NA: str = "NA"
39
54
 
40
- REALTIME_PLOT_CURSOR_COLOR = "red"
55
+ REALTIME_PLOT_CURSOR_COLOR: str = "red"
41
56
 
42
- DYNAMIC_TIME_CUTOFF_DEFAULT = 300
57
+ DARKER_DIFFERENCE = 5
43
58
 
44
59
  CTRL_KEY: str = "Ctrl"
60
+ ALT_KEY: str = "Alt"
45
61
 
46
62
  SPECTRO_TIMER: int = 500
47
63
 
@@ -72,6 +88,7 @@ EVENTS = "events"
72
88
  TIME_OFFSET = "time offset"
73
89
 
74
90
  CODING_MAP = "coding_map"
91
+ CODING_MAP_sp = "coding map" # space between words (no underscore)
75
92
  BEHAVIORS_CODING_MAP = "behaviors_coding_map"
76
93
  SUBJECTS = "subjects_conf"
77
94
  ETHOGRAM = "behaviors_conf"
@@ -118,17 +135,29 @@ CHAR_FORBIDDEN_IN_MODIFIERS = "(|),`~"
118
135
  ADAPT_FAST_JUMP = "adapt_fast_jump"
119
136
  ADAPT_FAST_JUMP_DEFAULT = False
120
137
 
138
+ TIME = "time"
139
+ BEHAVIOR_CODE = "code"
140
+ SUBJECT = "subject"
141
+ MODIFIER = "modifier"
142
+ COMMENT = "comment"
143
+ BEHAVIOR_KEY = "key"
144
+ SUBJECT_KEY = "key"
145
+ BEHAVIOR_CATEGORY = "category"
146
+
121
147
 
122
- subjectsFields = ["key", SUBJECT_NAME, DESCRIPTION]
148
+ subjectsFields = [SUBJECT_KEY, SUBJECT_NAME, DESCRIPTION]
123
149
 
124
150
  UNPAIRED = "UNPAIRED"
125
151
  DISPLAY_SUBTITLES = "display_subtitles"
152
+ CHECK_PROJECT_INTEGRITY = "check_project_integrity"
126
153
 
127
154
 
128
155
  YES = "Yes"
129
156
  NO = "No"
130
157
  CANCEL = "Cancel"
158
+ IGNORE = "Ignore"
131
159
  APPEND = "Append"
160
+ CLOSE = "Close"
132
161
  REPLACE = "Replace"
133
162
  REMOVE = "Remove"
134
163
  SAVE = "Save"
@@ -173,13 +202,6 @@ DATA_PLOT_FIELDS = {
173
202
  }
174
203
  DATA_PLOT_STYLES = ["b-", "r-", "g-", "bo", "ro", "go"]
175
204
 
176
- TIME = "time"
177
- BEHAVIOR_CODE = "code"
178
- SUBJECT = "subject"
179
- MODIFIER = "modifier"
180
- COMMENT = "comment"
181
- BEHAVIOR_KEY = "key"
182
- BEHAVIOR_CATEGORY = "category"
183
205
 
184
206
  FILE_PATH = "file_path"
185
207
 
@@ -188,27 +210,19 @@ IMAGE_PATH = "image path"
188
210
  FRAME_INDEX = "frame index"
189
211
 
190
212
  ZOOM_LEVEL = "zoom level"
213
+ PAN_X = "pan-x"
214
+ PAN_Y = "pan-y"
191
215
  ROTATION_ANGLE = "rotation angle"
192
216
  DISPLAY_MEDIA_SUBTITLES = "display subtitles"
193
217
  OVERLAY = "video overlay"
194
218
 
195
219
 
196
220
  USE_EXIF_DATE = "use_exif_date"
221
+ SUBSTRACT_FIRST_EXIF_DATE = "substract_first_exif_date"
197
222
  TIME_LAPSE = "time_lapse_delay"
198
223
 
199
224
 
200
225
  # fields for event configuration
201
- """
202
- fields = {
203
- "type": 0,
204
- "key": 1,
205
- "code": 2,
206
- "description": 3,
207
- "modifiers": 4,
208
- "excluded": 5,
209
- "coding map": 6,
210
- }
211
- """
212
226
 
213
227
  ETHOGRAM_TABLE_COLUMNS: dict = {
214
228
  0: "key",
@@ -233,18 +247,6 @@ behavioursFields: dict = {
233
247
  "excluded": 7,
234
248
  "coding map": 8,
235
249
  }
236
- """
237
- ETHOGRAM_FIELDS = [
238
- "type",
239
- "key",
240
- "code",
241
- "description",
242
- "category",
243
- "modifiers",
244
- "excluded",
245
- "coding map",
246
- ]
247
- """
248
250
  ETHOGRAM_EDITABLE_FIELDS: tuple = ("key", "code", "description")
249
251
 
250
252
  PROJECT_BEHAVIORS_KEY_FIELD_IDX = 1
@@ -254,13 +256,20 @@ MEDIA_FILE_PATH_IDX = 2
254
256
  HAS_AUDIO_IDX = 6
255
257
 
256
258
  STATE_EVENT = "State event"
259
+ STATE_EVENT_WITH_CODING_MAP = "State event with coding map"
260
+
261
+ STATE_EVENT_TYPES = [STATE_EVENT, STATE_EVENT_WITH_CODING_MAP]
262
+
257
263
  POINT_EVENT = "Point event"
264
+ POINT_EVENT_WITH_CODING_MAP = "Point event with coding map"
265
+
266
+ POINT_EVENT_TYPES = [POINT_EVENT, POINT_EVENT_WITH_CODING_MAP]
258
267
 
259
268
  BEHAVIOR_TYPES = [
260
- "Point event",
261
- "State event",
262
- "Point event with coding map",
263
- "State event with coding map",
269
+ POINT_EVENT,
270
+ STATE_EVENT,
271
+ POINT_EVENT_WITH_CODING_MAP,
272
+ STATE_EVENT_WITH_CODING_MAP,
264
273
  ]
265
274
 
266
275
  DEFAULT_BEHAVIOR_TYPE = "Point event"
@@ -272,7 +281,7 @@ MEDIA_TW_EVENTS_FIELDS_DEFAULT = ("time", FRAME_INDEX, "subject", "code", "type"
272
281
  MEDIA_TW_EVENTS_FIELDS = ("time", FRAME_INDEX, "subject", "code", "type", "modifier", "comment")
273
282
  # MEDIA_TW_EVENTS_FIELDS = ("time", "subject", "code", "type", "modifier", "comment")
274
283
  LIVE_TW_EVENTS_FIELDS = ("time", "subject", "code", "type", "modifier", "comment")
275
- IMAGES_TW_EVENTS_FIELDS = ("time", "subject", "code", "type", "modifier", "comment", IMAGE_INDEX, "image path")
284
+ IMAGES_TW_EVENTS_FIELDS = ("time", "subject", "code", "type", "modifier", "comment", IMAGE_INDEX, IMAGE_PATH)
276
285
 
277
286
  TW_EVENTS_FIELDS = {
278
287
  MEDIA: MEDIA_TW_EVENTS_FIELDS,
@@ -294,7 +303,7 @@ for observation_type in TW_EVENTS_FIELDS:
294
303
  # fields for project events list
295
304
  MEDIA_PJ_EVENTS_FIELDS = (TIME, "subject", "code", "modifier", "comment", FRAME_INDEX)
296
305
  LIVE_PJ_EVENTS_FIELDS = (TIME, "subject", "code", "modifier", "comment")
297
- IMAGES_PJ_EVENTS_FIELDS = (TIME, "subject", "code", "modifier", "comment", "image index", "image path")
306
+ IMAGES_PJ_EVENTS_FIELDS = (TIME, "subject", "code", "modifier", "comment", IMAGE_INDEX, IMAGE_PATH)
298
307
 
299
308
  PJ_EVENTS_FIELDS = {
300
309
  MEDIA: MEDIA_PJ_EVENTS_FIELDS,
@@ -305,9 +314,6 @@ PJ_EVENTS_FIELDS = {
305
314
  VIEWER_IMAGES: IMAGES_PJ_EVENTS_FIELDS,
306
315
  }
307
316
 
308
- # fields for independent variable definition
309
- tw_indVarFields = ["label", "description", "type", "default value", "possible values"]
310
-
311
317
 
312
318
  PJ_OBS_FIELDS = {}
313
319
  for observation_type in PJ_EVENTS_FIELDS:
@@ -315,12 +321,17 @@ for observation_type in PJ_EVENTS_FIELDS:
315
321
  for idx, field in enumerate(PJ_EVENTS_FIELDS[observation_type]):
316
322
  PJ_OBS_FIELDS[observation_type][field] = idx
317
323
 
324
+
325
+ # fields for independent variable definition
326
+ tw_indVarFields = ["label", "description", "type", "default value", "possible values"]
327
+
328
+
318
329
  EVENT_TIME_FIELD_IDX = 0
319
330
  EVENT_SUBJECT_FIELD_IDX = 1
320
331
  EVENT_BEHAVIOR_FIELD_IDX = 2
321
332
  EVENT_MODIFIER_FIELD_IDX = 3
322
333
  EVENT_COMMENT_FIELD_IDX = 4
323
- EVENT_STATUS_FIELD_IDX = 5
334
+ EVENT_STATUS_FIELD_IDX = -1
324
335
  # EVENT_IMAGEIDX_FIELD_IDX = 6
325
336
  # EVENT_IMAGEPATH_FIELD_IDX = 7
326
337
 
@@ -345,6 +356,14 @@ START_FROM_CURRENT_EPOCH_TIME = "start_from_current_epoch_time"
345
356
 
346
357
  SCAN_SAMPLING_TIME = "scan_sampling_time"
347
358
 
359
+ POINT_OBJECT = "Point"
360
+ SEGMENT_OBJECT = "Segment"
361
+ ANGLE_OBJECT = "Angle"
362
+ ORIENTED_ANGLE_OBJECT = "Oriented angle"
363
+ POLYGON_OBJECT = "Polygon"
364
+ POLYLINE_OBJECT = "Polyline"
365
+
366
+
348
367
  NEW = "new"
349
368
  LIST = "list"
350
369
  EDIT = "edit"
@@ -364,6 +383,7 @@ SELECTED_BEHAVIORS = "selected behaviors"
364
383
  SELECTED_SUBJECTS = "selected subjects"
365
384
  INCLUDE_MODIFIERS = "include modifiers"
366
385
  EXCLUDE_BEHAVIORS = "exclude behaviors"
386
+ EXCLUDE_NON_CODED_MODIFIERS = "exclude_non_coded_modifiers"
367
387
  EXCLUDED_BEHAVIORS = "excluded behaviors"
368
388
  TIME_INTERVAL = "time"
369
389
  START_TIME = "start time"
@@ -381,6 +401,7 @@ TIMESTAMP_idx = 3
381
401
 
382
402
  TIME_FULL_OBS = "full obs"
383
403
  TIME_EVENTS = "limit to events"
404
+ TIME_OBS_INTERVAL = "interval of observation"
384
405
  TIME_ARBITRARY_INTERVAL = "time interval"
385
406
 
386
407
  AVAILABLE_INDEP_VAR_TYPES = [NUMERIC, TEXT, SET_OF_VALUES, TIMESTAMP]
@@ -390,16 +411,27 @@ OBSERVATIONS = "observations"
390
411
 
391
412
  CLOSE_BEHAVIORS_BETWEEN_VIDEOS = "close_behaviors_between_videos"
392
413
 
393
- MPV_HWDEC_OPTIONS = ("auto", "auto-safe", "no")
394
- MPV_HWDEC_DEFAULT_VALUE = "auto"
414
+ # MPV hardware decode
395
415
  MPV_HWDEC = "mpv_hwdec"
416
+ MPV_HWDEC_NO = "no"
417
+ MPV_HWDEC_AUTO = "auto"
418
+ MPV_HWDEC_AUTOSAFE = "auto-safe"
419
+ MPV_HWDEC_OPTIONS = (MPV_HWDEC_AUTO, MPV_HWDEC_AUTOSAFE, MPV_HWDEC_NO)
420
+ MPV_HWDEC_DEFAULT_VALUE = MPV_HWDEC_AUTO
396
421
 
422
+ ANALYSIS_PLUGINS = "analysis_plugins"
423
+ EXCLUDED_PLUGINS = "excluded_plugins"
424
+ PERSONAL_PLUGINS_DIR = "personal_plugins_dir"
397
425
 
398
426
  PROJECT_FILE_INDENTATION = "project file indentation"
399
427
  PROJECT_FILE_INDENTATION_COMBO_OPTIONS = ("None", "Newline", "Tab", "2 spaces", "4 spaces")
400
428
  PROJECT_FILE_INDENTATION_OPTIONS = (None, 0, "\t", 2, 4)
401
429
  PROJECT_FILE_INDENTATION_DEFAULT_VALUE = None
402
430
 
431
+ TOOLBAR_ICON_SIZE = "toolbar icon size"
432
+ DEFAULT_TOOLBAR_ICON_SIZE_VALUE = 24
433
+
434
+
403
435
  VIDEO_VIEWER = 0
404
436
  PICTURE_VIEWER = 1
405
437
 
@@ -416,6 +448,7 @@ LENGTH = "length"
416
448
  FPS = "fps"
417
449
  HAS_AUDIO = "hasAudio"
418
450
  HAS_VIDEO = "hasVideo"
451
+ MEDIA_CREATION_TIME = "media_creation_time"
419
452
 
420
453
  STATE = "STATE"
421
454
  POINT = "POINT"
@@ -423,12 +456,15 @@ POINT = "POINT"
423
456
  START = "START"
424
457
  STOP = "STOP"
425
458
 
426
- PLAYER1, PLAYER2 = "1", "2"
459
+ PLAYER1 = "1"
460
+ PLAYER2 = "2"
427
461
  ALL_PLAYERS = [str(x + 1) for x in range(N_PLAYER)]
428
462
 
429
463
  VISUALIZE_SPECTROGRAM = "visualize_spectrogram"
430
464
  VISUALIZE_WAVEFORM = "visualize_waveform"
465
+ MEDIA_CREATION_DATE_AS_OFFSET = "media_creation_date_as_offset"
431
466
 
467
+ MEDIA_SCAN_SAMPLING_DURATION = "media_scan_sampling_duration"
432
468
  IMAGE_DISPLAY_DURATION = "image_display_duration"
433
469
 
434
470
  # plot type
@@ -436,6 +472,9 @@ WAVEFORM_PLOT = "waveform"
436
472
  SPECTROGRAM_PLOT = "spectrogram"
437
473
  EVENTS_PLOT = "plot_events"
438
474
 
475
+ PLAYING = "playing"
476
+ PAUSED = "paused"
477
+ STOPPED = "stopped"
439
478
 
440
479
  POINT_EVENT_ST_DURATION = 0.5
441
480
 
@@ -446,6 +485,8 @@ SLIDER_MAXIMUM = 1000
446
485
 
447
486
  FRAME_DEFAULT_CACHE_SIZE = 1
448
487
 
488
+ EXCLUDED = "excluded"
489
+
449
490
  # modifiers
450
491
  MODIFIERS = "modifiers"
451
492
  SINGLE_SELECTION = 0
@@ -489,6 +530,16 @@ NO_COLOR_CODING_PAD = "#777777"
489
530
  SPECTROGRAM_COLOR_MAPS = ["viridis", "inferno", "plasma", "magma", "gray", "YlOrRd"]
490
531
  SPECTROGRAM_DEFAULT_COLOR_MAP = "viridis"
491
532
  SPECTROGRAM_DEFAULT_TIME_INTERVAL = 10
533
+ SPECTROGRAM_WINDOW_TYPE = "SPECTROGRAM_WINDOW_TYPE"
534
+ SPECTROGRAM_DEFAULT_WINDOW_TYPE = "hanning"
535
+ SPECTROGRAM_NFFT = "SPECTROGRAM_NFFT"
536
+ SPECTROGRAM_DEFAULT_NFFT = "1024"
537
+ SPECTROGRAM_NOVERLAP = "SPECTROGRAM_NOVERLAP"
538
+ SPECTROGRAM_DEFAULT_NOVERLAP = 900
539
+ SPECTROGRAM_VMIN = "SPECTROGRAM_VMIN"
540
+ SPECTROGRAM_DEFAULT_VMIN = -100
541
+ SPECTROGRAM_VMAX = "SPECTROGRAM_VMAX"
542
+ SPECTROGRAM_DEFAULT_VMAX = -20
492
543
 
493
544
  # see matplotlib.colors.cnames.keys()
494
545
  # https://xkcd.com/color/rgb/
@@ -663,6 +714,7 @@ EMPTY_PROJECT = {
663
714
  ETHOGRAM: {},
664
715
  OBSERVATIONS: {},
665
716
  BEHAVIORAL_CATEGORIES: [],
717
+ BEHAVIORAL_CATEGORIES_CONF: {},
666
718
  INDEPENDENT_VARIABLES: {},
667
719
  CODING_MAP: {},
668
720
  BEHAVIORS_CODING_MAP: [],
@@ -683,10 +735,10 @@ INIT_PARAM = {
683
735
  SDIS_EXT = "sds"
684
736
  TBS_EXT = "tbs"
685
737
  TSV_EXT = "tsv"
686
- CSV_EXT = "cvs"
738
+ CSV_EXT = "csv"
687
739
  RDS_EXT = "rds"
688
740
  PANDAS_DF_EXT = "pkl"
689
- HMTL_EXT = "html"
741
+ HTML_EXT = "html"
690
742
  SQL_EXT = "sql"
691
743
  ODS_EXT = "ods"
692
744
  XLS_EXT = "xls"
@@ -716,7 +768,7 @@ FILE_NAME_SUFFIX = {
716
768
  XLSX: XLSX_EXT,
717
769
  XLSX_WB: XLSX_EXT,
718
770
  XLS: XLS_EXT,
719
- HTML: HMTL_EXT,
771
+ HTML: HTML_EXT,
720
772
  PANDAS_DF: PANDAS_DF_EXT,
721
773
  RDS: RDS_EXT,
722
774
  SQL: SQL_EXT,
boris/config_file.py CHANGED
@@ -1,7 +1,7 @@
1
1
  """
2
2
  BORIS
3
3
  Behavioral Observation Research Interactive Software
4
- Copyright 2012-2023 Olivier Friard
4
+ Copyright 2012-2025 Olivier Friard
5
5
 
6
6
  This file is part of BORIS.
7
7
 
@@ -18,21 +18,17 @@ This file is part of BORIS.
18
18
  You should have received a copy of the GNU General Public License
19
19
  along with this program; if not see <http://www.gnu.org/licenses/>.
20
20
 
21
- """
22
-
23
- """
24
21
  Read and write the BORIS config file
25
22
  """
26
23
 
27
24
  import pathlib as pl
28
25
  import logging
29
26
  import time
30
- import os
31
27
 
32
28
  from . import config as cfg
33
29
  from . import dialog
34
30
 
35
- from PyQt5.QtCore import QByteArray, QSettings
31
+ from PySide6.QtCore import QByteArray, QSettings
36
32
 
37
33
 
38
34
  def read(self):
@@ -40,19 +36,19 @@ def read(self):
40
36
  read config file
41
37
  """
42
38
 
43
- iniFilePath = pl.Path.home() / pl.Path(".boris")
39
+ ini_fil_p_pe_p_path = pl.Path.home() / pl.Path(".boris")
44
40
 
45
- logging.debug(f"read config file: {iniFilePath}")
41
+ logging.debug(f"read config file: {ini_fil_p_pe_p_path}")
46
42
 
47
- if iniFilePath.is_file():
48
- settings = QSettings(str(iniFilePath), QSettings.IniFormat)
43
+ if ini_fil_p_pe_p_path.is_file():
44
+ settings = QSettings(str(ini_fil_p_pe_p_path), QSettings.IniFormat)
49
45
 
50
46
  try:
51
47
  self.config_param = settings.value("config")
52
48
  except Exception:
53
- self.config_param = None
54
- pass
55
- if self.config_param is None:
49
+ self.config_param = {}
50
+
51
+ if self.config_param == {}:
56
52
  self.config_param = cfg.INIT_PARAM
57
53
 
58
54
  # for back compatibility
@@ -76,7 +72,7 @@ def read(self):
76
72
  if not isinstance(self.saved_state, QByteArray):
77
73
  self.saved_state = None
78
74
 
79
- logging.debug(f"saved state: {self.saved_state}")
75
+ # logging.debug(f"saved state: {self.saved_state}")
80
76
 
81
77
  self.timeFormat = cfg.HHMMSS
82
78
  try:
@@ -172,25 +168,27 @@ def read(self):
172
168
 
173
169
  # check for new version
174
170
  self.checkForNewVersion = False
175
- try:
176
- if settings.value("check_for_new_version") is None:
177
- self.checkForNewVersion = (
178
- dialog.MessageDialog(
179
- cfg.programName,
180
- (
181
- "Allow BORIS to automatically check for new version and news?\n"
182
- "(An internet connection is required)\n"
183
- "You can change this option in the Preferences (File > Preferences)"
184
- ),
185
- [cfg.YES, cfg.NO],
171
+
172
+ if not self.no_first_launch_dialog:
173
+ try:
174
+ if settings.value("check_for_new_version") is None:
175
+ self.checkForNewVersion = (
176
+ dialog.MessageDialog(
177
+ cfg.programName,
178
+ (
179
+ "Allow BORIS to automatically check for new version and news?\n"
180
+ "(An internet connection is required)\n"
181
+ "You can change this option in the Preferences (File > Preferences)"
182
+ ),
183
+ [cfg.YES, cfg.NO],
184
+ )
185
+ == cfg.YES
186
186
  )
187
- == cfg.YES
188
- )
189
- else:
190
- self.checkForNewVersion = settings.value("check_for_new_version") == "true"
191
- except Exception:
192
- self.checkForNewVersion = False
193
- logging.debug(f"check_for_new_version: {self.checkForNewVersion}")
187
+ else:
188
+ self.checkForNewVersion = settings.value("check_for_new_version") == "true"
189
+ except Exception:
190
+ self.checkForNewVersion = False
191
+ logging.debug(f"Automatic check for new version: {self.checkForNewVersion}")
194
192
 
195
193
  # pause before add event
196
194
  self.pause_before_addevent = False
@@ -203,11 +201,11 @@ def read(self):
203
201
 
204
202
  if self.checkForNewVersion:
205
203
  if settings.value("last_check_for_new_version") and (
206
- int(time.mktime(time.localtime())) - int(settings.value("last_check_for_new_version"))
207
- > cfg.CHECK_NEW_VERSION_DELAY
204
+ int(time.mktime(time.localtime())) - int(settings.value("last_check_for_new_version")) > cfg.CHECK_NEW_VERSION_DELAY
208
205
  ):
209
206
  self.actionCheckUpdate_activated(flagMsgOnlyIfNew=True)
210
- logging.debug(f"last_check_for_new_version: {settings.value('last_check_for_new_version')}")
207
+
208
+ logging.debug(f"last check for new version: {settings.value('last_check_for_new_version')}")
211
209
 
212
210
  self.ffmpeg_cache_dir = ""
213
211
  try:
@@ -245,10 +243,7 @@ def read(self):
245
243
  if (
246
244
  dialog.MessageDialog(
247
245
  cfg.programName,
248
- (
249
- "The colors list contain colors that are very light.\n"
250
- "Do you want to reload the default colors list?"
251
- ),
246
+ ("The colors list contain colors that are very light.\nDo you want to reload the default colors list?"),
252
247
  [cfg.NO, cfg.YES],
253
248
  )
254
249
  == cfg.YES
@@ -261,18 +256,11 @@ def read(self):
261
256
  except Exception:
262
257
  self.behav_category_colors = cfg.CATEGORY_COLORS_LIST
263
258
 
264
- if (
265
- "white" in self.behav_category_colors
266
- or "azure" in self.behav_category_colors
267
- or "snow" in self.behav_category_colors
268
- ):
259
+ if "white" in self.behav_category_colors or "azure" in self.behav_category_colors or "snow" in self.behav_category_colors:
269
260
  if (
270
261
  dialog.MessageDialog(
271
262
  cfg.programName,
272
- (
273
- "The colors list contain colors that are very light.\n"
274
- "Do you want to reload the default colors list?"
275
- ),
263
+ ("The colors list contain colors that are very light.\nDo you want to reload the default colors list?"),
276
264
  [cfg.NO, cfg.YES],
277
265
  )
278
266
  == cfg.YES
@@ -282,25 +270,28 @@ def read(self):
282
270
  else: # no .boris file found
283
271
  logging.info("No config file found")
284
272
  # ask user for checking for new version
285
- self.checkForNewVersion = (
286
- dialog.MessageDialog(
287
- cfg.programName,
288
- (
289
- "Allow BORIS to automatically check for new version?\n"
290
- "(An internet connection is required)\n"
291
- "You can change this option in the"
292
- " Preferences (File > Preferences)"
293
- ),
294
- [cfg.NO, cfg.YES],
273
+ if not self.no_first_launch_dialog:
274
+ self.checkForNewVersion = (
275
+ dialog.MessageDialog(
276
+ cfg.programName,
277
+ (
278
+ "Allow BORIS to automatically check for new version?\n"
279
+ "(An internet connection is required)\n"
280
+ "You can change this option in the"
281
+ " Preferences (File > Preferences)"
282
+ ),
283
+ [cfg.NO, cfg.YES],
284
+ )
285
+ == cfg.YES
295
286
  )
296
- == cfg.YES
297
- )
287
+ else:
288
+ self.checkForNewVersion = False
298
289
 
299
290
  # recent projects
300
- logging.info("read recent projects")
301
- iniFilePath = str(pl.Path.home() / ".boris_recent_projects")
302
- if os.path.isfile(iniFilePath):
303
- settings = QSettings(iniFilePath, QSettings.IniFormat)
291
+ logging.debug("read recent projects")
292
+ recent_projects_file_path = pl.Path.home() / ".boris_recent_projects"
293
+ if recent_projects_file_path.is_file():
294
+ settings = QSettings(str(recent_projects_file_path), QSettings.IniFormat)
304
295
  try:
305
296
  self.recent_projects = settings.value("recent_projects").split("|||")
306
297
  while "" in self.recent_projects: