views:

1933

answers:

7

I have a Python script that calls an executable program with various arguments (in this example, it is 'sqlpubwiz.exe' which is the "Microsoft SQL Server Database Publishing Wizard"):

import os

sqlpubwiz = r'"C:\Program Files\Microsoft SQL Server\90\Tools\Publishing\sqlpubwiz.exe"'
server = 'myLocalServer'
database = 'myLocalDatabase'
connection_values = ['server=' + server, 'database=' + database, 'trusted_connection=true']
connection_string = ';'.join(connection_values)
dbms_version = '2000'
sqlscript_filename = 'CreateSchema.sql'

args = [
        sqlpubwiz,
        'script',
        '-C ' + connection_string,
        sqlscript_filename,
        '-schemaonly',
        '-targetserver ' + dbms_version,
        '-f',
]

cmd = ' '.join(args)
os.system(cmd)

This code runs properly but I have would like to get into the habit of using subprocess since it is intended to replace os.system. However, after a few failed attempts, I can not seem to get it work properly.

How would the above code look like if it was converted to use subprocess in place of os.system?

+3  A: 
import subprocess
p=subprocess.Popen(args, stdout=subprocess.PIPE)
print p.communicate()[0]

It would look pretty much the same. But the path should not be r'"whatever the path is"'. Because that gives me an error. You want "the path with escaped backslashes" or r'the path without escaping'.

Also args should be of the form ['-arg', 'args'] instead of ['arg argsval'].

Carlos Rendon
I tried that but I get the following error: WindowsError: [Error 3] The system cannot find the path specified
Ray Vega
I think Popen takes args as a sequence, not a big space-separated string. Try just passing 'args' instead of 'cmd'.
Jay Conrod
Removing the quotes allowed the script to execute without error but no sql file was created. How can I see the console output of an exe?
Ray Vega
Now that I see the error from sqlpubwiz exe. It is showing: >Missing/wrong number of arguments.>Unrecognized command line argument '-targetserver 2000'btw, I'm using 'args' list and not 'cmd'. Not sure why sqlpubwiz doesn't like how arguments are being passed to it using subprocess vs os.system?
Ray Vega
(This is why I have not been having much luck with subprocess vs just using os.system)
Ray Vega
I bet it wants the commands as ['-targetserver', '2000'] instead of with the spaces.
Carlos Rendon
Yes! That fixed it and it works. Thanks!!
Ray Vega
+3  A: 

Remove quotes from the name of the executable. On the first line of your example, instead of

sqlpubwiz = r'"C:\Program Files\Microsoft SQL Server\90\Tools\Publishing\sqlpubwiz.exe"'

use:

sqlpubwiz = r'C:\Program Files\Microsoft SQL Server\90\Tools\Publishing\sqlpubwiz.exe'

That's because you don't have to escape anything since a shell won't be involved.

Then just use subprocess.call(args) (don't join the args, pass them as a list)

If you want to capture the output (os.system can't do it) just follow subprocess documentation:

result = subprocess.Popen(args, stdout=subprocess.PIPE).communicate()[0]
print result
nosklo
using subprocess.call(args) gives me the same error as Carlos Rendon: >Missing/wrong number of arguments. >Unrecognized command line argument '-targetserver 2000'.
Ray Vega
Do the args values need to be different somehow for subprocess as opposed to how it is built up in a string command for os.system?
Ray Vega
A: 

Please remember that os.system uses the shell, and so you must really pass

shell=True

to the Popen constructor/call to emulate it properly. You may not actually need a shell, of course, but there it is.

Ali A
-1 for using shell=True to add complexibility not needed.
nosklo
Just answering the question :)
Ali A
just voting on it ;)
nosklo
Haha, fair enough.
Ali A
A: 

This isnt an answer directly to your question but I thought it might be helpful.

In case you ever want more granular control over what is returned for exception handling etc, you can also check out pexpect. I have used it in situations where the process I was calling didn't necessarily exit with normal status signals, or I wanted to interact with it more. It's a pretty handy function.

Scanningcrew
+2  A: 

Below is my revised code based on Carlos Rendon (and nosklo) help and suggestions:

# import os
import subprocess    

sqlpubwiz = r'C:\Program Files\Microsoft SQL Server\90\Tools\Publishing\sqlpubwiz.exe'
server = 'myLocalServer'
database = 'myLocalDatabase'
connection_values = ['server=' + server, 'database=' + database, 'trusted_connection=true']
connection_string = ';'.join(connection_values)
dbms_version = '2000'
sqlscript_filename = 'CreateSchema.sql'       

args = [
            sqlpubwiz,
            'script',
            '-C',
            connection_string,
            sqlscript_filename,
            '-schemaonly',
            '-targetserver',
            dbms_version,
            '-f',
    ]   

# cmd = ' '.join(args)
# os.system(cmd)

subprocess.call(args)

(Note: The original argument values that contained spaces needed to be converted into separate list items.)

Ray Vega
Use `subprocess.call_check(args)` to catch possible errors.
J.F. Sebastian
+2  A: 

FYI, subprocess has a list2cmdline() function that will let you see the string that Popen will be using.

Your version gives:

'"C:\\Program Files\\Microsoft SQL Server\\90\\Tools\\Publishing\\sqlpubwiz.exe" script "-C server=myLocalServer;database=myLocalDatabase;trusted_connection=true" CreateSchema.sql -schemaonly "-targetserver 2000" -f'

with extra quotes around "-C server=myLocalServer;database=myLocalDatabase;trusted_connection=true" and "-targetserver 2000".

Properly formatted:

args = [
        sqlpubwiz,
        'script',
        '-C', connection_string,
        sqlscript_filename,
        '-schemaonly',
        '-targetserver', dbms_version,
        '-f',
]

gives:

'"C:\\Program Files\\Microsoft SQL Server\\90\\Tools\\Publishing\\sqlpubwiz.exe" script -C server=myLocalServer;database=myLocalDatabase;trusted_connection=true CreateSchema.sql -schemaonly -targetserver 2000 -f'

Also, minor point, but it's a good habit to make sequences such as args that don't need to be mutable into tuples instead of lists.

pantsgolem
A: 

Windows commands will accept forward slashes '/' in place of backslashes in pathnames, so you can use the former to avoid escaping backslashes in your command strings. Not exactly an answer to your question, but perhaps useful to know.

Jeff Bauer