151

I want to import subfolders as modules. Therefore every subfolder contains a __init__.py. My folder structure is like this:

src\
  main.py
  dirFoo\
    __init__.py
    foofactory.py
    dirFoo1\
      __init__.py
      foo1.py
    dirFoo2\
      __init__.py
      foo2.py

In my main script I import

from dirFoo.foofactory import FooFactory

In this factory file I include the sub modules:

from dirFoo1.foo1 import Foo1
from dirFoo2.foo2 import Foo2

If I call my foofactory I get the error, that python can't import the submodules foo1 and foo2:

Traceback (most recent call last):
  File "/Users/tmp/src/main.py", line 1, in <module>
from dirFoo.foofactory import FooFactory
  File "/Users/tmp/src/dirFoo/foofactory.py", line 1, in    <module>
from dirFoo1.foo1 import Foo1
    ImportError: No module named dirFoo1.foo1

6 Answers 6

201

There's no need to mess with your PYTHONPATH or sys.path here.

To properly use absolute imports in a package you should include the "root" packagename as well, e.g.:

from dirFoo.dirFoo1.foo1 import Foo1
from dirFoo.dirFoo2.foo2 import Foo2

Or you can use relative imports:

from .dirfoo1.foo1 import Foo1
from .dirfoo2.foo2 import Foo2
Sign up to request clarification or add additional context in comments.

6 Comments

One thing to remember! add __init__.py to every subfolder you are importing from.
Empty __init__.py may do the job.
What would the syntax be if previously Foo1 was in the parent directory and one coded something like from Foo1 import *. Is there a way to achieve that same effect so you don't have to prefix everything with Foo1?
@AzizAlto: without your comment this solution is not very useful
Using from .dirfoo1.foo1 import Foo1 etc. worked for me. Also, rather than empty dunder init files, I had these two lines: import site followed by site.addsitedir('./')
|
28

Just to notify here. (from a newbee, keviv22)

Never and ever for the sake of your own good, name the folders or files with symbols like "-" or "_". If you did so, you may face few issues. like mine, say, though your command for importing is correct, you wont be able to successfully import the desired files which are available inside such named folders.

Invalid Folder namings as follows:

  • Generic-Classes-Folder
  • Generic_Classes_Folder

valid Folder namings for above:

  • GenericClassesFolder or Genericclassesfolder or genericClassesFolder (or like this without any spaces or special symbols among the words)

What mistake I did:

consider the file structure.

Parent
   . __init__.py
   . Setup
     .. __init__.py
     .. Generic-Class-Folder
        ... __init__.py
        ... targetClass.py
   . Check
     .. __init__.py
     .. testFile.py

What I wanted to do?

  • from testFile.py, I wanted to import the 'targetClass.py' file inside the Generic-Class-Folder file to use the function named "functionExecute" in 'targetClass.py' file

What command I did?

  • from 'testFile.py', wrote command, from Core.Generic-Class-Folder.targetClass import functionExecute
  • Got errors like SyntaxError: invalid syntax

Tried many searches and viewed many stackoverflow questions and unable to decide what went wrong. I cross checked my files multiple times, i used __init__.py file, inserted environment path and hugely worried what went wrong......

And after a long long long time, i figured this out while talking with a friend of mine. I am little stupid to use such naming conventions. I should never use space or special symbols to define a name for any folder or file. So, this is what I wanted to convey. Have a good day!

(sorry for the huge post over this... just letting my frustrations go.... :) Thanks!)

1 Comment

Spaces and dashes ("-") would cause this, but underscores ("_") should still work fine.
12

Set your PYTHONPATH environment variable. For example like this PYTHONPATH=.:.. (for *nix family).

Also you can manually add your current directory (src in your case) to pythonpath:

import os
import sys
sys.path.insert(0, os.getcwd())

Comments

8

Say your project is structured this way:

+---MyPythonProject
|   +---.gitignore
|   +---run.py
|   |   +---subscripts
|   |   |   +---script_one.py
|   |   |   +---script_two.py

Inside run.py, you can import scripts one and two by:

from subscripts import script_one as One
from subscripts import script_two as Two

Now, still inside run.py, you'll be able to call their methods with:

One.method_from_one(param)
Two.method_from_two(other_param)

1 Comment

Your solution is very elegant. But there is a way to improve it using only a init.py file? Let's say I do not want One.method_from_one(param) but only method_from_one(param)
3

Just create an empty __init__.py file and add it in root as well as all the sub directory/folder of your python application where you have other python modules. See https://docs.python.org/3/tutorial/modules.html#packages

Comments

0

just tested and this worked:

# create sub dir
mkdir ./modules

create module1.py

vim ./modules/module1.py

def hello():
    print("hello have a nice day")
    
def bye():
    print("bye")

vim write and quit

:wq

include module1.py functionality into fileA.py and call it's functions

vim ./fileA.py

#!/usr/bin/env python
import sys
sys.path.append('./modules')

print("===== testing modules =====")
import module1

# call functions of the module
module1.hello()
module1.bye()

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.