@@ -0,0 +1,2873 @@
+import tempfile%0Aimport os%0Aimport coverage%0A%0Aclass Coverage(object):%0A    %22%22%22%0A    Context manager to handle code coverage using coverage.py module%0A    %0A    This handle multiples MPI processes by writing data%0A    to separate coverage files during code execution and using the %0A    root process to combine them at the end%0A    %22%22%22%0A    %0A    def __init__(self, comm, source, with_coverage=False, html_cov=False, %0A                    config_file=None, root=''):%0A        %22%22%22%0A        Parameters%0A        ----------%0A        comm : MPI communicator%0A            the MPI communicator%0A        source : str%0A            the name of the package module which we are reporting coverage for%0A        with_coverage : bool, optional%0A            whether to record the coverage%0A        html_cov : bool, optional%0A            whether to save a html coverage report; in 'build/coverage'%0A        config_file : str, optional%0A            a coveragerc file to load%0A        root : str, optional%0A            this specifies the root of the package %0A        %22%22%22%0A        self.comm = comm%0A        self.source = source%0A        self.root = root%0A        %0A        # options%0A        self.with_coverage = with_coverage %0A        self.config_file = os.path.join(root, config_file)%0A        self.html_cov = html_cov%0A        %0A        # check if coverage file exists%0A        if not os.path.exists(self.config_file):%0A            self.config_file = None%0A        %0A    def __enter__(self):%0A        %0A        if not self.with_coverage:%0A            self.cov = None%0A            return%0A        else:%0A            self.cov = coverage.coverage(source=%5Bself.source%5D, config_file=self.config_file)%0A            self.cov.start()%0A        %0A    def __exit__(self, type, value, tb):%0A        if not self.with_coverage:%0A            return%0A        %0A        self.cov.stop()%0A        with tempfile.TemporaryDirectory() as tmpdir:%0A            %0A            # write coverage data file%0A            self.cov.get_data().write_file(os.path.join(tmpdir, '.coverage.%25d' %25 os.getpid()))%0A            %0A            # now combine from each rank and save%0A            if self.comm.rank == 0:%0A                %0A                # write out combined data%0A                combined_cov = coverage.coverage(config_file=self.config_file, data_file='.coverage')%0A                combined_cov.combine(data_paths=%5Btmpdir%5D)%0A                combined_cov.get_data().write_file(os.path.join(self.root, self.cov.config.data_file))%0A                %0A                # and report%0A                combined_cov.report()%0A                %0A                # write html%0A                if self.html_cov:%0A                    html_dir = os.path.join(self.root, 'build', 'coverage')%0A                    if not os.path.exists(html_dir):%0A                        os.makedirs(html_dir)%0A                    combined_cov.html_report(directory=html_dir)%0A            %0A            self.comm.barrier()%0A%0A    

add a class to handle running coverage in parallel