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 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