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 |