summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNed Batchelder <ned@nedbatchelder.com>2012-12-17 07:34:28 -0500
committerNed Batchelder <ned@nedbatchelder.com>2012-12-17 07:34:28 -0500
commitb047cf5066cea144f004b1f30e59f8e795b2a350 (patch)
tree4f29300d3df0c12b8a0c956d09a0d953c1bbd347
parentc8ce85ae37236c43c6733b07948abd5d4380e008 (diff)
parentdf666bd3d23b0250bce797bc9d649c0a62588ae7 (diff)
downloadpython-coveragepy-git-b047cf5066cea144f004b1f30e59f8e795b2a350.tar.gz
Automated merge with ssh://bitbucket.org/ned/coveragepy
-rw-r--r--CHANGES.txt6
-rw-r--r--setup.py55
2 files changed, 54 insertions, 7 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index b7db8660..35bec455 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -5,6 +5,9 @@ Change history for Coverage.py
Version 3.6b2
-------------
+- The C extension is optionally compiled using a different more widely-used
+ technique, taking another stab at fixing ``issue 80``_ once and for all.
+
- Combining data files would create entries for phantom files if used with
``source`` and path aliases. It no longer does.
@@ -17,6 +20,9 @@ Version 3.6b2
.. _issue 221: https://bitbucket.org/ned/coveragepy/issue/221/coveragepy-incompatible-with-pyratemp
+.. _issue 80: https://bitbucket.org/ned/coveragepy/issue/80/is-there-a-duck-typing-way-to-know-we-cant
+
+
Version 3.6b1 -- 28 November 2012
---------------------------------
diff --git a/setup.py b/setup.py
index da054b7e..c62589c4 100644
--- a/setup.py
+++ b/setup.py
@@ -41,6 +41,10 @@ import os, sys
from setuptools import setup
from distutils.core import Extension # pylint: disable=E0611,F0401
+from distutils.command.build_ext import build_ext
+from distutils.errors import (
+ CCompilerError, DistutilsExecError, DistutilsPlatformError
+ )
# Get or massage our metadata. We exec coverage/version.py so we can avoid
# importing the product code into setup.py.
@@ -105,7 +109,44 @@ setup_args = dict(
url = __url__,
)
+# A replacement for the build_ext command which raises a single exception
+# if the build fails, so we can fallback nicely.
+
+ext_errors = (CCompilerError, DistutilsExecError, DistutilsPlatformError)
+if sys.platform == 'win32' and sys.version_info > (2, 6):
+ # 2.6's distutils.msvc9compiler can raise an IOError when failing to
+ # find the compiler
+ ext_errors += (IOError,)
+
+class BuildFailed(Exception):
+ """Raise this to indicate the C extension wouldn't build."""
+ def __init__(self):
+ self.cause = sys.exc_info()[1] # work around py 2/3 different syntax
+
+class ve_build_ext(build_ext):
+ """Build C extensions, but fail with a straightforward exception."""
+
+ def run(self):
+ """Wrap `run` with `BuildFailed`."""
+ try:
+ build_ext.run(self)
+ except DistutilsPlatformError:
+ raise BuildFailed()
+
+ def build_extension(self, ext):
+ """Wrap `build_extension` with `BuildFailed`."""
+ try:
+ build_ext.build_extension(self, ext)
+ except ext_errors:
+ raise BuildFailed()
+ except ValueError:
+ # this can happen on Windows 64 bit, see Python issue 7511
+ if "'path'" in str(sys.exc_info()[1]): # works with both py 2/3
+ raise BuildFailed()
+ raise
+
# There are a few reasons we might not be able to compile the C extension.
+# Figure out if we should attempt the C extension or not.
compile_extension = True
@@ -122,8 +163,13 @@ if compile_extension:
ext_modules = [
Extension("coverage.tracer", sources=["coverage/tracer.c"])
],
+ cmdclass = {
+ 'build_ext': ve_build_ext,
+ },
))
+# Py3.x-specific details.
+
if sys.version_info >= (3, 0):
setup_args.update(dict(
use_2to3=False,
@@ -135,15 +181,10 @@ def main():
# extension. Try it with, and if it fails, try it without.
try:
setup(**setup_args)
- except: # pylint: disable=W0702
- # When setup() can't compile, it tries to exit. We'll catch SystemExit
- # here :-(, and try again.
- if 'install' not in sys.argv or 'ext_modules' not in setup_args:
- # We weren't trying to install an extension, so forget it.
- raise
+ except BuildFailed:
msg = "Couldn't install with extension module, trying without it..."
exc = sys.exc_info()[1]
- exc_msg = "%s: %s" % (exc.__class__.__name__, exc)
+ exc_msg = "%s: %s" % (exc.__class__.__name__, exc.cause)
print("**\n** %s\n** %s\n**" % (msg, exc_msg))
del setup_args['ext_modules']