Skip to content

Commit 59955ea

Browse files
committed
feat(utils): render list of arguments
1 parent 1ff8d9c commit 59955ea

1 file changed

Lines changed: 43 additions & 13 deletions

File tree

codesectools/utils.py

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"""
77

88
import os
9+
import re
910
import subprocess
1011
from collections.abc import Sequence
1112
from importlib.resources import files
@@ -39,31 +40,60 @@ def DEBUG() -> bool:
3940

4041

4142
# Subprocess wrapper
42-
def render_command(command: list[str], map: dict[str, str]) -> list[str]:
43+
def get_pattern(arg: str, mapping: dict[str, str]) -> str | None:
44+
"""Find a placeholder pattern like '{placeholder}' in an argument string.
45+
46+
Args:
47+
arg: The string to search for a pattern.
48+
mapping: A dictionary of placeholders, kept for contextual consistency
49+
with `render_command`.
50+
51+
Returns:
52+
The found pattern string (e.g., '{placeholder}') or None if not found.
53+
54+
"""
55+
if m := re.search(r"\{.*\}", arg):
56+
return m.group(0)
57+
58+
59+
def render_command(command: list, mapping: dict[str, str]) -> list[str]:
4360
"""Render a command template by replacing placeholders with values.
4461
62+
Substitutes placeholders in a command list from a given map. It handles
63+
simple string arguments and optional arguments represented as tuples.
64+
If a mapped value is a list, the argument is expanded.
65+
4566
Args:
46-
command: The command template as a list of strings.
47-
map: A dictionary of placeholders to their replacement values.
67+
command: The command template, which can contain strings and tuples
68+
of the form `(default, optional_template)`.
69+
mapping: A dictionary of placeholders to their replacement values.
4870
4971
Returns:
5072
The rendered command as a list of strings.
5173
5274
"""
5375
_command = command.copy()
54-
for pattern, value in map.items():
55-
for i, arg in enumerate(_command):
56-
# Check if optional argument can be used
57-
if isinstance(arg, tuple):
58-
default_arg, optional_arg = arg
59-
if pattern in optional_arg:
60-
_command[i] = arg.replace(pattern, value)
76+
for i, arg in enumerate(_command):
77+
# Check if optional argument can be used
78+
if isinstance(arg, tuple):
79+
default_arg, optional_arg = arg
80+
81+
if pattern := get_pattern(optional_arg, mapping):
82+
_command[i] = optional_arg.replace(pattern, mapping[pattern])
83+
elif pattern := get_pattern(default_arg, mapping):
84+
_command[i] = default_arg.replace(pattern, mapping[pattern])
85+
else:
86+
if pattern := get_pattern(arg, mapping):
87+
value = mapping[pattern]
88+
if isinstance(value, list):
89+
_command[i] = " ".join(
90+
arg.replace(pattern, subvalue) for subvalue in value
91+
)
6192
else:
62-
_command[i] = default_arg
63-
else:
64-
if pattern in arg:
6593
_command[i] = arg.replace(pattern, value)
6694

95+
_command = " ".join(_command).split(" ")
96+
6797
# Remove not rendered part of the command:
6898
__command = []
6999
for part in _command:

0 commit comments

Comments
 (0)