19

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))
Robert MacLean
  • 38,975
  • 25
  • 98
  • 152
binaryguy
  • 1,167
  • 3
  • 12
  • 29
  • Can you post some actual code that you used? – Greg Hewgill Nov 30 '09 at 09:47
  • 1
    @ wanderameise: Do not post information that clarifies the question as an "answer". It is NOT an answer. It's important information that must be part of the question so that we can help. Please DELETE your non-answer, and UPDATE your question with the additional information. – S.Lott Nov 30 '09 at 15:24
  • What happens if you call the batch like: `cmd.exe /c batchfile.bat`? Of course, you'd replace batchfile.bat with the path to your file. – Geo Nov 30 '09 at 19:24
  • 1
    I believe you can pass params directly to Popen (p = subprocess.Popen(params)), since list2cmdline is called internally by Popen. – codeape Dec 01 '09 at 09:47

2 Answers2

28

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.

codeape
  • 97,830
  • 24
  • 159
  • 188
  • regarding to your second proposal: [Error 193] %1 is not a valid Win32 application – binaryguy Nov 30 '09 at 12:03
  • Update your question with a code snippet that reproduces the error. – codeape Nov 30 '09 at 19:21
  • Thanks for this, but it would be a bit more clear if you show that the .bat file should be written as an absolute path...it's not so clear, given that the absolute path is required for the directory already (It took me a minute to figure that out) – JasonBK Aug 12 '15 at 12:59
0

First, you don't need all those quotes. So remove them. You only need quotes around parameters that have a filename when that filename has a space (stupidly, Windows does this often).

Your parameters are simply a list of strings, some of which need quotes. Because Windows uses non-standard \ for a path separator, use "raw" strings for these names.

params = [
    r'"C:\Program Files\Systems\Emb Work 5.4\arm\bin\mpr.dll"',
    r'"C:\Program Files\Systems\Emb Work 5.4\arm\bin\ajl.dll"',
    r'"C:\Documents and Settings\USER\Desktop\abc.out"',
    "--backend",
    "-B", 
    "--endian=little",
    "--cpu=Cortex",
    "--fpu=None",
    "-p",
    r'"C:\Program Files\unknown\abc.ddf"',
    "--drv_verify_download",
    "--semihosting",
    "--device=STM32F10xxB",
    "-d",
    "jjftk",
    "--drv_communication=USB0",
    "--speed=auto",
    "--initial_speed=32",
    "--reset_strategy=0,0"]

Use something like

program = r'"C:\Program Files\Systems\Emb Work 5.4\common\bin\run"'
subprocess.Popen( [program]+params )
codeape
  • 97,830
  • 24
  • 159
  • 188
S.Lott
  • 384,516
  • 81
  • 508
  • 779
  • WindowsError: [Error 3] The system cannot find the path specified – binaryguy Nov 30 '09 at 11:52
  • Which one? Please provide details by updating your question. – S.Lott Nov 30 '09 at 15:25
  • 1
    @S.Lott: I belive you should not quote the params containing spaces (in this case params[0], [1], [2] and [9]. subprocess.list2cmdline will quote parameters as needed when building the string that is passed to CreateProcess – codeape Nov 30 '09 at 19:19
  • @codeape: I think it depends on the shell=True vs. shell=False setting. shell=True requires the extra filename quotes. shell=False does not. In windows, I'm usually happier with shell=True setting. – S.Lott Nov 30 '09 at 19:38
  • @S.Lott: I tried this it on my Windows box. From my testing, it looks like the extra filename quotes cause an error, both with shell=False and shell=True. Testcase: http://pastebin.com/f3e06f80b – codeape Dec 01 '09 at 09:58