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