Python Forum
moving from os to subprocess
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
moving from os to subprocess
#1
I am working on a Linux Mint 18.2 laptop.
I used python 2.7 in the past but moved to 3.5 and now 3.6. I have carried on using os.system calls as I cannot figure out the correct syntax for using subprocess calls.
Here is an example of what I am struggling with.
with os.system I can do
vid = home + "/myvids/videos/" + vidstore[thevid]
vid2play = "mpv --fs  " + vid
os.system(vid2play)
 i get the variable home from
from os.path import expanduser
home = expanduser(~)
I have no idea what can replace expanduser and try as I might I cannot find any combination of " ' , and so on which can be passed to subprocess.call which it accepts. I have googled until my eyes swap places but all the suggestions I have tried so far have failed me.
something like this example is fine
import subprocess
subprocess.call(["ls", "-l"])
but how can I use variables as in the os.system call?
I tried 
subprocess.call('mpv', '--fs', vid)
also
subprocess.call('mpv', '--fs', 'vid')
along with various other combinations but get
Quote:Exception in Tkinter callback
Traceback (most recent call last):
  File "/usr/lib/python3.6/tkinter/__init__.py", line 1702, in __call__
    return self.func(*args)
  File "./sign-songsPCC.py", line 143, in play_song
    subprocess.call('mpv', '--fs', 'vid') #,  'mwbv_BSL_201712_05_r720P.mp4')
  File "/usr/lib/python3.6/subprocess.py", line 267, in call
    with Popen(*popenargs, **kwargs) as p:
  File "/usr/lib/python3.6/subprocess.py", line 609, in __init__
    raise TypeError("bufsize must be an integer")
TypeError: bufsize must be an integer

So I do hope someone can point me in the right direction please.
Reply
#2
You have to pass a list to subprocess.call.

>>> import subprocess
>>> import os.path
>>> video = os.path.abspath("gotham.206.hdtv-lol.mp4")
>>> video
'/media/storage/Download/Video/Gotham.S02.HDTV.x264-Zamunda.SE/gotham.206.hdtv-lol.mp4'
>>> subprocess.call(['mpv', video])
Playing: /media/storage/Download/Video/Gotham.S02.HDTV.x264-Zamunda.SE/gotham.206.hdtv-lol.mp4
 (+) Video --vid=1 (*) (h264)
 (+) Audio --aid=1 --alang=und (*) (aac)
 (+) Subs  --sid=1 'gotham.206.hdtv-lol.srt' (subrip) (external)
[vo/opengl/x11] Disabling screensaver failed (4). Make sure the xdg-screensaver script is installed.
[sub] Using subtitle charset: cp1251
AO: [pulse] 48000Hz stereo 2ch float
VO: [opengl] 720x404 yuv420p
AV: 00:00:16 / 00:43:48 (0%) A-V:  0.000 Dropped: 12 Cache: 10s+73MB


Exiting... (Quit)
4
"As they say in Mexico 'dosvidaniya'. That makes two vidaniyas."
https://freedns.afraid.org
Reply
#3
(Dec-17-2017, 05:59 PM)wavic Wrote: You have to pass a list to subprocess.call.

>>> import subprocess
>>> import os.path
>>> video = os.path.abspath("gotham.206.hdtv-lol.mp4")
>>> video
'/media/storage/Download/Video/Gotham.S02.HDTV.x264-Zamunda.SE/gotham.206.hdtv-lol.mp4'
>>> subprocess.call(['mpv', video])
Playing: /media/storage/Download/Video/Gotham.S02.HDTV.x264-Zamunda.SE/gotham.206.hdtv-lol.mp4
 (+) Video --vid=1 (*) (h264)
 (+) Audio --aid=1 --alang=und (*) (aac)
 (+) Subs  --sid=1 'gotham.206.hdtv-lol.srt' (subrip) (external)
[vo/opengl/x11] Disabling screensaver failed (4). Make sure the xdg-screensaver script is installed.
[sub]Using subtitle charset: cp1251
AO: [pulse] 48000Hz stereo 2ch float
VO: [opengl] 720x404 yuv420p
AV: 00:00:16 / 00:43:48 (0%) A-V:  0.000 Dropped: 12 Cache: 10s+73MB


