Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / third_party / pycoverage / setup.py
blobf0e83e677a39b59707c9221a61dafbbf03127ccf
1 # setup.py for coverage.py
3 """Code coverage measurement for Python
5 Coverage.py measures code coverage, typically during test execution. It uses
6 the code analysis tools and tracing hooks provided in the Python standard
7 library to determine which lines are executable, and which have been executed.
9 Coverage.py runs on Pythons 2.3 through 3.3, and PyPy 1.9.
11 Documentation is at `nedbatchelder.com <%s>`_. Code repository and issue
12 tracker are on `Bitbucket <http://bitbucket.org/ned/coveragepy>`_, with a
13 mirrored repo on `Github <https://github.com/nedbat/coveragepy>`_.
15 New in 3.7: ``--debug``, and 12 bugs closed.
17 New in 3.6: ``--fail-under``, and >20 bugs closed.
19 New in 3.5: Branch coverage exclusions, keyboard shortcuts in HTML report.
21 New in 3.4: Better control over source to measure, and unexecuted files
22 can be reported.
24 New in 3.3: .coveragerc files.
26 New in 3.2: Branch coverage!
27 """
29 # This file is used unchanged under all versions of Python, 2.x and 3.x.
31 classifiers = """\
32 Environment :: Console
33 Intended Audience :: Developers
34 License :: OSI Approved :: BSD License
35 Operating System :: OS Independent
36 Programming Language :: Python :: 2
37 Programming Language :: Python :: 3
38 Topic :: Software Development :: Quality Assurance
39 Topic :: Software Development :: Testing
40 """
42 # Pull in the tools we need.
43 import os, sys
45 from setuptools import setup
46 from distutils.core import Extension # pylint: disable=E0611,F0401
47 from distutils.command.build_ext import build_ext # pylint: disable=E0611,F0401,C0301
48 from distutils import errors # pylint: disable=E0611,F0401
50 # Get or massage our metadata. We exec coverage/version.py so we can avoid
51 # importing the product code into setup.py.
53 doc = __doc__ # __doc__ will be overwritten by version.py.
54 __version__ = __url__ = "" # Keep pylint happy.
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()
63 doclines = (doc % __url__).splitlines()
64 classifier_list = classifiers.splitlines()
66 if 'a' in __version__:
67 devstat = "3 - Alpha"
68 elif 'b' in __version__:
69 devstat = "4 - Beta"
70 else:
71 devstat = "5 - Production/Stable"
72 classifier_list.append("Development Status :: " + devstat)
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],
82 # Create the keyword arguments for setup()
84 setup_args = dict(
85 name = 'coverage',
86 version = __version__,
88 packages = [
89 'coverage',
92 package_data = {
93 'coverage': [
94 'htmlfiles/*.*',
98 entry_points = {'console_scripts': scripts},
100 # We need to get HTML assets from our htmlfiles dir.
101 zip_safe = False,
103 author = 'Ned Batchelder and others',
104 author_email = 'ned@nedbatchelder.com',
105 description = doclines[0],
106 long_description = '\n'.join(doclines[2:]),
107 keywords = 'code coverage testing',
108 license = 'BSD',
109 classifiers = classifier_list,
110 url = __url__,
113 # A replacement for the build_ext command which raises a single exception
114 # if the build fails, so we can fallback nicely.
116 ext_errors = (
117 errors.CCompilerError,
118 errors.DistutilsExecError,
119 errors.DistutilsPlatformError,
121 if sys.platform == 'win32' and sys.version_info > (2, 6):
122 # 2.6's distutils.msvc9compiler can raise an IOError when failing to
123 # find the compiler
124 ext_errors += (IOError,)
126 class BuildFailed(Exception):
127 """Raise this to indicate the C extension wouldn't build."""
128 def __init__(self):
129 Exception.__init__(self)
130 self.cause = sys.exc_info()[1] # work around py 2/3 different syntax
132 class ve_build_ext(build_ext):
133 """Build C extensions, but fail with a straightforward exception."""
135 def run(self):
136 """Wrap `run` with `BuildFailed`."""
137 try:
138 build_ext.run(self)
139 except errors.DistutilsPlatformError:
140 raise BuildFailed()
142 def build_extension(self, ext):
143 """Wrap `build_extension` with `BuildFailed`."""
144 try:
145 # Uncomment to test compile failures:
146 # raise errors.CCompilerError("OOPS")
147 build_ext.build_extension(self, ext)
148 except ext_errors:
149 raise BuildFailed()
150 except ValueError:
151 # 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
153 raise BuildFailed()
154 raise
156 # 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.
159 compile_extension = True
161 if sys.platform.startswith('java'):
162 # Jython can't compile C extensions
163 compile_extension = False
165 if '__pypy__' in sys.builtin_module_names:
166 # Pypy can't compile C extensions
167 compile_extension = False
169 if compile_extension:
170 setup_args.update(dict(
171 ext_modules = [
172 Extension("coverage.tracer", sources=["coverage/tracer.c"])
174 cmdclass = {
175 'build_ext': ve_build_ext,
179 # Py3.x-specific details.
181 if sys.version_info >= (3, 0):
182 setup_args.update(dict(
183 use_2to3 = False,
186 def main():
187 """Actually invoke setup() with the arguments we built above."""
188 # 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.
190 try:
191 setup(**setup_args)
192 except BuildFailed:
193 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)
196 print("**\n** %s\n** %s\n**" % (msg, exc_msg))
198 del setup_args['ext_modules']
199 setup(**setup_args)
201 if __name__ == '__main__':
202 main()