Search code examples
pythonimportpython-importimporterror

How to import from absolute path in python 3.8?


I am trying to import a module given an absolute path. I have read through some posts and I chose to follow one method mentioned in https://stackoverflow.com/a/53311583/19947267 but for some reason it doesnt work; below is my directory. my example directory looks like this:

<root>
 |
 +- /std1
 |   |
 |   +- main.py
 |
 +- /std2
 |   |
 |   +- lib.py

I cd to /std1 and now I want to import a module from lib.py, but when I implement the following code:

import sys 
import os
configfile = '~/std2/'
sys.path.append(os.path.dirname(os.path.expanduser(configfile)))
from std2.lib import target_module

It cant seem to recognise std2.lib, the error message was

ModuleNotFoundError: No module named 'std2.lib'

is there something I did wrong here? Can anyone please help?


Solution

  • Messing with sys.path is almost never the right way to do this. If you must though, then you need to understand that if you append ~/std2/ to the search path, it won't be able to find the name std2, because the import system searches inside of std2. And that is what your code does, your approach wasn't working because of this behavior of os.path.dirname when the string has a leading forward slash:

    >>> os.path.dirname(os.path.expanduser('~/std2/'))
    '/Users/juan/std2'
    >>> os.path.dirname(os.path.expanduser('~/std2'))
    '/Users/juan'
    

    So, the simplest fix is:

    import sys 
    import os
    configfile = '~/std2' # NOTE NO TRAILING FORWARD SLASH
    sys.path.append(os.path.dirname(os.path.expanduser(configfile)))
    import std2.lib
    

    Or instead, you can change your import statement to use just lib, so:

    import sys 
    import os
    configfile = '~/std2/'
    sys.path.append(os.path.dirname(os.path.expanduser(configfile)))
    import lib
    

    Better yet, you should use pathlib instead of os.path:

    import sys
    import pathlib
    configfile = pathlib.Path("~/std2/")
    sys.path.append(str(configfile.expanduser()))
    import lib
    

    But if you wanted to be able to import std2, you could add the parent directory to the path:

    import sys
    import pathlib
    configfile = pathlib.Path("~/std2/")
    sys.path.append(str(configfile.expanduser().parent))
    import std2.lib
    

    (See how much nicer pathlib is?)

    But I really must reiterate, you almost certainly shouldn't be messing with sys.path to begin with.