pipewire_python._utils
Here we store internal functions, don't expect to see something here in documentation html version.
1""" 2Here we store internal functions, don't expect 3to see something here in documentation html version. 4""" 5import asyncio 6import re 7import subprocess 8from typing import Dict, List 9 10# Loading constants Constants.py 11from pipewire_python._constants import MESSAGES_ERROR 12 13 14def _print_std( 15 stdout: bytes, 16 stderr: bytes, 17 # Debug 18 verbose: bool = False, 19): 20 """ 21 Print terminal output if are different to None and verbose activated 22 """ 23 24 if stdout is not None and verbose: 25 print(f"[_print_std][stdout][type={type(stdout)}]\n{stdout.decode()}") 26 if stderr is not None and verbose: 27 print(f"[_print_std][stderr][type={type(stderr)}]\n{stderr.decode()}") 28 29 30def _get_dict_from_stdout( 31 stdout: str, 32 # Debug 33 verbose: bool = False, 34): 35 """ 36 Converts shell output (str) to dictionary looking for 37 "default" and "--" values 38 """ 39 40 rows = stdout.split("\n") 41 config_dict = {} 42 for row in rows: 43 if "default" in row: 44 key = "--" + row.split("--")[1].split(" ")[0] 45 value = row.split("default ")[1].replace(")", "") 46 config_dict[key] = value 47 if verbose: 48 print(config_dict) 49 return config_dict 50 51 52def _update_dict_by_dict( 53 main_dict: Dict, 54 secondary_dict: Dict, 55): 56 """ 57 Update values of one dictionary with values of another dictionary 58 based on keys 59 """ 60 return main_dict.update( 61 ([(key, secondary_dict[key]) for key in secondary_dict.keys()]) 62 ) 63 64 65def _drop_keys_with_none_values(main_dict: dict): 66 """ 67 Drop keys with None values to parse safe dictionary config 68 """ 69 return {k: v for k, v in main_dict.items() if v is not None} 70 71 72def _generate_command_by_dict( 73 mydict: Dict, 74 # Debug 75 verbose: bool = False, 76): 77 """ 78 Generate an array based on dictionary with keys and values 79 """ 80 array_command = [] 81 # append to a list 82 for key, value in mydict.items(): 83 array_command.extend([key, value]) 84 if verbose: 85 print(array_command) 86 # return values 87 return array_command 88 89 90def _execute_shell_command( 91 command: List[str], 92 timeout: int = -1, # *default= no limit 93 # Debug 94 verbose: bool = False, 95): 96 """ 97 Execute command on terminal via subprocess 98 99 Args: 100 - command (str): command line to execute. Example: 'ls -l' 101 - timeout (int): (seconds) time to end the terminal process 102 - verbose (bool): print variables for debug purposes 103 Return: 104 - stdout (str): terminal response to the command 105 - stderr (str): terminal response to the command 106 """ 107 # Create subprocess 108 # NO-RESOURCE-ALLOCATING 109 # terminal_subprocess = subprocess.Popen( 110 # command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT # Example ['ls ','l'] 111 # ) 112 113 with subprocess.Popen( 114 command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT # Example ['ls ','l'] 115 ) as terminal_subprocess: 116 # Execute command depending or not in timeout 117 try: 118 if timeout == -1: 119 stdout, stderr = terminal_subprocess.communicate() 120 else: 121 stdout, stderr = terminal_subprocess.communicate(timeout=timeout) 122 except subprocess.TimeoutExpired: # When script finish in time 123 terminal_subprocess.kill() 124 stdout, stderr = terminal_subprocess.communicate() 125 126 # Print terminal output 127 _print_std(stdout, stderr, verbose=verbose) 128 129 # Return terminal output 130 return stdout, stderr 131 132 133async def _execute_shell_command_async( 134 command, 135 timeout: int = -1, 136 # Debug 137 verbose: bool = False, 138): 139 """[ASYNC] Function that execute terminal commands in asyncio way 140 141 Args: 142 - command (str): command line to execute. Example: 'ls -l' 143 Return: 144 - stdout (str): terminal response to the command. 145 - stderr (str): terminal response to the command. 146 """ 147 if timeout == -1: 148 # No timeout 149 terminal_process_async = await asyncio.create_subprocess_shell( 150 command, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE 151 ) 152 stdout, stderr = await terminal_process_async.communicate() 153 print( 154 f"[_execute_shell_command_async]\ 155 [{command!r} exited with\ 156 {terminal_process_async.returncode}]" 157 ) 158 _print_std(stdout, stderr, verbose=verbose) 159 160 else: 161 raise NotImplementedError(MESSAGES_ERROR["NotImplementedError"]) 162 163 return stdout, stderr 164 165 166def _generate_dict_list_targets( 167 longstring: str, # string output of shell 168 # Debug 169 verbose: bool = False, 170): 171 """ 172 Function that transform long string of list targets 173 to a `dict` 174 """ 175 176 regex_id = r"(\d.*):" 177 regex_desc = r'description="([^"]*)"' 178 regex_prio = r"prio=(-?\d.*)" 179 regex_default_node = r"[*]\t(\d\d)" 180 regex_alsa_node = r"(alsa_[a-zA-Z].*)" 181 182 results_regex_id = re.findall(regex_id, longstring) 183 results_regex_desc = re.findall(regex_desc, longstring) 184 results_regex_prio = re.findall(regex_prio, longstring) 185 results_regex_default_node = re.findall(regex_default_node, longstring) 186 results_regex_alsa_mode = re.findall(regex_alsa_node, longstring) 187 188 mydict = {} 189 for idx, _ in enumerate(results_regex_id): 190 mydict[results_regex_id[idx]] = { 191 "description": results_regex_desc[idx], 192 "prior": results_regex_prio[idx], 193 } 194 mydict["_list_nodes"] = results_regex_id 195 mydict["_node_default"] = results_regex_default_node 196 mydict["_alsa_node"] = results_regex_alsa_mode 197 198 if verbose: 199 print(mydict) 200 201 return mydict 202 203 204def _generate_dict_interfaces( 205 longstring: str, # string output of shell 206 # Debug 207 verbose: bool = False, 208): 209 """ 210 Function that transform long string of list interfaces 211 to a `dict` 212 """ 213 214 mydict = {} 215 text_in_lines = longstring.split("\n") 216 first_level = "X" 217 218 for line in text_in_lines: 219 try: 220 is_interface = True 221 if "id: " in line: 222 # when interface starts 223 regex_id = r"\tid: ([0-9]*)" 224 results_regex_id = re.findall(regex_id, line) 225 is_interface = False 226 227 if is_interface: 228 if "*" in line[:1]: 229 # delete * on each line at the beginning 230 line = line[1:] 231 if "\t\t" in line: 232 # third level data 233 data = line.replace("\t\t", "") 234 data = data.split(" = ") 235 third_level = str(data[0]) 236 data_to_place = " ".join(data[1:]).replace('"', "") 237 238 if "properties" not in mydict[first_level]: 239 mydict[first_level]["properties"] = {} 240 if third_level not in mydict[first_level]["properties"]: 241 mydict[first_level]["properties"][third_level] = {} 242 mydict[first_level]["properties"][third_level] = data_to_place 243 244 elif "\t " in line: 245 # second level data: params 246 247 data = line.replace("\t ", "").split(" ") 248 third_level = str(data[0]) 249 if type(mydict[first_level]["params"]) != dict: 250 mydict[first_level]["params"] = {} 251 mydict[first_level]["params"][third_level] = { 252 "spa": data[1], 253 "permissions": data[2], 254 } 255 256 elif "\t" in line: 257 # first level data 258 data = line.replace("\t", "") 259 data = data.split(": ") 260 first_level = str(results_regex_id[0]) 261 second_level = str(data[0]) 262 data_to_place = " ".join(data[1:]).replace('"', "") 263 264 # to_dict 265 if first_level not in mydict: 266 mydict[str(first_level)] = {} 267 268 mydict[first_level][second_level] = data_to_place 269 except Exception as e: 270 print(e) 271 272 if verbose: 273 print(mydict) 274 275 return mydict 276 277 278def _filter_by_type( 279 dict_interfaces: dict, # interfaecs dict 280 type_interfaces: str, # string with type 281 # Debug 282 verbose: bool = False, 283): 284 """ 285 Function that filters a `dict` by type of interface 286 """ 287 288 dict_filtered = {} 289 for key in dict_interfaces: 290 # Filter 291 if type_interfaces in dict_interfaces[key]["type"]: 292 dict_filtered[key] = dict_interfaces[key] 293 294 if verbose: 295 print(dict_filtered) 296 297 return dict_filtered