58

I have a module foo, containing util.py and bar.py.

I want to import it in IDLE or python session. How do I go about this?

I could find no documentation on how to import modules not in the current directory or the default python PATH. After trying import "<full path>/foo/util.py", and from "<full path>" import util

The closest I could get was

import imp
imp.load_source('foo.util','C:/.../dir/dir2/foo')

Which gave me Permission denied on windows 7.

Garrett
  • 4,007
  • 2
  • 41
  • 59
Vort3x
  • 1,778
  • 2
  • 20
  • 37
  • Also worth checking out this [related question](http://stackoverflow.com/questions/15109548/set-pythonpath-before-import-statements). In particular, I like the [top answer](http://stackoverflow.com/a/15109660/95852) there, for its clarity about the safety of changes to `sys.path`. – John Y Mar 17 '15 at 18:49
  • Possible duplicate of [How to import a module given the full path?](http://stackoverflow.com/questions/67631/how-to-import-a-module-given-the-full-path) – Dan Gayle Nov 30 '15 at 02:03

4 Answers4

81

One way is to simply amend your path:

import sys
sys.path.append('C:/full/path')
from foo import util,bar

Note that this requires foo to be a python package, i.e. contain a __init__.py file. If you don't want to modify sys.path, you can also modify the PYTHONPATH environment variable or install the module on your system. Beware that this means that other directories or .py files in that directory may be loaded inadvertently.

Therefore, you may want to use imp.load_source instead. It needs the filename, not a directory (to a file which the current user is allowed to read):

import imp
util = imp.load_source('util', 'C:/full/path/foo/util.py')
phihag
  • 278,196
  • 72
  • 453
  • 469
  • It works, but now when trying to use util.method by using method, it says 'method' not defined. But I can use it by util.method. Why? – Vort3x Apr 15 '12 at 11:54
  • 2
    Because you haven't defined `method`, only "the `method` in `util`". You can define `method = util.method` if you want. – Katriel Apr 15 '12 at 11:57
  • Note that `from foo import *` is bad coding unless you're just hacking around in the shell. – Katriel Apr 15 '12 at 11:58
  • @katrielalex Thanks. And I'm using from foo import util, not from foo import *. So don't worry ;) – Vort3x Apr 15 '12 at 12:18
  • @Vort3x Well, that makes `util` available in your namespace. Why do you expect `util.method` to be available under the name `method`? That would mean that you'd have to ensure that there's not another `method` in `bar`, and thereby defeat the whole point of a module system, i.e. not having to worry about name collisions. – phihag Apr 15 '12 at 12:21
  • 1
    @Wooble Corrected to *package*. `__init__.py` **is** required. Observe `mkdir foo; touch foo/util.py; python -c 'from foo import util'` and `touch foo/__init__.py; python -c 'from foo import util'` – phihag Apr 16 '12 at 17:48
  • -1 Because appending to the Python path is a *bad* solution. It works, but it's strictly worse than `imp.load_source` because the user may not want to modify any system paths, or may be working on a computer where she or he cannot do so. This is actually one of the most annoying "features" in Python, which otherwise is an elegant language. It's silly that you can't just give `import` a string naming a path to another .py file. And given that you can't, protecting against changing system paths by using `imp` is *strictly* better. – ely Apr 16 '12 at 17:51
  • 5
    @EMS The Python documentation [explicitly mentions `sys.path`](http://docs.python.org/tutorial/modules.html#the-module-search-path). If the user cannot modify `sys.path`, it's extremely likely that the `imp` module is blocked as well (note that Python's `sys.path` has nothing with the [system's `PATH`](http://en.wikipedia.org/wiki/PATH_(variable))). Personally, I don't think that loading modules by name instead of filename is silly; it allows system-wide installations of Python packages (for example, on 2.5 you may want to serve your alternative `json` module). Added a cautionary note. – phihag Apr 16 '12 at 18:01
  • Well, yes, to import from a package you do need `__init__.py`, although if `/foo` were added to sys.path without it, then `import util` and `import bar` would both work. (changed vote to +1) – Wooble Apr 16 '12 at 20:24
5

You could customize the module search path using the PYTHONPATH environment variable, or manually modify the sys.path directory list.

See Module Search Path documentation on python.org.

icecrime
  • 74,451
  • 13
  • 99
  • 111
2

Give this a try

import sys
sys.path.append('c:/.../dir/dir2')
import foo
Levon
  • 138,105
  • 33
  • 200
  • 191
  • 1
    -1 Because appending to the Python path is a bad solution. It works, but it's strictly worse than imp.load_source because the user may not want to modify any system paths, or may be working on a computer where she or he cannot do so. This is actually one of the most annoying "features" in Python, which otherwise is an elegant language. It's silly that you can't just give import a string naming a path to another .py file. And given that you can't, protecting against changing system paths by using imp is strictly better. – ely Apr 16 '12 at 17:51
  • 1
    @EMS Ah .. I see what you are saying, I didn't realize it before, but now the point you make is clear. Thanks for pointing this out. (I may have to modify some of my own code now :) – Levon Apr 16 '12 at 17:58
  • 4
    Don't worry. This is the intended purpose of `sys.path` (or at least *an* intended use case). Mr. F (who apparently was previously EMS) is wrong. As phihag notes in his response to the identical -1 comment on his answer, `sys.path` is *not* related to the overall system path. – John Y Mar 17 '15 at 18:36
  • @ely It seems that imp.load_source (load_module) is deprecated after python3.3 what can be the alternative? – zviad Apr 12 '18 at 13:18
  • after importing foo, do a sys.path.pop() if you are worried about messing other imports up. – Robert Lugg Oct 17 '19 at 18:25
  • 1
    @zviad saw this many years later - there is [another post](https://stackoverflow.com/questions/19009932/import-arbitrary-python-source-file-python-3-3) which shows workarounds and changes for newer versions of Python – ely Oct 07 '22 at 18:54
2

Following phihag's tip, I have this solution. Just give the path of a source file to load_src and it will load it. You must also provide a name, so you can import this module using this name. I prefer to do it this way because it's more explicit:

def load_src(name, fpath):
    import os, imp
    return imp.load_source(name, os.path.join(os.path.dirname(__file__), fpath))

load_src("util", "../util.py")
import util

print util.method()

Another (less explicit) way is this:

util = load_src("util", "../util.py")    # "import util" is implied here

print util.method()    # works, util was imported by the previous line

Edit: the method is rewritten to make it clearer.

Jabba
  • 19,598
  • 6
  • 52
  • 45