Installing Oracle Client on Ubuntu 11.10

Oracle Logo(Another post written for personal documentation)

Get Software

Download these three packages from Oracle for the proper operating system (32 bit for me):

  • Instant Client Basic-Lite
  • Instant Client SDK
  • Instand Client SQLPlus

Unzip and copy to /opt/oracle/11_2/instantclient

Set LD_LIBRARY_PATH

Create /etc/ld.so.conf.d/oracle_instantclient.conf:

#Oracle client LD_LIBRARY_PATH setting
/opt/oracle/11_2/instantclient

Update cache:

sudo ldconfig -v

Symbolic Link to Library

ln -s libclntsh.so.10.1 libclntsh.so

Set ORACLE_HOME

export ORACLE_HOME=/opt/oracle/11_2/instantclient

Install Python Library

The library is called cx-oracle. Use your favorite installation method. (Don’t forget about your virtual environment!)

That’s It

Hope I remembered everything.

UPDATE

Found another post that outlines the procedure maybe a little better than I did, and includes notes on setting up tnsnames.ora. See Install Oracle Instant Client 11.1 and cx_Oracle 4.4 on Ubuntu 8.04 on Technoblog.

My Eclipse Setup for Django

Eclipse LogoDocumenting my Eclipse setup as I install onto a fresh Ubuntu 11.04 machine.

First, is the choice of Eclipse package. There are several that will work for Python/Django – basically any of the Language IDE focused bundles. This time I am using the Java EE setup (v3.7.1), but I have also installed the standard Java and C/C++ builds with success.

I wish that there was an install procedure for Eclipse that would setup the menus, etc. The package available in the Ubuntu Software Center is usually an older version (currently 3.5) and is a basic install only. It is up to the user to add the additional features desired. Instead, I download the package, extract to /opt, and setup the menus myself.

Next is Aptana Studio 3. This includes PyDev (which supplies Python and Django functionality), web tools, Ruby support, and other goodies. For Python/Django support only, I have used the standalone PyDev install instead. However, once PyDev is installed, the Aptana install complains if installed later.

Also important is version control support. Eclipse comes with CVS included, and clients for other systems are available. Since I use Subversion, I install the Subclipse add-in from Tigrs. Check the version numbers of both your Eclipse and svn installs to select the correct Subclipse package. Eclipse will complain about JavaHL not being available the first time SVN is used. There is a setting in Eclipse (under Team/SVN) to switch to the SVNKit client.

I have also used Eclipse SQL Explorer for database access. It is a bit of a fight to get the proper drivers and configuration all figured out, but worth it to have DB commands within the Eclipse environment here. Read more about SQL Explorer in this earlier post.

That is pretty much it. I may at a later date talk about setting up virtual environments in Eclipse, so stay tuned.

Any questions or suggestions? Please post a comment below.

And As If Version Upgrades Weren’t Enough…

In addition to the Django version upgrades I’m in the middle of, I also am facing a scheduled upgrade of the Oracle version used by my apps. They share an Oracle instance with the enterprise application that runs the business, so these smaller systems upgrade on the big guy’s schedule.

Currently, all run on Oracle 10g, and the DB platform upgrades to 11g in July. Shouldn’t be a big deal, but I don’t have enough experience with the Oracle client running on the web servers, or with the Python interface to Oracle.

This project starts next week.

Base64 Encoding of Images

Today I’m working on an XML feed of events into an enterprise calendar program.  One of the requirements is the base64 encoding of accompanying images. My system gives the option to store the URL to a photo, not to store the image locally.  A bit of a shortcut I know, but I didn’t want to mess with the bureaucracy of the server team to work out the storage a backup of the images.  Luckily, it’s no big deal to Python either way. For a locally stored images, one can convert to base64 pretty easily, given the file name.  Try this:

import base64

image = 'example.jpg'
image_64 = base64.encodestring(open(image,"rb").read())

Not much different working with a URL, as urllib provides the urlopen method to present an online resource with a .read() function:

import base64, urllib

image = urllib.urlopen('http://docs.python.org/_static/py.png')
image_64 = base64.encodestring(image.read())

In this example, I’m using the location of the little Python symbol on the top left of most python.org pages.  Even this small graphic converts to a lot of base64 characters.  Here is the result:

iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A
/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9gEGxE4IQYzJ14AAAI3SURBVDjL
ZZNPSFVBFIe/e9+zd3silBCl0SZoU4s2rVq0EB5tQip4UNvATVGu3QRBiyAi2iltWkgbF5EgRhFF
RpiWtrWIzDIV1Pzz7p15M2fmtvDevOqBw8DM9zvnN8ycgF3R/eDtM2mac96ZdrFNxBikqbRV+vHH
/ut9gAZczoe7C3gnF0f6au1OLM5avFi8d1Ea+JvAMSAq8nsKOGs5f2cYJ3Y7rc2PO4BqkS8DdD98
f9tbe1ysCoxOBo1qlEXHJWcM4b5KPU19zleA0o4Clx99eO3EdqVewHsCoFRugUoVghJO7A6H6Vx9
wdtYi27cr5x6dy/03nVtWTU7bWeZh6jNUcAiCaFTURl9A+gs56AviHzh3mnqtdPxm6knfQPLU7Ua
okASQq/agY7yDrG16Mba6Pz48NP56VdrgAApYObGaicPtkovToFLQBKA/WUxTe3FRk4san15aGKg
d3Dj560rrdGJS6FT0X9YYvLuiMKL1kAQOpHZ3PqfyZfP41+9PW1VfzX0RXFSECfgNEmSTgImdDru
F2O0E8vvqZG1auQubAsKooIYYHpGvwA2g+xndQBHgWa6cG0ih5cW/w6VvEq3nChwCoBvs+bL2Z7V
ceBHGTDAIrABpMVuhw+4OiLgLIglOLPYBTQAlfErIeCzjRVg1dtEb1kt5Omv+DTV2YssAN+zNdkz
C42N9brV8WdvYp07seOdM2Of1F3AAknW0AJpwN6IgEPAEaANaMlcbmZdl7KRBuAfAb+v//yMAJoA
AAAASUVORK5CYII=

My application doesn’t put any limitations on the size of the image being linked, so I may have to add logic to resize it to something sensible for the receiving program.  I surely don’t need a 5MB image in my XML stream!  Watch this space for updates. Finally, I need to put this converted data into the XML output.  Template tags to the rescue! In tempplatetags/filters.py:

@register.filter
def b64(url):
    import base64, urllib
    if url:
        try:
            i = urllib.urlopen(url)
            return base64.encodestring(i.read())
        except:
            return None
    return None

This tag will try to open the url and convert the contents.  Not much error checking here.  If it doesn’t work, the value of None is returned. An this is an example template file, called ucal.xml:

{% load filters %}<!--?xml version="1.0" encoding="utf-8"?-->

...

{% if e.photo_link %}{{ e.photo_link|b64 }}{% endif %}

(Note that the {% load filters %} directive is on the same line as the xml version declaration.) The b64 filter takes the supplied URL and returns the base64 encoded version.

UPDATE:

Learned that the calendar can also just take a URL to the photo as input. Oh well, at least I got to learn something new.

Using the Python iCalendar Library

An application I’m working on uses the icalendar library (http://codespeak.net/icalendar/) to generate an ICS file of upcoming events that can be linked to another calendar program (I’ve tried Outlook and Google Calendar). One problem I was having was that I was unable to generate time zone aware times. Mine were all naive – also called ‘floating’ times – that would appear the same regardless of the calendar program’s timezone.

What I was trying to do was to create a new time zone in the ICS file, and then append the TZID parameter to each date/time value. It was not happening.

So, I dug into the source code for icalendar. This library is well documented with tests, and I soon found a solution – include a tzinfo value when supplying the date/time and icalendar will convert it to UTC and append a ‘Z’ to the end of the time to indicate this. icalendar supplies a class called LocalTimezone that can be used for this purpose. I tried it, and it worked! Here’s a simplified version of my code:

    from icalendar import Calendar, Event
    from datetime import datetime
    from icalendar import LocalTimezone   

    cal = Calendar()

    cal.add('version', '2.0')
    cal.add('prodid', '-//test file//example.com//')
    cal.add('X-WR-CALNAME','Test Calendar ' )

    lt = LocalTimezone() # we append the local timezone to each time so that icalendar will convert
                         # to UTC in the output

    for ent in queryset:
        event = Event()
        event.add('summary', ent.event_name)
        event.add('dtstart', datetime.combine(ent.event_date,ent.start_time).replace(tzinfo=lt))
        event.add('dtend', datetime.combine(ent.stop_date,ent.stop_time).replace(tzinfo=lt))
        event.add('dtstamp', ent.updated_on.replace(tzinfo=lt))
        event['uid'] = ent.pk  # should probably use a better guid than just the PK
        event.add('priority', 5)

        cal.add_component(event)

    return cal

And this is a sample event from the output:

BEGIN:VEVENT
DTEND: 20100714T184500Z
DTSTAMP:20100714T185936Z
DTSTART:20100719T174500Z
PRIORITY:5
SUMMARY:Gateway Production
UID:66
END:VEVENT

Note that my 1:45pm event in the US Eastern time zone (EDT) shows as 1745 in UTC.

Changing Hosts in Dreamhost

Dreamhost logoLast night, Dreamhost moved my account to a new host. Not a big deal, and it’s certainly understandable, but it did break my one running Django app – the Gentryart Gallery. Here’s what I did to fix it.

First, as suggested in the Dreamhost Server Moves Page, I recompiled Python to create a 64bit version. While I was at it, I upgraded from v2.5.2 to v2.6.5. This great page by Ryan Kanno outlined the steps. I just changed the version number. I also deleted my old installation of Python so there wouldn’t be any chance of confusion there.

Now, if I would have used the same python version and kept everything in the same locations, I would have been done. Since I didn’t, I had a little more to do.

Next, I needed to install all of the python packages I use. Here’s the list:

Following the famous Jeff Croft post, I updated the admin_media shortcut to point to the new Django files.

And the gallery is back in business!