-
Notifications
You must be signed in to change notification settings - Fork 264
refactor: use run-like syntax #672
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
81d30a5
to
9978482
Compare
9978482
to
203bf33
Compare
I'm not sure I agree with the motivation behind this change. I think a key motivator for the existing |
The original call wrapper was a wrapper for |
That would help, yeah. But I still don't understand the need to unify the two platforms >>> subprocess.run(['/bin/echo', 'hello!'])
hello!
CompletedProcess(args=['/bin/echo', 'hello!'], returncode=0)
>>> subprocess.run(['/bin/echo', 'hello!'], shell=True)
CompletedProcess(args=['/bin/echo', 'hello!'], returncode=0) Note the missing output on the second example. It's missing because the 'hello!' argument went to (sorry for going deep, but I had to make sure I wasn't making a mountain out of a molehill!) |
On windows, this is simulating what would be done if Windows didn't have the (linked) bug. If that bug was fixed, then you could remove the custom handling and it would look like the others. But currently, we have to pretend that |
Apologies for the delay in getting back to this @henryiii ! Probably I've been dragging my feet because I'm conflict-averse and I didn't see it as a high priority, but I do see the value in unifying some kind of wrapper, as we saw in #521. So I return to this with slightly more understanding of the why. That said,
It would be lovely to match the subprocess.run API for familiarity, but I think that the above concerns are more important, and we wouldn't have a wrapper if we weren't changing behaviour (logging plus the windows workaround), so there is some logic in changing the name. I've gone around the houses on this, but settled on something quite neat I think. So my counter proposal might look something like: def call(
args: Sequence[PathOrStr],
env: Optional[Dict[str, str]] = None,
cwd: Optional[PathOrStr] = None,
) -> None:
"""
Executes a command, like subprocess.run(..., check=True), but:
- Prints the command before executing it
- Works around a couple of bugs on Windows
"""
print("+ " + " ".join(shlex.quote(str(a)) for a in args))
# execute in a shell on Windows to workaround a PATH resolution bug
# https://bugs.python.org/issue8557
shell = sys.platform.startswith("win")
# converts Paths to strings, due to Windows behavior at least on older Pythons.
subprocess.run([str(a) for a in args], shell=shell, env=env, cwd=cwd, check=True)
Curious what you think @henryiii. I realise that this doesn't match your original idea, but I think maybe this would unify the API in a way that we can both agree on? |
I was always fine going the other way too; I have not been a fan of the subprocess syntax since 2015. :)
Since we are coming up with a new syntax, what about: def call(
*args: PathOrStr,
env: Optional[Dict[str, str]] = None,
cwd: Optional[PathOrStr] = None,
) -> None: Adding the brackets each time isn't very necessary, and it allows this misusage of a plus sign: call(my_args + ["--other"]) to be written like this: call(*my_args, "--other") |
This is taken from pypa#672
This is taken from pypa#672
This is taken from pypa#672
This is taken from pypa#672
This is taken from pypa#672
This standardizes the "call" and "shell" commands into a single "run" utility. This utility is just a wrapper around
subprocess.run
that prints the command before running it, and has a better default on Windows due to a Python bug. The goal here is really not to simplify, or to even help out #665 anymore, but to better match the stdlib run syntax to be more recognizable to readers. This is a natural followup to #592 which changedsubprocess.check_call(...)
tosubprocess.run(..., check=True)
. I think if this was developed from scratch today, it would look more like this syntax vs. the oldcall
.Mapping:
call(...)
->run(..., check=True)
shell(...)
->run(..., check=True, shell=True)
(on Windows, for now, this is the same as the above line, but highlights that it is intentionally needing/using the shell, while the one above does not except for the mentioned bug)call_with_arch(...)
->run_with_arch(..., check=True)
I did not change the docker
self.call
, as that's already pretty far fromsubprocess.run
, AFAICT, and therefore benefits less from mimicking it. Though it could be changed.Not absolutely glued to the idea if others have objections. The other direction would be to try to simply the call command to diverge farther from
subprocess.run
, say by accepting*args
, smarter cwd default, etc. This could then allowpip = partial(call, "python", "-m", "pip")
, for example.