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

Asked By: Ollieeeee

||

Answers:

Answered By: Dlunhappy226

Example:

sys.path.insert(0, "path_to_your_project")
Answered By: Dlunhappy226

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).

Answered By: Nathaniel Ford

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.

  1. Add __init__.py to the tests directory so that pytest loads the tests from within the parent dir and natively finds the include directory.
  2. 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"
Answered By: jwal
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.