I’m branching this off from the Template.join() thread and is related to the PEP 787 discussion.
A Template.split(sep=’ ') function that broke a t-string into its respective parts seems like it would be logical, and would be a good sequence to feed into subprocess.run. Only the string parts of the template would be split, the Interpolation parts would not be . It would look like:
name = "Dolly"
feet = 12
greeting = with_split(t"Hello {name}")
print(greeting.split()) # ('Hello ', 'Dolly')
conversion = with_split(t"A foot is {feet:.2f} inches")
print(conversion.split()) # ('A foot is ', '12.00', ' inches')
user_input = "/tmp; rm -fr /"
no_inject = with_split(t"ls {user_input}")
print(no_inject.split()) # ('ls ', '/tmp; rm -fr /')
home = "/home"
long_listing = with_split(t"ls -l{home}")
print(long_listing.split()) # ('ls', '-l', '/home')
Because it would use the t string curly delinerators instead of (suspect) shell splitting rules, it could look more like a command line: t"ls {user_input}" but would not be subject to injection attacks
An implementation could be something like:
def split(self,sep=' '):
context = globals()
parts = []
strings = self._template.strings
interpolations = self._template.interpolations
for i in range(len(interpolations)):
if strings[i]:
parts.extend(strings[i].split(sep))
expr = interpolations[i].expression
conversion = interpolations[i].conversion
fmt = interpolations[i].format_spec or ""
value = eval(expr, context)
if conversion == "s":
value = str(value)
elif conversion == "r":
value = repr(value)
elif conversion == "a":
value = ascii(value)
parts.append(format(value, fmt))
if strings[-1]:
parts.append(strings[-1])
return tuple(parts)