I tried to call a process via Python with several arguments. Executing the batch file itself works fine for me but translating it into Python makes me scream. Here the contents of the batch file:
"C:\Program Files\bin\cspybat" "C:\Program Files\bin\armproc.dll" "C:\Program Files\bin\armjlink.dll" "C:\Documents and Settings\USER\Desktop\CAL\testing\Verification\FRT\Code\TC1\Output\Genericb\Debug\Exe\Gen.out" --download_only --backend -B "--endian=little" "--cpu=Cortex-M3" "--fpu=None" "-p" "C:\Program Files\CONFIG\debugger\ST\iostm32f10xxb.ddf" "--drv_verify_download" "--semihosting" "--device=STM32F10xxB" "-d" "jlink" "--drv_communication=USB0" "--jlink_speed=auto" "--jlink_initial_speed=32" "--jlink_reset_strategy=0,0"
The executable that is run by the batch file is named cspybat
. The output of the executable provides the information: All parameters after
--backendare passed to the back end
.
Also note that some of the the parameters are strings and some not.
Solution
That works for me now:
""" MCU flashing function"""
params = [r"C:\Program Files\bin\cspy",
r"C:\Program Files\bin\arpro.dll",
r"C:\Program Files\bin\arjink.dll",
r"C:\Documents and Settings\USER\Desktop\Exe\GenerV530b.out",
"--download_only", "--backend", "-B", "--endian=little", "--cpu=Cort3", "--fpu=None", "-p",
r"C:\Program Files\CONFIG\debugger\ST\iostm32f10xxb.ddf",
"--drv_verify_download", "--semihosting", "--device=STM32F10xxB", "-d", "jlink", "--drv_communication=USB0",
"--jlink_speed=auto", "--jlink_initial_speed=32", "--jlink_reset_strategy=0,0" ]
print(subprocess.list2cmdline(params))
p = subprocess.Popen(subprocess.list2cmdline(params))
To start a new process, or in other words, a new subprocess in Python, you need to use the Popen function call. It is possible to pass two parameters in the function call. The first parameter is the program you want to start, and the second is the file argument.
Python method popen() opens a pipe to or from command. The return value is an open file object connected to the pipe, which can be read or written depending on whether mode is 'r' (default) or 'w'.
To capture the output of the subprocess. run method, use an additional argument named “capture_output=True”. You can individually access stdout and stderr values by using “output. stdout” and “output.
The subprocess module provides a function named call. This function allows you to call another program, wait for the command to complete and then return the return code. It accepts one or more arguments as well as the following keyword arguments (with their defaults): stdin=None, stdout=None, stderr=None, shell=False.
What is Subprocess in Python? Subprocess is the task of executing or running other programs in Python by creating a new process. We can use subprocess when running a code from Github or running a file storing code in any other programming language like C, C++, etc. We can also run those programs that we can run on the command line.
Since subprocess.run has the ability to perform arbitrary commands on your computer, malicious actors can use it to manipulate your computer in unexpected ways. Now that we can invoke an external program using subprocess.run, let’s see how we can capture output from that program.
Warning: Never pass untrusted input to subprocess.run. Since subprocess.run has the ability to perform arbitrary commands on your computer, malicious actors can use it to manipulate your computer in unexpected ways. Now that we can invoke an external program using subprocess.run, let’s see how we can capture output from that program.
Call () function in Subprocess Python. This function can be used to run an external command without disturbing it, wait till the execution is completed, and then return the output. Its syntax is. subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False, timeout=None)
To execute a batch file in Windows:
from subprocess import Popen
p = Popen("batchfile.bat", cwd=r"c:\directory\containing\batchfile")
stdout, stderr = p.communicate()
If you don't want to execute the batch file, but rather execute the command in your question directly from Python, you need to experiment a bit with the first argument to Popen.
First of all, the first argument can either be a string or a sequence.
So you either write:
p = Popen(r'"C:\Program Files\Systems\Emb Work 5.4\common\bin\run" "C:\Program Files\Systems\Emb Work 5.4\arm\bin\mpr.dll" ... ...', cwd=r"...")
or
p = Popen([r"C:\Program Files\Systems\Emb Work 5.4\common\bin\run", r"C:\Program Files\Systems\Emb Work 5.4\arm\bin\mpr.dll", ...], cwd=r"...")
# ... notice how you don't need to quote the elements containing spaces
According to the documentation:
On Windows: the Popen class uses CreateProcess() to execute the child program, which operates on strings. If args is a sequence, it will be converted to a string using the list2cmdline() method. Please note that not all MS Windows applications interpret the command line the same way: list2cmdline() is designed for applications using the same rules as the MS C runtime.
So if you use a sequence, it will be converted to a string. I would probably try with a sequence first, since then you won't have to quote all the elements that contain spaces (list2cmdline()
does that for you).
For troubleshooting, I recommend you pass your sequence to subprocess.list2cmdline()
and check the output.
Edit:
Here's what I'd do if I were you:
a) Create a simple Python script (testparams.py
) like this:
import subprocess
params = [r"C:\Program Files\Systems\Emb Work 5.4\common\bin\run.exe", ...]
print subprocess.list2cmdline(params)
b) Run the script from the command line (python testparams.py
), copy and paste the output to another command line, press enter and see what happens.
c) If it does not work, edit the python file and repeat until it works.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With