3

I have trouble importing package. My file structure is like this:

filelib/  
    __init__.py
    converters/ 
        __init__.py
        cmp2locus.py
    modelmaker/ 
        __init__.py
        command_file.py

In module command_file.py I have a class named CommandFile which i want to call in the cmp2locus.py module.

I have tried the following in cmp2locus.py module:

import filelib.modelmaker.command_file
import modelmaker.command_file
from filelib.modelmaker.command_file import CommandFile

All these options return ImportError: No modules named ... Appreciate any hint on solving this. I do not understand why this import does not work.

RAM
  • 2,257
  • 2
  • 19
  • 41
duanerf
  • 41
  • 1
  • 1
  • 2
  • Possible duplicate of [Adding folder to Python's path permanently](https://stackoverflow.com/questions/3722248/adding-folder-to-pythons-path-permanently) – moe asal Sep 22 '19 at 18:12

2 Answers2

5

To perform these imports you have 3 options, I'll list them in the order I'd prefer. (For all of these options I will be assuming python 3)

Relative imports

Your file structure looks like a proper package file structure so this should work however anyone else trying this option should note that it requires you to be in a package; this won't work for some random script.

You'll also need to run the script doing the importing from outside the package, for example by importing it and running it from there rather than just running the cmp2locus.py script directly

Then you'll need to change your imports to be relative by using .. So:

import filelib.modelmaker.command_file

becomes

from ..modelmaker import command_file

The .. refers to the parent folder (like the hidden file in file systems). Also note you have to use the from import syntax because names starting with .. aren't valid identifiers in python. However you can of course import it as whatever you'd like using from import as.

See also the PEP

Absolute imports

If you place your package in site-packages (the directories returned by site.getsitepackages()) you will be able to use the format of imports that you were trying to use in the question. Note that this requires any users of your package to install it there too so this isn't ideal (although they probably would, relying on it is bad).

Modifying the python path

As Meera answered you can also directly modify the python path by using sys.

I dislike this option personally as it feels very 'hacky' but I've been told it can be useful as it gives you precise control of what you can import.

Community
  • 1
  • 1
Blimmo
  • 363
  • 3
  • 11
  • Thank you @Blimmo. I like the idea of the relative imports. I am actually running Python2.7. If i try your `suggestion:from ..modelmaker import command_file`, i get the following error: `ValueError: Attempted relative import in non-package`. Do i need anything special in my __initi__.py for this to work? Or is it Python2.7 preventing it? – duanerf Mar 17 '17 at 10:26
  • 1
    I just realised the comment "rather than just running the cmp2locus.py". I am not sure I understand where i should import it from if i want to use in that particular module. – duanerf Mar 17 '17 at 10:30
  • 1
    @duanerf You just have to call the script you want to do the imports from somewhere else originally, the script can still use the imports in it. This is because python packages aren't really supposed to be run themselves, just used. So you could make a run.py outside of the package that just consists of `import filelib.converters.cmp2locus`. This would run the script from outside which allows the package to be loaded. [This](https://docs.python.org/2/tutorial/modules.html#intra-package-references) may be useful. – Blimmo Mar 17 '17 at 10:41
3

To import from another folder, you have to append that path of the folder to sys.path:

import sys
sys.path.append('path/filelib/modelmaker')
import command_file
Michael H.
  • 3,323
  • 2
  • 23
  • 31
Meera
  • 170
  • 7
  • Thank you @Meera. However it seems this does not add the path permanently. It means i need to always add this `sys.path.append` in my code. I find it strange and never noticed it was necessary. Is there a way to permanently add my `filelib` package in the sys.path to then import whetever is in that library? – duanerf Mar 17 '17 at 10:14