views:

443

answers:

4

I need to execute the command . /home/db2v95/sqllib/db2profile before I can import ibm_db_dbi in Python 2.6.

Executing it before I enter Python works:

baldurb@gigur:~$ . /home/db2v95/sqllib/db2profile
baldurb@gigur:~$ python
Python 2.6.4 (r264:75706, Dec  7 2009, 18:45:15) 
[GCC 4.4.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import ibm_db_dbi
>>> 

but executing it in Python using os.system(". /home/db2v95/sqllib/db2profile") or subprocess.Popen([". /home/db2v95/sqllib/db2profile"]) results in an error. What am I doing wrong?

Edit: this is the error I receive:

> Traceback (most recent call last):  
> File "<file>.py", line 8, in
> <module>
>     subprocess.Popen([". /home/db2v95/sqllib/db2profile"])  
> File
> "/usr/lib/python2.6/subprocess.py",
> line 621, in __init__
>     errread, errwrite)   File "/usr/lib/python2.6/subprocess.py",
> line 1126, in _execute_child
>     raise child_exception OSError: [Errno 2] No such file or directory
A: 

Maybe os.popen is what you're looking for (better yet, one of the popen[2-4] variants)? Example:

import os
p = os.popen(". /home/b2v95/sqllib/db2profile")
p.close() # this will wait for the command to finish
import ibm_db_dbi

Edit: I see that your error says No such file or directory. Try running it without the dot, like so:

os.popen("/home/b2v95/sqllib/db2profile")

If this doesn't work, it might have something to do with your environment. Maybe you're running Python jailed/chrooted?

Felix
`os.popen` is deprecated
SilentGhost
Oh, darn. Didn't see the big red warning. Sorry about that.
Felix
Not only deprecated – never meant to be used this way (to open the pipe and ignor the output). If you just want to run a shell command without communicating with it use `os.system()` or `subprocess.call()`, not `os.popen()`.
Jacek Konieczny
A: 

you need to do:

subprocess.Popen(['.', '/home/db2v95/sqllib/db2profile'], shell=True)
SilentGhost
That may „work” (not raise any exception), but most probably will not do what expected. As the file is 'sourced' it probably sets some environment variables. Those variables will only be set in the shell started by Popen and not visible in the Python script calling.
Jacek Konieczny
This results in:Traceback (most recent call last): File "gagnagrunnur.py", line 14, in <module> import ibm_db_dbi File "/usr/local/lib/python2.6/dist-packages/ibm_db_dbi.py", line 26, in <module> import ibm_dbImportError: libdb2.so.1: cannot open shared object file: No such file or directoryI want to stress that this worked using the command line.
Baldur
@baldur: are you waiting for process to terminate?
SilentGhost
@ SilentGhost: Yes.
Baldur
+6  A: 

You are calling a '.' shell command. This command means 'execute this shell file in current process'. You cannot execute shell file in Python process as Python is not a shell script interpreter.

The /home/b2v95/sqllib/db2profile probably sets some shell environment variables. If you read it using system() function, then the variables will be only changed in the shell executed and will not be visible in the process calling that shell (your script).

You can only load this file before starting your python script – you could make a shell wrapper script which would do . /home/b2v95/sqllib/db2profile and execute your python script.

Other way would be to see what the db2profile contains. If that are only NAME=value lines, you could parse it in your python script and update os.environ with the data obtained. If script does something more (like calling something else to obtain the values) you can reimplement whole script in Python.

Update An idea: read the script into python, pipe it (using Popen) to the shell, after the script write env command to the same shell and read the output. This way you will get all the variables defined in the shell. Now you can read the variables.

Something like this:

shell = subprocess.Popen(["sh"], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
script = open("/home/db2v95/sqllib/db2profile", "r").read()
shell.stdin.write(script + "\n")
shell.stdin.write("env\n")
shell.stdin.close()
for line in shell.stdout:
    name, value = line.strip().split("=", 1)
    os.environ[name] = value
Jacek Konieczny
Ah, good point-- db2profile does indeed set shell environment variables. Unfortunately I can't call the python script using a shell wrapper (due to the nature of the project), the db2profile is long and includes some moderately complicated functions and (you guessed it) environmental variables. How would I go about running the entire file in Python?
Baldur
I.e. is it possible to run a BASH script with a lot of assignments, environmental variables and functions within Python? Or will I have to rewrite the entire code in Python?
Baldur
I got an idea how it could be done: see the update to my post.
Jacek Konieczny
Odd... it outputs: """Traceback (most recent call last): File "<file>.py", line 14, in <module> shell = subprocess.Popen(["sh"], stdin=subprocess.pipe, stdout=subprocess.pipe)AttributeError: 'module' object has no attribute 'pipe'"""
Baldur
That was my mistake (the constant is named 'PIPE' not 'pipe'), already fixed.
Jacek Konieczny
It the script only needs to be executed to set the environ variables, then you could try running it in a subshell and doing an 'env' at the end to output the environ settings. Read this output in the python parent process, parse and set sys.env from those settings.
Steven D. Majewski
A: 

Not sure what OS you are working on and what DB2 version you are using. The newer versions (at least 9.5 and above, not sure about 9.0 or 9.1) work by setting db2clp to **$$**. Since the DB2 usually is a LUW it might work under linux/unix too. However, under AIX I need to run the profile script to connect to the right DB instance. Haven't checked too much into what that script does.

Peter Schuetze