coveragepy icon indicating copy to clipboard operation
coveragepy copied to clipboard

pytest and multiprocessing: CoverageException: Can't combine line data with arc dat

Open nedbat opened this issue 7 years ago • 38 comments

Originally reported by Samuel Colvin (Bitbucket: samuelcolvin, GitHub: samuelcolvin)


I'm getting CoverageException: Can't combine line data with arc dat when using coverage with the pytest-cov pytest extension. I think this is similar to #399, but that issue is closed.

Example failure on travis: https://travis-ci.org/samuelcolvin/arq/builds/148541711

The test causing problems is using click's CliRunner, code here. The CLI command that's testing starts another process (using multiprocessing.Process) to run the worker which is what's causing the problem, if you prevent the worker process being started the exception doesn't occur.

I tried changing the concurrency mode but it made no difference.

To reproduce: clone, pip install -e . && pip install -r tests/requirements.txt, py.test --cov=arq.

relevant bits of pip freeze:

click==6.6
coverage==4.2
pytest==2.9.2
pytest-cov==2.3.0

Let me know if you need anymore information.


  • Bitbucket: https://bitbucket.org/ned/coveragepy/issue/512

nedbat avatar Jul 30 '16 15:07 nedbat

Original comment by Miguel Sánchez de León Peque (Bitbucket: Peque, GitHub: Peque)


@ionelmc Thanks. That helped and it currently finishes the report. However, the source and omit parameters are ignored.

Have not figured out why. Here is the repo/branch: https://github.com/Peque/osbrain/tree/coverage

nedbat avatar May 30 '17 12:05 nedbat

Original comment by Ionel Cristian Mărieș (Bitbucket: ionelmc, GitHub: ionelmc)


Maybe you need to tell pytest-cov what is the coverage config file (eg --cov-config=setup.cfg).

nedbat avatar May 29 '17 14:05 nedbat

Original comment by Miguel Sánchez de León Peque (Bitbucket: Peque, GitHub: Peque)


I think I may have hit this issue too.

