python setup.py test the code using multiprocess

wrap up

--Running a unittest with a multiprocess module in setup.py results in an infinite loop --Apparently the specifications of the multiprocess module --Temporarily rewrite "\ _ \ _ main \ _ \ _" as a workaround

Premise

To run a function in multiple processes in python, use the "multiprocess" module.

The formula is easy enough to understand how to use and sample code. https://docs.python.org/ja/3/library/multiprocessing.html

Now look at the following code


from multiprocessing import Pool

def f(x):
    return x*x
def main():
    with Pool(5) as p:
        print(p.map(f, [1, 2, 3]))
main()
    

I've omitted "if \ _ \ _ name \ _ \ _ =='\ _ \ _ main \ _ \ _':" from the official sample code. Doing this would be great. (You will need a process kill in an infinite loop)

This seems to be a specification as it is officially mentioned https://docs.python.org/ja/3/library/multiprocessing.html#the-spawn-and-forkserver-start-methods

For the time being ** Do not omit "if \ _ \ _ name \ _ \ _ =='\ _ \ _ main \ _ \ _':" in code using multiprocess ** It means that.

Main subject

Now, suppose you want to create a module that uses multi-process and run unittest.

mp_test.py



from multiprocessing import Pool

def f(x):
    return x*x
def main():
    with Pool(5) as p:
        print(p.map(f, [1, 2, 3]))
if __name__ == '__main__':
    pass
    

test_mp_test.py


"""Tests for `multiprocess_test` package."""


import unittest

from mp_test import mp_test

class TestMultiprocess_test(unittest.TestCase):
    """Tests for `multiprocess_test` package."""

    def setUp(self):
        """Set up test fixtures, if any."""

    def tearDown(self):
        """Tear down test fixtures, if any."""

    def test_000_something(self):

        mp_test.main()

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

Let's test it.

$python test_mp_test.py

This can be done.

So what happens if you run this test via ** setup.py **?

Directory structure.


mp_test
  |-mp_test.py
tests
  |-test_mp_test.py
setup.py

setup.py


#!/usr/bin/env python

"""The setup script."""

from setuptools import setup, find_packages

setup(
    author="rr28",
    author_email='[email protected]',
    python_requires='>=3.5',
    description="multiprocess test.",
    entry_points={
        'console_scripts': [
            'mp_test=mp_test.mp_test:main',
        ],
    },
    name='mp_test',
    packages=find_packages(include=['mp_test', 'mp_test.*']),
    test_suite='tests',
    version='0.1.0',
)

Run

$python setup.py test

**That's right. Even though I didn't omit "if name =='main':", I get an infinite loop. ** **

Execution result

======================================================================
ERROR: test_000_something (tests.test_mp_test.TestMp_test)
Test something.
----------------------------------------------------------------------
Traceback (most recent call last):
~ Omitted ~
RuntimeError:
        An attempt has been made to start a new process before the
        current process has finished its bootstrapping phase.

        This probably means that you are not using fork to start your
        child processes and you have forgotten to use the proper idiom
        in the main module:

            if __name__ == '__main__':
                freeze_support()
                ...

        The "freeze_support()" line can be omitted if the program
        is not going to be frozen to produce an executable.

----------------------------------------------------------------------
Ran 1 test in 0.007s

FAILED (errors=1)
Test failed: <unittest.runner.TextTestResult run=1 errors=1 failures=0>
test_000_something (tests.test_mp_test.TestMp_test)
Test something. ... ERROR

The following loop
・
・
・

Workaround

I think that the test execution process of setup.py does not meet the multiprocess specification, The workaround I came up with was:

test_mp_test.py


"""Tests for `multiprocess_test` package."""


import unittest
import sys

from mp_test import mp_test

class TestMp_test(unittest.TestCase):
    """Tests for `mp_test` package."""

    def setUp(self):
        """Set up test fixtures, if any."""

    def tearDown(self):
        """Tear down test fixtures, if any."""

    def test_000_something(self):
        old_main =                          sys.modules["__main__"]
        old_main_file =                     sys.modules["__main__"].__file__
        sys.modules["__main__"] =           sys.modules["mp_test.mp_test"]
        sys.modules["__main__"].__file__ =  sys.modules["mp_test.mp_test"].__file__
        
        mp_test.main()

        sys.modules["__main__"] =           old_main
        sys.modules["__main__"].__file__ =  old_main_file

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

