CleanCut / green

Green is a clean, colorful, fast python test runner.
MIT License
793 stars 75 forks source link

FileNotFoundError when using multiprocessing Process and Value in tests. #154

Closed cjwelborn closed 7 years ago

cjwelborn commented 7 years ago

I'm testing a subclass of multiprocessing.Process, using a multiprocessing.Value to share some values with the caller of the process. All of the other test runners can run these tests with no problem (nose, py.test), but if I run them with green I'm getting a FileNotFoundError. It looks like there is some cleanup of /tmp files happening twice, but I'm not sure about that. Here is the minimum code required to produce this error:

import multiprocessing
import unittest
from ctypes import c_double

class ProcessTests(unittest.TestCase):
    """ Debugging FileNotFoundError when using a multiprocessing.Value. """

    def test_process(self):

        def func(v):
            v.value = 1.23
            print(v.value)

        val = multiprocessing.Value(c_double, 0)
        p = multiprocessing.Process(
            target=func,
            args=(val, )
        )

The process is never started. Just initializing it will cause this. Here is the output I am getting:

test.test_progress
  ProcessTests
.   test_process
Traceback (most recent call last):
  File "/usr/lib/python3.5/multiprocessing/util.py", line 254, in _run_finalizers
    finalizer()
  File "/usr/lib/python3.5/multiprocessing/util.py", line 186, in __call__
    res = self._callback(*self._args, **self._kwargs)
  File "/usr/lib/python3.5/shutil.py", line 465, in rmtree
    onerror(os.lstat, path, sys.exc_info())
  File "/usr/lib/python3.5/shutil.py", line 463, in rmtree
    orig_st = os.lstat(path)
FileNotFoundError: [Errno 2] No such file or directory: '/tmp/tmpqt6h940m/pymp-u9261qui'

Ran 1 test in 0.118s

OK (passes=1)

I've tried patching multiprocessing.util._run_finalizers, or just catching bad Finalize objects from multiprocessing.util._finalizer_registry and cancel()ing them, but I can't seem to catch it in time. I don't know exactly where this Finalize callback is being created or called when running this test through green. I can inspect the Finalize objects/callbacks during setUp, tearDown, or while the test is running (in the method body, before or after initializing the Process), and I see a few callbacks, but none with the filename/address that is being reported as "not found". If I could find it, then I could cancel it.

Anyway, I thought maybe someone else might know more about what's going on here, or how to fix it. I really like using green. Thanks for creating/maintaining it :smile:. Hopefully there is a simple fix/workaround for this.

P.S. - I've been debugging multi-process stuff (communication mainly) in my own little project for a while now, hence the need for tests, and wrapping my stuff in unittest or green's multi-process stuff and then trying to debug this error is giving me a headache :face_with_head_bandage:. Thank you for any pointers you can give me about this little problem.

Green Version: 2.7.0 Python Version: 3.5.2

CleanCut commented 7 years ago

I'm so sorry this is causing you a problem! Green uses multiprocess internally and each process customizes the tempfile directory location so that code being tested that uses temp files won't ever have collisions (so long as the tempfile module is being used).

So...there's a bunch of things that could be interacting with your problem. I'll dig into it as soon as I can and see if I can figure out what's going on.

cjwelborn commented 7 years ago

Awesome, thanks for taking the time. :smile: I'll probably dig into it a little bit more just in case I missed something.

cjwelborn commented 7 years ago

@CleanCut, thanks for taking care of this. What's the release schedule for green as far as PyPi (pip) is concerned? I was wondering when I should start looking to upgrade to 2.7.1.

CleanCut commented 7 years ago

ASAP. I try to always add a comment to each issue stating the release it has been fixed in. I'm dealing with flaky pypy builds on Travis. If it fails one more time, I'm going to move pypy over to the "ignore" section. There's something wrong with pypy on Travis. It just randomly fails when multiprocessing in random places -- but always with a timeout, which is something I've never been able to replicate on any real machine.

CleanCut commented 7 years ago

That was quick. Re-running the pypy build passed for now, so it is spared a little while longer.

The fix for this issue is in 2.7.1.

cjwelborn commented 7 years ago

@CleanCut, awesome :smile: . Already installed and tests are passing! Thanks again for the fix.

CleanCut commented 7 years ago

No problem! I don't like bugs. They ought to be squashed. ;-)