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
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).
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.
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.
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.
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 namedspam.py
in a list of directories given by the variablesys.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 variablePATH
).- 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With