xref: /aosp_15_r20/external/grpc-grpc/src/python/grpcio/support.py (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
1*cc02d7e2SAndroid Build Coastguard Worker# Copyright 2016 gRPC authors.
2*cc02d7e2SAndroid Build Coastguard Worker#
3*cc02d7e2SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
4*cc02d7e2SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
5*cc02d7e2SAndroid Build Coastguard Worker# You may obtain a copy of the License at
6*cc02d7e2SAndroid Build Coastguard Worker#
7*cc02d7e2SAndroid Build Coastguard Worker#     http://www.apache.org/licenses/LICENSE-2.0
8*cc02d7e2SAndroid Build Coastguard Worker#
9*cc02d7e2SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
10*cc02d7e2SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
11*cc02d7e2SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*cc02d7e2SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
13*cc02d7e2SAndroid Build Coastguard Worker# limitations under the License.
14*cc02d7e2SAndroid Build Coastguard Worker
15*cc02d7e2SAndroid Build Coastguard Workerimport os
16*cc02d7e2SAndroid Build Coastguard Workerimport os.path
17*cc02d7e2SAndroid Build Coastguard Workerimport shutil
18*cc02d7e2SAndroid Build Coastguard Workerimport sys
19*cc02d7e2SAndroid Build Coastguard Workerimport tempfile
20*cc02d7e2SAndroid Build Coastguard Worker
21*cc02d7e2SAndroid Build Coastguard Workertry:
22*cc02d7e2SAndroid Build Coastguard Worker    from setuptools.errors import CompileError
23*cc02d7e2SAndroid Build Coastguard Workerexcept ImportError:
24*cc02d7e2SAndroid Build Coastguard Worker    # CompileError only exist for setuptools>=59.0.1, which becomes standard library
25*cc02d7e2SAndroid Build Coastguard Worker    # after Python 3.10.6.
26*cc02d7e2SAndroid Build Coastguard Worker    # TODO(xuanwn): Remove this once Python version floor is higher than 3.10.
27*cc02d7e2SAndroid Build Coastguard Worker    from distutils.errors import CompileError
28*cc02d7e2SAndroid Build Coastguard Worker
29*cc02d7e2SAndroid Build Coastguard Workerimport commands
30*cc02d7e2SAndroid Build Coastguard Worker
31*cc02d7e2SAndroid Build Coastguard WorkerC_PYTHON_DEV = """
32*cc02d7e2SAndroid Build Coastguard Worker#include <Python.h>
33*cc02d7e2SAndroid Build Coastguard Workerint main(int argc, char **argv) { return 0; }
34*cc02d7e2SAndroid Build Coastguard Worker"""
35*cc02d7e2SAndroid Build Coastguard WorkerC_PYTHON_DEV_ERROR_MESSAGE = """
36*cc02d7e2SAndroid Build Coastguard WorkerCould not find <Python.h>. This could mean the following:
37*cc02d7e2SAndroid Build Coastguard Worker  * You're on Ubuntu and haven't run `apt-get install <PY_REPR>-dev`.
38*cc02d7e2SAndroid Build Coastguard Worker  * You're on RHEL/Fedora and haven't run `yum install <PY_REPR>-devel` or
39*cc02d7e2SAndroid Build Coastguard Worker    `dnf install <PY_REPR>-devel` (make sure you also have redhat-rpm-config
40*cc02d7e2SAndroid Build Coastguard Worker    installed)
41*cc02d7e2SAndroid Build Coastguard Worker  * You're on Mac OS X and the usual Python framework was somehow corrupted
42*cc02d7e2SAndroid Build Coastguard Worker    (check your environment variables or try re-installing?)
43*cc02d7e2SAndroid Build Coastguard Worker  * You're on Windows and your Python installation was somehow corrupted
44*cc02d7e2SAndroid Build Coastguard Worker    (check your environment variables or try re-installing?)
45*cc02d7e2SAndroid Build Coastguard Worker"""
46*cc02d7e2SAndroid Build Coastguard Workerif sys.version_info[0] == 2:
47*cc02d7e2SAndroid Build Coastguard Worker    PYTHON_REPRESENTATION = "python"
48*cc02d7e2SAndroid Build Coastguard Workerelif sys.version_info[0] == 3:
49*cc02d7e2SAndroid Build Coastguard Worker    PYTHON_REPRESENTATION = "python3"
50*cc02d7e2SAndroid Build Coastguard Workerelse:
51*cc02d7e2SAndroid Build Coastguard Worker    raise NotImplementedError("Unsupported Python version: %s" % sys.version)
52*cc02d7e2SAndroid Build Coastguard Worker
53*cc02d7e2SAndroid Build Coastguard WorkerC_CHECKS = {
54*cc02d7e2SAndroid Build Coastguard Worker    C_PYTHON_DEV: C_PYTHON_DEV_ERROR_MESSAGE.replace(
55*cc02d7e2SAndroid Build Coastguard Worker        "<PY_REPR>", PYTHON_REPRESENTATION
56*cc02d7e2SAndroid Build Coastguard Worker    ),
57*cc02d7e2SAndroid Build Coastguard Worker}
58*cc02d7e2SAndroid Build Coastguard Worker
59*cc02d7e2SAndroid Build Coastguard Worker
60*cc02d7e2SAndroid Build Coastguard Workerdef _compile(compiler, source_string):
61*cc02d7e2SAndroid Build Coastguard Worker    tempdir = tempfile.mkdtemp()
62*cc02d7e2SAndroid Build Coastguard Worker    cpath = os.path.join(tempdir, "a.c")
63*cc02d7e2SAndroid Build Coastguard Worker    with open(cpath, "w") as cfile:
64*cc02d7e2SAndroid Build Coastguard Worker        cfile.write(source_string)
65*cc02d7e2SAndroid Build Coastguard Worker    try:
66*cc02d7e2SAndroid Build Coastguard Worker        compiler.compile([cpath])
67*cc02d7e2SAndroid Build Coastguard Worker    except CompileError as error:
68*cc02d7e2SAndroid Build Coastguard Worker        return error
69*cc02d7e2SAndroid Build Coastguard Worker    finally:
70*cc02d7e2SAndroid Build Coastguard Worker        shutil.rmtree(tempdir)
71*cc02d7e2SAndroid Build Coastguard Worker
72*cc02d7e2SAndroid Build Coastguard Worker
73*cc02d7e2SAndroid Build Coastguard Workerdef _expect_compile(compiler, source_string, error_message):
74*cc02d7e2SAndroid Build Coastguard Worker    if _compile(compiler, source_string) is not None:
75*cc02d7e2SAndroid Build Coastguard Worker        sys.stderr.write(error_message)
76*cc02d7e2SAndroid Build Coastguard Worker        raise commands.CommandError(
77*cc02d7e2SAndroid Build Coastguard Worker            "Diagnostics found a compilation environment issue:\n{}".format(
78*cc02d7e2SAndroid Build Coastguard Worker                error_message
79*cc02d7e2SAndroid Build Coastguard Worker            )
80*cc02d7e2SAndroid Build Coastguard Worker        )
81*cc02d7e2SAndroid Build Coastguard Worker
82*cc02d7e2SAndroid Build Coastguard Worker
83*cc02d7e2SAndroid Build Coastguard Workerdef diagnose_compile_error(build_ext, error):
84*cc02d7e2SAndroid Build Coastguard Worker    """Attempt to diagnose an error during compilation."""
85*cc02d7e2SAndroid Build Coastguard Worker    for c_check, message in C_CHECKS.items():
86*cc02d7e2SAndroid Build Coastguard Worker        _expect_compile(build_ext.compiler, c_check, message)
87*cc02d7e2SAndroid Build Coastguard Worker    python_sources = [
88*cc02d7e2SAndroid Build Coastguard Worker        source
89*cc02d7e2SAndroid Build Coastguard Worker        for source in build_ext.get_source_files()
90*cc02d7e2SAndroid Build Coastguard Worker        if source.startswith("./src/python") and source.endswith("c")
91*cc02d7e2SAndroid Build Coastguard Worker    ]
92*cc02d7e2SAndroid Build Coastguard Worker    for source in python_sources:
93*cc02d7e2SAndroid Build Coastguard Worker        if not os.path.isfile(source):
94*cc02d7e2SAndroid Build Coastguard Worker            raise commands.CommandError(
95*cc02d7e2SAndroid Build Coastguard Worker                (
96*cc02d7e2SAndroid Build Coastguard Worker                    "Diagnostics found a missing Python extension source"
97*cc02d7e2SAndroid Build Coastguard Worker                    " file:\n{}\n\nThis is usually because the Cython sources"
98*cc02d7e2SAndroid Build Coastguard Worker                    " haven't been transpiled into C yet and you're building"
99*cc02d7e2SAndroid Build Coastguard Worker                    " from source.\nTry setting the environment variable"
100*cc02d7e2SAndroid Build Coastguard Worker                    " `GRPC_PYTHON_BUILD_WITH_CYTHON=1` when invoking"
101*cc02d7e2SAndroid Build Coastguard Worker                    " `setup.py` or when using `pip`, e.g.:\n\npip install"
102*cc02d7e2SAndroid Build Coastguard Worker                    " -rrequirements.txt\nGRPC_PYTHON_BUILD_WITH_CYTHON=1 pip"
103*cc02d7e2SAndroid Build Coastguard Worker                    " install ."
104*cc02d7e2SAndroid Build Coastguard Worker                ).format(source)
105*cc02d7e2SAndroid Build Coastguard Worker            )
106*cc02d7e2SAndroid Build Coastguard Worker
107*cc02d7e2SAndroid Build Coastguard Worker
108*cc02d7e2SAndroid Build Coastguard Workerdef diagnose_attribute_error(build_ext, error):
109*cc02d7e2SAndroid Build Coastguard Worker    if any("_needs_stub" in arg for arg in error.args):
110*cc02d7e2SAndroid Build Coastguard Worker        raise commands.CommandError(
111*cc02d7e2SAndroid Build Coastguard Worker            "We expect a missing `_needs_stub` attribute from older versions of"
112*cc02d7e2SAndroid Build Coastguard Worker            " setuptools. Consider upgrading setuptools."
113*cc02d7e2SAndroid Build Coastguard Worker        )
114*cc02d7e2SAndroid Build Coastguard Worker
115*cc02d7e2SAndroid Build Coastguard Worker
116*cc02d7e2SAndroid Build Coastguard Worker_ERROR_DIAGNOSES = {
117*cc02d7e2SAndroid Build Coastguard Worker    CompileError: diagnose_compile_error,
118*cc02d7e2SAndroid Build Coastguard Worker    AttributeError: diagnose_attribute_error,
119*cc02d7e2SAndroid Build Coastguard Worker}
120*cc02d7e2SAndroid Build Coastguard Worker
121*cc02d7e2SAndroid Build Coastguard Worker
122*cc02d7e2SAndroid Build Coastguard Workerdef diagnose_build_ext_error(build_ext, error, formatted):
123*cc02d7e2SAndroid Build Coastguard Worker    diagnostic = _ERROR_DIAGNOSES.get(type(error))
124*cc02d7e2SAndroid Build Coastguard Worker    if diagnostic is None:
125*cc02d7e2SAndroid Build Coastguard Worker        raise commands.CommandError(
126*cc02d7e2SAndroid Build Coastguard Worker            "\n\nWe could not diagnose your build failure with type {}. If you are unable to"
127*cc02d7e2SAndroid Build Coastguard Worker            " proceed, please file an issue at http://www.github.com/grpc/grpc"
128*cc02d7e2SAndroid Build Coastguard Worker            " with `[Python install]` in the title; please attach the whole log"
129*cc02d7e2SAndroid Build Coastguard Worker            " (including everything that may have appeared above the Python"
130*cc02d7e2SAndroid Build Coastguard Worker            " backtrace).\n\n{}".format(type(error), formatted)
131*cc02d7e2SAndroid Build Coastguard Worker        )
132*cc02d7e2SAndroid Build Coastguard Worker    else:
133*cc02d7e2SAndroid Build Coastguard Worker        diagnostic(build_ext, error)
134