boris-behav-obs 8.16.6__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.
- boris/__init__.py +1 -1
- boris/__main__.py +1 -1
- boris/about.py +24 -40
- boris/add_modifier.py +88 -80
- boris/add_modifier_ui.py +235 -131
- boris/advanced_event_filtering.py +23 -29
- boris/analysis_plugins/__init__.py +0 -0
- boris/analysis_plugins/_latency.py +59 -0
- boris/analysis_plugins/irr_cohen_kappa.py +109 -0
- boris/analysis_plugins/irr_cohen_kappa_with_modifiers.py +112 -0
- boris/analysis_plugins/irr_weighted_cohen_kappa.py +157 -0
- boris/analysis_plugins/irr_weighted_cohen_kappa_with_modifiers.py +162 -0
- boris/analysis_plugins/list_of_dataframe_columns.py +22 -0
- boris/analysis_plugins/number_of_occurences.py +22 -0
- boris/analysis_plugins/number_of_occurences_by_independent_variable.py +54 -0
- boris/analysis_plugins/time_budget.py +61 -0
- boris/behav_coding_map_creator.py +228 -229
- boris/behavior_binary_table.py +33 -50
- boris/behaviors_coding_map.py +17 -18
- boris/boris_cli.py +6 -25
- boris/cmd_arguments.py +12 -1
- boris/coding_pad.py +16 -34
- boris/config.py +101 -49
- boris/config_file.py +55 -64
- boris/connections.py +105 -58
- boris/converters.py +13 -37
- boris/converters_ui.py +187 -110
- boris/cooccurence.py +250 -0
- boris/core.py +2108 -1275
- boris/core_qrc.py +15892 -10829
- boris/core_ui.py +941 -806
- boris/db_functions.py +17 -42
- boris/dev.py +134 -0
- boris/dialog.py +461 -242
- boris/duration_widget.py +9 -14
- boris/edit_event.py +61 -31
- boris/edit_event_ui.py +208 -97
- boris/event_operations.py +405 -281
- boris/events_cursor.py +25 -17
- boris/events_snapshots.py +36 -82
- boris/exclusion_matrix.py +4 -9
- boris/export_events.py +180 -203
- boris/export_observation.py +60 -73
- boris/external_processes.py +123 -98
- boris/geometric_measurement.py +427 -218
- boris/gui_utilities.py +91 -14
- boris/image_overlay.py +4 -4
- boris/import_observations.py +190 -98
- boris/ipc_mpv.py +304 -0
- boris/irr.py +20 -57
- boris/latency.py +31 -24
- boris/measurement_widget.py +14 -18
- boris/media_file.py +17 -19
- boris/menu_options.py +16 -6
- boris/modifier_coding_map_creator.py +1013 -0
- boris/modifiers_coding_map.py +7 -9
- boris/mpv2.py +127 -36
- boris/observation.py +493 -210
- boris/observation_operations.py +1010 -391
- boris/observation_ui.py +573 -363
- boris/observations_list.py +51 -58
- boris/otx_parser.py +74 -68
- boris/param_panel.py +45 -59
- boris/param_panel_ui.py +254 -138
- boris/player_dock_widget.py +91 -56
- boris/plot_data_module.py +18 -53
- boris/plot_events.py +56 -153
- boris/plot_events_rt.py +16 -30
- boris/plot_spectrogram_rt.py +80 -56
- boris/plot_waveform_rt.py +23 -48
- boris/plugins.py +431 -0
- boris/portion/__init__.py +18 -8
- boris/portion/const.py +35 -18
- boris/portion/dict.py +5 -5
- boris/portion/func.py +2 -2
- boris/portion/interval.py +21 -41
- boris/portion/io.py +41 -32
- boris/preferences.py +298 -123
- boris/preferences_ui.py +664 -225
- boris/project.py +293 -270
- boris/project_functions.py +610 -537
- boris/project_import_export.py +204 -213
- boris/project_ui.py +673 -441
- boris/qrc_boris.py +6 -3
- boris/qrc_boris5.py +6 -3
- boris/select_modifiers.py +62 -90
- boris/select_observations.py +19 -197
- boris/select_subj_behav.py +67 -39
- boris/state_events.py +51 -33
- boris/subjects_pad.py +6 -8
- boris/synthetic_time_budget.py +25 -17
- boris/time_budget_functions.py +169 -169
- boris/time_budget_widget.py +71 -86
- boris/transitions.py +41 -41
- boris/utilities.py +562 -222
- boris/version.py +3 -3
- boris/video_equalizer.py +16 -14
- boris/video_equalizer_ui.py +199 -130
- boris/video_operations.py +78 -28
- boris/view_df.py +104 -0
- boris/view_df_ui.py +75 -0
- boris/write_event.py +240 -136
- boris_behav_obs-9.7.1.dist-info/METADATA +140 -0
- boris_behav_obs-9.7.1.dist-info/RECORD +109 -0
- {boris_behav_obs-8.16.6.dist-info → boris_behav_obs-9.7.1.dist-info}/WHEEL +1 -1
- boris_behav_obs-9.7.1.dist-info/entry_points.txt +2 -0
- boris/README.TXT +0 -22
- boris/add_modifier.ui +0 -323
- boris/converters.ui +0 -289
- boris/core.qrc +0 -37
- boris/core.ui +0 -1571
- boris/edit_event.ui +0 -233
- boris/icons/logo_eye.ico +0 -0
- boris/map_creator.py +0 -982
- boris/observation.ui +0 -814
- boris/param_panel.ui +0 -379
- boris/preferences.ui +0 -537
- boris/project.ui +0 -1074
- boris/vlc_local.py +0 -90
- boris_behav_obs-8.16.6.dist-info/LICENSE.TXT +0 -674
- boris_behav_obs-8.16.6.dist-info/METADATA +0 -134
- boris_behav_obs-8.16.6.dist-info/RECORD +0 -106
- boris_behav_obs-8.16.6.dist-info/entry_points.txt +0 -2
- {boris → boris_behav_obs-9.7.1.dist-info/licenses}/LICENSE.TXT +0 -0
- {boris_behav_obs-8.16.6.dist-info → boris_behav_obs-9.7.1.dist-info}/top_level.txt +0 -0
boris/external_processes.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
BORIS
|
|
3
3
|
Behavioral Observation Research Interactive Software
|
|
4
|
-
Copyright 2012-
|
|
4
|
+
Copyright 2012-2025 Olivier Friard
|
|
5
5
|
|
|
6
6
|
This file is part of BORIS.
|
|
7
7
|
|
|
@@ -20,13 +20,13 @@ This file is part of BORIS.
|
|
|
20
20
|
|
|
21
21
|
"""
|
|
22
22
|
|
|
23
|
-
|
|
24
23
|
import os
|
|
25
24
|
import tempfile
|
|
26
|
-
|
|
25
|
+
from pathlib import Path
|
|
26
|
+
import logging
|
|
27
27
|
|
|
28
|
-
from
|
|
29
|
-
from
|
|
28
|
+
from PySide6.QtWidgets import QFileDialog, QMessageBox, QInputDialog
|
|
29
|
+
from PySide6.QtCore import (
|
|
30
30
|
Qt,
|
|
31
31
|
QProcess,
|
|
32
32
|
)
|
|
@@ -41,9 +41,9 @@ def ffmpeg_process(self, action: str):
|
|
|
41
41
|
launch ffmpeg process with QProcess
|
|
42
42
|
|
|
43
43
|
Args:
|
|
44
|
-
action (str): "reencode_resize, rotate, merge
|
|
44
|
+
action (str): "reencode_resize, rotate, merge, video_spectrogram
|
|
45
45
|
"""
|
|
46
|
-
if action not in ("reencode_resize", "rotate", "merge"):
|
|
46
|
+
if action not in ("reencode_resize", "rotate", "merge", "video_spectrogram"):
|
|
47
47
|
return
|
|
48
48
|
|
|
49
49
|
def readStdOutput(idx):
|
|
@@ -61,7 +61,7 @@ def ffmpeg_process(self, action: str):
|
|
|
61
61
|
# self.processes_widget.lwi.clear()
|
|
62
62
|
std_out = self.processes[idx - 1][0].readAllStandardOutput().data().decode("utf-8")
|
|
63
63
|
if std_out:
|
|
64
|
-
self.processes_widget.lwi.addItems((f"{
|
|
64
|
+
self.processes_widget.lwi.addItems((f"{Path(self.processes[idx - 1][1][2]).name}: {std_out}",))
|
|
65
65
|
|
|
66
66
|
"""
|
|
67
67
|
std_err = self.processes[idx - 1][0].readAllStandardError().data().decode("utf-8")
|
|
@@ -83,9 +83,7 @@ def ffmpeg_process(self, action: str):
|
|
|
83
83
|
self.processes[-1][0].start(self.processes[-1][1][0], self.processes[-1][1][1])
|
|
84
84
|
else:
|
|
85
85
|
self.processes_widget.label.setText(
|
|
86
|
-
(
|
|
87
|
-
f"Done: {self.processes_widget.number_of_files - len(self.processes)} of {self.processes_widget.number_of_files}"
|
|
88
|
-
)
|
|
86
|
+
(f"Done: {self.processes_widget.number_of_files - len(self.processes)} of {self.processes_widget.number_of_files}")
|
|
89
87
|
)
|
|
90
88
|
"""
|
|
91
89
|
self.processes_widget.hide()
|
|
@@ -102,36 +100,37 @@ def ffmpeg_process(self, action: str):
|
|
|
102
100
|
else:
|
|
103
101
|
msg = f"Select one or more video files to {action.replace('_', ' and ')}"
|
|
104
102
|
file_type = "Video files (*)"
|
|
105
|
-
|
|
106
|
-
fileNames = fn[0] if type(fn) is tuple else fn
|
|
103
|
+
file_names, _ = QFileDialog().getOpenFileNames(self, msg, "", file_type)
|
|
107
104
|
|
|
108
|
-
if not
|
|
105
|
+
if not file_names:
|
|
109
106
|
return
|
|
110
107
|
|
|
111
108
|
if action == "reencode_resize":
|
|
112
|
-
current_bitrate =
|
|
109
|
+
current_bitrate = 10_000_000 # default 10 Mb/s
|
|
113
110
|
current_resolution = 1024
|
|
114
111
|
|
|
115
|
-
r = util.accurate_media_analysis(self.ffmpeg_bin,
|
|
112
|
+
r = util.accurate_media_analysis(self.ffmpeg_bin, file_names[0])
|
|
116
113
|
if "error" in r:
|
|
117
|
-
QMessageBox.warning(self, cfg.programName, f"{
|
|
114
|
+
QMessageBox.warning(self, cfg.programName, f"{file_names[0]}. {r['error']}")
|
|
118
115
|
elif r["has_video"]:
|
|
119
116
|
current_bitrate = r.get("bitrate", None)
|
|
120
117
|
if current_bitrate is None:
|
|
121
118
|
current_bitrate = -1
|
|
119
|
+
else:
|
|
120
|
+
current_bitrate = round(current_bitrate / 1024 / 1024) # Convert to Mb/s
|
|
122
121
|
current_resolution = int(r["resolution"].split("x")[0]) if r["resolution"] is not None else None
|
|
123
122
|
|
|
124
123
|
ib = dialog.Input_dialog(
|
|
125
124
|
"Set the parameters for re-encoding / resizing",
|
|
126
125
|
[
|
|
127
126
|
("sb", "Horizontal resolution (in pixel)", 352, 3840, 100, current_resolution),
|
|
128
|
-
("sb", "Video quality (bitrate)",
|
|
127
|
+
("sb", "Video quality (bitrate Mb/s)", 1, 1000, 1, current_bitrate),
|
|
129
128
|
],
|
|
130
129
|
)
|
|
131
130
|
if not ib.exec_():
|
|
132
131
|
return
|
|
133
132
|
|
|
134
|
-
if len(
|
|
133
|
+
if len(file_names) > 1:
|
|
135
134
|
if (
|
|
136
135
|
dialog.MessageDialog(
|
|
137
136
|
cfg.programName,
|
|
@@ -143,18 +142,18 @@ def ffmpeg_process(self, action: str):
|
|
|
143
142
|
return
|
|
144
143
|
|
|
145
144
|
horiz_resol = ib.elements["Horizontal resolution (in pixel)"].value()
|
|
146
|
-
video_quality = ib.elements["Video quality (bitrate)"].value()
|
|
145
|
+
video_quality = ib.elements["Video quality (bitrate Mb/s)"].value()
|
|
147
146
|
|
|
148
147
|
if action == "merge":
|
|
149
|
-
if len(
|
|
148
|
+
if len(file_names) == 1:
|
|
150
149
|
QMessageBox.critical(self, cfg.programName, "Select more than one file")
|
|
151
150
|
return
|
|
152
151
|
|
|
153
152
|
file_extensions = [] # check extension of 1st media file
|
|
154
153
|
file_list_lst = []
|
|
155
|
-
for file_name in
|
|
154
|
+
for file_name in file_names:
|
|
156
155
|
file_list_lst.append(f"file '{file_name}'")
|
|
157
|
-
file_extensions.append(
|
|
156
|
+
file_extensions.append(Path(file_name).suffix)
|
|
158
157
|
if len(set(file_extensions)) > 1:
|
|
159
158
|
QMessageBox.critical(self, cfg.programName, "All media files must have the same format")
|
|
160
159
|
return
|
|
@@ -163,11 +162,14 @@ def ffmpeg_process(self, action: str):
|
|
|
163
162
|
output_file_name, _ = QFileDialog().getSaveFileName(self, "Output file name", "", "*")
|
|
164
163
|
if output_file_name == "":
|
|
165
164
|
return
|
|
166
|
-
if
|
|
165
|
+
if Path(output_file_name).suffix != file_extensions[0]:
|
|
167
166
|
QMessageBox.warning(
|
|
168
167
|
self,
|
|
169
168
|
cfg.programName,
|
|
170
|
-
|
|
169
|
+
(
|
|
170
|
+
"The extension of output file must be the same than the extension of input files "
|
|
171
|
+
f"(<b>{file_extensions[0]}</b>).<br>You selected a {Path(output_file_name).suffix} file."
|
|
172
|
+
),
|
|
171
173
|
)
|
|
172
174
|
else:
|
|
173
175
|
break
|
|
@@ -190,10 +192,9 @@ def ffmpeg_process(self, action: str):
|
|
|
190
192
|
# check if processed files already exist
|
|
191
193
|
if action in ("reencode_resize", "rotate"):
|
|
192
194
|
files_list = []
|
|
193
|
-
for file_name in
|
|
194
|
-
|
|
195
|
+
for file_name in file_names:
|
|
195
196
|
if action == "reencode_resize":
|
|
196
|
-
fn = f"{file_name}.re-encoded.{horiz_resol}px.{video_quality}
|
|
197
|
+
fn = f"{file_name}.re-encoded.{horiz_resol}px.{video_quality}Mb.avi"
|
|
197
198
|
|
|
198
199
|
if action == "rotate":
|
|
199
200
|
fn = f"{file_name}.rotated{['', '90', '-90', '180'][rotation_idx]}.avi"
|
|
@@ -214,94 +215,118 @@ def ffmpeg_process(self, action: str):
|
|
|
214
215
|
self.processes_widget.resize(700, 300)
|
|
215
216
|
|
|
216
217
|
self.processes_widget.setWindowFlags(Qt.WindowStaysOnTopHint)
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
self.processes_widget.
|
|
218
|
+
match action:
|
|
219
|
+
case "reencode_resize":
|
|
220
|
+
self.processes_widget.setWindowTitle("Re-encoding and resizing with FFmpeg")
|
|
221
|
+
case "rotate":
|
|
222
|
+
self.processes_widget.setWindowTitle("Rotating the video with FFmpeg")
|
|
223
|
+
case "merge":
|
|
224
|
+
self.processes_widget.setWindowTitle("Merging media files")
|
|
225
|
+
case "video_spectrogram":
|
|
226
|
+
self.processes_widget.setWindowTitle("Creating a video spectrogram")
|
|
227
|
+
|
|
228
|
+
self.processes_widget.label.setText("This operation can be long. Be patient...\nIn the meanwhile you can continue to use BORIS\n\n")
|
|
229
|
+
self.processes_widget.number_of_files = len(file_names)
|
|
228
230
|
self.processes_widget.show()
|
|
229
231
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
self.processes[-1][0].start(self.processes[-1][1][0], self.processes[-1][1][1])
|
|
232
|
+
match action:
|
|
233
|
+
case "merge":
|
|
234
|
+
# ffmpeg -f concat -safe 0 -i join_video.txt -c copy output.mp4
|
|
235
|
+
args = ["-hide_banner", "-y", "-f", "concat", "-safe", "0", "-i", file_list, "-c", "copy", output_file_name]
|
|
236
|
+
self.processes.append([QProcess(self), [self.ffmpeg_bin, args, output_file_name]])
|
|
237
|
+
self.processes[-1][0].setProcessChannelMode(QProcess.MergedChannels)
|
|
238
|
+
self.processes[-1][0].readyReadStandardOutput.connect(lambda: readStdOutput(len(self.processes)))
|
|
239
|
+
self.processes[-1][0].readyReadStandardError.connect(lambda: readStdOutput(len(self.processes)))
|
|
240
|
+
self.processes[-1][0].finished.connect(lambda: qprocess_finished(len(self.processes)))
|
|
240
241
|
|
|
241
|
-
|
|
242
|
-
for file_name in sorted(fileNames, reverse=True):
|
|
242
|
+
self.processes[-1][0].start(self.processes[-1][1][0], self.processes[-1][1][1])
|
|
243
243
|
|
|
244
|
-
|
|
244
|
+
case "video_spectrogram":
|
|
245
|
+
# ffmpeg -i video.mp4 -filter_complex showspectrum=mode=combined:color=intensity:slide=1:scale=cbrt -y -acodec copy output.mp4
|
|
246
|
+
for file_name in sorted(file_names, reverse=True):
|
|
247
|
+
output_file_name = str(Path(file_name).with_suffix(f".spectrogram{Path(file_name).suffix}"))
|
|
245
248
|
args = [
|
|
246
249
|
"-hide_banner",
|
|
247
250
|
"-y",
|
|
248
251
|
"-i",
|
|
249
|
-
|
|
250
|
-
"-
|
|
251
|
-
|
|
252
|
-
"-
|
|
253
|
-
|
|
254
|
-
|
|
252
|
+
file_name,
|
|
253
|
+
"-filter_complex",
|
|
254
|
+
"showspectrum=mode=combined:color=intensity:slide=1:scale=cbrt",
|
|
255
|
+
"-acodec",
|
|
256
|
+
"copy",
|
|
257
|
+
output_file_name,
|
|
255
258
|
]
|
|
259
|
+
self.processes.append([QProcess(self), [self.ffmpeg_bin, args, output_file_name]])
|
|
260
|
+
self.processes[-1][0].setProcessChannelMode(QProcess.MergedChannels)
|
|
261
|
+
self.processes[-1][0].readyReadStandardOutput.connect(lambda: readStdOutput(len(self.processes)))
|
|
262
|
+
self.processes[-1][0].readyReadStandardError.connect(lambda: readStdOutput(len(self.processes)))
|
|
263
|
+
self.processes[-1][0].finished.connect(lambda: qprocess_finished(len(self.processes)))
|
|
256
264
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
# check bitrate
|
|
260
|
-
r = util.accurate_media_analysis(self.ffmpeg_bin, file_name)
|
|
261
|
-
if "error" not in r and r["bitrate"] is not None:
|
|
262
|
-
video_quality = r["bitrate"]
|
|
263
|
-
else:
|
|
264
|
-
video_quality = 200_000
|
|
265
|
+
self.processes[-1][0].start(self.processes[-1][1][0], self.processes[-1][1][1])
|
|
265
266
|
|
|
266
|
-
|
|
267
|
+
case "reencode_resize" | "rotate":
|
|
268
|
+
for file_name in sorted(file_names, reverse=True):
|
|
269
|
+
if action == "reencode_resize":
|
|
267
270
|
args = [
|
|
268
271
|
"-hide_banner",
|
|
269
272
|
"-y",
|
|
270
273
|
"-i",
|
|
271
274
|
f"{file_name}",
|
|
272
275
|
"-vf",
|
|
273
|
-
f"
|
|
274
|
-
"-codec:a",
|
|
275
|
-
"copy",
|
|
276
|
+
f"scale={horiz_resol}:-1",
|
|
276
277
|
"-b:v",
|
|
277
|
-
f"{video_quality}",
|
|
278
|
-
f"{file_name}.
|
|
278
|
+
f"{video_quality * 1024 * 1024}",
|
|
279
|
+
f"{file_name}.re-encoded.{horiz_resol}px.{video_quality}Mb.avi",
|
|
279
280
|
]
|
|
280
281
|
|
|
281
|
-
if
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
"
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
282
|
+
if action == "rotate":
|
|
283
|
+
# check bitrate
|
|
284
|
+
r = util.accurate_media_analysis(self.ffmpeg_bin, file_name)
|
|
285
|
+
if "error" not in r and r["bitrate"] is not None:
|
|
286
|
+
current_bitrate = r["bitrate"]
|
|
287
|
+
else:
|
|
288
|
+
current_bitrate = 10_000_000
|
|
289
|
+
|
|
290
|
+
if rotation_idx in (1, 2):
|
|
291
|
+
args = [
|
|
292
|
+
"-hide_banner",
|
|
293
|
+
"-y",
|
|
294
|
+
"-i",
|
|
295
|
+
f"{file_name}",
|
|
296
|
+
"-vf",
|
|
297
|
+
f"transpose={rotation_idx}",
|
|
298
|
+
"-codec:a",
|
|
299
|
+
"copy",
|
|
300
|
+
"-b:v",
|
|
301
|
+
f"{current_bitrate}",
|
|
302
|
+
f"{file_name}.rotated{['', '90', '-90'][rotation_idx]}.avi",
|
|
303
|
+
]
|
|
304
|
+
|
|
305
|
+
if rotation_idx == 3: # 180
|
|
306
|
+
args = [
|
|
307
|
+
"-hide_banner",
|
|
308
|
+
"-y",
|
|
309
|
+
"-i",
|
|
310
|
+
f"{file_name}",
|
|
311
|
+
"-vf",
|
|
312
|
+
"transpose=2,transpose=2",
|
|
313
|
+
"-codec:a",
|
|
314
|
+
"copy",
|
|
315
|
+
"-b:v",
|
|
316
|
+
f"{current_bitrate}",
|
|
317
|
+
f"{file_name}.rotated180.avi",
|
|
318
|
+
]
|
|
319
|
+
|
|
320
|
+
logging.debug("Launch process")
|
|
321
|
+
logging.debug(f"{self.ffmpeg_bin} {' '.join(args)}")
|
|
322
|
+
|
|
323
|
+
self.processes.append([QProcess(self), [self.ffmpeg_bin, args, file_name]])
|
|
324
|
+
|
|
325
|
+
## FFmpeg output the work in progress on stderr
|
|
326
|
+
self.processes[-1][0].setProcessChannelMode(QProcess.MergedChannels)
|
|
327
|
+
self.processes[-1][0].readyReadStandardOutput.connect(lambda: readStdOutput(len(self.processes)))
|
|
328
|
+
# self.processes[-1][0].readyReadStandardError.connect(lambda: readStdOutput(len(self.processes)))
|
|
329
|
+
|
|
330
|
+
self.processes[-1][0].finished.connect(lambda: qprocess_finished(len(self.processes)))
|
|
295
331
|
|
|
296
|
-
self.processes.
|
|
297
|
-
|
|
298
|
-
# self.processes[-1][0].setProcessChannelMode(QProcess.SeparateChannels)
|
|
299
|
-
|
|
300
|
-
## FFmpeg output the work in progress on stderr
|
|
301
|
-
self.processes[-1][0].setProcessChannelMode(QProcess.MergedChannels)
|
|
302
|
-
self.processes[-1][0].readyReadStandardOutput.connect(lambda: readStdOutput(len(self.processes)))
|
|
303
|
-
# self.processes[-1][0].readyReadStandardError.connect(lambda: readStdOutput(len(self.processes)))
|
|
304
|
-
|
|
305
|
-
self.processes[-1][0].finished.connect(lambda: qprocess_finished(len(self.processes)))
|
|
306
|
-
|
|
307
|
-
self.processes[-1][0].start(self.processes[-1][1][0], self.processes[-1][1][1])
|
|
332
|
+
self.processes[-1][0].start(self.processes[-1][1][0], self.processes[-1][1][1])
|