1# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 2# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt 3 4"""Code coverage measurement for Python""" 5 6# Distutils setup for coverage.py 7# This file is used unchanged under all versions of Python, 2.x and 3.x. 8 9import os 10import sys 11 12from setuptools import setup 13from distutils.core import Extension # pylint: disable=no-name-in-module, import-error 14from distutils.command.build_ext import build_ext # pylint: disable=no-name-in-module, import-error 15from distutils import errors # pylint: disable=no-name-in-module 16 17# Get or massage our metadata. We exec coverage/version.py so we can avoid 18# importing the product code into setup.py. 19 20classifiers = """\ 21Environment :: Console 22Intended Audience :: Developers 23License :: OSI Approved :: Apache Software License 24Operating System :: OS Independent 25Programming Language :: Python :: 2.6 26Programming Language :: Python :: 2.7 27Programming Language :: Python :: 3.3 28Programming Language :: Python :: 3.4 29Programming Language :: Python :: 3.5 30Programming Language :: Python :: Implementation :: CPython 31Programming Language :: Python :: Implementation :: PyPy 32Topic :: Software Development :: Quality Assurance 33Topic :: Software Development :: Testing 34""" 35 36cov_ver_py = os.path.join(os.path.split(__file__)[0], "coverage/version.py") 37with open(cov_ver_py) as version_file: 38 # __doc__ will be overwritten by version.py. 39 doc = __doc__ 40 # Keep pylint happy. 41 __version__ = __url__ = version_info = "" 42 # Execute the code in version.py. 43 exec(compile(version_file.read(), cov_ver_py, 'exec')) 44 45with open("README.rst") as readme: 46 long_description = readme.read().replace("http://coverage.readthedocs.org", __url__) 47 48classifier_list = classifiers.splitlines() 49 50if version_info[3] == 'alpha': 51 devstat = "3 - Alpha" 52elif version_info[3] in ['beta', 'candidate']: 53 devstat = "4 - Beta" 54else: 55 assert version_info[3] == 'final' 56 devstat = "5 - Production/Stable" 57classifier_list.append("Development Status :: " + devstat) 58 59# Create the keyword arguments for setup() 60 61setup_args = dict( 62 name='coverage', 63 version=__version__, 64 65 packages=[ 66 'coverage', 67 ], 68 69 package_data={ 70 'coverage': [ 71 'htmlfiles/*.*', 72 ] 73 }, 74 75 entry_points={ 76 # Install a script as "coverage", and as "coverage[23]", and as 77 # "coverage-2.7" (or whatever). 78 'console_scripts': [ 79 'coverage = coverage.cmdline:main', 80 'coverage%d = coverage.cmdline:main' % sys.version_info[:1], 81 'coverage-%d.%d = coverage.cmdline:main' % sys.version_info[:2], 82 ], 83 }, 84 85 # We need to get HTML assets from our htmlfiles directory. 86 zip_safe=False, 87 88 author='Ned Batchelder and others', 89 author_email='ned@nedbatchelder.com', 90 description=doc, 91 long_description=long_description, 92 keywords='code coverage testing', 93 license='Apache 2.0', 94 classifiers=classifier_list, 95 url=__url__, 96) 97 98# A replacement for the build_ext command which raises a single exception 99# if the build fails, so we can fallback nicely. 100 101ext_errors = ( 102 errors.CCompilerError, 103 errors.DistutilsExecError, 104 errors.DistutilsPlatformError, 105) 106if sys.platform == 'win32': 107 # distutils.msvc9compiler can raise an IOError when failing to 108 # find the compiler 109 ext_errors += (IOError,) 110 111 112class BuildFailed(Exception): 113 """Raise this to indicate the C extension wouldn't build.""" 114 def __init__(self): 115 Exception.__init__(self) 116 self.cause = sys.exc_info()[1] # work around py 2/3 different syntax 117 118 119class ve_build_ext(build_ext): 120 """Build C extensions, but fail with a straightforward exception.""" 121 122 def run(self): 123 """Wrap `run` with `BuildFailed`.""" 124 try: 125 build_ext.run(self) 126 except errors.DistutilsPlatformError: 127 raise BuildFailed() 128 129 def build_extension(self, ext): 130 """Wrap `build_extension` with `BuildFailed`.""" 131 try: 132 # Uncomment to test compile failure handling: 133 # raise errors.CCompilerError("OOPS") 134 build_ext.build_extension(self, ext) 135 except ext_errors: 136 raise BuildFailed() 137 except ValueError as err: 138 # this can happen on Windows 64 bit, see Python issue 7511 139 if "'path'" in str(err): # works with both py 2/3 140 raise BuildFailed() 141 raise 142 143# There are a few reasons we might not be able to compile the C extension. 144# Figure out if we should attempt the C extension or not. 145 146compile_extension = True 147 148if sys.platform.startswith('java'): 149 # Jython can't compile C extensions 150 compile_extension = False 151 152if '__pypy__' in sys.builtin_module_names: 153 # Pypy can't compile C extensions 154 compile_extension = False 155 156if compile_extension: 157 setup_args.update(dict( 158 ext_modules=[ 159 Extension( 160 "coverage.tracer", 161 sources=[ 162 "coverage/ctracer/datastack.c", 163 "coverage/ctracer/filedisp.c", 164 "coverage/ctracer/module.c", 165 "coverage/ctracer/tracer.c", 166 ], 167 ), 168 ], 169 cmdclass={ 170 'build_ext': ve_build_ext, 171 }, 172 )) 173 174# Py3.x-specific details. 175 176if sys.version_info >= (3, 0): 177 setup_args.update(dict( 178 use_2to3=False, 179 )) 180 181 182def main(): 183 """Actually invoke setup() with the arguments we built above.""" 184 # For a variety of reasons, it might not be possible to install the C 185 # extension. Try it with, and if it fails, try it without. 186 try: 187 setup(**setup_args) 188 except BuildFailed as exc: 189 msg = "Couldn't install with extension module, trying without it..." 190 exc_msg = "%s: %s" % (exc.__class__.__name__, exc.cause) 191 print("**\n** %s\n** %s\n**" % (msg, exc_msg)) 192 193 del setup_args['ext_modules'] 194 setup(**setup_args) 195 196if __name__ == '__main__': 197 main() 198