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