1############################################################################## 2# 3# Copyright (c) 2006 Zope Foundation and Contributors. 4# All Rights Reserved. 5# 6# This software is subject to the provisions of the Zope Public License, 7# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. 8# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED 9# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 10# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS 11# FOR A PARTICULAR PURPOSE. 12# 13############################################################################## 14""" 15Support functions for dealing with differences in platforms, including Python 16versions and implementations. 17 18This file should have no imports from the rest of zope.interface because it is 19used during early bootstrapping. 20""" 21import os 22import sys 23import types 24 25if sys.version_info[0] < 3: 26 27 def _normalize_name(name): 28 if isinstance(name, basestring): 29 return unicode(name) 30 raise TypeError("name must be a regular or unicode string") 31 32 CLASS_TYPES = (type, types.ClassType) 33 STRING_TYPES = (basestring,) 34 35 _BUILTINS = '__builtin__' 36 37 PYTHON3 = False 38 PYTHON2 = True 39 40else: 41 42 def _normalize_name(name): 43 if isinstance(name, bytes): 44 name = str(name, 'ascii') 45 if isinstance(name, str): 46 return name 47 raise TypeError("name must be a string or ASCII-only bytes") 48 49 CLASS_TYPES = (type,) 50 STRING_TYPES = (str,) 51 52 _BUILTINS = 'builtins' 53 54 PYTHON3 = True 55 PYTHON2 = False 56 57PYPY = hasattr(sys, 'pypy_version_info') 58PYPY2 = PYTHON2 and PYPY 59 60def _skip_under_py3k(test_method): 61 import unittest 62 return unittest.skipIf(sys.version_info[0] >= 3, "Only on Python 2")(test_method) 63 64 65def _skip_under_py2(test_method): 66 import unittest 67 return unittest.skipIf(sys.version_info[0] < 3, "Only on Python 3")(test_method) 68 69 70def _c_optimizations_required(): 71 """ 72 Return a true value if the C optimizations are required. 73 74 This uses the ``PURE_PYTHON`` variable as documented in `_use_c_impl`. 75 """ 76 pure_env = os.environ.get('PURE_PYTHON') 77 require_c = pure_env == "0" 78 return require_c 79 80 81def _c_optimizations_available(): 82 """ 83 Return the C optimization module, if available, otherwise 84 a false value. 85 86 If the optimizations are required but not available, this 87 raises the ImportError. 88 89 This does not say whether they should be used or not. 90 """ 91 catch = () if _c_optimizations_required() else (ImportError,) 92 try: 93 from zope.interface import _zope_interface_coptimizations as c_opt 94 return c_opt 95 except catch: # pragma: no cover (only Jython doesn't build extensions) 96 return False 97 98 99def _c_optimizations_ignored(): 100 """ 101 The opposite of `_c_optimizations_required`. 102 """ 103 pure_env = os.environ.get('PURE_PYTHON') 104 return pure_env is not None and pure_env != "0" 105 106 107def _should_attempt_c_optimizations(): 108 """ 109 Return a true value if we should attempt to use the C optimizations. 110 111 This takes into account whether we're on PyPy and the value of the 112 ``PURE_PYTHON`` environment variable, as defined in `_use_c_impl`. 113 """ 114 is_pypy = hasattr(sys, 'pypy_version_info') 115 116 if _c_optimizations_required(): 117 return True 118 if is_pypy: 119 return False 120 return not _c_optimizations_ignored() 121 122 123def _use_c_impl(py_impl, name=None, globs=None): 124 """ 125 Decorator. Given an object implemented in Python, with a name like 126 ``Foo``, import the corresponding C implementation from 127 ``zope.interface._zope_interface_coptimizations`` with the name 128 ``Foo`` and use it instead. 129 130 If the ``PURE_PYTHON`` environment variable is set to any value 131 other than ``"0"``, or we're on PyPy, ignore the C implementation 132 and return the Python version. If the C implementation cannot be 133 imported, return the Python version. If ``PURE_PYTHON`` is set to 134 0, *require* the C implementation (let the ImportError propagate); 135 note that PyPy can import the C implementation in this case (and all 136 tests pass). 137 138 In all cases, the Python version is kept available. in the module 139 globals with the name ``FooPy`` and the name ``FooFallback`` (both 140 conventions have been used; the C implementation of some functions 141 looks for the ``Fallback`` version, as do some of the Sphinx 142 documents). 143 144 Example:: 145 146 @_use_c_impl 147 class Foo(object): 148 ... 149 """ 150 name = name or py_impl.__name__ 151 globs = globs or sys._getframe(1).f_globals 152 153 def find_impl(): 154 if not _should_attempt_c_optimizations(): 155 return py_impl 156 157 c_opt = _c_optimizations_available() 158 if not c_opt: # pragma: no cover (only Jython doesn't build extensions) 159 return py_impl 160 161 __traceback_info__ = c_opt 162 return getattr(c_opt, name) 163 164 c_impl = find_impl() 165 # Always make available by the FooPy name and FooFallback 166 # name (for testing and documentation) 167 globs[name + 'Py'] = py_impl 168 globs[name + 'Fallback'] = py_impl 169 170 return c_impl 171