cov-core-1.15.0/0000755000076500000240000000000012434066752015070 5ustar marcschlaichstaff00000000000000cov-core-1.15.0/cov_core.egg-info/0000755000076500000240000000000012434066752020361 5ustar marcschlaichstaff00000000000000cov-core-1.15.0/cov_core.egg-info/dependency_links.txt0000644000076500000240000000000112434066751024426 0ustar marcschlaichstaff00000000000000 cov-core-1.15.0/cov_core.egg-info/not-zip-safe0000644000076500000240000000000112324173460022600 0ustar marcschlaichstaff00000000000000 cov-core-1.15.0/cov_core.egg-info/PKG-INFO0000644000076500000240000000212012434066751021450 0ustar marcschlaichstaff00000000000000Metadata-Version: 1.1 Name: cov-core Version: 1.15.0 Summary: plugin core for use by pytest-cov, nose-cov and nose2-cov Home-page: https://github.com/schlamar/cov-core Author: Marc Schlaich Author-email: marc.schlaich@gmail.com License: MIT License Description: cov-core ======== This is a lib package for use by pytest-cov, nose-cov and nose2-cov. Unless you're developing a coverage plugin for a test framework, you probably want one of those. Keywords: cover coverage Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2.4 Classifier: Programming Language :: Python :: 2.5 Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3.0 Classifier: Programming Language :: Python :: 3.1 Classifier: Topic :: Software Development :: Testing cov-core-1.15.0/cov_core.egg-info/requires.txt0000644000076500000240000000001612434066751022755 0ustar marcschlaichstaff00000000000000coverage>=3.6 cov-core-1.15.0/cov_core.egg-info/SOURCES.txt0000644000076500000240000000040612434066752022245 0ustar marcschlaichstaff00000000000000LICENSE.txt MANIFEST.in README.rst cov_core.py cov_core_init.py setup.py cov_core.egg-info/PKG-INFO cov_core.egg-info/SOURCES.txt cov_core.egg-info/dependency_links.txt cov_core.egg-info/not-zip-safe cov_core.egg-info/requires.txt cov_core.egg-info/top_level.txtcov-core-1.15.0/cov_core.egg-info/top_level.txt0000644000076500000240000000002712434066751023111 0ustar marcschlaichstaff00000000000000cov_core_init cov_core cov-core-1.15.0/cov_core.py0000644000076500000240000002414312434066375017246 0ustar marcschlaichstaff00000000000000"""Coverage controllers for use by pytest-cov and nose-cov.""" from cov_core_init import UNIQUE_SEP import cov_core_init import coverage import socket import sys import os def multiprocessing_start(obj): cov = cov_core_init.init() import multiprocessing.util multiprocessing.util.Finalize( None, multiprocessing_finish, args=(cov,), exitpriority=1000) def multiprocessing_finish(cov): cov.stop() cov.save() try: import multiprocessing.util multiprocessing.util.register_after_fork(multiprocessing_start, multiprocessing_start) except ImportError: pass class CovController(object): """Base class for different plugin implementations.""" def __init__(self, cov_source, cov_report, cov_config, config=None, nodeid=None): """Get some common config used by multiple derived classes.""" self.cov_source = cov_source self.cov_report = cov_report self.cov_config = cov_config self.config = config self.nodeid = nodeid self.cov = None self.node_descs = set() self.failed_slaves = [] self.topdir = os.getcwd() self.cov_data_file = '.coverage' def set_env(self): """Put info about coverage into the env so that subprocesses can activate coverage.""" if self.cov_source is None: os.environ['COV_CORE_SOURCE'] = '' else: os.environ['COV_CORE_SOURCE'] = UNIQUE_SEP.join(self.cov_source) os.environ['COV_CORE_DATA_FILE'] = self.cov_data_file os.environ['COV_CORE_CONFIG'] = self.cov_config @staticmethod def unset_env(): """Remove coverage info from env.""" os.environ.pop('COV_CORE_SOURCE', None) os.environ.pop('COV_CORE_DATA_FILE', None) os.environ.pop('COV_CORE_CONFIG', None) @staticmethod def get_node_desc(platform, version_info): """Return a description of this node.""" return 'platform %s, python %s' % (platform, '%s.%s.%s-%s-%s' % version_info[:5]) @staticmethod def sep(stream, s, txt): if hasattr(stream, 'sep'): stream.sep(s, txt) else: sep_total = max((70 - 2 - len(txt)), 2) sep_len = sep_total // 2 sep_extra = sep_total % 2 out = '%s %s %s\n' % (s * sep_len, txt, s * (sep_len + sep_extra)) stream.write(out) def summary(self, stream): """Produce coverage reports.""" # Output coverage section header. if len(self.node_descs) == 1: self.sep(stream, '-', 'coverage: %s' % ''.join(self.node_descs)) else: self.sep(stream, '-', 'coverage') for node_desc in sorted(self.node_descs): self.sep(stream, ' ', '%s' % node_desc) # Produce terminal report if wanted. if 'term' in self.cov_report or 'term-missing' in self.cov_report: show_missing = 'term-missing' in self.cov_report self.cov.report(show_missing=show_missing, ignore_errors=True, file=stream) # Produce annotated source code report if wanted. if 'annotate' in self.cov_report: self.cov.annotate(ignore_errors=True) stream.write('Coverage annotated source written next to source\n') # Produce html report if wanted. if 'html' in self.cov_report: self.cov.html_report(ignore_errors=True) stream.write('Coverage HTML written to dir %s\n' % self.cov.config.html_dir) # Produce xml report if wanted. if 'xml' in self.cov_report: self.cov.xml_report(ignore_errors=True) stream.write('Coverage XML written to file %s\n' % self.cov.config.xml_output) # Report on any failed slaves. if self.failed_slaves: self.sep(stream, '-', 'coverage: failed slaves') stream.write('The following slaves failed to return coverage data, ' 'ensure that pytest-cov is installed on these slaves.\n') for node in self.failed_slaves: stream.write('%s\n' % node.gateway.id) class Central(CovController): """Implementation for centralised operation.""" def start(self): """Erase any previous coverage data and start coverage.""" self.cov = coverage.coverage(source=self.cov_source, data_file=self.cov_data_file, config_file=self.cov_config) self.cov.erase() self.cov.start() self.set_env() def finish(self): """Stop coverage, save data to file and set the list of coverage objects to report on.""" self.unset_env() self.cov.stop() self.cov.combine() self.cov.save() node_desc = self.get_node_desc(sys.platform, sys.version_info) self.node_descs.add(node_desc) def summary(self, stream): """Produce coverage reports.""" CovController.summary(self, stream) class DistMaster(CovController): """Implementation for distributed master.""" def start(self): """Ensure coverage rc file rsynced if appropriate.""" if self.cov_config and os.path.exists(self.cov_config): self.config.option.rsyncdir.append(self.cov_config) self.cov = coverage.coverage(source=self.cov_source, data_file=self.cov_data_file, config_file=self.cov_config) self.cov.erase() self.cov.start() self.cov.config.paths['source'] = [self.topdir] def configure_node(self, node): """Slaves need to know if they are collocated and what files have moved.""" node.slaveinput['cov_master_host'] = socket.gethostname() node.slaveinput['cov_master_topdir'] = self.topdir node.slaveinput['cov_master_rsync_roots'] = [str(root) for root in node.nodemanager.roots] def testnodedown(self, node, error): """Collect data file name from slave. Also save data to file if slave not collocated.""" # If slave doesn't return any data then it is likely that this # plugin didn't get activated on the slave side. if not (hasattr(node, 'slaveoutput') and 'cov_slave_node_id' in node.slaveoutput): self.failed_slaves.append(node) return # If slave is not collocated then we must save the data file # that it returns to us. if 'cov_slave_lines' in node.slaveoutput: cov = coverage.coverage(source=self.cov_source, data_file=self.cov_data_file, data_suffix=node.slaveoutput['cov_slave_node_id'], config_file=self.cov_config) cov.start() cov.data.lines = node.slaveoutput['cov_slave_lines'] cov.data.arcs = node.slaveoutput['cov_slave_arcs'] cov.stop() cov.save() path = node.slaveoutput['cov_slave_path'] self.cov.config.paths['source'].append(path) # Record the slave types that contribute to the data file. rinfo = node.gateway._rinfo() node_desc = self.get_node_desc(rinfo.platform, rinfo.version_info) self.node_descs.add(node_desc) def finish(self): """Combines coverage data and sets the list of coverage objects to report on.""" # Combine all the suffix files into the data file. self.cov.stop() self.cov.combine() self.cov.save() def summary(self, stream): """Produce coverage reports.""" CovController.summary(self, stream) class DistSlave(CovController): """Implementation for distributed slaves.""" def start(self): """Determine what data file and suffix to contribute to and start coverage.""" # Determine whether we are collocated with master. self.is_collocated = bool(socket.gethostname() == self.config.slaveinput['cov_master_host'] and self.topdir == self.config.slaveinput['cov_master_topdir']) # If we are not collocated then rewrite master paths to slave paths. if not self.is_collocated: master_topdir = self.config.slaveinput['cov_master_topdir'] slave_topdir = self.topdir self.cov_source = [source.replace(master_topdir, slave_topdir) for source in self.cov_source] self.cov_data_file = self.cov_data_file.replace(master_topdir, slave_topdir) self.cov_config = self.cov_config.replace(master_topdir, slave_topdir) # Our slave node id makes us unique from all other slaves so # adjust the data file that we contribute to and the master # will combine our data with other slaves later. self.cov_data_file += '.%s' % self.nodeid # Erase any previous data and start coverage. self.cov = coverage.coverage(source=self.cov_source, data_file=self.cov_data_file, config_file=self.cov_config) self.cov.erase() self.cov.start() self.set_env() def finish(self): """Stop coverage and send relevant info back to the master.""" self.unset_env() self.cov.stop() self.cov.combine() self.cov.save() if self.is_collocated: # If we are collocated then just inform the master of our # data file to indicate that we have finished. self.config.slaveoutput['cov_slave_node_id'] = self.nodeid else: # If we are not collocated then add the current path # and coverage data to the output so we can combine # it on the master node. # Send all the data to the master over the channel. self.config.slaveoutput['cov_slave_path'] = self.topdir self.config.slaveoutput['cov_slave_node_id'] = self.nodeid self.config.slaveoutput['cov_slave_lines'] = self.cov.data.lines self.config.slaveoutput['cov_slave_arcs'] = self.cov.data.arcs def summary(self, stream): """Only the master reports so do nothing.""" pass cov-core-1.15.0/cov_core_init.py0000644000076500000240000000437312434066375020274 0ustar marcschlaichstaff00000000000000"""Activate coverage at python startup if appropriate. The python site initialisation will ensure that anything we import will be removed and not visible at the end of python startup. However we minimise all work by putting these init actions in this separate module and only importing what is needed when needed. For normal python startup when coverage should not be activated the pth file checks a single env var and does not import or call the init fn here. For python startup when an ancestor process has set the env indicating that code coverage is being collected we activate coverage based on info passed via env vars. """ UNIQUE_SEP = '084031f3d2994d40a88c8b699b69e148' import cov_core # noqa: register multiprocessing handler def init(): # Any errors encountered should only prevent coverage from # starting, it should not cause python to complain that importing # of site failed. try: # Only continue if ancestor process has set everything needed in # the env. import os cov_source = os.environ.get('COV_CORE_SOURCE') cov_data_file = os.environ.get('COV_CORE_DATA_FILE') cov_config = os.environ.get('COV_CORE_CONFIG') if cov_data_file and cov_config: # Import what we need to activate coverage. import socket import random import coverage # Determine all source roots. if cov_source == '': cov_source = None else: cov_source = cov_source.split(UNIQUE_SEP) # Produce a unique suffix for this process in the same # manner as coverage. data_suffix = '%s.%s.%s' % (socket.gethostname(), os.getpid(), random.randint(0, 999999)) # Activate coverage for this process. cov = coverage.coverage(source=cov_source, data_file=cov_data_file, data_suffix=data_suffix, config_file=cov_config, auto_data=True) cov.erase() cov.start() return cov except Exception: pass cov-core-1.15.0/LICENSE.txt0000644000076500000240000000205712324031644016705 0ustar marcschlaichstaff00000000000000The MIT License Copyright (c) 2010 Meme Dough Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. cov-core-1.15.0/MANIFEST.in0000644000076500000240000000014512326154634016623 0ustar marcschlaichstaff00000000000000include README.rst include LICENSE.txt include setup.py include cov_core.py include cov_core_init.py cov-core-1.15.0/PKG-INFO0000644000076500000240000000212012434066752016160 0ustar marcschlaichstaff00000000000000Metadata-Version: 1.1 Name: cov-core Version: 1.15.0 Summary: plugin core for use by pytest-cov, nose-cov and nose2-cov Home-page: https://github.com/schlamar/cov-core Author: Marc Schlaich Author-email: marc.schlaich@gmail.com License: MIT License Description: cov-core ======== This is a lib package for use by pytest-cov, nose-cov and nose2-cov. Unless you're developing a coverage plugin for a test framework, you probably want one of those. Keywords: cover coverage Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2.4 Classifier: Programming Language :: Python :: 2.5 Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3.0 Classifier: Programming Language :: Python :: 3.1 Classifier: Topic :: Software Development :: Testing cov-core-1.15.0/README.rst0000644000076500000240000000027212326152305016546 0ustar marcschlaichstaff00000000000000cov-core ======== This is a lib package for use by pytest-cov, nose-cov and nose2-cov. Unless you're developing a coverage plugin for a test framework, you probably want one of those. cov-core-1.15.0/setup.cfg0000644000076500000240000000007312434066752016711 0ustar marcschlaichstaff00000000000000[egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 cov-core-1.15.0/setup.py0000644000076500000240000000600112434066665016602 0ustar marcschlaichstaff00000000000000import setuptools import sys import os # The name of the path file must appear after easy-install.pth so that # cov_core has been added to the sys.path and cov_core_init can be # imported. PTH_FILE_NAME = 'init_cov_core.pth' # The line in the path file must begin with "import" # so that site.py will exec it. PTH_FILE = '''\ import os; 'COV_CORE_SOURCE' in os.environ and __import__('cov_core_init').init() ''' PTH_FILE_FAILURE = ''' Subprocesses WILL NOT have coverage collected. To measure subprocesses put the following in a pth file called %s: %s ''' % (PTH_FILE_NAME, PTH_FILE) setuptools.setup(name='cov-core', version='1.15.0', description='plugin core for use by pytest-cov, ' 'nose-cov and nose2-cov', long_description=open('README.rst').read().strip(), author='Marc Schlaich', author_email='marc.schlaich@gmail.com', url='https://github.com/schlamar/cov-core', py_modules=['cov_core', 'cov_core_init'], install_requires=['coverage>=3.6'], license='MIT License', zip_safe=False, keywords='cover coverage', classifiers=['Development Status :: 4 - Beta', 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', 'Operating System :: OS Independent', 'Programming Language :: Python', 'Programming Language :: Python :: 2.4', 'Programming Language :: Python :: 2.5', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3.0', 'Programming Language :: Python :: 3.1', 'Topic :: Software Development :: Testing']) if sys.argv[1] in ('install', 'develop'): for path in sys.path: if (path.endswith('site-packages')) or (path.endswith('dist-packages') and 'local' in path): path = os.path.join(path, PTH_FILE_NAME) try: pth_file = open(path, 'w') pth_file.write(PTH_FILE) pth_file.close() sys.stdout.write('\nWrote pth file for subprocess ' 'measurement to %s\n' % path) break except Exception: sys.stdout.write('\nFailed to write pth file for subprocess ' 'measurement to %s\n' % path) sys.stdout.write(PTH_FILE_FAILURE) break else: sys.stdout.write('\nFailed to find site-packages or dist-packages ' 'dir to put pth file in.\n') sys.stdout.write(PTH_FILE_FAILURE)