Builds used to pass without any problems, but when moving the configuration from .coveragerc to setup.cfg (https://github.com/Peque/osbrain/commit/f9eb8c65c5f0e16618b6602786e74eaff9e46a4a), it fails (https://travis-ci.org/Peque/osbrain/builds/237146025?utm_source=github_status&utm_medium=notification).

nedbat avatar May 29 '17 14:05 nedbat

Original comment by Loic Dachary (Bitbucket: dachary, GitHub: dachary)


The following patch retries with the coverage: prefix if a non default file was specified and nothing was read from it. There could be a cleaner way to do the same and I'm willing to work on it if you think it is worth implementing. To be fully backward compatible it should only retry with the coverage: prefix in the case where a file was provided and nothing was read from it because it serves no useful purpose. Unless there is a valid use case for --rcfile=/dev/null ?

#!diff

diff -r [24aff3d7bfd5 (bb)](https://bitbucket.org/ned/coveragepy/commits/24aff3d7bfd5) coverage/config.py
--- a/coverage/config.py	Mon Dec 12 08:26:18 2016 +0100
+++ b/coverage/config.py	Thu Dec 15 10:35:14 2016 +0100
@@ -151,6 +151,7 @@
         # Metadata about the config.
         self.attempted_config_files = []
         self.config_files = []
+        self.any_set = False
 
         # Defaults for [run]
         self.branch = False
@@ -223,12 +224,11 @@
 
         self.config_files.extend(files_read)
 
-        any_set = False
         try:
             for option_spec in self.CONFIG_FILE_OPTIONS:
                 was_set = self._set_attr_from_config_option(cp, *option_spec)
                 if was_set:
-                    any_set = True
+                    self.any_set = True
         except ValueError as err:
             raise CoverageException("Couldn't read config file %s: %s" % (filename, err))
 
@@ -253,18 +253,18 @@
         if cp.has_section('paths'):
             for option in cp.options('paths'):
                 self.paths[option] = cp.getlist('paths', option)
-                any_set = True
+                self.any_set = True
 
         # plugins can have options
         for plugin in self.plugins:
             if cp.has_section(plugin):
                 self.plugin_options[plugin] = cp.get_section(plugin)
-                any_set = True
+                self.any_set = True
 
         # Was this file used as a config file? If no prefix, then it was used.
         # If a prefix, then it was only used if we found some settings in it.
         if section_prefix:
-            return any_set
+            return self.any_set
         else:
             return True
 
@@ -422,9 +422,12 @@
             config_read = config.from_file(fname, section_prefix=prefix)
             is_config_file = fname == config_file
 
-            if not config_read and is_config_file and specified_file:
-                raise CoverageException("Couldn't read '%s' as a config file" % fname)
-
+            if is_config_file and specified_file:
+                if not config_read:
+                    raise CoverageException("Couldn't read '%s' as a config file" % fname)
+                if not config.any_set:
+                    config_read = config.from_file(fname, section_prefix="coverage:")
+                    
             if config_read:
                 break
 

nedbat avatar Dec 15 '16 09:12 nedbat

Original comment by Ionel Cristian Mărieș (Bitbucket: ionelmc, GitHub: ionelmc)


I don't see how it's relevant. pytest-cov doesn't read the file, it will only pass the absolute path (if it exists).

nedbat avatar Aug 07 '16 22:08 nedbat

The sections are named differently ("[run]" vs "[coverage:run]"). If you specify setup.cfg as the file, coverage.py will try to read the "[run]" section and won't find it. It only looks for "[coverage:run]" when it is reading setup.cfg because it couldn't find .coveragerc.

Of course, this behavior could change, but that's the way the code is now.

nedbat avatar Aug 07 '16 22:08 nedbat

Original comment by Ionel Cristian Mărieș (Bitbucket: ionelmc, GitHub: ionelmc)


What do you mean, "discovered implicitly"?

nedbat avatar Aug 07 '16 22:08 nedbat

@ionelmc it isn't enough to tell coverage.py to use setup.cfg. It won't be read properly unless it is discovered implicitly.

nedbat avatar Aug 07 '16 22:08 nedbat

Original comment by Ionel Cristian Mărieș (Bitbucket: ionelmc, GitHub: ionelmc)


pytest-cov could have an improvement to use setup.cfg if .coveragerc don't exist (same as coverage, but with pytest-cov's correct handling of relatiev paths). Open a bug report if you want it.

nedbat avatar Aug 07 '16 22:08 nedbat

Original comment by Samuel Colvin (Bitbucket: samuelcolvin, GitHub: samuelcolvin)


Ned, thanks so much for the help. I've switched to using .coveragerc and that seems to have fixed it.

Perhaps a comment in the docs saying that using setup.cfg is not always the same as using .coveragerc would be useful?

nedbat avatar Aug 07 '16 22:08 nedbat

I've come to some different conclusions that Ionel did, though he was very helpful in getting me going with debugging with his aspectlib.

The problem here is the Process spawned by test_repeat_worker_close. It doesn't find the same configuration file that the rest of the tests do. Specifying --cov-config=setup.cfg doesn't help, because coverage.py only reads that file properly when it is read implicitly, not explicitly (that could be the subject of another bug report).

I think this is a combination of the direct use of Process, which perhaps coverage.py hasn't patched enough, and having settings in the implicitly-read setup.cfg file.

One simple solution is to move your coverage.py settings into a .coveragerc file. If you do that, things work.

nedbat avatar Aug 06 '16 16:08 nedbat

Original comment by Ionel Cristian Mărieș (Bitbucket: ionelmc, GitHub: ionelmc)


I've taken a look at this as well, my opinion is that a combination of configuration, subprocess use and cwd changes cause the problem. That's why you get the data file saved without arcs (branch=False).

There are thee ways to deal with this:

  • Specify --cov-config=setup.cfg (pytest-cov will absolutize it before tmpworkdir is used). Alternatively, you could use a .coveragerc (pytest-cov absolutize that if it exists).
  • Fix the test to not use subprocesses. Afaik the test spawns a suprocess that sigterms the parent. This makes no sense to me - you can do that with no subprocess at all. Eg: signal.kill(os.getpid(), signal.SIGTERM) or even a thread.
  • Stop changing current working directory (tmpworkdir fixture).

There is no bug in either coverage or pytest-cov here.

Also, note that concurrency = multiprocessing is completely un-necessary if you use pytest-cov (it completely manages coverage measurements in subprocesses for you).

nedbat avatar Aug 06 '16 14:08 nedbat

Original comment by Samuel Colvin (Bitbucket: samuelcolvin, GitHub: samuelcolvin)


Sorry about that, on ubuntu redis runs as a service so is always there. I've dusted off my mac and tried to run the code however brew seems to be broken so I can't install python3.5.

As far as I know it should be as simple:

  • brew install redis
  • redis-server, leave the terminal with redis running
  • in another terminal in the arq directory git fetch && git checkout coverage-broken (I've added a test on that branch which breaks coverage), see here.
  • run py.test all tests should pass
  • run py.test --cov=arq you should get CoverageException as on travis.

nedbat avatar Aug 05 '16 11:08 nedbat

@samuelcolvin I'm willing to try reproducing this, but I need explicit instructions, or I'll wander in the redis-wilderness for a while. What should I do on my Mac to get things to pass? Do you think the test failures are preventing the coverage failure?

nedbat avatar Aug 05 '16 11:08 nedbat

Original comment by Samuel Colvin (Bitbucket: samuelcolvin, GitHub: samuelcolvin)


looks like you don't have redis installed.

nedbat avatar Aug 05 '16 09:08 nedbat

I tried running your scenario, and did not get the error you describe. The full output is here: https://gist.github.com/nedbat/a482ea69fa509de5e0a7c3da8f378e4b

The test run ends with:

 tests/test_worker.py ✓✓✓✓✓✓✓✓✓✓✓                                                                                                                100% ██████████

---------- coverage: platform darwin, python 3.5.2-final-0 -----------
Name              Stmts   Miss Branch BrPart  Cover
---------------------------------------------------
arq/__init__.py       4      0      0      0   100%
arq/cli.py           15      0      0      0   100%
arq/logs.py          18      1      2      1    90%
arq/main.py          85      1     22      1    98%
arq/testing.py      164      6     34      0    97%
arq/utils.py         53      2     12      1    95%
arq/version.py        2      0      0      0   100%
arq/worker.py       245     31     54      4    88%
---------------------------------------------------
TOTAL               586     41    124      7    93%


Results (4.23s):
      29 passed
      11 failed
         - /usr/local/pythonz/pythons/CPython-3.5.2/lib/python3.5/asyncio/base_events.py:704: OSError: Multiple exceptions: [Errno 61] Connect call failed ('127.0.0.1', 6379), [Errno 61] Connect call failed ('::1', 6379), [Errno 61] Connect call failed ('fe80::1%lo0', 6379, 0, 1)
         - /usr/local/pythonz/pythons/CPython-3.5.2/lib/python3.5/asyncio/base_events.py:704: OSError: Multiple exceptions: [Errno 61] Connect call failed ('127.0.0.1', 6379), [Errno 61] Connect call failed ('::1', 6379), [Errno 61] Connect call failed ('fe80::1%lo0', 6379, 0, 1)
         - /Users/ned/foo/arq/tests/test_main.py:137: assert None
         - /usr/local/pythonz/pythons/CPython-3.5.2/lib/python3.5/asyncio/base_events.py:704: OSError: Multiple exceptions: [Errno 61] Connect call failed ('127.0.0.1', 6379), [Errno 61] Connect call failed ('::1', 6379), [Errno 61] Connect call failed ('fe80::1%lo0', 6379, 0, 1)
         - /usr/local/pythonz/pythons/CPython-3.5.2/lib/python3.5/asyncio/base_events.py:704: OSError: Multiple exceptions: [Errno 61] Connect call failed ('127.0.0.1', 6379), [Errno 61] Connect call failed ('::1', 6379), [Errno 61] Connect call failed ('fe80::1%lo0', 6379, 0, 1)
         - /usr/local/pythonz/pythons/CPython-3.5.2/lib/python3.5/asyncio/base_events.py:704: OSError: Multiple exceptions: [Errno 61] Connect call failed ('127.0.0.1', 6379), [Errno 61] Connect call failed ('::1', 6379), [Errno 61] Connect call failed ('fe80::1%lo0', 6379, 0, 1)
         - /usr/local/pythonz/pythons/CPython-3.5.2/lib/python3.5/asyncio/base_events.py:704: OSError: Multiple exceptions: [Errno 61] Connect call failed ('127.0.0.1', 6379), [Errno 61] Connect call failed ('::1', 6379), [Errno 61] Connect call failed ('fe80::1%lo0', 6379, 0, 1)
         - /usr/local/pythonz/pythons/CPython-3.5.2/lib/python3.5/asyncio/base_events.py:704: OSError: Multiple exceptions: [Errno 61] Connect call failed ('127.0.0.1', 6379), [Errno 61] Connect call failed ('::1', 6379), [Errno 61] Connect call failed ('fe80::1%lo0', 6379, 0, 1)
         - /usr/local/pythonz/pythons/CPython-3.5.2/lib/python3.5/asyncio/base_events.py:704: OSError: Multiple exceptions: [Errno 61] Connect call failed ('127.0.0.1', 6379), [Errno 61] Connect call failed ('::1', 6379), [Errno 61] Connect call failed ('fe80::1%lo0', 6379, 0, 1)
         - /usr/local/pythonz/pythons/CPython-3.5.2/lib/python3.5/asyncio/base_events.py:704: OSError: Multiple exceptions: [Errno 61] Connect call failed ('127.0.0.1', 6379), [Errno 61] Connect call failed ('::1', 6379), [Errno 61] Connect call failed ('fe80::1%lo0', 6379, 0, 1)
         - /usr/local/pythonz/pythons/CPython-3.5.2/lib/python3.5/asyncio/base_events.py:704: OSError: Multiple exceptions: [Errno 61] Connect call failed ('127.0.0.1', 6379), [Errno 61] Connect call failed ('::1', 6379), [Errno 61] Connect call failed ('fe80::1%lo0', 6379, 0, 1)

I'm not sure what caused my test failures, but I wouldn't think they are significant in this case.

nedbat avatar Aug 04 '16 22:08 nedbat

Original comment by Samuel Colvin (Bitbucket: samuelcolvin, GitHub: samuelcolvin)


Same error with hg clone ... setup.py install I'm afraid:

...
INTERNALERROR>   File "/home/samuel/code/arq/env/lib/python3.5/site-packages/pytest_cov/engine.py", line 150, in finish
INTERNALERROR>     self.cov.combine()
INTERNALERROR>   File "/home/samuel/code/arq/env/lib/python3.5/site-packages/coverage-4.2.1a0-py3.5-linux-x86_64.egg/coverage/control.py", line 822, in combine
INTERNALERROR>     self.data_files.combine_parallel_data(self.data, aliases=aliases, data_paths=data_paths)
INTERNALERROR>   File "/home/samuel/code/arq/env/lib/python3.5/site-packages/coverage-4.2.1a0-py3.5-linux-x86_64.egg/coverage/data.py", line 716, in combine_parallel_data
INTERNALERROR>     data.update(new_data, aliases=aliases)
INTERNALERROR>   File "/home/samuel/code/arq/env/lib/python3.5/site-packages/coverage-4.2.1a0-py3.5-linux-x86_64.egg/coverage/data.py", line 481, in update
INTERNALERROR>     raise CoverageException("Can't combine line data with arc data")
INTERNALERROR> coverage.misc.CoverageException: Can't combine line data with arc data

nedbat avatar Aug 04 '16 17:08 nedbat

@samuelcolvin Sorry, I haven't started digging into this. It does sounds a lot like the fix I put in 4.2, so I will have to look at it soon. Have you tried it with the tip of coverage.py?

nedbat avatar Aug 04 '16 17:08 nedbat

Original comment by Samuel Colvin (Bitbucket: samuelcolvin, GitHub: samuelcolvin)


Any update on this? I'm currently having to choose between coverage and running some tests.

nedbat avatar Aug 04 '16 16:08 nedbat

One simple solution is to move your coverage.py settings into a .coveragerc file. If you do that, things work.

My project uses a .coveragerc file and coverage reporting still fails with this error what seems like 1 in 3 runs.

joshfriend avatar Aug 04 '21 15:08 joshfriend

@joshfriend can you give us specific instructions to reproduce what you are seeing, even if it's cloning your full project?

nedbat avatar Aug 04 '21 21:08 nedbat

Feel free to re-open if you get more information.

nedbat avatar Feb 03 '22 02:02 nedbat

Thanks for the reminder, sorry I was not able to give a full project example (it's proprietary). I may still be able to extract a shareable example from it though someday.

The only insight I have is that we use testing.postgresql to create temporary postgres database instances for integration testing. This may introduce subprocesses to the tests, but I didn't think of that initially because the code being tested doesn't use subprocesses. In CI we attach a postgres docker container instead of using the testing.postgresql package, which is probably why tests never fail with this coverage exception in CI.

joshfriend avatar Feb 03 '22 15:02 joshfriend

@joshfriend Thanks for still trying. One way to get more information is to run with coverage debugging. You can add this to your configuration file:

[run]
debug = process, pid, dataio, dataop

The debug output will go to stderr, but you can redirect it to a file with the COVERAGE_DEBUG_FILE environment variable (odd that it can't be set from the configuration file...).

You will get a lot of information. Let's see what it says.

nedbat avatar Feb 03 '22 16:02 nedbat

I don't see anything weird in this debug log, but this is from a test session that ended with the Can't combine arc data with line data failure:

41553.9654: cwd is now '/Users/jfriend/proj-dir'
41553.9654: New process: executable: '/Users/jfriend/proj-dir/.venv/bin/python'
41553.9654: New process: cmd: ['/Users/jfriend/proj-dir/.venv/bin/pytest', 'tests', '--random-order', 'tests', '-W', 'ignore::cryptography.utils.CryptographyDeprecationWarning', '-W', 'ignore::DeprecationWarning', '--random-order-seed=278164', '--cov=cirrus', '--cov-config', '.coveragerc', '--cov-report', 'html', '--cov-report', 'xml', '--junitxml=junit_report.xml']
41553.9654: New process: pid: 41553, parent pid: 41523
41553.9654: Erasing data file '/Users/jfriend/proj-dir/.coverage'
41553.9654: Setting context: None
41553.9654: Adding arcs: 73 files, 4760 arcs total
41553.9654: Erasing data file '/Users/jfriend/proj-dir/.coverage.MacBook-Pro.skynet.41553.515875'
41553.9654: Opening data file '/Users/jfriend/proj-dir/.coverage.MacBook-Pro.skynet.41553.515875'
41553.9654: Initing data file '/Users/jfriend/proj-dir/.coverage.MacBook-Pro.skynet.41553.515875'
41553.9654: Adding file tracers: 0 files
41553.9654: Touching ['...snip...']
41553.9654: Opening data file '/Users/jfriend/proj-dir/.coverage'
41553.9654: Combining data file '/Users/jfriend/proj-dir/.coverage.MacBook-Pro.skynet.41553.515875'
41553.9654: Opening data file '/Users/jfriend/proj-dir/.coverage.MacBook-Pro.skynet.41553.515875'
41553.9654: Updating with data from '/Users/jfriend/proj-dir/.coverage.MacBook-Pro.skynet.41553.515875'
41553.9654: atexit: pid: 41553, instance: <coverage.control.Coverage object at 0x109f50460>

For full context:

  • Coverage 6.3 (also tried 6.3.1)
  • Python 3.8.5
  • macOS 12.1
  • I have an M1 mac, but the python binary is built with x86_64 architecture, and I've had this error plenty of times on my intel mac as well.
  • I've tried a native arm64 python3.10.2 as well, still got the error

.coveragerc file:

[run]
branch = true
relative_files = true
debug = process, pid, dataio, dataop
omit =
    */env/*
    */test/*
    log_lint_plugin.py

[report]
fail_under = 100
exclude_lines =
    def __repr__
    def __str__
    def __unicode__
    pragma: no cover

joshfriend avatar Feb 03 '22 18:02 joshfriend

Thanks. Does this include the "dataop" setting, and is it the full log (other than "...snip...")? I've added another debug message to coverage master, if you could run it again with dataop.

nedbat avatar Feb 03 '22 23:02 nedbat

Yes, dataop was included, and thats a full output to the file I specified with COVERAGE_DEBUG_FILE. What's inside snip is just a list of all the python files in my project.

I updated to coverage @ cf712c6 and almost immediately had one failing test run. The log output looked identical to before, though so far I have only had one CoverageException failure, so I'm not 100% confident in the logs below. I'll include them anyways and keep trying. Unfortunately, when I'm actively looking for things to fail, it seems to happen far less frequently 😆

27174.f71d: cwd is now '/Users/jfriend/proj-dir'
27174.f71d: New process: executable: '/Users/jfriend/proj-dir/.venv/bin/python'
27174.f71d: New process: cmd: ['/Users/jfriend/proj-dir/.venv/bin/pytest', 'tests', '--random-order', 'tests', '--cov=cirrus', '--cov-config', '.coveragerc', '--cov-report', 'html', '--cov-report', 'xml', '--junitxml=junit_report.xml']
27174.f71d: New process: pid: 27174, parent pid: 27006
27174.f71d: Erasing data file '/Users/jfriend/proj-dir/.coverage'
27174.f71d: Setting context: None
27174.f71d: Adding arcs: 72 files, 4698 arcs total
27174.f71d: Erasing data file '/Users/jfriend/proj-dir/.coverage.MacBook-Pro.skynet.27174.812723'
27174.f71d: Opening data file '/Users/jfriend/proj-dir/.coverage.MacBook-Pro.skynet.27174.812723'
27174.f71d: Initing data file '/Users/jfriend/proj-dir/.coverage.MacBook-Pro.skynet.27174.812723'
27174.f71d: Adding file tracers: 0 files
27174.f71d: Touching ['...snip...']
27174.f71d: Opening data file '/Users/jfriend/proj-dir/.coverage'
27174.f71d: Combining data file '/Users/jfriend/proj-dir/.coverage.MacBook-Pro.skynet.27174.812723'
27174.f71d: Opening data file '/Users/jfriend/proj-dir/.coverage.MacBook-Pro.skynet.27174.812723'
27174.f71d: Updating with data from '/Users/jfriend/proj-dir/.coverage.MacBook-Pro.skynet.27174.812723'
27174.f71d: atexit: pid: 27174, instance: <coverage.control.Coverage object at 0x10acda490>

Also, I'm not sure if this is expected, but when debug is printed to stderr instead of a file, an exception is thrown at the end:

Exception ignored in atexit callback: <bound method Coverage._atexit of <coverage.control.Coverage object at 0x105a06470>>
Traceback (most recent call last):
  File "/Users/jfriend/proj-dir/.venv/lib/python3.10/site-packages/coverage/control.py", line 600, in _atexit
    self._debug.write(f"{event}: pid: {os.getpid()}, instance: {self!r}")
  File "/Users/jfriend/proj-dir/.venv/lib/python3.10/site-packages/coverage/debug.py", line 74, in write
    self.output.write(msg+"\n")
  File "/Users/jfriend/proj-dir/.venv/lib/python3.10/site-packages/coverage/debug.py", line 319, in write
    self.outfile.write(filter_text(text, self.filters))
ValueError: I/O operation on closed file.

joshfriend avatar Feb 04 '22 15:02 joshfriend

Just ran into this bug and worked around it with --cov-config=.coveragerc. Symptomology is similar to @joshfriend above, but my project uses pyproject.toml and expected coverage.py to find its configuration there in multiprocess Processes.

Unfortunately, those subprocesses were not reading the toml file, and were generating data in arc instead of line (or vice-versa, I can't remember...), thus the error. I had to copy my config out of the pyproject.toml file into .coveragerc and use the --cov-config option with pytest-cov to force reading of it in all subprocesses.

Prior to the patch, there was some weirdness with collectors on Windows.

Tests would always show this kind of noise:

tests/test_hough.py::test_form_pdf
self._collectors:
  <Collector at 0x25409186df0: CTracer>
                _find_and_load : <frozen importlib._bootstrap>:1007
       _find_and_load_unlocked : <frozen importlib._bootstrap>:986
                _load_unlocked : <frozen importlib._bootstrap>:680
                   exec_module : <frozen importlib._bootstrap_external>:850
     _call_with_frames_removed : <frozen importlib._bootstrap>:228
                      <module> : C:\Python39\lib\site.py:589
                          main : C:\Python39\lib\site.py:576
               addsitepackages : C:\Python39\lib\site.py:359
                    addsitedir : C:\Python39\lib\site.py:208
                    addpackage : C:\Python39\lib\site.py:169
                      <module> : <string>:1
                      <module> : <string>:4
                          init : C:\Users\Joan\AppData\Local\pypoetry\Cache\virtualenvs\hough-Va69xgWd-py3.9\lib\site-packages\pytest_cov\embed.py:52
                         start : C:\Users\Joan\AppData\Local\pypoetry\Cache\virtualenvs\hough-Va69xgWd-py3.9\lib\site-packages\coverage\control.py:575
               _init_for_start : C:\Users\Joan\AppData\Local\pypoetry\Cache\virtualenvs\hough-Va69xgWd-py3.9\lib\site-packages\coverage\control.py:483
                      __init__ : C:\Users\Joan\AppData\Local\pypoetry\Cache\virtualenvs\hough-Va69xgWd-py3.9\lib\site-packages\coverage\collector.py:114
  <Collector at 0x2540924e190: CTracer>
                      <module> : <string>:1
                    spawn_main : C:\Python39\lib\multiprocessing\spawn.py:116
                         _main : C:\Python39\lib\multiprocessing\spawn.py:129
                    _bootstrap : C:\Users\Joan\AppData\Local\pypoetry\Cache\virtualenvs\hough-Va69xgWd-py3.9\lib\site-packages\coverage\multiproc.py:32
                         start : C:\Users\Joan\AppData\Local\pypoetry\Cache\virtualenvs\hough-Va69xgWd-py3.9\lib\site-packages\coverage\control.py:575
               _init_for_start : C:\Users\Joan\AppData\Local\pypoetry\Cache\virtualenvs\hough-Va69xgWd-py3.9\lib\site-packages\coverage\control.py:483
                      __init__ : C:\Users\Joan\AppData\Local\pypoetry\Cache\virtualenvs\hough-Va69xgWd-py3.9\lib\site-packages\coverage\collector.py:114
Analysis:   0%|                                                                                              | 0/1 [00:00<?, ?pg/s]self._collectors:
  <Collector at 0x26014147df0: CTracer>
                _find_and_load : <frozen importlib._bootstrap>:1007
       _find_and_load_unlocked : <frozen importlib._bootstrap>:986
                _load_unlocked : <frozen importlib._bootstrap>:680
                   exec_module : <frozen importlib._bootstrap_external>:850
     _call_with_frames_removed : <frozen importlib._bootstrap>:228
                      <module> : C:\Python39\lib\site.py:589
                          main : C:\Python39\lib\site.py:576
               addsitepackages : C:\Python39\lib\site.py:359
                    addsitedir : C:\Python39\lib\site.py:208
                    addpackage : C:\Python39\lib\site.py:169
                      <module> : <string>:1
                      <module> : <string>:4
                          init : C:\Users\Joan\AppData\Local\pypoetry\Cache\virtualenvs\hough-Va69xgWd-py3.9\lib\site-packages\pytest_cov\embed.py:52
                         start : C:\Users\Joan\AppData\Local\pypoetry\Cache\virtualenvs\hough-Va69xgWd-py3.9\lib\site-packages\coverage\control.py:575
               _init_for_start : C:\Users\Joan\AppData\Local\pypoetry\Cache\virtualenvs\hough-Va69xgWd-py3.9\lib\site-packages\coverage\control.py:483
                      __init__ : C:\Users\Joan\AppData\Local\pypoetry\Cache\virtualenvs\hough-Va69xgWd-py3.9\lib\site-packages\coverage\collector.py:114
  <Collector at 0x26077a9d0a0: CTracer>
                      <module> : <string>:1
                    spawn_main : C:\Python39\lib\multiprocessing\spawn.py:116
                         _main : C:\Python39\lib\multiprocessing\spawn.py:129
                    _bootstrap : C:\Users\Joan\AppData\Local\pypoetry\Cache\virtualenvs\hough-Va69xgWd-py3.9\lib\site-packages\coverage\multiproc.py:32
                         start : C:\Users\Joan\AppData\Local\pypoetry\Cache\virtualenvs\hough-Va69xgWd-py3.9\lib\site-packages\coverage\control.py:575
               _init_for_start : C:\Users\Joan\AppData\Local\pypoetry\Cache\virtualenvs\hough-Va69xgWd-py3.9\lib\site-packages\coverage\control.py:483
                      __init__ : C:\Users\Joan\AppData\Local\pypoetry\Cache\virtualenvs\hough-Va69xgWd-py3.9\lib\site-packages\coverage\collector.py:114
self._collectors:
  <Collector at 0x13aaad36df0: CTracer>
                _find_and_load : <frozen importlib._bootstrap>:1007
       _find_and_load_unlocked : <frozen importlib._bootstrap>:986
                _load_unlocked : <frozen importlib._bootstrap>:680
                   exec_module : <frozen importlib._bootstrap_external>:850
     _call_with_frames_removed : <frozen importlib._bootstrap>:228
                      <module> : C:\Python39\lib\site.py:589
                          main : C:\Python39\lib\site.py:576
               addsitepackages : C:\Python39\lib\site.py:359
                    addsitedir : C:\Python39\lib\site.py:208
                    addpackage : C:\Python39\lib\site.py:169
                      <module> : <string>:1
                      <module> : <string>:4
                          init : C:\Users\Joan\AppData\Local\pypoetry\Cache\virtualenvs\hough-Va69xgWd-py3.9\lib\site-packages\pytest_cov\embed.py:52
                         start : C:\Users\Joan\AppData\Local\pypoetry\Cache\virtualenvs\hough-Va69xgWd-py3.9\lib\site-packages\coverage\control.py:575
               _init_for_start : C:\Users\Joan\AppData\Local\pypoetry\Cache\virtualenvs\hough-Va69xgWd-py3.9\lib\site-packages\coverage\control.py:483
                      __init__ : C:\Users\Joan\AppData\Local\pypoetry\Cache\virtualenvs\hough-Va69xgWd-py3.9\lib\site-packages\coverage\collector.py:114
...

but only on Windows. Go figure.

Hope this detail helps track down the bug.

wohali avatar Mar 08 '22 15:03 wohali

I get this error when I use branch = true. @wohali @joshfriend can you confirm this with your repo?

charmoniumQ avatar Apr 12 '22 17:04 charmoniumQ

I do use branch = true, I posted my entire coveragerc in an earlier comment: https://github.com/nedbat/coveragepy/issues/512#issuecomment-1030099482

joshfriend avatar Apr 12 '22 17:04 joshfriend

My question is: does turning off branch = true fix the crash in your repo?

charmoniumQ avatar Apr 12 '22 17:04 charmoniumQ

The issue is not able to be replicated reliably in my projects, so unfortunately I could not tell you

joshfriend avatar Apr 12 '22 17:04 joshfriend

I get this error when I use branch = true. @wohali @joshfriend can you confirm this with your repo?

Yes, I use branch = true. As I understand it this changes the format of the file, as I mentioned above, so the results cannot be combined with runs that don't include that. Something to do with multiprocess runs and the toml file not being included caused the mixed format issue for me.

wohali avatar Apr 18 '22 23:04 wohali

Just ran into this bug and worked around it with --cov-config=.coveragerc. Symptomology is similar to @joshfriend above, but my project uses pyproject.toml and expected coverage.py to find its configuration there in multiprocess Processes.

We also use pyproject.toml for our coverage configuration, and wanted to mention that I both encountered and was (seemingly) able to work around this issue by explicitly specifying --cov-config=pyproject.toml as an argument when invoking pytest. Explicitly passing the path of the config file seemed to be sufficient without also extracting it out into .coveragerc format.

dmartin avatar Apr 19 '22 00:04 dmartin

I have been using explicit --cov-config=path/to/.coveragerc the entire time as my projects use a git submodule to share the coverage/linter/etc configs across projects.

I have not changed anything about my coverage setup other than to update coverage.py as new versions come out periodically, and I rarely see this issue anymore. It used to happen quite frequently, but recently is so infrequent that I can't try anything to debug it, but it is also not annoying anymore so I stopped trying.

joshfriend avatar Apr 19 '22 02:04 joshfriend

We also use pyproject.toml for our coverage configuration, and wanted to mention that I both encountered and was (seemingly) able to work around this issue by explicitly specifying --cov-config=pyproject.toml as an argument when invoking pytest. Explicitly passing the path of the config file seemed to be sufficient without also extracting it out into .coveragerc format.

Tried this and it didn't work -- is your project multiprocess as well?

wohali avatar Apr 19 '22 03:04 wohali

Tried this and it didn't work -- is your project multiprocess as well?

Hmm, our project itself doesn't use multiprocessing so I suppose the scenario is slightly different, but we do use pytest-xdist to distribute test cases across cores, which seems to be the cause of the error in our case.

dmartin avatar Apr 19 '22 07:04 dmartin

Original comment by Ionel Cristian Mărieș (Bitbucket: ionelmc, GitHub: ionelmc)

I've taken a look at this as well, my opinion is that a combination of configuration, subprocess use and cwd changes cause the problem. That's why you get the data file saved without arcs (branch=False).

There are thee ways to deal with this:

* Specify `--cov-config=setup.cfg` (pytest-cov will absolutize it before `tmpworkdir` is used). Alternatively, you could use a `.coveragerc` (pytest-cov absolutize that if it exists).

* Fix the test to not use subprocesses. Afaik the test spawns a suprocess that sigterms the parent. This makes no sense to me - you can do that with no subprocess at all. Eg: `signal.kill(os.getpid(), signal.SIGTERM)` or even a thread.

* Stop changing current working directory (`tmpworkdir` fixture).

There is no bug in either coverage or pytest-cov here.

Also, note that concurrency = multiprocessing is completely un-necessary if you use pytest-cov (it completely manages coverage measurements in subprocesses for you).

Specifying --cov-config=setup.cfg as an addopted parameter in my setup.cfg solved the issue for me. Thanks!

Here are a few keywords on my setting so others might find this solution: I use hydra config manager (which changes the current directory), and have a subprocess called thanks to sh.python(command). In addition, I use the tmp_dir fixture.

CharlesGaydon avatar Apr 27 '22 13:04 CharlesGaydon