amine@269
|
1 import os
|
amine@267
|
2 from unittest import TestCase
|
amine@271
|
3 from unittest.mock import patch
|
amine@269
|
4 from tempfile import TemporaryDirectory
|
amine@267
|
5 from collections import namedtuple
|
amine@267
|
6 from genty import genty, genty_dataset
|
amine@267
|
7
|
amine@267
|
8 from auditok.cmdline_util import (
|
amine@273
|
9 _AUDITOK_LOGGER,
|
amine@267
|
10 make_kwargs,
|
amine@291
|
11 make_duration_formatter,
|
amine@267
|
12 make_logger,
|
amine@267
|
13 initialize_workers,
|
amine@267
|
14 KeywordArguments,
|
amine@267
|
15 )
|
amine@271
|
16 from auditok.workers import (
|
amine@271
|
17 StreamSaverWorker,
|
amine@271
|
18 RegionSaverWorker,
|
amine@271
|
19 PlayerWorker,
|
amine@271
|
20 CommandLineWorker,
|
amine@271
|
21 PrintWorker,
|
amine@271
|
22 )
|
amine@267
|
23 from auditok.exceptions import TimeFormatError
|
amine@267
|
24
|
amine@267
|
25 _ArgsNamespece = namedtuple(
|
amine@267
|
26 "_ArgsNamespece",
|
amine@267
|
27 [
|
amine@267
|
28 "input",
|
amine@267
|
29 "max_time",
|
amine@267
|
30 "analysis_window",
|
amine@267
|
31 "sampling_rate",
|
amine@267
|
32 "sample_width",
|
amine@267
|
33 "channels",
|
amine@267
|
34 "use_channel",
|
amine@267
|
35 "input_format",
|
amine@267
|
36 "output_format",
|
amine@267
|
37 "large_file",
|
amine@267
|
38 "frame_per_buffer",
|
amine@267
|
39 "input_device_index",
|
amine@267
|
40 "save_stream",
|
amine@267
|
41 "plot",
|
amine@267
|
42 "save_image",
|
amine@267
|
43 "min_duration",
|
amine@267
|
44 "max_duration",
|
amine@267
|
45 "max_silence",
|
amine@267
|
46 "drop_trailing_silence",
|
amine@267
|
47 "strict_min_duration",
|
amine@267
|
48 "energy_threshold",
|
amine@267
|
49 "echo",
|
amine@267
|
50 "command",
|
amine@267
|
51 "quiet",
|
amine@267
|
52 "printf",
|
amine@267
|
53 "time_format",
|
amine@267
|
54 "timestamp_format",
|
amine@267
|
55 ],
|
amine@267
|
56 )
|
amine@267
|
57
|
amine@267
|
58
|
amine@267
|
59 @genty
|
amine@268
|
60 class _TestCmdLineUtil(TestCase):
|
amine@267
|
61 @genty_dataset(
|
amine@267
|
62 no_record=("stream.ogg", False, None, "mix", "mix", False),
|
amine@267
|
63 no_record_plot=("stream.ogg", True, None, None, None, False),
|
amine@267
|
64 no_record_save_image=(
|
amine@267
|
65 "stream.ogg",
|
amine@267
|
66 True,
|
amine@267
|
67 "image.png",
|
amine@267
|
68 None,
|
amine@267
|
69 None,
|
amine@267
|
70 False,
|
amine@267
|
71 ),
|
amine@267
|
72 record_plot=(None, True, None, None, None, True),
|
amine@267
|
73 record_save_image=(None, False, "image.png", None, None, True),
|
amine@267
|
74 int_use_channel=("stream.ogg", False, None, "1", 1, False),
|
amine@267
|
75 )
|
amine@267
|
76 def test_make_kwargs(
|
amine@267
|
77 self,
|
amine@267
|
78 save_stream,
|
amine@267
|
79 plot,
|
amine@267
|
80 save_image,
|
amine@267
|
81 use_channel,
|
amine@267
|
82 exp_use_channel,
|
amine@267
|
83 exp_record,
|
amine@267
|
84 ):
|
amine@267
|
85
|
amine@267
|
86 args = (
|
amine@267
|
87 "file",
|
amine@267
|
88 30,
|
amine@267
|
89 0.01,
|
amine@267
|
90 16000,
|
amine@267
|
91 2,
|
amine@267
|
92 2,
|
amine@267
|
93 use_channel,
|
amine@267
|
94 "raw",
|
amine@267
|
95 "ogg",
|
amine@267
|
96 True,
|
amine@267
|
97 None,
|
amine@267
|
98 1,
|
amine@267
|
99 save_stream,
|
amine@267
|
100 plot,
|
amine@267
|
101 save_image,
|
amine@267
|
102 0.2,
|
amine@267
|
103 10,
|
amine@267
|
104 0.3,
|
amine@267
|
105 False,
|
amine@267
|
106 False,
|
amine@267
|
107 55,
|
amine@267
|
108 )
|
amine@267
|
109 misc = (False, None, True, None, "TIME_FORMAT", "TIMESTAMP_FORMAT")
|
amine@267
|
110
|
amine@267
|
111 args_ns = _ArgsNamespece(*(args + misc))
|
amine@267
|
112
|
amine@267
|
113 io_kwargs = {
|
amine@267
|
114 "input": "file",
|
amine@267
|
115 "max_read": 30,
|
amine@267
|
116 "block_dur": 0.01,
|
amine@267
|
117 "sampling_rate": 16000,
|
amine@267
|
118 "sample_width": 2,
|
amine@267
|
119 "channels": 2,
|
amine@267
|
120 "use_channel": exp_use_channel,
|
amine@267
|
121 "save_stream": save_stream,
|
amine@267
|
122 "audio_format": "raw",
|
amine@267
|
123 "export_format": "ogg",
|
amine@267
|
124 "large_file": True,
|
amine@267
|
125 "frames_per_buffer": None,
|
amine@267
|
126 "input_device_index": 1,
|
amine@267
|
127 "record": exp_record,
|
amine@267
|
128 }
|
amine@267
|
129
|
amine@267
|
130 split_kwargs = {
|
amine@267
|
131 "min_dur": 0.2,
|
amine@267
|
132 "max_dur": 10,
|
amine@267
|
133 "max_silence": 0.3,
|
amine@267
|
134 "drop_trailing_silence": False,
|
amine@267
|
135 "strict_min_dur": False,
|
amine@267
|
136 "energy_threshold": 55,
|
amine@267
|
137 }
|
amine@267
|
138
|
amine@267
|
139 miscellaneous = {
|
amine@267
|
140 "echo": False,
|
amine@267
|
141 "command": None,
|
amine@267
|
142 "quiet": True,
|
amine@267
|
143 "printf": None,
|
amine@267
|
144 "time_format": "TIME_FORMAT",
|
amine@267
|
145 "timestamp_format": "TIMESTAMP_FORMAT",
|
amine@267
|
146 }
|
amine@267
|
147
|
amine@267
|
148 expected = KeywordArguments(io_kwargs, split_kwargs, miscellaneous)
|
amine@267
|
149 kwargs = make_kwargs(args_ns)
|
amine@267
|
150 self.assertEqual(kwargs, expected)
|
amine@268
|
151
|
amine@268
|
152 @genty_dataset(
|
amine@268
|
153 only_seconds=("%S", 5400, "5400.000"),
|
amine@268
|
154 only_millis=("%I", 5400, "5400000"),
|
amine@268
|
155 full=("%h:%m:%s.%i", 3725.365, "01:02:05.365"),
|
amine@268
|
156 full_zero_hours=("%h:%m:%s.%i", 1925.075, "00:32:05.075"),
|
amine@268
|
157 full_zero_minutes=("%h:%m:%s.%i", 3659.075, "01:00:59.075"),
|
amine@268
|
158 full_zero_seconds=("%h:%m:%s.%i", 3720.075, "01:02:00.075"),
|
amine@268
|
159 full_zero_millis=("%h:%m:%s.%i", 3725, "01:02:05.000"),
|
amine@268
|
160 duplicate_directive=(
|
amine@268
|
161 "%h %h:%m:%s.%i %s",
|
amine@268
|
162 3725.365,
|
amine@268
|
163 "01 01:02:05.365 05",
|
amine@268
|
164 ),
|
amine@268
|
165 no_millis=("%h:%m:%s", 3725, "01:02:05"),
|
amine@268
|
166 no_seconds=("%h:%m", 3725, "01:02"),
|
amine@268
|
167 no_minutes=("%h", 3725, "01"),
|
amine@268
|
168 no_hours=("%m:%s.%i", 3725, "02:05.000"),
|
amine@268
|
169 )
|
amine@291
|
170 def test_make_duration_formatter(self, fmt, duration, expected):
|
amine@291
|
171 formatter = make_duration_formatter(fmt)
|
amine@268
|
172 result = formatter(duration)
|
amine@268
|
173 self.assertEqual(result, expected)
|
amine@268
|
174
|
amine@268
|
175 @genty_dataset(
|
amine@268
|
176 duplicate_only_seconds=("%S %S",),
|
amine@268
|
177 duplicate_only_millis=("%I %I",),
|
amine@268
|
178 unknown_directive=("%x",),
|
amine@268
|
179 )
|
amine@291
|
180 def test_make_duration_formatter_error(self, fmt):
|
amine@268
|
181 with self.assertRaises(TimeFormatError):
|
amine@291
|
182 make_duration_formatter(fmt)
|
amine@269
|
183
|
amine@273
|
184 def test_make_logger_stderr_and_file(self):
|
amine@269
|
185 with TemporaryDirectory() as tmpdir:
|
amine@269
|
186 file = os.path.join(tmpdir, "file.log")
|
amine@273
|
187 logger = make_logger(stderr=True, file=file)
|
amine@273
|
188 self.assertEqual(logger.name, _AUDITOK_LOGGER)
|
amine@269
|
189 self.assertEqual(len(logger.handlers), 2)
|
amine@273
|
190 self.assertEqual(logger.handlers[0].stream.name, "<stderr>")
|
amine@269
|
191 self.assertEqual(logger.handlers[1].stream.name, file)
|
amine@269
|
192
|
amine@269
|
193 def test_make_logger_None(self):
|
amine@273
|
194 logger = make_logger(stderr=False, file=None)
|
amine@269
|
195 self.assertIsNone(logger)
|
amine@271
|
196
|
amine@271
|
197 def test_initialize_workers_all(self):
|
amine@271
|
198 with patch("auditok.cmdline_util.player_for") as patched_player_for:
|
amine@285
|
199 with TemporaryDirectory() as tmpdir:
|
amine@285
|
200 export_filename = os.path.join(tmpdir, "output.wav")
|
amine@285
|
201 reader, observers = initialize_workers(
|
amine@285
|
202 input="tests/data/test_16KHZ_mono_400Hz.wav",
|
amine@285
|
203 save_stream=export_filename,
|
amine@285
|
204 export_format="wave",
|
amine@285
|
205 save_detections_as="{id}.wav",
|
amine@285
|
206 echo=True,
|
amine@285
|
207 progress_bar=False,
|
amine@285
|
208 command="some command",
|
amine@285
|
209 quiet=False,
|
amine@285
|
210 printf="abcd",
|
amine@285
|
211 time_format="%S",
|
amine@285
|
212 timestamp_format="%h:%M:%S",
|
amine@285
|
213 )
|
amine@285
|
214 reader.stop()
|
amine@285
|
215 self.assertTrue(patched_player_for.called)
|
amine@285
|
216 self.assertIsInstance(reader, StreamSaverWorker)
|
amine@285
|
217 for obs, cls in zip(
|
amine@285
|
218 observers,
|
amine@285
|
219 [
|
amine@285
|
220 RegionSaverWorker,
|
amine@285
|
221 PlayerWorker,
|
amine@285
|
222 CommandLineWorker,
|
amine@285
|
223 PrintWorker,
|
amine@285
|
224 ],
|
amine@285
|
225 ):
|
amine@285
|
226 self.assertIsInstance(obs, cls)
|
amine@271
|
227
|
amine@271
|
228 def test_initialize_workers_no_RegionSaverWorker(self):
|
amine@271
|
229 with patch("auditok.cmdline_util.player_for") as patched_player_for:
|
amine@285
|
230 with TemporaryDirectory() as tmpdir:
|
amine@285
|
231 export_filename = os.path.join(tmpdir, "output.wav")
|
amine@285
|
232 reader, observers = initialize_workers(
|
amine@285
|
233 input="tests/data/test_16KHZ_mono_400Hz.wav",
|
amine@285
|
234 save_stream=export_filename,
|
amine@285
|
235 export_format="wave",
|
amine@285
|
236 save_detections_as=None,
|
amine@285
|
237 echo=True,
|
amine@285
|
238 progress_bar=False,
|
amine@285
|
239 command="some command",
|
amine@285
|
240 quiet=False,
|
amine@285
|
241 printf="abcd",
|
amine@285
|
242 time_format="%S",
|
amine@285
|
243 timestamp_format="%h:%M:%S",
|
amine@285
|
244 )
|
amine@285
|
245 reader.stop()
|
amine@285
|
246 self.assertTrue(patched_player_for.called)
|
amine@285
|
247 self.assertIsInstance(reader, StreamSaverWorker)
|
amine@285
|
248 for obs, cls in zip(
|
amine@285
|
249 observers, [PlayerWorker, CommandLineWorker, PrintWorker]
|
amine@285
|
250 ):
|
amine@285
|
251 self.assertIsInstance(obs, cls)
|
amine@271
|
252
|
amine@271
|
253 def test_initialize_workers_no_PlayerWorker(self):
|
amine@271
|
254 with patch("auditok.cmdline_util.player_for") as patched_player_for:
|
amine@285
|
255 with TemporaryDirectory() as tmpdir:
|
amine@285
|
256 export_filename = os.path.join(tmpdir, "output.wav")
|
amine@285
|
257 reader, observers = initialize_workers(
|
amine@285
|
258 input="tests/data/test_16KHZ_mono_400Hz.wav",
|
amine@285
|
259 save_stream=export_filename,
|
amine@285
|
260 export_format="wave",
|
amine@285
|
261 save_detections_as="{id}.wav",
|
amine@285
|
262 echo=False,
|
amine@285
|
263 progress_bar=False,
|
amine@285
|
264 command="some command",
|
amine@285
|
265 quiet=False,
|
amine@285
|
266 printf="abcd",
|
amine@285
|
267 time_format="%S",
|
amine@285
|
268 timestamp_format="%h:%M:%S",
|
amine@285
|
269 )
|
amine@285
|
270 reader.stop()
|
amine@285
|
271 self.assertFalse(patched_player_for.called)
|
amine@285
|
272 self.assertIsInstance(reader, StreamSaverWorker)
|
amine@285
|
273 for obs, cls in zip(
|
amine@285
|
274 observers,
|
amine@285
|
275 [RegionSaverWorker, CommandLineWorker, PrintWorker],
|
amine@285
|
276 ):
|
amine@285
|
277 self.assertIsInstance(obs, cls)
|
amine@271
|
278
|
amine@271
|
279 def test_initialize_workers_no_CommandLineWorker(self):
|
amine@271
|
280 with patch("auditok.cmdline_util.player_for") as patched_player_for:
|
amine@285
|
281 with TemporaryDirectory() as tmpdir:
|
amine@285
|
282 export_filename = os.path.join(tmpdir, "output.wav")
|
amine@285
|
283 reader, observers = initialize_workers(
|
amine@285
|
284 input="tests/data/test_16KHZ_mono_400Hz.wav",
|
amine@285
|
285 save_stream=export_filename,
|
amine@285
|
286 export_format="wave",
|
amine@285
|
287 save_detections_as="{id}.wav",
|
amine@285
|
288 echo=True,
|
amine@285
|
289 progress_bar=False,
|
amine@285
|
290 command=None,
|
amine@285
|
291 quiet=False,
|
amine@285
|
292 printf="abcd",
|
amine@285
|
293 time_format="%S",
|
amine@285
|
294 timestamp_format="%h:%M:%S",
|
amine@285
|
295 )
|
amine@285
|
296 reader.stop()
|
amine@285
|
297 self.assertTrue(patched_player_for.called)
|
amine@285
|
298 self.assertIsInstance(reader, StreamSaverWorker)
|
amine@285
|
299 for obs, cls in zip(
|
amine@285
|
300 observers, [RegionSaverWorker, PlayerWorker, PrintWorker]
|
amine@285
|
301 ):
|
amine@285
|
302 self.assertIsInstance(obs, cls)
|
amine@271
|
303
|
amine@271
|
304 def test_initialize_workers_no_PrintWorker(self):
|
amine@271
|
305 with patch("auditok.cmdline_util.player_for") as patched_player_for:
|
amine@285
|
306 with TemporaryDirectory() as tmpdir:
|
amine@285
|
307 export_filename = os.path.join(tmpdir, "output.wav")
|
amine@285
|
308 reader, observers = initialize_workers(
|
amine@285
|
309 input="tests/data/test_16KHZ_mono_400Hz.wav",
|
amine@285
|
310 save_stream=export_filename,
|
amine@285
|
311 export_format="wave",
|
amine@285
|
312 save_detections_as="{id}.wav",
|
amine@285
|
313 echo=True,
|
amine@285
|
314 progress_bar=False,
|
amine@285
|
315 command="some command",
|
amine@285
|
316 quiet=True,
|
amine@285
|
317 printf="abcd",
|
amine@285
|
318 time_format="%S",
|
amine@285
|
319 timestamp_format="%h:%M:%S",
|
amine@285
|
320 )
|
amine@285
|
321 reader.stop()
|
amine@285
|
322 self.assertTrue(patched_player_for.called)
|
amine@285
|
323 self.assertIsInstance(reader, StreamSaverWorker)
|
amine@285
|
324 for obs, cls in zip(
|
amine@285
|
325 observers,
|
amine@285
|
326 [RegionSaverWorker, PlayerWorker, CommandLineWorker],
|
amine@285
|
327 ):
|
amine@285
|
328 self.assertIsInstance(obs, cls)
|
amine@271
|
329
|
amine@271
|
330 def test_initialize_workers_no_observers(self):
|
amine@271
|
331 with patch("auditok.cmdline_util.player_for") as patched_player_for:
|
amine@271
|
332 reader, observers = initialize_workers(
|
amine@271
|
333 input="tests/data/test_16KHZ_mono_400Hz.wav",
|
amine@271
|
334 save_stream=None,
|
amine@271
|
335 export_format="wave",
|
amine@271
|
336 save_detections_as=None,
|
amine@271
|
337 echo=True,
|
amine@271
|
338 progress_bar=False,
|
amine@271
|
339 command=None,
|
amine@271
|
340 quiet=True,
|
amine@271
|
341 printf="abcd",
|
amine@271
|
342 time_format="%S",
|
amine@271
|
343 timestamp_format="%h:%M:%S",
|
amine@271
|
344 )
|
amine@271
|
345 self.assertTrue(patched_player_for.called)
|
amine@271
|
346 self.assertFalse(isinstance(reader, StreamSaverWorker))
|
amine@271
|
347 self.assertTrue(len(observers), 0)
|