This is in Windows 10 Linux (wsl) running Python 3.8.5 and 3.90rc1. Not using Windows native.
I'm os.walking through a directory hierarchy consisting of a number of recorded Albums listed by Album Title first, and within that title there is a song list in track order. I'm trying to use the full name of the song and output it to the Popen process which opens an external program /usr/bin/flac -ts which scans the single file and reports (usually through stderr) if it is in any way defective. The tracks are all .FLAC files. I've tried a variety of ways to accomplish this using sample techniques from here and other sites. Not matter what, though, there is always some problem, like the flac program never gets the filename, or causes Python to fail from (seemingly) some strange error. Here's an excerpt from my current version:
for path, dirs, files in os.walk(StartScanDir):
i=0
runout=[ ]
# runout[i]=path
runout.append(path)
print (runout[i])
# print (path)
for f in files:
if not f.endswith('.flac'):
continue
i=i+1
# print(i)
runout.append(f)
print (runout[i]) # > FLAClistOut
# print ("f")
pipe=Popen("/usr/bin/flac","-ts", stdout=PIPE, stderr=PIPE)
text = pipe.communicate()[0]
# text = pipe.communicate(b"f")
print(text)
print (stdout)
print (stderr)
This one raises the exception from /usr/lib/python3.9/subprocess.py 'bufsize must be an integer'. I sometimes get that, but in other variations of my coding, I get a complaint about the input wanting binary and getting a str. It's the same behavior on either version of Python.
Can anyone spot what I might be doing wrong and/or suggest a better way? There are some lines commented out that were just for testing.
Thanks.
I've updated and commented the code so what's going on is clearer.
os.chdir(StartScanDir) #start at the top of the directory hierarchy
# print(os.getcwd())
for path, dirs, files in os.walk(StartScanDir):
i=0
runout=[ ] #clear logging string array
runout.append(path) #add album title
print (runout[i])
for f in files:
if not f.endswith('.flac'):
continue
i=i+1
runout.append(f) #add individual song titles
cmd = ['/usr/bin/flac','-t','-s']
print (runout[i]) # > FLAClistOut
p=subprocess.Popen(cmd, stdout = subprocess.PIPE, stdin = subprocess.PIPE)
out,err=p.communicate('f' )
print (out)
print (err)
This produces the error:
Traceback (most recent call last):
File "/mnt/x/incoming/py-work/fixflac.py", line 35, in <module>
out,err=p.communicate('f' )
File "/usr/lib/python3.9/subprocess.py", line 1130, in communicate
stdout, stderr = self._communicate(input, endtime, timeout)
File "/usr/lib/python3.9/subprocess.py", line 1957, in _communicate
input_view = memoryview(self._input)
TypeError: memoryview: a bytes-like object is required, not 'str'
can be replaced with
as long as you only want
b'f'to be the only input. The input must be a bytes array, since a str could be encoded as ISO-8859-1, UTF8, UCS16, etc. Python doesn't know which encoding flac will be expecting.However,
p.communicate()does several different steps, and it may be clearer to handle each step separately. For example, theerrvariable will always beNonebecause your call toPopen()does not includestderr=subprocess.PIPE. Instead of p.communicate(), you could write:The error that you encountered in the first example is because all the
flacarguments must be in the first argument tosubprocess.Popen(). If you use a str as the first argument, you can't pass any other arguments toflac.Popen("/usr/bin/flac", "-ts", stdout=PIPE, stderr=PIPE)passes"-ts"as the second argument, which is thebufsizeargument, and it expects an integer.I haven't used
flacbefore, but I believe you will need to pass the filename as an argument. For example:I don't think you will need to send data to
flac, so you can just callout_bytes = p.stdout.read(). It will return a byte array. If you want to convert it to a str, you can callout_str = out_bytes.decode('utf-8').flacis probably just outputing ascii, but UTF-8 is a superset of ascii, and it is the most common encoding.