How can I import a module folder from a tests folder
Question:
I’m working on a project with this folder structure using pytest for tests
project
├── example
│ ├── __init__.py
│ └── example.py
├── setup.py
└── tests
└── test_1.py
I’m trying to import example.py
from test_1.py
but every way I’ve tried hasn’t worked.
I’ve tried using sys.path.append('../)
then import example
and just using from ... import example
but neither of these methods has worked. sys.path.append('../')
didn’t let me import example and from ... import example
errored with ImportError: attempted relative import with no known parent package
. I’ve also tried using python setup.py develop
and it let me import example, but none of the methods are imported.
This is the code that is in test_1.py. It currently imports example but it has no content.
import sys
import os
sys.path.append("../example/")
import example
example.test()
Contents of example.py
class test:
def __init__(self):
self.a = 1
self.b = 2
The setup.py is the template from here
Answers:
You can try system path (sys.path) to insert.
https://www.geeksforgeeks.org/python-import-module-from-different-directory/
Example:
sys.path.insert(0, "path_to_your_project")
I think your problem is that the path resolution isn’t functioning as you expect. In your example.py
file do this:
import sys
import os
dir_path = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.realpath(f"{dir_path}/../example"))
import example
example.test()
Then, when in your root directory run python tests/test_1.py
. This should execute test()
from the example directory.
The realpath()
function is the key here, as it will resolve the actual system path. If that isn’t resolved it assumes whatever you’re handing it is from the root (i.e. /example
, which is wrong).
Use of sys.path.append
results in flake8 reporting E402 module level import not at the top of the file. There are various hacks to this around which essentially depend on disabling E402; directly or by deception. There are at least two other ways.
- Add
__init__.py
to the tests directory so that pytest loads the tests from within the parent dir and natively finds the include directory.
pip install -e .
from within the parent and have the package loaded in a developer environment.
For the sake of consistency I started with uninstalling every package (so pip freeze returns nothing) and creating virtual environments for each of the approaches. I omitted the setup.py
file favoring a minimal pyproject.toml
file. Then pip install pytest
and pip install flake8
in both. For packages, the second approach then shows an additional example
package, i.e.
(.venv) PS C:xxxxStackoverflowproj_hatch> pip freeze
attrs==22.1.0
colorama==0.4.5
# Editable install with no version control (example==0.0.1)
-e c:xxxxstackoverflowproj_hatch
flake8==5.0.4
iniconfig==1.1.1
mccabe==0.7.0
packaging==21.3
pluggy==1.0.0
py==1.11.0
pycodestyle==2.9.1
pyflakes==2.5.0
pyparsing==3.0.9
pytest==7.1.3
tomli==2.0.1
The net outcome is that both approaches have a working pytest.
(.venv) PS C:xxxxStackoverflowproj_hatch> pytest
================ test session starts =========================
platform win32 -- Python 3.10.8, pytest-7.1.3, pluggy-1.0.0
rootdir: C:xxxxStackoverflowproj_hatch
collected 1 item
teststest_1.py . [100%]
=================== 1 passed in 0.01s ========================
(.venv) PS C:xxxxStackoverflowproj_hatch>
In both versions set example/__init__.py
as below. This has an additional benefit of allowing the structure (which function in which file) to change later while keeping the import for other applications stable.
from example.example import test
__all__ = [
"test",
]
In both versions the test is:
import example
def test_1():
ex1 = example.Test()
assert ex1.b == 2
With the first approach it is necessary to add .tests__init__.py
so that pytest loads the test from within the project directory and is able to find the example
directory. I expect this has some implications for how you write tests.
With the second approach I started off using hatch however it seemed to work with little more than moving the example
directory to srcexample
and by creating a pyproject.toml
file. I’ve a suspicion there is some magic in the later versions of python that help. I am using 3.10.8 for this exercise.
[project]
name = "example"
version = "0.0.1"
I’m working on a project with this folder structure using pytest for tests
project
├── example
│ ├── __init__.py
│ └── example.py
├── setup.py
└── tests
└── test_1.py
I’m trying to import example.py
from test_1.py
but every way I’ve tried hasn’t worked.
I’ve tried using sys.path.append('../)
then import example
and just using from ... import example
but neither of these methods has worked. sys.path.append('../')
didn’t let me import example and from ... import example
errored with ImportError: attempted relative import with no known parent package
. I’ve also tried using python setup.py develop
and it let me import example, but none of the methods are imported.
This is the code that is in test_1.py. It currently imports example but it has no content.
import sys
import os
sys.path.append("../example/")
import example
example.test()
Contents of example.py
class test:
def __init__(self):
self.a = 1
self.b = 2
The setup.py is the template from here
You can try system path (sys.path) to insert.
https://www.geeksforgeeks.org/python-import-module-from-different-directory/
Example:
sys.path.insert(0, "path_to_your_project")
I think your problem is that the path resolution isn’t functioning as you expect. In your example.py
file do this:
import sys
import os
dir_path = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.realpath(f"{dir_path}/../example"))
import example
example.test()
Then, when in your root directory run python tests/test_1.py
. This should execute test()
from the example directory.
The realpath()
function is the key here, as it will resolve the actual system path. If that isn’t resolved it assumes whatever you’re handing it is from the root (i.e. /example
, which is wrong).
Use of sys.path.append
results in flake8 reporting E402 module level import not at the top of the file. There are various hacks to this around which essentially depend on disabling E402; directly or by deception. There are at least two other ways.
- Add
__init__.py
to the tests directory so that pytest loads the tests from within the parent dir and natively finds the include directory. pip install -e .
from within the parent and have the package loaded in a developer environment.
For the sake of consistency I started with uninstalling every package (so pip freeze returns nothing) and creating virtual environments for each of the approaches. I omitted the setup.py
file favoring a minimal pyproject.toml
file. Then pip install pytest
and pip install flake8
in both. For packages, the second approach then shows an additional example
package, i.e.
(.venv) PS C:xxxxStackoverflowproj_hatch> pip freeze
attrs==22.1.0
colorama==0.4.5
# Editable install with no version control (example==0.0.1)
-e c:xxxxstackoverflowproj_hatch
flake8==5.0.4
iniconfig==1.1.1
mccabe==0.7.0
packaging==21.3
pluggy==1.0.0
py==1.11.0
pycodestyle==2.9.1
pyflakes==2.5.0
pyparsing==3.0.9
pytest==7.1.3
tomli==2.0.1
The net outcome is that both approaches have a working pytest.
(.venv) PS C:xxxxStackoverflowproj_hatch> pytest
================ test session starts =========================
platform win32 -- Python 3.10.8, pytest-7.1.3, pluggy-1.0.0
rootdir: C:xxxxStackoverflowproj_hatch
collected 1 item
teststest_1.py . [100%]
=================== 1 passed in 0.01s ========================
(.venv) PS C:xxxxStackoverflowproj_hatch>
In both versions set example/__init__.py
as below. This has an additional benefit of allowing the structure (which function in which file) to change later while keeping the import for other applications stable.
from example.example import test
__all__ = [
"test",
]
In both versions the test is:
import example
def test_1():
ex1 = example.Test()
assert ex1.b == 2
With the first approach it is necessary to add .tests__init__.py
so that pytest loads the test from within the project directory and is able to find the example
directory. I expect this has some implications for how you write tests.
With the second approach I started off using hatch however it seemed to work with little more than moving the example
directory to srcexample
and by creating a pyproject.toml
file. I’ve a suspicion there is some magic in the later versions of python that help. I am using 3.10.8 for this exercise.
[project]
name = "example"
version = "0.0.1"