summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNed Batchelder <ned@nedbatchelder.com>2019-12-23 15:45:39 -0500
committerNed Batchelder <ned@nedbatchelder.com>2019-12-23 18:01:49 -0500
commitdf82a9638cd8fbe8a33c5969ff9c0d348d069adb (patch)
treeb5b83ea6a199deef9a02c1faa17343dd6ce1ff52
parent7fb6fc15d88778f15a49ab1e63bdf550c2c7c981 (diff)
downloadpython-coveragepy-git-df82a9638cd8fbe8a33c5969ff9c0d348d069adb.tar.gz
Use abspath to rc file so that chdir doesn't bork us. #890
-rw-r--r--CHANGES.rst8
-rw-r--r--coverage/config.py5
-rw-r--r--coverage/multiproc.py3
-rw-r--r--tests/test_concurrency.py19
4 files changed, 31 insertions, 4 deletions
diff --git a/CHANGES.rst b/CHANGES.rst
index 9ba439f9..4a177a19 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -21,10 +21,16 @@ want to know what's different in 5.0 since 4.5.x, see :ref:`whatsnew5x`.
.. Version 7.8.1 --- 2021-07-27
.. ----------------------------
+
Unreleased
----------
-Nothing yet.
+- Programs that used multiprocessing and changed directories would fail under
+ coverage. This is now fixed (`issue 890`_). A side effect is that debug
+ information about the config files read now shows absolute paths to the
+ files.
+
+.. _issue 890: https://github.com/nedbat/coveragepy/issues/890
.. _changes_501:
diff --git a/coverage/config.py b/coverage/config.py
index 452d320e..78a3e86a 100644
--- a/coverage/config.py
+++ b/coverage/config.py
@@ -6,6 +6,7 @@
import collections
import copy
import os
+import os.path
import re
from coverage import env
@@ -275,7 +276,7 @@ class CoverageConfig(object):
if not files_read:
return False
- self.config_files_read.extend(files_read)
+ self.config_files_read.extend(map(os.path.abspath, files_read))
any_set = False
try:
@@ -323,7 +324,7 @@ class CoverageConfig(object):
used = any_set
if used:
- self.config_file = filename
+ self.config_file = os.path.abspath(filename)
with open(filename) as f:
self._config_contents = f.read()
diff --git a/coverage/multiproc.py b/coverage/multiproc.py
index c466301f..2931b3be 100644
--- a/coverage/multiproc.py
+++ b/coverage/multiproc.py
@@ -6,6 +6,7 @@
import multiprocessing
import multiprocessing.process
import os
+import os.path
import sys
import traceback
@@ -85,7 +86,7 @@ def patch_multiprocessing(rcfile):
# Set the value in ProcessWithCoverage that will be pickled into the child
# process.
- os.environ["COVERAGE_RCFILE"] = rcfile
+ os.environ["COVERAGE_RCFILE"] = os.path.abspath(rcfile)
# When spawning processes rather than forking them, we have no state in the
# new process. We sneak in there with a Stowaway: we stuff one of our own
diff --git a/tests/test_concurrency.py b/tests/test_concurrency.py
index 3a127499..9bfd88ca 100644
--- a/tests/test_concurrency.py
+++ b/tests/test_concurrency.py
@@ -493,6 +493,25 @@ class MultiprocessingTest(CoverageTest):
self.assertIn("Exception during multiprocessing bootstrap init", out)
self.assertIn("Exception: Crashing because called by _bootstrap", out)
+ def test_bug890(self):
+ # chdir in multiprocessing shouldn't keep us from finding the
+ # .coveragerc file.
+ self.make_file("multi.py", """\
+ import multiprocessing, os, os.path
+ if __name__ == "__main__":
+ if not os.path.exists("./tmp"): os.mkdir("./tmp")
+ os.chdir("./tmp")
+ with multiprocessing.Manager():
+ pass
+ print("ok")
+ """)
+ self.make_file(".coveragerc", """\
+ [run]
+ concurrency = multiprocessing
+ """)
+ out = self.run_command("coverage run multi.py")
+ self.assertEqual(out.splitlines()[-1], "ok")
+
def test_coverage_stop_in_threads():
has_started_coverage = []