Skip Navigation

How should I deal with multiple imports having the same name?

stackoverflow.com

How should I deal with multiple imports having the same name

I have a repository that contains multiple programs:

 
        .
    └── Programs
        ├── program1
        │   └── Generic_named.py
        └── program2
            └── Generic_named.py


  

I would like to add testing to this repository.

I have attempted to do it like this:

 
        .
    ├── Programs
    │   ├── program1
    │   │   └── Generic_named.py
    │   └── program2
    │       └── Generic_named.py
    └── Tests
        ├── mock
        │   ├── 1
        │   │   └── custom_module.py
        │   └── 2
        │       └── custom_module.py
        ├── temp
        ├── test1.py
        └── test2.py


  

Where temp is a folder to store each program temporarily with mock versions of any required imports that can not be stored directly with the program.

Suppose we use a hello world example like this:

 
        cat Programs/program1/Generic_named.py
    import custom_module
    
    def main():
        return custom_module.out()


    cat Programs/program2/Generic_named.py
    import custom_module
    
    def main():
        return custom_module.out("Goodbye, World!")


    cat Tests/mock/1/custom_module.py
    def out():return "Hello, World!"


    cat Tests/mock/2/custom_module.py
    def out(x):return x


  

And I were to use these scripts to test it:

 
        cat Tests/test1.py
    import unittest
    import os
    import sys
    import shutil
    
    if os.path.exists('Tests/temp/1'):
        shutil.rmtree('Tests/temp/1')
    
    shutil.copytree('Tests/mock/1', 'Tests/temp/1/')
    shutil.copyfile('Programs/program1/Generic_named.py', 'Tests/temp/1/Generic_named.py')
    
    sys.path.append('Tests/temp/1')
    import Generic_named
    sys.path.remove('Tests/temp/1')
    
    class Test(unittest.TestCase):
        def test_case1(self):
                self.assertEqual(Generic_named.main(), "Hello, World!")
    
    if __name__ == '__main__':
        unittest.main()



    cat Tests/test2.py
    import unittest
    import os
    import sys
    import shutil
    
    if os.path.exists('Tests/temp/2'):
        shutil.rmtree('Tests/temp/2')
    
    shutil.copytree('Tests/mock/2', 'Tests/temp/2')
    shutil.copyfile('Programs/program2/Generic_named.py', 'Tests/temp/2/Generic_named.py')
    
    sys.path.append('Tests/temp/2')
    import Generic_named
    sys.path.remove('Tests/temp/2')
    
    class Test(unittest.TestCase):
        def test_case1(self):
                self.assertEqual(Generic_named.main(), "Goodbye, World!")
    
    if __name__ == '__main__':
        unittest.main()



  

Both tests pass when run individually:

 
        python3 -m unittest Tests/test1.py
    .
    ----------------------------------------------------------------------
    Ran 1 test in 0.000s
    
    OK
    
    
    python3 -m unittest Tests/test2.py
    .
    ----------------------------------------------------------------------
    Ran 1 test in 0.000s
    
    OK


  

However, they fail when being run together:

 
        python3 -m unittest discover -p test*.py -s Tests/
    .F
    ======================================================================
    FAIL: test_case1 (test2.Test)
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "/home/s/Documents/Coding practice/2024/Test Mess/1/Tests/test2.py", line 18, in test_case1
        self.assertEqual(Generic_named.main(), "Goodbye, World!")
    AssertionError: 'Hello, World!' != 'Goodbye, World!'
    - Hello, World!
    + Goodbye, World!
    
    
    ----------------------------------------------------------------------
    Ran 2 tests in 0.001s
    
    FAILED (failures=1)


  

If I try to use a different temporary name for one of the scripts I am trying to test,

 
        cat Tests/test2.py
    import unittest
    import os
    import sys
    import shutil
    
    if os.path.exists('Tests/temp/2'):
        shutil.rmtree('Tests/temp/2')
    
    shutil.copytree('Tests/mock/2', 'Tests/temp/2')
    shutil.copyfile('Programs/program2/Generic_named.py', 'Tests/temp/2/Generic_named1.py')
    
    sys.path.append('Tests/temp/2')
    import Generic_named1
    sys.path.remove('Tests/temp/2')
    
    class Test(unittest.TestCase):
        def test_case1(self):
                self.assertEqual(Generic_named1.main(), "Goodbye, World!")
    
    if __name__ == '__main__':
        unittest.main()


  

Then I get a different error:

 
        python3 -m unittest discover -p test*.py -s Tests/
    .E
    ======================================================================
    ERROR: test_case1 (test2.Test)
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "/home/s/Documents/Coding practice/2024/Test Mess/2/Tests/test2.py", line 18, in test_case1
        self.assertEqual(Generic_named1.main(), "Goodbye, World!")
      File "/home/s/Documents/Coding practice/2024/Test Mess/2/Tests/temp/2/Generic_named1.py", line 4, in main
        return custom_module.out("Goodbye, World!")
    TypeError: out() takes 0 positional arguments but 1 was given
    
    ----------------------------------------------------------------------
    Ran 2 tests in 0.001s
    
    FAILED (errors=1)


  

It seems to be trying to import the same file, despite me using a different file from a different path with the same name. This seems strange, as I've been making sure to undo any changes to the Python Path after importing what I wish to test. Is there any way to mock the path? I can't change the name of the custom_module, as that would require changing the programs I wish to test.

How should I write, approach, or setup these tests such that they can be tested with unittest discover the same as they can individually?

4 comments