The problem
I have a directory structure for my project which follows the standard for Python packages, as it was created with this cookiecutter template: https://github.com/audreyr/cookiecutter-pypackage#quickstart
The directory structure is
project_name
├── project_name
│ ├── __init__.py
│ └── module1.py
└── tests
└── test_module1.py
The first code line of test_module1.py
is:
from project_name import module1
But I get a ModuleNotFoundError: No module named 'project_name'
.
To my understanding, this should work since the folder called project_name
is a package, which is ensured by presence of the __init__.py
file.
I have always had trouble understanding how imports like this work. For my projects I have always just settled with having my tests in the same folder as the modules to test. I know this is bad practice, but the only way I could get the modules to actually import.
What I already tried
I have tried renaming the folder with the __init__.py
file to something else and then import, as I thought it could have something to do with the parent folder and the child folder both having the name project_name
. This did not work, same error.
I also tried making the test folder into a package by creating an __init.py__
file inside it, even though the Cookiecutter template does not have that.
I read in many places that making the test folder into a package is discouraged, but some suggest that structure. That did not work either.
I have searched thoroughly for solutions to this seemingly very standard problem, some of the links are here:
- Python, importing modules for testing
- https://gist.github.com/tasdikrahman/2bdb3fb31136a3768fac
- Importing modules from parent folder
- https://alex.dzyoba.com/blog/python-import/
- Sibling package imports
- Python imports for tests using nose - what is best practice for imports of modules above current package
My last try was to start a project with Cookiecutter, so everything would be set up properly form the beginning. However, I still get the ModuleNotFoundError
.
What I don't want
I don't want to modify sys.path
as many answers seem to suggest. There must be a cleaner way for such a common problem.
What am I doing wrong?
Edit for some additional info (see question from @Nicholas):
The contents of __init__.py
is
# -*- coding: utf-8 -*-
"""Top-level package for project_name."""
__author__ = """my_name"""
__email__ = 'my_email'
__version__ = '0.1.0'
Which was generated by the Cookiecutter template.
Inside test_module1
, I added the following before the before the ModuleNotFoundError
occurs:
import sys
import os
print(sys.path)
print(os.getcwd())
sys.path
prints a list, where first element is the tests
directory.
['c:\\Users\\...\\project_name\\tests',
'C:\\Users\\...\\Miniconda3\\python37.zip',
'C:\\Users\\...\\Miniconda3\\DLLs', 'C:\\Users\\...\\Miniconda3\\lib',
'C:\\Users\\...\\Miniconda3',
'C:\\Users\\...\\Miniconda3\\lib\\site- packages',
'C:\\Users\\...\\Miniconda3\\lib\\site-packages\\win32',
'C:\\Users\\...\\Miniconda3\\lib\\site-packages\\win32\\lib',
'C:\\Users\\...\\Miniconda3\\lib\\site-packages\\Pythonwin']
I don't know if the lowercase 'c' in the first element matters.
os.getcwd()
prints the root directory 'c:\Users\....\project_name'
. Also with a lowercase 'c'.