from spam import eggs, spam at runtime, how?

R

Rene Pijlman

How do I do:

from spam import eggs

.... when 'spam' is only known at runtime?
 
S

Skip Montanaro

Rene> How do I do:
Rene> from spam import eggs

Rene> ... when 'spam' is only known at runtime?

help(__import__)

Skip
 
R

Rene Pijlman

Aahz:
spam = __import__('spam')
eggs = spam.eggs

Hmm... my spam is a package and eggs is a module. This code gives me:

AttributeError: 'spam' module has no attribute 'eggs'

But it works like this:

spam = __import__('spam',globals(),locals(),['eggs'])
eggs = spam.eggs

Thanks for putting me on track. Skip to.
 
F

Fredrik Lundh

Rene said:
Hmm... my spam is a package and eggs is a module. This code gives me:

AttributeError: 'spam' module has no attribute 'eggs'

But it works like this:

spam = __import__('spam',globals(),locals(),['eggs'])
eggs = spam.eggs

or:

spam = __import__('spam.eggs')
eggs = spam.eggs

</F>
 
R

Rene Pijlman

Fredrik Lundh:
Rene Pijlman:
But it works like this:

spam = __import__('spam',globals(),locals(),['eggs'])
eggs = spam.eggs

or:

spam = __import__('spam.eggs')
eggs = spam.eggs

Yes, and a bit more elegant (pythonic?). Thanks.
 
G

Ganesan R

Fredrik" == Fredrik Lundh said:
spam = __import__('spam.eggs')
eggs = spam.eggs

Is there a way to do this if I don't know about "eggs" beforehand. I have
some code which needs to import a DB module dynamically. The module could be
'PyPgSQL.PgSQL' or 'sqlite'. Is there a sane way to do this without exec?

Ganesan
 
G

Ganesan R

Is there a way to do this if I don't know about "eggs" beforehand. I have
some code which needs to import a DB module dynamically. The module could be
'PyPgSQL.PgSQL' or 'sqlite'. Is there a sane way to do this without exec?

db = __import__(dbname, globals(), locals(), ["connect"]) works. The last
argument just needs to be a non-empty list. __import__ does not seem to do
anything with it.

Ganesan
 
F

Fredrik Lundh

Ganesan R said:
Is there a way to do this if I don't know about "eggs" beforehand. I have
some code which needs to import a DB module dynamically. The module could be
'PyPgSQL.PgSQL' or 'sqlite'. Is there a sane way to do this without exec?

here's one way to do it:

dbapi = __import__(dbname)
for p in name.split(".")[1:]:
dbapi = getattr(dbapi, p)

notes:

- when given a package, __import__ imports all components, but
returns a reference to the toplevel module).

- you may still need DB-specific code to connect to the database

</F>
 
J

John J. Lee

Rene Pijlman said:
How do I do:

from spam import eggs

... when 'spam' is only known at runtime?

Why not just stick the import statement where you need it?

def do_something_that_needs_spam_module():
import spam
...


John
 
R

Rene Pijlman

John J. Lee:
Rene Pijlman:

Why not just stick the import statement where you need it?

Because I need a module from one of a number of different packages, at one
specific point in my code.

The modules are Cheetah templates (http://www.cheetahtemplate.org/) in
different skins of a website. I've made one package per skin, and my
website generator basically does:

from skin import template

where skin is only known at runtime (it's passed as a parameter or hidden
field to my mod_python application).

The alternative would be:

if skin == 'basic':
from basic import homepage
elif skin == 'modern':
from modern import homepage

.... but this is unmaintainable and unpythonic.
 
P

Paul Rubin

Rene Pijlman said:
Because I need a module from one of a number of different packages, at one
specific point in my code.

I still don't understand why you don't want to use an exec statement
for this. That's by far the most natural and understandable way to do it.
 
P

Peter Hansen

Paul said:
I still don't understand why you don't want to use an exec statement
for this. That's by far the most natural and understandable way to do it.

In this case, he's getting the actual string from the web, so I wouldn't
be surprised if exec would be a real can of security worms.

-Peter
 
P

Peter Hansen

Rene said:
The modules are Cheetah templates (http://www.cheetahtemplate.org/) in
different skins of a website. I've made one package per skin, and my
website generator basically does:

from skin import template

where skin is only known at runtime (it's passed as a parameter or hidden
field to my mod_python application).

The alternative would be:

if skin == 'basic':
from basic import homepage
elif skin == 'modern':
from modern import homepage

... but this is unmaintainable and unpythonic.

Unmaintainable as-is, perhaps, but pythonicism has nothing to do with this.

What is probably cleaner *and* more maintainable is to have an extra level
of indirection, with some kind of configuration file that in effect maps
between the skin names and the Python package which implements it. I'd
personally do this with a quick bit of XML, but I've been drinking too
much Koolaid(tm) so ignore me.

The problem I see with the above approach is that you are tying some
strings that are used in your HTML pages directly to the names of Python
modules. Unless you are doing this in an entirely automated fashion
(e.g. generating the list of available skins via a directory scan) then
you are increasing the coupling in your system inappropriately, and
*that* is certain to be the least maintainable approach of all, IMHO.

-Peter
 
J

Just

Peter Hansen said:
In this case, he's getting the actual string from the web, so I wouldn't
be surprised if exec would be a real can of security worms.

Also, __import__ returns a module object, so you don't have to pull it
out of the globals you passed to exec. Compare:

g = {}
exec "import %s" % modulename in d
m = g[modulename]

with

m = __import__(modulename)

Just
 
P

Paul Rubin

Yuch. Although, the string can be checked against the list of available
modules before exec'ing.
Also, __import__ returns a module object, so you don't have to pull it
out of the globals you passed to exec. Compare:

g = {}
exec "import %s" % modulename in d
m = g[modulename]

I think I'd have used

exec "import %s as mymod"% modulename
with
m = __import__(modulename)

OK, that's not as ugly as some of the other stuff I've seen going by.
I guess it's better than an exec, if you can now just say m.whatever.
 
S

Stuart Bishop

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1


from skin import template

where skin is only known at runtime (it's passed as a parameter or
hidden
field to my mod_python application).

That is scary - you need to treat anything arriving from the client
as an attack. Consider what would happen if someone accessed the url:
http://whatever/myapp?skin=test.testall

Maintaining a blacklist is impossible, as new modules may be installed
in the future.
The alternative would be:

if skin == 'basic':
from basic import homepage
elif skin == 'modern':
from modern import homepage

... but this is unmaintainable and unpythonic.

It is also correct IMHO, although you would be better off
using a dictionary mapping string -> module, so you could just do:

try:
homepage = skinmod[skin]
except KeyError:
raise ValueError, 'No such skin: %r' % (skin,)

You may want to use the import tricks elsewhere in this thread to
build this dictionary though, for instance by doing an os.listdir() on
your 'skins' directory.


- --
Stuart Bishop <[email protected]>
http://www.stuartbishop.net/
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.3 (Darwin)

iD8DBQE/1nZaAfqZj7rGN0oRAlxqAJ4kf+Dm2BBkEhKJpIpokWAxhDPSLACePJlJ
PKgunqahsWAYzuCHmcvXoxo=
=bKfh
-----END PGP SIGNATURE-----
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

Forum statistics

Threads
473,731
Messages
2,569,432
Members
44,835
Latest member
KetoRushACVBuy

Latest Threads

Top