setup.py 6.0 KB

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