Reputation: 916
I need to format a command line where some parameters come from simple variables, and others are the result of a longer expression. Python f-strings work well for the variables, and I'm using a printf-style %s
and providing the long expression outside the string because it would just clutter the command template too much if placed inline:
run(f"""zstd -dc {diff_file} |
git apply -p2 {exclude_args} --directory='%s'""" % (os.getcwd() + "/output"))
I didn't store the directory parameter in a named variable because it only gets used once as opposed to diff_file
and exclude_args
.
Is there a cleaner way to avoid putting os.getcwd() + "/output"
directly in the f-string, and also avoid mixing old printf %s
syntax and new f-strings ?
Are there downsides to doing it like above other than it being a bit confusing to someone who reads the code ?
Edit: to clarify, my question is how to put placeholders in f-strings without declaring additional named variables, not how to inline calls to getcwd()
in f-strings.
Upvotes: 2
Views: 68
Reputation: 178
I am a little confused, but if I understand the problem correct, then you want to put the % (os.getcwd() + "/output")
stuff later, for example the next line.
You can do that:
string = f"""zstd -dc {diff_file} |
git apply -p2 {exclude_args} --directory='%s'"""
run(string % (os.getcwd() + "/output"))
There is also a format()-function in the str class which allows us to do the following two examples.
string = f"""zstd -dc {diff_file} |
git apply -p2 {exclude_args} --directory='{{0}}'"""
run(string.format((os.getcwd() + "/output")))
string = f"""zstd -dc {diff_file} |
git apply -p2 {exclude_args} --directory='{{placeholder}}'"""
run(string.format(placeholder=(os.getcwd() + "/output")))
Cuz I am confused about what you want, the same examples as oneliner:
run(f"""zstd -dc {diff_file} |
git apply -p2 {exclude_args} --directory='{{0}}'""".format((os.getcwd() + "/output")))
run(f"""zstd -dc {diff_file} |
git apply -p2 {exclude_args} --directory='{{placeholder}}'""".format(placeholder=(os.getcwd() + "/output")))
I hope the desired answer is some where in the post, if not please leave a comment.
For anyone confused what is going on:
str.format allows us to delay the f-string format. So for example we can do:
template = "{0} {user}!"
print(template.format("Hello", user="World"))
# results in "Hello World!")
So why are there doubled curly braces? (--directory='{{0}}') Thought we need only one opening and one closing. This is because f-strings uses the single curly braces for their special stuff. So we need them to escape them, which is done with double them. So f"{{0}}" results in the string "{0}".
Upvotes: 0
Reputation: 532093
Don't use string formatting at all.
from pathlib import Path
from subprocess import Popen, PIPE, run
p = Popen(["zstd", "-dc", diff_file], stdout=PIPE)
# exclude_args itself should be a list like ["foo", "bar"] rather than
# a single string like "foo bar"
run(["git", "apply", "-p2", *exclude_args, "--directory", Path.cwd() / "output"], stdin=p.stdout)
Instead of creating a shell pipeline, create one subprocess for the zstd
command, then connect its standard output to the standard input of a separate git
subprocess.
You probably don't need Path
at all; "output"
alone as a relative path can be used by git
as long as you don't execute git
with a working directory different from your Python script's working directory.
Upvotes: 3
Reputation: 12822
From the docs
Formatted string literals (also called f-strings for short) let you include the value of Python expressions inside a string by prefixing the string with f or F and writing expressions as {expression}.
So
run(f"""zstd -dc {diff_file} |
git apply -p2 {exclude_args} --directory='{os.getcwd()}/output'""")
A line continuation must be added If the new line after the pipe is needed
run(f"""zstd -dc {diff_file} | \
git apply -p2 {exclude_args} --directory='{os.getcwd()}/output'""")
Upvotes: 3