From 7c6448ddf699c20323068ee7c2a17aa60fd3a3ae Mon Sep 17 00:00:00 2001 From: Meme Dough Date: Sat, 17 Jul 2010 14:51:27 +1000 Subject: [PATCH 001/134] Moved the coverage controllers out of pytest-cov to new package. --- LICENSE.txt | 21 ++++ MANIFEST.in | 5 + README.txt | 6 ++ cov_core.py | 275 +++++++++++++++++++++++++++++++++++++++++++++++ cov_core_init.py | 56 ++++++++++ setup.py | 58 ++++++++++ 6 files changed, 421 insertions(+) create mode 100644 LICENSE.txt create mode 100644 MANIFEST.in create mode 100644 README.txt create mode 100644 cov_core.py create mode 100644 cov_core_init.py create mode 100644 setup.py diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 00000000..5b3634b4 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,21 @@ +The 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. diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 00000000..fe99a41d --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,5 @@ +include README.txt +include LICENSE.txt +include setup.py +include cov_core.py +include cov_core_init.py diff --git a/README.txt b/README.txt new file mode 100644 index 00000000..34dd31ca --- /dev/null +++ b/README.txt @@ -0,0 +1,6 @@ +cov-core +======== + +This is a lib package for use by pytest-cov and nose-cov. Unless your +developing a coverage plugin for a test framework then you probably +want one of those. diff --git a/cov_core.py b/cov_core.py new file mode 100644 index 00000000..6f7984d2 --- /dev/null +++ b/cov_core.py @@ -0,0 +1,275 @@ +"""Coverage controllers for use by pytest-cov and nose-cov.""" + +import coverage +import socket +import sys +import os + +try: + import configparser +except ImportError: + import ConfigParser as configparser + +from cov_core_init import UNIQUE_SEP + +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 = [] + + # For data file name consider coverage rc file, coverage env + # vars in priority order. + parser = configparser.RawConfigParser() + parser.read(self.cov_config) + for default, section, item, env_var, option in [ + ('.coverage', 'run', 'data_file', 'COVERAGE_FILE', 'cov_data_file')]: + + # Lowest priority is coverage hard coded default. + result = default + + # Override with coverage rc file. + if parser.has_option(section, item): + result = parser.get(section, item) + + # Override with coverage env var. + if env_var: + result = os.environ.get(env_var, result) + + # Set config option on ourselves. + setattr(self, option, result) + + def set_env(self): + """Put info about coverage into the env so that subprocesses can activate coverage.""" + + 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.""" + + del os.environ['COV_CORE_SOURCE'] + del os.environ['COV_CORE_DATA_FILE'] + del os.environ['COV_CORE_CONFIG'] + + @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.""" + + # Produce terminal report if wanted. + if 'term' in self.cov_report or 'term-missing' in self.cov_report: + 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) + 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) + + # Produce html report if wanted. + if 'html' in self.cov_report: + self.cov.html_report(ignore_errors=True) + + # Produce xml report if wanted. + if 'xml' in self.cov_report: + self.cov.xml_report(ignore_errors=True) + + # 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) + + 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.config.topdir + node.slaveinput['cov_master_rsync_roots'] = 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() + + # 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 = coverage.coverage(source=self.cov_source, + data_file=self.cov_data_file, + config_file=self.cov_config) + self.cov.erase() + 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.config.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 = str(self.config.slaveinput['cov_master_topdir']) + slave_topdir = str(self.config.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 rewrite the filenames from + # the slave location to the master location. + slave_topdir = self.config.topdir + path_rewrites = [(str(slave_topdir.join(rsync_root.basename)), str(rsync_root)) + for rsync_root in self.config.slaveinput['cov_master_rsync_roots']] + path_rewrites.append((str(self.config.topdir), str(self.config.slaveinput['cov_master_topdir']))) + + def rewrite_path(filename): + for slave_path, master_path in path_rewrites: + filename = filename.replace(slave_path, master_path) + return filename + + lines = dict((rewrite_path(filename), data) for filename, data in self.cov.data.lines.items()) + arcs = dict((rewrite_path(filename), data) for filename, data in self.cov.data.arcs.items()) + + # Send all the data to the master over the channel. + self.config.slaveoutput['cov_slave_node_id'] = self.nodeid + self.config.slaveoutput['cov_slave_lines'] = lines + self.config.slaveoutput['cov_slave_arcs'] = arcs + + def summary(self, stream): + """Only the master reports so do nothing.""" + + pass diff --git a/cov_core_init.py b/cov_core_init.py new file mode 100644 index 00000000..fd781c9c --- /dev/null +++ b/cov_core_init.py @@ -0,0 +1,56 @@ +"""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 we +only import os, look for one env var and get out. + +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' + +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 env. + import os + if os.environ.get('COV_CORE_SOURCE'): + + # Only continue if we have all needed info from env. + cov_source = os.environ.get('COV_CORE_SOURCE').split(UNIQUE_SEP) + cov_data_file = os.environ.get('COV_CORE_DATA_FILE') + cov_config = os.environ.get('COV_CORE_CONFIG') + if cov_source and cov_data_file and cov_config: + + # Import what we need to activate coverage. + import socket + import random + import coverage + + # 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() + + except Exception: + pass diff --git a/setup.py b/setup.py new file mode 100644 index 00000000..572cbd16 --- /dev/null +++ b/setup.py @@ -0,0 +1,58 @@ +import 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' + +PTH_FILE = '''\ +import cov_core_init; cov_core_init.init() +''' + +UNKNOWN_SITE_PACKAGES_DIR ='''\ +Failed to find site-packages or dist-packages dir to put pth file in. +Sub processes will not have coverage collected. + +To measure sub processes put the following in a file called %s: +%s +''' % (PTH_FILE_NAME, PTH_FILE) + +setuptools.setup(name='cov-core', + version='1.0a2', + description='plugin core for use by pytest-cov and nose-cov', + long_description=open('README.txt').read().strip(), + author='Meme Dough', + author_email='memedough@gmail.com', + url='http://bitbucket.org/memedough/cov-core/overview', + py_modules=['cov_core', + 'cov_core_init'], + install_requires=['coverage>=3.4a1'], + 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 'site-packages' in path or 'dist-packages' in path: + path = os.path.dirname(path) + pth_file = open(os.path.join(path, PTH_FILE_NAME), 'w') + pth_file.write(PTH_FILE) + pth_file.close() + break + else: + sys.stdout.write(UNKNOWN_SITE_PACKAGES_DIR) + sys.stdout.write(PTH_FILE) From 383912563852cc7e8ac49ee7f5cf5ff4f438b687 Mon Sep 17 00:00:00 2001 From: Meme Dough Date: Mon, 2 Aug 2010 22:19:47 +1000 Subject: [PATCH 002/134] Changed to work with current released coverage. --- README.txt | 5 ++--- cov_core.py | 28 ++++++++++++++++++++-------- setup.py | 16 ++++++++-------- 3 files changed, 30 insertions(+), 19 deletions(-) diff --git a/README.txt b/README.txt index 34dd31ca..310fa584 100644 --- a/README.txt +++ b/README.txt @@ -1,6 +1,5 @@ cov-core ======== -This is a lib package for use by pytest-cov and nose-cov. Unless your -developing a coverage plugin for a test framework then you probably -want one of those. +This is a lib package for use by pytest-cov, nose-cov and unittest2-cov. Unless your developing a +coverage plugin for a test framework then you probably want one of those. diff --git a/cov_core.py b/cov_core.py index 6f7984d2..7c263809 100644 --- a/cov_core.py +++ b/cov_core.py @@ -84,6 +84,14 @@ def sep(stream, s, txt): def summary(self, stream): """Produce coverage reports.""" + # Determine the modules or files to limit reports on. + morfs = list(set(module.__file__ + for name, module in sys.modules.items() + for package in self.cov_source + if hasattr(module, '__file__') and + os.path.splitext(module.__file__)[1] in ('.py', '.pyc', '.pyo') and + name.startswith(package))) + # Produce terminal report if wanted. if 'term' in self.cov_report or 'term-missing' in self.cov_report: if len(self.node_descs) == 1: @@ -93,19 +101,23 @@ def summary(self, stream): for node_desc in sorted(self.node_descs): self.sep(stream, ' ', '%s' % node_desc) show_missing = 'term-missing' in self.cov_report - self.cov.report(show_missing=show_missing, ignore_errors=True, file=stream) + #self.cov.report(show_missing=show_missing, ignore_errors=True, file=stream) + self.cov.report(morfs, 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) + #self.cov.annotate(ignore_errors=True) + self.cov.annotate(morfs, ignore_errors=True) # Produce html report if wanted. if 'html' in self.cov_report: - self.cov.html_report(ignore_errors=True) + #self.cov.html_report(ignore_errors=True) + self.cov.html_report(morfs, ignore_errors=True) # Produce xml report if wanted. if 'xml' in self.cov_report: - self.cov.xml_report(ignore_errors=True) + #self.cov.xml_report(ignore_errors=True) + self.cov.xml_report(morfs, ignore_errors=True) # Report on any failed slaves. if self.failed_slaves: @@ -122,7 +134,7 @@ class Central(CovController): def start(self): """Erase any previous coverage data and start coverage.""" - self.cov = coverage.coverage(source=self.cov_source, + self.cov = coverage.coverage(#source=self.cov_source, data_file=self.cov_data_file, config_file=self.cov_config) self.cov.erase() @@ -173,7 +185,7 @@ def testnodedown(self, node, error): # 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, + 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) @@ -192,7 +204,7 @@ 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 = coverage.coverage(source=self.cov_source, + self.cov = coverage.coverage(#source=self.cov_source, data_file=self.cov_data_file, config_file=self.cov_config) self.cov.erase() @@ -229,7 +241,7 @@ def start(self): self.cov_data_file += '.%s' % self.nodeid # Erase any previous data and start coverage. - self.cov = coverage.coverage(source=self.cov_source, + self.cov = coverage.coverage(#source=self.cov_source, data_file=self.cov_data_file, config_file=self.cov_config) self.cov.erase() diff --git a/setup.py b/setup.py index 572cbd16..0b49ba8a 100644 --- a/setup.py +++ b/setup.py @@ -11,7 +11,7 @@ import cov_core_init; cov_core_init.init() ''' -UNKNOWN_SITE_PACKAGES_DIR ='''\ +UNKNOWN_SITE_PACKAGES_DIR =''' Failed to find site-packages or dist-packages dir to put pth file in. Sub processes will not have coverage collected. @@ -20,15 +20,15 @@ ''' % (PTH_FILE_NAME, PTH_FILE) setuptools.setup(name='cov-core', - version='1.0a2', - description='plugin core for use by pytest-cov and nose-cov', + version='1.0', + description='plugin core for use by pytest-cov, nose-cov and unittest2-cov', long_description=open('README.txt').read().strip(), author='Meme Dough', author_email='memedough@gmail.com', url='http://bitbucket.org/memedough/cov-core/overview', py_modules=['cov_core', 'cov_core_init'], - install_requires=['coverage>=3.4a1'], + install_requires=['coverage>=3.3.1'], license='MIT License', zip_safe=False, keywords='cover coverage', @@ -47,12 +47,12 @@ if sys.argv[1] in ('install', 'develop'): for path in sys.path: - if 'site-packages' in path or 'dist-packages' in path: - path = os.path.dirname(path) - pth_file = open(os.path.join(path, PTH_FILE_NAME), 'w') + if ('site-packages' in path) or ('dist-packages' in path and 'local' in path): + path = os.path.join(path, PTH_FILE_NAME) + 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 else: sys.stdout.write(UNKNOWN_SITE_PACKAGES_DIR) - sys.stdout.write(PTH_FILE) From 1f9aba2e2565accd6d92a2b292a71bb2462b6935 Mon Sep 17 00:00:00 2001 From: Meme Dough Date: Mon, 2 Aug 2010 23:20:11 +1000 Subject: [PATCH 003/134] Subprocesses can't use source option yet. Better way to find site-packages. --- cov_core_init.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cov_core_init.py b/cov_core_init.py index fd781c9c..062d6677 100644 --- a/cov_core_init.py +++ b/cov_core_init.py @@ -44,7 +44,7 @@ def init(): random.randint(0, 999999)) # Activate coverage for this process. - cov = coverage.coverage(source=cov_source, + cov = coverage.coverage(#source=cov_source, data_file=cov_data_file, data_suffix=data_suffix, config_file=cov_config, diff --git a/setup.py b/setup.py index 0b49ba8a..53087ab7 100644 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ if sys.argv[1] in ('install', 'develop'): for path in sys.path: - if ('site-packages' in path) or ('dist-packages' in path and 'local' in path): + if (path.endswith('site-packages')) or (path.endswith('dist-packages') and 'local' in path): path = os.path.join(path, PTH_FILE_NAME) pth_file = open(path, 'w') pth_file.write(PTH_FILE) From ca7b46d9a23e504020333cee885e32daf187fb53 Mon Sep 17 00:00:00 2001 From: Meme Dough Date: Mon, 2 Aug 2010 23:21:02 +1000 Subject: [PATCH 004/134] Added tag RELEASE_1_0 for changeset bc62935c7d6e From 09e2bf6762b7e0f09dc7b837a91c6e5f536ee09c Mon Sep 17 00:00:00 2001 From: Meme Dough Date: Sun, 8 Aug 2010 17:46:21 +1000 Subject: [PATCH 005/134] Changes to cov option, reporting and imports. Change cov option to work on filesystem paths and make the help text more clear. Change reporting to indicating files and dirs written to. Also output warning if nothing to report on. Minimise imports by only importing if actually needed. --- cov_core.py | 76 +++++++++++++++++++++++++++++++---------------------- setup.py | 2 +- 2 files changed, 45 insertions(+), 33 deletions(-) diff --git a/cov_core.py b/cov_core.py index 7c263809..e7e315c7 100644 --- a/cov_core.py +++ b/cov_core.py @@ -84,40 +84,52 @@ def sep(stream, s, txt): def summary(self, stream): """Produce coverage reports.""" - # Determine the modules or files to limit reports on. - morfs = list(set(module.__file__ - for name, module in sys.modules.items() - for package in self.cov_source - if hasattr(module, '__file__') and - os.path.splitext(module.__file__)[1] in ('.py', '.pyc', '.pyo') and - name.startswith(package))) - - # Produce terminal report if wanted. - if 'term' in self.cov_report or 'term-missing' in self.cov_report: - 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) - show_missing = 'term-missing' in self.cov_report - #self.cov.report(show_missing=show_missing, ignore_errors=True, file=stream) - self.cov.report(morfs, 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) - self.cov.annotate(morfs, ignore_errors=True) - - # Produce html report if wanted. - if 'html' in self.cov_report: - #self.cov.html_report(ignore_errors=True) - self.cov.html_report(morfs, ignore_errors=True) - - # Produce xml report if wanted. + # 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) + + # Determine the files to limit reports on. + morfs = list(set(filename + for filename in self.cov.data.executed_files() + for source in self.cov_source + if os.path.realpath(filename).startswith(os.path.realpath(source)))) + + if morfs: + # 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) + self.cov.report(morfs, 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) + self.cov.annotate(morfs, 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) + self.cov.html_report(morfs, ignore_errors=True) + stream.write('Coverage HTML written to dir %s\n' % self.cov.config.html_dir) + + else: + # Output warning that there is nothing to report on. + stream.write('Nothing to report on with specified cov options: %s\n' % ', '.join(self.cov_source)) + + # Produce xml report if wanted. Produce empty reports in case CI server is expecting one. if 'xml' in self.cov_report: + xml_morfs = morfs or ['BOGUS_TO_PRODUCE_EMPTY_REPORT'] #self.cov.xml_report(ignore_errors=True) - self.cov.xml_report(morfs, ignore_errors=True) + self.cov.xml_report(xml_morfs, ignore_errors=True) + if morfs: + stream.write('Coverage XML written to file %s\n' % self.cov.config.xml_output) + else: + stream.write('Coverage XML written to file %s: empty coverage report\n' % self.cov.config.xml_output) # Report on any failed slaves. if self.failed_slaves: diff --git a/setup.py b/setup.py index 53087ab7..72c7d407 100644 --- a/setup.py +++ b/setup.py @@ -20,7 +20,7 @@ ''' % (PTH_FILE_NAME, PTH_FILE) setuptools.setup(name='cov-core', - version='1.0', + version='1.1', description='plugin core for use by pytest-cov, nose-cov and unittest2-cov', long_description=open('README.txt').read().strip(), author='Meme Dough', From a57321c088acc309aea7acbcf7c068bb2d3ff2b4 Mon Sep 17 00:00:00 2001 From: Meme Dough Date: Sun, 8 Aug 2010 17:46:40 +1000 Subject: [PATCH 006/134] Added tag RELEASE_1_1 for changeset f0cd8f24d77e From 97a2646d5590d3f51b1145f98a23d35f35a42344 Mon Sep 17 00:00:00 2001 From: Meme Dough Date: Thu, 23 Sep 2010 22:20:54 +1000 Subject: [PATCH 007/134] Change to use source option in coverage 3.4 --- cov_core.py | 63 +++++++++++++++++------------------------------- cov_core_init.py | 2 +- setup.py | 4 +-- 3 files changed, 25 insertions(+), 44 deletions(-) diff --git a/cov_core.py b/cov_core.py index e7e315c7..ea017567 100644 --- a/cov_core.py +++ b/cov_core.py @@ -92,44 +92,25 @@ def summary(self, stream): for node_desc in sorted(self.node_descs): self.sep(stream, ' ', '%s' % node_desc) - # Determine the files to limit reports on. - morfs = list(set(filename - for filename in self.cov.data.executed_files() - for source in self.cov_source - if os.path.realpath(filename).startswith(os.path.realpath(source)))) - - if morfs: - # 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) - self.cov.report(morfs, 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) - self.cov.annotate(morfs, 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) - self.cov.html_report(morfs, ignore_errors=True) - stream.write('Coverage HTML written to dir %s\n' % self.cov.config.html_dir) - - else: - # Output warning that there is nothing to report on. - stream.write('Nothing to report on with specified cov options: %s\n' % ', '.join(self.cov_source)) - - # Produce xml report if wanted. Produce empty reports in case CI server is expecting one. + # 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: - xml_morfs = morfs or ['BOGUS_TO_PRODUCE_EMPTY_REPORT'] - #self.cov.xml_report(ignore_errors=True) - self.cov.xml_report(xml_morfs, ignore_errors=True) - if morfs: - stream.write('Coverage XML written to file %s\n' % self.cov.config.xml_output) - else: - stream.write('Coverage XML written to file %s: empty coverage report\n' % self.cov.config.xml_output) + 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: @@ -146,7 +127,7 @@ class Central(CovController): def start(self): """Erase any previous coverage data and start coverage.""" - self.cov = coverage.coverage(#source=self.cov_source, + self.cov = coverage.coverage(source=self.cov_source, data_file=self.cov_data_file, config_file=self.cov_config) self.cov.erase() @@ -197,7 +178,7 @@ def testnodedown(self, node, error): # 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, + 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) @@ -216,7 +197,7 @@ 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 = coverage.coverage(#source=self.cov_source, + self.cov = coverage.coverage(source=self.cov_source, data_file=self.cov_data_file, config_file=self.cov_config) self.cov.erase() @@ -253,7 +234,7 @@ def start(self): self.cov_data_file += '.%s' % self.nodeid # Erase any previous data and start coverage. - self.cov = coverage.coverage(#source=self.cov_source, + self.cov = coverage.coverage(source=self.cov_source, data_file=self.cov_data_file, config_file=self.cov_config) self.cov.erase() diff --git a/cov_core_init.py b/cov_core_init.py index 062d6677..fd781c9c 100644 --- a/cov_core_init.py +++ b/cov_core_init.py @@ -44,7 +44,7 @@ def init(): random.randint(0, 999999)) # Activate coverage for this process. - cov = coverage.coverage(#source=cov_source, + cov = coverage.coverage(source=cov_source, data_file=cov_data_file, data_suffix=data_suffix, config_file=cov_config, diff --git a/setup.py b/setup.py index 72c7d407..ea86a2e2 100644 --- a/setup.py +++ b/setup.py @@ -20,7 +20,7 @@ ''' % (PTH_FILE_NAME, PTH_FILE) setuptools.setup(name='cov-core', - version='1.1', + version='1.2', description='plugin core for use by pytest-cov, nose-cov and unittest2-cov', long_description=open('README.txt').read().strip(), author='Meme Dough', @@ -28,7 +28,7 @@ url='http://bitbucket.org/memedough/cov-core/overview', py_modules=['cov_core', 'cov_core_init'], - install_requires=['coverage>=3.3.1'], + install_requires=['coverage>=3.4'], license='MIT License', zip_safe=False, keywords='cover coverage', From 415f8246dfa082103a1debee08d307a7d7ee20b9 Mon Sep 17 00:00:00 2001 From: Meme Dough Date: Thu, 23 Sep 2010 22:21:16 +1000 Subject: [PATCH 008/134] Added tag RELEASE_1_2 for changeset a2ddd5473f1b From 42b75c40f4c886ccba912cefbfb884f2f6d4f857 Mon Sep 17 00:00:00 2001 From: Meme Dough Date: Sun, 27 Mar 2011 13:23:21 +1100 Subject: [PATCH 009/134] Update to detect session type and top dir for latest pytest. Also remove reading coverage config file. --- cov_core.py | 44 ++++++++++---------------------------------- 1 file changed, 10 insertions(+), 34 deletions(-) diff --git a/cov_core.py b/cov_core.py index ea017567..97a13c8e 100644 --- a/cov_core.py +++ b/cov_core.py @@ -5,11 +5,6 @@ import sys import os -try: - import configparser -except ImportError: - import ConfigParser as configparser - from cov_core_init import UNIQUE_SEP class CovController(object): @@ -27,27 +22,8 @@ def __init__(self, cov_source, cov_report, cov_config, config=None, nodeid=None) self.cov = None self.node_descs = set() self.failed_slaves = [] - - # For data file name consider coverage rc file, coverage env - # vars in priority order. - parser = configparser.RawConfigParser() - parser.read(self.cov_config) - for default, section, item, env_var, option in [ - ('.coverage', 'run', 'data_file', 'COVERAGE_FILE', 'cov_data_file')]: - - # Lowest priority is coverage hard coded default. - result = default - - # Override with coverage rc file. - if parser.has_option(section, item): - result = parser.get(section, item) - - # Override with coverage env var. - if env_var: - result = os.environ.get(env_var, result) - - # Set config option on ourselves. - setattr(self, option, result) + 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.""" @@ -163,8 +139,8 @@ 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.config.topdir - node.slaveinput['cov_master_rsync_roots'] = node.nodemanager.roots + 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.""" @@ -218,12 +194,12 @@ def start(self): # Determine whether we are collocated with master. self.is_collocated = bool(socket.gethostname() == self.config.slaveinput['cov_master_host'] and - self.config.topdir == self.config.slaveinput['cov_master_topdir']) + 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 = str(self.config.slaveinput['cov_master_topdir']) - slave_topdir = str(self.config.topdir) + 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) @@ -256,10 +232,10 @@ def finish(self): else: # If we are not collocated then rewrite the filenames from # the slave location to the master location. - slave_topdir = self.config.topdir - path_rewrites = [(str(slave_topdir.join(rsync_root.basename)), str(rsync_root)) + slave_topdir = self.topdir + path_rewrites = [(os.path.join(slave_topdir, os.path.basename(rsync_root)), rsync_root) for rsync_root in self.config.slaveinput['cov_master_rsync_roots']] - path_rewrites.append((str(self.config.topdir), str(self.config.slaveinput['cov_master_topdir']))) + path_rewrites.append((slave_topdir, self.config.slaveinput['cov_master_topdir'])) def rewrite_path(filename): for slave_path, master_path in path_rewrites: From 6a52472547d3f0e2f30e5e04263b0dae2fa95dd5 Mon Sep 17 00:00:00 2001 From: Meme Dough Date: Sun, 27 Mar 2011 15:46:33 +1100 Subject: [PATCH 010/134] Path file only imports cov_core_init if needs to activate coverage. --- .hgignore | 9 +++++++ cov_core_init.py | 63 +++++++++++++++++++++++++----------------------- setup.py | 5 ++-- 3 files changed, 45 insertions(+), 32 deletions(-) create mode 100644 .hgignore diff --git a/.hgignore b/.hgignore new file mode 100644 index 00000000..403e1dbd --- /dev/null +++ b/.hgignore @@ -0,0 +1,9 @@ +syntax: glob + +*~ +*.pyo +*.pyc +*egg-info +build +dist +env* diff --git a/cov_core_init.py b/cov_core_init.py index fd781c9c..53494fc6 100644 --- a/cov_core_init.py +++ b/cov_core_init.py @@ -5,8 +5,9 @@ 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 we -only import os, look for one env var and get out. +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 @@ -15,6 +16,7 @@ UNIQUE_SEP = '084031f3d2994d40a88c8b699b69e148' + def init(): # Any errors encountered should only prevent coverage from @@ -22,35 +24,36 @@ def init(): # of site failed. try: - # Only continue if ancestor process has set env. + # Only continue if ancestor process has set everything needed in + # the env. import os - if os.environ.get('COV_CORE_SOURCE'): - - # Only continue if we have all needed info from env. - cov_source = os.environ.get('COV_CORE_SOURCE').split(UNIQUE_SEP) - cov_data_file = os.environ.get('COV_CORE_DATA_FILE') - cov_config = os.environ.get('COV_CORE_CONFIG') - if cov_source and cov_data_file and cov_config: - - # Import what we need to activate coverage. - import socket - import random - import coverage - - # 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() + 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_source and cov_data_file and cov_config: + + # Import what we need to activate coverage. + import socket + import random + import coverage + + # Determine all source roots. + 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() except Exception: pass diff --git a/setup.py b/setup.py index ea86a2e2..6ec1eaeb 100644 --- a/setup.py +++ b/setup.py @@ -7,11 +7,12 @@ # 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 cov_core_init; cov_core_init.init() +import os; os.environ.get('COV_CORE_SOURCE') and __import__('cov_core_init').init() ''' -UNKNOWN_SITE_PACKAGES_DIR =''' +UNKNOWN_SITE_PACKAGES_DIR = ''' Failed to find site-packages or dist-packages dir to put pth file in. Sub processes will not have coverage collected. From 182f9a9ef13981fd805c20cb1b5404013f85ef36 Mon Sep 17 00:00:00 2001 From: Meme Dough Date: Sun, 27 Mar 2011 21:28:06 +1100 Subject: [PATCH 011/134] Bump version for release. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 6ec1eaeb..225086e1 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ ''' % (PTH_FILE_NAME, PTH_FILE) setuptools.setup(name='cov-core', - version='1.2', + version='1.3', description='plugin core for use by pytest-cov, nose-cov and unittest2-cov', long_description=open('README.txt').read().strip(), author='Meme Dough', From 6d28bac17cd973028ab600a742f04a878bcea4d7 Mon Sep 17 00:00:00 2001 From: Meme Dough Date: Sun, 27 Mar 2011 21:44:57 +1100 Subject: [PATCH 012/134] Added tag RELEASE_1_3 for changeset 56fc572faa29 From 1e7a2f25bd8c12d41ffe43647bcbc2568abebfe4 Mon Sep 17 00:00:00 2001 From: Guillaume Ayoub Date: Wed, 22 Feb 2012 13:10:50 +0100 Subject: [PATCH 013/134] Fix a python3 division bug --- cov_core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cov_core.py b/cov_core.py index 97a13c8e..631622e9 100644 --- a/cov_core.py +++ b/cov_core.py @@ -52,7 +52,7 @@ def sep(stream, s, txt): stream.sep(s, txt) else: sep_total = max((70 - 2 - len(txt)), 2) - sep_len = sep_total / 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) From 2eb5dbf7de083e102a99bb49bf73d713f7136e88 Mon Sep 17 00:00:00 2001 From: Meme Dough Date: Sun, 11 Mar 2012 10:48:17 +1100 Subject: [PATCH 014/134] Bump version for release. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 225086e1..642f2cc9 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ ''' % (PTH_FILE_NAME, PTH_FILE) setuptools.setup(name='cov-core', - version='1.3', + version='1.4', description='plugin core for use by pytest-cov, nose-cov and unittest2-cov', long_description=open('README.txt').read().strip(), author='Meme Dough', From bce57896413717f36591792479448566459104ec Mon Sep 17 00:00:00 2001 From: Meme Dough Date: Sun, 11 Mar 2012 10:49:35 +1100 Subject: [PATCH 015/134] Added tag RELEASE_1_4 for changeset e493e868963a From 083a00c1d3885805a026ef0c9f67f079fd05289a Mon Sep 17 00:00:00 2001 From: Meme Dough Date: Sun, 11 Mar 2012 18:17:30 +1100 Subject: [PATCH 016/134] Add hooks to start coverage for multiprocess forks. --- cov_core.py | 19 ++++++++++++++++++- cov_core_init.py | 2 ++ setup.py | 4 ++-- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/cov_core.py b/cov_core.py index 631622e9..c39df979 100644 --- a/cov_core.py +++ b/cov_core.py @@ -1,11 +1,27 @@ """Coverage controllers for use by pytest-cov and nose-cov.""" +from cov_core_init import UNIQUE_SEP +import cov_core_init import coverage +import multiprocessing.util import socket import sys import os -from cov_core_init import UNIQUE_SEP + +def multiprocessing_start(obj): + cov = cov_core_init.init() + if cov: + multiprocessing.util.Finalize(None, + multiprocessing_finish, + args=(cov,), + exitpriority=1000) + + +def multiprocessing_finish(cov): + cov.stop() + cov.save() + class CovController(object): """Base class for different plugin implementations.""" @@ -31,6 +47,7 @@ def set_env(self): 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 + multiprocessing.util.register_after_fork(multiprocessing_start, multiprocessing_start) @staticmethod def unset_env(): diff --git a/cov_core_init.py b/cov_core_init.py index 53494fc6..7170b082 100644 --- a/cov_core_init.py +++ b/cov_core_init.py @@ -55,5 +55,7 @@ def init(): cov.erase() cov.start() + return cov + except Exception: pass diff --git a/setup.py b/setup.py index 642f2cc9..bdf9b4dd 100644 --- a/setup.py +++ b/setup.py @@ -21,8 +21,8 @@ ''' % (PTH_FILE_NAME, PTH_FILE) setuptools.setup(name='cov-core', - version='1.4', - description='plugin core for use by pytest-cov, nose-cov and unittest2-cov', + version='1.5', + description='plugin core for use by pytest-cov, nose-cov and nose2-cov', long_description=open('README.txt').read().strip(), author='Meme Dough', author_email='memedough@gmail.com', From 7a84a6fefb57c2a2dfeede02b97fabd831a035b8 Mon Sep 17 00:00:00 2001 From: Meme Dough Date: Sun, 11 Mar 2012 18:17:47 +1100 Subject: [PATCH 017/134] Added tag RELEASE_1_5 for changeset 69f3e3c7c4df From 132eba7f656f9779fc333ca901e4b132696b50b7 Mon Sep 17 00:00:00 2001 From: Meme Dough Date: Mon, 12 Mar 2012 12:16:28 +1100 Subject: [PATCH 018/134] Fix python 2.4 / 2.5 --- README.txt | 2 +- cov_core.py | 13 +++++++++++-- setup.py | 2 +- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/README.txt b/README.txt index 310fa584..6887bf9e 100644 --- a/README.txt +++ b/README.txt @@ -1,5 +1,5 @@ cov-core ======== -This is a lib package for use by pytest-cov, nose-cov and unittest2-cov. Unless your developing a +This is a lib package for use by pytest-cov, nose-cov and nose2-cov. Unless your developing a coverage plugin for a test framework then you probably want one of those. diff --git a/cov_core.py b/cov_core.py index c39df979..37120353 100644 --- a/cov_core.py +++ b/cov_core.py @@ -3,15 +3,24 @@ from cov_core_init import UNIQUE_SEP import cov_core_init import coverage -import multiprocessing.util import socket import sys import os +def multiprocessing_hook(): + try: + import multiprocessing.util + multiprocessing.util.register_after_fork(multiprocessing_start, + multiprocessing_start) + except ImportError: + pass + + def multiprocessing_start(obj): cov = cov_core_init.init() if cov: + import multiprocessing.util multiprocessing.util.Finalize(None, multiprocessing_finish, args=(cov,), @@ -47,7 +56,7 @@ def set_env(self): 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 - multiprocessing.util.register_after_fork(multiprocessing_start, multiprocessing_start) + multiprocessing_hook() @staticmethod def unset_env(): diff --git a/setup.py b/setup.py index bdf9b4dd..19fc1d0d 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ ''' % (PTH_FILE_NAME, PTH_FILE) setuptools.setup(name='cov-core', - version='1.5', + version='1.6', description='plugin core for use by pytest-cov, nose-cov and nose2-cov', long_description=open('README.txt').read().strip(), author='Meme Dough', From ed17cd48661b17b3373ba074c830516125578485 Mon Sep 17 00:00:00 2001 From: Meme Dough Date: Mon, 12 Mar 2012 12:16:54 +1100 Subject: [PATCH 019/134] Added tag RELEASE_1_6 for changeset a1ec97f79a80 From 7455103e0f7747d5f16c5bb0499c2612e350fea1 Mon Sep 17 00:00:00 2001 From: cwithers Date: Tue, 10 Jul 2012 12:30:05 +0100 Subject: [PATCH 020/134] handle failing to write to a path --- setup.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/setup.py b/setup.py index 19fc1d0d..8639c27b 100644 --- a/setup.py +++ b/setup.py @@ -50,10 +50,14 @@ 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) - 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 + try: + pth_file = open(path, 'w') + pth_file.write(PTH_FILE) + pth_file.close() + except: + sys.stdout.write('\nFailed to write pth file for subprocess measurement to %s\n' % path) + else: + sys.stdout.write('\nWrote pth file for subprocess measurement to %s\n' % path) + break else: sys.stdout.write(UNKNOWN_SITE_PACKAGES_DIR) From fa6c3e66f53c2e26749a0813d34738758f452069 Mon Sep 17 00:00:00 2001 From: Meme Dough Date: Sat, 1 Sep 2012 14:33:55 +1000 Subject: [PATCH 021/134] Change pth file failure handling. --- setup.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/setup.py b/setup.py index 8639c27b..5649eed7 100644 --- a/setup.py +++ b/setup.py @@ -12,11 +12,10 @@ import os; os.environ.get('COV_CORE_SOURCE') and __import__('cov_core_init').init() ''' -UNKNOWN_SITE_PACKAGES_DIR = ''' -Failed to find site-packages or dist-packages dir to put pth file in. -Sub processes will not have coverage collected. +PTH_FILE_FAILURE = ''' +Subprocesses WILL NOT have coverage collected. -To measure sub processes put the following in a file called %s: +To measure subprocesses put the following in a pth file called %s: %s ''' % (PTH_FILE_NAME, PTH_FILE) @@ -54,10 +53,12 @@ pth_file = open(path, 'w') pth_file.write(PTH_FILE) pth_file.close() - except: - sys.stdout.write('\nFailed to write pth file for subprocess measurement to %s\n' % path) - else: 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(UNKNOWN_SITE_PACKAGES_DIR) + sys.stdout.write('\nFailed to find site-packages or dist-packages dir to put pth file in.\n') + sys.stdout.write(PTH_FILE_FAILURE) From fe64e2d095b23df213eeb892b61a125a8904d379 Mon Sep 17 00:00:00 2001 From: Meme Dough Date: Sat, 1 Sep 2012 16:11:32 +1000 Subject: [PATCH 022/134] Bump version for release. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 5649eed7..86550e13 100644 --- a/setup.py +++ b/setup.py @@ -20,7 +20,7 @@ ''' % (PTH_FILE_NAME, PTH_FILE) setuptools.setup(name='cov-core', - version='1.6', + version='1.7', description='plugin core for use by pytest-cov, nose-cov and nose2-cov', long_description=open('README.txt').read().strip(), author='Meme Dough', From 6fa2bdea99c20b8b94b26177ed3d6e4eb1b21882 Mon Sep 17 00:00:00 2001 From: Meme Dough Date: Sat, 1 Sep 2012 16:15:08 +1000 Subject: [PATCH 023/134] Added tag RELEASE_1_7 for changeset 11d168c649be From 9c325546ff57f31be3e368ad4e1bbe2a2ee03fe6 Mon Sep 17 00:00:00 2001 From: schlamar Date: Fri, 18 Apr 2014 11:57:57 +0200 Subject: [PATCH 024/134] Updated setup.py --- setup.py | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/setup.py b/setup.py index 86550e13..fbccd86c 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,8 @@ # 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. +# The line in the path file must begin with "import" +# so that site.py will exec it. PTH_FILE = '''\ import os; os.environ.get('COV_CORE_SOURCE') and __import__('cov_core_init').init() ''' @@ -21,11 +22,12 @@ setuptools.setup(name='cov-core', version='1.7', - description='plugin core for use by pytest-cov, nose-cov and nose2-cov', + description='plugin core for use by pytest-cov, ' + 'nose-cov and nose2-cov', long_description=open('README.txt').read().strip(), - author='Meme Dough', - author_email='memedough@gmail.com', - url='http://bitbucket.org/memedough/cov-core/overview', + 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.4'], @@ -47,18 +49,22 @@ 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): + 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) + 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('\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('\nFailed to find site-packages or dist-packages ' + 'dir to put pth file in.\n') sys.stdout.write(PTH_FILE_FAILURE) From e8d1025cb93d4fe60859674bc987c0fa8103e3f2 Mon Sep 17 00:00:00 2001 From: schlamar Date: Fri, 18 Apr 2014 12:00:00 +0200 Subject: [PATCH 025/134] Renamed README. --- README.txt => README.rst | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename README.txt => README.rst (100%) diff --git a/README.txt b/README.rst similarity index 100% rename from README.txt rename to README.rst From a052c080eab37d30a28b7cb29c96e0a2b7037282 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Fri, 18 Apr 2014 15:40:01 -0700 Subject: [PATCH 026/134] English fixes in README Was https://bitbucket.org/memedough/cov-core/pull-request/4/english-fixes-in-readme --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 6887bf9e..1a41daf2 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ cov-core ======== -This is a lib package for use by pytest-cov, nose-cov and nose2-cov. Unless your developing a -coverage plugin for a test framework then you probably want one of those. +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. From 27c59a76264d35fd9c6575c09ce4f69a139f3aab Mon Sep 17 00:00:00 2001 From: schlamar Date: Thu, 24 Apr 2014 10:49:47 +0200 Subject: [PATCH 027/134] Added gitignore. --- .hgignore => .gitignore | 3 --- 1 file changed, 3 deletions(-) rename .hgignore => .gitignore (69%) diff --git a/.hgignore b/.gitignore similarity index 69% rename from .hgignore rename to .gitignore index 403e1dbd..46a6d937 100644 --- a/.hgignore +++ b/.gitignore @@ -1,6 +1,3 @@ -syntax: glob - -*~ *.pyo *.pyc *egg-info From b77c10a3d257b5a041434c1f9af47a1bec04ebca Mon Sep 17 00:00:00 2001 From: schlamar Date: Thu, 24 Apr 2014 11:09:12 +0200 Subject: [PATCH 028/134] Fixed setup.py. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index fbccd86c..9035d271 100644 --- a/setup.py +++ b/setup.py @@ -24,7 +24,7 @@ version='1.7', description='plugin core for use by pytest-cov, ' 'nose-cov and nose2-cov', - long_description=open('README.txt').read().strip(), + long_description=open('README.rst').read().strip(), author='Marc Schlaich', author_email='marc.schlaich@gmail.com', url='https://github.com/schlamar/cov-core', From d50273c259340c3fc701567218871d2866c5034b Mon Sep 17 00:00:00 2001 From: schlamar Date: Thu, 24 Apr 2014 10:51:02 +0200 Subject: [PATCH 029/134] Enabled coverage collection in DistMaster. --- cov_core.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/cov_core.py b/cov_core.py index 37120353..2a9b8788 100644 --- a/cov_core.py +++ b/cov_core.py @@ -161,6 +161,12 @@ def start(self): 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() + def configure_node(self, node): """Slaves need to know if they are collocated and what files have moved.""" @@ -199,10 +205,6 @@ 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 = coverage.coverage(source=self.cov_source, - data_file=self.cov_data_file, - config_file=self.cov_config) - self.cov.erase() self.cov.combine() self.cov.save() From d6a120b77528327f46b18877a5aac4e8a4e780e8 Mon Sep 17 00:00:00 2001 From: schlamar Date: Thu, 24 Apr 2014 11:30:23 +0200 Subject: [PATCH 030/134] Updated MANIFEST. --- MANIFEST.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MANIFEST.in b/MANIFEST.in index fe99a41d..9ad66a9b 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,4 @@ -include README.txt +include README.rst include LICENSE.txt include setup.py include cov_core.py From 493be4c71e82d7c43db4166673a45b06221d8976 Mon Sep 17 00:00:00 2001 From: schlamar Date: Thu, 24 Apr 2014 11:36:03 +0200 Subject: [PATCH 031/134] Bump version. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 9035d271..a81eb94c 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ ''' % (PTH_FILE_NAME, PTH_FILE) setuptools.setup(name='cov-core', - version='1.7', + version='1.8', description='plugin core for use by pytest-cov, ' 'nose-cov and nose2-cov', long_description=open('README.rst').read().strip(), From a9b9dbc7f1c6ff3fe5bf62de079bf2304b5a54a6 Mon Sep 17 00:00:00 2001 From: Marc Schlaich Date: Fri, 25 Apr 2014 11:52:13 +0200 Subject: [PATCH 032/134] Stop coverage in DistMaster. --- cov_core.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cov_core.py b/cov_core.py index 2a9b8788..62074f13 100644 --- a/cov_core.py +++ b/cov_core.py @@ -205,6 +205,7 @@ 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() From a4fc404956b7e133e2517b5784a97b5fa2fc7f75 Mon Sep 17 00:00:00 2001 From: schlamar Date: Sat, 26 Apr 2014 00:14:13 +0200 Subject: [PATCH 033/134] Use coverage's path rewrite. --- cov_core.py | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/cov_core.py b/cov_core.py index 62074f13..0846d0af 100644 --- a/cov_core.py +++ b/cov_core.py @@ -166,6 +166,7 @@ def start(self): 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.""" @@ -195,6 +196,8 @@ def testnodedown(self, node, error): 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() @@ -259,25 +262,15 @@ def finish(self): # data file to indicate that we have finished. self.config.slaveoutput['cov_slave_node_id'] = self.nodeid else: - # If we are not collocated then rewrite the filenames from - # the slave location to the master location. - slave_topdir = self.topdir - path_rewrites = [(os.path.join(slave_topdir, os.path.basename(rsync_root)), rsync_root) - for rsync_root in self.config.slaveinput['cov_master_rsync_roots']] - path_rewrites.append((slave_topdir, self.config.slaveinput['cov_master_topdir'])) - - def rewrite_path(filename): - for slave_path, master_path in path_rewrites: - filename = filename.replace(slave_path, master_path) - return filename - - lines = dict((rewrite_path(filename), data) for filename, data in self.cov.data.lines.items()) - arcs = dict((rewrite_path(filename), data) for filename, data in self.cov.data.arcs.items()) + # 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'] = lines - self.config.slaveoutput['cov_slave_arcs'] = arcs + 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.""" From dc522ee694aea78cdb0509a693624ebd62bb6308 Mon Sep 17 00:00:00 2001 From: schlamar Date: Sat, 26 Apr 2014 00:15:40 +0200 Subject: [PATCH 034/134] Bump version. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index a81eb94c..616abf7e 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ ''' % (PTH_FILE_NAME, PTH_FILE) setuptools.setup(name='cov-core', - version='1.8', + version='1.9', description='plugin core for use by pytest-cov, ' 'nose-cov and nose2-cov', long_description=open('README.rst').read().strip(), From dd81be583e68ec17f3040280730d2716f374f111 Mon Sep 17 00:00:00 2001 From: schlamar Date: Sat, 26 Apr 2014 17:16:30 +0200 Subject: [PATCH 035/134] Fixed possible KeyError when clearing environ in tests. --- cov_core.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/cov_core.py b/cov_core.py index 0846d0af..a068ca1a 100644 --- a/cov_core.py +++ b/cov_core.py @@ -61,10 +61,9 @@ def set_env(self): @staticmethod def unset_env(): """Remove coverage info from env.""" - - del os.environ['COV_CORE_SOURCE'] - del os.environ['COV_CORE_DATA_FILE'] - del os.environ['COV_CORE_CONFIG'] + 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): From 770871d295e8181e86ce26e2c817a0cb95abe44b Mon Sep 17 00:00:00 2001 From: schlamar Date: Sat, 26 Apr 2014 17:17:14 +0200 Subject: [PATCH 036/134] Bump version. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 616abf7e..c03f33ef 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ ''' % (PTH_FILE_NAME, PTH_FILE) setuptools.setup(name='cov-core', - version='1.9', + version='1.10', description='plugin core for use by pytest-cov, ' 'nose-cov and nose2-cov', long_description=open('README.rst').read().strip(), From b980d6f53eb327f8e277efa071b3165230520388 Mon Sep 17 00:00:00 2001 From: schlamar Date: Mon, 28 Apr 2014 10:21:43 +0200 Subject: [PATCH 037/134] Fixed multiprocessing_hook on Windows. --- cov_core.py | 27 +++++++++------------------ cov_core_init.py | 12 +++++++++++- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/cov_core.py b/cov_core.py index a068ca1a..1c12ec48 100644 --- a/cov_core.py +++ b/cov_core.py @@ -8,23 +8,8 @@ import os -def multiprocessing_hook(): - try: - import multiprocessing.util - multiprocessing.util.register_after_fork(multiprocessing_start, - multiprocessing_start) - except ImportError: - pass - - def multiprocessing_start(obj): - cov = cov_core_init.init() - if cov: - import multiprocessing.util - multiprocessing.util.Finalize(None, - multiprocessing_finish, - args=(cov,), - exitpriority=1000) + cov_core_init.init() def multiprocessing_finish(cov): @@ -32,12 +17,19 @@ def multiprocessing_finish(cov): 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 @@ -56,7 +48,6 @@ def set_env(self): 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 - multiprocessing_hook() @staticmethod def unset_env(): diff --git a/cov_core_init.py b/cov_core_init.py index 7170b082..3e9b8a8c 100644 --- a/cov_core_init.py +++ b/cov_core_init.py @@ -14,8 +14,11 @@ info passed via env vars. """ + UNIQUE_SEP = '084031f3d2994d40a88c8b699b69e148' +import cov_core + def init(): @@ -55,7 +58,14 @@ def init(): cov.erase() cov.start() - return cov + try: + import multiprocessing.util + multiprocessing.util.Finalize(None, + cov_core.multiprocessing_finish, + args=(cov,), + exitpriority=1000) + except ImportError: + pass except Exception: pass From ffb66a0874eb70ecfabd818ce12827ce36437cb4 Mon Sep 17 00:00:00 2001 From: schlamar Date: Mon, 28 Apr 2014 10:26:16 +0200 Subject: [PATCH 038/134] Bump version. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index c03f33ef..013a54c7 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ ''' % (PTH_FILE_NAME, PTH_FILE) setuptools.setup(name='cov-core', - version='1.10', + version='1.11', description='plugin core for use by pytest-cov, ' 'nose-cov and nose2-cov', long_description=open('README.rst').read().strip(), From bdaed91bc2f5e5584abdc503d91f78e7bcb0a1d9 Mon Sep 17 00:00:00 2001 From: schlamar Date: Mon, 5 May 2014 08:31:03 +0200 Subject: [PATCH 039/134] Fixed API-breaking change. Regression from b980d6f. --- cov_core.py | 3 ++- cov_core_init.py | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/cov_core.py b/cov_core.py index 1c12ec48..e3e6b630 100644 --- a/cov_core.py +++ b/cov_core.py @@ -13,7 +13,8 @@ def multiprocessing_start(obj): def multiprocessing_finish(cov): - cov.stop() + if cov._started: + cov.stop() cov.save() diff --git a/cov_core_init.py b/cov_core_init.py index 3e9b8a8c..60b9065e 100644 --- a/cov_core_init.py +++ b/cov_core_init.py @@ -67,5 +67,7 @@ def init(): except ImportError: pass + return cov + except Exception: pass From 31c6f623b3e1f6e916d064f4c0a2994988321c69 Mon Sep 17 00:00:00 2001 From: schlamar Date: Mon, 5 May 2014 08:54:30 +0200 Subject: [PATCH 040/134] Bump version. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 013a54c7..17521d24 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ ''' % (PTH_FILE_NAME, PTH_FILE) setuptools.setup(name='cov-core', - version='1.11', + version='1.12', description='plugin core for use by pytest-cov, ' 'nose-cov and nose2-cov', long_description=open('README.rst').read().strip(), From 398dceb6c64682a6a84272b1b1128519b88b179b Mon Sep 17 00:00:00 2001 From: Marc Schlaich Date: Thu, 5 Jun 2014 08:05:12 +0200 Subject: [PATCH 041/134] Updated required coverage version. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 17521d24..3c7c11eb 100644 --- a/setup.py +++ b/setup.py @@ -30,7 +30,7 @@ url='https://github.com/schlamar/cov-core', py_modules=['cov_core', 'cov_core_init'], - install_requires=['coverage>=3.4'], + install_requires=['coverage>=3.6'], license='MIT License', zip_safe=False, keywords='cover coverage', From 82f3b53637f1d3e50a798f77e2dd1a5571d169cc Mon Sep 17 00:00:00 2001 From: schlamar Date: Thu, 5 Jun 2014 14:50:57 +0200 Subject: [PATCH 042/134] Fixed race condition in multiprocessing hook. Register finalize hook only if coverage was initialized by after fork hook. --- cov_core.py | 8 +++++--- cov_core_init.py | 12 +----------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/cov_core.py b/cov_core.py index e3e6b630..95de5e4a 100644 --- a/cov_core.py +++ b/cov_core.py @@ -9,12 +9,14 @@ def multiprocessing_start(obj): - cov_core_init.init() + cov = cov_core_init.init() + import multiprocessing.util + multiprocessing.util.Finalize( + None, multiprocessing_finish, args=(cov,), exitpriority=1000) def multiprocessing_finish(cov): - if cov._started: - cov.stop() + cov.stop() cov.save() diff --git a/cov_core_init.py b/cov_core_init.py index 60b9065e..e931ab2a 100644 --- a/cov_core_init.py +++ b/cov_core_init.py @@ -17,7 +17,7 @@ UNIQUE_SEP = '084031f3d2994d40a88c8b699b69e148' -import cov_core +import cov_core # noqa: register multiprocessing handler def init(): @@ -57,16 +57,6 @@ def init(): auto_data=True) cov.erase() cov.start() - - try: - import multiprocessing.util - multiprocessing.util.Finalize(None, - cov_core.multiprocessing_finish, - args=(cov,), - exitpriority=1000) - except ImportError: - pass - return cov except Exception: From d92699fcb23b5989e50f47afbacae84e0729a10d Mon Sep 17 00:00:00 2001 From: schlamar Date: Thu, 5 Jun 2014 11:23:47 +0200 Subject: [PATCH 043/134] Added support for py.process.ForkedFunc --- cov_core.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/cov_core.py b/cov_core.py index 95de5e4a..59d55bbe 100644 --- a/cov_core.py +++ b/cov_core.py @@ -28,6 +28,27 @@ def multiprocessing_finish(cov): pass +_cov_data = dict() + + +def on_py_fork_starts(proc): + cov = cov_core_init.init() + _cov_data[proc] = cov + + +def on_py_fork_exits(proc): + cov = _cov_data.pop(proc) + multiprocessing_finish(cov) + + +try: + import py + py.process.ForkedFunc.register_on_start(on_py_fork_starts) + py.process.ForkedFunc.register_on_exit(on_py_fork_exits) +except (ImportError, AttributeError): + pass + + class CovController(object): """Base class for different plugin implementations.""" From 3029d926ba86f1fbaca4a0059950732219bef2b3 Mon Sep 17 00:00:00 2001 From: schlamar Date: Thu, 12 Jun 2014 20:41:54 +0200 Subject: [PATCH 044/134] Bump version. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 3c7c11eb..6fc03bd6 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ ''' % (PTH_FILE_NAME, PTH_FILE) setuptools.setup(name='cov-core', - version='1.12', + version='1.13.0', description='plugin core for use by pytest-cov, ' 'nose-cov and nose2-cov', long_description=open('README.rst').read().strip(), From 034ded061467cf8a4cd8971bf083fa9e2315d424 Mon Sep 17 00:00:00 2001 From: schlamar Date: Fri, 22 Aug 2014 21:24:16 +0200 Subject: [PATCH 045/134] Revert "Added support for py.process.ForkedFunc" This reverts commit d92699fcb23b5989e50f47afbacae84e0729a10d as support for register hooks has changed in py. --- cov_core.py | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/cov_core.py b/cov_core.py index 59d55bbe..95de5e4a 100644 --- a/cov_core.py +++ b/cov_core.py @@ -28,27 +28,6 @@ def multiprocessing_finish(cov): pass -_cov_data = dict() - - -def on_py_fork_starts(proc): - cov = cov_core_init.init() - _cov_data[proc] = cov - - -def on_py_fork_exits(proc): - cov = _cov_data.pop(proc) - multiprocessing_finish(cov) - - -try: - import py - py.process.ForkedFunc.register_on_start(on_py_fork_starts) - py.process.ForkedFunc.register_on_exit(on_py_fork_exits) -except (ImportError, AttributeError): - pass - - class CovController(object): """Base class for different plugin implementations.""" From 324030518afc74311cbde265cc20121474e663cc Mon Sep 17 00:00:00 2001 From: schlamar Date: Fri, 22 Aug 2014 21:51:05 +0200 Subject: [PATCH 046/134] Bump version. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 6fc03bd6..64e6258e 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ ''' % (PTH_FILE_NAME, PTH_FILE) setuptools.setup(name='cov-core', - version='1.13.0', + version='1.14.0', description='plugin core for use by pytest-cov, ' 'nose-cov and nose2-cov', long_description=open('README.rst').read().strip(), From 188dda76626cfec2f540269c7b180fb4836200e4 Mon Sep 17 00:00:00 2001 From: Buck Golemon Date: Wed, 22 Oct 2014 14:52:26 -0700 Subject: [PATCH 047/134] allow for cov_source=None --- cov_core.py | 5 ++++- cov_core_init.py | 7 +++++-- setup.py | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/cov_core.py b/cov_core.py index 95de5e4a..a7a033b0 100644 --- a/cov_core.py +++ b/cov_core.py @@ -48,7 +48,10 @@ def __init__(self, cov_source, cov_report, cov_config, config=None, nodeid=None) def set_env(self): """Put info about coverage into the env so that subprocesses can activate coverage.""" - os.environ['COV_CORE_SOURCE'] = UNIQUE_SEP.join(self.cov_source) + 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 diff --git a/cov_core_init.py b/cov_core_init.py index e931ab2a..ff359c15 100644 --- a/cov_core_init.py +++ b/cov_core_init.py @@ -33,7 +33,7 @@ def init(): 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_source and cov_data_file and cov_config: + if cov_data_file and cov_config: # Import what we need to activate coverage. import socket @@ -41,7 +41,10 @@ def init(): import coverage # Determine all source roots. - cov_source = cov_source.split(UNIQUE_SEP) + 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. diff --git a/setup.py b/setup.py index 64e6258e..8ac3c575 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ # The line in the path file must begin with "import" # so that site.py will exec it. PTH_FILE = '''\ -import os; os.environ.get('COV_CORE_SOURCE') and __import__('cov_core_init').init() +import os; 'COV_CORE_SOURCE' in os.environ and __import__('cov_core_init').init() ''' PTH_FILE_FAILURE = ''' From 791b1f6890456ee9e3beec33c89a7c573a382b7b Mon Sep 17 00:00:00 2001 From: schlamar Date: Sat, 22 Nov 2014 12:04:38 +0100 Subject: [PATCH 048/134] bump version --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 8ac3c575..0989863e 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ ''' % (PTH_FILE_NAME, PTH_FILE) setuptools.setup(name='cov-core', - version='1.14.0', + version='1.15.0', description='plugin core for use by pytest-cov, ' 'nose-cov and nose2-cov', long_description=open('README.rst').read().strip(), From 08b72c60cc68de49dda41196b73b13121d62d9eb Mon Sep 17 00:00:00 2001 From: schlamar Date: Sat, 22 Nov 2014 13:15:47 +0100 Subject: [PATCH 049/134] moved pytest-cov to subdirectory --- .travis.yml | 2 +- .gitignore => pytest-cov/.gitignore | 0 LICENSE.txt => pytest-cov/LICENSE.txt | 0 MANIFEST.in => pytest-cov/MANIFEST.in | 0 README.rst => pytest-cov/README.rst | 0 pytest_cov.py => pytest-cov/pytest_cov.py | 0 setup.py => pytest-cov/setup.py | 0 test_pytest_cov.py => pytest-cov/test_pytest_cov.py | 0 tox.ini => pytest-cov/tox.ini | 0 9 files changed, 1 insertion(+), 1 deletion(-) rename .gitignore => pytest-cov/.gitignore (100%) rename LICENSE.txt => pytest-cov/LICENSE.txt (100%) rename MANIFEST.in => pytest-cov/MANIFEST.in (100%) rename README.rst => pytest-cov/README.rst (100%) rename pytest_cov.py => pytest-cov/pytest_cov.py (100%) rename setup.py => pytest-cov/setup.py (100%) rename test_pytest_cov.py => pytest-cov/test_pytest_cov.py (100%) rename tox.ini => pytest-cov/tox.ini (100%) diff --git a/.travis.yml b/.travis.yml index daabdf11..5c52f6cb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,7 @@ env: install: - pip install tox script: - - tox -e $TOX_ENV + - cd pytest-cov && tox -e $TOX_ENV notifications: email: on_success: never diff --git a/.gitignore b/pytest-cov/.gitignore similarity index 100% rename from .gitignore rename to pytest-cov/.gitignore diff --git a/LICENSE.txt b/pytest-cov/LICENSE.txt similarity index 100% rename from LICENSE.txt rename to pytest-cov/LICENSE.txt diff --git a/MANIFEST.in b/pytest-cov/MANIFEST.in similarity index 100% rename from MANIFEST.in rename to pytest-cov/MANIFEST.in diff --git a/README.rst b/pytest-cov/README.rst similarity index 100% rename from README.rst rename to pytest-cov/README.rst diff --git a/pytest_cov.py b/pytest-cov/pytest_cov.py similarity index 100% rename from pytest_cov.py rename to pytest-cov/pytest_cov.py diff --git a/setup.py b/pytest-cov/setup.py similarity index 100% rename from setup.py rename to pytest-cov/setup.py diff --git a/test_pytest_cov.py b/pytest-cov/test_pytest_cov.py similarity index 100% rename from test_pytest_cov.py rename to pytest-cov/test_pytest_cov.py diff --git a/tox.ini b/pytest-cov/tox.ini similarity index 100% rename from tox.ini rename to pytest-cov/tox.ini From 434d7f791981a6741a4d95aaeb94c7d406619379 Mon Sep 17 00:00:00 2001 From: schlamar Date: Sat, 22 Nov 2014 13:35:52 +0100 Subject: [PATCH 050/134] moved cov-core to subdirectory --- .gitignore => cov-core/.gitignore | 0 LICENSE.txt => cov-core/LICENSE.txt | 0 MANIFEST.in => cov-core/MANIFEST.in | 0 README.rst => cov-core/README.rst | 0 cov_core.py => cov-core/cov_core.py | 0 cov_core_init.py => cov-core/cov_core_init.py | 0 setup.py => cov-core/setup.py | 0 7 files changed, 0 insertions(+), 0 deletions(-) rename .gitignore => cov-core/.gitignore (100%) rename LICENSE.txt => cov-core/LICENSE.txt (100%) rename MANIFEST.in => cov-core/MANIFEST.in (100%) rename README.rst => cov-core/README.rst (100%) rename cov_core.py => cov-core/cov_core.py (100%) rename cov_core_init.py => cov-core/cov_core_init.py (100%) rename setup.py => cov-core/setup.py (100%) diff --git a/.gitignore b/cov-core/.gitignore similarity index 100% rename from .gitignore rename to cov-core/.gitignore diff --git a/LICENSE.txt b/cov-core/LICENSE.txt similarity index 100% rename from LICENSE.txt rename to cov-core/LICENSE.txt diff --git a/MANIFEST.in b/cov-core/MANIFEST.in similarity index 100% rename from MANIFEST.in rename to cov-core/MANIFEST.in diff --git a/README.rst b/cov-core/README.rst similarity index 100% rename from README.rst rename to cov-core/README.rst diff --git a/cov_core.py b/cov-core/cov_core.py similarity index 100% rename from cov_core.py rename to cov-core/cov_core.py diff --git a/cov_core_init.py b/cov-core/cov_core_init.py similarity index 100% rename from cov_core_init.py rename to cov-core/cov_core_init.py diff --git a/setup.py b/cov-core/setup.py similarity index 100% rename from setup.py rename to cov-core/setup.py From 0a6b00dd73c2c49d38e50d01add558e1bb4f3c92 Mon Sep 17 00:00:00 2001 From: Marc Schlaich Date: Mon, 24 Nov 2014 18:15:44 +0100 Subject: [PATCH 051/134] Create CONTRIBUTING.md --- CONTRIBUTING.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..e94ef66b --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1 @@ +All new features should go into [2.0 branch](https://github.com/schlamar/pytest-cov/tree/2.0). Thanks! :cake: From 1ba7ee6bd6fd6e105265083beb7a7d5044a7b675 Mon Sep 17 00:00:00 2001 From: schlamar Date: Sat, 22 Nov 2014 13:39:22 +0100 Subject: [PATCH 052/134] add README --- README.rst | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 README.rst diff --git a/README.rst b/README.rst new file mode 100644 index 00000000..4edbedcb --- /dev/null +++ b/README.rst @@ -0,0 +1,7 @@ +py-cov +====== + +Collection of Python coverage projects. + +- pytest-cov +- cov-core From 2a8f111d7857c39787cd913dd4f124e27a0a065c Mon Sep 17 00:00:00 2001 From: schlamar Date: Sat, 22 Nov 2014 14:04:38 +0100 Subject: [PATCH 053/134] run tests also against cov-core master --- .travis.yml | 26 +++++++++++++++++++------- pytest-cov/tox.ini | 1 + 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5c52f6cb..2b68abcc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,17 +2,29 @@ language: python python: 2.7 env: - TOX_ENV=flake8 - - TOX_ENV=pypy - - TOX_ENV=pypy3 - - TOX_ENV=py26 - - TOX_ENV=py27 - - TOX_ENV=py32 - - TOX_ENV=py33 - - TOX_ENV=py34 + + - TOX_ENV=pypy COV_CORE_DEP=cov-core + - TOX_ENV=pypy3 COV_CORE_DEP=cov-core + - TOX_ENV=py26 COV_CORE_DEP=cov-core + - TOX_ENV=py27 COV_CORE_DEP=cov-core + - TOX_ENV=py32 COV_CORE_DEP=cov-core + - TOX_ENV=py33 COV_CORE_DEP=cov-core + - TOX_ENV=py34 COV_CORE_DEP=cov-core + + - TOX_ENV=pypy COV_CORE_DEP=../cov-core + - TOX_ENV=pypy3 COV_CORE_DEP=../cov-core + - TOX_ENV=py26 COV_CORE_DEP=../cov-core + - TOX_ENV=py27 COV_CORE_DEP=../cov-core + - TOX_ENV=py32 COV_CORE_DEP=../cov-core + - TOX_ENV=py33 COV_CORE_DEP=../cov-core + - TOX_ENV=py34 COV_CORE_DEP=../cov-core + install: - pip install tox + script: - cd pytest-cov && tox -e $TOX_ENV + notifications: email: on_success: never diff --git a/pytest-cov/tox.ini b/pytest-cov/tox.ini index 0588e3b9..7d20cadb 100644 --- a/pytest-cov/tox.ini +++ b/pytest-cov/tox.ini @@ -6,6 +6,7 @@ usedevelop = True setenv = PYTHONHASHSEED = random deps = + {env:COV_CORE_DEP:cov-core} pytest pytest-xdist virtualenv From 8f1927e21dfe471ff16eb27b261d4a4cec603209 Mon Sep 17 00:00:00 2001 From: schlamar Date: Sat, 22 Nov 2014 14:39:10 +0100 Subject: [PATCH 054/134] cov-core: adjust maximum line length to 100 --- cov-core/cov_core.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cov-core/cov_core.py b/cov-core/cov_core.py index a7a033b0..82b8756a 100644 --- a/cov-core/cov_core.py +++ b/cov-core/cov_core.py @@ -221,14 +221,15 @@ 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']) + self.is_collocated = (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_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) From 56b161c41bb3bc73ccad2648ee419f391190c5ea Mon Sep 17 00:00:00 2001 From: schlamar Date: Sat, 22 Nov 2014 14:39:50 +0100 Subject: [PATCH 055/134] general: run flake8 against all projects --- .gitignore | 2 ++ .travis.yml | 33 ++++++++++++++++----------------- pytest-cov/tox.ini | 6 +----- setup.py | 3 +++ tox.ini | 9 +++++++++ 5 files changed, 31 insertions(+), 22 deletions(-) create mode 100644 .gitignore create mode 100644 setup.py create mode 100644 tox.ini diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..b2b962ec --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.tox/ +*.egg-info/ diff --git a/.travis.yml b/.travis.yml index 2b68abcc..dc4c508e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,29 +1,28 @@ language: python python: 2.7 env: - - TOX_ENV=flake8 + - CWD=. TOX_ENV=flake8 - - TOX_ENV=pypy COV_CORE_DEP=cov-core - - TOX_ENV=pypy3 COV_CORE_DEP=cov-core - - TOX_ENV=py26 COV_CORE_DEP=cov-core - - TOX_ENV=py27 COV_CORE_DEP=cov-core - - TOX_ENV=py32 COV_CORE_DEP=cov-core - - TOX_ENV=py33 COV_CORE_DEP=cov-core - - TOX_ENV=py34 COV_CORE_DEP=cov-core - - - TOX_ENV=pypy COV_CORE_DEP=../cov-core - - TOX_ENV=pypy3 COV_CORE_DEP=../cov-core - - TOX_ENV=py26 COV_CORE_DEP=../cov-core - - TOX_ENV=py27 COV_CORE_DEP=../cov-core - - TOX_ENV=py32 COV_CORE_DEP=../cov-core - - TOX_ENV=py33 COV_CORE_DEP=../cov-core - - TOX_ENV=py34 COV_CORE_DEP=../cov-core + - CWD=pytest-cov TOX_ENV=pypy COV_CORE_DEP=cov-core + - CWD=pytest-cov TOX_ENV=pypy3 COV_CORE_DEP=cov-core + - CWD=pytest-cov TOX_ENV=py26 COV_CORE_DEP=cov-core + - CWD=pytest-cov TOX_ENV=py27 COV_CORE_DEP=cov-core + - CWD=pytest-cov TOX_ENV=py32 COV_CORE_DEP=cov-core + - CWD=pytest-cov TOX_ENV=py33 COV_CORE_DEP=cov-core + - CWD=pytest-cov TOX_ENV=py34 COV_CORE_DEP=cov-core + - CWD=pytest-cov TOX_ENV=pypy COV_CORE_DEP=../cov-core + - CWD=pytest-cov TOX_ENV=pypy3 COV_CORE_DEP=../cov-core + - CWD=pytest-cov TOX_ENV=py26 COV_CORE_DEP=../cov-core + - CWD=pytest-cov TOX_ENV=py27 COV_CORE_DEP=../cov-core + - CWD=pytest-cov TOX_ENV=py32 COV_CORE_DEP=../cov-core + - CWD=pytest-cov TOX_ENV=py33 COV_CORE_DEP=../cov-core + - CWD=pytest-cov TOX_ENV=py34 COV_CORE_DEP=../cov-core install: - pip install tox script: - - cd pytest-cov && tox -e $TOX_ENV + - cd $CWD && tox -e $TOX_ENV notifications: email: diff --git a/pytest-cov/tox.ini b/pytest-cov/tox.ini index 7d20cadb..8fcabbb2 100644 --- a/pytest-cov/tox.ini +++ b/pytest-cov/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py26, py27, pypy, pypy3, py32, py33, py34, flake8 +envlist = py26, py27, pypy, pypy3, py32, py33, py34 [testenv] usedevelop = True @@ -11,7 +11,3 @@ deps = pytest-xdist virtualenv commands = py.test -v test_pytest_cov.py {posargs} - -[testenv:flake8] -deps = flake8 -commands = flake8 pytest_cov.py setup.py test_pytest_cov.py diff --git a/setup.py b/setup.py new file mode 100644 index 00000000..60684932 --- /dev/null +++ b/setup.py @@ -0,0 +1,3 @@ +from setuptools import setup + +setup() diff --git a/tox.ini b/tox.ini new file mode 100644 index 00000000..b59374ac --- /dev/null +++ b/tox.ini @@ -0,0 +1,9 @@ +[tox] +envlist = flake8 + +[flake8] +max-line-length = 99 + +[testenv:flake8] +deps = flake8 +commands = flake8 From 29ceb5bca7c02a5b344abe20ca8639f31084c728 Mon Sep 17 00:00:00 2001 From: schlamar Date: Sat, 22 Nov 2014 15:35:36 +0100 Subject: [PATCH 056/134] use data_suffix=True instead of manual calculation --- cov-core/cov_core.py | 8 ++------ cov-core/cov_core_init.py | 10 +--------- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/cov-core/cov_core.py b/cov-core/cov_core.py index 82b8756a..345ceafe 100644 --- a/cov-core/cov_core.py +++ b/cov-core/cov_core.py @@ -185,7 +185,7 @@ def testnodedown(self, node, error): 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'], + data_suffix=True, config_file=self.cov_config) cov.start() cov.data.lines = node.slaveoutput['cov_slave_lines'] @@ -233,14 +233,10 @@ def start(self): 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, + data_suffix=True, config_file=self.cov_config) self.cov.erase() self.cov.start() diff --git a/cov-core/cov_core_init.py b/cov-core/cov_core_init.py index ff359c15..d362216d 100644 --- a/cov-core/cov_core_init.py +++ b/cov-core/cov_core_init.py @@ -36,8 +36,6 @@ def init(): if cov_data_file and cov_config: # Import what we need to activate coverage. - import socket - import random import coverage # Determine all source roots. @@ -46,16 +44,10 @@ def init(): 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, + data_suffix=True, config_file=cov_config, auto_data=True) cov.erase() From e3e83c6e66bae2ff7eb4773fccdb9439b8cd4792 Mon Sep 17 00:00:00 2001 From: schlamar Date: Sat, 22 Nov 2014 16:54:36 +0100 Subject: [PATCH 057/134] cov-core: do not hard code data file --- cov-core/cov_core.py | 8 -------- cov-core/cov_core_init.py | 7 +++---- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/cov-core/cov_core.py b/cov-core/cov_core.py index 345ceafe..432b9108 100644 --- a/cov-core/cov_core.py +++ b/cov-core/cov_core.py @@ -43,7 +43,6 @@ def __init__(self, cov_source, cov_report, cov_config, config=None, nodeid=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.""" @@ -52,14 +51,12 @@ def set_env(self): 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 @@ -126,7 +123,6 @@ 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() @@ -158,7 +154,6 @@ def start(self): 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() @@ -184,7 +179,6 @@ def testnodedown(self, node, error): # 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=True, config_file=self.cov_config) cov.start() @@ -230,12 +224,10 @@ def start(self): 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) # Erase any previous data and start coverage. self.cov = coverage.coverage(source=self.cov_source, - data_file=self.cov_data_file, data_suffix=True, config_file=self.cov_config) self.cov.erase() diff --git a/cov-core/cov_core_init.py b/cov-core/cov_core_init.py index d362216d..f91ad34c 100644 --- a/cov-core/cov_core_init.py +++ b/cov-core/cov_core_init.py @@ -30,23 +30,22 @@ def init(): # 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: + if cov_config: # Import what we need to activate coverage. import coverage # Determine all source roots. - if cov_source == '': + if not cov_source: cov_source = None else: cov_source = cov_source.split(UNIQUE_SEP) # Activate coverage for this process. cov = coverage.coverage(source=cov_source, - data_file=cov_data_file, data_suffix=True, config_file=cov_config, auto_data=True) From 44925d5e6e6ac4e5cf740a36e9f452b6ee384a06 Mon Sep 17 00:00:00 2001 From: schlamar Date: Mon, 24 Nov 2014 17:54:01 +0100 Subject: [PATCH 058/134] add example tox project --- .gitignore | 2 ++ example-tox-project/mylib/__init__.py | 13 +++++++++++ example-tox-project/setup.py | 7 ++++++ example-tox-project/tests/test_mylib.py | 7 ++++++ example-tox-project/tox.ini | 30 +++++++++++++++++++++++++ 5 files changed, 59 insertions(+) create mode 100644 example-tox-project/mylib/__init__.py create mode 100644 example-tox-project/setup.py create mode 100644 example-tox-project/tests/test_mylib.py create mode 100644 example-tox-project/tox.ini diff --git a/.gitignore b/.gitignore index b2b962ec..47e23b11 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ .tox/ *.egg-info/ +.coverage +*.pyc \ No newline at end of file diff --git a/example-tox-project/mylib/__init__.py b/example-tox-project/mylib/__init__.py new file mode 100644 index 00000000..f014f944 --- /dev/null +++ b/example-tox-project/mylib/__init__.py @@ -0,0 +1,13 @@ + +import sys + +PY3 = sys.version_info[0] == 3 + + +if PY3: + def add(a, b): + return a + b + +else: + def add(a, b): + return b + a diff --git a/example-tox-project/setup.py b/example-tox-project/setup.py new file mode 100644 index 00000000..588af2e3 --- /dev/null +++ b/example-tox-project/setup.py @@ -0,0 +1,7 @@ + +from setuptools import setup, find_packages + + +setup( + packages=find_packages() +) diff --git a/example-tox-project/tests/test_mylib.py b/example-tox-project/tests/test_mylib.py new file mode 100644 index 00000000..f858b049 --- /dev/null +++ b/example-tox-project/tests/test_mylib.py @@ -0,0 +1,7 @@ + +import mylib + + +def test_add(): + assert mylib.add(1, 1) == 2 + assert not mylib.add(0, 1) == 2 diff --git a/example-tox-project/tox.ini b/example-tox-project/tox.ini new file mode 100644 index 00000000..9bd8fe39 --- /dev/null +++ b/example-tox-project/tox.ini @@ -0,0 +1,30 @@ +[tox] +envlist = cov-init,py27,py34,cov-report + + +[testenv] +usedevelop=True +setenv = + COVERAGE_FILE = .coverage.{envname} +commands = py.test --cov mylib --cov-report= {posargs} +deps = + ../cov-core + pytest + ../pytest-cov + + +[testenv:cov-init] +setenv = + COVERAGE_FILE = .coverage +deps = coverage +commands = + coverage erase + + +[testenv:cov-report] +setenv = + COVERAGE_FILE = .coverage +deps = coverage +commands = + coverage combine + coverage report From c46d9c588f3c1edf93ff9e0245eea40ea72f442c Mon Sep 17 00:00:00 2001 From: schlamar Date: Mon, 24 Nov 2014 18:04:18 +0100 Subject: [PATCH 059/134] cov-core: print no header if report is disabled --- cov-core/cov_core.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/cov-core/cov_core.py b/cov-core/cov_core.py index 432b9108..b9618050 100644 --- a/cov-core/cov_core.py +++ b/cov-core/cov_core.py @@ -78,6 +78,8 @@ def sep(stream, s, txt): def summary(self, stream): """Produce coverage reports.""" + if self.cov_report == ['']: + return # Output coverage section header. if len(self.node_descs) == 1: @@ -138,11 +140,6 @@ def finish(self): 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.""" @@ -202,11 +199,6 @@ def finish(self): self.cov.combine() self.cov.save() - def summary(self, stream): - """Produce coverage reports.""" - - CovController.summary(self, stream) - class DistSlave(CovController): """Implementation for distributed slaves.""" From 92d4549db7c8b3e92cc2f0dc05cfe308560bfd45 Mon Sep 17 00:00:00 2001 From: schlamar Date: Mon, 24 Nov 2014 17:43:05 +0100 Subject: [PATCH 060/134] travis: allow tests to fail with PyPI's cov-core They should only pass before releasing pytest-cov. --- .travis.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.travis.yml b/.travis.yml index dc4c508e..a97ffebd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,7 @@ env: - CWD=pytest-cov TOX_ENV=py32 COV_CORE_DEP=cov-core - CWD=pytest-cov TOX_ENV=py33 COV_CORE_DEP=cov-core - CWD=pytest-cov TOX_ENV=py34 COV_CORE_DEP=cov-core + - CWD=pytest-cov TOX_ENV=pypy COV_CORE_DEP=../cov-core - CWD=pytest-cov TOX_ENV=pypy3 COV_CORE_DEP=../cov-core - CWD=pytest-cov TOX_ENV=py26 COV_CORE_DEP=../cov-core @@ -18,6 +19,16 @@ env: - CWD=pytest-cov TOX_ENV=py33 COV_CORE_DEP=../cov-core - CWD=pytest-cov TOX_ENV=py34 COV_CORE_DEP=../cov-core +matrix: + allow_failures: + - env: CWD=pytest-cov TOX_ENV=pypy COV_CORE_DEP=cov-core + - env: CWD=pytest-cov TOX_ENV=pypy3 COV_CORE_DEP=cov-core + - env: CWD=pytest-cov TOX_ENV=py26 COV_CORE_DEP=cov-core + - env: CWD=pytest-cov TOX_ENV=py27 COV_CORE_DEP=cov-core + - env: CWD=pytest-cov TOX_ENV=py32 COV_CORE_DEP=cov-core + - env: CWD=pytest-cov TOX_ENV=py33 COV_CORE_DEP=cov-core + - env: CWD=pytest-cov TOX_ENV=py34 COV_CORE_DEP=cov-core + install: - pip install tox From d289f7619562b21c42c99c1bc279afff84ff0c41 Mon Sep 17 00:00:00 2001 From: schlamar Date: Mon, 24 Nov 2014 18:19:21 +0100 Subject: [PATCH 061/134] travis: run important tests first --- .travis.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index a97ffebd..c66461af 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,14 +3,6 @@ python: 2.7 env: - CWD=. TOX_ENV=flake8 - - CWD=pytest-cov TOX_ENV=pypy COV_CORE_DEP=cov-core - - CWD=pytest-cov TOX_ENV=pypy3 COV_CORE_DEP=cov-core - - CWD=pytest-cov TOX_ENV=py26 COV_CORE_DEP=cov-core - - CWD=pytest-cov TOX_ENV=py27 COV_CORE_DEP=cov-core - - CWD=pytest-cov TOX_ENV=py32 COV_CORE_DEP=cov-core - - CWD=pytest-cov TOX_ENV=py33 COV_CORE_DEP=cov-core - - CWD=pytest-cov TOX_ENV=py34 COV_CORE_DEP=cov-core - - CWD=pytest-cov TOX_ENV=pypy COV_CORE_DEP=../cov-core - CWD=pytest-cov TOX_ENV=pypy3 COV_CORE_DEP=../cov-core - CWD=pytest-cov TOX_ENV=py26 COV_CORE_DEP=../cov-core @@ -19,6 +11,14 @@ env: - CWD=pytest-cov TOX_ENV=py33 COV_CORE_DEP=../cov-core - CWD=pytest-cov TOX_ENV=py34 COV_CORE_DEP=../cov-core + - CWD=pytest-cov TOX_ENV=pypy COV_CORE_DEP=cov-core + - CWD=pytest-cov TOX_ENV=pypy3 COV_CORE_DEP=cov-core + - CWD=pytest-cov TOX_ENV=py26 COV_CORE_DEP=cov-core + - CWD=pytest-cov TOX_ENV=py27 COV_CORE_DEP=cov-core + - CWD=pytest-cov TOX_ENV=py32 COV_CORE_DEP=cov-core + - CWD=pytest-cov TOX_ENV=py33 COV_CORE_DEP=cov-core + - CWD=pytest-cov TOX_ENV=py34 COV_CORE_DEP=cov-core + matrix: allow_failures: - env: CWD=pytest-cov TOX_ENV=pypy COV_CORE_DEP=cov-core From 16ee9d6d56391c379bb522152cf6d7358ef0364f Mon Sep 17 00:00:00 2001 From: schlamar Date: Mon, 24 Nov 2014 20:03:04 +0100 Subject: [PATCH 062/134] test against cov-core master per default --- pytest-cov/tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pytest-cov/tox.ini b/pytest-cov/tox.ini index 8fcabbb2..a3fb768e 100644 --- a/pytest-cov/tox.ini +++ b/pytest-cov/tox.ini @@ -6,7 +6,7 @@ usedevelop = True setenv = PYTHONHASHSEED = random deps = - {env:COV_CORE_DEP:cov-core} + {env:COV_CORE_DEP:../cov-core} pytest pytest-xdist virtualenv From 5773cec4ad2c66a0fc177f84cec2b68fa88f76e4 Mon Sep 17 00:00:00 2001 From: schlamar Date: Mon, 24 Nov 2014 20:09:54 +0100 Subject: [PATCH 063/134] don't use private terminal reporter API --- pytest-cov/pytest_cov.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pytest-cov/pytest_cov.py b/pytest-cov/pytest_cov.py index c9c6db4f..2bbe9245 100644 --- a/pytest-cov/pytest_cov.py +++ b/pytest-cov/pytest_cov.py @@ -135,7 +135,7 @@ def pytest_terminal_summary(self, terminalreporter): if self.cov_controller is None: return if not (self.failed and self.options.no_cov_on_fail): - self.cov_controller.summary(terminalreporter._tw) + self.cov_controller.summary(terminalreporter.writer) def pytest_runtest_setup(self, item): if os.getpid() != self.pid: From c6cb24f37763ab677e4910099c0f55a10878c533 Mon Sep 17 00:00:00 2001 From: Rick van Hattem Date: Mon, 24 Nov 2014 20:17:47 +0100 Subject: [PATCH 064/134] added support for `cov-min` option to require coverage percentage --- cov-core/cov_core.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/cov-core/cov_core.py b/cov-core/cov_core.py index b9618050..2b895245 100644 --- a/cov-core/cov_core.py +++ b/cov-core/cov_core.py @@ -81,6 +81,8 @@ def summary(self, stream): if self.cov_report == ['']: return + total = 0 + # Output coverage section header. if len(self.node_descs) == 1: self.sep(stream, '-', 'coverage: %s' % ''.join(self.node_descs)) @@ -92,21 +94,21 @@ def summary(self, stream): # 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) + total = 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) + total = 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) + total = 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) + total = 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. @@ -117,6 +119,8 @@ def summary(self, stream): for node in self.failed_slaves: stream.write('%s\n' % node.gateway.id) + return total + class Central(CovController): """Implementation for centralised operation.""" @@ -140,7 +144,6 @@ def finish(self): node_desc = self.get_node_desc(sys.platform, sys.version_info) self.node_descs.add(node_desc) - class DistMaster(CovController): """Implementation for distributed master.""" From 8f679db735ab99f66808e79d4e401996a9191ec0 Mon Sep 17 00:00:00 2001 From: Rick van Hattem Date: Mon, 24 Nov 2014 11:13:49 +0100 Subject: [PATCH 065/134] added support for `cov-min` option to require coverage percentage --- pytest-cov/pytest_cov.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/pytest-cov/pytest_cov.py b/pytest-cov/pytest_cov.py index c9c6db4f..c27aca9e 100644 --- a/pytest-cov/pytest_cov.py +++ b/pytest-cov/pytest_cov.py @@ -8,6 +8,10 @@ import cov_core_init +class CoverageError(Exception): + '''Indicates that our coverage is too low''' + + def pytest_addoption(parser): """Add options to control coverage.""" @@ -30,6 +34,9 @@ def pytest_addoption(parser): dest='no_cov_on_fail', help='do not report coverage if test run fails, ' 'default: False') + group.addoption('--cov-min', action='store', metavar='MIN', type='int', + help='Fail if the total coverage is less than MIN.') + @pytest.mark.tryfirst @@ -135,7 +142,11 @@ def pytest_terminal_summary(self, terminalreporter): if self.cov_controller is None: return if not (self.failed and self.options.no_cov_on_fail): - self.cov_controller.summary(terminalreporter._tw) + total = self.cov_controller.summary(terminalreporter._tw) + if total < self.options.cov_min: + raise CoverageError(('Required test coverage of %d%% not ' + 'reached. Total coverage: %.2f%%') + % (self.options.cov_min, total)) def pytest_runtest_setup(self, item): if os.getpid() != self.pid: From 241b72b6e3eedd9f01a889b734dc3e83655c8489 Mon Sep 17 00:00:00 2001 From: schlamar Date: Mon, 24 Nov 2014 21:02:12 +0100 Subject: [PATCH 066/134] update gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 47e23b11..0fbfbd25 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .tox/ *.egg-info/ .coverage +.coverage.* *.pyc \ No newline at end of file From af39229cc630793d5c84732d504c7e03f117fbdc Mon Sep 17 00:00:00 2001 From: Rick van Hattem Date: Mon, 24 Nov 2014 21:03:36 +0100 Subject: [PATCH 067/134] fixed merge flake8 errors --- cov-core/cov_core.py | 1 + pytest-cov/pytest_cov.py | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/cov-core/cov_core.py b/cov-core/cov_core.py index 2b895245..d375f783 100644 --- a/cov-core/cov_core.py +++ b/cov-core/cov_core.py @@ -144,6 +144,7 @@ def finish(self): node_desc = self.get_node_desc(sys.platform, sys.version_info) self.node_descs.add(node_desc) + class DistMaster(CovController): """Implementation for distributed master.""" diff --git a/pytest-cov/pytest_cov.py b/pytest-cov/pytest_cov.py index c27aca9e..2a42e05f 100644 --- a/pytest-cov/pytest_cov.py +++ b/pytest-cov/pytest_cov.py @@ -38,7 +38,6 @@ def pytest_addoption(parser): help='Fail if the total coverage is less than MIN.') - @pytest.mark.tryfirst def pytest_load_initial_conftests(early_config, parser, args): ns = parser.parse_known_args(args) From beef5f0a80bddc56588f0a45fa6a9c2821e2f3d4 Mon Sep 17 00:00:00 2001 From: schlamar Date: Mon, 24 Nov 2014 21:02:51 +0100 Subject: [PATCH 068/134] make --cov a flag per default --- pytest-cov/pytest_cov.py | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/pytest-cov/pytest_cov.py b/pytest-cov/pytest_cov.py index 2bbe9245..d9b917b8 100644 --- a/pytest-cov/pytest_cov.py +++ b/pytest-cov/pytest_cov.py @@ -11,10 +11,14 @@ def pytest_addoption(parser): """Add options to control coverage.""" - group = parser.getgroup('coverage reporting with distributed testing ' - 'support') - group.addoption('--cov', action='append', default=[], metavar='path', - dest='cov_source', + group = parser.getgroup( + 'cov', 'coverage reporting with distributed testing support') + + group.addoption('--cov', action='append', nargs='?', dest='cov', + const=True, default=[], + help='Enable coverage plugin.') + group.addoption('--cov-source', action='append', default=[], + metavar='path', dest='cov_source', help='measure coverage for filesystem path ' '(multi-allowed)') group.addoption('--cov-report', action='append', default=[], @@ -35,14 +39,23 @@ def pytest_addoption(parser): @pytest.mark.tryfirst def pytest_load_initial_conftests(early_config, parser, args): ns = parser.parse_known_args(args) - if ns.cov_source: + if ns.cov and ns.cov != [True]: + print ('Deprecation warning: --cov shouldn\'t be used ' + 'with additional source arguments anymore. Use ' + '--cov-source instead.') + ns.cov_source.extend(ns.cov) + + if not ns.cov_source: + ns.cov_source = None + + if ns.cov: plugin = CovPlugin(ns, early_config.pluginmanager) early_config.pluginmanager.register(plugin, '_cov') def pytest_configure(config): """Activate coverage plugin if appropriate.""" - if config.getvalue('cov_source'): + if config.getvalue('cov'): if not config.pluginmanager.hasplugin('_cov'): plugin = CovPlugin(config.option, config.pluginmanager, start=False) From af3cb290060671d4a2baeb721d1cec63d1ed40bc Mon Sep 17 00:00:00 2001 From: schlamar Date: Mon, 24 Nov 2014 21:14:13 +0100 Subject: [PATCH 069/134] update example project with new cmd API --- example-tox-project/.coveragerc | 2 ++ example-tox-project/tox.ini | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 example-tox-project/.coveragerc diff --git a/example-tox-project/.coveragerc b/example-tox-project/.coveragerc new file mode 100644 index 00000000..76f1eb15 --- /dev/null +++ b/example-tox-project/.coveragerc @@ -0,0 +1,2 @@ +[run] +source = mylib \ No newline at end of file diff --git a/example-tox-project/tox.ini b/example-tox-project/tox.ini index 9bd8fe39..88f66529 100644 --- a/example-tox-project/tox.ini +++ b/example-tox-project/tox.ini @@ -6,7 +6,7 @@ envlist = cov-init,py27,py34,cov-report usedevelop=True setenv = COVERAGE_FILE = .coverage.{envname} -commands = py.test --cov mylib --cov-report= {posargs} +commands = py.test --cov --cov-report= {posargs} deps = ../cov-core pytest From 2603073f2f5698ba0b6dbb34201b0cf3fb250672 Mon Sep 17 00:00:00 2001 From: schlamar Date: Mon, 24 Nov 2014 21:18:05 +0100 Subject: [PATCH 070/134] update tests with new cmd API --- pytest-cov/test_pytest_cov.py | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/pytest-cov/test_pytest_cov.py b/pytest-cov/test_pytest_cov.py index 88e3d927..eca454b7 100644 --- a/pytest-cov/test_pytest_cov.py +++ b/pytest-cov/test_pytest_cov.py @@ -96,7 +96,7 @@ def test_central(testdir): script = testdir.makepyfile(SCRIPT) result = testdir.runpytest('-v', - '--cov=%s' % script.dirpath(), + '--cov', '--cov-source=%s' % script.dirpath(), '--cov-report=term-missing', script) @@ -112,7 +112,7 @@ def test_no_cov_on_fail(testdir): script = testdir.makepyfile(SCRIPT_FAIL) result = testdir.runpytest('-v', - '--cov=%s' % script.dirpath(), + '--cov', '--cov-source=%s' % script.dirpath(), '--cov-report=term-missing', '--no-cov-on-fail', script) @@ -125,7 +125,7 @@ def test_dist_collocated(testdir): script = testdir.makepyfile(SCRIPT) result = testdir.runpytest('-v', - '--cov=%s' % script.dirpath(), + '--cov', '--cov-source=%s' % script.dirpath(), '--cov-report=term-missing', '--dist=load', '--tx=2*popen', @@ -145,7 +145,7 @@ def test_dist_not_collocated(testdir): dir2 = testdir.mkdir('dir2') result = testdir.runpytest('-v', - '--cov=%s' % script.dirpath(), + '--cov', '--cov-source=%s' % script.dirpath(), '--cov-report=term-missing', '--dist=load', '--tx=popen//chdir=%s' % dir1, @@ -167,7 +167,7 @@ def test_central_subprocess(testdir): parent_script = scripts.dirpath().join('parent_script.py') result = testdir.runpytest('-v', - '--cov=%s' % scripts.dirpath(), + '--cov', '--cov-source=%s' % scripts.dirpath(), '--cov-report=term-missing', parent_script) @@ -185,7 +185,7 @@ def test_dist_subprocess_collocated(testdir): parent_script = scripts.dirpath().join('parent_script.py') result = testdir.runpytest('-v', - '--cov=%s' % scripts.dirpath(), + '--cov', '--cov-source=%s' % scripts.dirpath(), '--cov-report=term-missing', '--dist=load', '--tx=2*popen', @@ -209,7 +209,7 @@ def test_dist_subprocess_not_collocated(testdir, tmpdir): dir2 = tmpdir.mkdir('dir2') result = testdir.runpytest('-v', - '--cov=%s' % scripts.dirpath(), + '--cov', '--cov-source=%s' % scripts.dirpath(), '--cov-report=term-missing', '--dist=load', '--tx=popen//chdir=%s' % dir1, @@ -230,7 +230,7 @@ def test_empty_report(testdir): script = testdir.makepyfile(SCRIPT) result = testdir.runpytest('-v', - '--cov=non_existent_module', + '--cov', '--cov-source=non_existent_module', '--cov-report=term-missing', script) @@ -253,7 +253,7 @@ def test_dist_missing_data(testdir): script = testdir.makepyfile(SCRIPT) result = testdir.runpytest('-v', - '--cov=%s' % script.dirpath(), + '--cov', '--cov-source=%s' % script.dirpath(), '--cov-report=term-missing', '--dist=load', '--tx=popen//python=%s' % exe, @@ -269,7 +269,7 @@ def test_funcarg(testdir): script = testdir.makepyfile(SCRIPT_FUNCARG) result = testdir.runpytest('-v', - '--cov=%s' % script.dirpath(), + '--cov', '--cov-source=%s' % script.dirpath(), '--cov-report=term-missing', script) @@ -299,7 +299,7 @@ def test_multiprocessing_subprocess(testdir): script = testdir.makepyfile(MULTIPROCESSING_SCRIPT) result = testdir.runpytest('-v', - '--cov=%s' % script.dirpath(), + '--cov', '--cov-source=%s' % script.dirpath(), '--cov-report=term-missing', script) @@ -340,7 +340,7 @@ def test_cover_conftest(testdir): testdir.makeconftest(CONFTEST) script = testdir.makepyfile(BASIC_TEST) result = testdir.runpytest('-v', - '--cov=%s' % script.dirpath(), + '--cov', '--cov-source=%s' % script.dirpath(), '--cov-report=term-missing', script) assert result.ret == 0 @@ -352,7 +352,7 @@ def test_cover_conftest_dist(testdir): testdir.makeconftest(CONFTEST) script = testdir.makepyfile(BASIC_TEST) result = testdir.runpytest('-v', - '--cov=%s' % script.dirpath(), + '--cov', '--cov-source=%s' % script.dirpath(), '--cov-report=term-missing', '--dist=load', '--tx=2*popen', @@ -388,7 +388,7 @@ def test_coveragerc(testdir): script = testdir.makepyfile(EXCLUDED_TEST) result = testdir.runpytest('-v', '--cov-config=coveragerc', - '--cov=%s' % script.dirpath(), + '--cov', '--cov-source=%s' % script.dirpath(), '--cov-report=term-missing', script) assert result.ret == 0 @@ -400,7 +400,7 @@ def test_coveragerc_dist(testdir): script = testdir.makepyfile(EXCLUDED_TEST) result = testdir.runpytest('-v', '--cov-config=coveragerc', - '--cov=%s' % script.dirpath(), + '--cov', '--cov-source=%s' % script.dirpath(), '--cov-report=term-missing', '-n', '2', script) @@ -422,7 +422,7 @@ def test_basic(): def test_clear_environ(testdir): script = testdir.makepyfile(CLEAR_ENVIRON_TEST) result = testdir.runpytest('-v', - '--cov=%s' % script.dirpath(), + '--cov', '--cov-source=%s' % script.dirpath(), '--cov-report=term-missing', script) assert result.ret == 0 @@ -445,7 +445,7 @@ def test_dist_boxed(testdir): script = testdir.makepyfile(SCRIPT_SIMPLE) result = testdir.runpytest('-v', - '--cov=%s' % script.dirpath(), + '--cov', '--cov-source=%s' % script.dirpath(), '--boxed', script) From 0afa8ab27024e7213aeda5d0aa74080e900983a5 Mon Sep 17 00:00:00 2001 From: schlamar Date: Mon, 24 Nov 2014 21:21:44 +0100 Subject: [PATCH 071/134] add tests from @bukzor --- pytest-cov/test_pytest_cov.py | 46 +++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/pytest-cov/test_pytest_cov.py b/pytest-cov/test_pytest_cov.py index eca454b7..cf819493 100644 --- a/pytest-cov/test_pytest_cov.py +++ b/pytest-cov/test_pytest_cov.py @@ -25,6 +25,11 @@ def test_foo(): assert False ''' +COVERAGERC_SOURCE = '''\ +[run] +source = . +''' + SCRIPT_CHILD = ''' import sys @@ -108,6 +113,47 @@ def test_central(testdir): assert result.ret == 0 +def test_central_nonspecific(testdir): + script = testdir.makepyfile(SCRIPT) + + result = testdir.runpytest('-v', + '--cov', + '--cov-report=term-missing', + script) + + result.stdout.fnmatch_lines([ + '*- coverage: platform *, python * -*', + 'test_central_nonspecific * %s *' % SCRIPT_RESULT, + '*10 passed*' + ]) + + # multi-module coverage report + assert result.stdout.lines[-3].startswith('TOTAL ') + + assert result.ret == 0 + + +def test_central_coveragerc(testdir): + script = testdir.makepyfile(SCRIPT) + testdir.tmpdir.join('.coveragerc').write(COVERAGERC_SOURCE) + + result = testdir.runpytest('-v', + '--cov', + '--cov-report=term-missing', + script) + + result.stdout.fnmatch_lines([ + '*- coverage: platform *, python * -*', + 'test_central_coveragerc * %s *' % SCRIPT_RESULT, + '*10 passed*', + ]) + + # single-module coverage report + assert result.stdout.lines[-3].startswith('test_central_coveragerc ') + + assert result.ret == 0 + + def test_no_cov_on_fail(testdir): script = testdir.makepyfile(SCRIPT_FAIL) From 313d5b98b64d5310a30a03e0bc4c5812572834de Mon Sep 17 00:00:00 2001 From: schlamar Date: Mon, 24 Nov 2014 21:30:34 +0100 Subject: [PATCH 072/134] test deprecation warning --- pytest-cov/test_pytest_cov.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/pytest-cov/test_pytest_cov.py b/pytest-cov/test_pytest_cov.py index cf819493..6da07dd9 100644 --- a/pytest-cov/test_pytest_cov.py +++ b/pytest-cov/test_pytest_cov.py @@ -507,3 +507,16 @@ def test_not_started_plugin_does_not_fail(testdir): plugin = pytest_cov.CovPlugin(None, None, start=False) plugin.pytest_sessionfinish(None, None) plugin.pytest_terminal_summary(None) + + +def test_deprecation_warning(testdir): + script = testdir.makepyfile(SCRIPT) + + result = testdir.runpytest('-v', + '--cov=%s' % script.dirpath(), + script) + + result.stdout.fnmatch_lines([ + 'Deprecation warning: * --cov-source instead*' + ]) + assert result.ret == 0 From 50a6672ba96ef82b41ce0916e68fd61fc48feb64 Mon Sep 17 00:00:00 2001 From: Rick van Hattem Date: Mon, 24 Nov 2014 22:51:54 +0100 Subject: [PATCH 073/134] added python 3 support --- pytest-cov/pytest_cov.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pytest-cov/pytest_cov.py b/pytest-cov/pytest_cov.py index a179eb0f..d13fac57 100644 --- a/pytest-cov/pytest_cov.py +++ b/pytest-cov/pytest_cov.py @@ -155,7 +155,8 @@ def pytest_terminal_summary(self, terminalreporter): return if not (self.failed and self.options.no_cov_on_fail): total = self.cov_controller.summary(terminalreporter.writer) - if total < self.options.cov_min: + cov_min = self.options.cov_min + if cov_min is not None and total < cov_min: raise CoverageError(('Required test coverage of %d%% not ' 'reached. Total coverage: %.2f%%') % (self.options.cov_min, total)) From c967ef2927c02461d66ca5bddf93debff3a4777b Mon Sep 17 00:00:00 2001 From: Rick van Hattem Date: Mon, 24 Nov 2014 22:52:00 +0100 Subject: [PATCH 074/134] added tests --- pytest-cov/test_pytest_cov.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/pytest-cov/test_pytest_cov.py b/pytest-cov/test_pytest_cov.py index 6da07dd9..10857c47 100644 --- a/pytest-cov/test_pytest_cov.py +++ b/pytest-cov/test_pytest_cov.py @@ -113,6 +113,30 @@ def test_central(testdir): assert result.ret == 0 +def test_central_cov_min_100(testdir): + script = testdir.makepyfile(SCRIPT) + + result = testdir.runpytest('-v', + '--cov', '--cov-source=%s' % script.dirpath(), + '--cov-report=term-missing', + '--cov-min=100', + script) + + assert result.ret == 1 + + +def test_central_cov_min_50(testdir): + script = testdir.makepyfile(SCRIPT) + + result = testdir.runpytest('-v', + '--cov', '--cov-source=%s' % script.dirpath(), + '--cov-report=term-missing', + '--cov-min=50', + script) + + assert result.ret == 0 + + def test_central_nonspecific(testdir): script = testdir.makepyfile(SCRIPT) From f978add780bbb0583fdb2b7f879191f8d29e235a Mon Sep 17 00:00:00 2001 From: Rick van Hattem Date: Mon, 24 Nov 2014 22:57:43 +0100 Subject: [PATCH 075/134] added test for no-report --- pytest-cov/test_pytest_cov.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/pytest-cov/test_pytest_cov.py b/pytest-cov/test_pytest_cov.py index 10857c47..a6c2ee76 100644 --- a/pytest-cov/test_pytest_cov.py +++ b/pytest-cov/test_pytest_cov.py @@ -137,6 +137,17 @@ def test_central_cov_min_50(testdir): assert result.ret == 0 +def test_central_cov_min_no_report(testdir): + script = testdir.makepyfile(SCRIPT) + + result = testdir.runpytest('-v', + '--cov', '--cov-source=%s' % script.dirpath(), + '--cov-min=50', + script) + + assert result.ret == 0 + + def test_central_nonspecific(testdir): script = testdir.makepyfile(SCRIPT) From f24ec87a84cf13334ff91cfc25bb5ebdfb8fc2f8 Mon Sep 17 00:00:00 2001 From: Rick van Hattem Date: Mon, 24 Nov 2014 22:58:52 +0100 Subject: [PATCH 076/134] renamed tests for clarity --- pytest-cov/test_pytest_cov.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pytest-cov/test_pytest_cov.py b/pytest-cov/test_pytest_cov.py index a6c2ee76..36aae5a6 100644 --- a/pytest-cov/test_pytest_cov.py +++ b/pytest-cov/test_pytest_cov.py @@ -113,7 +113,7 @@ def test_central(testdir): assert result.ret == 0 -def test_central_cov_min_100(testdir): +def test_cov_min_100(testdir): script = testdir.makepyfile(SCRIPT) result = testdir.runpytest('-v', @@ -125,7 +125,7 @@ def test_central_cov_min_100(testdir): assert result.ret == 1 -def test_central_cov_min_50(testdir): +def test_cov_min_50(testdir): script = testdir.makepyfile(SCRIPT) result = testdir.runpytest('-v', @@ -137,7 +137,7 @@ def test_central_cov_min_50(testdir): assert result.ret == 0 -def test_central_cov_min_no_report(testdir): +def test_cov_min_no_report(testdir): script = testdir.makepyfile(SCRIPT) result = testdir.runpytest('-v', From f80178d8e72e28c12cf968355129d8ea8bbc7ed2 Mon Sep 17 00:00:00 2001 From: Rick van Hattem Date: Tue, 25 Nov 2014 10:45:23 +0100 Subject: [PATCH 077/134] added tests for --cov-report="" --- cov-core/cov_core.py | 8 +++++--- pytest-cov/pytest_cov.py | 1 + pytest-cov/test_pytest_cov.py | 1 + 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/cov-core/cov_core.py b/cov-core/cov_core.py index d375f783..dd5a2b57 100644 --- a/cov-core/cov_core.py +++ b/cov-core/cov_core.py @@ -78,11 +78,13 @@ def sep(stream, s, txt): def summary(self, stream): """Produce coverage reports.""" - if self.cov_report == ['']: - return - total = 0 + if self.cov_report == ['']: + with open(os.devnull, 'w') as null: + total = self.cov.report(show_missing=True, ignore_errors=True, file=null) + return total + # Output coverage section header. if len(self.node_descs) == 1: self.sep(stream, '-', 'coverage: %s' % ''.join(self.node_descs)) diff --git a/pytest-cov/pytest_cov.py b/pytest-cov/pytest_cov.py index d13fac57..edfe73b2 100644 --- a/pytest-cov/pytest_cov.py +++ b/pytest-cov/pytest_cov.py @@ -155,6 +155,7 @@ def pytest_terminal_summary(self, terminalreporter): return if not (self.failed and self.options.no_cov_on_fail): total = self.cov_controller.summary(terminalreporter.writer) + assert total is not None, 'Test coverage should never be `None`' cov_min = self.options.cov_min if cov_min is not None and total < cov_min: raise CoverageError(('Required test coverage of %d%% not ' diff --git a/pytest-cov/test_pytest_cov.py b/pytest-cov/test_pytest_cov.py index 36aae5a6..5dacc1c2 100644 --- a/pytest-cov/test_pytest_cov.py +++ b/pytest-cov/test_pytest_cov.py @@ -142,6 +142,7 @@ def test_cov_min_no_report(testdir): result = testdir.runpytest('-v', '--cov', '--cov-source=%s' % script.dirpath(), + '--cov-report=', '--cov-min=50', script) From a123ac16e837071625729691ae72a1440ef9fb4e Mon Sep 17 00:00:00 2001 From: schlamar Date: Tue, 25 Nov 2014 17:05:46 +0100 Subject: [PATCH 078/134] improved internal handling of --cov_report --- cov-core/cov_core.py | 2 +- pytest-cov/pytest_cov.py | 7 ++++++- pytest-cov/test_pytest_cov.py | 25 +++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/cov-core/cov_core.py b/cov-core/cov_core.py index dd5a2b57..5a725f13 100644 --- a/cov-core/cov_core.py +++ b/cov-core/cov_core.py @@ -80,7 +80,7 @@ def summary(self, stream): """Produce coverage reports.""" total = 0 - if self.cov_report == ['']: + if not self.cov_report: with open(os.devnull, 'w') as null: total = self.cov.report(show_missing=True, ignore_errors=True, file=null) return total diff --git a/pytest-cov/pytest_cov.py b/pytest-cov/pytest_cov.py index edfe73b2..0ac9dd81 100644 --- a/pytest-cov/pytest_cov.py +++ b/pytest-cov/pytest_cov.py @@ -54,6 +54,11 @@ def pytest_load_initial_conftests(early_config, parser, args): if not ns.cov_source: ns.cov_source = None + if not ns.cov_report: + ns.cov_report = ['term'] + elif ns.cov_report == ['']: + ns.cov_report = [] + if ns.cov: plugin = CovPlugin(ns, early_config.pluginmanager) early_config.pluginmanager.register(plugin, '_cov') @@ -111,7 +116,7 @@ class Config(object): self.cov_controller = controller_cls( self.options.cov_source, - self.options.cov_report or ['term'], + self.options.cov_report, self.options.cov_config, config, nodeid diff --git a/pytest-cov/test_pytest_cov.py b/pytest-cov/test_pytest_cov.py index 5dacc1c2..d49bc59c 100644 --- a/pytest-cov/test_pytest_cov.py +++ b/pytest-cov/test_pytest_cov.py @@ -556,3 +556,28 @@ def test_deprecation_warning(testdir): 'Deprecation warning: * --cov-source instead*' ]) assert result.ret == 0 + + +def test_default_output_setting(testdir): + script = testdir.makepyfile(SCRIPT) + + result = testdir.runpytest('-v', + '--cov', '--cov-source=%s' % script.dirpath(), + script) + + result.stdout.fnmatch_lines([ + '*coverage*' + ]) + assert result.ret == 0 + + +def test_disabled_output(testdir): + script = testdir.makepyfile(SCRIPT) + + result = testdir.runpytest('-v', + '--cov', '--cov-source=%s' % script.dirpath(), + '--cov-report=', + script) + + assert 'coverage' not in result.stdout.str() + assert result.ret == 0 From 82ee928f77b8c3029271c62ae12c6feb0830973e Mon Sep 17 00:00:00 2001 From: schlamar Date: Tue, 25 Nov 2014 17:51:18 +0100 Subject: [PATCH 079/134] Delete CONTRIBUTING.md --- CONTRIBUTING.md | 1 - 1 file changed, 1 deletion(-) delete mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index e94ef66b..00000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1 +0,0 @@ -All new features should go into [2.0 branch](https://github.com/schlamar/pytest-cov/tree/2.0). Thanks! :cake: From 6e542ccc4d594a28f77927142ae2354b49e98031 Mon Sep 17 00:00:00 2001 From: Josh Kalderimis Date: Tue, 25 Nov 2014 18:10:48 +0100 Subject: [PATCH 080/134] Use the new build env on Travis more ram and cpu, improved network and boot times http://docs.travis-ci.com/user/workers/container-based-infrastructure/ more docs coming soon --- .travis.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.travis.yml b/.travis.yml index daabdf11..ca31b4c1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,7 @@ language: python + python: 2.7 + env: - TOX_ENV=flake8 - TOX_ENV=pypy @@ -9,10 +11,15 @@ env: - TOX_ENV=py32 - TOX_ENV=py33 - TOX_ENV=py34 + +sudo: false + install: - pip install tox + script: - tox -e $TOX_ENV + notifications: email: on_success: never From f609c0609158db16b5acbdbeb7c5701bdc58fa18 Mon Sep 17 00:00:00 2001 From: schlamar Date: Wed, 10 Dec 2014 21:44:58 +0100 Subject: [PATCH 081/134] add test for setting COVERAGE_FILE --- pytest-cov/test_pytest_cov.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/pytest-cov/test_pytest_cov.py b/pytest-cov/test_pytest_cov.py index d49bc59c..b2a3ee3d 100644 --- a/pytest-cov/test_pytest_cov.py +++ b/pytest-cov/test_pytest_cov.py @@ -581,3 +581,18 @@ def test_disabled_output(testdir): assert 'coverage' not in result.stdout.str() assert result.ret == 0 + + +def test_coverage_file(testdir): + script = testdir.makepyfile(SCRIPT) + data_file_name = 'covdata' + os.environ['COVERAGE_FILE'] = data_file_name + try: + result = testdir.runpytest('-v', '--cov', + '--cov-source=%s' % script.dirpath(), + script) + assert result.ret == 0 + data_file = testdir.tmpdir.join(data_file_name) + assert data_file.check() + finally: + os.environ.pop('COVERAGE_FILE') From ee119a062af6cc3171bc7bc5c441f24137838fc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Tue, 23 Dec 2014 11:20:55 +0200 Subject: [PATCH 082/134] Allow import to fail. This is not a good place to raise exceptions. (eg: coverage package is not installed). --- cov-core/setup.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/cov-core/setup.py b/cov-core/setup.py index 0989863e..bd6853f0 100644 --- a/cov-core/setup.py +++ b/cov-core/setup.py @@ -10,7 +10,14 @@ # 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() +import os; exec(%r) +''' % ''' +if 'COV_CORE_SOURCE' in os.environ: + try: + import cov_core_init + cov_core_init.init() + except ImportError: + pass ''' PTH_FILE_FAILURE = ''' From 0525a0759dee9a837276294b9bf809cda0e3d761 Mon Sep 17 00:00:00 2001 From: Eric Larson Date: Tue, 6 Jan 2015 09:25:34 -0800 Subject: [PATCH 083/134] ENH: Update README.rst --- pytest-cov/README.rst | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/pytest-cov/README.rst b/pytest-cov/README.rst index 7a81bde0..11aa749b 100644 --- a/pytest-cov/README.rst +++ b/pytest-cov/README.rst @@ -190,14 +190,20 @@ The terminal report with line numbers:: TOTAL 353 20 94% -The remaining three reports output to files without showing anything on the terminal (useful for -when the output is going to a continuous integration server):: +These three report options output to files without showing anything on the terminal:: py.test --cov-report html --cov-report xml --cov-report annotate --cov myproj tests/ +The final report option can also suppress printing to the terminal:: + + py.test --cov-report= tests/ + +This mode can be especially useful on continuous integration servers, where a coverage file +coverage file is needed for subsequent processing, but no local report needs to be viewed. +For example, test run on Travis-CI could produce a .coverage file for use with Coveralls. Coverage Data File ------------------ From 9316835a05938de9cb639a4bc52f676a4bc4c77c Mon Sep 17 00:00:00 2001 From: Eric89GXL Date: Wed, 7 Jan 2015 09:44:57 -0800 Subject: [PATCH 084/134] FIX: Update to cov-source --- pytest-cov/README.rst | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/pytest-cov/README.rst b/pytest-cov/README.rst index 11aa749b..9100bb8f 100644 --- a/pytest-cov/README.rst +++ b/pytest-cov/README.rst @@ -68,7 +68,7 @@ subprocesses. Running centralised testing:: - py.test --cov myproj tests/ + py.test --cov-source myproj tests/ Shows a terminal report:: @@ -91,7 +91,7 @@ file system. Each slave will have it's subprocesses measured. Running distributed testing with dist mode set to load:: - py.test --cov myproj -n 2 tests/ + py.test --cov-source myproj -n 2 tests/ Shows a terminal report:: @@ -107,7 +107,7 @@ Shows a terminal report:: Again but spread over different hosts and different directories:: - py.test --cov myproj --dist load + py.test --cov-source myproj --dist load --tx ssh=memedough@host1//chdir=testenv1 --tx ssh=memedough@host2//chdir=/tmp/testenv2//python=/tmp/env1/bin/python --rsyncdir myproj --rsyncdir tests --rsync examples @@ -134,7 +134,7 @@ environments. Running distributed testing with dist mode set to each:: - py.test --cov myproj --dist each + py.test --cov-source myproj --dist each --tx popen//chdir=/tmp/testenv3//python=/usr/local/python27/bin/python --tx ssh=memedough@host2//chdir=/tmp/testenv4//python=/tmp/env2/bin/python --rsyncdir myproj --rsyncdir tests --rsync examples @@ -164,7 +164,7 @@ annotated source code. The terminal report without line numbers (default):: - py.test --cov-report term --cov myproj tests/ + py.test --cov-report term --cov-source myproj tests/ -------------------- coverage: platform linux2, python 2.6.4-final-0 --------------------- Name Stmts Miss Cover @@ -178,7 +178,7 @@ The terminal report without line numbers (default):: The terminal report with line numbers:: - py.test --cov-report term-missing --cov myproj tests/ + py.test --cov-report term-missing --cov-source myproj tests/ -------------------- coverage: platform linux2, python 2.6.4-final-0 --------------------- Name Stmts Miss Cover Missing @@ -195,15 +195,15 @@ These three report options output to files without showing anything on the termi py.test --cov-report html --cov-report xml --cov-report annotate - --cov myproj tests/ + --cov-source myproj tests/ The final report option can also suppress printing to the terminal:: - py.test --cov-report= tests/ + py.test --cov-report= --cov-source myproj tests/ This mode can be especially useful on continuous integration servers, where a coverage file -coverage file is needed for subsequent processing, but no local report needs to be viewed. -For example, test run on Travis-CI could produce a .coverage file for use with Coveralls. +is needed for subsequent processing, but no local report needs to be viewed. For example, +tests run on Travis-CI could produce a .coverage file for use with Coveralls. Coverage Data File ------------------ @@ -224,7 +224,7 @@ For example if tests are contained within the directory tree being measured the excluded if desired by using a .coveragerc file with the omit option set:: py.test --cov-config .coveragerc - --cov myproj + --cov-source myproj myproj/tests/ Where the .coveragerc file contains file globs:: From de6f8e453b469432acac684f4aeb8fe0ad1737ed Mon Sep 17 00:00:00 2001 From: Marc Schlaich Date: Fri, 27 Mar 2015 08:42:13 +0100 Subject: [PATCH 085/134] pin test dependencies to working versions --- pytest-cov/tox.ini | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pytest-cov/tox.ini b/pytest-cov/tox.ini index a3fb768e..830ea8d0 100644 --- a/pytest-cov/tox.ini +++ b/pytest-cov/tox.ini @@ -7,7 +7,8 @@ setenv = PYTHONHASHSEED = random deps = {env:COV_CORE_DEP:../cov-core} - pytest + execnet>=1.2.0,<1.3.0 + pytest>=2.6.4,<2.7.0 pytest-xdist virtualenv commands = py.test -v test_pytest_cov.py {posargs} From 5a06154586c372c0770805e0a1e6bfcb41eb2506 Mon Sep 17 00:00:00 2001 From: Ali-Akber Saifee Date: Fri, 27 Mar 2015 12:51:50 +0800 Subject: [PATCH 086/134] Remove MP Finalize if cov didnt initialize. There may be cases where cov_core_init.init() returns None. Currently, multiprocessing_finish raises an AttributeError. --- cov-core/cov_core.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cov-core/cov_core.py b/cov-core/cov_core.py index 5a725f13..b948178a 100644 --- a/cov-core/cov_core.py +++ b/cov-core/cov_core.py @@ -10,9 +10,10 @@ def multiprocessing_start(obj): cov = cov_core_init.init() - import multiprocessing.util - multiprocessing.util.Finalize( - None, multiprocessing_finish, args=(cov,), exitpriority=1000) + if cov: + import multiprocessing.util + multiprocessing.util.Finalize( + None, multiprocessing_finish, args=(cov,), exitpriority=1000) def multiprocessing_finish(cov): From a793976e84f070b8ce06a038ae69e925f0086962 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Fri, 5 Jun 2015 20:27:38 +0300 Subject: [PATCH 087/134] Initial relayouting. --- cov-core/.gitignore | 6 ------ cov-core/LICENSE.txt | 21 ------------------- cov-core/MANIFEST.in | 5 ----- cov-core/README.rst | 5 ----- setup.py | 3 --- src/pytest_cover/__init__.py | 1 + .../pytest_cover/embed.py | 0 .../cov_core.py => src/pytest_cover/engine.py | 0 .../pytest_cover/plugin.py | 0 9 files changed, 1 insertion(+), 40 deletions(-) delete mode 100644 cov-core/.gitignore delete mode 100644 cov-core/LICENSE.txt delete mode 100644 cov-core/MANIFEST.in delete mode 100644 cov-core/README.rst delete mode 100644 setup.py create mode 100644 src/pytest_cover/__init__.py rename cov-core/cov_core_init.py => src/pytest_cover/embed.py (100%) rename cov-core/cov_core.py => src/pytest_cover/engine.py (100%) rename pytest-cov/pytest_cov.py => src/pytest_cover/plugin.py (100%) diff --git a/cov-core/.gitignore b/cov-core/.gitignore deleted file mode 100644 index 46a6d937..00000000 --- a/cov-core/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -*.pyo -*.pyc -*egg-info -build -dist -env* diff --git a/cov-core/LICENSE.txt b/cov-core/LICENSE.txt deleted file mode 100644 index 5b3634b4..00000000 --- a/cov-core/LICENSE.txt +++ /dev/null @@ -1,21 +0,0 @@ -The 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. diff --git a/cov-core/MANIFEST.in b/cov-core/MANIFEST.in deleted file mode 100644 index 9ad66a9b..00000000 --- a/cov-core/MANIFEST.in +++ /dev/null @@ -1,5 +0,0 @@ -include README.rst -include LICENSE.txt -include setup.py -include cov_core.py -include cov_core_init.py diff --git a/cov-core/README.rst b/cov-core/README.rst deleted file mode 100644 index 1a41daf2..00000000 --- a/cov-core/README.rst +++ /dev/null @@ -1,5 +0,0 @@ -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. diff --git a/setup.py b/setup.py deleted file mode 100644 index 60684932..00000000 --- a/setup.py +++ /dev/null @@ -1,3 +0,0 @@ -from setuptools import setup - -setup() diff --git a/src/pytest_cover/__init__.py b/src/pytest_cover/__init__.py new file mode 100644 index 00000000..3dc1f76b --- /dev/null +++ b/src/pytest_cover/__init__.py @@ -0,0 +1 @@ +__version__ = "0.1.0" diff --git a/cov-core/cov_core_init.py b/src/pytest_cover/embed.py similarity index 100% rename from cov-core/cov_core_init.py rename to src/pytest_cover/embed.py diff --git a/cov-core/cov_core.py b/src/pytest_cover/engine.py similarity index 100% rename from cov-core/cov_core.py rename to src/pytest_cover/engine.py diff --git a/pytest-cov/pytest_cov.py b/src/pytest_cover/plugin.py similarity index 100% rename from pytest-cov/pytest_cov.py rename to src/pytest_cover/plugin.py From 906926dddde6e4286e672cc55f0ea193a10d45eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Fri, 5 Jun 2015 20:27:59 +0300 Subject: [PATCH 088/134] Move this. --- pytest-cov/setup.py => setup.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename pytest-cov/setup.py => setup.py (100%) diff --git a/pytest-cov/setup.py b/setup.py similarity index 100% rename from pytest-cov/setup.py rename to setup.py From ebc6a991a3726820b9bd0a410f84b795842939dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Fri, 5 Jun 2015 20:32:38 +0300 Subject: [PATCH 089/134] More relayouting --- README.rst | 7 ---- {example-tox-project => example}/.coveragerc | 0 .../mylib/__init__.py | 0 {example-tox-project => example}/setup.py | 0 .../tests/test_mylib.py | 0 {example-tox-project => example}/tox.ini | 0 pytest-cov/.gitignore | 8 ----- pytest-cov/LICENSE.txt | 21 ------------ pytest-cov/MANIFEST.in | 5 --- pytest-cov/tox.ini | 14 -------- setup.py | 32 ------------------- .../test_pytest_cover.py | 0 12 files changed, 87 deletions(-) delete mode 100644 README.rst rename {example-tox-project => example}/.coveragerc (100%) rename {example-tox-project => example}/mylib/__init__.py (100%) rename {example-tox-project => example}/setup.py (100%) rename {example-tox-project => example}/tests/test_mylib.py (100%) rename {example-tox-project => example}/tox.ini (100%) delete mode 100644 pytest-cov/.gitignore delete mode 100644 pytest-cov/LICENSE.txt delete mode 100644 pytest-cov/MANIFEST.in delete mode 100644 pytest-cov/tox.ini delete mode 100644 setup.py rename pytest-cov/test_pytest_cov.py => tests/test_pytest_cover.py (100%) diff --git a/README.rst b/README.rst deleted file mode 100644 index 4edbedcb..00000000 --- a/README.rst +++ /dev/null @@ -1,7 +0,0 @@ -py-cov -====== - -Collection of Python coverage projects. - -- pytest-cov -- cov-core diff --git a/example-tox-project/.coveragerc b/example/.coveragerc similarity index 100% rename from example-tox-project/.coveragerc rename to example/.coveragerc diff --git a/example-tox-project/mylib/__init__.py b/example/mylib/__init__.py similarity index 100% rename from example-tox-project/mylib/__init__.py rename to example/mylib/__init__.py diff --git a/example-tox-project/setup.py b/example/setup.py similarity index 100% rename from example-tox-project/setup.py rename to example/setup.py diff --git a/example-tox-project/tests/test_mylib.py b/example/tests/test_mylib.py similarity index 100% rename from example-tox-project/tests/test_mylib.py rename to example/tests/test_mylib.py diff --git a/example-tox-project/tox.ini b/example/tox.ini similarity index 100% rename from example-tox-project/tox.ini rename to example/tox.ini diff --git a/pytest-cov/.gitignore b/pytest-cov/.gitignore deleted file mode 100644 index cbb44d89..00000000 --- a/pytest-cov/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -*.pyo -*.pyc -*egg-info -build -dist -env* -.tox -.coverage* diff --git a/pytest-cov/LICENSE.txt b/pytest-cov/LICENSE.txt deleted file mode 100644 index 5b3634b4..00000000 --- a/pytest-cov/LICENSE.txt +++ /dev/null @@ -1,21 +0,0 @@ -The 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. diff --git a/pytest-cov/MANIFEST.in b/pytest-cov/MANIFEST.in deleted file mode 100644 index 99e6799f..00000000 --- a/pytest-cov/MANIFEST.in +++ /dev/null @@ -1,5 +0,0 @@ -include README.rst -include LICENSE.txt -include setup.py -include pytest_cov.py -include test_pytest_cov.py diff --git a/pytest-cov/tox.ini b/pytest-cov/tox.ini deleted file mode 100644 index 830ea8d0..00000000 --- a/pytest-cov/tox.ini +++ /dev/null @@ -1,14 +0,0 @@ -[tox] -envlist = py26, py27, pypy, pypy3, py32, py33, py34 - -[testenv] -usedevelop = True -setenv = - PYTHONHASHSEED = random -deps = - {env:COV_CORE_DEP:../cov-core} - execnet>=1.2.0,<1.3.0 - pytest>=2.6.4,<2.7.0 - pytest-xdist - virtualenv -commands = py.test -v test_pytest_cov.py {posargs} diff --git a/setup.py b/setup.py deleted file mode 100644 index ec7623a5..00000000 --- a/setup.py +++ /dev/null @@ -1,32 +0,0 @@ -import setuptools - -setuptools.setup(name='pytest-cov', - version='1.8.1', - description='py.test plugin for coverage reporting with ' - 'support for both centralised and distributed testing, ' - 'including subprocesses and multiprocessing', - long_description=open('README.rst').read().strip(), - author='Marc Schlaich', - author_email='marc.schlaich@gmail.com', - url='https://github.com/schlamar/pytest-cov', - py_modules=['pytest_cov'], - install_requires=['py>=1.4.22', - 'pytest>=2.6.0', - 'coverage>=3.7.1', - 'cov-core>=1.14.0'], - entry_points={'pytest11': ['pytest_cov = pytest_cov']}, - license='MIT License', - zip_safe=False, - keywords='py.test pytest cover coverage distributed parallel', - 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']) diff --git a/pytest-cov/test_pytest_cov.py b/tests/test_pytest_cover.py similarity index 100% rename from pytest-cov/test_pytest_cov.py rename to tests/test_pytest_cover.py From ecdf3bfe3618e6d139dc59c1873b7b84660c9562 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Fri, 5 Jun 2015 20:34:28 +0300 Subject: [PATCH 090/134] Complete project structure. --- .coveragerc | 12 +++ .gitignore | 58 +++++++++++++- .travis.yml | 60 ++++++-------- AUTHORS.rst | 5 ++ CHANGELOG.rst | 8 ++ CONTRIBUTING.rst | 89 +++++++++++++++++++++ LICENSE | 19 +++++ MANIFEST.in | 21 +++++ pytest-cov/README.rst => README.rst | 0 appveyor.yml | 96 +++++++++++++++++++++++ ci/appveyor-bootstrap.ps1 | 88 +++++++++++++++++++++ ci/appveyor-with-compiler.cmd | 37 +++++++++ ci/bootstrap.py | 64 +++++++++++++++ ci/templates/.travis.yml | 27 +++++++ ci/templates/appveyor.yml | 39 ++++++++++ ci/templates/tox.ini | 117 ++++++++++++++++++++++++++++ docs/authors.rst | 1 + docs/changelog.rst | 1 + docs/conf.py | 44 +++++++++++ docs/contributing.rst | 1 + docs/index.rst | 23 ++++++ docs/installation.rst | 7 ++ docs/readme.rst | 5 ++ docs/reference/index.rst | 7 ++ docs/reference/pytest_cover.rst | 5 ++ docs/requirements.txt | 4 + docs/spelling_wordlist.txt | 11 +++ docs/usage.rst | 7 ++ setup.cfg | 86 ++++++++++++++++++++ cov-core/setup.py => setup.py | 0 tox.ini | 116 +++++++++++++++++++++++++-- 31 files changed, 1013 insertions(+), 45 deletions(-) create mode 100644 .coveragerc create mode 100644 AUTHORS.rst create mode 100644 CHANGELOG.rst create mode 100644 CONTRIBUTING.rst create mode 100644 LICENSE create mode 100644 MANIFEST.in rename pytest-cov/README.rst => README.rst (100%) create mode 100644 appveyor.yml create mode 100644 ci/appveyor-bootstrap.ps1 create mode 100644 ci/appveyor-with-compiler.cmd create mode 100755 ci/bootstrap.py create mode 100644 ci/templates/.travis.yml create mode 100644 ci/templates/appveyor.yml create mode 100644 ci/templates/tox.ini create mode 100644 docs/authors.rst create mode 100644 docs/changelog.rst create mode 100644 docs/conf.py create mode 100644 docs/contributing.rst create mode 100644 docs/index.rst create mode 100644 docs/installation.rst create mode 100644 docs/readme.rst create mode 100644 docs/reference/index.rst create mode 100644 docs/reference/pytest_cover.rst create mode 100644 docs/requirements.txt create mode 100644 docs/spelling_wordlist.txt create mode 100644 docs/usage.rst create mode 100644 setup.cfg rename cov-core/setup.py => setup.py (100%) diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 00000000..772866d2 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,12 @@ +[paths] +source = src + +[run] +branch = True +source = src +parallel = true + +[report] +show_missing = true +precision = 2 +omit = *migrations* diff --git a/.gitignore b/.gitignore index 0fbfbd25..88b9214b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,57 @@ -.tox/ -*.egg-info/ +*.py[cod] + +# C extensions +*.so + +# Packages +*.egg +*.egg-info +dist +build +eggs +parts +bin +var +sdist +develop-eggs +.installed.cfg +lib +lib64 +venv*/ +pyvenv*/ + +# Installer logs +pip-log.txt + +# Unit test / coverage reports .coverage +.tox .coverage.* -*.pyc \ No newline at end of file +nosetests.xml +htmlcov + +# Translations +*.mo + +# Mr Developer +.mr.developer.cfg +.project +.pydevproject +.idea +*.iml +*.komodoproject + +# Complexity +output/*.html +output/*/index.html + +# Sphinx +docs/_build + +.DS_Store +*~ +.*.sw[po] +.build +.ve +.bootstrap +*.bak diff --git a/.travis.yml b/.travis.yml index f09d0e10..80caf6f2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,45 +1,33 @@ language: python - python: 2.7 - -env: - - CWD=. TOX_ENV=flake8 - - - CWD=pytest-cov TOX_ENV=pypy COV_CORE_DEP=../cov-core - - CWD=pytest-cov TOX_ENV=pypy3 COV_CORE_DEP=../cov-core - - CWD=pytest-cov TOX_ENV=py26 COV_CORE_DEP=../cov-core - - CWD=pytest-cov TOX_ENV=py27 COV_CORE_DEP=../cov-core - - CWD=pytest-cov TOX_ENV=py32 COV_CORE_DEP=../cov-core - - CWD=pytest-cov TOX_ENV=py33 COV_CORE_DEP=../cov-core - - CWD=pytest-cov TOX_ENV=py34 COV_CORE_DEP=../cov-core - - - CWD=pytest-cov TOX_ENV=pypy COV_CORE_DEP=cov-core - - CWD=pytest-cov TOX_ENV=pypy3 COV_CORE_DEP=cov-core - - CWD=pytest-cov TOX_ENV=py26 COV_CORE_DEP=cov-core - - CWD=pytest-cov TOX_ENV=py27 COV_CORE_DEP=cov-core - - CWD=pytest-cov TOX_ENV=py32 COV_CORE_DEP=cov-core - - CWD=pytest-cov TOX_ENV=py33 COV_CORE_DEP=cov-core - - CWD=pytest-cov TOX_ENV=py34 COV_CORE_DEP=cov-core - -matrix: - allow_failures: - - env: CWD=pytest-cov TOX_ENV=pypy COV_CORE_DEP=cov-core - - env: CWD=pytest-cov TOX_ENV=pypy3 COV_CORE_DEP=cov-core - - env: CWD=pytest-cov TOX_ENV=py26 COV_CORE_DEP=cov-core - - env: CWD=pytest-cov TOX_ENV=py27 COV_CORE_DEP=cov-core - - env: CWD=pytest-cov TOX_ENV=py32 COV_CORE_DEP=cov-core - - env: CWD=pytest-cov TOX_ENV=py33 COV_CORE_DEP=cov-core - - env: CWD=pytest-cov TOX_ENV=py34 COV_CORE_DEP=cov-core - sudo: false - +env: + global: + LD_PRELOAD=/lib/x86_64-linux-gnu/libSegFault.so + matrix: + - TOXENV=check + - TOXENV=2.6,coveralls + - TOXENV=2.6-nocover + - TOXENV=2.7,coveralls + - TOXENV=2.7-nocover + - TOXENV=3.3,coveralls + - TOXENV=3.3-nocover + - TOXENV=3.4,coveralls + - TOXENV=3.4-nocover + - TOXENV=pypy,coveralls + - TOXENV=pypy-nocover +before_install: + - python --version + - virtualenv --version + - pip --version + - uname -a + - lsb_release -a install: - pip install tox - script: - - cd $CWD && tox -e $TOX_ENV - + - tox -v notifications: email: on_success: never - on_failure: change + on_failure: always + diff --git a/AUTHORS.rst b/AUTHORS.rst new file mode 100644 index 00000000..0e54887e --- /dev/null +++ b/AUTHORS.rst @@ -0,0 +1,5 @@ + +Authors +======= + +* Ionel Cristian Mărieș - http://blog.ionelmc.ro diff --git a/CHANGELOG.rst b/CHANGELOG.rst new file mode 100644 index 00000000..e1310db5 --- /dev/null +++ b/CHANGELOG.rst @@ -0,0 +1,8 @@ + +Changelog +========= + +0.1.0 (2015-06-05) +----------------------------------------- + +* First release on PyPI. diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst new file mode 100644 index 00000000..10586f82 --- /dev/null +++ b/CONTRIBUTING.rst @@ -0,0 +1,89 @@ +============ +Contributing +============ + +Contributions are welcome, and they are greatly appreciated! Every +little bit helps, and credit will always be given. + +Bug reports +=========== + +When `reporting a bug `_ please include: + + * Your operating system name and version. + * Any details about your local setup that might be helpful in troubleshooting. + * Detailed steps to reproduce the bug. + +Documentation improvements +========================== + +pytest-cover could always use more documentation, whether as part of the +official pytest-cover docs, in docstrings, or even on the web in blog posts, +articles, and such. + +Feature requests and feedback +============================= + +The best way to send feedback is to file an issue at https://github.com/ionelmc/pytest-cover/issues. + +If you are proposing a feature: + +* Explain in detail how it would work. +* Keep the scope as narrow as possible, to make it easier to implement. +* Remember that this is a volunteer-driven project, and that contributions are welcome :) + +Development +=========== + +To set up `pytest-cover` for local development: + +1. `Fork pytest-cover on GitHub `_. +2. Clone your fork locally:: + + git clone git@github.com:your_name_here/pytest-cover.git + +3. Create a branch for local development:: + + git checkout -b name-of-your-bugfix-or-feature + + Now you can make your changes locally. + +4. When you're done making changes, run all the checks, doc builder and spell checker with `tox `_ one command:: + + tox + +5. Commit your changes and push your branch to GitHub:: + + git add . + git commit -m "Your detailed description of your changes." + git push origin name-of-your-bugfix-or-feature + +6. Submit a pull request through the GitHub website. + +Pull Request Guidelines +----------------------- + +If you need some code review or feedback while you're developing the code just make the pull request. + +For merging, you should: + +1. Include passing tests (run ``tox``) [1]_. +2. Update documentation when there's new API, functionality etc. +3. Add a note to ``CHANGELOG.rst`` about the changes. +4. Add yourself to ``AUTHORS.rst``. + +.. [1] If you don't have all the necessary python versions available locally you can rely on Travis - it will + `run the tests `_ for each change you add in the pull request. + + It will be slower though ... + +Tips +---- + +To run a subset of tests:: + + tox -e envname -- py.test -k test_myfeature + +To run all the test environments in *parallel* (you need to ``pip install detox``):: + + detox \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..768c5f00 --- /dev/null +++ b/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2015, Ionel Cristian Mărieș +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following +disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 00000000..f44be4b5 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,21 @@ +graft docs +graft examples +graft src +graft ci +graft tests + +include *.komodoproject +include .bumpversion.cfg +include .coveragerc +include .isort.cfg +include .pylintrc + +include AUTHORS.rst +include CHANGELOG.rst +include CONTRIBUTING.rst +include LICENSE +include README.rst + +include tox.ini .travis.yml appveyor.yml + +global-exclude *.py[cod] __pycache__ *.so diff --git a/pytest-cov/README.rst b/README.rst similarity index 100% rename from pytest-cov/README.rst rename to README.rst diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 00000000..251e22f8 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,96 @@ +version: '{branch}-{build}' +build: off +environment: + global: + WITH_COMPILER: "cmd /E:ON /V:ON /C .\\ci\\appveyor-with-compiler.cmd" + matrix: + - TOXENV: check + PYTHON_HOME: "C:\\Python27" + PYTHON_VERSION: "2.7" + PYTHON_ARCH: "32" + - TOXENV: "2.7" + TOXPYTHON: "C:\\Python27\\python.exe" + WINDOWS_SDK_VERSION: "v7.0" + PYTHON_HOME: "C:\\Python27" + PYTHON_VERSION: "2.7" + PYTHON_ARCH: "32" + - TOXENV: "2.7" + TOXPYTHON: "C:\\Python27-x64\\python.exe" + WINDOWS_SDK_VERSION: "v7.0" + PYTHON_HOME: "C:\\Python27-x64" + PYTHON_VERSION: "2.7" + PYTHON_ARCH: "64" + - TOXENV: "2.7-nocover" + TOXPYTHON: "C:\\Python27\\python.exe" + WINDOWS_SDK_VERSION: "v7.0" + PYTHON_HOME: "C:\\Python27" + PYTHON_VERSION: "2.7" + PYTHON_ARCH: "32" + - TOXENV: "2.7-nocover" + TOXPYTHON: "C:\\Python27-x64\\python.exe" + WINDOWS_SDK_VERSION: "v7.0" + PYTHON_HOME: "C:\\Python27-x64" + PYTHON_VERSION: "2.7" + PYTHON_ARCH: "64" + - TOXENV: "3.3" + TOXPYTHON: "C:\\Python33\\python.exe" + WINDOWS_SDK_VERSION: "v7.1" + PYTHON_HOME: "C:\\Python33" + PYTHON_VERSION: "3.3" + PYTHON_ARCH: "32" + - TOXENV: "3.3" + TOXPYTHON: "C:\\Python33-x64\\python.exe" + WINDOWS_SDK_VERSION: "v7.1" + PYTHON_HOME: "C:\\Python33-x64" + PYTHON_VERSION: "3.3" + PYTHON_ARCH: "64" + - TOXENV: "3.3-nocover" + TOXPYTHON: "C:\\Python33\\python.exe" + WINDOWS_SDK_VERSION: "v7.1" + PYTHON_HOME: "C:\\Python33" + PYTHON_VERSION: "3.3" + PYTHON_ARCH: "32" + - TOXENV: "3.3-nocover" + TOXPYTHON: "C:\\Python33-x64\\python.exe" + WINDOWS_SDK_VERSION: "v7.1" + PYTHON_HOME: "C:\\Python33-x64" + PYTHON_VERSION: "3.3" + PYTHON_ARCH: "64" + - TOXENV: "3.4" + TOXPYTHON: "C:\\Python34\\python.exe" + WINDOWS_SDK_VERSION: "v7.1" + PYTHON_HOME: "C:\\Python34" + PYTHON_VERSION: "3.4" + PYTHON_ARCH: "32" + - TOXENV: "3.4" + TOXPYTHON: "C:\\Python34-x64\\python.exe" + WINDOWS_SDK_VERSION: "v7.1" + PYTHON_HOME: "C:\\Python34-x64" + PYTHON_VERSION: "3.4" + PYTHON_ARCH: "64" + - TOXENV: "3.4-nocover" + TOXPYTHON: "C:\\Python34\\python.exe" + WINDOWS_SDK_VERSION: "v7.1" + PYTHON_HOME: "C:\\Python34" + PYTHON_VERSION: "3.4" + PYTHON_ARCH: "32" + - TOXENV: "3.4-nocover" + TOXPYTHON: "C:\\Python34-x64\\python.exe" + WINDOWS_SDK_VERSION: "v7.1" + PYTHON_HOME: "C:\\Python34-x64" + PYTHON_VERSION: "3.4" + PYTHON_ARCH: "64" +init: + - "ECHO %TOXENV%" + - ps: "ls C:\\Python*" +install: + - "powershell ci\\appveyor-bootstrap.ps1" +test_script: + - "%PYTHON_HOME%\\Scripts\\tox --version" + - "%PYTHON_HOME%\\Scripts\\virtualenv --version" + - "%PYTHON_HOME%\\Scripts\\pip --version" + - "%WITH_COMPILER% %PYTHON_HOME%\\Scripts\\tox" +after_test: + - "IF \"%TOXENV:~-8,8%\" == \"-nocover\" %WITH_COMPILER% %TOXPYTHON% setup.py bdist_wheel" +artifacts: + - path: dist\* diff --git a/ci/appveyor-bootstrap.ps1 b/ci/appveyor-bootstrap.ps1 new file mode 100644 index 00000000..1dd53420 --- /dev/null +++ b/ci/appveyor-bootstrap.ps1 @@ -0,0 +1,88 @@ +# Source: https://github.com/pypa/python-packaging-user-guide/blob/master/source/code/install.ps1 +# Sample script to install Python and pip under Windows +# Authors: Olivier Grisel and Kyle Kastner +# License: CC0 1.0 Universal: http://creativecommons.org/publicdomain/zero/1.0/ + +$BASE_URL = "https://www.python.org/ftp/python/" +$GET_PIP_URL = "https://bootstrap.pypa.io/get-pip.py" +$GET_PIP_PATH = "C:\get-pip.py" + + +function DownloadPython ($python_version, $platform_suffix) { + $webclient = New-Object System.Net.WebClient + $filename = "python-" + $python_version + $platform_suffix + ".msi" + $url = $BASE_URL + $python_version + "/" + $filename + + $basedir = $pwd.Path + "\" + $filepath = $basedir + $filename + if (Test-Path $filename) { + Write-Host "Reusing" $filepath + return $filepath + } + + # Download and retry up to 5 times in case of network transient errors. + Write-Host "Downloading" $filename "from" $url + $retry_attempts = 3 + for($i=0; $i -lt $retry_attempts; $i++){ + try { + $webclient.DownloadFile($url, $filepath) + break + } + Catch [Exception]{ + Start-Sleep 1 + } + } + Write-Host "File saved at" $filepath + return $filepath +} + + +function InstallPython ($python_version, $architecture, $python_home) { + Write-Host "Installing Python" $python_version "for" $architecture "bit architecture to" $python_home + if (Test-Path $python_home) { + Write-Host $python_home "already exists, skipping." + return $false + } + if ($architecture -eq "32") { + $platform_suffix = "" + } else { + $platform_suffix = ".amd64" + } + $filepath = DownloadPython $python_version $platform_suffix + Write-Host "Installing" $filepath "to" $python_home + $args = "/qn /i $filepath TARGETDIR=$python_home" + Write-Host "msiexec.exe" $args + Start-Process -FilePath "msiexec.exe" -ArgumentList $args -Wait -Passthru + Write-Host "Python $python_version ($architecture) installation complete" + return $true +} + + +function InstallPip ($python_home) { + $pip_path = $python_home + "/Scripts/pip.exe" + $python_path = $python_home + "/python.exe" + if (-not(Test-Path $pip_path)) { + Write-Host "Installing pip..." + $webclient = New-Object System.Net.WebClient + $webclient.DownloadFile($GET_PIP_URL, $GET_PIP_PATH) + Write-Host "Executing:" $python_path $GET_PIP_PATH + Start-Process -FilePath "$python_path" -ArgumentList "$GET_PIP_PATH" -Wait -Passthru + } else { + Write-Host "pip already installed." + } +} + +function InstallPackage ($python_home, $pkg) { + $pip_path = $python_home + "/Scripts/pip.exe" + & $pip_path install $pkg +} + +function main () { + InstallPython $env:PYTHON_VERSION $env:PYTHON_ARCH $env:PYTHON_HOME + InstallPip $env:PYTHON_HOME + InstallPackage $env:PYTHON_HOME setuptools + InstallPackage $env:PYTHON_HOME wheel + InstallPackage $env:PYTHON_HOME tox +} + +main diff --git a/ci/appveyor-with-compiler.cmd b/ci/appveyor-with-compiler.cmd new file mode 100644 index 00000000..3619733b --- /dev/null +++ b/ci/appveyor-with-compiler.cmd @@ -0,0 +1,37 @@ +:: To build extensions for 64 bit Python 3, we need to configure environment +:: variables to use the MSVC 2010 C++ compilers from GRMSDKX_EN_DVD.iso of: +:: MS Windows SDK for Windows 7 and .NET Framework 4 (SDK v7.1) +:: +:: To build extensions for 64 bit Python 2, we need to configure environment +:: variables to use the MSVC 2008 C++ compilers from GRMSDKX_EN_DVD.iso of: +:: MS Windows SDK for Windows 7 and .NET Framework 3.5 (SDK v7.0) +:: +:: 32 bit builds do not require specific environment configurations. +:: +:: Note: this script needs to be run with the /E:ON and /V:ON flags for the +:: cmd interpreter, at least for (SDK v7.0) +:: +:: More details at: +:: https://github.com/cython/cython/wiki/64BitCythonExtensionsOnWindows +:: http://stackoverflow.com/a/13751649/163740 +:: +:: Author: Olivier Grisel +:: License: CC0 1.0 Universal: http://creativecommons.org/publicdomain/zero/1.0/ +@ECHO OFF + +SET COMMAND_TO_RUN=%* +SET WIN_SDK_ROOT=C:\Program Files\Microsoft SDKs\Windows + +IF "%PYTHON_ARCH%"=="64" ( + ECHO SDK: %WINDOWS_SDK_VERSION% ARCH: %PYTHON_ARCH% + SET DISTUTILS_USE_SDK=1 + SET MSSdk=1 + "%WIN_SDK_ROOT%\%WINDOWS_SDK_VERSION%\Setup\WindowsSdkVer.exe" -q -version:%WINDOWS_SDK_VERSION% + "%WIN_SDK_ROOT%\%WINDOWS_SDK_VERSION%\Bin\SetEnv.cmd" /x64 /release + ECHO Executing: %COMMAND_TO_RUN% + call %COMMAND_TO_RUN% || EXIT 1 +) ELSE ( + ECHO SDK: %WINDOWS_SDK_VERSION% ARCH: %PYTHON_ARCH% + ECHO Executing: %COMMAND_TO_RUN% + call %COMMAND_TO_RUN% || EXIT 1 +) diff --git a/ci/bootstrap.py b/ci/bootstrap.py new file mode 100755 index 00000000..466bb8fe --- /dev/null +++ b/ci/bootstrap.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +from __future__ import absolute_import, print_function, unicode_literals + +import os +import sys +from os.path import exists +from os.path import join +from os.path import dirname +from os.path import abspath + + +if __name__ == "__main__": + base_path = dirname(dirname(abspath(__file__))) + print("Project path: {0}".format(base_path)) + env_path = join(base_path, ".tox", "bootstrap") + if sys.platform == "win32": + bin_path = join(env_path, "Scripts") + else: + bin_path = join(env_path, "bin") + if not exists(env_path): + import subprocess + print("Making bootstrap env in: {0} ...".format(env_path)) + try: + subprocess.check_call(["virtualenv", env_path]) + except Exception: + subprocess.check_call([sys.executable, "-m", "virtualenv", env_path]) + print("Installing `jinja2` and `matrix` into bootstrap environment ...") + subprocess.check_call([join(bin_path, "pip"), "install", "jinja2", "matrix"]) + activate = join(bin_path, "activate_this.py") + exec(compile(open(activate, "rb").read(), activate, "exec"), dict(__file__=activate)) + + import jinja2 + import matrix + + jinja = jinja2.Environment( + loader=jinja2.FileSystemLoader(join(base_path, "ci", "templates")), + trim_blocks=True, + lstrip_blocks=True, + keep_trailing_newline=True + ) + tox_environments = {} + for (alias, conf) in matrix.from_file(join(base_path, "setup.cfg")).items(): + python = conf["python_versions"] + deps = conf["dependencies"] + if "coverage_flags" in conf: + cover = {"false": False, "true": True}[conf["coverage_flags"].lower()] + if "environment_variables" in conf: + env_vars = conf["environment_variables"] + + tox_environments[alias] = { + "python": "python" + python if "py" not in python else python, + "deps": deps.split(), + } + if "coverage_flags" in conf: + tox_environments[alias].update(cover=cover) + if "environment_variables" in conf: + tox_environments[alias].update(env_vars=env_vars.split()) + + for name in os.listdir(join("ci", "templates")): + with open(join(base_path, name), "w") as fh: + fh.write(jinja.get_template(name).render(tox_environments=tox_environments)) + print("Wrote {}".format(name)) + print("DONE.") diff --git a/ci/templates/.travis.yml b/ci/templates/.travis.yml new file mode 100644 index 00000000..b1d89b30 --- /dev/null +++ b/ci/templates/.travis.yml @@ -0,0 +1,27 @@ +language: python +python: 2.7 +sudo: false +env: + global: + LD_PRELOAD=/lib/x86_64-linux-gnu/libSegFault.so + matrix: + - TOXENV=check +{% for env, config in tox_environments|dictsort %} + - TOXENV={{ env }}{% if config.cover %},coveralls{% endif %} + +{% endfor %} +before_install: + - python --version + - virtualenv --version + - pip --version + - uname -a + - lsb_release -a +install: + - pip install tox +script: + - tox -v +notifications: + email: + on_success: never + on_failure: always + diff --git a/ci/templates/appveyor.yml b/ci/templates/appveyor.yml new file mode 100644 index 00000000..55310322 --- /dev/null +++ b/ci/templates/appveyor.yml @@ -0,0 +1,39 @@ +version: '{branch}-{build}' +build: off +environment: + global: + WITH_COMPILER: "cmd /E:ON /V:ON /C .\\ci\\appveyor-with-compiler.cmd" + matrix: + - TOXENV: check + PYTHON_HOME: "C:\\Python27" + PYTHON_VERSION: "2.7" + PYTHON_ARCH: "32" +{% for env, config in tox_environments|dictsort %}{% if env.startswith('2.7') or env.startswith('3.4') or env.startswith('3.3') %} + - TOXENV: "{{ env }}" + TOXPYTHON: "C:\\Python{{ env[:3].replace('.', '') }}\\python.exe" + WINDOWS_SDK_VERSION: "v7.{{ '1' if env[0] == '3' else '0' }}" + PYTHON_HOME: "C:\\Python{{ env[:3].replace('.', '') }}" + PYTHON_VERSION: "{{ env[:3] }}" + PYTHON_ARCH: "32" + - TOXENV: "{{ env }}" + TOXPYTHON: "C:\\Python{{ env[:3].replace('.', '') }}-x64\\python.exe" + WINDOWS_SDK_VERSION: "v7.{{ '1' if env[0] == '3' else '0' }}" + PYTHON_HOME: "C:\\Python{{ env[:3].replace('.', '') }}-x64" + PYTHON_VERSION: "{{ env[:3] }}" + PYTHON_ARCH: "64" +{% endif %}{% endfor %} +init: + - "ECHO %TOXENV%" + - ps: "ls C:\\Python*" +install: + - "powershell ci\\appveyor-bootstrap.ps1" +test_script: + - "%PYTHON_HOME%\\Scripts\\tox --version" + - "%PYTHON_HOME%\\Scripts\\virtualenv --version" + - "%PYTHON_HOME%\\Scripts\\pip --version" + - "%WITH_COMPILER% %PYTHON_HOME%\\Scripts\\tox" +after_test: + - "IF \"%TOXENV:~-8,8%\" == \"-nocover\" %WITH_COMPILER% %TOXPYTHON% setup.py bdist_wheel" +artifacts: + - path: dist\* + diff --git a/ci/templates/tox.ini b/ci/templates/tox.ini new file mode 100644 index 00000000..c96fb687 --- /dev/null +++ b/ci/templates/tox.ini @@ -0,0 +1,117 @@ +[tox] +envlist = + clean, + check, +{% for env in tox_environments|sort %} + {{ env }}, +{% endfor %} + report, + docs + +[testenv] +setenv = + PYTHONPATH={toxinidir}/tests + PYTHONUNBUFFERED=yes +passenv = + * +deps = + pytest + pytest-capturelog +commands = + {posargs:py.test -vv --ignore=src} + +[testenv:spell] +setenv = + SPELLCHECK = 1 +commands = + sphinx-build -b spelling docs dist/docs +usedevelop = true +deps = + -r{toxinidir}/docs/requirements.txt + sphinxcontrib-spelling + pyenchant + +[testenv:docs] +whitelist_externals = + rm +commands = + sphinx-build {posargs:-E} -b html docs dist/docs + sphinx-build -b linkcheck docs dist/docs +usedevelop = true +deps = + -r{toxinidir}/docs/requirements.txt + +[testenv:configure] +deps = + jinja2 + matrix +usedevelop = true +commands = + python bootstrap.py + +[testenv:check] +basepython = python3.4 +deps = + docutils + check-manifest + flake8 + readme + pygments +usedevelop = true +commands = + python setup.py check --strict --metadata --restructuredtext + check-manifest {toxinidir} + flake8 src + +[testenv:coveralls] +deps = + coveralls +usedevelop = true +commands = + coverage combine + coverage report + coveralls + +[testenv:report] +basepython = python3.4 +commands = + coverage combine + coverage report +usedevelop = true +deps = coverage + +[testenv:clean] +commands = coverage erase +usedevelop = true +deps = coverage + +{% for env, config in tox_environments|dictsort %} +[testenv:{{ env }}] +basepython = {{ config.python }} +{% if config.cover or config.env_vars %} +setenv = + {[testenv]setenv} +{% endif %} +{% for var in config.env_vars %} + {{ var }} +{% endfor %} +{% if config.cover %} + WITH_COVERAGE=yes +usedevelop = true +commands = + {posargs:py.test --cov=src --cov-report=term-missing -vv} +{% endif %} +{% if config.cover or config.deps %} +deps = + {[testenv]deps} +{% endif %} +{% if config.cover %} + pytest-cov +{% endif %} +{% for dep in config.deps %} + {{ dep }} +{% endfor %} + +{% endfor %} + + diff --git a/docs/authors.rst b/docs/authors.rst new file mode 100644 index 00000000..e122f914 --- /dev/null +++ b/docs/authors.rst @@ -0,0 +1 @@ +.. include:: ../AUTHORS.rst diff --git a/docs/changelog.rst b/docs/changelog.rst new file mode 100644 index 00000000..565b0521 --- /dev/null +++ b/docs/changelog.rst @@ -0,0 +1 @@ +.. include:: ../CHANGELOG.rst diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 00000000..42fc5872 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +import os + + +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.autosummary', + 'sphinx.ext.todo', + 'sphinx.ext.coverage', + 'sphinx.ext.ifconfig', + 'sphinx.ext.viewcode', + 'sphinxcontrib.napoleon' +] +if os.getenv('SPELLCHECK'): + extensions += 'sphinxcontrib.spelling', + spelling_show_suggestions = True + spelling_lang = 'en_US' + +source_suffix = '.rst' +master_doc = 'index' +project = u'pytest-cover' +year = u'2015' +author = u'Ionel Cristian M\u0103rie\u0219' +copyright = '{0}, {1}'.format(year, author) +version = release = u'0.1.0' + +import sphinx_py3doc_enhanced_theme +html_theme = "sphinx_py3doc_enhanced_theme" +html_theme_path = [sphinx_py3doc_enhanced_theme.get_html_theme_path()] + +pygments_style = 'trac' +templates_path = ['.'] +html_use_smartypants = True +html_last_updated_fmt = '%b %d, %Y' +html_split_index = True +html_sidebars = { + '**': ['searchbox.html', 'globaltoc.html', 'sourcelink.html'], +} +html_short_title = '%s-%s' % (project, version) +html_theme_options = { + 'githuburl': 'https://github.com/ionelmc/pytest-cover/' +} diff --git a/docs/contributing.rst b/docs/contributing.rst new file mode 100644 index 00000000..e582053e --- /dev/null +++ b/docs/contributing.rst @@ -0,0 +1 @@ +.. include:: ../CONTRIBUTING.rst diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 00000000..be946912 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,23 @@ +Welcome to pytest-cover's documentation! +====================================== + +Contents: + +.. toctree:: + :maxdepth: 2 + + readme + installation + usage + reference/index + contributing + authors + changelog + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/docs/installation.rst b/docs/installation.rst new file mode 100644 index 00000000..76e143b2 --- /dev/null +++ b/docs/installation.rst @@ -0,0 +1,7 @@ +============ +Installation +============ + +At the command line:: + + pip install pytest-cover diff --git a/docs/readme.rst b/docs/readme.rst new file mode 100644 index 00000000..6be290b8 --- /dev/null +++ b/docs/readme.rst @@ -0,0 +1,5 @@ +######## +Overview +######## + +.. include:: ../README.rst diff --git a/docs/reference/index.rst b/docs/reference/index.rst new file mode 100644 index 00000000..8cb90cb5 --- /dev/null +++ b/docs/reference/index.rst @@ -0,0 +1,7 @@ +Reference +========= + +.. toctree:: + :glob: + + pytest_cover* diff --git a/docs/reference/pytest_cover.rst b/docs/reference/pytest_cover.rst new file mode 100644 index 00000000..a3695344 --- /dev/null +++ b/docs/reference/pytest_cover.rst @@ -0,0 +1,5 @@ +pytest_cover +============================= + +.. automodule:: pytest_cover + :members: diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 00000000..1632a968 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,4 @@ +sphinx +sphinxcontrib-napoleon +sphinx-py3doc-enhanced-theme +-e . diff --git a/docs/spelling_wordlist.txt b/docs/spelling_wordlist.txt new file mode 100644 index 00000000..f95eb78d --- /dev/null +++ b/docs/spelling_wordlist.txt @@ -0,0 +1,11 @@ +builtin +builtins +classmethod +staticmethod +classmethods +staticmethods +args +kwargs +callstack +Changelog +Indices diff --git a/docs/usage.rst b/docs/usage.rst new file mode 100644 index 00000000..36872c2d --- /dev/null +++ b/docs/usage.rst @@ -0,0 +1,7 @@ +===== +Usage +===== + +To use pytest-cover in a project:: + + import pytest_cover diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 00000000..1b2705ee --- /dev/null +++ b/setup.cfg @@ -0,0 +1,86 @@ +[bdist_wheel] +universal = 1 + +[aliases] +release = register clean --all sdist bdist_wheel + +[flake8] +max-line-length = 140 +exclude = tests/*,*/migrations/*,*/south_migrations/* + +[bumpversion] +current_version = 0.1.0 +files = setup.py docs/conf.py src/pytest_cover/__init__.py +commit = True +tag = True + +[pytest] +norecursedirs = + .git + .tox + dist + build + south_migrations + migrations +python_files = + test_*.py + *_test.py + tests.py +addopts = + -rxEfs + --strict + --ignore=docs/conf.py + --ignore=setup.py + --ignore=ci + --doctest-modules + --doctest-glob=\*.rst + --tb=short + +[isort] +force_single_line=True +line_length=120 +known_first_party=pytest_cover +default_section=THIRDPARTY +forced_separate=test_pytest_cover + +[matrix] +# This is the configuration for the `./bootstrap.py` script. +# It generates `.travis.yml`, `tox.ini` and `appveyor.yml`. +# +# Syntax: [alias:] value [!variable[glob]] [&variable[glob]] +# +# alias: +# - is used to generate the tox environment +# - it's optional +# - if not present the alias will be computed from the `value` +# value: +# - a value of "-" means empty +# !variable[glob]: +# - exclude the combination of the current `value` with +# any value matching the `glob` in `variable` +# - can use as many you want +# &variable[glob]: +# - only include the combination of the current `value` +# when there's a value matching `glob` in `variable` +# - can use as many you want + +python_versions = + 2.6 + 2.7 + 3.3 + 3.4 + pypy + +dependencies = +# 1.4: Django==1.4.16 !python_versions[3.*] +# 1.5: Django==1.5.11 +# 1.6: Django==1.6.8 +# 1.7: Django==1.7.1 !python_versions[2.6] +# Deps commented above are provided as examples. That's what you would use in a Django project. + +coverage_flags = + : true + nocover: false + +environment_variables = + - diff --git a/cov-core/setup.py b/setup.py similarity index 100% rename from cov-core/setup.py rename to setup.py diff --git a/tox.ini b/tox.ini index b59374ac..9896ed03 100644 --- a/tox.ini +++ b/tox.ini @@ -1,9 +1,113 @@ +; a generative tox configuration, see: https://testrun.org/tox/latest/config.html#generative-envlist + [tox] -envlist = flake8 +envlist = + clean, + check, + {2.6,2.7,3.3,3.4,pypy}, + {2.6,2.7,3.3,3.4,pypy}-nocover, + report, + docs + +[testenv] +basepython = + pypy: pypy + 2.6: python2.6 + {2.7,docs}: python2.7 + 3.3: python3.3 + 3.4: python3.4 + {clean,check,report,extension-coveralls,coveralls}: python3.4 +setenv = + PYTHONPATH={toxinidir}/tests + PYTHONUNBUFFERED=yes +passenv = + * +deps = + pytest + pytest-capturelog + pytest-cov +commands = + {posargs:py.test --cov=src --cov-report=term-missing -vv} +usedevelop = true + +[testenv:spell] +setenv = + SPELLCHECK=1 +commands = + sphinx-build -b spelling docs dist/docs +usedevelop = true +deps = + -r{toxinidir}/docs/requirements.txt + sphinxcontrib-spelling + pyenchant + +[testenv:docs] +whitelist_externals = + rm +commands = + sphinx-build {posargs:-E} -b html docs dist/docs + sphinx-build -b linkcheck docs dist/docs +usedevelop = true +deps = + -r{toxinidir}/docs/requirements.txt + +[testenv:check] +basepython = python3.4 +deps = + docutils + check-manifest + flake8 + readme + pygments +usedevelop = true +commands = + python setup.py check --strict --metadata --restructuredtext + check-manifest {toxinidir} + flake8 src + +[testenv:coveralls] +deps = + coveralls +usedevelop = true +commands = + coverage combine + coverage report + coveralls +[testenv:report] +basepython = python3.4 +commands = + coverage combine + coverage report +usedevelop = true +deps = coverage + +[testenv:clean] +commands = coverage erase +usedevelop = true +deps = coverage + +[testenv:2.6-nocover] +commands = + {posargs:py.test -vv --ignore=src} +usedevelop = false + +[testenv:2.7-nocover] +commands = + {posargs:py.test -vv --ignore=src} +usedevelop = false + +[testenv:3.3-nocover] +commands = + {posargs:py.test -vv --ignore=src} +usedevelop = false + +[testenv:3.4-nocover] +commands = + {posargs:py.test -vv --ignore=src} +usedevelop = false -[flake8] -max-line-length = 99 +[testenv:pypy-nocover] +commands = + {posargs:py.test -vv --ignore=src} +usedevelop = false -[testenv:flake8] -deps = flake8 -commands = flake8 From f1e0bd3d7ded284d2bb662dd68542b8acd72d0dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Fri, 5 Jun 2015 21:29:43 +0300 Subject: [PATCH 091/134] More corrections. --- LICENSE | 25 ++++++------- README.rst | 102 +++++++++++++++++++++++++++++++---------------------- 2 files changed, 69 insertions(+), 58 deletions(-) diff --git a/LICENSE b/LICENSE index 768c5f00..e98b6474 100644 --- a/LICENSE +++ b/LICENSE @@ -1,19 +1,14 @@ Copyright (c) 2015, Ionel Cristian Mărieș -All rights reserved. -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -following conditions are met: +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: -1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following -disclaimer. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the +Software. -2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following -disclaimer in the documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +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. \ No newline at end of file diff --git a/README.rst b/README.rst index 9100bb8f..68e51c14 100644 --- a/README.rst +++ b/README.rst @@ -1,26 +1,62 @@ -pytest-cov -========== +=============================== +pytest-cover +=============================== -.. image:: https://travis-ci.org/schlamar/pytest-cov.svg?branch=master - :target: https://travis-ci.org/schlamar/pytest-cov - :alt: Build status - -.. image:: https://pypip.in/download/pytest-cov/badge.png - :target: https://pypi.python.org/pypi//pytest-cov/ - :alt: Downloads +| |docs| |travis| |appveyor| |coveralls| +| |version| |downloads| |wheel| |supported-versions| |supported-implementations| -.. image:: https://pypip.in/version/pytest-cov/badge.png - :target: https://pypi.python.org/pypi/pytest-cov/ - :alt: Latest Version +.. |docs| image:: https://readthedocs.org/projects/pytest-coverer/badge/?style=flat + :target: https://readthedocs.org/projects/pytest-coverer + :alt: Documentation Status -.. image:: https://pypip.in/license/pytest-cov/badge.png - :target: https://pypi.python.org/pypi/pytest-cov/ - :alt: License +.. |travis| image:: http://img.shields.io/travis/ionelmc/pytest-coverer/master.png?style=flat + :alt: Travis-CI Build Status + :target: https://travis-ci.org/ionelmc/pytest-coverer + +.. |appveyor| image:: https://ci.appveyor.com/api/projects/status/github/ionelmc/pytest-coverer?branch=master + :alt: AppVeyor Build Status + :target: https://ci.appveyor.com/project/ionelmc/pytest-coverer + +.. |coveralls| image:: http://img.shields.io/coveralls/ionelmc/pytest-coverer/master.png?style=flat + :alt: Coverage Status + :target: https://coveralls.io/r/ionelmc/pytest-coverer + +.. |landscape| image:: https://landscape.io/github/ionelmc/pytest-coverer/master/landscape.svg?style=flat + :target: https://landscape.io/github/ionelmc/pytest-coverer/master + :alt: Code Quality Status + +.. |version| image:: http://img.shields.io/pypi/v/pytest-coverer.png?style=flat + :alt: PyPI Package latest release + :target: https://pypi.python.org/pypi/pytest-coverer + +.. |downloads| image:: http://img.shields.io/pypi/dm/pytest-coverer.png?style=flat + :alt: PyPI Package monthly downloads + :target: https://pypi.python.org/pypi/pytest-coverer + +.. |wheel| image:: https://pypip.in/wheel/pytest-coverer/badge.png?style=flat + :alt: PyPI Wheel + :target: https://pypi.python.org/pypi/pytest-coverer + +.. |supported-versions| image:: https://pypip.in/py_versions/pytest-coverer/badge.png?style=flat + :alt: Supported versions + :target: https://pypi.python.org/pypi/pytest-coverer + +.. |supported-implementations| image:: https://pypip.in/implementation/pytest-coverer/badge.png?style=flat + :alt: Supported imlementations + :target: https://pypi.python.org/pypi/pytest-coverer + +.. |scrutinizer| image:: https://img.shields.io/scrutinizer/g/ionelmc/pytest-coverer/master.png?style=flat + :alt: Scrutinizer Status + :target: https://scrutinizer-ci.com/g/ionelmc/pytest-coverer/ + +Pytest plugin for measuring coverage. Forked from `pytest-cov `_. + +* Free software: MIT license This plugin produces coverage reports. It supports centralised testing and distributed testing in both load and each modes. It also supports coverage of subprocesses. -All features offered by the coverage package should be available, either through pytest-cov or +All features offered by the coverage package should be available, either through pytest-cover or through coverage's config file. @@ -29,7 +65,7 @@ Installation Install with pip:: - pip install pytest-cov + pip install pytest-cover For distributed testing support install pytest-xdist:: @@ -46,16 +82,7 @@ Uninstallation Uninstall with pip:: - pip uninstall pytest-cov - pip uninstall cov-core - -.. NOTE:: - - Ensure that you manually delete the init_cov_core.pth file in your site-packages directory. - - This file starts coverage collection of subprocesses if appropriate during site initialisation - at python startup. - + pip uninstall pytest-cover Usage ----- @@ -244,12 +271,12 @@ effect. These include specifying source to be measured (source option) and all Limitations ----------- -For distributed testing the slaves must have the pytest-cov package installed. This is needed since -the plugin must be registered through setuptools / distribute for pytest to start the plugin on the +For distributed testing the slaves must have the pytest-cover package installed. This is needed since +the plugin must be registered through setuptools for pytest to start the plugin on the slave. For subprocess measurement environment variables must make it from the main process to the -subprocess. The python used by the subprocess must have pytest-cov installed. The subprocess must +subprocess. The python used by the subprocess must have pytest-cover installed. The subprocess must do normal site initialisation so that the environment variables can be detected and coverage started. @@ -257,16 +284,5 @@ started. Acknowledgements ---------------- -Whilst this plugin has been built fresh from the ground up it has been influenced by the work done -on pytest-coverage (Ross Lawley, James Mills, Holger Krekel) and nose-cover (Jason Pellerin) which are -other coverage plugins. - -Ned Batchelder for coverage and its ability to combine the coverage results of parallel runs. - -Holger Krekel for pytest with its distributed testing support. - -Jason Pellerin for nose. - -Michael Foord for unittest2. - -No doubt others have contributed to these tools as well. +`Marc Schlaich` for creating `pytest-cov (and cov-core) `_. +This plugin is a merge of those two packages with other fixes. \ No newline at end of file From c9731ab59edd7325732dc597484e6929845417b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Fri, 5 Jun 2015 21:52:32 +0300 Subject: [PATCH 092/134] Update setup.py to have the new pth handling and layout support. --- setup.py | 202 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 128 insertions(+), 74 deletions(-) diff --git a/setup.py b/setup.py index bd6853f0..f37d3b84 100644 --- a/setup.py +++ b/setup.py @@ -1,77 +1,131 @@ -import setuptools -import sys +#!/usr/bin/env python +# -*- encoding: utf-8 -*- +from __future__ import absolute_import, print_function + +import io import os +import re +from glob import glob +from os.path import basename +from os.path import dirname +from os.path import join +from os.path import relpath +from os.path import splitext + +from setuptools import find_packages +from setuptools import setup + +def read(*names, **kwargs): + return io.open( + join(dirname(__file__), *names), + encoding=kwargs.get('encoding', 'utf8') + ).read() + + +class BuildWithPTH(build): + def run(self): + build.run(self) + path = join(dirname(__file__), 'src', 'pytest-cover.pth') + dest = join(self.build_lib, basename(path)) + self.copy_file(path, dest) + + +class EasyInstallWithPTH(easy_install): + def run(self): + easy_install.run(self) + path = join(dirname(__file__), 'src', 'pytest-cover.pth') + dest = join(self.install_dir, basename(path)) + self.copy_file(path, dest) + + +class InstallLibWithPTH(install_lib): + def run(self): + install_lib.run(self) + path = join(dirname(__file__), 'src', 'pytest-cover.pth') + dest = join(self.install_dir, basename(path)) + self.copy_file(path, dest) + self.outputs = [dest] -# 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; exec(%r) -''' % ''' -if 'COV_CORE_SOURCE' in os.environ: - try: - import cov_core_init - cov_core_init.init() - except ImportError: + def get_outputs(self): + return chain(install_lib.get_outputs(self), self.outputs) + + +class DevelopWithPTH(develop): + def run(self): + develop.run(self) + path = join(dirname(__file__), 'src', 'pytest-cover.pth') + dest = join(self.install_dir, basename(path)) + self.copy_file(path, dest) + + +class GeneratePTH(Command): + user_options = [] + + def initialize_options(self): pass -''' - -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) + + def finalize_options(self): + pass + + def run(self): + with open(join(dirname(__file__), 'src', 'pytest-cover.pth'), 'w') as fh: + with open(join(dirname(__file__), 'src', 'pytest-cover.embed')) as sh: + fh.write( + 'import os, sys;' + 'exec(%r)' % sh.read().replace(' ', ' ') + ) + +setup( + name='pytest-cover', + version='0.1.0', + license='MIT', + description='Pytest plugin for measuring coverage. Forked from `pytest-cov`.', + long_description='%s\n%s' % (read('README.rst'), re.sub(':[a-z]+:`~?(.*?)`', r'``\1``', read('CHANGELOG.rst'))), + author='Marc Schlaich', + author_email='marc.schlaich@gmail.com', + maintainer='Ionel Cristian M\u0103rie\u0219', + maintainer_email='contact@ionelmc.ro', + url='https://github.com/ionelmc/pytest-cover', + packages=find_packages('src'), + package_dir={'': 'src'}, + py_modules=[splitext(basename(path))[0] for path in glob('src/*.py')], + include_package_data=True, + zip_safe=False, + classifiers=[ + # complete classifier list: http://pypi.python.org/pypi?%3Aaction=list_classifiers + 'Development Status :: 5 - Production/Stable', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: BSD License', + 'Operating System :: Unix', + 'Operating System :: POSIX', + 'Operating System :: Microsoft :: Windows', + 'Programming Language :: Python', + 'Programming Language :: Python :: 2.6', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: Implementation :: CPython', + 'Programming Language :: Python :: Implementation :: PyPy', + 'Topic :: Utilities', + 'Topic :: Software Development :: Testing' + ], + keywords=[ + 'cover', 'coverage', 'pytest', 'py.test', 'distributed', 'parallel', + ], + install_requires=[ + ], + extras_require={ + }, + entry_points={ + 'console_scripts': [ + ] + }, + cmdclass={ + 'build': BuildWithPTH, + 'easy_install': EasyInstallWithPTH, + 'install_lib': InstallLibWithPTH, + 'develop': DevelopWithPTH, + 'genpth': GeneratePTH, + }, +) From a6c5fa6c8c2b245602f83cbe8a180c9a1ea40b42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Sat, 6 Jun 2015 00:43:05 +0300 Subject: [PATCH 093/134] Remove --cov-source and fix --cov without arg to activate coverage (with no sources specified). --- src/pytest_cover/plugin.py | 16 +++------ tests/test_pytest_cover.py | 67 +++++++++++++++----------------------- 2 files changed, 31 insertions(+), 52 deletions(-) diff --git a/src/pytest_cover/plugin.py b/src/pytest_cover/plugin.py index 0ac9dd81..289a8223 100644 --- a/src/pytest_cover/plugin.py +++ b/src/pytest_cover/plugin.py @@ -17,12 +17,8 @@ def pytest_addoption(parser): group = parser.getgroup( 'cov', 'coverage reporting with distributed testing support') - - group.addoption('--cov', action='append', nargs='?', dest='cov', - const=True, default=[], - help='Enable coverage plugin.') - group.addoption('--cov-source', action='append', default=[], - metavar='path', dest='cov_source', + group.addoption('--cov', action='append', default=[], metavar='path', + nargs='?', const=True, dest='cov_source', help='measure coverage for filesystem path ' '(multi-allowed)') group.addoption('--cov-report', action='append', default=[], @@ -45,13 +41,9 @@ def pytest_addoption(parser): @pytest.mark.tryfirst def pytest_load_initial_conftests(early_config, parser, args): ns = parser.parse_known_args(args) - if ns.cov and ns.cov != [True]: - print ('Deprecation warning: --cov shouldn\'t be used ' - 'with additional source arguments anymore. Use ' - '--cov-source instead.') - ns.cov_source.extend(ns.cov) + ns.cov = bool(ns.cov_source) - if not ns.cov_source: + if ns.cov_source == [True]: ns.cov_source = None if not ns.cov_report: diff --git a/tests/test_pytest_cover.py b/tests/test_pytest_cover.py index b2a3ee3d..e7ad85f7 100644 --- a/tests/test_pytest_cover.py +++ b/tests/test_pytest_cover.py @@ -1,4 +1,3 @@ - import os import sys @@ -6,7 +5,8 @@ import py import pytest -import pytest_cov +import subprocess +import pytest_cover.plugin pytest_plugins = 'pytester', 'cov' @@ -101,7 +101,7 @@ def test_central(testdir): script = testdir.makepyfile(SCRIPT) result = testdir.runpytest('-v', - '--cov', '--cov-source=%s' % script.dirpath(), + '--cov=%s' % script.dirpath(), '--cov-report=term-missing', script) @@ -117,7 +117,7 @@ def test_cov_min_100(testdir): script = testdir.makepyfile(SCRIPT) result = testdir.runpytest('-v', - '--cov', '--cov-source=%s' % script.dirpath(), + '--cov=%s' % script.dirpath(), '--cov-report=term-missing', '--cov-min=100', script) @@ -129,7 +129,7 @@ def test_cov_min_50(testdir): script = testdir.makepyfile(SCRIPT) result = testdir.runpytest('-v', - '--cov', '--cov-source=%s' % script.dirpath(), + '--cov=%s' % script.dirpath(), '--cov-report=term-missing', '--cov-min=50', script) @@ -141,7 +141,7 @@ def test_cov_min_no_report(testdir): script = testdir.makepyfile(SCRIPT) result = testdir.runpytest('-v', - '--cov', '--cov-source=%s' % script.dirpath(), + '--cov=%s' % script.dirpath(), '--cov-report=', '--cov-min=50', script) @@ -194,7 +194,7 @@ def test_no_cov_on_fail(testdir): script = testdir.makepyfile(SCRIPT_FAIL) result = testdir.runpytest('-v', - '--cov', '--cov-source=%s' % script.dirpath(), + '--cov=%s' % script.dirpath(), '--cov-report=term-missing', '--no-cov-on-fail', script) @@ -207,7 +207,7 @@ def test_dist_collocated(testdir): script = testdir.makepyfile(SCRIPT) result = testdir.runpytest('-v', - '--cov', '--cov-source=%s' % script.dirpath(), + '--cov=%s' % script.dirpath(), '--cov-report=term-missing', '--dist=load', '--tx=2*popen', @@ -227,7 +227,7 @@ def test_dist_not_collocated(testdir): dir2 = testdir.mkdir('dir2') result = testdir.runpytest('-v', - '--cov', '--cov-source=%s' % script.dirpath(), + '--cov=%s' % script.dirpath(), '--cov-report=term-missing', '--dist=load', '--tx=popen//chdir=%s' % dir1, @@ -249,7 +249,7 @@ def test_central_subprocess(testdir): parent_script = scripts.dirpath().join('parent_script.py') result = testdir.runpytest('-v', - '--cov', '--cov-source=%s' % scripts.dirpath(), + '--cov=%s' % scripts.dirpath(), '--cov-report=term-missing', parent_script) @@ -267,7 +267,7 @@ def test_dist_subprocess_collocated(testdir): parent_script = scripts.dirpath().join('parent_script.py') result = testdir.runpytest('-v', - '--cov', '--cov-source=%s' % scripts.dirpath(), + '--cov=%s' % scripts.dirpath(), '--cov-report=term-missing', '--dist=load', '--tx=2*popen', @@ -291,7 +291,7 @@ def test_dist_subprocess_not_collocated(testdir, tmpdir): dir2 = tmpdir.mkdir('dir2') result = testdir.runpytest('-v', - '--cov', '--cov-source=%s' % scripts.dirpath(), + '--cov=%s' % scripts.dirpath(), '--cov-report=term-missing', '--dist=load', '--tx=popen//chdir=%s' % dir1, @@ -312,7 +312,7 @@ def test_empty_report(testdir): script = testdir.makepyfile(SCRIPT) result = testdir.runpytest('-v', - '--cov', '--cov-source=non_existent_module', + '--cov=non_existent_module', '--cov-report=term-missing', script) @@ -332,10 +332,11 @@ def test_dist_missing_data(testdir): exe = os.path.join(venv_path, 'Scripts', 'python.exe') else: exe = os.path.join(venv_path, 'bin', 'python') + subprocess.check_call([exe, '-mpip', 'install', 'py', 'pytest']) script = testdir.makepyfile(SCRIPT) result = testdir.runpytest('-v', - '--cov', '--cov-source=%s' % script.dirpath(), + '--cov=%s' % script.dirpath(), '--cov-report=term-missing', '--dist=load', '--tx=popen//python=%s' % exe, @@ -351,7 +352,7 @@ def test_funcarg(testdir): script = testdir.makepyfile(SCRIPT_FUNCARG) result = testdir.runpytest('-v', - '--cov', '--cov-source=%s' % script.dirpath(), + '--cov=%s' % script.dirpath(), '--cov-report=term-missing', script) @@ -381,7 +382,7 @@ def test_multiprocessing_subprocess(testdir): script = testdir.makepyfile(MULTIPROCESSING_SCRIPT) result = testdir.runpytest('-v', - '--cov', '--cov-source=%s' % script.dirpath(), + '--cov=%s' % script.dirpath(), '--cov-report=term-missing', script) @@ -422,7 +423,7 @@ def test_cover_conftest(testdir): testdir.makeconftest(CONFTEST) script = testdir.makepyfile(BASIC_TEST) result = testdir.runpytest('-v', - '--cov', '--cov-source=%s' % script.dirpath(), + '--cov=%s' % script.dirpath(), '--cov-report=term-missing', script) assert result.ret == 0 @@ -434,7 +435,7 @@ def test_cover_conftest_dist(testdir): testdir.makeconftest(CONFTEST) script = testdir.makepyfile(BASIC_TEST) result = testdir.runpytest('-v', - '--cov', '--cov-source=%s' % script.dirpath(), + '--cov=%s' % script.dirpath(), '--cov-report=term-missing', '--dist=load', '--tx=2*popen', @@ -470,7 +471,7 @@ def test_coveragerc(testdir): script = testdir.makepyfile(EXCLUDED_TEST) result = testdir.runpytest('-v', '--cov-config=coveragerc', - '--cov', '--cov-source=%s' % script.dirpath(), + '--cov=%s' % script.dirpath(), '--cov-report=term-missing', script) assert result.ret == 0 @@ -482,7 +483,7 @@ def test_coveragerc_dist(testdir): script = testdir.makepyfile(EXCLUDED_TEST) result = testdir.runpytest('-v', '--cov-config=coveragerc', - '--cov', '--cov-source=%s' % script.dirpath(), + '--cov=%s' % script.dirpath(), '--cov-report=term-missing', '-n', '2', script) @@ -504,7 +505,7 @@ def test_basic(): def test_clear_environ(testdir): script = testdir.makepyfile(CLEAR_ENVIRON_TEST) result = testdir.runpytest('-v', - '--cov', '--cov-source=%s' % script.dirpath(), + '--cov=%s' % script.dirpath(), '--cov-report=term-missing', script) assert result.ret == 0 @@ -527,7 +528,7 @@ def test_dist_boxed(testdir): script = testdir.makepyfile(SCRIPT_SIMPLE) result = testdir.runpytest('-v', - '--cov', '--cov-source=%s' % script.dirpath(), + '--cov=%s' % script.dirpath(), '--boxed', script) @@ -540,29 +541,16 @@ def test_dist_boxed(testdir): def test_not_started_plugin_does_not_fail(testdir): - plugin = pytest_cov.CovPlugin(None, None, start=False) + plugin = pytest_cover.plugin.CovPlugin(None, None, start=False) plugin.pytest_sessionfinish(None, None) plugin.pytest_terminal_summary(None) -def test_deprecation_warning(testdir): - script = testdir.makepyfile(SCRIPT) - - result = testdir.runpytest('-v', - '--cov=%s' % script.dirpath(), - script) - - result.stdout.fnmatch_lines([ - 'Deprecation warning: * --cov-source instead*' - ]) - assert result.ret == 0 - - def test_default_output_setting(testdir): script = testdir.makepyfile(SCRIPT) result = testdir.runpytest('-v', - '--cov', '--cov-source=%s' % script.dirpath(), + '--cov=%s' % script.dirpath(), script) result.stdout.fnmatch_lines([ @@ -575,7 +563,7 @@ def test_disabled_output(testdir): script = testdir.makepyfile(SCRIPT) result = testdir.runpytest('-v', - '--cov', '--cov-source=%s' % script.dirpath(), + '--cov=%s' % script.dirpath(), '--cov-report=', script) @@ -588,8 +576,7 @@ def test_coverage_file(testdir): data_file_name = 'covdata' os.environ['COVERAGE_FILE'] = data_file_name try: - result = testdir.runpytest('-v', '--cov', - '--cov-source=%s' % script.dirpath(), + result = testdir.runpytest('-v', '--cov=%s' % script.dirpath(), script) assert result.ret == 0 data_file = testdir.tmpdir.join(data_file_name) From ca12e6b970fe7d9ab12e51f1f1ec4d7fcb66a017 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Sat, 6 Jun 2015 00:43:52 +0300 Subject: [PATCH 094/134] Fix imports. --- src/pytest_cover/embed.py | 2 +- src/pytest_cover/engine.py | 7 ++++--- src/pytest_cover/plugin.py | 18 +++++++++--------- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/pytest_cover/embed.py b/src/pytest_cover/embed.py index f91ad34c..a09aa8ad 100644 --- a/src/pytest_cover/embed.py +++ b/src/pytest_cover/embed.py @@ -17,7 +17,7 @@ UNIQUE_SEP = '084031f3d2994d40a88c8b699b69e148' -import cov_core # noqa: register multiprocessing handler +from . import engine # noqa: register multiprocessing handler def init(): diff --git a/src/pytest_cover/engine.py b/src/pytest_cover/engine.py index b948178a..68eeea01 100644 --- a/src/pytest_cover/engine.py +++ b/src/pytest_cover/engine.py @@ -1,7 +1,6 @@ """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 @@ -9,7 +8,8 @@ def multiprocessing_start(obj): - cov = cov_core_init.init() + from . import embed + cov = embed.init() if cov: import multiprocessing.util multiprocessing.util.Finalize( @@ -47,6 +47,7 @@ def __init__(self, cov_source, cov_report, cov_config, config=None, nodeid=None) def set_env(self): """Put info about coverage into the env so that subprocesses can activate coverage.""" + from .embed import UNIQUE_SEP if self.cov_source is None: os.environ['COV_CORE_SOURCE'] = '' diff --git a/src/pytest_cover/plugin.py b/src/pytest_cover/plugin.py index 289a8223..d85c5228 100644 --- a/src/pytest_cover/plugin.py +++ b/src/pytest_cover/plugin.py @@ -4,12 +4,12 @@ import pytest -import cov_core -import cov_core_init +from . import engine +from . import embed class CoverageError(Exception): - '''Indicates that our coverage is too low''' + """Indicates that our coverage is too low""" def pytest_addoption(parser): @@ -92,15 +92,15 @@ def __init__(self, options, pluginmanager, start=True): getattr(options, 'distload', False) or getattr(options, 'dist', 'no') != 'no') if is_dist and start: - self.start(cov_core.DistMaster) + self.start(engine.DistMaster) elif start: - self.start(cov_core.Central) + self.start(engine.Central) # slave is started in pytest hook def start(self, controller_cls, config=None, nodeid=None): if config is None: - # fake config option for cov_core + # fake config option for engine class Config(object): option = self.options @@ -122,7 +122,7 @@ def pytest_sessionstart(self, session): if is_slave: nodeid = session.config.slaveinput.get('slaveid', getattr(session, 'nodeid')) - self.start(cov_core.DistSlave, session.config, nodeid) + self.start(engine.DistSlave, session.config, nodeid) def pytest_configure_node(self, node): """Delegate to our implementation. @@ -163,11 +163,11 @@ def pytest_runtest_setup(self, item): if os.getpid() != self.pid: # test is run in another process than session, run # coverage manually - self.cov = cov_core_init.init() + self.cov = embed.init() def pytest_runtest_teardown(self, item): if self.cov is not None: - cov_core.multiprocessing_finish(self.cov) + engine.multiprocessing_finish(self.cov) self.cov = None From 0fdd8a3d44f3cacec157317a691f54c6083fc605 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Sat, 6 Jun 2015 00:44:02 +0300 Subject: [PATCH 095/134] Update readme about the --cov arg. --- README.rst | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/README.rst b/README.rst index 68e51c14..85e8695a 100644 --- a/README.rst +++ b/README.rst @@ -95,7 +95,7 @@ subprocesses. Running centralised testing:: - py.test --cov-source myproj tests/ + py.test --cov=myproj tests/ Shows a terminal report:: @@ -118,7 +118,7 @@ file system. Each slave will have it's subprocesses measured. Running distributed testing with dist mode set to load:: - py.test --cov-source myproj -n 2 tests/ + py.test --cov=myproj -n 2 tests/ Shows a terminal report:: @@ -134,7 +134,7 @@ Shows a terminal report:: Again but spread over different hosts and different directories:: - py.test --cov-source myproj --dist load + py.test --cov=myproj --dist load --tx ssh=memedough@host1//chdir=testenv1 --tx ssh=memedough@host2//chdir=/tmp/testenv2//python=/tmp/env1/bin/python --rsyncdir myproj --rsyncdir tests --rsync examples @@ -161,7 +161,7 @@ environments. Running distributed testing with dist mode set to each:: - py.test --cov-source myproj --dist each + py.test --cov=myproj --dist each --tx popen//chdir=/tmp/testenv3//python=/usr/local/python27/bin/python --tx ssh=memedough@host2//chdir=/tmp/testenv4//python=/tmp/env2/bin/python --rsyncdir myproj --rsyncdir tests --rsync examples @@ -191,7 +191,7 @@ annotated source code. The terminal report without line numbers (default):: - py.test --cov-report term --cov-source myproj tests/ + py.test --cov-report term --cov=myproj tests/ -------------------- coverage: platform linux2, python 2.6.4-final-0 --------------------- Name Stmts Miss Cover @@ -205,7 +205,7 @@ The terminal report without line numbers (default):: The terminal report with line numbers:: - py.test --cov-report term-missing --cov-source myproj tests/ + py.test --cov-report term-missing --cov=myproj tests/ -------------------- coverage: platform linux2, python 2.6.4-final-0 --------------------- Name Stmts Miss Cover Missing @@ -222,11 +222,11 @@ These three report options output to files without showing anything on the termi py.test --cov-report html --cov-report xml --cov-report annotate - --cov-source myproj tests/ + --cov=myproj tests/ The final report option can also suppress printing to the terminal:: - py.test --cov-report= --cov-source myproj tests/ + py.test --cov-report= --cov=myproj tests/ This mode can be especially useful on continuous integration servers, where a coverage file is needed for subsequent processing, but no local report needs to be viewed. For example, @@ -251,7 +251,7 @@ For example if tests are contained within the directory tree being measured the excluded if desired by using a .coveragerc file with the omit option set:: py.test --cov-config .coveragerc - --cov-source myproj + --cov=myproj myproj/tests/ Where the .coveragerc file contains file globs:: @@ -285,4 +285,4 @@ Acknowledgements ---------------- `Marc Schlaich` for creating `pytest-cov (and cov-core) `_. -This plugin is a merge of those two packages with other fixes. \ No newline at end of file +This plugin is a merge of those two packages with other fixes. From a4a0d0a1c19265a6db6dd1f16b7b6623518ecd26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Sat, 6 Jun 2015 00:44:14 +0300 Subject: [PATCH 096/134] Packaging fixes. --- setup.cfg | 1 + setup.py | 12 ++++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/setup.cfg b/setup.cfg index 1b2705ee..32f9ed12 100644 --- a/setup.cfg +++ b/setup.cfg @@ -22,6 +22,7 @@ norecursedirs = build south_migrations migrations + example python_files = test_*.py *_test.py diff --git a/setup.py b/setup.py index f37d3b84..2dada20a 100644 --- a/setup.py +++ b/setup.py @@ -3,17 +3,22 @@ from __future__ import absolute_import, print_function import io -import os +from itertools import chain import re from glob import glob from os.path import basename from os.path import dirname from os.path import join -from os.path import relpath from os.path import splitext +from distutils.command.build import build +from setuptools import Command from setuptools import find_packages from setuptools import setup +from setuptools.command.develop import develop +from setuptools.command.install_lib import install_lib +from setuptools.command.easy_install import easy_install + def read(*names, **kwargs): return io.open( @@ -118,6 +123,9 @@ def run(self): extras_require={ }, entry_points={ + 'pytest11': [ + 'pytest_cov = pytest_cover.plugin', + ], 'console_scripts': [ ] }, From d4681d55e894f4eff8427689c043cdde109dc5d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Sat, 6 Jun 2015 00:44:19 +0300 Subject: [PATCH 097/134] Add missing deps. --- tox.ini | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 9896ed03..ac24b3da 100644 --- a/tox.ini +++ b/tox.ini @@ -25,7 +25,9 @@ passenv = deps = pytest pytest-capturelog - pytest-cov + coverage + virtualenv + pytest-xdist commands = {posargs:py.test --cov=src --cov-report=term-missing -vv} usedevelop = true From 3dd5f86b3d0bb48489fad1426d2a687c8acec5c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Sat, 6 Jun 2015 00:45:01 +0300 Subject: [PATCH 098/134] Add pth files. --- src/pytest-cover.embed | 10 ++++++++++ src/pytest-cover.pth | 1 + 2 files changed, 11 insertions(+) create mode 100644 src/pytest-cover.embed create mode 100644 src/pytest-cover.pth diff --git a/src/pytest-cover.embed b/src/pytest-cover.embed new file mode 100644 index 00000000..5e5fa729 --- /dev/null +++ b/src/pytest-cover.embed @@ -0,0 +1,10 @@ +if 'COV_CORE_SOURCE' in os.environ: + try: + from pytest_cover.embed import init + init() + except ImportError: + sys.stderr.write( + "Failed to setup coverage." + "Sources: {[COV_CORE_SOURCE]!r}" + "Config: {[COV_CORE_CONFIG]!r}" + "Exception: {!r}\n".format(os.environ, exc)) diff --git a/src/pytest-cover.pth b/src/pytest-cover.pth new file mode 100644 index 00000000..18376552 --- /dev/null +++ b/src/pytest-cover.pth @@ -0,0 +1 @@ +import os, sys;exec('if \'COV_CORE_SOURCE\' in os.environ:\n try:\n from pytest_cover.embed import init\n init()\n except ImportError:\n sys.stderr.write(\n "Failed to setup coverage."\n "Sources: {[COV_CORE_SOURCE]!r}"\n "Config: {[COV_CORE_CONFIG]!r}"\n "Exception: {!r}\\n".format(os.environ, exc))\n') \ No newline at end of file From 9489bb5b43ae12c229be433e14607019f85ef556 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Sat, 6 Jun 2015 00:51:20 +0300 Subject: [PATCH 099/134] Fix config.getvalue check. --- src/pytest_cover/plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pytest_cover/plugin.py b/src/pytest_cover/plugin.py index d85c5228..2e674ceb 100644 --- a/src/pytest_cover/plugin.py +++ b/src/pytest_cover/plugin.py @@ -58,7 +58,7 @@ def pytest_load_initial_conftests(early_config, parser, args): def pytest_configure(config): """Activate coverage plugin if appropriate.""" - if config.getvalue('cov'): + if config.getvalue('cov_source'): if not config.pluginmanager.hasplugin('_cov'): plugin = CovPlugin(config.option, config.pluginmanager, start=False) From 742baa7a07f2e9bda7ecc2ce5e963c51267e4a60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Sat, 6 Jun 2015 01:06:35 +0300 Subject: [PATCH 100/134] Fix heading levels and correct names. --- README.rst | 72 ++++++++++++++++++++++++++---------------------------- 1 file changed, 35 insertions(+), 37 deletions(-) diff --git a/README.rst b/README.rst index 85e8695a..8de31d54 100644 --- a/README.rst +++ b/README.rst @@ -2,52 +2,52 @@ pytest-cover =============================== -| |docs| |travis| |appveyor| |coveralls| +| |docs| |travis| |appveyor| | |version| |downloads| |wheel| |supported-versions| |supported-implementations| -.. |docs| image:: https://readthedocs.org/projects/pytest-coverer/badge/?style=flat - :target: https://readthedocs.org/projects/pytest-coverer +.. |docs| image:: https://readthedocs.org/projects/pytest-cover/badge/?style=flat + :target: https://readthedocs.org/projects/pytest-cover :alt: Documentation Status -.. |travis| image:: http://img.shields.io/travis/ionelmc/pytest-coverer/master.png?style=flat +.. |travis| image:: http://img.shields.io/travis/ionelmc/pytest-cover/master.png?style=flat :alt: Travis-CI Build Status - :target: https://travis-ci.org/ionelmc/pytest-coverer + :target: https://travis-ci.org/ionelmc/pytest-cover -.. |appveyor| image:: https://ci.appveyor.com/api/projects/status/github/ionelmc/pytest-coverer?branch=master +.. |appveyor| image:: https://ci.appveyor.com/api/projects/status/github/ionelmc/pytest-cover?branch=master :alt: AppVeyor Build Status - :target: https://ci.appveyor.com/project/ionelmc/pytest-coverer + :target: https://ci.appveyor.com/project/ionelmc/pytest-cover -.. |coveralls| image:: http://img.shields.io/coveralls/ionelmc/pytest-coverer/master.png?style=flat +.. |coveralls| image:: http://img.shields.io/coveralls/ionelmc/pytest-cover/master.png?style=flat :alt: Coverage Status - :target: https://coveralls.io/r/ionelmc/pytest-coverer + :target: https://coveralls.io/r/ionelmc/pytest-cover -.. |landscape| image:: https://landscape.io/github/ionelmc/pytest-coverer/master/landscape.svg?style=flat - :target: https://landscape.io/github/ionelmc/pytest-coverer/master +.. |landscape| image:: https://landscape.io/github/ionelmc/pytest-cover/master/landscape.svg?style=flat + :target: https://landscape.io/github/ionelmc/pytest-cover/master :alt: Code Quality Status -.. |version| image:: http://img.shields.io/pypi/v/pytest-coverer.png?style=flat +.. |version| image:: http://img.shields.io/pypi/v/pytest-cover.png?style=flat :alt: PyPI Package latest release - :target: https://pypi.python.org/pypi/pytest-coverer + :target: https://pypi.python.org/pypi/pytest-cover -.. |downloads| image:: http://img.shields.io/pypi/dm/pytest-coverer.png?style=flat +.. |downloads| image:: http://img.shields.io/pypi/dm/pytest-cover.png?style=flat :alt: PyPI Package monthly downloads - :target: https://pypi.python.org/pypi/pytest-coverer + :target: https://pypi.python.org/pypi/pytest-cover -.. |wheel| image:: https://pypip.in/wheel/pytest-coverer/badge.png?style=flat +.. |wheel| image:: https://pypip.in/wheel/pytest-cover/badge.png?style=flat :alt: PyPI Wheel - :target: https://pypi.python.org/pypi/pytest-coverer + :target: https://pypi.python.org/pypi/pytest-cover -.. |supported-versions| image:: https://pypip.in/py_versions/pytest-coverer/badge.png?style=flat +.. |supported-versions| image:: https://pypip.in/py_versions/pytest-cover/badge.png?style=flat :alt: Supported versions - :target: https://pypi.python.org/pypi/pytest-coverer + :target: https://pypi.python.org/pypi/pytest-cover -.. |supported-implementations| image:: https://pypip.in/implementation/pytest-coverer/badge.png?style=flat +.. |supported-implementations| image:: https://pypip.in/implementation/pytest-cover/badge.png?style=flat :alt: Supported imlementations - :target: https://pypi.python.org/pypi/pytest-coverer + :target: https://pypi.python.org/pypi/pytest-cover -.. |scrutinizer| image:: https://img.shields.io/scrutinizer/g/ionelmc/pytest-coverer/master.png?style=flat +.. |scrutinizer| image:: https://img.shields.io/scrutinizer/g/ionelmc/pytest-cover/master.png?style=flat :alt: Scrutinizer Status - :target: https://scrutinizer-ci.com/g/ionelmc/pytest-coverer/ + :target: https://scrutinizer-ci.com/g/ionelmc/pytest-cover/ Pytest plugin for measuring coverage. Forked from `pytest-cov `_. @@ -61,7 +61,7 @@ through coverage's config file. Installation ------------- +============ Install with pip:: @@ -78,17 +78,17 @@ For distributed testing support install pytest-xdist:: Uninstallation --------------- +============== Uninstall with pip:: pip uninstall pytest-cover Usage ------ +===== Centralised Testing -~~~~~~~~~~~~~~~~~~~ +------------------- Centralised testing will report on the combined coverage of the main process and all of it's subprocesses. @@ -110,7 +110,7 @@ Shows a terminal report:: Distributed Testing: Load -~~~~~~~~~~~~~~~~~~~~~~~~~ +------------------------- Distributed testing with dist mode set to load will report on the combined coverage of all slaves. The slaves may be spread out over any number of hosts and each slave may be located anywhere on the @@ -153,7 +153,7 @@ Shows a terminal report:: Distributed Testing: Each -~~~~~~~~~~~~~~~~~~~~~~~~~ +------------------------- Distributed testing with dist mode set to each will report on the combined coverage of all slaves. Since each slave is running all tests this allows generating a combined coverage report for multiple @@ -182,7 +182,7 @@ Shows a terminal report:: Reporting ---------- +========= It is possible to generate any combination of the reports for a single test run. @@ -233,7 +233,7 @@ is needed for subsequent processing, but no local report needs to be viewed. For tests run on Travis-CI could produce a .coverage file for use with Coveralls. Coverage Data File ------------------- +================== The data file is erased at the beginning of testing to ensure clean data for each test run. @@ -242,7 +242,7 @@ examine it. Coverage Config File --------------------- +==================== This plugin provides a clean minimal set of command line options that are added to pytest. For further control of coverage use a coverage config file. @@ -267,9 +267,8 @@ Note that this plugin controls some options and setting the option in the config effect. These include specifying source to be measured (source option) and all data file handling (data_file and parallel options). - Limitations ------------ +=========== For distributed testing the slaves must have the pytest-cover package installed. This is needed since the plugin must be registered through setuptools for pytest to start the plugin on the @@ -280,9 +279,8 @@ subprocess. The python used by the subprocess must have pytest-cover installed. do normal site initialisation so that the environment variables can be detected and coverage started. - Acknowledgements ----------------- +================ -`Marc Schlaich` for creating `pytest-cov (and cov-core) `_. +`Marc Schlaich` and everyone else for contributing and creating `pytest-cov (and cov-core) `_. This plugin is a merge of those two packages with other fixes. From a208b922a7f570e893bdf86602230dedb3065962 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Sat, 6 Jun 2015 01:06:53 +0300 Subject: [PATCH 101/134] Fix test on python 2.6. --- tests/test_pytest_cover.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_pytest_cover.py b/tests/test_pytest_cover.py index e7ad85f7..eace33eb 100644 --- a/tests/test_pytest_cover.py +++ b/tests/test_pytest_cover.py @@ -332,7 +332,7 @@ def test_dist_missing_data(testdir): exe = os.path.join(venv_path, 'Scripts', 'python.exe') else: exe = os.path.join(venv_path, 'bin', 'python') - subprocess.check_call([exe, '-mpip', 'install', 'py', 'pytest']) + subprocess.check_call([exe, '-mpip' if sys.version_info >= (2, 7) else '-mpip.__main__', 'install', 'py', 'pytest']) script = testdir.makepyfile(SCRIPT) result = testdir.runpytest('-v', From d935aa5281deeb584ea56e37f476933e2a0fe311 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Sat, 6 Jun 2015 01:07:06 +0300 Subject: [PATCH 102/134] Remove un-necessary tox envs. --- setup.cfg | 1 + tox.ini | 29 ++--------------------------- 2 files changed, 3 insertions(+), 27 deletions(-) diff --git a/setup.cfg b/setup.cfg index 32f9ed12..c6c0e2bc 100644 --- a/setup.cfg +++ b/setup.cfg @@ -32,6 +32,7 @@ addopts = --strict --ignore=docs/conf.py --ignore=setup.py + --ignore=src --ignore=ci --doctest-modules --doctest-glob=\*.rst diff --git a/tox.ini b/tox.ini index ac24b3da..7b12ca3f 100644 --- a/tox.ini +++ b/tox.ini @@ -5,7 +5,6 @@ envlist = clean, check, {2.6,2.7,3.3,3.4,pypy}, - {2.6,2.7,3.3,3.4,pypy}-nocover, report, docs @@ -29,8 +28,8 @@ deps = virtualenv pytest-xdist commands = - {posargs:py.test --cov=src --cov-report=term-missing -vv} -usedevelop = true + {posargs:py.test -vv} +usedevelop = false [testenv:spell] setenv = @@ -88,28 +87,4 @@ commands = coverage erase usedevelop = true deps = coverage -[testenv:2.6-nocover] -commands = - {posargs:py.test -vv --ignore=src} -usedevelop = false - -[testenv:2.7-nocover] -commands = - {posargs:py.test -vv --ignore=src} -usedevelop = false - -[testenv:3.3-nocover] -commands = - {posargs:py.test -vv --ignore=src} -usedevelop = false - -[testenv:3.4-nocover] -commands = - {posargs:py.test -vv --ignore=src} -usedevelop = false - -[testenv:pypy-nocover] -commands = - {posargs:py.test -vv --ignore=src} -usedevelop = false From d73b543dd81298463b48bb04a66efcf028343f21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Sat, 6 Jun 2015 01:07:21 +0300 Subject: [PATCH 103/134] Update changelog and authorship. --- AUTHORS.rst | 10 +++++++++- CHANGELOG.rst | 14 ++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/AUTHORS.rst b/AUTHORS.rst index 0e54887e..f46a017f 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -1,5 +1,13 @@ - Authors ======= +* Marc Schlaich - http://www.schlamar.org/ +* Rick van Hattem - http://wol.ph/ +* Buck Evan - https://github.com/bukzor +* Eric Larson - http://larsoner.com/ +* Marc Abramowitz - http://marc-abramowitz.com/ +* Thomas Kluyver - https://github.com/takluyver +* Guillaume Ayoub - http://www.yabz.fr/ +* Federico Ceratto - http://firelet.net/ +* Josh Kalderimis - http://blog.cookiestack.com/ * Ionel Cristian Mărieș - http://blog.ionelmc.ro diff --git a/CHANGELOG.rst b/CHANGELOG.rst index e1310db5..67240076 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,8 +1,14 @@ - Changelog ========= -0.1.0 (2015-06-05) ------------------------------------------ +1.0.0 (2015-06-05) +------------------ + +* Forked from the `2.0` branch of https://github.com/schlamar/pytest-cov/ +* Fixed `.pth` installation to work in all cases (install, easy_install, wheels, develop etc). +* Fixed `.pth` uninstallation to work for wheel installs. +* Reverted the unreleased ``--cov=path`` deprecation. +* Removed the unreleased addition of ``--cov-source=path``. + + -* First release on PyPI. From 004c99d83e847f0e801effafee03ad20632cb81a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Sat, 6 Jun 2015 01:07:26 +0300 Subject: [PATCH 104/134] Fix manifest. --- MANIFEST.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MANIFEST.in b/MANIFEST.in index f44be4b5..69475e23 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,5 +1,5 @@ graft docs -graft examples +graft example graft src graft ci graft tests From 12b2abcd94e5bd45a33add5875599f0a0f46bf61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Sat, 6 Jun 2015 01:36:40 +0300 Subject: [PATCH 105/134] Update target version --- setup.py | 2 +- src/pytest_cover/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 2dada20a..ffa67eb8 100644 --- a/setup.py +++ b/setup.py @@ -82,7 +82,7 @@ def run(self): setup( name='pytest-cover', - version='0.1.0', + version='1.0.0', license='MIT', description='Pytest plugin for measuring coverage. Forked from `pytest-cov`.', long_description='%s\n%s' % (read('README.rst'), re.sub(':[a-z]+:`~?(.*?)`', r'``\1``', read('CHANGELOG.rst'))), diff --git a/src/pytest_cover/__init__.py b/src/pytest_cover/__init__.py index 3dc1f76b..5becc17c 100644 --- a/src/pytest_cover/__init__.py +++ b/src/pytest_cover/__init__.py @@ -1 +1 @@ -__version__ = "0.1.0" +__version__ = "1.0.0" From 824aa4fbdbf41acf7e22049081575ef0ddc209e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Sat, 6 Jun 2015 01:39:16 +0300 Subject: [PATCH 106/134] Use os.pathsep instead of some arbitrary string. Make things easier to read when debugging. --- src/pytest_cover/embed.py | 3 +-- src/pytest_cover/engine.py | 4 +--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/pytest_cover/embed.py b/src/pytest_cover/embed.py index a09aa8ad..9cbfd75c 100644 --- a/src/pytest_cover/embed.py +++ b/src/pytest_cover/embed.py @@ -15,7 +15,6 @@ """ -UNIQUE_SEP = '084031f3d2994d40a88c8b699b69e148' from . import engine # noqa: register multiprocessing handler @@ -42,7 +41,7 @@ def init(): if not cov_source: cov_source = None else: - cov_source = cov_source.split(UNIQUE_SEP) + cov_source = cov_source.split(os.pathsep) # Activate coverage for this process. cov = coverage.coverage(source=cov_source, diff --git a/src/pytest_cover/engine.py b/src/pytest_cover/engine.py index 68eeea01..3be20c6a 100644 --- a/src/pytest_cover/engine.py +++ b/src/pytest_cover/engine.py @@ -47,12 +47,10 @@ def __init__(self, cov_source, cov_report, cov_config, config=None, nodeid=None) def set_env(self): """Put info about coverage into the env so that subprocesses can activate coverage.""" - from .embed import UNIQUE_SEP - 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_SOURCE'] = os.pathsep.join(self.cov_source) os.environ['COV_CORE_CONFIG'] = self.cov_config @staticmethod From 4974160bb6fd8646292b7a5affb42bb01bbe3abe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Sat, 6 Jun 2015 01:43:46 +0300 Subject: [PATCH 107/134] Move the multiprocessing fixups in embed.py. Fixes circular import issues (or the need for lazy imports). --- src/pytest_cover/embed.py | 75 ++++++++++++++++++++------------------ src/pytest_cover/engine.py | 27 +------------- src/pytest_cover/plugin.py | 5 +-- 3 files changed, 44 insertions(+), 63 deletions(-) diff --git a/src/pytest_cover/embed.py b/src/pytest_cover/embed.py index 9cbfd75c..3cfc4c74 100644 --- a/src/pytest_cover/embed.py +++ b/src/pytest_cover/embed.py @@ -13,44 +13,49 @@ that code coverage is being collected we activate coverage based on info passed via env vars. """ +import os +def multiprocessing_start(obj): + cov = init() + if cov: + multiprocessing.util.Finalize(None, multiprocessing_finish, args=(cov,), exitpriority=1000) -from . import engine # noqa: register multiprocessing handler +def multiprocessing_finish(cov): + cov.stop() + cov.save() -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_config = os.environ.get('COV_CORE_CONFIG') - if cov_config: - - # Import what we need to activate coverage. - import coverage - - # Determine all source roots. - if not cov_source: - cov_source = None - else: - cov_source = cov_source.split(os.pathsep) - - # Activate coverage for this process. - cov = coverage.coverage(source=cov_source, - data_suffix=True, - config_file=cov_config, - auto_data=True) - cov.erase() - cov.start() - return cov - - except Exception: - pass +try: + import multiprocessing.util +except ImportError: + pass +else: + multiprocessing.util.register_after_fork(multiprocessing_start, multiprocessing_start) + + +def init(): + # Only continue if ancestor process has set everything needed in + # the env. + + cov_source = os.environ.get('COV_CORE_SOURCE') + cov_config = os.environ.get('COV_CORE_CONFIG') + if cov_config: + # Import what we need to activate coverage. + import coverage + + # Determine all source roots. + if not cov_source: + cov_source = None + else: + cov_source = cov_source.split(os.pathsep) + + # Activate coverage for this process. + cov = coverage.coverage(source=cov_source, + data_suffix=True, + config_file=cov_config, + auto_data=True) + cov.erase() + cov.start() + return cov diff --git a/src/pytest_cover/engine.py b/src/pytest_cover/engine.py index 3be20c6a..b2121c08 100644 --- a/src/pytest_cover/engine.py +++ b/src/pytest_cover/engine.py @@ -1,32 +1,9 @@ """Coverage controllers for use by pytest-cov and nose-cov.""" - - -import coverage +import os import socket import sys -import os - -def multiprocessing_start(obj): - from . import embed - cov = embed.init() - if cov: - 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 +import coverage class CovController(object): diff --git a/src/pytest_cover/plugin.py b/src/pytest_cover/plugin.py index 2e674ceb..7ce61037 100644 --- a/src/pytest_cover/plugin.py +++ b/src/pytest_cover/plugin.py @@ -1,11 +1,10 @@ """Coverage plugin for pytest.""" - import os import pytest -from . import engine from . import embed +from . import engine class CoverageError(Exception): @@ -167,7 +166,7 @@ def pytest_runtest_setup(self, item): def pytest_runtest_teardown(self, item): if self.cov is not None: - engine.multiprocessing_finish(self.cov) + embed.multiprocessing_finish(self.cov) self.cov = None From d8a12d91e2adae33e6bda91837cb46545e714c0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Sat, 6 Jun 2015 01:48:44 +0300 Subject: [PATCH 108/134] Update CI conf. --- .travis.yml | 15 +++++---------- appveyor.yml | 38 -------------------------------------- 2 files changed, 5 insertions(+), 48 deletions(-) diff --git a/.travis.yml b/.travis.yml index 80caf6f2..915592f0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,16 +6,11 @@ env: LD_PRELOAD=/lib/x86_64-linux-gnu/libSegFault.so matrix: - TOXENV=check - - TOXENV=2.6,coveralls - - TOXENV=2.6-nocover - - TOXENV=2.7,coveralls - - TOXENV=2.7-nocover - - TOXENV=3.3,coveralls - - TOXENV=3.3-nocover - - TOXENV=3.4,coveralls - - TOXENV=3.4-nocover - - TOXENV=pypy,coveralls - - TOXENV=pypy-nocover + - TOXENV=2.6 + - TOXENV=2.7 + - TOXENV=3.3 + - TOXENV=3.4 + - TOXENV=pypy before_install: - python --version - virtualenv --version diff --git a/appveyor.yml b/appveyor.yml index 251e22f8..ec342220 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -20,18 +20,6 @@ environment: PYTHON_HOME: "C:\\Python27-x64" PYTHON_VERSION: "2.7" PYTHON_ARCH: "64" - - TOXENV: "2.7-nocover" - TOXPYTHON: "C:\\Python27\\python.exe" - WINDOWS_SDK_VERSION: "v7.0" - PYTHON_HOME: "C:\\Python27" - PYTHON_VERSION: "2.7" - PYTHON_ARCH: "32" - - TOXENV: "2.7-nocover" - TOXPYTHON: "C:\\Python27-x64\\python.exe" - WINDOWS_SDK_VERSION: "v7.0" - PYTHON_HOME: "C:\\Python27-x64" - PYTHON_VERSION: "2.7" - PYTHON_ARCH: "64" - TOXENV: "3.3" TOXPYTHON: "C:\\Python33\\python.exe" WINDOWS_SDK_VERSION: "v7.1" @@ -44,18 +32,6 @@ environment: PYTHON_HOME: "C:\\Python33-x64" PYTHON_VERSION: "3.3" PYTHON_ARCH: "64" - - TOXENV: "3.3-nocover" - TOXPYTHON: "C:\\Python33\\python.exe" - WINDOWS_SDK_VERSION: "v7.1" - PYTHON_HOME: "C:\\Python33" - PYTHON_VERSION: "3.3" - PYTHON_ARCH: "32" - - TOXENV: "3.3-nocover" - TOXPYTHON: "C:\\Python33-x64\\python.exe" - WINDOWS_SDK_VERSION: "v7.1" - PYTHON_HOME: "C:\\Python33-x64" - PYTHON_VERSION: "3.3" - PYTHON_ARCH: "64" - TOXENV: "3.4" TOXPYTHON: "C:\\Python34\\python.exe" WINDOWS_SDK_VERSION: "v7.1" @@ -68,18 +44,6 @@ environment: PYTHON_HOME: "C:\\Python34-x64" PYTHON_VERSION: "3.4" PYTHON_ARCH: "64" - - TOXENV: "3.4-nocover" - TOXPYTHON: "C:\\Python34\\python.exe" - WINDOWS_SDK_VERSION: "v7.1" - PYTHON_HOME: "C:\\Python34" - PYTHON_VERSION: "3.4" - PYTHON_ARCH: "32" - - TOXENV: "3.4-nocover" - TOXPYTHON: "C:\\Python34-x64\\python.exe" - WINDOWS_SDK_VERSION: "v7.1" - PYTHON_HOME: "C:\\Python34-x64" - PYTHON_VERSION: "3.4" - PYTHON_ARCH: "64" init: - "ECHO %TOXENV%" - ps: "ls C:\\Python*" @@ -90,7 +54,5 @@ test_script: - "%PYTHON_HOME%\\Scripts\\virtualenv --version" - "%PYTHON_HOME%\\Scripts\\pip --version" - "%WITH_COMPILER% %PYTHON_HOME%\\Scripts\\tox" -after_test: - - "IF \"%TOXENV:~-8,8%\" == \"-nocover\" %WITH_COMPILER% %TOXPYTHON% setup.py bdist_wheel" artifacts: - path: dist\* From 308f61f7361b7f664e2f314f8c4ffd69e8e47df4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Sat, 6 Jun 2015 03:03:30 +0300 Subject: [PATCH 109/134] Add missing deps. --- setup.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup.py b/setup.py index ffa67eb8..dfb52a5d 100644 --- a/setup.py +++ b/setup.py @@ -119,6 +119,8 @@ def run(self): 'cover', 'coverage', 'pytest', 'py.test', 'distributed', 'parallel', ], install_requires=[ + 'pytest>=2.6.0', + 'coverage>=3.7.1' ], extras_require={ }, From e807665b5c09f303e4433eeca7c8a2c30f1c8290 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Sat, 6 Jun 2015 03:35:54 +0300 Subject: [PATCH 110/134] Test coverage 4.0 too. Loosen up a bit the tests (seems that in the report with 4.0 files show up with extension). --- .travis.yml | 15 ++++++++---- appveyor.yml | 50 +++++++++++++++++++++++++++++++++----- tests/test_pytest_cover.py | 36 +++++++++++++-------------- tox.ini | 33 ++++++------------------- 4 files changed, 79 insertions(+), 55 deletions(-) diff --git a/.travis.yml b/.travis.yml index 915592f0..1224b274 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,11 +6,16 @@ env: LD_PRELOAD=/lib/x86_64-linux-gnu/libSegFault.so matrix: - TOXENV=check - - TOXENV=2.6 - - TOXENV=2.7 - - TOXENV=3.3 - - TOXENV=3.4 - - TOXENV=pypy + - TOXENV=2.6-37 + - TOXENV=2.7-37 + - TOXENV=3.3-37 + - TOXENV=3.4-37 + - TOXENV=pypy-37 + - TOXENV=2.6-40 + - TOXENV=2.7-40 + - TOXENV=3.3-40 + - TOXENV=3.4-40 + - TOXENV=pypy-40 before_install: - python --version - virtualenv --version diff --git a/appveyor.yml b/appveyor.yml index ec342220..2d5de003 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -8,37 +8,75 @@ environment: PYTHON_HOME: "C:\\Python27" PYTHON_VERSION: "2.7" PYTHON_ARCH: "32" - - TOXENV: "2.7" + + - TOXENV: "2.7-37" TOXPYTHON: "C:\\Python27\\python.exe" WINDOWS_SDK_VERSION: "v7.0" PYTHON_HOME: "C:\\Python27" PYTHON_VERSION: "2.7" PYTHON_ARCH: "32" - - TOXENV: "2.7" + - TOXENV: "2.7-37" TOXPYTHON: "C:\\Python27-x64\\python.exe" WINDOWS_SDK_VERSION: "v7.0" PYTHON_HOME: "C:\\Python27-x64" PYTHON_VERSION: "2.7" PYTHON_ARCH: "64" - - TOXENV: "3.3" + - TOXENV: "3.3-37" TOXPYTHON: "C:\\Python33\\python.exe" WINDOWS_SDK_VERSION: "v7.1" PYTHON_HOME: "C:\\Python33" PYTHON_VERSION: "3.3" PYTHON_ARCH: "32" - - TOXENV: "3.3" + - TOXENV: "3.3-37" TOXPYTHON: "C:\\Python33-x64\\python.exe" WINDOWS_SDK_VERSION: "v7.1" PYTHON_HOME: "C:\\Python33-x64" PYTHON_VERSION: "3.3" PYTHON_ARCH: "64" - - TOXENV: "3.4" + - TOXENV: "3.4-37" TOXPYTHON: "C:\\Python34\\python.exe" WINDOWS_SDK_VERSION: "v7.1" PYTHON_HOME: "C:\\Python34" PYTHON_VERSION: "3.4" PYTHON_ARCH: "32" - - TOXENV: "3.4" + - TOXENV: "3.4-37" + TOXPYTHON: "C:\\Python34-x64\\python.exe" + WINDOWS_SDK_VERSION: "v7.1" + PYTHON_HOME: "C:\\Python34-x64" + PYTHON_VERSION: "3.4" + PYTHON_ARCH: "64" + + - TOXENV: "2.7-40" + TOXPYTHON: "C:\\Python27\\python.exe" + WINDOWS_SDK_VERSION: "v7.0" + PYTHON_HOME: "C:\\Python27" + PYTHON_VERSION: "2.7" + PYTHON_ARCH: "32" + - TOXENV: "2.7-40" + TOXPYTHON: "C:\\Python27-x64\\python.exe" + WINDOWS_SDK_VERSION: "v7.0" + PYTHON_HOME: "C:\\Python27-x64" + PYTHON_VERSION: "2.7" + PYTHON_ARCH: "64" + - TOXENV: "3.3-40" + TOXPYTHON: "C:\\Python33\\python.exe" + WINDOWS_SDK_VERSION: "v7.1" + PYTHON_HOME: "C:\\Python33" + PYTHON_VERSION: "3.3" + PYTHON_ARCH: "32" + - TOXENV: "3.3-40" + TOXPYTHON: "C:\\Python33-x64\\python.exe" + WINDOWS_SDK_VERSION: "v7.1" + PYTHON_HOME: "C:\\Python33-x64" + PYTHON_VERSION: "3.3" + PYTHON_ARCH: "64" + - TOXENV: "3.4-40" + TOXPYTHON: "C:\\Python34\\python.exe" + WINDOWS_SDK_VERSION: "v7.1" + PYTHON_HOME: "C:\\Python34" + PYTHON_VERSION: "3.4" + PYTHON_ARCH: "32" + - TOXENV: "3.4-40" TOXPYTHON: "C:\\Python34-x64\\python.exe" WINDOWS_SDK_VERSION: "v7.1" PYTHON_HOME: "C:\\Python34-x64" diff --git a/tests/test_pytest_cover.py b/tests/test_pytest_cover.py index eace33eb..82e70cdc 100644 --- a/tests/test_pytest_cover.py +++ b/tests/test_pytest_cover.py @@ -107,7 +107,7 @@ def test_central(testdir): result.stdout.fnmatch_lines([ '*- coverage: platform *, python * -*', - 'test_central * %s *' % SCRIPT_RESULT, + 'test_central* %s *' % SCRIPT_RESULT, '*10 passed*' ]) assert result.ret == 0 @@ -159,7 +159,7 @@ def test_central_nonspecific(testdir): result.stdout.fnmatch_lines([ '*- coverage: platform *, python * -*', - 'test_central_nonspecific * %s *' % SCRIPT_RESULT, + 'test_central_nonspecific* %s *' % SCRIPT_RESULT, '*10 passed*' ]) @@ -180,12 +180,12 @@ def test_central_coveragerc(testdir): result.stdout.fnmatch_lines([ '*- coverage: platform *, python * -*', - 'test_central_coveragerc * %s *' % SCRIPT_RESULT, + 'test_central_coveragerc* %s *' % SCRIPT_RESULT, '*10 passed*', ]) # single-module coverage report - assert result.stdout.lines[-3].startswith('test_central_coveragerc ') + assert result.stdout.lines[-3].startswith('test_central_coveragerc') assert result.ret == 0 @@ -215,7 +215,7 @@ def test_dist_collocated(testdir): result.stdout.fnmatch_lines([ '*- coverage: platform *, python * -*', - 'test_dist_collocated * %s *' % SCRIPT_RESULT, + 'test_dist_collocated* %s *' % SCRIPT_RESULT, '*10 passed*' ]) assert result.ret == 0 @@ -237,7 +237,7 @@ def test_dist_not_collocated(testdir): result.stdout.fnmatch_lines([ '*- coverage: platform *, python * -*', - 'test_dist_not_collocated * %s *' % SCRIPT_RESULT, + 'test_dist_not_collocated* %s *' % SCRIPT_RESULT, '*10 passed*' ]) assert result.ret == 0 @@ -255,8 +255,8 @@ def test_central_subprocess(testdir): result.stdout.fnmatch_lines([ '*- coverage: platform *, python * -*', - 'child_script * %s *' % CHILD_SCRIPT_RESULT, - 'parent_script * %s *' % PARENT_SCRIPT_RESULT, + 'child_script* %s *' % CHILD_SCRIPT_RESULT, + 'parent_script* %s *' % PARENT_SCRIPT_RESULT, ]) assert result.ret == 0 @@ -275,8 +275,8 @@ def test_dist_subprocess_collocated(testdir): result.stdout.fnmatch_lines([ '*- coverage: platform *, python * -*', - 'child_script * %s *' % CHILD_SCRIPT_RESULT, - 'parent_script * %s *' % PARENT_SCRIPT_RESULT, + 'child_script* %s *' % CHILD_SCRIPT_RESULT, + 'parent_script* %s *' % PARENT_SCRIPT_RESULT, ]) assert result.ret == 0 @@ -302,8 +302,8 @@ def test_dist_subprocess_not_collocated(testdir, tmpdir): result.stdout.fnmatch_lines([ '*- coverage: platform *, python * -*', - 'child_script * %s *' % CHILD_SCRIPT_RESULT, - 'parent_script * %s *' % PARENT_SCRIPT_RESULT, + 'child_script* %s *' % CHILD_SCRIPT_RESULT, + 'parent_script* %s *' % PARENT_SCRIPT_RESULT, ]) assert result.ret == 0 @@ -358,7 +358,7 @@ def test_funcarg(testdir): result.stdout.fnmatch_lines([ '*- coverage: platform *, python * -*', - 'test_funcarg * 3 * 100%*', + 'test_funcarg* 3 * 100%*', '*1 passed*' ]) assert result.ret == 0 @@ -388,7 +388,7 @@ def test_multiprocessing_subprocess(testdir): result.stdout.fnmatch_lines([ '*- coverage: platform *, python * -*', - 'test_multiprocessing_subprocess * 8 * 100%*', + 'test_multiprocessing_subprocess* 8 * 100%*', '*1 passed*' ]) assert result.ret == 0 @@ -415,7 +415,7 @@ def test_basic(): ''' -CONF_RESULT = 'mod * 2 * 100% *' +CONF_RESULT = 'mod* 2 * 100% *' def test_cover_conftest(testdir): @@ -475,7 +475,7 @@ def test_coveragerc(testdir): '--cov-report=term-missing', script) assert result.ret == 0 - result.stdout.fnmatch_lines(['test_coveragerc * %s' % EXCLUDED_RESULT]) + result.stdout.fnmatch_lines(['test_coveragerc* %s' % EXCLUDED_RESULT]) def test_coveragerc_dist(testdir): @@ -489,7 +489,7 @@ def test_coveragerc_dist(testdir): script) assert result.ret == 0 result.stdout.fnmatch_lines( - ['test_coveragerc_dist * %s' % EXCLUDED_RESULT]) + ['test_coveragerc_dist* %s' % EXCLUDED_RESULT]) CLEAR_ENVIRON_TEST = ''' @@ -534,7 +534,7 @@ def test_dist_boxed(testdir): result.stdout.fnmatch_lines([ '*- coverage: platform *, python * -*', - 'test_dist_boxed * %s*' % SCRIPT_SIMPLE_RESULT, + 'test_dist_boxed* %s*' % SCRIPT_SIMPLE_RESULT, '*1 passed*' ]) assert result.ret == 0 diff --git a/tox.ini b/tox.ini index 7b12ca3f..f922a5af 100644 --- a/tox.ini +++ b/tox.ini @@ -2,10 +2,8 @@ [tox] envlist = - clean, check, - {2.6,2.7,3.3,3.4,pypy}, - report, + {2.6,2.7,3.3,3.4,pypy}-{37,40}, docs [testenv] @@ -22,11 +20,14 @@ setenv = passenv = * deps = - pytest + pytest==2.7.1 pytest-capturelog - coverage + 37: coverage==3.7.1 + 40: coverage==4.0a5 virtualenv - pytest-xdist + pytest-xdist==1.12 +pip_pre = true + commands = {posargs:py.test -vv} usedevelop = false @@ -66,25 +67,5 @@ commands = check-manifest {toxinidir} flake8 src -[testenv:coveralls] -deps = - coveralls -usedevelop = true -commands = - coverage combine - coverage report - coveralls -[testenv:report] -basepython = python3.4 -commands = - coverage combine - coverage report -usedevelop = true -deps = coverage - -[testenv:clean] -commands = coverage erase -usedevelop = true -deps = coverage From e450a1cbc973b4a0a6c294085284c4eed0eb7c61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Sat, 6 Jun 2015 22:23:55 +0300 Subject: [PATCH 111/134] Update changelog. --- CHANGELOG.rst | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 67240076..edea7f86 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -4,11 +4,18 @@ Changelog 1.0.0 (2015-06-05) ------------------ -* Forked from the `2.0` branch of https://github.com/schlamar/pytest-cov/ * Fixed `.pth` installation to work in all cases (install, easy_install, wheels, develop etc). * Fixed `.pth` uninstallation to work for wheel installs. * Reverted the unreleased ``--cov=path`` deprecation. * Removed the unreleased addition of ``--cov-source=path``. +----- + +* Forked from the `2.0` branch of https://github.com/schlamar/pytest-cov/ - fixes include: + + * No need to specify the source anymore via ``--cov``. The source settings from + ``.coveragerc`` will be used instead. + * Support for ``--cov-min``. + From 1c62766dbe60220de3398d146718a0eedaa087e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Thu, 18 Jun 2015 13:51:02 +0300 Subject: [PATCH 112/134] Add .env to ignores. --- .gitignore | 1 + setup.cfg | 1 + 2 files changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 88b9214b..8365f940 100644 --- a/.gitignore +++ b/.gitignore @@ -53,5 +53,6 @@ docs/_build .*.sw[po] .build .ve +.env .bootstrap *.bak diff --git a/setup.cfg b/setup.cfg index c6c0e2bc..e7e42f25 100644 --- a/setup.cfg +++ b/setup.cfg @@ -18,6 +18,7 @@ tag = True norecursedirs = .git .tox + .env dist build south_migrations From e6b30882672d9205f4ca8d6370b56ebe881001d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Thu, 18 Jun 2015 13:51:50 +0300 Subject: [PATCH 113/134] Change a bit test_central_nonspecific and the test to actually trigger library coverage. --- tests/test_pytest_cover.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/test_pytest_cover.py b/tests/test_pytest_cover.py index 82e70cdc..e6e16ef7 100644 --- a/tests/test_pytest_cover.py +++ b/tests/test_pytest_cover.py @@ -1,4 +1,5 @@ import os +from pprint import pprint import sys import virtualenv @@ -12,7 +13,7 @@ pytest_plugins = 'pytester', 'cov' SCRIPT = ''' -import sys +import sys, pprint def pytest_generate_tests(metafunc): for i in range(10): @@ -20,7 +21,7 @@ def pytest_generate_tests(metafunc): def test_foo(): x = True - assert x + assert pprint.pformat(x) # get some library coverage if sys.version_info[0] > 5: assert False ''' From e74f7d71516b526773e6939035ecee239f95b2be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Sat, 20 Jun 2015 15:58:38 +0300 Subject: [PATCH 114/134] Reformat. --- tests/test_pytest_cover.py | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/tests/test_pytest_cover.py b/tests/test_pytest_cover.py index e6e16ef7..e657eb56 100644 --- a/tests/test_pytest_cover.py +++ b/tests/test_pytest_cover.py @@ -1,5 +1,4 @@ import os -from pprint import pprint import sys import virtualenv @@ -9,7 +8,6 @@ import subprocess import pytest_cover.plugin - pytest_plugins = 'pytester', 'cov' SCRIPT = ''' @@ -86,7 +84,6 @@ def test_run_target(): p.join() ''' - SCRIPT_FAIL = ''' def test_fail(): assert False @@ -110,7 +107,7 @@ def test_central(testdir): '*- coverage: platform *, python * -*', 'test_central* %s *' % SCRIPT_RESULT, '*10 passed*' - ]) + ]) assert result.ret == 0 @@ -162,7 +159,7 @@ def test_central_nonspecific(testdir): '*- coverage: platform *, python * -*', 'test_central_nonspecific* %s *' % SCRIPT_RESULT, '*10 passed*' - ]) + ]) # multi-module coverage report assert result.stdout.lines[-3].startswith('TOTAL ') @@ -183,7 +180,7 @@ def test_central_coveragerc(testdir): '*- coverage: platform *, python * -*', 'test_central_coveragerc* %s *' % SCRIPT_RESULT, '*10 passed*', - ]) + ]) # single-module coverage report assert result.stdout.lines[-3].startswith('test_central_coveragerc') @@ -218,7 +215,7 @@ def test_dist_collocated(testdir): '*- coverage: platform *, python * -*', 'test_dist_collocated* %s *' % SCRIPT_RESULT, '*10 passed*' - ]) + ]) assert result.ret == 0 @@ -240,7 +237,7 @@ def test_dist_not_collocated(testdir): '*- coverage: platform *, python * -*', 'test_dist_not_collocated* %s *' % SCRIPT_RESULT, '*10 passed*' - ]) + ]) assert result.ret == 0 @@ -258,7 +255,7 @@ def test_central_subprocess(testdir): '*- coverage: platform *, python * -*', 'child_script* %s *' % CHILD_SCRIPT_RESULT, 'parent_script* %s *' % PARENT_SCRIPT_RESULT, - ]) + ]) assert result.ret == 0 @@ -278,7 +275,7 @@ def test_dist_subprocess_collocated(testdir): '*- coverage: platform *, python * -*', 'child_script* %s *' % CHILD_SCRIPT_RESULT, 'parent_script* %s *' % PARENT_SCRIPT_RESULT, - ]) + ]) assert result.ret == 0 @@ -305,7 +302,7 @@ def test_dist_subprocess_not_collocated(testdir, tmpdir): '*- coverage: platform *, python * -*', 'child_script* %s *' % CHILD_SCRIPT_RESULT, 'parent_script* %s *' % PARENT_SCRIPT_RESULT, - ]) + ]) assert result.ret == 0 @@ -320,7 +317,7 @@ def test_empty_report(testdir): result.stdout.fnmatch_lines([ '*- coverage: platform *, python * -*', '*10 passed*' - ]) + ]) assert result.ret == 0 matching_lines = [line for line in result.outlines if '%' in line] assert not matching_lines @@ -345,7 +342,7 @@ def test_dist_missing_data(testdir): result.stdout.fnmatch_lines([ '*- coverage: failed slaves -*' - ]) + ]) assert result.ret == 0 @@ -361,7 +358,7 @@ def test_funcarg(testdir): '*- coverage: platform *, python * -*', 'test_funcarg* 3 * 100%*', '*1 passed*' - ]) + ]) assert result.ret == 0 @@ -373,7 +370,7 @@ def test_funcarg_not_active(testdir): result.stdout.fnmatch_lines([ '*1 passed*' - ]) + ]) assert result.ret == 0 @@ -391,7 +388,7 @@ def test_multiprocessing_subprocess(testdir): '*- coverage: platform *, python * -*', 'test_multiprocessing_subprocess* 8 * 100%*', '*1 passed*' - ]) + ]) assert result.ret == 0 @@ -537,7 +534,7 @@ def test_dist_boxed(testdir): '*- coverage: platform *, python * -*', 'test_dist_boxed* %s*' % SCRIPT_SIMPLE_RESULT, '*1 passed*' - ]) + ]) assert result.ret == 0 From 7ee700f9dc81339d2d4d40b0b1f272acf698d2ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Sat, 20 Jun 2015 17:02:29 +0300 Subject: [PATCH 115/134] Change a bit the test so the external code is non-stdlib. --- tests/test_pytest_cover.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_pytest_cover.py b/tests/test_pytest_cover.py index e657eb56..cbe147e4 100644 --- a/tests/test_pytest_cover.py +++ b/tests/test_pytest_cover.py @@ -11,7 +11,7 @@ pytest_plugins = 'pytester', 'cov' SCRIPT = ''' -import sys, pprint +import sys, pytest def pytest_generate_tests(metafunc): for i in range(10): @@ -19,7 +19,7 @@ def pytest_generate_tests(metafunc): def test_foo(): x = True - assert pprint.pformat(x) # get some library coverage + pytest.importorskip('sys') # get some library coverage if sys.version_info[0] > 5: assert False ''' From 2f9c530c07778b87650dc9fea2e2bc86c43f4272 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Sat, 20 Jun 2015 17:31:50 +0300 Subject: [PATCH 116/134] Use a helper module in a different location to test that inclue paths are properly applied. --- tests/helper.py | 3 +++ tests/test_pytest_cover.py | 4 ++-- tox.ini | 1 + 3 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 tests/helper.py diff --git a/tests/helper.py b/tests/helper.py new file mode 100644 index 00000000..3e7da4bb --- /dev/null +++ b/tests/helper.py @@ -0,0 +1,3 @@ +def do_stuff(): + a = 1 + return a diff --git a/tests/test_pytest_cover.py b/tests/test_pytest_cover.py index cbe147e4..61c8ba13 100644 --- a/tests/test_pytest_cover.py +++ b/tests/test_pytest_cover.py @@ -11,7 +11,7 @@ pytest_plugins = 'pytester', 'cov' SCRIPT = ''' -import sys, pytest +import sys, helper def pytest_generate_tests(metafunc): for i in range(10): @@ -19,7 +19,7 @@ def pytest_generate_tests(metafunc): def test_foo(): x = True - pytest.importorskip('sys') # get some library coverage + helper.do_stuff() # get some coverage in some other completely different location if sys.version_info[0] > 5: assert False ''' diff --git a/tox.ini b/tox.ini index f922a5af..0e171104 100644 --- a/tox.ini +++ b/tox.ini @@ -26,6 +26,7 @@ deps = 40: coverage==4.0a5 virtualenv pytest-xdist==1.12 + pytest-cache==1.0.0 pip_pre = true commands = From 8c4c5b8ab7cebbaa6e7a21b1f6733a0eaa1ad370 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Sun, 21 Jun 2015 21:14:48 +0300 Subject: [PATCH 117/134] Use new 4.0 release. --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 0e171104..e441da6b 100644 --- a/tox.ini +++ b/tox.ini @@ -23,7 +23,7 @@ deps = pytest==2.7.1 pytest-capturelog 37: coverage==3.7.1 - 40: coverage==4.0a5 + 40: coverage==4.0a6 virtualenv pytest-xdist==1.12 pytest-cache==1.0.0 From 098ed9b094d7df2bae5f9dfc0493829df930a0ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Sun, 28 Jun 2015 19:56:32 +0300 Subject: [PATCH 118/134] Test that --cov-report=term will report missing lines if .coveragerc has show_missing=true. Ref #1. --- tests/test_pytest_cover.py | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/tests/test_pytest_cover.py b/tests/test_pytest_cover.py index 61c8ba13..3e18f875 100644 --- a/tests/test_pytest_cover.py +++ b/tests/test_pytest_cover.py @@ -1,11 +1,10 @@ import os import sys +import subprocess import virtualenv - import py import pytest -import subprocess import pytest_cover.plugin pytest_plugins = 'pytester', 'cov' @@ -188,6 +187,34 @@ def test_central_coveragerc(testdir): assert result.ret == 0 +def test_show_missing_coveragerc(testdir): + script = testdir.makepyfile(SCRIPT) + testdir.tmpdir.join('.coveragerc').write(""" +[run] +source = . + +[report] +show_missing = true +""") + + result = testdir.runpytest('-v', + '--cov', + '--cov-report=term', + script) + + result.stdout.fnmatch_lines([ + '*- coverage: platform *, python * -*', + 'Name * Stmts * Miss * Cover * Missing', + 'test_show_missing_coveragerc* %s * 11' % SCRIPT_RESULT, + '*10 passed*', + ]) + + # single-module coverage report + assert result.stdout.lines[-3].startswith('test_show_missing_coveragerc') + + assert result.ret == 0 + + def test_no_cov_on_fail(testdir): script = testdir.makepyfile(SCRIPT_FAIL) From 9841727b211609c46467eb44b31a0ca1c3636edd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Sun, 28 Jun 2015 19:57:48 +0300 Subject: [PATCH 119/134] If `term-missing` is not specified then use `None` instead of `False` for `show_missing` option. This allows the `show_missing` specified in .coveragerc to be used. Ref #1. --- src/pytest_cover/engine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pytest_cover/engine.py b/src/pytest_cover/engine.py index b2121c08..4c867cd9 100644 --- a/src/pytest_cover/engine.py +++ b/src/pytest_cover/engine.py @@ -72,7 +72,7 @@ def summary(self, stream): # 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 + show_missing = ('term-missing' in self.cov_report) or None total = self.cov.report(show_missing=show_missing, ignore_errors=True, file=stream) # Produce annotated source code report if wanted. From 97e4b22d6f1ca74ecc911119c6770c2e47170205 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Sun, 28 Jun 2015 22:36:34 +0300 Subject: [PATCH 120/134] Load default cov_min from `[report]fail_under` (if coverage is 4.0). Ref #2. --- src/pytest_cover/plugin.py | 3 +++ tests/test_pytest_cover.py | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/pytest_cover/plugin.py b/src/pytest_cover/plugin.py index 7ce61037..11d720fe 100644 --- a/src/pytest_cover/plugin.py +++ b/src/pytest_cover/plugin.py @@ -113,6 +113,9 @@ class Config(object): nodeid ) self.cov_controller.start() + cov_config = self.cov_controller.cov.config + if self.options.cov_min is None and hasattr(cov_config, 'fail_under'): + self.options.cov_min = cov_config.fail_under def pytest_sessionstart(self, session): """At session start determine our implementation and delegate to it.""" diff --git a/tests/test_pytest_cover.py b/tests/test_pytest_cover.py index 3e18f875..d397b7c5 100644 --- a/tests/test_pytest_cover.py +++ b/tests/test_pytest_cover.py @@ -1,7 +1,9 @@ +from distutils.version import StrictVersion import os import sys import subprocess +import coverage import virtualenv import py import pytest @@ -166,6 +168,22 @@ def test_central_nonspecific(testdir): assert result.ret == 0 +@pytest.mark.skipif('StrictVersion(coverage.__version__) <= StrictVersion("3.8")') +def test_cov_min_from_coveragerc(testdir): + script = testdir.makepyfile(SCRIPT) + testdir.tmpdir.join('.coveragerc').write(""" +[report] +fail_under = 100 +""") + + result = testdir.runpytest('-v', + '--cov=%s' % script.dirpath(), + '--cov-report=term-missing', + script) + + assert result.ret == 1 + + def test_central_coveragerc(testdir): script = testdir.makepyfile(SCRIPT) testdir.tmpdir.join('.coveragerc').write(COVERAGERC_SOURCE) From 10a54f17c4435cd8ce5eabf44ecbec8d020708c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Sun, 28 Jun 2015 22:51:05 +0300 Subject: [PATCH 121/134] Rename --cov-min to --cov-fail-under. --- src/pytest_cover/plugin.py | 2 +- tests/test_pytest_cover.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pytest_cover/plugin.py b/src/pytest_cover/plugin.py index 11d720fe..1febf0f1 100644 --- a/src/pytest_cover/plugin.py +++ b/src/pytest_cover/plugin.py @@ -33,7 +33,7 @@ def pytest_addoption(parser): dest='no_cov_on_fail', help='do not report coverage if test run fails, ' 'default: False') - group.addoption('--cov-min', action='store', metavar='MIN', type='int', + group.addoption('--cov-fail-under', action='store', metavar='MIN', type='int', help='Fail if the total coverage is less than MIN.') diff --git a/tests/test_pytest_cover.py b/tests/test_pytest_cover.py index d397b7c5..87ddcbe5 100644 --- a/tests/test_pytest_cover.py +++ b/tests/test_pytest_cover.py @@ -118,7 +118,7 @@ def test_cov_min_100(testdir): result = testdir.runpytest('-v', '--cov=%s' % script.dirpath(), '--cov-report=term-missing', - '--cov-min=100', + '--cov-fail-under=100', script) assert result.ret == 1 @@ -130,7 +130,7 @@ def test_cov_min_50(testdir): result = testdir.runpytest('-v', '--cov=%s' % script.dirpath(), '--cov-report=term-missing', - '--cov-min=50', + '--cov-fail-under=50', script) assert result.ret == 0 @@ -142,7 +142,7 @@ def test_cov_min_no_report(testdir): result = testdir.runpytest('-v', '--cov=%s' % script.dirpath(), '--cov-report=', - '--cov-min=50', + '--cov-fail-under=50', script) assert result.ret == 0 From 90a6e35f11512b376992709516ee2494aa286ee4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Sun, 28 Jun 2015 22:52:15 +0300 Subject: [PATCH 122/134] Update changelog. Closes #1. Closes #2. --- CHANGELOG.rst | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index edea7f86..2d3ba20c 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,14 @@ Changelog ========= +2.0.0 (??????????) +------------------ + +* Renamed ``--cov-min`` to ``--cov-fail-under`` to be consistent with the new ``fail_under`` option in `coverage-4.0`. +* Changed ``--cov-report=term`` to automatically upgrade to ``--cov-report=term-missing`` if there's ``[run] show_missing = True`` in + ``.coveragerc``. +* Changed ``--cov-fail-under`` to be automatically activated if there's a ``[report] fail_under =`` in ``.coveragerc``. + 1.0.0 (2015-06-05) ------------------ @@ -13,7 +21,7 @@ Changelog * Forked from the `2.0` branch of https://github.com/schlamar/pytest-cov/ - fixes include: - * No need to specify the source anymore via ``--cov``. The source settings from + * No need to specify the source anymore via ``--cov``. The source settings from ``.coveragerc`` will be used instead. * Support for ``--cov-min``. From cbebaa356c4d3bb59387a76308bd417cc45df7c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Sun, 28 Jun 2015 23:01:13 +0300 Subject: [PATCH 123/134] Update skel a bit. --- .gitignore | 2 ++ MANIFEST.in | 2 +- README.rst | 36 +++++++++++++++++++++++++----------- docs/conf.py | 15 +++++++-------- setup.cfg | 5 ++++- 5 files changed, 39 insertions(+), 21 deletions(-) diff --git a/.gitignore b/.gitignore index 8365f940..01f10962 100644 --- a/.gitignore +++ b/.gitignore @@ -54,5 +54,7 @@ docs/_build .build .ve .env +.cache +.pytest .bootstrap *.bak diff --git a/MANIFEST.in b/MANIFEST.in index 69475e23..e64932b8 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -4,9 +4,9 @@ graft src graft ci graft tests -include *.komodoproject include .bumpversion.cfg include .coveragerc +include .cookiecutterrc include .isort.cfg include .pylintrc diff --git a/README.rst b/README.rst index 8de31d54..7e10ac9d 100644 --- a/README.rst +++ b/README.rst @@ -2,50 +2,64 @@ pytest-cover =============================== -| |docs| |travis| |appveyor| -| |version| |downloads| |wheel| |supported-versions| |supported-implementations| +.. list-table:: + :stub-columns: 1 + + * - docs + - |docs| + * - tests + - | |travis| |appveyor| + * - package + - |version| |downloads| + +.. + |wheel| |supported-versions| |supported-implementations| .. |docs| image:: https://readthedocs.org/projects/pytest-cover/badge/?style=flat :target: https://readthedocs.org/projects/pytest-cover :alt: Documentation Status -.. |travis| image:: http://img.shields.io/travis/ionelmc/pytest-cover/master.png?style=flat +.. |travis| image:: http://img.shields.io/travis/ionelmc/pytest-cover/master.svg?style=flat&label=Travis :alt: Travis-CI Build Status :target: https://travis-ci.org/ionelmc/pytest-cover -.. |appveyor| image:: https://ci.appveyor.com/api/projects/status/github/ionelmc/pytest-cover?branch=master +.. |appveyor| image:: https://img.shields.io/appveyor/ci/ionelmc/pytest-cover/master.svg?style=flat&label=AppVeyor :alt: AppVeyor Build Status :target: https://ci.appveyor.com/project/ionelmc/pytest-cover -.. |coveralls| image:: http://img.shields.io/coveralls/ionelmc/pytest-cover/master.png?style=flat +.. |coveralls| image:: http://img.shields.io/coveralls/ionelmc/pytest-cover/master.svg?style=flat&label=Coveralls :alt: Coverage Status :target: https://coveralls.io/r/ionelmc/pytest-cover +.. |codecov| image:: http://img.shields.io/codecov/c/github/ionelmc/pytest-cover/master.svg?style=flat&label=Codecov + :alt: Coverage Status + :target: https://codecov.io/github/ionelmc/pytest-cover + .. |landscape| image:: https://landscape.io/github/ionelmc/pytest-cover/master/landscape.svg?style=flat :target: https://landscape.io/github/ionelmc/pytest-cover/master :alt: Code Quality Status -.. |version| image:: http://img.shields.io/pypi/v/pytest-cover.png?style=flat +.. |version| image:: http://img.shields.io/pypi/v/pytest-cover.svg?style=flat :alt: PyPI Package latest release :target: https://pypi.python.org/pypi/pytest-cover -.. |downloads| image:: http://img.shields.io/pypi/dm/pytest-cover.png?style=flat +.. |downloads| image:: http://img.shields.io/pypi/dm/pytest-cover.svg?style=flat :alt: PyPI Package monthly downloads :target: https://pypi.python.org/pypi/pytest-cover -.. |wheel| image:: https://pypip.in/wheel/pytest-cover/badge.png?style=flat +.. |wheel| image:: https://pypip.in/wheel/pytest-cover/badge.svg?style=flat :alt: PyPI Wheel :target: https://pypi.python.org/pypi/pytest-cover -.. |supported-versions| image:: https://pypip.in/py_versions/pytest-cover/badge.png?style=flat +.. |supported-versions| image:: https://pypip.in/py_versions/pytest-cover/badge.svg?style=flat :alt: Supported versions :target: https://pypi.python.org/pypi/pytest-cover -.. |supported-implementations| image:: https://pypip.in/implementation/pytest-cover/badge.png?style=flat +.. |supported-implementations| image:: https://pypip.in/implementation/pytest-cover/badge.svg?style=flat :alt: Supported imlementations :target: https://pypi.python.org/pypi/pytest-cover -.. |scrutinizer| image:: https://img.shields.io/scrutinizer/g/ionelmc/pytest-cover/master.png?style=flat +.. |scrutinizer| image:: https://img.shields.io/scrutinizer/g/ionelmc/pytest-cover/master.svg?style=flat :alt: Scrutinizer Status :target: https://scrutinizer-ci.com/g/ionelmc/pytest-cover/ diff --git a/docs/conf.py b/docs/conf.py index 42fc5872..65c15d84 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -20,15 +20,17 @@ source_suffix = '.rst' master_doc = 'index' -project = u'pytest-cover' -year = u'2015' -author = u'Ionel Cristian M\u0103rie\u0219' +project = 'pytest-cover' +year = '2015' +author = 'Ionel Cristian Mărieș' copyright = '{0}, {1}'.format(year, author) -version = release = u'0.1.0' - +version = release = '1.0.0' import sphinx_py3doc_enhanced_theme html_theme = "sphinx_py3doc_enhanced_theme" html_theme_path = [sphinx_py3doc_enhanced_theme.get_html_theme_path()] +html_theme_options = { + 'githuburl': 'https://github.com/ionelmc/pytest-cover/' +} pygments_style = 'trac' templates_path = ['.'] @@ -39,6 +41,3 @@ '**': ['searchbox.html', 'globaltoc.html', 'sourcelink.html'], } html_short_title = '%s-%s' % (project, version) -html_theme_options = { - 'githuburl': 'https://github.com/ionelmc/pytest-cover/' -} diff --git a/setup.cfg b/setup.cfg index e7e42f25..b41424e7 100644 --- a/setup.cfg +++ b/setup.cfg @@ -10,10 +10,13 @@ exclude = tests/*,*/migrations/*,*/south_migrations/* [bumpversion] current_version = 0.1.0 -files = setup.py docs/conf.py src/pytest_cover/__init__.py commit = True tag = True +[bumpversion:file:setup.py] +[bumpversion:file:docs/conf.py] +[bumpversion:file:src/pytest_cover/__init__.py] + [pytest] norecursedirs = .git From 076045f12a1419078cda886df3a57297c2fe2174 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Sun, 28 Jun 2015 23:04:31 +0300 Subject: [PATCH 124/134] Fix incorrect renaming. --- src/pytest_cover/plugin.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/pytest_cover/plugin.py b/src/pytest_cover/plugin.py index 1febf0f1..7abb0bef 100644 --- a/src/pytest_cover/plugin.py +++ b/src/pytest_cover/plugin.py @@ -114,8 +114,8 @@ class Config(object): ) self.cov_controller.start() cov_config = self.cov_controller.cov.config - if self.options.cov_min is None and hasattr(cov_config, 'fail_under'): - self.options.cov_min = cov_config.fail_under + if self.options.cov_fail_under is None and hasattr(cov_config, 'fail_under'): + self.options.cov_fail_under = cov_config.fail_under def pytest_sessionstart(self, session): """At session start determine our implementation and delegate to it.""" @@ -155,11 +155,11 @@ def pytest_terminal_summary(self, terminalreporter): if not (self.failed and self.options.no_cov_on_fail): total = self.cov_controller.summary(terminalreporter.writer) assert total is not None, 'Test coverage should never be `None`' - cov_min = self.options.cov_min - if cov_min is not None and total < cov_min: + cov_fail_under = self.options.cov_fail_under + if cov_fail_under is not None and total < cov_fail_under: raise CoverageError(('Required test coverage of %d%% not ' 'reached. Total coverage: %.2f%%') - % (self.options.cov_min, total)) + % (self.options.cov_fail_under, total)) def pytest_runtest_setup(self, item): if os.getpid() != self.pid: From 781a9e936ced449dd99e228ab7902c41da0e5f07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Mon, 29 Jun 2015 11:22:31 +0300 Subject: [PATCH 125/134] Update changelog. --- CHANGELOG.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 2d3ba20c..f20df406 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,13 +1,13 @@ Changelog ========= -2.0.0 (??????????) +2.0.0 (2015-06-29) ------------------ * Renamed ``--cov-min`` to ``--cov-fail-under`` to be consistent with the new ``fail_under`` option in `coverage-4.0`. * Changed ``--cov-report=term`` to automatically upgrade to ``--cov-report=term-missing`` if there's ``[run] show_missing = True`` in ``.coveragerc``. -* Changed ``--cov-fail-under`` to be automatically activated if there's a ``[report] fail_under =`` in ``.coveragerc``. +* Changed ``--cov-fail-under`` to be automatically activated if there's a ``[report] fail_under = ...`` in ``.coveragerc``. 1.0.0 (2015-06-05) ------------------ From c25b99645df7ee04e1c0f731ccf5ba24f9b97915 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Mon, 29 Jun 2015 11:27:14 +0300 Subject: [PATCH 126/134] Unicodes --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index dfb52a5d..fa8828e7 100644 --- a/setup.py +++ b/setup.py @@ -88,7 +88,7 @@ def run(self): long_description='%s\n%s' % (read('README.rst'), re.sub(':[a-z]+:`~?(.*?)`', r'``\1``', read('CHANGELOG.rst'))), author='Marc Schlaich', author_email='marc.schlaich@gmail.com', - maintainer='Ionel Cristian M\u0103rie\u0219', + maintainer='Ionel Cristian Mărieș', maintainer_email='contact@ionelmc.ro', url='https://github.com/ionelmc/pytest-cover', packages=find_packages('src'), From 2cfebe5aca4066282287911e89ca61292ab8433e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Mon, 29 Jun 2015 11:39:01 +0300 Subject: [PATCH 127/134] Fix version. --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index b41424e7..173b20ae 100644 --- a/setup.cfg +++ b/setup.cfg @@ -9,7 +9,7 @@ max-line-length = 140 exclude = tests/*,*/migrations/*,*/south_migrations/* [bumpversion] -current_version = 0.1.0 +current_version = 1.0.0 commit = True tag = True From 3439cf4e899f97be536844722b0cb3e3b9059b6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Mon, 29 Jun 2015 11:39:03 +0300 Subject: [PATCH 128/134] =?UTF-8?q?Bump=20version:=201.0.0=20=E2=86=92=202?= =?UTF-8?q?.0.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/conf.py | 2 +- setup.cfg | 119 ++++++++++++++--------------------- setup.py | 2 +- src/pytest_cover/__init__.py | 2 +- 4 files changed, 50 insertions(+), 75 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 65c15d84..1eca1fc7 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -24,7 +24,7 @@ year = '2015' author = 'Ionel Cristian Mărieș' copyright = '{0}, {1}'.format(year, author) -version = release = '1.0.0' +version = release = '2.0.0' import sphinx_py3doc_enhanced_theme html_theme = "sphinx_py3doc_enhanced_theme" html_theme_path = [sphinx_py3doc_enhanced_theme.get_html_theme_path()] diff --git a/setup.cfg b/setup.cfg index 173b20ae..a30ce397 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,3 +1,8 @@ +[bumpversion] +current_version = 2.0.0 +commit = True +tag = True + [bdist_wheel] universal = 1 @@ -8,85 +13,55 @@ release = register clean --all sdist bdist_wheel max-line-length = 140 exclude = tests/*,*/migrations/*,*/south_migrations/* -[bumpversion] -current_version = 1.0.0 -commit = True -tag = True - [bumpversion:file:setup.py] + [bumpversion:file:docs/conf.py] + [bumpversion:file:src/pytest_cover/__init__.py] [pytest] -norecursedirs = - .git - .tox - .env - dist - build - south_migrations - migrations - example -python_files = - test_*.py - *_test.py - tests.py -addopts = - -rxEfs - --strict - --ignore=docs/conf.py - --ignore=setup.py - --ignore=src - --ignore=ci - --doctest-modules - --doctest-glob=\*.rst - --tb=short +norecursedirs = + .git + .tox + .env + dist + build + south_migrations + migrations + example +python_files = + test_*.py + *_test.py + tests.py +addopts = + -rxEfs + --strict + --ignore=docs/conf.py + --ignore=setup.py + --ignore=src + --ignore=ci + --doctest-modules + --doctest-glob=\*.rst + --tb=short [isort] -force_single_line=True -line_length=120 -known_first_party=pytest_cover -default_section=THIRDPARTY -forced_separate=test_pytest_cover +force_single_line = True +line_length = 120 +known_first_party = pytest_cover +default_section = THIRDPARTY +forced_separate = test_pytest_cover [matrix] -# This is the configuration for the `./bootstrap.py` script. -# It generates `.travis.yml`, `tox.ini` and `appveyor.yml`. -# -# Syntax: [alias:] value [!variable[glob]] [&variable[glob]] -# -# alias: -# - is used to generate the tox environment -# - it's optional -# - if not present the alias will be computed from the `value` -# value: -# - a value of "-" means empty -# !variable[glob]: -# - exclude the combination of the current `value` with -# any value matching the `glob` in `variable` -# - can use as many you want -# &variable[glob]: -# - only include the combination of the current `value` -# when there's a value matching `glob` in `variable` -# - can use as many you want - -python_versions = - 2.6 - 2.7 - 3.3 - 3.4 - pypy - -dependencies = -# 1.4: Django==1.4.16 !python_versions[3.*] -# 1.5: Django==1.5.11 -# 1.6: Django==1.6.8 -# 1.7: Django==1.7.1 !python_versions[2.6] -# Deps commented above are provided as examples. That's what you would use in a Django project. - -coverage_flags = - : true - nocover: false +python_versions = + 2.6 + 2.7 + 3.3 + 3.4 + pypy +dependencies = +coverage_flags = + : true + nocover: false +environment_variables = + - -environment_variables = - - diff --git a/setup.py b/setup.py index fa8828e7..33002e24 100644 --- a/setup.py +++ b/setup.py @@ -82,7 +82,7 @@ def run(self): setup( name='pytest-cover', - version='1.0.0', + version='2.0.0', license='MIT', description='Pytest plugin for measuring coverage. Forked from `pytest-cov`.', long_description='%s\n%s' % (read('README.rst'), re.sub(':[a-z]+:`~?(.*?)`', r'``\1``', read('CHANGELOG.rst'))), diff --git a/src/pytest_cover/__init__.py b/src/pytest_cover/__init__.py index 5becc17c..8c0d5d5b 100644 --- a/src/pytest_cover/__init__.py +++ b/src/pytest_cover/__init__.py @@ -1 +1 @@ -__version__ = "1.0.0" +__version__ = "2.0.0" From c1f29b5192647800af174a5bf8219214fafcacb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Tue, 30 Jun 2015 20:37:14 +0300 Subject: [PATCH 129/134] Unfork project (rename back to pytest-cov). --- CHANGELOG.rst | 28 +++---- CONTRIBUTING.rst | 26 +++---- LICENSE | 29 +++++--- README.rst | 77 +++++++++++--------- docs/conf.py | 4 +- docs/index.rst | 2 +- docs/installation.rst | 2 +- docs/reference/index.rst | 2 +- docs/reference/pytest_cover.rst | 4 +- docs/usage.rst | 4 +- setup.cfg | 18 ++--- setup.py | 22 +++--- src/{pytest-cover.embed => pytest-cov.embed} | 2 +- src/pytest-cov.pth | 1 + src/pytest-cover.pth | 1 - src/{pytest_cover => pytest_cov}/__init__.py | 0 src/{pytest_cover => pytest_cov}/embed.py | 0 src/{pytest_cover => pytest_cov}/engine.py | 0 src/{pytest_cover => pytest_cov}/plugin.py | 0 tests/test_pytest_cover.py | 4 +- 20 files changed, 116 insertions(+), 110 deletions(-) rename src/{pytest-cover.embed => pytest-cov.embed} (87%) create mode 100644 src/pytest-cov.pth delete mode 100644 src/pytest-cover.pth rename src/{pytest_cover => pytest_cov}/__init__.py (100%) rename src/{pytest_cover => pytest_cov}/embed.py (100%) rename src/{pytest_cover => pytest_cov}/engine.py (100%) rename src/{pytest_cover => pytest_cov}/plugin.py (100%) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f20df406..dc22f299 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -4,26 +4,16 @@ Changelog 2.0.0 (2015-06-29) ------------------ -* Renamed ``--cov-min`` to ``--cov-fail-under`` to be consistent with the new ``fail_under`` option in `coverage-4.0`. -* Changed ``--cov-report=term`` to automatically upgrade to ``--cov-report=term-missing`` if there's ``[run] show_missing = True`` in - ``.coveragerc``. -* Changed ``--cov-fail-under`` to be automatically activated if there's a ``[report] fail_under = ...`` in ``.coveragerc``. - -1.0.0 (2015-06-05) ------------------- - +* Added ``--cov-fail-under``, akin to the new ``fail_under`` option in `coverage-4.0` + (automatically activated if there's a ``[report] fail_under = ...`` in ``.coveragerc``). +* Changed ``--cov-report=term`` to automatically upgrade to ``--cov-report=term-missing`` + if there's ``[run] show_missing = True`` in ``.coveragerc``. +* Changed ``--cov`` so it can be used with no path argument (in wich case the source + settings from ``.coveragerc`` will be used instead). * Fixed `.pth` installation to work in all cases (install, easy_install, wheels, develop etc). * Fixed `.pth` uninstallation to work for wheel installs. -* Reverted the unreleased ``--cov=path`` deprecation. -* Removed the unreleased addition of ``--cov-source=path``. - ------ - -* Forked from the `2.0` branch of https://github.com/schlamar/pytest-cov/ - fixes include: - - * No need to specify the source anymore via ``--cov``. The source settings from - ``.coveragerc`` will be used instead. - * Support for ``--cov-min``. - +1.8.2 (2014-11-06) +------------------ +* N/A diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 10586f82..91573192 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -8,7 +8,7 @@ little bit helps, and credit will always be given. Bug reports =========== -When `reporting a bug `_ please include: +When `reporting a bug `_ please include: * Your operating system name and version. * Any details about your local setup that might be helpful in troubleshooting. @@ -17,14 +17,14 @@ When `reporting a bug `_ please Documentation improvements ========================== -pytest-cover could always use more documentation, whether as part of the -official pytest-cover docs, in docstrings, or even on the web in blog posts, +pytest-cov could always use more documentation, whether as part of the +official pytest-cov docs, in docstrings, or even on the web in blog posts, articles, and such. Feature requests and feedback ============================= -The best way to send feedback is to file an issue at https://github.com/ionelmc/pytest-cover/issues. +The best way to send feedback is to file an issue at https://github.com/schlamar/pytest-cov/issues. If you are proposing a feature: @@ -35,12 +35,12 @@ If you are proposing a feature: Development =========== -To set up `pytest-cover` for local development: +To set up `pytest-cov` for local development: -1. `Fork pytest-cover on GitHub `_. +1. `Fork pytest-cov on GitHub `_. 2. Clone your fork locally:: - git clone git@github.com:your_name_here/pytest-cover.git + git clone git@github.com:your_name_here/pytest-cov.git 3. Create a branch for local development:: @@ -68,15 +68,15 @@ If you need some code review or feedback while you're developing the code just m For merging, you should: 1. Include passing tests (run ``tox``) [1]_. -2. Update documentation when there's new API, functionality etc. +2. Update documentation when there's new API, functionality etc. 3. Add a note to ``CHANGELOG.rst`` about the changes. 4. Add yourself to ``AUTHORS.rst``. -.. [1] If you don't have all the necessary python versions available locally you can rely on Travis - it will - `run the tests `_ for each change you add in the pull request. - +.. [1] If you don't have all the necessary python versions available locally you can rely on Travis - it will + `run the tests `_ for each change you add in the pull request. + It will be slower though ... - + Tips ---- @@ -86,4 +86,4 @@ To run a subset of tests:: To run all the test environments in *parallel* (you need to ``pip install detox``):: - detox \ No newline at end of file + detox diff --git a/LICENSE b/LICENSE index e98b6474..5b3634b4 100644 --- a/LICENSE +++ b/LICENSE @@ -1,14 +1,21 @@ -Copyright (c) 2015, Ionel Cristian Mărieș +The MIT License -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: +Copyright (c) 2010 Meme Dough -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the -Software. +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 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. \ No newline at end of file +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. diff --git a/README.rst b/README.rst index 7e10ac9d..4e277f4f 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ =============================== -pytest-cover +pytest-cov =============================== .. list-table:: @@ -15,62 +15,62 @@ pytest-cover .. |wheel| |supported-versions| |supported-implementations| -.. |docs| image:: https://readthedocs.org/projects/pytest-cover/badge/?style=flat - :target: https://readthedocs.org/projects/pytest-cover +.. |docs| image:: https://readthedocs.org/projects/pytest-cov/badge/?style=flat + :target: https://readthedocs.org/projects/pytest-cov :alt: Documentation Status -.. |travis| image:: http://img.shields.io/travis/ionelmc/pytest-cover/master.svg?style=flat&label=Travis +.. |travis| image:: http://img.shields.io/travis/schlamar/pytest-cov/master.svg?style=flat&label=Travis :alt: Travis-CI Build Status - :target: https://travis-ci.org/ionelmc/pytest-cover + :target: https://travis-ci.org/schlamar/pytest-cov -.. |appveyor| image:: https://img.shields.io/appveyor/ci/ionelmc/pytest-cover/master.svg?style=flat&label=AppVeyor +.. |appveyor| image:: https://img.shields.io/appveyor/ci/schlamar/pytest-cov/master.svg?style=flat&label=AppVeyor :alt: AppVeyor Build Status - :target: https://ci.appveyor.com/project/ionelmc/pytest-cover + :target: https://ci.appveyor.com/project/schlamar/pytest-cov -.. |coveralls| image:: http://img.shields.io/coveralls/ionelmc/pytest-cover/master.svg?style=flat&label=Coveralls +.. |coveralls| image:: http://img.shields.io/coveralls/schlamar/pytest-cov/master.svg?style=flat&label=Coveralls :alt: Coverage Status - :target: https://coveralls.io/r/ionelmc/pytest-cover + :target: https://coveralls.io/r/schlamar/pytest-cov -.. |codecov| image:: http://img.shields.io/codecov/c/github/ionelmc/pytest-cover/master.svg?style=flat&label=Codecov +.. |codecov| image:: http://img.shields.io/codecov/c/github/schlamar/pytest-cov/master.svg?style=flat&label=Codecov :alt: Coverage Status - :target: https://codecov.io/github/ionelmc/pytest-cover + :target: https://codecov.io/github/schlamar/pytest-cov -.. |landscape| image:: https://landscape.io/github/ionelmc/pytest-cover/master/landscape.svg?style=flat - :target: https://landscape.io/github/ionelmc/pytest-cover/master +.. |landscape| image:: https://landscape.io/github/schlamar/pytest-cov/master/landscape.svg?style=flat + :target: https://landscape.io/github/schlamar/pytest-cov/master :alt: Code Quality Status -.. |version| image:: http://img.shields.io/pypi/v/pytest-cover.svg?style=flat +.. |version| image:: http://img.shields.io/pypi/v/pytest-cov.svg?style=flat :alt: PyPI Package latest release - :target: https://pypi.python.org/pypi/pytest-cover + :target: https://pypi.python.org/pypi/pytest-cov -.. |downloads| image:: http://img.shields.io/pypi/dm/pytest-cover.svg?style=flat +.. |downloads| image:: http://img.shields.io/pypi/dm/pytest-cov.svg?style=flat :alt: PyPI Package monthly downloads - :target: https://pypi.python.org/pypi/pytest-cover + :target: https://pypi.python.org/pypi/pytest-cov -.. |wheel| image:: https://pypip.in/wheel/pytest-cover/badge.svg?style=flat +.. |wheel| image:: https://pypip.in/wheel/pytest-cov/badge.svg?style=flat :alt: PyPI Wheel - :target: https://pypi.python.org/pypi/pytest-cover + :target: https://pypi.python.org/pypi/pytest-cov -.. |supported-versions| image:: https://pypip.in/py_versions/pytest-cover/badge.svg?style=flat +.. |supported-versions| image:: https://pypip.in/py_versions/pytest-cov/badge.svg?style=flat :alt: Supported versions - :target: https://pypi.python.org/pypi/pytest-cover + :target: https://pypi.python.org/pypi/pytest-cov -.. |supported-implementations| image:: https://pypip.in/implementation/pytest-cover/badge.svg?style=flat +.. |supported-implementations| image:: https://pypip.in/implementation/pytest-cov/badge.svg?style=flat :alt: Supported imlementations - :target: https://pypi.python.org/pypi/pytest-cover + :target: https://pypi.python.org/pypi/pytest-cov -.. |scrutinizer| image:: https://img.shields.io/scrutinizer/g/ionelmc/pytest-cover/master.svg?style=flat +.. |scrutinizer| image:: https://img.shields.io/scrutinizer/g/schlamar/pytest-cov/master.svg?style=flat :alt: Scrutinizer Status - :target: https://scrutinizer-ci.com/g/ionelmc/pytest-cover/ + :target: https://scrutinizer-ci.com/g/schlamar/pytest-cov/ -Pytest plugin for measuring coverage. Forked from `pytest-cov `_. +Pytest plugin for measuring coverage. * Free software: MIT license This plugin produces coverage reports. It supports centralised testing and distributed testing in both load and each modes. It also supports coverage of subprocesses. -All features offered by the coverage package should be available, either through pytest-cover or +All features offered by the coverage package should be available, either through pytest-cov or through coverage's config file. @@ -79,7 +79,7 @@ Installation Install with pip:: - pip install pytest-cover + pip install pytest-cov For distributed testing support install pytest-xdist:: @@ -96,7 +96,7 @@ Uninstallation Uninstall with pip:: - pip uninstall pytest-cover + pip uninstall pytest-cov Usage ===== @@ -284,17 +284,28 @@ effect. These include specifying source to be measured (source option) and all Limitations =========== -For distributed testing the slaves must have the pytest-cover package installed. This is needed since +For distributed testing the slaves must have the pytest-cov package installed. This is needed since the plugin must be registered through setuptools for pytest to start the plugin on the slave. For subprocess measurement environment variables must make it from the main process to the -subprocess. The python used by the subprocess must have pytest-cover installed. The subprocess must +subprocess. The python used by the subprocess must have pytest-cov installed. The subprocess must do normal site initialisation so that the environment variables can be detected and coverage started. Acknowledgements ================ -`Marc Schlaich` and everyone else for contributing and creating `pytest-cov (and cov-core) `_. -This plugin is a merge of those two packages with other fixes. +Whilst this plugin has been built fresh from the ground up it has been influenced by the work done +on pytest-coverage (Ross Lawley, James Mills, Holger Krekel) and nose-cover (Jason Pellerin) which are +other coverage plugins. + +Ned Batchelder for coverage and its ability to combine the coverage results of parallel runs. + +Holger Krekel for pytest with its distributed testing support. + +Jason Pellerin for nose. + +Michael Foord for unittest2. + +No doubt others have contributed to these tools as well. diff --git a/docs/conf.py b/docs/conf.py index 1eca1fc7..d48985a3 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -20,7 +20,7 @@ source_suffix = '.rst' master_doc = 'index' -project = 'pytest-cover' +project = 'pytest-cov' year = '2015' author = 'Ionel Cristian Mărieș' copyright = '{0}, {1}'.format(year, author) @@ -29,7 +29,7 @@ html_theme = "sphinx_py3doc_enhanced_theme" html_theme_path = [sphinx_py3doc_enhanced_theme.get_html_theme_path()] html_theme_options = { - 'githuburl': 'https://github.com/ionelmc/pytest-cover/' + 'githuburl': 'https://github.com/schlamar/pytest-cov/' } pygments_style = 'trac' diff --git a/docs/index.rst b/docs/index.rst index be946912..1d1c58c1 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,4 +1,4 @@ -Welcome to pytest-cover's documentation! +Welcome to pytest-cov's documentation! ====================================== Contents: diff --git a/docs/installation.rst b/docs/installation.rst index 76e143b2..d12d3475 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -4,4 +4,4 @@ Installation At the command line:: - pip install pytest-cover + pip install pytest-cov diff --git a/docs/reference/index.rst b/docs/reference/index.rst index 8cb90cb5..5fd2c7f9 100644 --- a/docs/reference/index.rst +++ b/docs/reference/index.rst @@ -4,4 +4,4 @@ Reference .. toctree:: :glob: - pytest_cover* + pytest_cov* diff --git a/docs/reference/pytest_cover.rst b/docs/reference/pytest_cover.rst index a3695344..caf88b39 100644 --- a/docs/reference/pytest_cover.rst +++ b/docs/reference/pytest_cover.rst @@ -1,5 +1,5 @@ -pytest_cover +pytest_cov ============================= -.. automodule:: pytest_cover +.. automodule:: pytest_cov :members: diff --git a/docs/usage.rst b/docs/usage.rst index 36872c2d..89b4912e 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -2,6 +2,6 @@ Usage ===== -To use pytest-cover in a project:: +To use pytest-cov in a project:: - import pytest_cover + import pytest_cov diff --git a/setup.cfg b/setup.cfg index a30ce397..89d17ff1 100644 --- a/setup.cfg +++ b/setup.cfg @@ -17,10 +17,10 @@ exclude = tests/*,*/migrations/*,*/south_migrations/* [bumpversion:file:docs/conf.py] -[bumpversion:file:src/pytest_cover/__init__.py] +[bumpversion:file:src/pytest_cov/__init__.py] [pytest] -norecursedirs = +norecursedirs = .git .tox .env @@ -29,11 +29,11 @@ norecursedirs = south_migrations migrations example -python_files = +python_files = test_*.py *_test.py tests.py -addopts = +addopts = -rxEfs --strict --ignore=docs/conf.py @@ -47,21 +47,21 @@ addopts = [isort] force_single_line = True line_length = 120 -known_first_party = pytest_cover +known_first_party = pytest_cov default_section = THIRDPARTY forced_separate = test_pytest_cover [matrix] -python_versions = +python_versions = 2.6 2.7 3.3 3.4 pypy -dependencies = -coverage_flags = +dependencies = +coverage_flags = : true nocover: false -environment_variables = +environment_variables = - diff --git a/setup.py b/setup.py index 33002e24..adb70197 100644 --- a/setup.py +++ b/setup.py @@ -30,7 +30,7 @@ def read(*names, **kwargs): class BuildWithPTH(build): def run(self): build.run(self) - path = join(dirname(__file__), 'src', 'pytest-cover.pth') + path = join(dirname(__file__), 'src', 'pytest-cov.pth') dest = join(self.build_lib, basename(path)) self.copy_file(path, dest) @@ -38,7 +38,7 @@ def run(self): class EasyInstallWithPTH(easy_install): def run(self): easy_install.run(self) - path = join(dirname(__file__), 'src', 'pytest-cover.pth') + path = join(dirname(__file__), 'src', 'pytest-cov.pth') dest = join(self.install_dir, basename(path)) self.copy_file(path, dest) @@ -46,7 +46,7 @@ def run(self): class InstallLibWithPTH(install_lib): def run(self): install_lib.run(self) - path = join(dirname(__file__), 'src', 'pytest-cover.pth') + path = join(dirname(__file__), 'src', 'pytest-cov.pth') dest = join(self.install_dir, basename(path)) self.copy_file(path, dest) self.outputs = [dest] @@ -58,7 +58,7 @@ def get_outputs(self): class DevelopWithPTH(develop): def run(self): develop.run(self) - path = join(dirname(__file__), 'src', 'pytest-cover.pth') + path = join(dirname(__file__), 'src', 'pytest-cov.pth') dest = join(self.install_dir, basename(path)) self.copy_file(path, dest) @@ -73,24 +73,22 @@ def finalize_options(self): pass def run(self): - with open(join(dirname(__file__), 'src', 'pytest-cover.pth'), 'w') as fh: - with open(join(dirname(__file__), 'src', 'pytest-cover.embed')) as sh: + with open(join(dirname(__file__), 'src', 'pytest-cov.pth'), 'w') as fh: + with open(join(dirname(__file__), 'src', 'pytest-cov.embed')) as sh: fh.write( 'import os, sys;' 'exec(%r)' % sh.read().replace(' ', ' ') ) setup( - name='pytest-cover', + name='pytest-cov', version='2.0.0', license='MIT', - description='Pytest plugin for measuring coverage. Forked from `pytest-cov`.', + description='Pytest plugin for measuring coverage.', long_description='%s\n%s' % (read('README.rst'), re.sub(':[a-z]+:`~?(.*?)`', r'``\1``', read('CHANGELOG.rst'))), author='Marc Schlaich', author_email='marc.schlaich@gmail.com', - maintainer='Ionel Cristian Mărieș', - maintainer_email='contact@ionelmc.ro', - url='https://github.com/ionelmc/pytest-cover', + url='https://github.com/schlamar/pytest-cov', packages=find_packages('src'), package_dir={'': 'src'}, py_modules=[splitext(basename(path))[0] for path in glob('src/*.py')], @@ -126,7 +124,7 @@ def run(self): }, entry_points={ 'pytest11': [ - 'pytest_cov = pytest_cover.plugin', + 'pytest_cov = pytest_cov.plugin', ], 'console_scripts': [ ] diff --git a/src/pytest-cover.embed b/src/pytest-cov.embed similarity index 87% rename from src/pytest-cover.embed rename to src/pytest-cov.embed index 5e5fa729..31f2fdab 100644 --- a/src/pytest-cover.embed +++ b/src/pytest-cov.embed @@ -1,6 +1,6 @@ if 'COV_CORE_SOURCE' in os.environ: try: - from pytest_cover.embed import init + from pytest_cov.embed import init init() except ImportError: sys.stderr.write( diff --git a/src/pytest-cov.pth b/src/pytest-cov.pth new file mode 100644 index 00000000..8734b5ef --- /dev/null +++ b/src/pytest-cov.pth @@ -0,0 +1 @@ +import os, sys;exec('if \'COV_CORE_SOURCE\' in os.environ:\n try:\n from pytest_cov.embed import init\n init()\n except ImportError:\n sys.stderr.write(\n "Failed to setup coverage."\n "Sources: {[COV_CORE_SOURCE]!r}"\n "Config: {[COV_CORE_CONFIG]!r}"\n "Exception: {!r}\\n".format(os.environ, exc))\n') diff --git a/src/pytest-cover.pth b/src/pytest-cover.pth deleted file mode 100644 index 18376552..00000000 --- a/src/pytest-cover.pth +++ /dev/null @@ -1 +0,0 @@ -import os, sys;exec('if \'COV_CORE_SOURCE\' in os.environ:\n try:\n from pytest_cover.embed import init\n init()\n except ImportError:\n sys.stderr.write(\n "Failed to setup coverage."\n "Sources: {[COV_CORE_SOURCE]!r}"\n "Config: {[COV_CORE_CONFIG]!r}"\n "Exception: {!r}\\n".format(os.environ, exc))\n') \ No newline at end of file diff --git a/src/pytest_cover/__init__.py b/src/pytest_cov/__init__.py similarity index 100% rename from src/pytest_cover/__init__.py rename to src/pytest_cov/__init__.py diff --git a/src/pytest_cover/embed.py b/src/pytest_cov/embed.py similarity index 100% rename from src/pytest_cover/embed.py rename to src/pytest_cov/embed.py diff --git a/src/pytest_cover/engine.py b/src/pytest_cov/engine.py similarity index 100% rename from src/pytest_cover/engine.py rename to src/pytest_cov/engine.py diff --git a/src/pytest_cover/plugin.py b/src/pytest_cov/plugin.py similarity index 100% rename from src/pytest_cover/plugin.py rename to src/pytest_cov/plugin.py diff --git a/tests/test_pytest_cover.py b/tests/test_pytest_cover.py index 87ddcbe5..8b82dd3f 100644 --- a/tests/test_pytest_cover.py +++ b/tests/test_pytest_cover.py @@ -7,7 +7,7 @@ import virtualenv import py import pytest -import pytest_cover.plugin +import pytest_cov.plugin pytest_plugins = 'pytester', 'cov' @@ -584,7 +584,7 @@ def test_dist_boxed(testdir): def test_not_started_plugin_does_not_fail(testdir): - plugin = pytest_cover.plugin.CovPlugin(None, None, start=False) + plugin = pytest_cov.plugin.CovPlugin(None, None, start=False) plugin.pytest_sessionfinish(None, None) plugin.pytest_terminal_summary(None) From 87d77b222ae6a3a87ef41d00b4c4589c486c2c05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Sat, 4 Jul 2015 14:45:03 +0300 Subject: [PATCH 130/134] Remove release date (not released yet). --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index dc22f299..6978606e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,7 +1,7 @@ Changelog ========= -2.0.0 (2015-06-29) +2.0.0 (??????????) ------------------ * Added ``--cov-fail-under``, akin to the new ``fail_under`` option in `coverage-4.0` From a2cd0608391a542473ba9b88bf73b18d4790dd22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Sat, 4 Jul 2015 14:45:55 +0300 Subject: [PATCH 131/134] Allow overriding interpreter from env (eg: for AppVeyor where there are 32/64bit variants). --- tox.ini | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tox.ini b/tox.ini index e441da6b..c59abb73 100644 --- a/tox.ini +++ b/tox.ini @@ -9,10 +9,10 @@ envlist = [testenv] basepython = pypy: pypy - 2.6: python2.6 - {2.7,docs}: python2.7 - 3.3: python3.3 - 3.4: python3.4 + 2.6: {env:TOXPYTHON:python2.6} + {2.7,docs}: {env:TOXPYTHON:python2.7} + 3.3: {env:TOXPYTHON:python3.3} + 3.4: {env:TOXPYTHON:python3.4} {clean,check,report,extension-coveralls,coveralls}: python3.4 setenv = PYTHONPATH={toxinidir}/tests From 8c5859b33899296264d3ac6fc0aa59107f8c42f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Sun, 5 Jul 2015 15:50:45 +0300 Subject: [PATCH 132/134] Remove some un-necessary cruft. --- ci/bootstrap.py | 64 --------------------- ci/templates/.travis.yml | 27 --------- ci/templates/appveyor.yml | 39 ------------- ci/templates/tox.ini | 117 -------------------------------------- setup.cfg | 15 ----- 5 files changed, 262 deletions(-) delete mode 100755 ci/bootstrap.py delete mode 100644 ci/templates/.travis.yml delete mode 100644 ci/templates/appveyor.yml delete mode 100644 ci/templates/tox.ini diff --git a/ci/bootstrap.py b/ci/bootstrap.py deleted file mode 100755 index 466bb8fe..00000000 --- a/ci/bootstrap.py +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -from __future__ import absolute_import, print_function, unicode_literals - -import os -import sys -from os.path import exists -from os.path import join -from os.path import dirname -from os.path import abspath - - -if __name__ == "__main__": - base_path = dirname(dirname(abspath(__file__))) - print("Project path: {0}".format(base_path)) - env_path = join(base_path, ".tox", "bootstrap") - if sys.platform == "win32": - bin_path = join(env_path, "Scripts") - else: - bin_path = join(env_path, "bin") - if not exists(env_path): - import subprocess - print("Making bootstrap env in: {0} ...".format(env_path)) - try: - subprocess.check_call(["virtualenv", env_path]) - except Exception: - subprocess.check_call([sys.executable, "-m", "virtualenv", env_path]) - print("Installing `jinja2` and `matrix` into bootstrap environment ...") - subprocess.check_call([join(bin_path, "pip"), "install", "jinja2", "matrix"]) - activate = join(bin_path, "activate_this.py") - exec(compile(open(activate, "rb").read(), activate, "exec"), dict(__file__=activate)) - - import jinja2 - import matrix - - jinja = jinja2.Environment( - loader=jinja2.FileSystemLoader(join(base_path, "ci", "templates")), - trim_blocks=True, - lstrip_blocks=True, - keep_trailing_newline=True - ) - tox_environments = {} - for (alias, conf) in matrix.from_file(join(base_path, "setup.cfg")).items(): - python = conf["python_versions"] - deps = conf["dependencies"] - if "coverage_flags" in conf: - cover = {"false": False, "true": True}[conf["coverage_flags"].lower()] - if "environment_variables" in conf: - env_vars = conf["environment_variables"] - - tox_environments[alias] = { - "python": "python" + python if "py" not in python else python, - "deps": deps.split(), - } - if "coverage_flags" in conf: - tox_environments[alias].update(cover=cover) - if "environment_variables" in conf: - tox_environments[alias].update(env_vars=env_vars.split()) - - for name in os.listdir(join("ci", "templates")): - with open(join(base_path, name), "w") as fh: - fh.write(jinja.get_template(name).render(tox_environments=tox_environments)) - print("Wrote {}".format(name)) - print("DONE.") diff --git a/ci/templates/.travis.yml b/ci/templates/.travis.yml deleted file mode 100644 index b1d89b30..00000000 --- a/ci/templates/.travis.yml +++ /dev/null @@ -1,27 +0,0 @@ -language: python -python: 2.7 -sudo: false -env: - global: - LD_PRELOAD=/lib/x86_64-linux-gnu/libSegFault.so - matrix: - - TOXENV=check -{% for env, config in tox_environments|dictsort %} - - TOXENV={{ env }}{% if config.cover %},coveralls{% endif %} - -{% endfor %} -before_install: - - python --version - - virtualenv --version - - pip --version - - uname -a - - lsb_release -a -install: - - pip install tox -script: - - tox -v -notifications: - email: - on_success: never - on_failure: always - diff --git a/ci/templates/appveyor.yml b/ci/templates/appveyor.yml deleted file mode 100644 index 55310322..00000000 --- a/ci/templates/appveyor.yml +++ /dev/null @@ -1,39 +0,0 @@ -version: '{branch}-{build}' -build: off -environment: - global: - WITH_COMPILER: "cmd /E:ON /V:ON /C .\\ci\\appveyor-with-compiler.cmd" - matrix: - - TOXENV: check - PYTHON_HOME: "C:\\Python27" - PYTHON_VERSION: "2.7" - PYTHON_ARCH: "32" -{% for env, config in tox_environments|dictsort %}{% if env.startswith('2.7') or env.startswith('3.4') or env.startswith('3.3') %} - - TOXENV: "{{ env }}" - TOXPYTHON: "C:\\Python{{ env[:3].replace('.', '') }}\\python.exe" - WINDOWS_SDK_VERSION: "v7.{{ '1' if env[0] == '3' else '0' }}" - PYTHON_HOME: "C:\\Python{{ env[:3].replace('.', '') }}" - PYTHON_VERSION: "{{ env[:3] }}" - PYTHON_ARCH: "32" - - TOXENV: "{{ env }}" - TOXPYTHON: "C:\\Python{{ env[:3].replace('.', '') }}-x64\\python.exe" - WINDOWS_SDK_VERSION: "v7.{{ '1' if env[0] == '3' else '0' }}" - PYTHON_HOME: "C:\\Python{{ env[:3].replace('.', '') }}-x64" - PYTHON_VERSION: "{{ env[:3] }}" - PYTHON_ARCH: "64" -{% endif %}{% endfor %} -init: - - "ECHO %TOXENV%" - - ps: "ls C:\\Python*" -install: - - "powershell ci\\appveyor-bootstrap.ps1" -test_script: - - "%PYTHON_HOME%\\Scripts\\tox --version" - - "%PYTHON_HOME%\\Scripts\\virtualenv --version" - - "%PYTHON_HOME%\\Scripts\\pip --version" - - "%WITH_COMPILER% %PYTHON_HOME%\\Scripts\\tox" -after_test: - - "IF \"%TOXENV:~-8,8%\" == \"-nocover\" %WITH_COMPILER% %TOXPYTHON% setup.py bdist_wheel" -artifacts: - - path: dist\* - diff --git a/ci/templates/tox.ini b/ci/templates/tox.ini deleted file mode 100644 index c96fb687..00000000 --- a/ci/templates/tox.ini +++ /dev/null @@ -1,117 +0,0 @@ -[tox] -envlist = - clean, - check, -{% for env in tox_environments|sort %} - {{ env }}, -{% endfor %} - report, - docs - -[testenv] -setenv = - PYTHONPATH={toxinidir}/tests - PYTHONUNBUFFERED=yes -passenv = - * -deps = - pytest - pytest-capturelog -commands = - {posargs:py.test -vv --ignore=src} - -[testenv:spell] -setenv = - SPELLCHECK = 1 -commands = - sphinx-build -b spelling docs dist/docs -usedevelop = true -deps = - -r{toxinidir}/docs/requirements.txt - sphinxcontrib-spelling - pyenchant - -[testenv:docs] -whitelist_externals = - rm -commands = - sphinx-build {posargs:-E} -b html docs dist/docs - sphinx-build -b linkcheck docs dist/docs -usedevelop = true -deps = - -r{toxinidir}/docs/requirements.txt - -[testenv:configure] -deps = - jinja2 - matrix -usedevelop = true -commands = - python bootstrap.py - -[testenv:check] -basepython = python3.4 -deps = - docutils - check-manifest - flake8 - readme - pygments -usedevelop = true -commands = - python setup.py check --strict --metadata --restructuredtext - check-manifest {toxinidir} - flake8 src - -[testenv:coveralls] -deps = - coveralls -usedevelop = true -commands = - coverage combine - coverage report - coveralls - -[testenv:report] -basepython = python3.4 -commands = - coverage combine - coverage report -usedevelop = true -deps = coverage - -[testenv:clean] -commands = coverage erase -usedevelop = true -deps = coverage - -{% for env, config in tox_environments|dictsort %} -[testenv:{{ env }}] -basepython = {{ config.python }} -{% if config.cover or config.env_vars %} -setenv = - {[testenv]setenv} -{% endif %} -{% for var in config.env_vars %} - {{ var }} -{% endfor %} -{% if config.cover %} - WITH_COVERAGE=yes -usedevelop = true -commands = - {posargs:py.test --cov=src --cov-report=term-missing -vv} -{% endif %} -{% if config.cover or config.deps %} -deps = - {[testenv]deps} -{% endif %} -{% if config.cover %} - pytest-cov -{% endif %} -{% for dep in config.deps %} - {{ dep }} -{% endfor %} - -{% endfor %} - - diff --git a/setup.cfg b/setup.cfg index 89d17ff1..9846450e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -50,18 +50,3 @@ line_length = 120 known_first_party = pytest_cov default_section = THIRDPARTY forced_separate = test_pytest_cover - -[matrix] -python_versions = - 2.6 - 2.7 - 3.3 - 3.4 - pypy -dependencies = -coverage_flags = - : true - nocover: false -environment_variables = - - - From 5b91aff62aaed7c013dc3a6b7fa1944ecaa559a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Sun, 5 Jul 2015 15:51:34 +0300 Subject: [PATCH 133/134] Extend the changelog with some of the changes mentioned in #28. --- CHANGELOG.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 6978606e..8b94fa3d 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -12,6 +12,9 @@ Changelog settings from ``.coveragerc`` will be used instead). * Fixed `.pth` installation to work in all cases (install, easy_install, wheels, develop etc). * Fixed `.pth` uninstallation to work for wheel installs. +* Support for coverage 4.0. +* Data file suffixing changed to use coverage's ``data_suffix=True`` option (instead of the + custom suffixing). 1.8.2 (2014-11-06) ------------------ From d89f5c7f87b7eef23aa0a9799309fda29d6e6bcc Mon Sep 17 00:00:00 2001 From: Marc Schlaich Date: Mon, 6 Jul 2015 12:25:02 +0200 Subject: [PATCH 134/134] Rename test_pytest_cover.py to test_pytest_cov.py --- tests/{test_pytest_cover.py => test_pytest_cov.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/{test_pytest_cover.py => test_pytest_cov.py} (100%) diff --git a/tests/test_pytest_cover.py b/tests/test_pytest_cov.py similarity index 100% rename from tests/test_pytest_cover.py rename to tests/test_pytest_cov.py