Reputation: 1354
I have a simple function that checks if a program is running and returns a boolean as appropriate. It does this by checking the output of the command ps -A
using the module subprocess
. I'm trying to get this function to work in both Python 2 and Python 3 but am encountering the following error:
TypeError: a bytes-like object is required, not 'str'
How should the function be changed such that it can work in both Python 2 and Python 3?
import subprocess
def running(program):
results = subprocess.Popen(
["ps", "-A"],
stdout = subprocess.PIPE
).communicate()[0].split("\n")
matches_current = [
line for line in results if program in line and "defunct" not in line
]
if matches_current:
return True
else:
return False
EDIT: Following some guidance by @Josh, I've changed the newline string delimiter to bytecode, however I'm still encountering a similar problem:
>>> import subprocess
>>> def running(program):
... results = subprocess.Popen(
... ["ps", "-A"],
... stdout = subprocess.PIPE
... ).communicate()[0].split(b"\n")
... matches_current = [
... line for line in results if program in line and "defunct" not in line
... ]
... if matches_current:
... return True
... else:
... return False
...
>>> running("top")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 7, in running
File "<stdin>", line 7, in <listcomp>
TypeError: a bytes-like object is required, not 'str'
Upvotes: 8
Views: 6419
Reputation: 1773
universal_newlines=True
produces strings instead of bytes.
results = subprocess.Popen(
["ps", "-A"],
stdout = subprocess.PIPE,
universal_newlines=True
).communicate()[0].split("\n")
Using iterator
p = subprocess.Popen(
["ps", "-A"],
stdout = subprocess.PIPE,
universal_newlines=True
)
for result in p.stdin:
print(result.strip())
Upvotes: 2
Reputation: 1074
It's an old question, but I've found a simpler way that works both in Python 2 and 3: add .decode()
after communicate()[0]
:
results = subprocess.Popen(
["ps", "-A"],
stdout = subprocess.PIPE
).communicate()[0].decode().split("\n")
So you don't have to add b
's before every string literal or encode()
to string variables in your code. As a bonus, results
will become an Unicode string.
PS. In my case I had subprocess.check_output()
and appending .decode()
also worked as expected.
EDIT: probably it is better to specify encoding, like decode('utf-8')
just in case.
Upvotes: 3
Reputation: 5549
Use bytestrings like b"\n"
instead of just plain "\n"
, and also use program.encode()
instead of program
(assuming you're being passed a string):
results = subprocess.Popen(
["ps", "-A"],
stdout = subprocess.PIPE
).communicate()[0].split(b"\n")
matches_current = [
line for line in results if program.encode() in line and b"defunct" not in line
]
This is because in Python 3, subprocess.Popen.communicate
returns bytes rather than a string by default. In Python 2.6+, b"\n" == "\n"
, so you shouldn't have any problems there.
Upvotes: 3