Skip to content

Commit 3dfa015

Browse files
hadwarerabittcjacoby
authored
Adding type hinting (#129)
Co-authored-by: Rachel Bittner <[email protected]> Co-authored-by: Christopher Jacoby <[email protected]>
1 parent 787de8d commit 3dfa015

File tree

6 files changed

+300
-143
lines changed

6 files changed

+300
-143
lines changed

.github/workflows/run-tests.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ jobs:
2626

2727
- name: Install dependencies
2828
run: |
29+
sudo apt-get update
2930
sudo apt-get install sox
3031
python -m pip install --upgrade pip
3132
python -m pip install flake8 pytest pytest-cov

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
license='BSD-3-Clause',
2626
install_requires=[
2727
'numpy >= 1.9.0',
28+
'typing-extensions >= 3.7.4.2 '
2829
],
2930
extras_require={
3031
'tests': [

sox/combine.py

Lines changed: 46 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,29 @@
77

88
from __future__ import print_function
99

10-
from . import file_info
10+
from pathlib import Path
11+
from typing import Union, Optional, List
12+
13+
from typing_extensions import Literal
14+
1115
from . import core
12-
from .log import logger
13-
from .core import ENCODING_VALS
14-
from .core import is_number
15-
from .core import sox
16-
from .core import play
16+
from . import file_info
17+
from .core import ENCODING_VALS, EncodingValue
1718
from .core import SoxError
1819
from .core import SoxiError
1920
from .core import VALID_FORMATS
20-
21+
from .core import is_number
22+
from .core import play
23+
from .core import sox
24+
from .log import logger
2125
from .transform import Transformer
2226

23-
2427
COMBINE_VALS = [
2528
'concatenate', 'merge', 'mix', 'mix-power', 'multiply'
2629
]
2730

31+
CombineType = Literal['concatenate', 'merge', 'mix', 'mix-power', 'multiply']
32+
2833

2934
class Combiner(Transformer):
3035
'''Audio file combiner.
@@ -38,8 +43,11 @@ class Combiner(Transformer):
3843
def __init__(self):
3944
super(Combiner, self).__init__()
4045

41-
def build(self, input_filepath_list, output_filepath, combine_type,
42-
input_volumes=None):
46+
def build(self,
47+
input_filepath_list: Union[str, Path],
48+
output_filepath: Union[str, Path],
49+
combine_type: CombineType,
50+
input_volumes: Optional[List[float]] = None):
4351
'''Builds the output_file by executing the current set of commands.
4452
4553
Parameters
@@ -116,7 +124,10 @@ def build(self, input_filepath_list, output_filepath, combine_type,
116124
logger.info("[SoX] {}".format(out))
117125
return True
118126

119-
def preview(self, input_filepath_list, combine_type, input_volumes=None):
127+
def preview(self,
128+
input_filepath_list: List[Union[str, Path]],
129+
combine_type: CombineType,
130+
input_volumes: Optional[List[float]] = None):
120131
'''Play a preview of the output with the current set of effects
121132
122133
Parameters
@@ -155,8 +166,13 @@ def preview(self, input_filepath_list, combine_type, input_volumes=None):
155166

156167
play(args)
157168

158-
def set_input_format(self, file_type=None, rate=None, bits=None,
159-
channels=None, encoding=None, ignore_length=None):
169+
def set_input_format(self,
170+
file_type: Optional[List[str]] = None,
171+
rate: Optional[List[float]] = None,
172+
bits: Optional[List[int]] = None,
173+
channels: Optional[List[int]] = None,
174+
encoding: Optional[List[EncodingValue]] = None,
175+
ignore_length: Optional[List[bool]] = None):
160176
'''Sets input file format arguments. This is primarily useful when
161177
dealing with audio files without a file extension. Overwrites any
162178
previously set input file arguments.
@@ -312,7 +328,8 @@ def set_input_format(self, file_type=None, rate=None, bits=None,
312328
return self
313329

314330

315-
def _validate_file_formats(input_filepath_list, combine_type):
331+
def _validate_file_formats(input_filepath_list: List[Union[str, Path]],
332+
combine_type: CombineType):
316333
'''Validate that combine method can be performed with given files.
317334
Raises IOError if input file formats are incompatible.
318335
'''
@@ -322,7 +339,8 @@ def _validate_file_formats(input_filepath_list, combine_type):
322339
_validate_num_channels(input_filepath_list, combine_type)
323340

324341

325-
def _validate_sample_rates(input_filepath_list, combine_type):
342+
def _validate_sample_rates(input_filepath_list: List[Path],
343+
combine_type: CombineType):
326344
''' Check if files in input file list have the same sample rate
327345
'''
328346
sample_rates = [
@@ -332,11 +350,12 @@ def _validate_sample_rates(input_filepath_list, combine_type):
332350
raise IOError(
333351
"Input files do not have the same sample rate. The {} combine "
334352
"type requires that all files have the same sample rate"
335-
.format(combine_type)
353+
.format(combine_type)
336354
)
337355

338356

339-
def _validate_num_channels(input_filepath_list, combine_type):
357+
def _validate_num_channels(input_filepath_list: List[Path],
358+
combine_type: CombineType):
340359
''' Check if files in input file list have the same number of channels
341360
'''
342361
channels = [
@@ -347,12 +366,14 @@ def _validate_num_channels(input_filepath_list, combine_type):
347366
"Input files do not have the same number of channels. The "
348367
"{} combine type requires that all files have the same "
349368
"number of channels"
350-
.format(combine_type)
369+
.format(combine_type)
351370
)
352371

353372

354-
def _build_input_format_list(input_filepath_list, input_volumes=None,
355-
input_format=None):
373+
def _build_input_format_list(input_filepath_list: List[Path],
374+
input_volumes: Optional[List[float]] = None,
375+
input_format: Optional[List[List[str]]] = None) \
376+
-> List[str]:
356377
'''Set input formats given input_volumes.
357378
358379
Parameters
@@ -426,7 +447,8 @@ def _build_input_format_list(input_filepath_list, input_volumes=None,
426447
return input_format_list
427448

428449

429-
def _build_input_args(input_filepath_list, input_format_list):
450+
def _build_input_args(input_filepath_list: List[Path],
451+
input_format_list: List[str]) -> List[str]:
430452
''' Builds input arguments by stitching input filepaths and input
431453
formats together.
432454
'''
@@ -446,7 +468,7 @@ def _build_input_args(input_filepath_list, input_format_list):
446468
return input_args
447469

448470

449-
def _validate_combine_type(combine_type):
471+
def _validate_combine_type(combine_type: List[CombineType]):
450472
'''Check that the combine_type is valid.
451473
452474
Parameters
@@ -462,7 +484,7 @@ def _validate_combine_type(combine_type):
462484
)
463485

464486

465-
def _validate_volumes(input_volumes):
487+
def _validate_volumes(input_volumes: List[float]):
466488
'''Check input_volumes contains a valid list of volumes.
467489
468490
Parameters
@@ -479,5 +501,5 @@ def _validate_volumes(input_volumes):
479501
if not core.is_number(vol):
480502
raise ValueError(
481503
"Elements of input_volumes must be numbers: found {}"
482-
.format(vol)
504+
.format(vol)
483505
)

sox/core.py

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,32 @@
11
'''Base module for calling SoX '''
22

3-
from pathlib import Path
43
import subprocess
4+
from pathlib import Path
55
from subprocess import CalledProcessError
6-
from typing import Union
6+
from typing import Union, List, Optional, Tuple, Iterable, Any
77

88
import numpy as np
9+
from typing_extensions import Literal
910

10-
from .log import logger
1111
from . import NO_SOX
12+
from .log import logger
1213

1314
SOXI_ARGS = ['B', 'b', 'c', 'a', 'D', 'e', 't', 's', 'r']
1415

1516
ENCODING_VALS = [
1617
'signed-integer', 'unsigned-integer', 'floating-point', 'a-law', 'u-law',
1718
'oki-adpcm', 'ima-adpcm', 'ms-adpcm', 'gsm-full-rate'
1819
]
20+
EncodingValue = Literal[
21+
'signed-integer', 'unsigned-integer', 'floating-point', 'a-law', 'u-law',
22+
'oki-adpcm', 'ima-adpcm', 'ms-adpcm', 'gsm-full-rate'
23+
]
1924

2025

21-
def sox(args, src_array=None, decode_out_with_utf=True):
26+
def sox(args: Iterable[str],
27+
src_array: Optional[np.ndarray] = None,
28+
decode_out_with_utf: bool = True) -> \
29+
Tuple[bool, Optional[Union[str, np.ndarray]], Optional[str]]:
2230
'''Pass an argument list to SoX.
2331
2432
Parameters
@@ -95,11 +103,12 @@ def sox(args, src_array=None, decode_out_with_utf=True):
95103
class SoxError(Exception):
96104
'''Exception to be raised when SoX exits with non-zero status.
97105
'''
106+
98107
def __init__(self, *args, **kwargs):
99108
Exception.__init__(self, *args, **kwargs)
100109

101110

102-
def _get_valid_formats():
111+
def _get_valid_formats() -> List[str]:
103112
''' Calls SoX help for a lists of audio formats available with the current
104113
install of SoX.
105114
@@ -164,7 +173,7 @@ def soxi(filepath: Union[str, Path], argument: str) -> str:
164173
return str(shell_output).strip('\n')
165174

166175

167-
def play(args):
176+
def play(args: Iterable[str]) -> bool:
168177
'''Pass an argument list to play.
169178
170179
Parameters
@@ -212,11 +221,12 @@ def play(args):
212221
class SoxiError(Exception):
213222
'''Exception to be raised when SoXI exits with non-zero status.
214223
'''
224+
215225
def __init__(self, *args, **kwargs):
216226
Exception.__init__(self, *args, **kwargs)
217227

218228

219-
def is_number(var):
229+
def is_number(var: Any) -> bool:
220230
'''Check if variable is a numeric value.
221231
222232
Parameters
@@ -237,7 +247,7 @@ def is_number(var):
237247
return False
238248

239249

240-
def all_equal(list_of_things):
250+
def all_equal(list_of_things: List[Any]) -> bool:
241251
'''Check if a list contains identical elements.
242252
243253
Parameters

sox/file_info.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
''' Audio file info computed by soxi.
22
'''
33
import os
4+
from numbers import Number
45
from pathlib import Path
6+
from typing import List, Dict
57
from typing import Optional, Union
68

79
from .core import VALID_FORMATS
8-
from .core import soxi
910
from .core import sox
11+
from .core import soxi
1012
from .log import logger
1113

1214

@@ -104,7 +106,7 @@ def comments(input_filepath: Union[str, Path]) -> str:
104106
return str(output)
105107

106108

107-
def duration(input_filepath: Union[str, Path]) -> float:
109+
def duration(input_filepath: Union[str, Path]) -> Optional[float]:
108110
'''
109111
Show duration in seconds, or None if not available.
110112
@@ -259,7 +261,7 @@ def validate_input_file(input_filepath: Union[str, Path]) -> None:
259261
)
260262

261263

262-
def validate_input_file_list(input_filepath_list: Union[str, Path]) -> None:
264+
def validate_input_file_list(input_filepath_list: List[Union[str, Path]]) -> None:
263265
'''Input file list validation function. Checks that object is a list and
264266
contains valid filepaths that can be processed by SoX.
265267
@@ -320,7 +322,7 @@ def validate_output_file(output_filepath: Union[str, Path]) -> None:
320322
)
321323

322324

323-
def file_extension(filepath: Union[str, Path]):
325+
def file_extension(filepath: Union[str, Path]) -> str:
324326
'''Get the extension of a filepath.
325327
326328
Parameters
@@ -336,7 +338,7 @@ def file_extension(filepath: Union[str, Path]):
336338
return Path(filepath).suffix[1:].lower()
337339

338340

339-
def info(filepath: Union[str, Path]) -> dict:
341+
def info(filepath: Union[str, Path]) -> Dict[str, Union[str, Number]]:
340342
'''Get a dictionary of file information
341343
342344
Parameters
@@ -370,7 +372,7 @@ def info(filepath: Union[str, Path]) -> dict:
370372
return info_dictionary
371373

372374

373-
def stat(filepath: Union[str, Path]) -> dict:
375+
def stat(filepath: Union[str, Path]) -> Dict[str, Optional[float]]:
374376
'''Returns a dictionary of audio statistics.
375377
376378
Parameters
@@ -407,7 +409,7 @@ def _stat_call(filepath: Union[str, Path]) -> str:
407409
return stat_output
408410

409411

410-
def _parse_stat(stat_output: Union[str, Path]) -> dict:
412+
def _parse_stat(stat_output: str) -> Dict[str, Optional[float]]:
411413
'''Parse the string output from sox's stat function
412414
413415
Parameters

0 commit comments

Comments
 (0)