]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Mark extension modules as optional
authorFederico Caselli <cfederico87@gmail.com>
Mon, 29 Aug 2022 22:26:49 +0000 (00:26 +0200)
committerMike Bayer <mike_mp@zzzcomputing.com>
Thu, 1 Sep 2022 22:21:41 +0000 (18:21 -0400)
This greatly simplifies the setup.py file and makes it compatible with
setuptools 64+ change to editable install.

Change-Id: I16a776b175bcf67e26f4bbb8f80b1b473f585e2a

setup.py

index c60a214141f7947ebd50ac6dca79348e80a73bb7..ae71acd2c528006093b43616100ab4559244218b 100644 (file)
--- a/setup.py
+++ b/setup.py
+from __future__ import annotations
+
 import os
 import platform
-import sys
+from typing import cast
+from typing import TYPE_CHECKING
 
-from setuptools import __version__
 from setuptools import setup
 
-if not int(__version__.partition(".")[0]) >= 47:
-    raise RuntimeError(f"Setuptools >= 47 required. Found {__version__}")
-
-# attempt to use pep-632 imports for setuptools symbols; however,
-# since these symbols were only added to setuptools as of 59.0.1,
-# fall back to the distutils symbols otherwise
-try:
-    from setuptools.errors import CCompilerError
-    from setuptools.errors import DistutilsExecError
-    from setuptools.errors import DistutilsPlatformError
-except ImportError:
-    from distutils.errors import CCompilerError
-    from distutils.errors import DistutilsExecError
-    from distutils.errors import DistutilsPlatformError
+if TYPE_CHECKING:
+    from setuptools import Extension
 
 try:
-    from Cython.Distutils.old_build_ext import old_build_ext
-    from Cython.Distutils.extension import Extension
+    from Cython.Build import build_ext as _cy_build_ext
+    from Cython.Distutils.extension import Extension as _cy_Extension
 
-    CYTHON = True
+    HAS_CYTHON = True
 except ImportError:
-    CYTHON = False
-
-cmdclass = {}
-
-cpython = platform.python_implementation() == "CPython"
-
-ext_errors = (CCompilerError, DistutilsExecError, DistutilsPlatformError)
-extra_compile_args = []
-if sys.platform == "win32":
-    # Work around issue https://github.com/pypa/setuptools/issues/1902
-    ext_errors += (IOError, TypeError)
-
-cython_files = [
-    "collections.pyx",
-    "immutabledict.pyx",
-    "processors.pyx",
-    "resultproxy.pyx",
-    "util.pyx",
-]
-cython_directives = {"language_level": "3"}
-
-if CYTHON:
-
-    def get_ext_modules():
-        module_prefix = "sqlalchemy.cyextension."
-        source_prefix = "lib/sqlalchemy/cyextension/"
-
-        ext_modules = []
-        for file in cython_files:
-            name, _ = os.path.splitext(file)
-            ext_modules.append(
-                Extension(
-                    module_prefix + name,
-                    sources=[source_prefix + file],
-                    extra_compile_args=extra_compile_args,
-                    cython_directives=cython_directives,
-                )
-            )
-        return ext_modules
-
-    class BuildFailed(Exception):
-        pass
-
-    class ve_build_ext(old_build_ext):
-        # This class allows Cython building to fail.
-
-        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
-
-    cmdclass["build_ext"] = ve_build_ext
-    ext_modules = get_ext_modules()
-else:
-    ext_modules = []
+    _cy_build_ext = _cy_Extension = None
+    HAS_CYTHON = False
 
+IS_CPYTHON = platform.python_implementation() == "CPython"
+DISABLE_EXTENSION = bool(os.environ.get("DISABLE_SQLALCHEMY_CEXT"))
+REQUIRE_EXTENSION = bool(os.environ.get("REQUIRE_SQLALCHEMY_CEXT"))
 
