ModuleNotFoundError when I am trying to import package

Viewed 334

my_controller.py is as follow:

from models import Person

david = Person('David')

And my project structure is

app
├── controller
│   └── my_controller.py
│   
└── models
    └── __init__.py
    └── person.py

I must do something wrong because I keep get

ModuleNotFoundError: No module named 'models'    

What is the correct way to import class Person to my_controller.py?

PS I am working on ubuntu

6 Answers

You need to use relative import

from . import models

Or it's better to import models that you will user, since it won't visually collide with django.db.models.

from django import forms
from .models import VolunteerBasicInfo

class BasicInfoCollectionForm(forms.ModelForm):

    class Meta:

        model = VolunteerBasicInfo
        ...

You also don't need to user brackets with class Meta.

I am assuming that you have app as a package and controllers and models as different modules.

To implement the package structure, you need to have __init__.py in the root that is app here and __init__.py inside every module.

After that, you can import one module functions/classes inn other modules without the need of relative import.

I tested the same structure that is present in the question with above suggestion.

The structure looks like this:

├── app
├── __init__.py
├── controllers
   ├── __init__.py
   ├── my_c.py
└── models
   ├── __init__.py
   └── my_m.py

  • All the __init__.py are empty.

  • The content of my_m.py is:

class Person:
    def test_model(self):
        x = "Model Imported"
        return x
  • The content of my_c.py is:
from models.my_m import Person

test = Person()
print(test.test_model())
  • When you execute:

    • python3 -m controllers.my_c inside app
  • Output is:

    • Model Imported

Let me know if it helps.

If you don't want to change any of the structure and you want to execute my_controller.py you will need to append access to the common folder so it can import any of the adjacent modules.

import sys
import os

sys.path.append(os.path.abspath(os.path.join(
    os.path.dirname(__file__), '..')
))

from models.person import Person

x = Person()

If you're just running the file in the shell its pretty simple. The idea is you want to start it from what your "root" directory is in the project.

First, add an empty __init__.py file in the app/ directory.

Second, change your import in my_controller.py to from models.person, instead of just from models:

from models.person import Person

david = Person('David')

Last, cd into the app/ directory, and run this bad boy.

$ python3 -m controller.my_controller.py

If that doesn't work, then set your PYTHONPATH to /app as well, like so:

export PYTHONPATH=$PYTHONPATH:/my/dir/app/venv/bin

and then attempt the first bash command again.

If your folder structure is the following...

app
├── __init__.py
│   
├── controller
│   └── my_controller.py
│   └── __init__.py
│   
└── models
    └── __init__.py
    └── person.py

And your root is the app folder, you can use in my_controller.py...

from app.models.person import Person

if __name__ == '__main__':
    david = Person('David')

Then if you run the program in the shell, you first navigate to the parent folder of app and use...

PYTHONPATH=. python app/controller/my_controller.py

It seems you are missing a __init__.py in the app and the controller folder as well as the correct import path.

Why using this approach

__init__.py files are necessary to treat the code in other folders as Python modules and allow for import. The if __name__ == '__main__': is not necessary but good practise, read more e.g. here. Now you might ask yourself what does PYTHONPATH=. mean. It sets the folder from where you execute your code as root. Using that, you need from <root>.<subfolder>.<file> import <class> as import paths. This helps you keeping a clean import structure, that shows the full scope of your project and makes adding a tests folder an ease :)

I hope I could help you!

Directory Structure like yours

when I tried this out, at first I got the same error as yours and after many attempts of debugging it, I found out one of my _init_.py contains some unusual code that I didn't add and it was :from models import person

so when I removed it from there , It run successfully but only when I am running it from the root directory as shown in the image below.

Even I tried several ways to run it from current working directory by changing the cwd to "app" or in my case "practice" but then it started showing me an error ModuleNotFoundError: No module named 'app' '

But for Now, I hope you get the solution...

Output

Note:=you'll see several other files as well , It was added by my IDE or python itself. so you don't need to worry about adding those files.

code in my_controller.py:-

from app.models import person

person.first()

and person.py module contains a function named first()

IDE USED:- PyCharm

Related