Ticket #5158: 5158.2.diff

File 5158.2.diff, 10.3 KB (added by lvh, 5 years ago)
  • twisted/python/dist.py

    diff --git c/twisted/python/dist.py w/twisted/python/dist.py
    index 0d358ee..9b0af2c 100644
    c w Don't use this outside of Twisted. 
    66Maintainer: Christopher Armstrong
    77"""
    88
    9 import sys, os
    109from distutils.command import build_scripts, install_data, build_ext, build_py
    1110from distutils.errors import CompileError
    1211from distutils import core
    1312from distutils.core import Extension
     13import fnmatch
     14import os
     15import platform
     16import sys
     17
    1418
    1519twisted_subprojects = ["conch", "lore", "mail", "names",
    1620                       "news", "pair", "runner", "web",
    1721                       "words"]
    1822
    1923
     24
    2025class ConditionalExtension(Extension):
    2126    """
    2227    An extension module that will only be compiled if certain conditions are
    def setup(**kw): 
    4651    """
    4752    return core.setup(**get_setup_args(**kw))
    4853
     54
    4955def get_setup_args(**kw):
    5056    if 'twisted_subproject' in kw:
    5157        if 'twisted' not in os.listdir('.'):
    def get_setup_args(**kw): 
    100106        kw.setdefault('cmdclass', {})['build_ext'] = my_build_ext
    101107    return kw
    102108
     109
    103110def getVersion(proj, base="twisted"):
    104111    """
    105112    Extract the version number for a given project.
    EXCLUDE_NAMES = ["{arch}", "CVS", ".cvsignore", "_darcs", 
    125132                 "RCS", "SCCS", ".svn"]
    126133EXCLUDE_PATTERNS = ["*.py[cdo]", "*.s[ol]", ".#*", "*~", "*.py"]
    127134
    128 import fnmatch
    129135
    130136def _filterNames(names):
    131     """Given a list of file names, return those names that should be copied.
     137    """
     138    Given a list of file names, return those names that should be copied.
    132139    """
    133140    names = [n for n in names
    134141             if n not in EXCLUDE_NAMES]
    def _filterNames(names): 
    140147                 and (not n.endswith('.py'))]
    141148    return names
    142149
     150
    143151def relativeTo(base, relativee):
    144152    """
    145153    Gets 'relativee' relative to 'basepath'.
    def getDataFiles(dname, ignore=None, parent=None): 
    201209                            for filename in resultfiles]))
    202210    return result
    203211
     212
    204213def getPackages(dname, pkgname=None, results=None, ignore=None, parent=None):
    205214    """
    206215    Get all packages which are under dname. This is necessary for
    def getPackages(dname, pkgname=None, results=None, ignore=None, parent=None): 
    231240    return res
    232241
    233242
    234 
    235243def getScripts(projname, basedir=''):
    236244    """
    237245    Returns a list of scripts for a Twisted subproject; this works in
    class build_ext_twisted(build_ext.build_ext): 
    360368        self.compiler.announce("checking for %s ..." % header_name, 0)
    361369        return self._compile_helper("#include <%s>\n" % header_name)
    362370
     371
     372
     373def _checkCPython(sys=sys, platform=platform):
     374    """
     375    Checks if this implementation is CPython.
     376
     377    On recent versions of Python, will use L{platform.python_implementation}.
     378    On 2.5, it will try to extract the implementation from sys.subversion. On
     379    older versions (currently the only supported older version is 2.4), checks
     380    if C{__pypy__} is in L{sys.modules}, since PyPy is the implementation we
     381    really care about. If it isn't, assumes CPython.
     382
     383    This takes C{sys} and C{platform} kwargs that by default use the real
     384    modules. You shouldn't care about these -- they are for testing purposes
     385    only.
     386
     387    @return: C{False} if the implementation is definitely not CPython, C{True}
     388        otherwise.
     389    """
     390    try:
     391        return platform.python_implementation() == "CPython"
     392    except AttributeError:
     393        # For 2.5:
     394        try:
     395            implementation, _, _ = sys.subversion
     396            return implementation == "CPython"
     397        except AttributeError:
     398            pass
     399
     400        # Are we on Pypy?
     401        if "__pypy__" in sys.modules:
     402            return False
     403
     404        # No? Well, then we're *probably* on CPython.
     405        return True
     406
     407
     408_isCPython = _checkCPython()
     409
     410
     411def _hasEpoll(builder):
     412    """
     413    Checks if the header for building epoll (C{sys/epoll.h}) is available.
     414
     415    @return: C{True} if the header is available, C{False} otherwise.
     416    """
     417    return builder._check_header("sys/epoll.h")
  • twisted/python/test/test_dist.py

    diff --git c/twisted/python/test/test_dist.py w/twisted/python/test/test_dist.py
    index a27ff94..39f4438 100644
    c w class GetScriptsTest(TestCase): 
    190190        os.mkdir(basedir)
    191191        scripts = dist.getScripts('noscripts', basedir=basedir)
    192192        self.assertEqual(scripts, [])
     193
     194
     195
     196class FakeModule(object):
     197    """
     198    A fake module, suitable for dependency injection in testing.
     199    """
     200    def __init__(self, attrs):
     201        """
     202        Initializes a fake module.
     203
     204        @param attrs: The attrs that will be accessible on the module.
     205        @type attrs: C{dict} of C{str} (Python names) to objects
     206        """
     207        self._attrs = attrs
     208
     209    def __getattr__(self, name):
     210        """
     211        Gets an attribute of this fake module from its attrs.
     212
     213        @raise AttributeError: When the requested attribute is missing.
     214        """
     215        try:
     216            return self._attrs[name]
     217        except KeyError:
     218            raise AttributeError()
     219
     220
     221
     222fakeCPythonPlatform = FakeModule({"python_implementation": lambda: "CPython"})
     223fakeOtherPlatform = FakeModule({"python_implementation": lambda: "lvhpy"})
     224emptyPlatform = FakeModule({})
     225
     226
     227
     228class WithPlatformTest(TestCase):
     229    """
     230    Tests if L{_checkCPython} works correctly with (fake) recent
     231    C{platform} modules.
     232    """
     233    def test_cpython(self):
     234        """
     235        Tests that L{_checkCPython} returns C{True} when
     236        C{platform.python_implementation} says we're running on CPython.
     237        """
     238        self.assertTrue(dist._checkCPython(platform=fakeCPythonPlatform))
     239
     240
     241    def test_other(self):
     242        """
     243        Tests that L{_checkCPython} returns C{True} when
     244        C{platform.python_implementation} says we're not running on CPython.
     245        """
     246        self.assertFalse(dist._checkCPython(platform=fakeOtherPlatform))
     247
     248
     249
     250fakeCPythonSys = FakeModule({"subversion": ("CPython", None, None)})
     251fakeOtherSys = FakeModule({"subversion": ("lvhpy", None, None)})
     252
     253
     254def _checkCPythonWithEmptyPlatform(sys):
     255    """
     256    A partially applied L{_checkCPython} that uses an empty C{platform}
     257    module (otherwise the code this test case is supposed to test won't
     258    even be called).
     259    """
     260    return dist._checkCPython(platform=emptyPlatform, sys=sys)
     261
     262
     263
     264class WithSubversionTest(TestCase):
     265    """
     266    Tests if L{_checkCPython} works correctly with (fake) recent (2.5+)
     267    C{sys.subversion}. This is effectively only relevant for 2.5, since 2.6
     268    and beyond have L{platform.python_implementation}, which is tried first.
     269    """
     270    def test_cpython(self):
     271        """
     272        Tests that L{_checkCPython} returns C{True} when
     273        C{platform.python_implementation} is unavailable and C{sys.subversion}
     274        says we're running on CPython.
     275        """
     276        isCPython = _checkCPythonWithEmptyPlatform(fakeCPythonSys)
     277        self.assertTrue(isCPython)
     278
     279
     280    def test_other(self):
     281        """
     282        Tests that L{_checkCPython} returns C{False} when
     283        C{platform.python_implementation} is unavailable and C{sys.subversion}
     284        says we're not running on CPython.
     285        """
     286        isCPython = _checkCPythonWithEmptyPlatform(fakeOtherSys)
     287        self.assertFalse(isCPython)
     288
     289
     290
     291oldCPythonSys = FakeModule({"modules": {}})
     292oldPypySys = FakeModule({"modules": {"__pypy__": None}})
     293
     294
     295class OldPythonsFallbackTest(TestCase):
     296    """
     297    Tests if L{_checkCPython} correctly recognizes PyPy on 2.4, when neither
     298    C{platform.python_implementation} or C{sys.subversion} is available.
     299    """
     300    def test_cpython(self):
     301        """
     302        Tests that L{_checkCPython} returns C{True} when both
     303        C{platform.python_implementation} and C{sys.subversion} are
     304        unavailable and there is no C{__pypy__} module in C{sys.modules}.
     305        """
     306        isCPython = _checkCPythonWithEmptyPlatform(oldCPythonSys)
     307        self.assertTrue(isCPython)
     308
     309
     310    def test_pypy(self):
     311        """
     312        Tests that L{_checkCPython} returns C{False} when both
     313        C{platform.python_implementation} and C{sys.subversion} are
     314        unavailable and there is a C{__pypy__} module in C{sys.modules}.
     315        """
     316        isCPython = _checkCPythonWithEmptyPlatform(oldPypySys)
     317        self.assertFalse(isCPython)
  • twisted/topfiles/setup.py

    diff --git c/twisted/topfiles/setup.py w/twisted/topfiles/setup.py
    index a1e0ae7..807dde2 100644
    c w  
    66Distutils installer for Twisted.
    77"""
    88
    9 import os, sys
     9import os
     10import sys
    1011
    1112if sys.version_info < (2,3):
    1213    print >>sys.stderr, "You must use at least Python 2.3 for Twisted"
    if os.path.exists('twisted'): 
    1718from twisted import copyright
    1819from twisted.python.dist import setup, ConditionalExtension as Extension
    1920from twisted.python.dist import getPackages, getDataFiles, getScripts
    20 from twisted.python.dist import twisted_subprojects
    21 
     21from twisted.python.dist import twisted_subprojects, _isCPython, _hasEpoll
    2222
    2323
    2424extensions = [
    2525    Extension("twisted.test.raiser",
    26               ["twisted/test/raiser.c"]),
     26              ["twisted/test/raiser.c"],
     27              condition=lambda _: _isCPython),
    2728
    2829    Extension("twisted.python._epoll",
    2930              ["twisted/python/_epoll.c"],
    30               condition=lambda builder: builder._check_header("sys/epoll.h")),
     31              condition=lambda builder: _isCPython and _hasEpoll(builder)),
    3132
    3233    Extension("twisted.internet.iocpreactor.iocpsupport",
    3334              ["twisted/internet/iocpreactor/iocpsupport/iocpsupport.c",
    3435               "twisted/internet/iocpreactor/iocpsupport/winsock_pointers.c"],
    3536              libraries=["ws2_32"],
    36               condition=lambda builder: sys.platform == "win32"),
     37              condition=lambda _: _isCPython and sys.platform == "win32"),
    3738
    3839    Extension("twisted.python._initgroups",
    3940              ["twisted/python/_initgroups.c"]),
    4041    Extension("twisted.internet._sigchld",
    4142              ["twisted/internet/_sigchld.c"],
    42               condition=lambda builder: sys.platform != "win32"),
     43              condition=lambda _: sys.platform != "win32"),
    4344]
    4445
    4546# Figure out which plugins to include: all plugins except subproject ones