Learning Python: module import issues

So I’ve taken it upon myself to learn Python, which is something I’ve wanted to do for a while. I usually write code in PHP or shellscript, with the odd thing in Perl every once in a while (but I’m not a real big fan of perl and I don’t have the desire to dig into it more). A lot of my more sophisticated projects that can’t be done in shellscript are usually done with CLI PHP. But Python is something I’ve wanted to learn, so I’ve started digging into it and my first dive is rewriting a CLI PHP program “suite” that creates and scours a database for RPM information (dependencies, requires, files, etc.).

I’ve been at it for about 2 weeks now with what little time I have and the original suite consists of two programs: rqp and rqs. These two programs were a result of a rewrite of the “srpm” PHP program that Stew Benedict wrote years ago for the Mandriva secteam (and which has proven invaluable of the years). It handled only src.rpm files, so I rewrote and extended it to handle binary and source rpm files (rqp and rqs respectively). It was a quick-n-dirty extension that was used for a few years on the Mandriva secteam and worked really well (and probably is still working well for them).

I’ve gotten rqp converted to Python and it’s working quite well. Because rqp and rqs share a *lot* of functions, I wanted to write rqp.py and rqs.py and have a shared module between them (rq.py) and this is where I’m having issues. Does anyone know how to have a module get access to an object from the calling program? For instance, rqp uses the optparse module to nicely handle the commandline arguments, but a lot of the modules use options.foo to look up arguments that were passed. The functions in rq.py (the module) can’t seem to get the value of options, and while I could put the optparse stuff in the module, it would leave the actual rqp and rqs programs really really small (and I’d have to either put in two functions because the two programs use different syntax). So I’ve got in rqp.py:

import rq

which works ok, but if rq.db_connect() requires options.database (for instance), it can’t get it. So in rq.py, I tried doing a circular import or whatever it’s called by doing:

import options from rqp

But this doesn’t want to work either. The output looks quite sad:

% ./rqp.py -d
rqp 0.2 ($Id: rqp 275 2009-03-07 22:34:15Z vdanen $)

Traceback (most recent call last):
  File "./rqp.py", line 548, in 
    import rq
  File "/Users/vdanen/svn/scripts/rq/trunk/rq.py", line 11, in 
    from rqp import options
ImportError: cannot import name options

There has to be a way to make the options variable (and one or two others I think) accessible to the module, but I haven’t been able to find a way to do it. Does anyone know how this can be accomplished?

4 Comments

  1. Eugeni

    I think you cannot import this unless “options” is a class, but you can do “from rqp import *”, and then “options” will be placed into global namespace.

    Or even better, create a different “options.py” file, put shared stuff into it, and just use “import * from options”.

    OR you could do “import rqp”, and then access options as “rqp.options”.

    Mar 08, 2009 @ 15:39:38
  2. greg

    Without seeing the full code this is my guess:

    The best way I can think to do that would be to make rq.db_connect() have the argument database. Them you would just call “rq.db_connect(options.database)” In theory you could do “rq.options = options”, but I don’t think this is the best way to go. You seem to be trying to get it to behave a tad more automagically, and while I see the point, but I don’t know that there is a “right” way to accomplish that magic. I’d like to know if there is.. i’ve been using python for almost 2 years now and doubt i’ll ever stop learning *shrug*

    Mar 08, 2009 @ 15:45:42
  3. vdanen

    Eugeni: you might be right, but I haven’t even gotten to classes yet… =) There are no classes defined.

    Greg: well, you’ve got about 1 year and 11mos on me with python. =) I was thinking of passing the options as an argument to the function, and maybe that’s what I’ll have to do, but there are a lot of functions that use these options.* variables (stuff like options.debug, options.verbose, and a lot more), which would be painful to do. I suppose if there is no other way to do it, it might be the best way and I’ll have to get away from the PHP-isms of defining stuff anywhere I like it and having it accessible all over the place.

    Thanks for the comments.. they’ve given me a few ideas for sure.

    Mar 08, 2009 @ 16:18:39
  4. greg

    I played with it a bit, and name space is seems to really be the full issue. I had the same issue when I went from PHP to Python. Namespace is much stricter than in PHP. You can try the 2nd option I gave, it should in theory work, but if you have flaky issues, thats why. Inside the function rq.db_connect() the options it is looking for is actually rq.options because it has been imported. I believe Eugeni’s suggestion about “from rq import *” would solve the issue as well, because nothing would be prefixed w/ “rq.” But you can import non-class objects from modules. (open a python console and enter “from os import R_OK” and then look at R_OK).

    I personally like being able to pass my options around as well (and some people would argue that its not wise to abstract what a function requires, but when you need over 5 variables adding them all is a pita too). To that end usually I will make options the argument for the function, and in one case I made a “Variables” holder object that I could store everything in and just pass around. Once its an object its nice that you don’t have to return it because its mutable (am i phrasing this correctly?), so changes in functions it is passed to exist outside the function.

    Mar 09, 2009 @ 06:16:00

Leave a Reply

*