https://stackoverflow.com/questions/33128681/how-to-unit-test-code-that-uses-python-multiprocessing

Rewrite the running "\ _ \ _ main \ _ \ _". By doing this, you can also run unittests from setup.py.

Also, if you want to execute multi-process processing in multiple test cases, You may make it a dedicated test class and describe it in setUp and tearDown.

test_mp_test.py


import unittest
import sys

from mp_test import mp_test

class TestMp_test(unittest.TestCase):
    """Tests for `mp_test` package."""

    def setUp(self):
        """Set up test fixtures, if any."""
        self._old_main =                    sys.modules["__main__"]
        self._old_main_file =               sys.modules["__main__"].__file__
        sys.modules["__main__"] =           sys.modules["mp_test.mp_test"]
        sys.modules["__main__"].__file__ =  sys.modules["mp_test.mp_test"].__file__

    def tearDown(self):
        """Tear down test fixtures, if any."""
        sys.modules["__main__"] =           self._old_main
        sys.modules["__main__"].__file__ =  self._old_main_file

    def test_000_something(self):
        """Test something."""
        mp_test.main()

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

in conclusion

I noticed and investigated while building a test environment with tox. I don't notice it with VSC or Unittest alone, so I think it may become "Wow!" At the end of development. However, there seems to be a smarter workaround, but I would appreciate it if anyone who knows it could tell me.

Recommended Posts

python setup.py test the code using multiprocess
Aggregate test results using the QualityForward Python library
[Python] Test sample using unittest2, mock
Write selenium test code in python
Extract the targz file using python
Check python code styles using pep8
Try using the Python Cmd module
[Python] Read the Flask source code
[VS Code] ~ Tips when using python ~
Let's measure the test coverage of pushed python code on GitHub.
Try using the Wunderlist API in Python
Execute Python code on C ++ (using Boost.Python)
Try using the Kraken API in Python
Behind the flyer: Using Docker with Python
Write the test in a python docstring
Write test-driven FizzBuzz code using Python doctest.
Getting Python source code metrics using radon
[Python3] Rewrite the code object of the function
Working with OpenStack using the Python SDK
Create documentation and test code using doctest.testfile ()
Reboot the router using Python, Selenium, PhantomJS
Integrating with setuptools / python setup.py test / pytest-runner
[Python] Get the character code of the file
Get the EDINET code list in Python
Notes on using code formatter in Python
python setup.py test the code using multiprocess
Modulo without using%
FizzBuzz with regular expressions etc. without using the'%' operator
[Python] Read the source code of Bottle Part 2
About the test
[Python] Let's execute the module regularly using schedule
Try using the BitFlyer Ligntning API in Python
[Python] Test the moon matagi of relative delta
Python: Try using the UI on Pythonista 3 on iPad
Debug with VS Code using boost python numpy
python character code
Try using the Python web framework Tornado Part 1
Try CIing the pushed python code on GitHub.
Use the Python framework "cocotb" to test Verilog.
I tried using the Datetime module by Python
Python Integrity Test
Pre-process the index in Python using Solr's ScriptUpdateProcessor
[Python] Algorithm-aware code
The 3rd Algorithm Practical Test (PAST) Explanation (Python)
Try using the collections module (ChainMap) of python3
Code for checking the operation of Python Matplotlib
Find the geometric mean of n! Using Python
Convert the character code of the file with Python3
Try using the Python web framework Tornado Part 2
[Python] About multi-process
Scraping using Python
Try using the DropBox Core API in Python
Run the Blue Prism process using Python (SOAP)
Explanation of the concept of regression analysis using python Part 2
[Unity (C #), Python] Try running Python code in Unity using IronPython
[Python] I immediately tried using Pylance's VS Code extension.
Cut a part of the string using a Python slice
[AWS IoT] Register things in AWS IoT using the AWS IoT Python SDK
[CRUD] [Django] Create a CRUD site using the Python framework Django ~ 1 ~
Initial settings when using the foursquare API in python
Pass the authentication proxy through communication using python urllib3
Determine the threshold using the P tile method in python
Let's break down the basics of TensorFlow Python code