BeNdErR
BeNdErR

Reputation: 17927

Run python file within python script, passing arguments

I've been struggling with this problem for at least 1 hour, now I give up, I need your precious help..

What I'm trying to do, is to run a python script within a python script, passing some arguments.

until now, I've done this using a bat file, like this:

test.bat

...
SET fileName='c:\works\files\file.xml'
SET url='someurl'
SET table='tablename'
c:\Python27\python.exe "C:\Program Files (x86)\Google\google_appengine\appcfg.py" upload_data --config_file=C:\works\config.yaml --filename="%fileName%" --url="%url%" --kind="%table%"

this works great. Now I need to call that script within another python script, like this:

test.py

...
fileName = 'c:\works\files\file.xml'
url = 'someurl'
table = 'tablename'
if(os.path.exists(fileName):
  print 'exists!'
  #launch appcfg.py here!!
else:
  print 'file missing'

the file is correctly found, the 'exists! message is correctly shown, but I don't know how to call that python file now.. I've tryed these two commands, but they don't work (maybe it's the white space in the path? I don't know how to get rit of that..)

first attempt: fail

os.system('c:\Python27\python.exe "C:\Program Files (x86)\Google\google_appengine\appcfg.py" upload_data --config_file=C:\works\config.yaml --filename='+fileName+' --url='+url+' --kind='+table)

second attempt: double fail

subprocess.call(['c:\Python27\python.exe','"C:\Program Files (x86)\Google\google_appengine\appcfg.py" upload_data --config_file=C:\works\config.yaml --filename='+fileName+' --url='+url+' --kind='+table ])

I hope I did not some copy/paste errors, the point is that I don't know how to pass so many arguments to another script, calling it inside the main python script..

I'm in your hands, thanks in advance, best regards

Upvotes: 0

Views: 2660

Answers (3)

kindall
kindall

Reputation: 184385

The reason for your first attempt's failure is obvious:

os.system('c:\Python27\python.exe "C:\Program Files (x86)\Google\google_appengine\appcfg.py" upload_data --config_file=C:\works\config.yaml --filename='+fileName+' --url='+url+' --kind='+table+')

This is a syntax error; you have an extra + sign and apostrophe before the closing parenthesis. In other words, that line should end:

... +table)

The reoson for your second attempt's failure is equally obvious:

subprocess.call(['c:\Python27\python.exe','"C:\Program Files (x86)\Google\google_appengine\appcfg.py" upload_data --config_file=C:\works\config.yaml --filename='+fileName+' --url='+url+' --kind='+table+' ])

It's the same problem as your first, plus you have failed to break up the individual arguments to the command into separate list items as is required by subprocess.call(). You also don't need the double quotes around arguments that contain spaces (these are hints to the shell as to what's an argument; this is not needed here since the shell won't be handling this and you've already broken up the arguments). In other words, it should look more like:

subprocess.call(['c:\Python27\python.exe','C:\Program Files (x86)\Google\google_appengine\appcfg.py', 'upload_data', '--config_file=C:\works\config.yaml',  '--filename='+fileName, '--url='+url, '--kind='+table])

Now you still have a problem... the backslashes. Backslash is an escape character in Python string literals, causing the next character to have a special meaning. Most of the backslashes in your strings do not precede a character with any special meaning so they won't cause any problems... however, there is \a which is converted to ASCII BEL (which beeps the terminal).

There are three approaches for dealing with backslashes, which you need to employ any time you use backslashes in a string literal:

  • Double all your backslashes. Python interprets two backslashes as a single backslash and the following character is not given any special meaning.
  • Use raw string literals by preceding the string literal with r. This causes the backslash to lose its special meaning (well, sorta, it doesn't work quite as you expect if the backslash is the last thing in the string).
  • For Windows pathnames, just use forward slashes instead of backslashes. Windows is happy with either!

Using the third option here, we have:

subprocess.call(['c:/Python27/python.exe','C:/Program Files (x86)/Google/google_appengine/appcfg.py', 'upload_data', '--config_file=C:/works/config.yaml',  '--filename='+fileName, '--url='+url, '--kind='+table])

Starting another Python process is a kind of heavyweight way to do something like this; there may be a better way, such as importing the script and calling its main() method.

Upvotes: 1

ThinkChaos
ThinkChaos

Reputation: 1853

Why don't you import the other python script? You can then pass the correct arguments to it's main function.

Edit: Here's appcfg.py's source. This should help you find what function you need.

Edit 2: Here's some code to help:

import appcfg
appcfg_globals = dict([(var, eval('appcfg.' + var))for var in dir(appcfg)])
# Insert arguments into appcfg_globals
appcfg.run_file_(appcfg.__file__, appcfg_globals)

How it works: dir(module) lists all the variables in 'module' like so:

['__builtins__', '__doc__', '__file__', '__name__', '__package__', [...]]

But we want a dict of the form:

{
 '__builtins__': {[...]},
 '__doc__': [...],
 '__file__': 'C:\Program Files (x86)\Google\google_appengine\appcfg.py',
 '__name__': 'appcfg',
 '__package__': [...],
 [...]
}

So we get the values associated to the names using eval, and associate them to there name in a tuple like this: (variable_name, variable_value). dict() does the rest!

All that's left to do is insert you arguments. I'll let you find that on you own!

Proof this works:

my_test.py:

my_globals = globals()

In Python:

>>> import my_test
>>> my_test.my_globals == dict([(var, eval('my_test.' + var))for var in dir(my_test)])
True

Upvotes: 1

Mahdi Yusuf
Mahdi Yusuf

Reputation: 21038

I would try doing somehting like this.

os.system("appcfg.py arg1 arg2 arg3")

I would look into this portion of the os documentation.

Goodluck.

Upvotes: 0

Related Questions