1

I'm trying to import a class in a different directory to another file, but can't seem to get it to work. I know this question has been asked a lot and I have looked through multiple stackoverflow solutions and at https://docs.python.org/3/tutorial/modules.html#packages

1: Importing files from different folder 2: import python file in another directory failed

I want to try to just use the method containing just __init__.py file instead of doing an import sys

My directory structure is as follows:

django_vue/
  __init__.py
  devices/
        __init__.py
        models.py
  lib/
        __init__.py
        my_file.py

I'm trying to import the class Device from /django_vue/devices/models.py to /django_vue/lib/my_file.py by:

from devices.models import Device

However when I do that I still get the error:

from devices.models import Device
ModuleNotFoundError: No module named 'devices'

I'm not sure what I'm dong wrong since I already have the __init__ file in both directories. Any help is appreciated. Also I'm running python 3.6.

Mark
  • 730
  • 1
  • 8
  • 22

3 Answers3

2

This is the folder structure I'm working with.

.
└── django_vue
    ├── devices
    │   └── models.py
    └── lib
        └── file.py

When you run

$ python file.py

python has no way of knowing what's outside the directory.

python can't go back and then into devices/ just like that.

The easiest way to solve this would be to add the folder devices/ to sys.path. When python imports a module, it searches for the module from sys.path. Adding the path to devices/ would make it available for imports.

Here are my files.

# models.py
Device = 'device'
# file.py
import sys
sys.path.append('..')  # adds the parent dir (which is django-vue/) to path
# django-vue dir has devices/ so now this is available for imports

# importing this works now
from devices.models import Device

print(Device)

Output

django_vue/lib$ python3 file.py 

device
Diptangsu Goswami
  • 5,554
  • 3
  • 25
  • 36
  • I got a Django error after that but I think I must have misconfigured something. It no longer gives me the same error so I think it works. Thank you. – Mark Jun 21 '20 at 18:40
0

Think about it your are inside my_file.py and import something called devices. How can python know where the name devices has come from. It won't search your entire Drive for that module/package

Relative Import

use a relative import instead. write from ..devices.models import Device. This is telling python to go up one directory to the parent directory and that's where it will find the devices package. Your lib module should now work as a module

If you however run the my_file.py package directly (as in python C:/django_vue/lib/my_file.py) You will still get an error. Not the same error; the new error will be something like

ImportError: attempted relative import with no known parent package

This is happening because you are actually running my_file.py

If you think about it why would you want to run my_file.py by itself when it is clearly a part of a package. Maybe you are just testing to see if the import works when you use your package. The problem with this is that it makes it seem like your packages relative imports don't work even though this actually works.

Create a main.py in django_vue and write from lib import my_file. This will run your my_file.py and you will notice there is no error.

What's happening here

Have you heard of __package__?

if you put print(str(__package__)) in your my_file.py and run my_file.py directly you will see that it prints None.

However if you run main.py (that you just created) you will see that when It reaches my_file.py, __package__ will actually be defined to something.

Ahhh... you see now it all makes sense; The error you originally got said something about no known parent package. If __package__ is undefined that means there is no relative parent package because the file was obviously run directly instead of as part of a package.

Consider Absolute imports

you also might want to consider using absolute imports because if you are working on the package you might change it directory structure while developing. so you need to keep changing the import references on the affected files.

Although you can find IDE's with python extensions that automatically to this as you change your directory. I believe VS Code does this automatically.

masonCherry
  • 894
  • 6
  • 14
-1

Replace the __init__ files with __main__.

bfontaine
  • 18,169
  • 13
  • 73
  • 107
Hexception
  • 722
  • 10
  • 25