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