Subprocess is not invoking my command(or is doing it wrong) - python

Overview:
I have an application that sometimes must make something with celery- and if it is simple task such as count something- everything is ok.
I' ve got one task which must convert existing file to another file using MS Windows program. So- I installed WINE, then installed application and added folowing task to my tasks.py:
def convert_file( fil, to_format = 'pdf', save_to = '/tmp', callback = None ):
devnull = open( '/dev/null', 'w' )
commands = "xvfb-run -a wine '[ABSOLUTE_PATH_TO_WINDOWS_APP]' /r /f 104 %s" % fil
p = subprocess.Popen( commands, shell=True, cwd='/home/test', env=os.environ, stdout = devnull, stderr = subprocess.STDOUT )
p.wait()
devnull.close()
if callback:
subtask( callback ).delay( )
else:
return outfile
Problem:
The command isn't called or is called but nothing is happening(there isn't new file anywhere in filesystem)- but if I'll call this command from bash or from interactive python shell, everything is ok.
Edit:
When I'm calling the command from command line I get this:
test#ubuntu:~$ xvfb-run -a /home/test/.wine/....exe /r /f 104 /home/test/fs/...
err:winediag:X11DRV_WineGL_InitOpenglInfo The Mesa OpenGL driver is using software rendering, most likely your OpenGL drivers haven't been installed correctly
test#ubuntu:~$ XIO: fatal IO error 11 (Zasoby chwilowo niedostępne) on X server ":99"
after 1262 requests (1226 known processed) with 0 events remaining.
[Here i must press enter]
test#ubuntu:~$

Use
p = subprocess.Popen( commands, shell=True, cwd='/home/test', env=os.environ, stdout = subprocess.PIPE, stderr = subprocess.PIPE)
for your Popen command, then
print p.communicate()
p.wait()
print p.communicate()
To see what it prints to stdout and stderr and figure out what you're doing wrong.
Edit: Xvfb is a fake framebuffer; it doesn't have hardware acceleration. Try changing your wine settings not to require hardware acceleration / not to use OpenGL / to do software rendering with winecfg.

Related

Run python scripts with sudo motion can't get output

