Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I properly import python modules in a multi directory project?

I have a python project with a basic setup that looks like this:

imptest.py

utils/something.py
utils/other.py

Here's what's in the scripts:

imptest.py

#!./venv/bin/python

import utils.something as something
import utils.other as other

def main():
    """
    Main function.
    """

    something.do_something()
    other.do_other()

if __name__ == "__main__":
    main()

something.py

#import other

def do_something():
    print("I am doing something")


def main():
    """
    Main function
    """

    do_something()
    #other.do_other()

if __name__ == "__main__":
    main()

other.py

def do_other():
    print("do other thing!")

def main():
    """
    Main function
    """

    do_other()

if __name__ == "__main__":
    main()

imptest.py is the main file that runs and calls the utils functions occasionally for some things.

And as you can see, I have commented out some lines in "something.py" where I am importing "other" module for testing.

But when I want to test certain functions in something.py, I have to run the file something.py and uncomment the import line.

This feels like a bit of a clunky way of doing this.

If I leave the

import other

uncommented and run imptest.py, I get this error:

Traceback (most recent call last):
  File "imptest.py", line 5, in <module>
    import utils.something as something
  File "...../projects/imptest/utils/something.py", line 3, in <module>
    import other
ModuleNotFoundError: No module named 'other'

What's a better way of doing this?

like image 887
ScipioAfricanus Avatar asked Dec 02 '20 01:12

ScipioAfricanus


1 Answers

The problem here is the path, Consider this directory structure

main
 - utils/something.py
 - utils/other.py
 imptest.py

When you try to import other using relative path in to something.py, then you would do something like from . import other. This would work when you execute $ python something.py but would fail when you run $ python imptest.py because in the second scenario it searches for main/other.py which doesn't exist.

So inorder to fix this issue, I would suggest that you write unit tests for something.py & other.py and run them using $ python -m (mod) command. ( I highly recommend this approach )

But.... if you really what your existing code to work without much modification then you can add these 2 lines in something.py file ( this works, but I don't recommend this approach )

import sys, os
sys.path.append(os.getcwd()) # Adding path to this module folder into sys path
import utils.other as other

def do_something():
    print("I am doing something")


def main():
    """
    Main function
    """

    do_something()
    other.do_other()

if __name__ == "__main__":
    main()

Here are some references to get better understanding:

  • Unit testing in python
  • Absolute vs Relative Imports in python
like image 167
Pavan Skipo Avatar answered Nov 15 '22 01:11

Pavan Skipo