Search code examples
pythonpathreference

Relative Import In Unittest


I have reviewed several posts re: Relative vs Absolute imports, but none of the solutions proposed seemed to solve my problem.

I have a directory structure like the following:

--src
    --dir1
        --signal
            __init__.py
            parent_class.py
            --hf
                __init__.py
                child_class.py
                child_class_tests.py
          

The import within child_class.py for the parent class is as follows from ..parent_class import Parent

If I execute the child_class_tests.py with the pycharm Run configuration with a script path of: C:\test\src\dir1\signal\hf\child_class_tests.py with a working directory of C:\test\src\dir1\signal\hf\ I get the exception: ImportError: attempted relative import with no known parent package

within child_class_tests.py I have the following code:

import unittest
import pandas as pd
import sys
import os
print(os.getcwd())
from child_class import Child


class TestSignals(unittest.TestCase):

    DATA = pd.read_pickle(r'data.pkl')

    def test_child_class(self):
        """
        Test 
        """
        test_set = self.DATA.copy()

        print(test_set.head())


if __name__ == '__main__':
    unittest.main()

The error occurs on the attempted from child_class import Child on from ..parent import Parent within the Child class definition.

I have tried adding absolute references as well as running from the higher directory and neither have worked. I'm using Python 3.9 with PyCharm 2021.1.1.

In following the other posts, I've tried to recreate the environments that they're referencing and have been unable to rectify the problem.


Solution

  • child_class is being treated as a top-level module not contained in any package, i.e. it is found in the directory src/dir1/signal/hf (which appears in sys.path implicitly as ''), not the package dir1.signal.hf.

    Your tests should not import it like this, but rather from the package it belongs to (and your test runner should thus be configured to know where to find dir1):

    import unittest
    import pandas as pd
    
    from dir1.signal.hf.child_class import Child
    
    
    class TestSignals(unittest.TestCase):
    
        DATA = pd.read_pickle(r'data.pkl')
    
        def test_child_class(self):
            """
            Test 
            """
            test_set = self.DATA.copy()
    
            print(test_set.head())
    
    
    if __name__ == '__main__':
        unittest.main()
    

    PEP 366 also suggests the following instead of modifying the import, which may work (though I haven't tested it):

    if __name__ == '__main__' and __package__ is None:
        __package__ = 'dir1.signal.hf'
    

    You still need to ensure that src is on the search path in order to find dir1, so I think I would still recommend modifying the import instead.