Edit on GitHub

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