Thursday, November 17, 2011

How to install cx_Oracle and oracle client on debian

In this post i'm going to explain how to install and use the python lib named cx_Oracle on a debian box. To make things a little more spicy, i will start from the assumption that oracle is not installed on the box, and that i don't want to install a full fledged oracle server on my box.

So after this procedure i will have a minimal install of oracle libs, that means the bare minimum to use cx_Oracle. More precisely, that means no oracle client, no sqlplus will be on that box.

The first step is to download the oracle instant client and the cx_Oracle library that matches. Out of laziness, i decided to use the pre compiled version of cx_Oracle.

Do download oracle instant client, go on oracle website here. Then choose the platform that / library that matches your oracle server. For me it was "instantclient-basiclite-linux32-11.2.0.2.0.zip"

Once you have downloaded that file unzip it and install it. I personnaly chose to install it in (i.e move the unzipped folder) into /usr/local/lib.

Once this done, you need to define two variables:
export ORACLE_HOME=/usr/local/lib/instantclient_11_1
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib/instantclient_11_1

Once this is done, we can move on to install cx_Oracle. I downloaded the RPM version that matches my python and oracle version, in my case cx_Oracle-5.1.1-11g-py26-1.i386.rpm.

Being under debian, RPM is not the favored method to install packages. Fortunately there's an utility that allows to convert RPMs to DEB files called alien. Here's the steps to install alien and cx_Oracle:
# install alien
sudo apt-get install alien

# convert cx_Oracle-5.1.1-11g-py26-1.i386.rpm to cx_Oracle-5.1.1-11g-py26-1.i386.deb and install it
alien -i cx_Oracle-5.1.1-11g-py26-1.i386.rpm



Once that done, there's one last step. This installed cx_Oracle library was installed under /usr/lib/python2.6/site-packages. Unfortunatly by default, site-packages wasn't part of the default python search path. There's several ways to go around that which i won't describe at length (more details here under "Modifying Python’s Search Path"). I chose to modify site.py under /usr/lib/python2.6/ (mostly because it's the first but probably not the last package that will be installed in site-packages).

In order to do that I simply edited site.py and searched for addsitepackages and edited it as follow:
def addsitepackages(known_paths):
    """Add site-packages (and possibly site-python) to sys.path"""
    sitedirs = []
    seen = []

    for prefix in PREFIXES:
        if not prefix or prefix in seen:
            continue
        seen.append(prefix)

        if sys.platform in ('os2emx', 'riscos'):
            sitedirs.append(os.path.join(prefix, "Lib", "site-packages"))
        elif os.sep == '/':
            sitedirs.append(os.path.join(prefix, "local/lib",
                                        "python" + sys.version[:3],
                                        "dist-packages"))
            sitedirs.append(os.path.join(prefix, "lib",
                                        "python" + sys.version[:3],
                                        "dist-packages"))
            sitedirs.append(os.path.join(prefix, "lib", "dist-python"))

            ##################
        # added following line to make site-packages part of default search path
            #################
            sitedirs.append(os.path.join(prefix, "lib",
                                        "python" + sys.version[:3],
                                        "site-packages"))

        else:
            sitedirs.append(prefix)
            sitedirs.append(os.path.join(prefix, "lib", "site-packages"))

        if sys.platform == "darwin":
            # for framework builds *only* we add the standard Apple
            # locations. Currently only per-user, but /Library and
            # /Network/Library could be added too
            if 'Python.framework' in prefix:
                sitedirs.append(
                    os.path.expanduser(
                        os.path.join("~", "Library", "Python",
                                     sys.version[:3], "site-packages")))

    for sitedir in sitedirs:
        if os.path.isdir(sitedir):
            addsitedir(sitedir, known_paths)

    return known_paths

After all that, you should be able to type "import cx_Oracle".