Coverage for src/nendo/utils.py: 66%
44 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-11-21 14:33 +0100
« prev ^ index » next coverage.py v7.3.2, created at 2023-11-21 14:33 +0100
1"""Utility functions used by Nendo."""
2import hashlib
3import logging
4import uuid
5from abc import ABC
6from typing import Callable, ClassVar, List, Optional, Union
8import numpy as np
9import sounddevice as sd
11logger = logging.getLogger("nendo")
14def get_wrapped_methods(plugin_class: ABC) -> List[Callable]:
15 """Get all wrapped methods of the given plugin class."""
16 return [
17 f
18 for f in type(plugin_class).__dict__.values()
19 if hasattr(f, "__wrapped__") and "pydantic" not in f.__name__
20 ]
23def md5sum(file_path):
24 """Compute md5 checksum of file found under the given file_path."""
25 hash_md5 = hashlib.md5() # noqa: S324
26 with open(file_path, "rb") as f:
27 for chunk in iter(lambda: f.read(4096), b""):
28 hash_md5.update(chunk)
29 return hash_md5.hexdigest()
32def play_signal(signal: np.ndarray, sr: int, loop: bool = False):
33 """Play the signal given as numpy array using `sounddevice`."""
34 logger.info("Playing signal with sample rate %d...", sr)
36 # sounddevice wants the signal to be in the shape (n_samples, n_channels)
37 sd.play(signal.T, samplerate=sr, loop=loop, blocking=True)
38 sd.wait()
41def ensure_uuid(target_id: Optional[Union[str, uuid.UUID]] = None) -> uuid.UUID:
42 """Take a string or a UUID and return the same value as a guaranteed UUID.
44 Args:
45 target_id (Union[str, uuid.UUID]): The target ID to convert to UUID type.
47 Returns:
48 uuid.UUID: The given target_id, converted to UUID. None if None was passed.
49 """
50 if target_id is not None and isinstance(target_id, str) and target_id != "":
51 return uuid.UUID(target_id)
52 if isinstance(target_id, uuid.UUID):
53 return target_id
54 return None
57class AudioFileUtils:
58 """Utility class for handling audio files."""
60 supported_filetypes: ClassVar[List[str]] = [
61 "wav",
62 "mp3",
63 "aiff",
64 "flac",
65 "ogg",
66 ]
68 def is_supported_filetype(self, filepath: str) -> bool:
69 """Check if the filetype of the given file is supported by Nendo."""
70 return filepath.lower().split(".")[-1] in self.supported_filetypes
73def pretty_print(data, indent=0):
74 """Helper function for pretty printing."""
75 result = ""
76 if isinstance(data, dict):
77 for key, value in data.items():
78 result += "\t" * indent + str(key) + ": "
79 if isinstance(value, (dict, list)):
80 result += "\n" + pretty_print(value, indent + 1)
81 else:
82 result += str(value) + "\n"
83 elif isinstance(data, list):
84 for item in data:
85 if isinstance(item, (dict, list)):
86 result += pretty_print(item, indent + 1)
87 else:
88 result += "\t" * indent + str(item) + "\n"
89 return result