Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: change setup.py to use optional build_ext option #2242

Merged
merged 5 commits into from
Jul 18, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 31 additions & 103 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,65 +2,29 @@
import io
import os
from os import path
import platform
import re
import sys

from setuptools import Extension
from setuptools import setup

MYDIR = path.abspath(os.path.dirname(__file__))

try:
sys.pypy_version_info
PYPY = True
except AttributeError:
PYPY = False

if PYPY:
CYTHON = False
else:
try:
from Cython.Distutils import build_ext

CYTHON = True
except ImportError:
CYTHON = False

from Cython.Build import build_ext as _cy_build_ext
from Cython.Distutils.extension import Extension as _cy_Extension

class BuildFailed(Exception):
pass
HAS_CYTHON = True
except ImportError:
_cy_build_ext = _cy_Extension = None
HAS_CYTHON = False

DISABLE_EXTENSION = bool(os.environ.get('FALCON_DISABLE_CYTHON'))
IS_CPYTHON = platform.python_implementation() == 'CPython'

def get_cython_options():
# from sqlalchemy setup.py
from distutils.errors import CCompilerError
from distutils.errors import DistutilsExecError
from distutils.errors import DistutilsPlatformError

ext_errors = (CCompilerError, DistutilsExecError, DistutilsPlatformError)
if sys.platform == 'win32':
# Work around issue https://github.com/pypa/setuptools/issues/1902
ext_errors += (IOError, TypeError)

class ve_build_ext(build_ext):
# This class allows Cython building to fail.
MYDIR = path.abspath(os.path.dirname(__file__))

def run(self):
try:
super().run()
except DistutilsPlatformError:
raise BuildFailed()

def build_extension(self, ext):
try:
super().build_extension(ext)
except ext_errors as e:
raise BuildFailed() from e
except ValueError as e:
# this can happen on Windows 64 bit, see Python issue 7511
if "'path'" in str(e):
raise BuildFailed() from e
raise
if HAS_CYTHON and IS_CPYTHON and not DISABLE_EXTENSION:
assert _cy_Extension is not None
assert _cy_build_ext is not None

def list_modules(dirname, pattern):
filenames = glob.glob(path.join(dirname, pattern))
Expand Down Expand Up @@ -102,15 +66,17 @@ def list_modules(dirname, pattern):
'falcon.util.sync',
]

cython_package_names = frozenset(
[
'falcon.cyutil',
]
)
cython_package_names = ('falcon.cyutil',)
# NOTE(vytas): Now that all our codebase is Python 3.7+, specify the
# Python 3 language level for Cython as well to avoid any surprises.
cython_directives = {'language_level': '3', 'annotation_typing': False}

ext_modules = [
Extension(
package + '.' + module, [path.join(*(package.split('.') + [module + ext]))]
_cy_Extension(
package + '.' + module,
sources=[path.join(*(package.split('.') + [module + ext]))],
cython_directives=cython_directives,
optional=True,
)
for package in package_names
for module, ext in list_modules(
Expand All @@ -120,13 +86,10 @@ def list_modules(dirname, pattern):
if (package + '.' + module) not in modules_to_exclude
]

# NOTE(vytas): Now that all our codebase is Python 3.7+, specify the
# Python 3 language level for Cython as well to avoid any surprises.
for ext_mod in ext_modules:
ext_mod.cython_directives = {'language_level': '3', 'annotation_typing': False}

cmdclass = {'build_ext': ve_build_ext}
return cmdclass, ext_modules
cmdclass = {'build_ext': _cy_build_ext}
else:
ext_modules = []
cmdclass = {}


def load_description():
Expand Down Expand Up @@ -163,47 +126,12 @@ def load_description():
return ''.join(description_lines)


def run_setup(CYTHON):
if CYTHON:
cmdclass, ext_modules = get_cython_options()
else:
cmdclass, ext_modules = {}, []

setup(
long_description=load_description(),
cmdclass=cmdclass,
ext_modules=ext_modules,
)


def status_msgs(*msgs):
print('*' * 75, *msgs, '*' * 75, sep='\n')


if not CYTHON:
run_setup(False)
if not PYPY:
status_msgs('Cython compilation not supported in this environment')
elif os.environ.get('FALCON_DISABLE_CYTHON'):
run_setup(False)
status_msgs(
'FALCON_DISABLE_CYTHON is set, skipping cython compilation.',
'Pure-Python build succeeded.',
)
else:
try:
run_setup(True)
except BuildFailed as exc:
status_msgs(
exc.__cause__,
'Cython compilation could not be completed, speedups are not enabled.',
'Failure information, if any, is above.',
'Retrying the build without the C extension now.',
)

run_setup(False)

status_msgs(
'Cython compilation could not be completed, speedups are not enabled.',
'Pure-Python build succeeded.',
)
setup(
long_description=load_description(),
cmdclass=cmdclass,
ext_modules=ext_modules,
)
Loading