#!/usr/bin/env python """gevent build & installation script""" from __future__ import print_function import sys import os import os.path import sysconfig # setuptools is *required* on Windows # (https://bugs.python.org/issue23246) and for PyPy. No reason not to # use it everywhere. v24.2.0 is needed for python_requires from setuptools import Extension, setup from setuptools import find_packages from _setuputils import read from _setuputils import read_version from _setuputils import system from _setuputils import PYPY, WIN from _setuputils import IGNORE_CFFI from _setuputils import SKIP_LIBUV from _setuputils import ConfiguringBuildExt from _setuputils import BuildFailed from _setuputils import cythonize1 if WIN: # Make sure the env vars that make.cmd needs are set if not os.environ.get('PYTHON_EXE'): os.environ['PYTHON_EXE'] = 'pypy' if PYPY else 'python' if not os.environ.get('PYEXE'): os.environ['PYEXE'] = os.environ['PYTHON_EXE'] if PYPY and sys.pypy_version_info[:3] < (2, 6, 1): # pylint:disable=no-member # We have to have CFFI >= 1.3.0, and this platform cannot upgrade # it. raise Exception("PyPy >= 2.6.1 is required") __version__ = read_version() from _setuplibev import libev_configure_command from _setuplibev import LIBEV_EMBED from _setuplibev import CORE from _setupares import ARES # Get access to the greenlet header file. # The sysconfig dir is not enough if we're in a virtualenv # See https://github.com/pypa/pip/issues/4610 include_dirs = [sysconfig.get_path("include")] venv_include_dir = os.path.join(sys.prefix, 'include', 'site', 'python' + sysconfig.get_python_version()) venv_include_dir = os.path.abspath(venv_include_dir) if os.path.exists(venv_include_dir): include_dirs.append(venv_include_dir) # If we're installed via buildout, and buildout also installs # greenlet, we have *NO* access to greenlet.h at all. So include # our own copy as a fallback. include_dirs.append('deps') SEMAPHORE = Extension(name="gevent.__semaphore", sources=["src/gevent/_semaphore.py"], depends=['src/gevent/__semaphore.pxd'], include_dirs=include_dirs) LOCAL = Extension(name="gevent._local", sources=["src/gevent/local.py"], depends=['src/gevent/_local.pxd'], include_dirs=include_dirs) GREENLET = Extension(name="gevent._greenlet", sources=[ "src/gevent/greenlet.py", ], depends=[ 'src/gevent/_greenlet.pxd', 'src/gevent/__ident.pxd', 'src/gevent/_ident.py' ], include_dirs=include_dirs) ABSTRACT_LINKABLE = Extension(name="gevent.__abstract_linkable", sources=["src/gevent/_abstract_linkable.py"], depends=['src/gevent/__abstract_linkable.pxd'], include_dirs=include_dirs) IDENT = Extension(name="gevent.__ident", sources=["src/gevent/_ident.py"], depends=['src/gevent/__ident.pxd'], include_dirs=include_dirs) IMAP = Extension(name="gevent.__imap", sources=["src/gevent/_imap.py"], depends=['src/gevent/__imap.pxd'], include_dirs=include_dirs) EVENT = Extension(name="gevent._event", sources=["src/gevent/event.py"], depends=['src/gevent/_event.pxd'], include_dirs=include_dirs) QUEUE = Extension(name="gevent._queue", sources=["src/gevent/queue.py"], depends=['src/gevent/_queue.pxd'], include_dirs=include_dirs) HUB_LOCAL = Extension(name="gevent.__hub_local", sources=["src/gevent/_hub_local.py"], depends=['src/gevent/__hub_local.pxd'], include_dirs=include_dirs) WAITER = Extension(name="gevent.__waiter", sources=["src/gevent/_waiter.py"], depends=['src/gevent/__waiter.pxd'], include_dirs=include_dirs) HUB_PRIMITIVES = Extension(name="gevent.__hub_primitives", sources=["src/gevent/_hub_primitives.py"], depends=['src/gevent/__hub_primitives.pxd'], include_dirs=include_dirs) GLT_PRIMITIVES = Extension(name="gevent.__greenlet_primitives", sources=["src/gevent/_greenlet_primitives.py"], depends=['src/gevent/__greenlet_primitives.pxd'], include_dirs=include_dirs) TRACER = Extension(name="gevent.__tracer", sources=["src/gevent/_tracer.py"], depends=['src/gevent/__tracer.pxd'], include_dirs=include_dirs) _to_cythonize = [ GLT_PRIMITIVES, HUB_PRIMITIVES, HUB_LOCAL, WAITER, GREENLET, TRACER, ABSTRACT_LINKABLE, SEMAPHORE, LOCAL, IDENT, IMAP, EVENT, QUEUE, ] EXT_MODULES = [ CORE, ARES, ABSTRACT_LINKABLE, SEMAPHORE, LOCAL, GREENLET, IDENT, IMAP, EVENT, QUEUE, HUB_LOCAL, WAITER, HUB_PRIMITIVES, GLT_PRIMITIVES, TRACER, ] LIBEV_CFFI_MODULE = 'src/gevent/libev/_corecffi_build.py:ffi' LIBUV_CFFI_MODULE = 'src/gevent/libuv/_corecffi_build.py:ffi' cffi_modules = [] if not WIN: # We can't properly handle (hah!) file-descriptors and # handle mapping on Windows/CFFI with libev, because the file needed, # libev_vfd.h, can't be included, linked, and used: it uses # Python API functions, and you're not supposed to do that from # CFFI code. Plus I could never get the libraries= line to ffi.compile() # correct to make linking work. # Also, we use the type `nlink_t`, which is not defined on Windows. cffi_modules.append( LIBEV_CFFI_MODULE ) if not SKIP_LIBUV: # libuv can't be built on manylinux1 because it needs glibc >= 2.12 # but manylinux1 has only 2.5, so we set SKIP_LIBUV in the script make-manylinux cffi_modules.append(LIBUV_CFFI_MODULE) greenlet_requires = [ # We need to watch our greenlet version fairly carefully, # since we compile cython code that extends the greenlet object. # Binary compatibility would break if the greenlet struct changes. # (Which it did in 0.4.14 for Python 3.7) 'greenlet >= 0.4.14; platform_python_implementation=="CPython"', ] # Note that we don't add cffi to install_requires, it's # optional. We tend to build and distribute wheels with the CFFI # modules built and they can be imported if CFFI is installed. # We need cffi 1.4.0 for new style callbacks; # we need cffi 1.11.3 (on CPython 3) to avoid test errors. # The exception is on Windows, where we want the libuv backend we distribute # to be the default, and that requires cffi; but don't try to install it # on PyPy or it messes up the build cffi_requires = [ "cffi >= 1.11.5 ; sys_platform == 'win32' and platform_python_implementation == 'CPython'", ] install_requires = greenlet_requires + cffi_requires # We use headers from greenlet, so it needs to be installed before we # can compile. If it isn't already installed before we start # installing, and we say 'pip install gevent', a 'setup_requires' # doesn't save us: pip happily downloads greenlet and drops it in a # .eggs/ directory in the build directory, but that directory doesn't # have includes! So we fail to build a wheel, pip goes ahead and # installs greenlet, and builds gevent again, which works. # Since we ship the greenlet header for buildout support (which fails # to install the headers at all, AFAICS, we don't need to bother with # the buggy setup_requires.) setup_requires = cffi_requires + [] if PYPY: # These use greenlet/greenlet.h, which doesn't exist on PyPy EXT_MODULES.remove(LOCAL) EXT_MODULES.remove(GREENLET) EXT_MODULES.remove(SEMAPHORE) EXT_MODULES.remove(ABSTRACT_LINKABLE) # As of PyPy 5.10, this builds, but won't import (missing _Py_ReprEnter) EXT_MODULES.remove(CORE) # This uses PyWeakReference and doesn't compile on PyPy EXT_MODULES.remove(IDENT) _to_cythonize.remove(LOCAL) _to_cythonize.remove(GREENLET) _to_cythonize.remove(SEMAPHORE) _to_cythonize.remove(IDENT) _to_cythonize.remove(ABSTRACT_LINKABLE) EXT_MODULES.remove(IMAP) _to_cythonize.remove(IMAP) EXT_MODULES.remove(EVENT) _to_cythonize.remove(EVENT) EXT_MODULES.remove(QUEUE) _to_cythonize.remove(QUEUE) EXT_MODULES.remove(HUB_LOCAL) _to_cythonize.remove(HUB_LOCAL) EXT_MODULES.remove(WAITER) _to_cythonize.remove(WAITER) EXT_MODULES.remove(GLT_PRIMITIVES) _to_cythonize.remove(GLT_PRIMITIVES) EXT_MODULES.remove(HUB_PRIMITIVES) _to_cythonize.remove(HUB_PRIMITIVES) EXT_MODULES.remove(TRACER) _to_cythonize.remove(TRACER) for mod in _to_cythonize: EXT_MODULES.remove(mod) EXT_MODULES.append(cythonize1(mod)) del _to_cythonize if IGNORE_CFFI and not PYPY: # Allow distributors to turn off CFFI builds # even if it's available, because CFFI always embeds # our copy of libev/libuv and they may not want that. del cffi_modules[:] # If we are running info / help commands, or we're being imported by # tools like pyroma, we don't need to build anything _BUILDING = True if ((len(sys.argv) >= 2 and ('--help' in sys.argv[1:] or sys.argv[1] in ('--help-commands', 'egg_info', '--version', 'clean', '--long-description'))) or __name__ != '__main__'): _BUILDING = False def make_long_description(): readme = read('README.rst') about = read('doc', '_about.rst') install = read('doc', 'install.rst') readme = readme.replace('.. include:: doc/_about.rst', about) readme = readme.replace('.. include:: doc/install.rst', install) return readme def run_setup(ext_modules, run_make): if run_make: if (not LIBEV_EMBED and not WIN and cffi_modules) or PYPY: # We're not embedding libev but we do want # to build the CFFI module. We need to configure libev # because the CORE Extension won't. # TODO: Generalize this. if LIBEV_CFFI_MODULE in cffi_modules and not WIN: system(libev_configure_command) setup( name='gevent', version=__version__, description='Coroutine-based network library', long_description=make_long_description(), license='MIT', keywords='greenlet coroutine cooperative multitasking light threads monkey', author='Denis Bilenko', author_email='denis.bilenko@gmail.com', maintainer='Jason Madden', maintainer_email='jason@nextthought.com', url='http://www.gevent.org/', project_urls={ 'Bug Tracker': 'https://github.com/gevent/gevent/issues', 'Source Code': 'https://github.com/gevent/gevent/', 'Documentation': 'http://www.gevent.org', }, package_dir={'': 'src'}, packages=find_packages('src'), include_package_data=True, ext_modules=ext_modules, cmdclass=dict(build_ext=ConfiguringBuildExt), install_requires=install_requires, setup_requires=setup_requires, extras_require={ 'dnspython': [ 'dnspython', 'idna', ], 'events': [ 'zope.event', 'zope.interface', ], 'doc': [ 'repoze.sphinx.autointerface', ], 'test': [ 'zope.interface', 'zope.event', # Makes tests faster # Fails to build on PyPy on Windows. 'psutil >= 5.6.1 ; platform_python_implementation == "CPython" or sys_platform != "win32"', # examples, called from tests, use this 'requests', # We don't run coverage on Windows, and pypy can't build it there # anyway (coveralls -> cryptopgraphy -> openssl) 'coverage>=5.0a4 ; sys_platform != "win32"', 'coveralls>=1.7.0 ; sys_platform != "win32"', 'futures ; python_version == "2.7"', 'mock ; python_version == "2.7"', # leak checks. previously we had a hand-rolled version. 'objgraph', ] }, # It's always safe to pass the CFFI keyword, even if # cffi is not installed: it's just ignored in that case. cffi_modules=cffi_modules, zip_safe=False, test_suite="greentest.testrunner", classifiers=[ "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Operating System :: MacOS :: MacOS X", "Operating System :: POSIX", "Operating System :: Microsoft :: Windows", "Topic :: Internet", "Topic :: Software Development :: Libraries :: Python Modules", "Intended Audience :: Developers", "Development Status :: 4 - Beta" ], python_requires=">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*", entry_points={ 'gevent.plugins.monkey.will_patch_all': [ "signal_os_incompat = gevent.monkey:_subscribe_signal_os", ], }, ) # Tools like pyroma expect the actual call to `setup` to be performed # at the top-level at import time, so don't stash it away behind 'if # __name__ == __main__' if os.getenv('READTHEDOCS'): # Sometimes RTD fails to put our virtualenv bin directory # on the PATH, meaning we can't run cython. Fix that. new_path = os.environ['PATH'] + os.pathsep + os.path.dirname(sys.executable) os.environ['PATH'] = new_path try: run_setup(EXT_MODULES, run_make=_BUILDING) except BuildFailed: if ARES not in EXT_MODULES or not ARES.optional: raise EXT_MODULES.remove(ARES) run_setup(EXT_MODULES, run_make=_BUILDING) if ARES not in EXT_MODULES and __name__ == '__main__' and _BUILDING: sys.stderr.write('\nWARNING: The gevent.ares extension has been disabled.\n')