Ayam Chan
Ayam Chan

Reputation: 85

Python cannot import function from module in same package

I have this package structure

project/
    package_a/
        __init__.py
        subpackage_b/
            __init__.py
            module_one.py
        subpackage_c
            __init__.py
            module_two.py
    package_b/

module_one.py

def test_func():
     return 0

How can I import test_func from module_two.py? I have tried using

from subpackage_b.module_one import test_func

from package_a.subpackage_b.module_one import test_func

from module_one import test_func

but none of them works, giving me ModuleNotFoundError. I understand there are many similar questions here but none of them seems to work for me. One which I have not tried is setting the PYTHONPATH variable, but I am not sure what to set it to. I am using VSCode and the current python.pythonPath is just the python file in my venv folder.

Upvotes: 1

Views: 1320

Answers (3)

Kaos
Kaos

Reputation: 1004

The root is of course your sys.path, and to answer why it does not work for you, I'll assume you attempt to invoke a python file from within your package, which will not allow python to find your package root properly.

Instead, invoke your code from a file directly in your project root (so the package is in the same directory as your main script file).

From https://docs.python.org/3/library/sys.html#sys.path

As initialized upon program startup, the first item of this list, path[0], is the directory containing the script that was used to invoke the Python interpreter.

$ tree
.
├── main.py
└── package_a
    ├── __init__.py
    ├── subpackage_b
    │   ├── __init__.py
    │   └── module_one.py
    └── subpackage_c
        ├── __init__.py
        └── module_two.py
# cat main.py 
import package_a.subpackage_c.module_two

# cat package_a/subpackage_b/module_one.py 
def test_func():
    return 0

# cat package_a/subpackage_c/module_two.py 
from package_a.subpackage_b.module_one import test_func
print("test func:", test_func())
$ python package_a/subpackage_c/module_two.py 
Traceback (most recent call last):
  File "package_a/subpackage_c/module_two.py", line 1, in <module>
    from package_a.subpackage_b.module_one import test_func
ModuleNotFoundError: No module named 'package_a'

$ python main.py
test func: 0

Upvotes: 0

Chandella07
Chandella07

Reputation: 2117

In python, When the interpreter executes the import statement, it searches for module in a list of directories assembled from the following sources:

  • The directory from which the input script was run, or the current directory if the interpreter is being run interactively
  • The list of directories contained in the PYTHONPATH environment variable, if it is set. (The format for PYTHONPATH is OS-dependent but should mimic the PATH environment variable.)
  • An installation-dependent list of directories configured at the time Python is installed (For example: in linux, /usr/local/lib/python)

In addition, You can put the module file in any directory of your choice and then modify sys.path at run-time so that it contains that directory but this would not be a standard. you can do it for internal purpose but not a best practice to share your code with this.

Rather you can use python's __file__ attribute, to get the path and put it in sys.path like below:

import sys
from os.path import dirname
sys.path.append(dirname(__file__)) 

Upvotes: 0

oskros
oskros

Reputation: 3305

You can find the set of paths that you can import from using

import sys
print(sys.path)

So, make sure that the project path is in sys.path. If it is not, then you can add it dynamically in your code with the following line, which should be run before your import statements

sys.path.append('C:/Path_to_project/project')

However, if you were running python from the project folder, the path should already be there.

The proper way to import when your sys.path is including your project folder, would be

from package_a.subpackage_b.module_one import test_func

Upvotes: 2

Related Questions