-def status_msgs(*msgs):
-    print("*" * 75)
-    for msg in msgs:
-        print(msg)
-    print("*" * 75)
+if DISABLE_EXTENSION and REQUIRE_EXTENSION:
+    raise RuntimeError(
+        "Cannot set both 'DISABLE_SQLALCHEMY_CEXT' and "
+        "'REQUIRE_SQLALCHEMY_CEXT' environment variables"
+    )
 
 
-def run_setup(with_cext):
-    kwargs = {}
-    if with_cext:
-        kwargs["ext_modules"] = ext_modules
-    else:
-        if os.environ.get("REQUIRE_SQLALCHEMY_CEXT"):
-            raise AssertionError(
-                "Can't build on this platform with REQUIRE_SQLALCHEMY_CEXT"
-                " set. Cython is required to build compiled extensions"
+if HAS_CYTHON and IS_CPYTHON and not DISABLE_EXTENSION:
+    assert _cy_Extension is not None
+    assert _cy_build_ext is not None
+
+    cython_files = [
+        "collections.pyx",
+        "immutabledict.pyx",
+        "processors.pyx",
+        "resultproxy.pyx",
+        "util.pyx",
+    ]
+    cython_directives = {"language_level": "3"}
+
+    module_prefix = "sqlalchemy.cyextension."
+    source_prefix = "lib/sqlalchemy/cyextension/"
+
+    ext_modules = cast(
+        "list[Extension]",
+        [
+            _cy_Extension(
+                f"{module_prefix}{os.path.splitext(file)[0]}",
+                sources=[f"{source_prefix}{file}"],
+                cython_directives=cython_directives,
+                optional=not REQUIRE_EXTENSION,
             )
+            for file in cython_files
+        ],
+    )
 
-        kwargs["ext_modules"] = []
-
-    setup(cmdclass=cmdclass, **kwargs)
+    cmdclass = {"build_ext": _cy_build_ext}
 
+elif REQUIRE_EXTENSION:
 
-if not cpython:
-    run_setup(False)
-    status_msgs(
-        "WARNING: Cython extensions are not supported on "
-        "this Python platform, speedups are not enabled.",
-        "Plain-Python build succeeded.",
-    )
-elif not CYTHON:
-    run_setup(False)
-    status_msgs(
-        "WARNING: Cython is required to build the compiled "
-        "extensions, speedups are not enabled.",
-        "Plain-Python build succeeded.",
-    )
-elif os.environ.get("DISABLE_SQLALCHEMY_CEXT"):
-    run_setup(False)
-    status_msgs(
-        "DISABLE_SQLALCHEMY_CEXT is set; "
-        "not attempting to build Cython extensions.",
-        "Plain-Python build succeeded.",
+    reasons = []
+    if not HAS_CYTHON:
+        reasons.append("Cython is missing")
+    if not IS_CPYTHON:
+        reasons.append("Not CPython, build is supported only on it")
+    raise RuntimeError(
+        "Cython extension build is required because REQUIRE_SQLALCHEMY_CEXT "
+        f"is set but it was deselected because: {'; '.join(reasons)}; "
+        "will not degrade to pure python install"
     )
+
 else:
-    try:
-        run_setup(True)
-    except BuildFailed as exc:
-
-        if os.environ.get("REQUIRE_SQLALCHEMY_CEXT"):
-            status_msgs(
-                "NOTE: Cython extension build is required because "
-                "REQUIRE_SQLALCHEMY_CEXT is set, and the build has failed; "
-                "will not degrade to non-C extensions"
-            )
-            raise
-
-        status_msgs(
-            exc.__cause__,
-            "WARNING: The Cython extension could not be compiled, "
-            "speedups are not enabled.",
-            "Failure information, if any, is above.",
-            "Retrying the build without the C extension now.",
-        )
-
-        run_setup(False)
-
-        status_msgs(
-            "WARNING: The Cython extension could not be compiled, "
-            "speedups are not enabled.",
-            "Plain-Python build succeeded.",
-        )
+    ext_modules = []
+    cmdclass = {}
+
+setup(cmdclass=cmdclass, ext_modules=ext_modules)