1a2094b1bSPhilip Jenveyfrom distutils.command.build_ext import build_ext
25ab9ab79SMike Bayerfrom distutils.errors import CCompilerError
35ab9ab79SMike Bayerfrom distutils.errors import DistutilsExecError
45ab9ab79SMike Bayerfrom distutils.errors import DistutilsPlatformError
51e278de4SMike Bayerimport os
61e278de4SMike Bayerimport platform
7cd03b8f0SMike Bayerimport re
81e278de4SMike Bayerimport sys
91e278de4SMike Bayer
101e278de4SMike Bayerfrom setuptools import Distribution as _Distribution
111e278de4SMike Bayerfrom setuptools import Extension
121e278de4SMike Bayerfrom setuptools import setup
135ab9ab79SMike Bayerfrom setuptools.command.test import test as TestCommand
147dcfccb3SMike Bayer
151e278de4SMike Bayer
16ec97911eSMike Bayercmdclass = {}
177dcfccb3SMike Bayer
181e1a38e7SMike Bayercpython = platform.python_implementation() == "CPython"
1956ef17e0SMike Bayer
205b6a1a98SFederico Caselliext_errors = (CCompilerError, DistutilsExecError, DistutilsPlatformError)
215b6a1a98SFederico Caselliif sys.platform == "win32":
225b6a1a98SFederico Caselli    # Work around issue https://github.com/pypa/setuptools/issues/1902
235b6a1a98SFederico Caselli    ext_errors += (IOError, TypeError)
245b6a1a98SFederico Caselli    extra_compile_args = []
25e3fbbf83SMike Bayerelif sys.platform in ("linux", "linux2"):
265b6a1a98SFederico Caselli    # warn for undefined symbols in .c files
27e3fbbf83SMike Bayer    extra_compile_args = ["-Wundef", "-Werror=implicit-function-declaration"]
285b6a1a98SFederico Casellielse:
295b6a1a98SFederico Caselli    extra_compile_args = []
305b6a1a98SFederico Caselli
3174f2e214SPhilip Jenveyext_modules = [
321e1a38e7SMike Bayer    Extension(
331e1a38e7SMike Bayer        "sqlalchemy.cprocessors",
341e1a38e7SMike Bayer        sources=["lib/sqlalchemy/cextension/processors.c"],
355b6a1a98SFederico Caselli        extra_compile_args=extra_compile_args,
361e1a38e7SMike Bayer    ),
371e1a38e7SMike Bayer    Extension(
381e1a38e7SMike Bayer        "sqlalchemy.cresultproxy",
391e1a38e7SMike Bayer        sources=["lib/sqlalchemy/cextension/resultproxy.c"],
405b6a1a98SFederico Caselli        extra_compile_args=extra_compile_args,
411e1a38e7SMike Bayer    ),
42fcbd03e4SMike Bayer    Extension(
43fcbd03e4SMike Bayer        "sqlalchemy.cimmutabledict",
44fcbd03e4SMike Bayer        sources=["lib/sqlalchemy/cextension/immutabledict.c"],
45fcbd03e4SMike Bayer        extra_compile_args=extra_compile_args,
46fcbd03e4SMike Bayer    ),
475ab9ab79SMike Bayer]
48a2094b1bSPhilip Jenvey
49304e5b2aSBrian Jarrett
50a2094b1bSPhilip Jenveyclass BuildFailed(Exception):
51fcded554SMike Bayer    def __init__(self):
5200e29c4cSMike Bayer        self.cause = sys.exc_info()[1]  # work around py 2/3 different syntax
53a2094b1bSPhilip Jenvey
54304e5b2aSBrian Jarrett
55a2094b1bSPhilip Jenveyclass ve_build_ext(build_ext):
56a2094b1bSPhilip Jenvey    # This class allows C extension building to fail.
57a2094b1bSPhilip Jenvey
58a2094b1bSPhilip Jenvey    def run(self):
59a2094b1bSPhilip Jenvey        try:
60a2094b1bSPhilip Jenvey            build_ext.run(self)
61fcded554SMike Bayer        except DistutilsPlatformError:
62fcded554SMike Bayer            raise BuildFailed()
63a2094b1bSPhilip Jenvey
64a2094b1bSPhilip Jenvey    def build_extension(self, ext):
65a2094b1bSPhilip Jenvey        try:
66a2094b1bSPhilip Jenvey            build_ext.build_extension(self, ext)
67fcded554SMike Bayer        except ext_errors:
68fcded554SMike Bayer            raise BuildFailed()
69dc75e0c6SMike Bayer        except ValueError:
70dc75e0c6SMike Bayer            # this can happen on Windows 64 bit, see Python issue 7511
7100e29c4cSMike Bayer            if "'path'" in str(sys.exc_info()[1]):  # works with both py 2/3
72dc75e0c6SMike Bayer                raise BuildFailed()
73dc75e0c6SMike Bayer            raise
74fcded554SMike Bayer
75fcded554SMike Bayer
761e1a38e7SMike Bayercmdclass["build_ext"] = ve_build_ext
77304e5b2aSBrian Jarrett
7839517d10SDonald Stufft
791e1a38e7SMike Bayerclass Distribution(_Distribution):
8039517d10SDonald Stufft    def has_ext_modules(self):
8139517d10SDonald Stufft        # We want to always claim that we have ext_modules. This will be fine
8239517d10SDonald Stufft        # if we don't actually have them (such as on PyPy) because nothing
8339517d10SDonald Stufft        # will get built, however we don't want to provide an overally broad
8439517d10SDonald Stufft        # Wheel package when building a wheel without C support. This will
8539517d10SDonald Stufft        # ensure that Wheel knows to treat us as if the build output is
8639517d10SDonald Stufft        # platform specific.
8739517d10SDonald Stufft        return True
8839517d10SDonald Stufft
8939517d10SDonald Stufft
90c312b3b2SMike Bayerclass UseTox(TestCommand):
91c312b3b2SMike Bayer    RED = 31
92c312b3b2SMike Bayer    RESET_SEQ = "\033[0m"
93c312b3b2SMike Bayer    BOLD_SEQ = "\033[1m"
94c312b3b2SMike Bayer    COLOR_SEQ = "\033[1;%dm"
955ab9ab79SMike Bayer
965ab9ab79SMike Bayer    def run_tests(self):
97c312b3b2SMike Bayer        sys.stderr.write(
98c312b3b2SMike Bayer            "%s%spython setup.py test is deprecated by pypa.  Please invoke "
99c312b3b2SMike Bayer            "'tox' with no arguments for a basic test run.\n%s"
100c312b3b2SMike Bayer            % (self.COLOR_SEQ % self.RED, self.BOLD_SEQ, self.RESET_SEQ)
1011e1a38e7SMike Bayer        )
102c312b3b2SMike Bayer        sys.exit(1)
1035ab9ab79SMike Bayer
1041e1a38e7SMike Bayer
105c312b3b2SMike Bayercmdclass["test"] = UseTox
1065ab9ab79SMike Bayer
1075ab9ab79SMike Bayer
108fcded554SMike Bayerdef status_msgs(*msgs):
1091e1a38e7SMike Bayer    print("*" * 75)
110fcded554SMike Bayer    for msg in msgs:
111fcded554SMike Bayer        print(msg)
1121e1a38e7SMike Bayer    print("*" * 75)
1136917ffb9SJason Kirtland
114304e5b2aSBrian Jarrett
115cd03b8f0SMike Bayerwith open(
116cd03b8f0SMike Bayer    os.path.join(os.path.dirname(__file__), "lib", "sqlalchemy", "__init__.py")
117cd03b8f0SMike Bayer) as v_file:
118cd03b8f0SMike Bayer    VERSION = (
119cd03b8f0SMike Bayer        re.compile(r""".*__version__ = ["'](.*?)['"]""", re.S)
120cd03b8f0SMike Bayer        .match(v_file.read())
121cd03b8f0SMike Bayer        .group(1)
122cd03b8f0SMike Bayer    )
123cd03b8f0SMike Bayer
124cd03b8f0SMike Bayer
125a2094b1bSPhilip Jenveydef run_setup(with_cext):
12644420423SMike Bayer    kwargs = {}
127a2094b1bSPhilip Jenvey    if with_cext:
1281e1a38e7SMike Bayer        kwargs["ext_modules"] = ext_modules
12939517d10SDonald Stufft    else:
130a54a0c6eSMike Bayer        if os.environ.get("REQUIRE_SQLALCHEMY_CEXT"):
131a54a0c6eSMike Bayer            raise AssertionError(
132a54a0c6eSMike Bayer                "Can't build on this platform with "
133a54a0c6eSMike Bayer                "REQUIRE_SQLALCHEMY_CEXT set."
134a54a0c6eSMike Bayer            )
135a54a0c6eSMike Bayer
1361e1a38e7SMike Bayer        kwargs["ext_modules"] = []
1375ab9ab79SMike Bayer
138cd03b8f0SMike Bayer    setup(version=VERSION, cmdclass=cmdclass, distclass=Distribution, **kwargs)
139a2094b1bSPhilip Jenvey
1401e1a38e7SMike Bayer
141ec97911eSMike Bayerif not cpython:
142a5c9907dSMike Bayer    run_setup(False)
143fcded554SMike Bayer    status_msgs(
1441e1a38e7SMike Bayer        "WARNING: C extensions are not supported on "
1451e1a38e7SMike Bayer        + "this Python platform, speedups are not enabled.",
1461e1a38e7SMike Bayer        "Plain-Python build succeeded.",
147fcded554SMike Bayer    )
1481e1a38e7SMike Bayerelif os.environ.get("DISABLE_SQLALCHEMY_CEXT"):
149ec97911eSMike Bayer    run_setup(False)
150ec97911eSMike Bayer    status_msgs(
1511e1a38e7SMike Bayer        "DISABLE_SQLALCHEMY_CEXT is set; "
1521e1a38e7SMike Bayer        + "not attempting to build C extensions.",
1531e1a38e7SMike Bayer        "Plain-Python build succeeded.",
154ec97911eSMike Bayer    )
155ec97911eSMike Bayer
156fcded554SMike Bayerelse:
157fcded554SMike Bayer    try:
158fcded554SMike Bayer        run_setup(True)
159a5c9907dSMike Bayer    except BuildFailed as exc:
160a54a0c6eSMike Bayer
161a54a0c6eSMike Bayer        if os.environ.get("REQUIRE_SQLALCHEMY_CEXT"):
162a54a0c6eSMike Bayer            status_msgs(
163a54a0c6eSMike Bayer                "NOTE: C extension build is required because "
164a54a0c6eSMike Bayer                "REQUIRE_SQLALCHEMY_CEXT is set, and the build has failed; "
165a54a0c6eSMike Bayer                "will not degrade to non-C extensions"
166a54a0c6eSMike Bayer            )
167a54a0c6eSMike Bayer            raise
168a54a0c6eSMike Bayer
169fcded554SMike Bayer        status_msgs(
170fcded554SMike Bayer            exc.cause,
1711e1a38e7SMike Bayer            "WARNING: The C extension could not be compiled, "
1721e1a38e7SMike Bayer            + "speedups are not enabled.",
173fcded554SMike Bayer            "Failure information, if any, is above.",
1741e1a38e7SMike Bayer            "Retrying the build without the C extension now.",
175fcded554SMike Bayer        )
176fcded554SMike Bayer
177fcded554SMike Bayer        run_setup(False)
178a2094b1bSPhilip Jenvey
179fcded554SMike Bayer        status_msgs(
1801e1a38e7SMike Bayer            "WARNING: The C extension could not be compiled, "
1811e1a38e7SMike Bayer            + "speedups are not enabled.",
1821e1a38e7SMike Bayer            "Plain-Python build succeeded.",
183fcded554SMike Bayer        )
184