views:

820

answers:

3

Hi all,

Say there is a folder '/home/user/temp/a40bd22344'. The name is completely random and changes in every iteration.

I need to be able to import this folder in python using fixed name, say 'project'.

I know I can add this folder to sys.path to enable import lookup, but is there a way to replace 'a40bd22344' with 'project'?

May be some clever hacks in init.py?

Added:

It needs to be global - i.e. other scripts loading 'project' via standard

import project

Have to work properly, loading a40bd22344 instead.

Thanks!

+8  A: 

Sure, project = __import__('a40bd22344') after sys.path is set properly will just work.

Suppose you want to do it in a function taking the full path as an argument and setting the global import of project properly (as well as magically making import project work afterwards in other modules). Piece of cake:

def weirdimport(fullpath):
  global project

  import os
  import sys
  sys.path.append(os.path.dirname(fullpath))
  try:
      project = __import__(os.path.basename(fullpath))
      sys.modules['project'] = project
  finally:
      del sys.path[-1]

this also leaves sys.path as it found it.

Alex Martelli
I've just added a clarification to my question, will it work in this case as well?
Art
Alex, put the __import__ statement in a try..finally bracket, so as to ensure that sys.path is always correctly restored.
krawyoti
@Art, as @krawyoti says that's accomplished by sticking it in sys.modules[project] as @krawyoti says. @krawyoti, good advice -- let me edit to reflect these two changes.
Alex Martelli
+7  A: 

Here's one way to do it, without touching sys.path, using the imp module in python:

import imp

f, filename, desc = imp.find_module('a40bd22344', ['/home/user/temp/'])
project = imp.load_module('a40bd22344', f, filename, desc)

project.some_func()

Here are links to some good documentation on the imp module:

http://docs.python.org/library/imp.html

http://blog.doughellmann.com/2008/02/pymotw-imp.html

ars
This doesn't touch sys.path but I think using imp causes the package to be reloaded every time this code is executed. I'd prefer Alex's solution because it does the right thing even if executed multiple times.
Jon-Eric
+5  A: 

You first import it with import:

>>> __import__('temp/a40bd22344')
<module 'temp/a40bd22344' from 'temp/a40bd22344/__init__.py'>

Then you make sure that this module gets known to Python as project:

>>> import sys
>>> sys.modules['project'] = sys.modules.pop('temp/a40bd22344')

After this, anything importing project in the current Python session will get the original module

>>> import project
>>> project
<module 'temp/a40bd22344' from 'temp/a40bd22344/__init__.py'>

This will work also for sub-modules: if you have a foobar.py in the same location you'll get

>>> import project.foobar
>>> project.foobar
<module 'project.foobar' from 'temp/a40bd22344/foobar.py'>

Addendum. Here's what I'm running:

>>> print sys.version
2.5.2 (r252:60911, Jul 31 2008, 17:28:52) 
[GCC 4.2.3 (Ubuntu 4.2.3-2ubuntu7)]
krawyoti
Excellent, that's what I need, thanks!
Art
Excellent, except for the little detail that it does not work: in Python 2.6 and 3.1 it says "ImportError: Import by filename is not supported.", in 2.5 just "ImportError: No module named temp/a40bd22344", on the __import__ (just tried all three on my Mac to confirm I hadn't forgotten how __import__ works!-). I assume it works on your platform, krawyoti, and yours, Art, or you wouldn't have marked it as accepted, so I'm curious: what platforms are those?
Alex Martelli
Well it stands to reason that this loophole in __import__ I was using was fixed. Lazy of me not to try it in Python 2.6 too.
krawyoti
Alex, worked for me. Ubuntu/python 2.5/2.6. You need to use full path in __import__, or alternatively, add it to sys.path and then call __import__ just on folder name
Art
You may want to set the module's `__name__` attribute as well, so that code inspecting it will see it as the same as code which looks at `sys.modules`.
Glyph