Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ModuleNotFoundError when using importlib.import_module

I have the following folder structure and I have a test method in util.py. When the util method is run, I see an error with a module that is imported within the module where I am trying to get all classes.

Parent
--report <dir>
----__init__.py
----AReport.py
----names_list.py
--util.py

util.py

import inspect
import importlib
import importlib.util

def get_class_names(fileName):
    for name, cls in inspect.getmembers(importlib.import_module(fileName, package='report'), inspect.isclass):
        print(name, cls)

if __name__ == '__main__':
    get_class_names('report.names_list')

names_list.py

from AReport import AReport

class Team:
    name = ""
    def __init__(self, name):
        self.name = name

class Names_List(AReport):
    def __init__(self, name=None):
        AReport.__init__(self, name)

    def test(self):
        print('In test')        

AReport.py

from abc import ABCMeta, abstractmethod

class AReport(metaclass=ABCMeta):
    def __init__(self, name=None):
        if name:
            self.name = name

    def test(self):
        pass

When I run my test method from util, I get the following error:

ModuleNotFoundError: No module named AReport
like image 449
dcu Avatar asked Jun 14 '19 17:06

dcu


People also ask

What does Importlib Import_module do?

The import_module() function acts as a simplifying wrapper around importlib. __import__(). This means all semantics of the function are derived from importlib. __import__(), including requiring the package from which an import is occurring to have been previously imported (i.e., package must already be imported).

How does Python Importlib work?

The purpose of the importlib package is two-fold. One is to provide the implementation of the import statement (and thus, by extension, the __import__() function) in Python source code. This provides an implementation of import which is portable to any Python interpreter.

What is __ import __ in Python?

One can use the Python's inbuilt __import__() function. It helps to import modules in runtime also. Syntax: __import__(name, globals, locals, fromlist, level) Parameters: name : Name of the module to be imported.

How do I delete an imported module in Python?

To remove an imported module in Python: Use the del statement to delete the sys reference to the module. Use the del statement to remove the direct reference to the module.


1 Answers

Assuming you did not change anything with sys.path or with PYTHONPATH, the problem is that AReport module is not "visible" from util.py.

You can check this by adding this at the top of util.py:

import sys
print(sys.path)

That's going to print out a list of all paths where the interpreter will look for modules. You'll see that only the path to the Parent module is there, because this is where the util.py was run from. This is explained in The Module Search Path documentation:

When a module named spam is imported, the interpreter first searches for a built-in module with that name. If not found, it then searches for a file named spam.py in a list of directories given by the variable sys.path. sys.path is initialized from these locations:

  • The directory containing the input script (or the current directory when no file is specified).
  • PYTHONPATH (a list of directory names, with the same syntax as the shell variable PATH).
  • The installation-dependent default.

When you run util.py from the Parent directory (= "The directory containing the input script"), and you do

from AReport import AReport

it will look for a AReport module from the Parent directory, but it's not there because only the report package is directly under the /path/to/Parent directory. That is why Python raises the ModuleNotFoundError. If you do instead

from report.AReport import AReport

it's going to work because the report package is under /path/to/Parent.

If you want to avoid the report. prefix when importing, one option is to add the report package to the sys.path on util.py:

import sys
sys.path.append("./report")

print(sys.path)
# should now show the /path/to/Parent/report on the list

Then your from AReport import will now work. Another option is to add /path/to/Parent/report to your PYTHONPATH environment variable before running util.py.

export PYTHONPATH=$PYTHONPATH:/path/to/Parent/report

I usually go with the PYTHONPATH option for tests, so that I don't need to modify the code.

like image 118
Gino Mempin Avatar answered Sep 28 '22 00:09

Gino Mempin