Exiting... (Quit)
4
[/sub]

So having read about how much better it it to use subprocess instead of os this seems to indicate
there is no point to using subprocess if I have to use os anyway and can't pass a variable to subprocess. I really hope there must be a way to get it to work.
Reply
#4
Well I have made some progress!
I seem to need subprocess.run() not subprocess.call()
and I can use variables as below
song2play = home + "/BSL/songs/" +  thesongs[playlist[j]]
args = "mpv", "--fs", song2play
subprocess.run(args)
So next I guess I will see if I can find the replacement for expanduser
Reply
#5
You are trying to pass the command as regular arguments: subprocess.call(' mpv ', '--fs', vid). It has to be subprocess.call(['mpv', '--fs', vid]). See the diference?
"As they say in Mexico 'dosvidaniya'. That makes two vidaniyas."
https://freedns.afraid.org
Reply
#6
Ah yes  I do see the difference but it does work with subprocess.run so, unless there is some reason to change it I guess either will work. Or am I wrong?
Reply
#7
They are basically the same. The call() method returns the return code of the executed command.

retcode = subprocess.call(['ls', '-l'])
print(retcode)
Output:
0
You can do the same with run() method but the return code is as an attribute to the returned object:

subprocess.run(['ls', '-l']).returncode
Same output

Ref: https://docs.python.org/3/library/subpro...-level-api
"As they say in Mexico 'dosvidaniya'. That makes two vidaniyas."
https://freedns.afraid.org
Reply
#8
Okay, I get that now but if I run either version of the example I get the directory listing but then I get a single character '0' on the last line. What is that?
Also I was hoping that I could completely replace os with subprocess but one of the things I want to do is write a utility ( just for practise initially ) which would allow any user to access a USB stick and find a file which would give instructions as to which mp3's or mp4's need to be copied and where to put them.
with os I can use expanduser to extract the username and glob to find the  Stick and file.
In Linux Sticks are mounted under /media/username but what the stick is called can be just about anything. I have done this part successfully using os calls and can handle every stick or SD card I have tried so far.
Is it actually possible to do without os and just use subprocess?
Reply
#9
Well, in Linux if a command exit code is 0 it means that it ran without any errors. 
So that is returned by subprocess.call and subprocess.run().teturncode.

Mounting a usb stick so all users can access it is simple enough.
Create a new group and add all users to it
Make a directory at /home/ - /home/storage for example.
Give the right permissions so that group can access /home/storage.
In /etc/fstab add this line:

/dev/sdb1   /home/storage    auto    noauto,user,umask=0000   0   0

Or you can manage this using udev: https://wiki.archlinux.org/index.php/udev
I can't say more about all of this because I am the only user of the OS and never faced that need.

About using os.system to run shell commands. If you can do the same with Python do it that way.
Do users have control over which shell they can use? I prefer using zsh or fish instead of bash. The script will be useless if one shell syntax differs from another. And that is right. If you want to do something within a Python script search the net how to do it with Python, not shell commands.

Also, you may find this interesting to read: http://www.sharats.me/posts/the-ever-use...ss-module/

But as I said do not use shell commands from Python script if you can do it with Python. Consider this. It's just an example.
Let say you want to list a directory and do not know how to do it in Python.

import os

dir_ = input("Directory to be listed?\n> ") # asking the user for input. Edited: dir is a keyword
path = os.path.abspath(dir)
command = 'ls -a' + path
os.system(command)
Everything looks normal, right?
What if the user input is something like this: . ; rm -rf /home/$USER/? It will list the current working directory and then the home will be wiped out. The same is applicable for subprocess if you are using shell=True parameter.
"As they say in Mexico 'dosvidaniya'. That makes two vidaniyas."
https://freedns.afraid.org
Reply
#10
yeah, if youre going to run shell commands based on input, its a good idea to sanitise all the input. $( ) and these guys: ` and & are other gotchas, not just ;

and & and && apply even to dos cmd, not just gnu/linux. and using the python builtins will save you all this trouble, unless theres a reason you absolutely have to use the shell.
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020