summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Madden <jamadden@gmail.com>2017-09-11 13:01:11 -0500
committerJason Madden <jamadden@gmail.com>2017-09-11 13:01:11 -0500
commit2a5fba13a04cea6119ba92fe38e4483f4cb5c7f6 (patch)
tree281047e4d980efa0d3af2181d95d9e2acf524b41
parentb339f682bf801ca4d041282e8f9a2662a68a0236 (diff)
downloadzope-security-2a5fba13a04cea6119ba92fe38e4483f4cb5c7f6.tar.gz
Use features and an optional_build_extissue33b
Just like zope.interface (copied from there). Fixes #33. This should eliminate any chance of polluting (local) wheel caches if PURE_PYTHON happens to be defined.
-rw-r--r--CHANGES.rst4
-rw-r--r--setup.py119
2 files changed, 76 insertions, 47 deletions
diff --git a/CHANGES.rst b/CHANGES.rst
index 1ebd486..cfeedca 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -35,7 +35,9 @@ Changes
- Simplify the internal ``_compat.py`` module now that we only run on
newer Python versions. See `PR 32 <https://github.com/zopefoundation/zope.security/pull/32>`_.
-- Respect ``PURE_PYTHON`` at runtime. See `issue 33
+- Respect ``PURE_PYTHON`` at runtime. At build time, always try to
+ build the C extensions on supported platforms, ignoring
+ ``PURE_PYTHON``. See `issue 33
<https://github.com/zopefoundation/zope.security/issues/33>`_.
- Fix watching checkers (``ZOPE_WATCH_CHECKERS=1``) in pure-Python
diff --git a/setup.py b/setup.py
index 8368c92..9bd6988 100644
--- a/setup.py
+++ b/setup.py
@@ -21,33 +21,45 @@
import os
import platform
import sys
+
+
+from distutils.errors import CCompilerError
+from distutils.errors import DistutilsExecError
+from distutils.errors import DistutilsPlatformError
+
+
from setuptools import Extension
+from setuptools.command.build_ext import build_ext
from setuptools import find_packages
from setuptools import setup
+from setuptools import Feature
+
+class optional_build_ext(build_ext):
+ """This class subclasses build_ext and allows
+ the building of C extensions to fail.
+ """
+ def run(self):
+ try:
+ build_ext.run(self)
+ except DistutilsPlatformError as e:
+ self._unavailable(e)
+
+ def build_extension(self, ext):
+ try:
+ build_ext.build_extension(self, ext)
+ except (CCompilerError, DistutilsExecError, OSError) as e:
+ self._unavailable(e)
+
+ def _unavailable(self, e):
+ print('*' * 80)
+ print("""WARNING:
+ An optional code optimization (C extension) could not be compiled.
+ Optimizations for this package will not be available!""")
+ print()
+ print(e)
+ print('*' * 80)
-TESTS_REQUIRE = [
- 'BTrees',
- 'zope.component',
- 'zope.configuration',
- 'zope.location',
- 'zope.testing',
- 'zope.testrunner',
-]
-def alltests():
- import os
- import sys
- import unittest
- # use the zope.testrunner machinery to find all the
- # test suites we've put under ourselves
- import zope.testrunner.find
- import zope.testrunner.options
- here = os.path.abspath(os.path.join(os.path.dirname(__file__), 'src'))
- args = sys.argv[:]
- defaults = ["--test-path", here]
- options = zope.testrunner.options.get_options(args, defaults)
- suites = list(zope.testrunner.find.find_suites(options))
- return unittest.TestSuite(suites)
here = os.path.abspath(os.path.dirname(__file__))
def read(*rnames):
@@ -55,9 +67,7 @@ def read(*rnames):
return f.read()
# Include directories for C extensions
-# Sniff the location of the headers in 'persistent' or fall back
-# to local headers in the include sub-directory
-
+# Sniff the location of the headers in the package distribution
class ModuleHeaderDir(object):
def __init__(self, require_spec, where='../..'):
@@ -71,40 +81,55 @@ class ModuleHeaderDir(object):
def __str__(self):
from pkg_resources import require
from pkg_resources import resource_filename
- from pkg_resources import DistributionNotFound
- try:
- require(self._require_spec)
- path = resource_filename(self._require_spec, self._where)
- except DistributionNotFound:
- path = os.path.join(here, 'include')
+ require(self._require_spec)
+ path = resource_filename(self._require_spec, self._where)
return os.path.abspath(path)
include = [ModuleHeaderDir('zope.proxy')]
+codeoptimization = Feature(
+ "Optional code optimizations",
+ standard=True,
+ ext_modules=[
+ Extension(
+ "zope.security._proxy",
+ [os.path.join('src', 'zope', 'security', "_proxy.c")],
+ include_dirs=include,
+ ),
+ Extension(
+ "zope.security._zope_security_checker",
+ [os.path.join('src', 'zope', 'security',
+ "_zope_security_checker.c")]
+ ),
+ ]
+)
+
# Jython cannot build the C optimizations, while on PyPy they are
# anti-optimizations (the C extension compatibility layer is known-slow,
# and defeats JIT opportunities).
py3 = sys.version_info[0] >= 3
py_impl = getattr(platform, 'python_implementation', lambda: None)
-pure_python = os.environ.get('PURE_PYTHON', False)
is_pypy = py_impl() == 'PyPy'
is_jython = 'java' in sys.platform
-if pure_python or is_pypy or is_jython:
+if is_pypy or is_jython:
setup_requires = []
- ext_modules = []
+ features = {}
else:
setup_requires = ['zope.proxy >= 4.1.0']
- ext_modules = [
- Extension("zope.security._proxy",
- [os.path.join('src', 'zope', 'security', "_proxy.c")],
- include_dirs=include,
- ),
- Extension("zope.security._zope_security_checker",
- [os.path.join('src', 'zope', 'security',
- "_zope_security_checker.c")]
- ),
- ]
+ features = {
+ 'codeoptimization': codeoptimization,
+ }
+
+TESTS_REQUIRE = [
+ 'BTrees',
+ 'zope.component',
+ 'zope.configuration',
+ 'zope.location',
+ 'zope.testing',
+ 'zope.testrunner',
+]
+
setup(name='zope.security',
version='4.1.2.dev0',
@@ -142,7 +167,10 @@ setup(name='zope.security',
package_dir={'': 'src'},
namespace_packages=['zope'],
setup_requires=setup_requires,
- ext_modules=ext_modules,
+ cmdclass={
+ 'build_ext': optional_build_ext,
+ },
+ features=features,
install_requires=[
'setuptools',
'zope.component',
@@ -152,7 +180,6 @@ setup(name='zope.security',
'zope.proxy >= 4.1.0',
'zope.schema',
],
- test_suite='__main__.alltests',
tests_require=TESTS_REQUIRE,
extras_require=dict(
pytz=["pytz"],