import subprocess
p = subprocess.Popen(['sudo motion'],
shell = True,
stdout = subprocess.PIPE,
stdin = subprocess.PIPE)
p.wait()
stdout, stderr = p.communicate()
out = stdout.decode('utf-8')
print('-----------', out)
and i use "python3 sh2.py" running the above script but get the following results
[22636168:motion] [NTC] [ALL] conf_load: Processing thread 0 - config file /etc/motion/motion.conf
[22636168:motion] [NTC] [ALL] motion_startup: Motion 4.1.1 Started
[22636168:motion] [NTC] [ALL] motion_startup: Logging to file (/var/log/motion/motion.log)
-----------
How can I get the results
If you want to capture stderr via p.communicate(), you need to set stderr to subprocess.PIPE in your Popen call (by contrast, it doesn’t seem like you’re using stdin):
p = subprocess.Popen(['sudo motion'],
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
By default, motion starts as a daemon, running in the background.
Depending on what are doing, you probably want configure it to run your script when some event occurs, using one of the on_ configuration settings (on_event_start, on_picture_save, etc).

How to hide console output of FFmpeg in Python?

I was working on a YouTube video downloader Python program.
I want to encode downloaded data to other media formats for this job i used FFmpeg and FFmpeg-Python (Package to use FFmpeg in Python).
Everything is Fine but i want to ask that how can i disable FFmpeg Output on the console ?
Here is some Pic of my Program :-
But this console often appears when my program starts encoding, suppressing the main GUI :-
If you know any solution for my problem then please give me some solution.
It is my first time that i am trying Stackoverflow for my problem.
THANKS IN ADVANCE !!!!!
It has been 1 year and 8 months since you have asked this question, you might already have a solution for that. However, I found a solution to solve your problem.
You can solve this problem by modifying the original ffmpeg code when you package your python program.
First, find your ffmpeg lib folder, if you install with the default location, you can check your libs here: C:\Users\User\AppData\Local\Programs\Python\Python310\Lib\site-packages\ffmpeg.
Second, find _probe.py and modify codes, here is the code that already got modified, any change is written in the comments. You need to Popen add args: shell=True, stdin=subprocess.PIPE.
import json
import subprocess
from ._run import Error
from ._utils import convert_kwargs_to_cmd_line_args
def probe(filename, cmd='ffprobe', **kwargs):
"""Run ffprobe on the specified file and return a JSON representation of the output.
Raises:
:class:`ffmpeg.Error`: if ffprobe returns a non-zero exit code,
an :class:`Error` is returned with a generic error message.
The stderr output can be retrieved by accessing the
``stderr`` property of the exception.
"""
args = [cmd, '-show_format', '-show_streams', '-of', 'json']
args += convert_kwargs_to_cmd_line_args(kwargs)
args += [filename]
# Original: p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# Popen add args: shell=True, stdin=subprocess.PIPE,
p = subprocess.Popen(args, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate()
if p.returncode != 0:
raise Error('ffprobe', out, err)
return json.loads(out.decode('utf-8'))
__all__ = ['probe']
Then, go to _run.py. You need to add shell=True, modify stdin=subprocess.PIPE or modify pipe_stdin=True (The code section below is just a part of the code):
#output_operator()
def run_async(
stream_spec,
cmd='ffmpeg',
pipe_stdin=False,
pipe_stdout=False,
pipe_stderr=False,
quiet=False,
overwrite_output=False,
):
"""Asynchronously invoke ffmpeg for the supplied node graph.
Args:
pipe_stdin: if True, connect pipe to subprocess stdin (to be
used with ``pipe:`` ffmpeg inputs).
pipe_stdout: if True, connect pipe to subprocess stdout (to be
used with ``pipe:`` ffmpeg outputs).
pipe_stderr: if True, connect pipe to subprocess stderr.
quiet: shorthand for setting ``capture_stdout`` and
``capture_stderr``.
**kwargs: keyword-arguments passed to ``get_args()`` (e.g.
``overwrite_output=True``).
Returns:
A `subprocess Popen`_ object representing the child process.
Examples:
Run and stream input::
process = (
ffmpeg
.input('pipe:', format='rawvideo', pix_fmt='rgb24', s='{}x{}'.format(width, height))
.output(out_filename, pix_fmt='yuv420p')
.overwrite_output()
.run_async(pipe_stdin=True)
)
process.communicate(input=input_data)
Run and capture output::
process = (
ffmpeg
.input(in_filename)
.output('pipe':, format='rawvideo', pix_fmt='rgb24')
.run_async(pipe_stdout=True, pipe_stderr=True)
)
out, err = process.communicate()
Process video frame-by-frame using numpy::
process1 = (
ffmpeg
.input(in_filename)
.output('pipe:', format='rawvideo', pix_fmt='rgb24')
.run_async(pipe_stdout=True)
)
process2 = (
ffmpeg
.input('pipe:', format='rawvideo', pix_fmt='rgb24', s='{}x{}'.format(width, height))
.output(out_filename, pix_fmt='yuv420p')
.overwrite_output()
.run_async(pipe_stdin=True)
)
while True:
in_bytes = process1.stdout.read(width * height * 3)
if not in_bytes:
break
in_frame = (
np
.frombuffer(in_bytes, np.uint8)
.reshape([height, width, 3])
)
out_frame = in_frame * 0.3
process2.stdin.write(
frame
.astype(np.uint8)
.tobytes()
)
process2.stdin.close()
process1.wait()
process2.wait()
.. _subprocess Popen: https://docs.python.org/3/library/subprocess.html#popen-objects
"""
args = compile(stream_spec, cmd, overwrite_output=overwrite_output)
stdin_stream = subprocess.PIPE if pipe_stdin else None
stdout_stream = subprocess.PIPE if pipe_stdout or quiet else None
stderr_stream = subprocess.PIPE if pipe_stderr or quiet else None
# Original: return subprocess.Popen(
# args, stdin=pipe_stdin, stdout=stdout_stream, stderr=stderr_stream)
# Add shell=True, modify stdin=subprocess.PIPE or modify pipe_stdin=True
return subprocess.Popen(
args, shell=True, stdin=subprocess.PIPE, stdout=stdout_stream, stderr=stderr_stream
)
Add "from subprocess import CREATE_NO_WINDOW" and use "creationflags=CREATE_NO_WINDOW" for Popen. Below is updated part of "_run.py" code from ffmpeg-python library, that worked for me.
from subprocess import CREATE_NO_WINDOW
#output_operator()
def run_async(
stream_spec,
cmd='ffmpeg',
pipe_stdin=False,
pipe_stdout=False,
pipe_stderr=False,
quiet=False,
overwrite_output=False,
):
args = compile(stream_spec, cmd, overwrite_output=overwrite_output)
stdin_stream = subprocess.PIPE if pipe_stdin else None
stdout_stream = subprocess.PIPE if pipe_stdout or quiet else None
stderr_stream = subprocess.PIPE if pipe_stderr or quiet else None
return subprocess.Popen(
args, stdin=subprocess.PIPE, stdout=stdout_stream, stderr=stderr_stream, creationflags=CREATE_NO_WINDOW
)
Bradley's answer worked for to stop console flashes after compiling with pyinstaller. However, I wasn't comfortable updating the ffmpeg-python library itself since it would be overwritten when there was an update from PIP, and felt a little hacky just in general.
I ended up hi-jacking the functions to use within my class and used those directly, which also did the trick. I think it's safer but still carries its own risks if the library is updated in a way that conflicts with the hijacked functions.
"""Run OS command
Function to merge video and
subtitle file(s) into an MKV
"""
def run_os_command(self, os_command):
subprocess.call(os_command, shell=True)
"""FFmpeg probe hi-jack
Customized arguments to Popen to
prevent console flashes after
compiled with PyInstaller
"""
def ffmpeg_probe(self, video_input_path):
command = ['ffprobe', '-show_format', '-show_streams', '-of', 'json']
command += [video_input_path]
process = subprocess.Popen(
command,
shell=True,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
out, err = process.communicate()
if process.returncode != 0:
raise Exception(f"ffprobe error: {err}")
return json.loads(out.decode('utf-8'))
"""FFmpeg run hi-jack
Uses argument compiler from
library but alternate sub-
process method to run command
to prevent console flashes.
"""
def ffmpeg_run(self, stream):
os_command = ffmpeg.compile(stream, 'ffmpeg', overwrite_output=True)
return self.run_os_command(os_command)
Then to use
probe = ffmpeg_probe(video_input_path) # use like ffmpeg.probe()
ffmpeg_run(stream) # use like ffmpeg.run() can update the function if you pass more than stream

Run cmd file using python

I have a cmd file "file.cmd" containing 100s of lines of command.
Example
pandoc --extract-media -f docx -t gfm "sample1.docx" -o "sample1.md"
pandoc --extract-media -f docx -t gfm "sample2.docx" -o "sample2.md"
pandoc --extract-media -f docx -t gfm "sample3.docx" -o "sample3.md"
I am trying to run these commands using a script so that I don't have to go to a file and click on it.
This is my code, and it results in no output:
file1 = open('example.cmd', 'r')
Lines = file1.readlines()
# print(Lines)
for i in Lines:
print(i)
os.system(i)
You don't need to read the cmd file line by line. you can simply try the following:
import os
os.system('myfile.cmd')
or using the subprocess module:
import subprocess
p = subprocess.Popen(['myfile.cmd'], shell = True, close_fds = True)
stdout, stderr = proc.communicate()
Example:
myfile.cmd:
#ECHO OFF
ECHO Grettings From Python!
PAUSE
script.py:
import os
os.system('myfile.cmd')
The cmd will open with:
Greetings From Python!
Press any key to continue ...
You can debug the issue by knowing the return exit code by:
import os
return_code=os.system('myfile.cmd')
assert return_code == 0 #asserts that the return code is 0 indicating success!
Note: os.system works by calling system() in C can only take up to 65533 arguments after a command (so it is a 16 bit issue). Giving one more argument will result in the return code 32512 (which implies the exit code 127).
The subprocess module provides more powerful facilities for spawning new processes and retrieving their results; using that module is preferable to using this function (os.system('command')).
since it is a command file (cmd), and only the shell can run it, then shell argument must set to be true. since you are setting the shell argument to true, the command needs to be string form and not a list.
use the Popen method for spawn a new process and the communicte for waiting on that process (you can time it out as well). if you whish to communicate with the child process, provide the PIPES (see mu example, but you dont have to!)
the code below for python 3.3 and beyond
import subprocess
try:
proc=subprocess.Popen('myfile.cmd', shell=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
outs, errs = proc.communicate(timeout=15) #timing out the execution, just if you want, you dont have to!
except TimeoutExpired:
proc.kill()
outs, errs = proc.communicate()
for older python versions
proc = subprocess.Popen('myfile.cmd', shell=True)
t=10
while proc.poll() is None and t >= 0:
print('Still waiting')
time.sleep(1)
t -= 1
proc.kill()
In both cases (python versions) if you dont need the timeout feature and you dont need to interact with the child process, then just, use:
proc = subprocess.Popen('myfile.cmd', shell=True)
proc.communicate()

Python subprocess.Popen() followed by time.sleep

I want to make a python script that will convert a TEX file to PDF and then open the output file with my document viewer.
I first tried the following:
import subprocess
subprocess.Popen(['xelatex', '--output-directory=Alunos/', 'Alunos/' + aluno + '_pratica.tex'], shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
subprocess.Popen(['gnome-open', 'Alunos/'+aluno+'_pratica.pdf'], shell=False)
This way, the conversion from TEX to PDF works all right, but, as it takes some time, the second command (open file with Document Viewer) is executed before the output file is created.
So, I tried do make the program wait some seconds before executing the second command. Here's what I've done:
import subprocess
import time
subprocess.Popen(['xelatex', '--output-directory=Alunos/', 'Alunos/' + aluno + '_pratica.tex'], shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
time.sleep(10)
subprocess.Popen(['gnome-open', 'Alunos/'+aluno+'_pratica.pdf'], shell=False)
But, when I do so, the output PDF file is not created. I can't understand why. The only change was the time.sleep command. Why does it affect the Popen process?
Could anyone give me some help?
EDIT:
I've followed the advice from Faust and Paulo Bu and in both cases the result is the same.
When I run this command...
subprocess.call('xelatex --output-directory=Alunos/ Alunos/{}_pratica.tex'.format(aluno), shell=True)
... or this...
p = subprocess.Popen(['xelatex', '--output-directory=Alunos/', 'Alunos/' + aluno + '_pratica.tex'], shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
p.wait()
...the Xelatex program is run but doesn't make the conversion.
Strangely, when I run the command directly in the shell...
$ xelatex --output-directory=Alunos/ Alunos/name_pratica.tex
... the conversion works perfectly.
Here's what I get when I run the subprocess.call() command:
$ python my_file.py
Enter name:
name
This is XeTeX, Version 3.1415926-2.4-0.9998 (TeX Live 2012/Debian)
restricted \write18 enabled.
entering extended mode
(./Alunos/name_pratica.tex
LaTeX2e <2011/06/27>
Babel <v3.8m> and hyphenation patterns for english, dumylang, nohyphenation, loaded.
)
*
When I write the command directly in the shell, the output is the same, but it followed automatically by the conversion.
Does anyone know why it happens this way?
PS: sorry for the bad formating. I don't know how to post the shell output properly.
If you need to wait the termination of the program and you are not interested in its output you should use subprocess.call
import subprocess
subprocess.call(['xelatex', '--output-directory=Alunos/', 'Alunos/{}_pratica.tex'.format(aluno)])
subprocess.call([('gnome-open', 'Alunos/{}_pratica.pdf'.format(aluno)])
EDIT:
Also it is generally a good thing to use English when you have to name variables or functions.
If xelatex command works in a shell but fails when you call it from Python then xelatex might be blocked on output in your Python code. You do not read the pipes despite setting stdout/stderr to PIPE. On my machine the pipe buffer is 64KB therefore if xelatex output size is less then it should not block.
You could redirect the output to os.devnull instead:
import os
import webbrowser
from subprocess import STDOUT, check_call
try:
from subprocess import DEVNULL # py3k
except ImportError:
DEVNULL = open(os.devnull, 'w+b')
basename = aluno + '_pratica'
output_dir = 'Alunos'
root = os.path.join(output_dir, basename)
check_call(['xelatex', '--output-directory', output_dir, root+'.tex'],
stdin=DEVNULL, stdout=DEVNULL, stderr=STDOUT)
webbrowser.open(root+'.pdf')
check_call is used to wait for xelatex and raise an exception on error.

Not able to give inputs to subprocess(process which runs adb shell command) after 100 iterations

I want to run a stress test for adb(android debug bridge) shell. ( adb shell in this respect just a command line tool provided by Android phones).
I create a sub-process from python and in this subprocess i execute 'adb shell' command. there are some commands which has to be given to this subprocess which I am providing via stdin proper of the sub process.
Everything seems to be fine but when I am running a stress test. after around 100 iterations the command which I give to stdin does not reach to subprocess. If I run commands in separate terminal it is running fine. but the problem is with this stdin.
Can anyone tell me what I am doing wrong. Below is the code sample
class ADB():
def __init__(self):
self.proc = subprocess.Popen('adb shell', stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True,bufsize=0)
def provideAMcommand(self, testParam):
try:
cmd1 = "am startservice -n com.test.myapp/.ADBSupport -e \"" + "command" + "\" \"" + "test" + "\""
cmd2 = " -e \"" + "param" + "\"" + " " + testParam
print cmd1+cmd2
sys.stdout.flush()
self.proc.stdin.write(cmd1 + cmd2 + "\n")
except:
raise Exception("Phone is not Connected to Desktop or ADB is not available \n")
If it works for the first few commands but blocks later then you might forgot to read from self.proc.stdout that might lead to (as the docs warn) to OS pipe buffer filling up and blocking the child process.
To discard the output, redirect it to os.devnull:
import os
from subprocess import Popen, PIPE, STDOUT
DEVNULL = open(os.devnull, 'wb')
# ...
self.proc = Popen(['adb', 'shell'], stdin=PIPE, stdout=DEVNULL, stderr=STDOUT)
# ...
self.proc.stdin.write(cmd1 + cmd2 + "\n")
self.proc.stdin.flush()
There is pexpect module that might be a better tool for a dialog-based interaction (if you want both read/write intermitently).
IN provideAMcommand you are writing to and flushing the stdout of your main process. That will not send anything to the stdin of the child process you have created with Popen. The following code creates a new bash child process, a bit like the code in your __init__:
import subprocess as sp
cproc = sp.Popen("bash", stdin=sp.PIPE, stdout=sp.PIPE, stderr=sp.PIPE, shell=True)
Now, the easiest way to communicate with that child process is the following:
#Send command 'ls' to bash.
out, err = cproc.communicate("ls")
This will send the text "ls" and EOF to bash (equal to running a bash script with only the text "ls" in it). Bash will execute the ls command and then quit. Anything that bash or ls write to stdout and stderr will end up in the variables out and err respectively. I have not used the adb shell, but I guess it behaves like bash in this regard.
If you just want your child process to print to the terminal, don't specify the stdout and stderr arguments to Popen.
You can check the exit code of the child, and raise an exception if it is non-zero (indicating an error):
if (cproc.returncode != 0):
raise Exception("Child process returned non-zero exit code")

Categories

Resources