boris-behav-obs 9.3.3__py2.py3-none-any.whl → 9.3.4__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/dialog.py CHANGED
@@ -184,7 +184,7 @@ class Info_widget(QWidget):
184
184
 
185
185
  class get_time_widget(QWidget):
186
186
  """
187
- widget for selecting a time in various formats: secondes, HH:MM:SS:ZZZ or YYYY-mm-DD HH:MM:SS:ZZZ
187
+ widget for selecting a time in various formats: seconds, HH:MM:SS:ZZZ or YYYY-mm-DD HH:MM:SS:ZZZ
188
188
  """
189
189
 
190
190
  def __init__(self, time_value=dec(0), parent=None):
@@ -408,7 +408,7 @@ class get_time_widget(QWidget):
408
408
  if self.pb_sign.text() == "-":
409
409
  time_sec = -time_sec
410
410
 
411
- return dec(time_sec) if time_sec is not None else None
411
+ return dec(time_sec).quantize(dec("0.001")) if time_sec is not None else None
412
412
 
413
413
  def set_time(self, new_time: dec) -> None:
414
414
  """
@@ -440,6 +440,11 @@ class get_time_widget(QWidget):
440
440
 
441
441
 
442
442
  class Ask_time(QDialog):
443
+ """
444
+ Qdialog class for asking time to user
445
+ User can select a time format between seconds, HHMMSS.zzz or YYY-mm-DD HH:MM:SS.zzz
446
+ """
447
+
443
448
  def __init__(self, time_value=0):
444
449
  super().__init__()
445
450
  self.setWindowTitle("")
@@ -453,10 +458,10 @@ class Ask_time(QDialog):
453
458
 
454
459
  hbox.addWidget(self.time_widget)
455
460
 
456
- self.pbOK = QPushButton("OK", clicked=self.pb_ok_clicked)
461
+ self.pbOK = QPushButton(cfg.OK, clicked=self.pb_ok_clicked)
457
462
  self.pbOK.setDefault(True)
458
463
 
459
- self.pbCancel = QPushButton("Cancel")
464
+ self.pbCancel = QPushButton(cfg.CANCEL)
460
465
  self.pbCancel.clicked.connect(self.reject)
461
466
 
462
467
  self.hbox2 = QHBoxLayout(self)
@@ -975,6 +980,70 @@ class Results_dialog(QDialog):
975
980
  self.done(cfg.SAVE_DATASET)
976
981
 
977
982
 
983
+ class Results_dialog_exit_code(QDialog):
984
+ """
985
+ widget for visualizing text output
986
+ """
987
+
988
+ def __init__(self):
989
+ super().__init__()
990
+
991
+ self.dataset = False
992
+
993
+ self.setWindowTitle("")
994
+
995
+ hbox = QVBoxLayout()
996
+
997
+ self.lb = QLabel("")
998
+ hbox.addWidget(self.lb)
999
+
1000
+ self.ptText = QPlainTextEdit()
1001
+ self.ptText.setReadOnly(True)
1002
+ hbox.addWidget(self.ptText)
1003
+
1004
+ hbox2 = QHBoxLayout()
1005
+ hbox2.addItem(QSpacerItem(241, 20, QSizePolicy.Expanding, QSizePolicy.Minimum))
1006
+
1007
+ self.pbSave = QPushButton("Save results", clicked=self.save_results)
1008
+ hbox2.addWidget(self.pbSave)
1009
+
1010
+ self.pb1 = QPushButton("1", clicked=lambda: self.done_(1))
1011
+ hbox2.addWidget(self.pb1)
1012
+
1013
+ self.pb2 = QPushButton("2", clicked=lambda: self.done_(2))
1014
+ hbox2.addWidget(self.pb2)
1015
+
1016
+ self.pb3 = QPushButton("3", clicked=lambda: self.done_(3))
1017
+ hbox2.addWidget(self.pb3)
1018
+
1019
+ hbox.addLayout(hbox2)
1020
+ self.setLayout(hbox)
1021
+
1022
+ self.resize(800, 640)
1023
+
1024
+ def done_(self, status):
1025
+ self.done(status)
1026
+
1027
+ def save_results(self):
1028
+ """
1029
+ save content of self.ptText
1030
+ """
1031
+
1032
+ if not self.dataset:
1033
+ file_name, _ = QFileDialog().getSaveFileName(self, "Save results", "", "Text files (*.txt *.tsv);;All files (*)")
1034
+
1035
+ if not file_name:
1036
+ return
1037
+ try:
1038
+ with open(file_name, "w") as f:
1039
+ f.write(self.ptText.toPlainText())
1040
+ except Exception:
1041
+ QMessageBox.critical(self, cfg.programName, f"The file {file_name} can not be saved")
1042
+
1043
+ else:
1044
+ self.done(cfg.SAVE_DATASET)
1045
+
1046
+
978
1047
  class View_data(QDialog):
979
1048
  """
