4 ms·
Note that this recommends "sh" package, which made an _interesting_ decision to run processes in tty by default. This goes against unix conventions that batch p
by theamk 8y ago
Note that this recommends "sh" package, which made an _interesting_ decision to run processes in tty by default. This goes against unix conventions that batch processes should not be using tty, and breaks a number of utilities like git and systemctl. This is so bad that even their example from the front page is broken(!):
$ python3
>>> import sh
>>> sh.git.show('HEAD').count('\n')
49
# Now resize your terminal window to be 10 lines tall
>>> sh.git.show('HEAD').count('\n')
9
Yep, it truncated "git show" output to the height of your terminal window. Do you want this in your code?
While you can append special flag for this, it is very easy to forget to do so, and the documentation does not help either. Their FAQ states that they are aware of the issue and won't fix it [0].
So my advice is: stay away from "sh" package, as it makes it very simple to generate unreliable code. Instead, use built-in tools which are pretty nice and just a bit more verbose:
>>> import subprocess
>>> subprocess.check_output('git show HEAD', shell=True).decode().count('\n')
49
[0] https://amoffat.github.io/sh/sections/faq.html#why-is-tty-out-true-the-default https://amoffat.github.io/sh/sections/faq.html#why-is-tty-ou...
- anarcat 8y agoit's not "just a bit more verbose", subprocess is much longer and complex module than sh! i constantly need to go back to the manual (is it check_output or call? or maybe i need to create a pipe for that one? never remember). sh provides clear semantics for certain use cases - that it doesn't match your expectations on how a program shold behave is understandable, but there are knobs to change that behavior, so I don't know if that is a strong enough argument to completely "stay away from" it altogether. i know i've been happy it's there and used it in a few projects with good success, particularly projects that need exactly that: replace a shell and have the terminal passed down correctly.
- theamk 8y agoIt is obviously each person's preference, but I especially hate non-reproducible, context dependent bugs. I think having a reproducible, consistent runs is key to having nice software that everyone enjoys developing. In this light, I find the tty decision particularly bad, as it is very prone to introducing subtle changes -- for example, do you need the special flag for "git log"? what about "git for-each-ref"? what about "ls"? what about "gcc"? For this reason, I find it way easier to just ban "sh" outright altogether. Our organization policy say "do not use sh module". When new member joins, and they way to shell stuff out, they will find out that they need to use subprocess module, grumble a bit, search the web, but then produce a working, if verbose, code. An alternative would be to say: You can use sh, but never use it as sh's own front page recommends. If you find an article on the web which mentions sh, be aware that you cannot just copy-paste code from it, as it can be broken depending on which command you run. You need to audit which command you run to see if it cares about tty. Currently, you have to include the flag for many (but not all) git subcommands, "ls", "apt", ... but that list can change at anytime. > i know i've been happy it's there and used it in a few projects with good success, particularly projects that need exactly that: replace a shell and have the terminal passed down correctly. You have been lucky so far, but every time you use "sh" you are walking on landmines. I can give you a ton of plausible examples where sh breaks. Here is a shell replacement gone wrong: $ git show HEAD | wc 49 273 2202 $ python3 -c 'import sh; print(sh.wc(sh.git.show("HEAD")))' 19 97 812 edit: have you seen "subprocess.run" in python 3.5 [0]? It gives nice all-in-one API, with readable options like `check=True' or `capture_stdout=True` [0] https://docs.python.org/3/library/subprocess.html#subprocess.run https://docs.python.org/3/library/subprocess.html#subprocess...
- mixmastamyk 8y agoIt's quite easy to create a simple run() function wrapper around subprocess for your use case.