980
1049
  widget for visualizing rows of data file
boris/event_operations.py CHANGED
@@ -576,6 +576,8 @@ def edit_event(self):
576
576
 
577
577
  pj_event_idx = self.tv_idx2events_idx[tvevents_row]
578
578
 
579
+ print(f"{self.pj[cfg.OBSERVATIONS][self.observationId][cfg.EVENTS]=}")
580
+
579
581
  time_value = self.pj[cfg.OBSERVATIONS][self.observationId][cfg.EVENTS][pj_event_idx][
580
582
  cfg.PJ_OBS_FIELDS[self.pj[cfg.OBSERVATIONS][self.observationId][cfg.TYPE]][cfg.TIME]
581
583
  ]
@@ -601,9 +603,12 @@ def edit_event(self):
601
603
  )
602
604
  edit_window.setWindowTitle("Edit event")
603
605
 
606
+ print(f"{time_value=}")
607
+
604
608
  # time
605
609
  if time_value.is_nan():
606
610
  edit_window.cb_set_time_na.setChecked(True)
611
+
607
612
  if self.playerType in (cfg.VIEWER_MEDIA, cfg.VIEWER_LIVE, cfg.VIEWER_IMAGES):
608
613
  edit_window.pb_set_to_current_time.setVisible(False)
609
614
 
@@ -673,12 +678,15 @@ def edit_event(self):
673
678
 
674
679
  flag_ok = False # for looping until event is OK or Cancel pressed
675
680
  while True:
676
- if edit_window.exec_(): # button OK
681
+ if edit_window.exec(): # button OK
677
682
  self.project_changed()
678
683
 
679
684
  # MEDIA / LIVE
680
685
  if self.pj[cfg.OBSERVATIONS][self.observationId][cfg.TYPE] in (cfg.MEDIA, cfg.LIVE):
681
686
  new_time = edit_window.time_widget.get_time()
687
+
688
+ print(f"{new_time=}")
689
+
682
690
  if new_time is None:
683
691
  QMessageBox.warning(
684
692
  self,
@@ -747,7 +755,11 @@ def edit_event(self):
747
755
  for key in self.pj[cfg.ETHOGRAM]:
748
756
  if self.pj[cfg.ETHOGRAM][key][cfg.BEHAVIOR_CODE] == edit_window.cobCode.currentText():
749
757
  event = self.full_event(key)
750
- if edit_window.time_value == cfg.NA or (edit_window.cb_set_time_na.isChecked()):
758
+ if (
759
+ edit_window.time_value == cfg.NA
760
+ or (isinstance(edit_window.time_value, dec) and edit_window.time_value.is_nan())
761
+ or (edit_window.cb_set_time_na.isChecked())
762
+ ):
751
763
  event[cfg.TIME] = dec("NaN")
752
764
  else:
753
765
  event[cfg.TIME] = edit_window.time_widget.get_time()
@@ -1100,7 +1100,7 @@ def close_observation(self):
1100
1100
 
1101
1101
  logging.info(f"Close observation (player type: {self.playerType})")
1102
1102
 
1103
- # check observation events
1103
+ # check observation state events
1104
1104
 
1105
1105
  flag_ok, msg = project_functions.check_state_events_obs(
1106
1106
  self.observationId,
@@ -1111,16 +1111,22 @@ def close_observation(self):
1111
1111
 
1112
1112
  if not flag_ok:
1113
1113
  out = f"The current observation has state event(s) that are not PAIRED:<br><br>{msg}"
1114
- results = dialog.Results_dialog()
1114
+ results = dialog.Results_dialog_exit_code()
1115
1115
  results.setWindowTitle(f"{cfg.programName} - Check selected observations")
1116
1116
  results.ptText.setReadOnly(True)
1117
1117
  results.ptText.appendHtml(out)
1118
- results.pbSave.setVisible(False)
1119
- results.pbCancel.setText("Close observation")
1120
- results.pbCancel.setVisible(True)
1121
- results.pbOK.setText("Fix unpaired state events")
1122
1118
 
1123
- if results.exec_(): # fix events
1119
+ results.pb1.setText("Close observation")
1120
+ results.pb2.setText("Return to observation")
1121
+ if self.playerType == cfg.IMAGES:
1122
+ results.pb3.setVisible(False)
1123
+ else:
1124
+ results.pb3.setText("Fix unpaired state events")
1125
+
1126
+ r = results.exec()
1127
+ if r == 2: # Return to observation
1128
+ return
1129
+ if r == 3: # Fix unpaired state events
1124
1130
  state_events.fix_unpaired_events(self, silent_mode=True)
1125
1131
 
1126
1132
  self.saved_state = self.saveState()
@@ -2407,8 +2413,11 @@ def event2media_file_name(observation: dict, timestamp: dec) -> Optional[str]:
2407
2413
 
2408
2414
  cumul_media_durations: list = [dec(0)]
2409
2415
  for media_file in observation[cfg.FILE][cfg.PLAYER1]:
2410
- media_duration = dec(str(observation[cfg.MEDIA_INFO][cfg.LENGTH][media_file]))
2411
- cumul_media_durations.append(round(cumul_media_durations[-1] + media_duration, 3))
2416
+ try:
2417
+ media_duration = dec(str(observation[cfg.MEDIA_INFO][cfg.LENGTH][media_file]))
2418
+ cumul_media_durations.append(round(cumul_media_durations[-1] + media_duration, 3))
2419
+ except KeyError:
2420
+ return None
2412
2421
 
2413
2422
  cumul_media_durations.remove(dec(0))
2414
2423
 
boris/project.py CHANGED
@@ -150,12 +150,14 @@ class BehavioralCategories(QDialog):
150
150
  sorted([pj[cfg.ETHOGRAM][idx].get(cfg.BEHAVIOR_CATEGORY, "") for idx in pj.get(cfg.ETHOGRAM, {})])
151
151
  )
152
152
 
153
- if behavioral_categories_in_ethogram.difference(set(behavioral_categories)):
153
+ if behavioral_categories_in_ethogram.difference(set(behavioral_categories)) and behavioral_categories_in_ethogram.difference(
154
+ set(behavioral_categories)
155
+ ) != {""}:
154
156
  if (
155
157
  dialog.MessageDialog(
156
158
  cfg.programName,
157
159
  (
158
- "They are behavioral categories that are present in ethogram but not defined.<br>"
160
+ "There are behavioral categories that are present in ethogram but not defined.<br>"
159
161
  f"{behavioral_categories_in_ethogram.difference(set(behavioral_categories))}<br>"
160
162
  "<br>"
161
163
  "Do you want to add them in the behavioral categories list?"
@@ -210,7 +212,6 @@ class BehavioralCategories(QDialog):
210
212
  color = col_diag.currentColor()
211
213
  if color.name() == "#000000": # black -> delete color
212
214
  self.lw.item(row, 1).setText("")
213
- # self.lw.item(row, 1).setBackground(QColor(230, 230, 230))
214
215
  self.lw.item(row, 1).setBackground(self.not_editable_column_color())
215
216
  elif color.isValid():
216
217
  self.lw.item(row, 1).setText(color.name())
@@ -820,18 +821,18 @@ class projectDialog(QDialog, Ui_dlgProject):
820
821
  column (int): column double-clicked
821
822
  """
822
823
 
823
- # check if double click on excluded column
824
+ # excluded column
824
825
  if column == cfg.behavioursFields[cfg.EXCLUDED]:
825
826
  self.exclusion_matrix()
826
827
 
827
- # check if double click on 'coding map' column
828
+ # coding map
828
829
  if column == cfg.behavioursFields[cfg.CODING_MAP_sp]:
829
830
  if "with coding map" in self.twBehaviors.item(row, cfg.behavioursFields[cfg.TYPE]).text():
830
831
  self.behavior_type_changed(row)
831
832
  else:
832
833
  QMessageBox.information(self, cfg.programName, "Change the behavior type on first column to select a coding map")
833
834
 
834
- # check if double click on behavior type
835
+ # behavior type
835
836
  if column == cfg.behavioursFields["type"]:
836
837
  self.behavior_type_doubleclicked(row)
837
838
 
@@ -843,7 +844,7 @@ class projectDialog(QDialog, Ui_dlgProject):
843
844
  if column == cfg.behavioursFields[cfg.BEHAVIOR_CATEGORY]:
844
845
  self.category_doubleclicked(row)
845
846
 
846
- # check if double click on modifiers
847
+ # modifiers
847
848
  if column == cfg.behavioursFields[cfg.MODIFIERS]:
848
849
  # check if behavior has coding map
849
850
  if (
@@ -897,16 +898,17 @@ class projectDialog(QDialog, Ui_dlgProject):
897
898
  if self.twBehaviors.item(row, cfg.behavioursFields[cfg.COLOR]).text():
898
899
  current_color = QColor(self.twBehaviors.item(row, cfg.behavioursFields[cfg.COLOR]).text())
899
900
  if current_color.isValid():
901
+ print(f"{current_color=}")
900
902
  col_diag.setCurrentColor(current_color)
901
903
 
902
- if col_diag.exec_():
904
+ if col_diag.exec():
903
905
  color = col_diag.currentColor()
904
906
  if color.name() == "#000000": # black -> delete color
905
907
  self.twBehaviors.item(row, cfg.behavioursFields[cfg.COLOR]).setText("")
906
908
  self.twBehaviors.item(row, cfg.behavioursFields[cfg.COLOR]).setBackground(self.not_editable_column_color())
907
909
  elif color.isValid():
910
+ self.twBehaviors.item(row, cfg.behavioursFields[cfg.COLOR]).setBackground(QColor(color.name()))
908
911
  self.twBehaviors.item(row, cfg.behavioursFields[cfg.COLOR]).setText(color.name())
909
- self.twBehaviors.item(row, cfg.behavioursFields[cfg.COLOR]).setBackground(color)
910
912
 
911
913
  def category_doubleclicked(self, row):
912
914
  """
@@ -356,7 +356,7 @@ def check_state_events(pj: dict, observations_list: list) -> Tuple[bool, tuple]:
356
356
  use check_state_events_obs function
357
357
  """
358
358
 
359
- logging.info("Check state events")
359
+ logging.info("Check state events function")
360
360
 
361
361
  out = ""
362
362
  not_paired_obs_list = []
@@ -404,7 +404,7 @@ def check_project_integrity(
404
404
  * check if media file are available (optional)
405
405
  * check if media length available
406
406
  * check independent variables
407
- * check if coded subjects are defines
407
+ * check if coded subjects are defined
408
408
 
409
409
  Args:
410
410
  pj (dict): BORIS project
@@ -474,6 +474,7 @@ def check_project_integrity(
474
474
  if not timestamp.is_nan() and not (-2147483647 <= timestamp <= 2147483647):
475
475
  out_events += f"Observation: <b>{obs_id}</b><br>The timestamp {timestamp} is not between -2147483647 and 2147483647.<br>"
476
476
 
477
+ """
477
478
  # check if media length available
478
479
  if pj[cfg.OBSERVATIONS][obs_id][cfg.TYPE] == cfg.MEDIA:
479
480
  for nplayer in cfg.ALL_PLAYERS:
@@ -484,6 +485,7 @@ def check_project_integrity(
484
485
  except KeyError:
485
486
  out += "<br><br>" if out else ""
486
487
  out += f"Observation: <b>{obs_id}</b><br>Length not available for media file <b>{media_file}</b>"
488
+ """
487
489
 
488
490
  out += "<br><br>" if out else ""
489
491
  out += out_events
@@ -530,25 +532,46 @@ def check_project_integrity(
530
532
  ]
531
533
  )
532
534
 
533
- out += "<br><br>" if out else ""
535
+ tmp_out: str = ""
534
536
  for obs_id in pj[cfg.OBSERVATIONS]:
535
537
  if cfg.INDEPENDENT_VARIABLES not in pj[cfg.OBSERVATIONS][obs_id]:
536
538
  continue
537
539
  for var_label in pj[cfg.OBSERVATIONS][obs_id][cfg.INDEPENDENT_VARIABLES]:
538
540
  if var_label in defined_set_var_label:
539
541
  if pj[cfg.OBSERVATIONS][obs_id][cfg.INDEPENDENT_VARIABLES][var_label] not in defined_set_var_label[var_label].split(","):
540
- out += (
542
+ tmp_out += (
541
543
  f"{obs_id}: the <b>{pj[cfg.OBSERVATIONS][obs_id][cfg.INDEPENDENT_VARIABLES][var_label]}</b> value "
542
544
  f" is not allowed for {var_label} (choose between {defined_set_var_label[var_label]})<br>"
543
545
  )
546
+ if tmp_out:
547
+ out += "<br><br>" if out else ""
548
+ out += tmp_out
544
549
 
545
550
  # check if coded subjects are defined in the subjects list
551
+ tmp_out: str = ""
546
552
  subjects_list: list = [pj[cfg.SUBJECTS][x]["name"] for x in pj[cfg.SUBJECTS]]
547
553
  coded_subjects = set(util.flatten_list([[y[1] for y in pj[cfg.OBSERVATIONS][x].get(cfg.EVENTS, [])] for x in pj[cfg.OBSERVATIONS]]))
548
554
 
549
555
  for subject in coded_subjects:
550
556
  if subject and subject not in subjects_list:
551
- out += f"The coded subject <b>{subject}</b> is not defined in the subjects list.<br>You can use the <b>Explore project</b> to fix it.<br><br>"
557
+ tmp_out += f"The coded subject <b>{subject}</b> is not defined in the subjects list.<br>You can use the <b>Explore project</b> to fix it.<br><br>"
558
+ if tmp_out:
559
+ out += "<br><br>" if out else ""
560
+ out += tmp_out
561
+
562
+ # check if media file have info in media_info section of project
563
+ tmp_out: str = ""
564
+ for obs_id in pj[cfg.OBSERVATIONS]:
565
+ for player in pj[cfg.OBSERVATIONS][obs_id][cfg.FILE]:
566
+ for media_file in pj[cfg.OBSERVATIONS][obs_id][cfg.FILE][player]:
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]:
569
+ tmp_out += f"Observation <b>{obs_id}</b>:<br>"
570
+ tmp_out += f"The media file {media_file} has no <b>{info}</b> info.<br>"
571
+ if tmp_out:
572
+ tmp_out += "<br>You should repick the media file to fix this issue."
573
+ out += "<br><br>" if out else ""
574
+ out += tmp_out
552
575
 
553
576
  return out
554
577
 
@@ -1168,13 +1191,8 @@ def observed_interval(observation: dict) -> Tuple[dec, dec]:
1168
1191
  """
1169
1192
  if not observation[cfg.EVENTS]:
1170
1193
  return (dec("0.0"), dec("0.0"))
1171
- if observation[cfg.TYPE] in (cfg.MEDIA, cfg.LIVE):
1172
- """
1173
- print("=" * 120)
1174
- print(observation[cfg.EVENTS])
1175
- print("=" * 120)
1176
- """
1177
1194
 
1195
+ if observation[cfg.TYPE] in (cfg.MEDIA, cfg.LIVE):
1178
1196
  event_timestamp = [event[cfg.PJ_OBS_FIELDS[observation[cfg.TYPE]][cfg.TIME]] for event in observation[cfg.EVENTS]]
1179
1197
 
1180
1198
  return (
@@ -1183,8 +1201,12 @@ def observed_interval(observation: dict) -> Tuple[dec, dec]:
1183
1201
  )
1184
1202
  if observation[cfg.TYPE] == cfg.IMAGES:
1185
1203
  events = [x[cfg.PJ_OBS_FIELDS[observation[cfg.TYPE]][cfg.IMAGE_INDEX]] for x in observation[cfg.EVENTS]]
1186
-
1187
- return (dec(min(events)), dec(max(events)))
1204
+ # test if indexes contain NA
1205
+ try:
1206
+ dec(min(events))
1207
+ return (dec(min(events)), dec(max(events)))
1208
+ except Exception:
1209
+ return (dec("NaN"), dec("NaN"))
1188
1210
 
1189
1211
 
1190
1212
  def events_start_stop(ethogram: dict, events: list, obs_type: str) -> List[tuple]:
@@ -1273,7 +1295,7 @@ def open_project_json(project_file_name: str) -> tuple:
1273
1295
  str: message
1274
1296
  """
1275
1297
 
1276
- logging.debug(f"open project: {project_file_name}")
1298
+ logging.debug(f"open_project_json function: {project_file_name}")
1277
1299
 
1278
1300
  projectChanged: bool = False
1279
1301
  msg: str = ""
@@ -1612,6 +1634,8 @@ def fix_unpaired_state_events2(ethogram: dict, events: list, fix_at_time: dec) -
1612
1634
  list: list of events with state events fixed
1613
1635
  """
1614
1636
 
1637
+ logging.debug("fix_unpaired_state_events2 function")
1638
+
1615
1639
  closing_events_to_add: list = []
1616
1640
  subjects: list = [event[cfg.EVENT_SUBJECT_FIELD_IDX] for event in events]
1617
1641
  ethogram_behaviors: dict = {ethogram[idx][cfg.BEHAVIOR_CODE] for idx in ethogram}
boris/utilities.py CHANGED
@@ -129,7 +129,7 @@ def extract_video_creation_date(file_path: str) -> int | None:
129
129
  return None
130
130
 
131
131
 
132
- def extract_date_time_from_file_name(file_path: str) -> int:
132
+ def extract_date_time_from_file_name(file_path: str) -> int | None:
133
133
  """
134
134
  extract YYYY-MM-DD_HHMMSS or YYYY-MM-DD_HH:MM:SS from file name
135
135
  """
boris/version.py CHANGED
@@ -20,5 +20,5 @@ This file is part of BORIS.
20
20
 
21
21
  """
22
22
 
23
- __version__ = "9.3.3"
24
- __version_date__ = "2025-05-07"
23
+ __version__ = "9.3.4"
24
+ __version_date__ = "2025-05-08"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boris-behav-obs
3
- Version: 9.3.3
3
+ Version: 9.3.4
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
@@ -24,7 +24,7 @@ Requires-Dist: matplotlib>=3.3.3
24
24
  Requires-Dist: pandas>=2.2.2
25
25
  Requires-Dist: tablib[cli,html,ods,pandas,xls,xlsx]>=3
26
26
  Requires-Dist: pyreadr
27
- Requires-Dist: pyside6==6.8.0.2
27
+ Requires-Dist: pyside6==6.9
28
28
  Requires-Dist: hachoir>=3.3.0
29
29
  Provides-Extra: dev
30
30
  Requires-Dist: ruff; extra == "dev"
@@ -17,15 +17,15 @@ boris/converters.py,sha256=c1Jps-URoglY5ILQHz-pCCf6-4DFUHZLtqr_ofsrFg0,11722
17
17
  boris/converters_ui.py,sha256=uu7LOBV_fKv2DBdOqsqPwjGsjgONr5ODBoscAA-EP48,9900
18
18
  boris/cooccurence.py,sha256=tVERC-V8MWjWHlGEfDuu08iS94qjt4do-38jwI62QaY,10367
19
19
  boris/core.py,sha256=EK19Xn0Z_sxu9TaqeRimMzzpn9ThZdTqUtlJJXz6pVY,233512
20
- boris/core_qrc.py,sha256=T3ki5e2Pj0I0QBGz63MPUgZzl8F_VHZwSq074mRNBDU,650669
20
+ boris/core_qrc.py,sha256=J0kom27nrmi4-TCDLJZCZbtUAitiXQ4WEDfErawuxt8,639879
21
21
  boris/core_ui.py,sha256=SeC26uveDCjrCBLsRPuQ6FaapKfON_HIRcQStEDLhl4,76384
22
22
  boris/db_functions.py,sha256=Uw9wWH_Pe-qNzpV1k21YG_jKsoOmfY_iiK_7ARZHGDc,13352
23
23
  boris/dev.py,sha256=9pUElbjl9g17rFUJXX5aVSu55_iIKIuDxNdrB0DI_d0,3671
24
- boris/dialog.py,sha256=6MayZdOsLZCXP1ns02EH9bygYbWPNoEKrXNQrOaw_aw,33071
24
+ boris/dialog.py,sha256=AxqXiTNiNOM5Ec9hGQ54aSeG-0jN_rycQdxJvhM7XWg,34956
25
25
  boris/duration_widget.py,sha256=GjZgCAMGOcsNjoPiRImEVe6yMkH2vuNoh44ulpd5nlg,6924
26
26
  boris/edit_event.py,sha256=2hpxn9DYuJW1CK02hF4iU0--J_0C_KTiN9gGZ1frJBc,7678
27
27
  boris/edit_event_ui.py,sha256=vhglQrhkF9tt0HVlkXnkG7symW0eOFA7nhbk6l_qn3k,7772
28
- boris/event_operations.py,sha256=csGX2hZOtLpmMmFhyTrCMgL-iYINiuu8IGMnEoC6lT4,38332
28
+ boris/event_operations.py,sha256=JNSK9zTbVaPSP2H4hGUtbygyBlFX4hmJXjOqKYRxKoc,38670
29
29
  boris/events_cursor.py,sha256=VPY_ygD0fxE5lp25mcd2l00XQXurCR6hprffF4tKRbU,2078
30
30
  boris/events_snapshots.py,sha256=PjWzQvUGQtIcEc_7FDsRphf7fAhhTccQgYc2eQSA65g,27621
31
31
  boris/exclusion_matrix.py,sha256=ff88xD6aqc8bpIuj9ZCz9ju_HeqqgibQwoaJrIOJ6RI,5272
@@ -47,7 +47,7 @@ boris/mpv-1.0.3.py,sha256=EXRtzQqFjOn4wMC6482Ilq3fNQ9N1GRP1VxwLzdeaBY,88077
47
47
  boris/mpv.py,sha256=EfzIHjPbgewG4w3smEtqEUPZoVwYmMQkL4Q8ZyW-a58,76410
48
48
  boris/mpv2.py,sha256=IUI4t4r9GYX7G5OXTjd3RhMMOkDdfal_15buBgksLsk,92152
49
49
  boris/observation.py,sha256=d-7q-RkMHuLDV87nF4yahvDFPYhlXp6GmE80vckn5zU,57073
50
- boris/observation_operations.py,sha256=Eh-D4ApnuHaXX6fhrFwSsAvEFjMHu7eaI_9vci-drgQ,105790
50
+ boris/observation_operations.py,sha256=5OLdnnzdlazhevJzalDMtXSxo9dRZOLN_5jVE54ZnKE,106039
51
51
  boris/observation_ui.py,sha256=DAnU94QBNvkLuHT6AxTwqSk_D_n6VUhSl8PexZv_dUk,33309
52
52
  boris/observations_list.py,sha256=NqwECGHtHYmKhSe-qCfqPmJ24SSfzlXvIXS2i3op_zE,10591
53
53
  boris/otx_parser.py,sha256=70QvilzFHXbjAHR88YH0aEXJ3xxheLS5fZGgHFHGpNE,16367
@@ -62,8 +62,8 @@ boris/plot_waveform_rt.py,sha256=05JN_6HCq674ROore_6PNw93GQNZJQDlDxp2ODAFkkA,747
62
62
  boris/plugins.py,sha256=CCS1I44OMkGZqcfLGKNPGfEQXPgngocy5YhWveXQPKM,10029
63
63
  boris/preferences.py,sha256=qPfd9Tyg7u30kXwVqMOgkdy2RXri9bItRa5U2-ZVQmg,16847
64
64
  boris/preferences_ui.py,sha256=D2bFLb3E0m6IwSeqKoItRDiqvPmJGoeXLHF2K02n1Zo,26293
65
- boris/project.py,sha256=Yrpoqr5kF8wlvbeYiwm_RK2A9-dLfnxfnhp8TU5ZQbM,86452
66
- boris/project_functions.py,sha256=mPaKTjcegsC6n-J8ZsOhWh_4TepJ3Y-vwXiIgl9nij0,79702
65
+ boris/project.py,sha256=nyXfCDY_rLP3jC1QGv-280jUKgbABqESjOm7I19rJ1U,86432
66
+ boris/project_functions.py,sha256=eP-YEjoFvZXEPuzNPBeXsRDYurt0wHP6B09a8k8SlDc,80792
67
67
  boris/project_import_export.py,sha256=oBG1CSXfKISsb3TLNT-8BH8kZPAzxIYSNemlLVH1Lh8,38560
68
68
  boris/project_ui.py,sha256=yB-ewhHt8S8DTTRIk-dNK2tPMNU24lNji9fDW_Xazu8,38805
69
69
  boris/qrc_boris.py,sha256=aH-qUirYY1CGxmTK1SFCPvuZfazIHX4DdUKF1gxZeYM,675008
@@ -77,8 +77,8 @@ boris/synthetic_time_budget.py,sha256=3Eb9onMLmgqCLd50CuxV9L8RV2ESzfaMWvPK_bXUMM
77
77
  boris/time_budget_functions.py,sha256=y5He8crz0xsTxVfz0jATwFFQVnPAIrNHja_0sF6NtRE,52551
78
78
  boris/time_budget_widget.py,sha256=z-tyITBtIz-KH1H2OdMB5a8x9QQLK7Wu96-zkC6NVDA,43213
79
79
  boris/transitions.py,sha256=_aZJfJWv3EBrtmQ7qsdTCayQo6uWU7BXqtQQgflEhr4,12250
80
- boris/utilities.py,sha256=7iZ6XQ8G1by9j-xVjTCBX6dp9FQg_9MbC5Ym1sZJYp0,52639
81
- boris/version.py,sha256=wqhoE3kKrpzgOgOUWT2QNHWqh24C1Kp05JOwqZKmU8k,787
80
+ boris/utilities.py,sha256=4b3BjO96eR54sPXIYkHwxkUnROGgY5f5vhWKIy8THUo,52646
81
+ boris/version.py,sha256=st-9YZePMhFx60fiF0uKR_IhGjVv4ik2D_Td5O2XQr0,787
82
82
  boris/video_equalizer.py,sha256=FartoGghFK-T53zklP70rPKYqTuzL8qdvfGlsOF2wwc,5854
83
83
  boris/video_equalizer_ui.py,sha256=1CG3s79eM4JAbaCx3i1ILZXLceb41_gGXlOLNfpBgnw,10142
84
84
  boris/video_operations.py,sha256=mh3iR__Sm2KnV44L_sW2pOo3AgLwlM7wiTnnqQiAVs4,9381
@@ -96,9 +96,9 @@ boris/portion/dict.py,sha256=SyHxc7PfDw2ufNLFQycwJtzmRfL48rDp4UrM2KN7IWc,11282
96
96
  boris/portion/func.py,sha256=3TkQtFKLfsqntwd27HSGHceFhnXHmT-EbNMqktElC5Q,2174
97
97
  boris/portion/interval.py,sha256=bAdUiJjGeUAPgsBAImwNeviiwfQq5odfhFZccAWzOTA,20299
98
98
  boris/portion/io.py,sha256=ppNeRpiLNrocF1yzGeuEUIhYMf2LfsR-cji3d0nmvUs,6371
99
- boris_behav_obs-9.3.3.dist-info/licenses/LICENSE.TXT,sha256=WJ7YI-moTFb-uVrFjnzzhGJrnL9P2iqQe8NuED3hutI,35141
100
- boris_behav_obs-9.3.3.dist-info/METADATA,sha256=oiGWIVEJKIfM9EOznjvVeDr15l2rtecxzculq_IsJAg,4518
101
- boris_behav_obs-9.3.3.dist-info/WHEEL,sha256=oSJJyWjO7Z2XSScFQUpXG1HL-N0sFMqqeKVVbZTPkWc,109
102
- boris_behav_obs-9.3.3.dist-info/entry_points.txt,sha256=k__8XvFi4vaA4QFvQehCZjYkKmZH34HSAJI2iYCWrMs,52
103
- boris_behav_obs-9.3.3.dist-info/top_level.txt,sha256=fJSgm62S7WesiwTorGbOO4nNN0yzgZ3klgfGi3Px4qI,6
104
- boris_behav_obs-9.3.3.dist-info/RECORD,,
99
+ boris_behav_obs-9.3.4.dist-info/licenses/LICENSE.TXT,sha256=WJ7YI-moTFb-uVrFjnzzhGJrnL9P2iqQe8NuED3hutI,35141
100
+ boris_behav_obs-9.3.4.dist-info/METADATA,sha256=G03KB1bA9U-pdA0egf0dsvhkvRG2O3jQZudOyEdjfyA,4514
101
+ boris_behav_obs-9.3.4.dist-info/WHEEL,sha256=oSJJyWjO7Z2XSScFQUpXG1HL-N0sFMqqeKVVbZTPkWc,109
102
+ boris_behav_obs-9.3.4.dist-info/entry_points.txt,sha256=k__8XvFi4vaA4QFvQehCZjYkKmZH34HSAJI2iYCWrMs,52
103
+ boris_behav_obs-9.3.4.dist-info/top_level.txt,sha256=fJSgm62S7WesiwTorGbOO4nNN0yzgZ3klgfGi3Px4qI,6
104
+ boris_behav_obs-9.3.4.dist-info/RECORD,,