1# Copyright 2020 The 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# distutils: language=c++ 15 16cimport cpython 17from cython.operator cimport dereference 18from libc cimport stdlib 19from libcpp.string cimport string 20from libcpp.utility cimport pair 21from libcpp.vector cimport vector 22 23import warnings 24 25from grpc_tools import grpc_version 26 27 28cdef extern from "grpc_tools/main.h" namespace "grpc_tools": 29 cppclass cProtocError "::grpc_tools::ProtocError": 30 string filename 31 int line 32 int column 33 string message 34 35 cppclass cProtocWarning "::grpc_tools::ProtocWarning": 36 string filename 37 int line 38 int column 39 string message 40 41 int protoc_main(int argc, char *argv[], char* version) 42 int protoc_get_protos(char* protobuf_path, 43 vector[string]* include_path, 44 vector[pair[string, string]]* files_out, 45 vector[cProtocError]* errors, 46 vector[cProtocWarning]* wrnings) except + nogil 47 int protoc_get_services(char* protobuf_path, char* version, 48 vector[string]* include_path, 49 vector[pair[string, string]]* files_out, 50 vector[cProtocError]* errors, 51 vector[cProtocWarning]* wrnings) except + nogil 52 53def run_main(list args not None): 54 cdef char **argv = <char **>stdlib.malloc(len(args)*sizeof(char *)) 55 for i in range(len(args)): 56 argv[i] = args[i] 57 return protoc_main(len(args), argv, grpc_version.VERSION.encode()) 58 59class ProtocError(Exception): 60 def __init__(self, filename, line, column, message): 61 self.filename = filename 62 self.line = line 63 self.column = column 64 self.message = message 65 66 def __repr__(self): 67 return "ProtocError(filename=\"{}\", line={}, column={}, message=\"{}\")".format( 68 self.filename, self.line, self.column, self.message) 69 70 def __str__(self): 71 return "{}:{}:{} error: {}".format(self.filename.decode("ascii"), 72 self.line, self.column, self.message.decode("ascii")) 73 74class ProtocWarning(Warning): 75 def __init__(self, filename, line, column, message): 76 self.filename = filename 77 self.line = line 78 self.column = column 79 self.message = message 80 81 def __repr__(self): 82 return "ProtocWarning(filename=\"{}\", line={}, column={}, message=\"{}\")".format( 83 self.filename, self.line, self.column, self.message) 84 85 __str__ = __repr__ 86 87 88class ProtocErrors(Exception): 89 def __init__(self, errors): 90 self._errors = errors 91 92 def errors(self): 93 return self._errors 94 95 def __repr__(self): 96 return "ProtocErrors[{}]".join(repr(err) for err in self._errors) 97 98 def __str__(self): 99 return "\n".join(str(err) for err in self._errors) 100 101cdef _c_protoc_error_to_protoc_error(cProtocError c_protoc_error): 102 return ProtocError(c_protoc_error.filename, c_protoc_error.line, 103 c_protoc_error.column, c_protoc_error.message) 104 105cdef _c_protoc_warning_to_protoc_warning(cProtocWarning c_protoc_warning): 106 return ProtocWarning(c_protoc_warning.filename, c_protoc_warning.line, 107 c_protoc_warning.column, c_protoc_warning.message) 108 109cdef _handle_errors(int rc, vector[cProtocError]* errors, vector[cProtocWarning]* wrnings, bytes protobuf_path): 110 for warning in dereference(wrnings): 111 warnings.warn(_c_protoc_warning_to_protoc_warning(warning)) 112 if rc != 0: 113 if dereference(errors).size() != 0: 114 py_errors = [_c_protoc_error_to_protoc_error(c_error) 115 for c_error in dereference(errors)] 116 raise ProtocErrors(py_errors) 117 raise Exception("An unknown error occurred while compiling {}".format(protobuf_path)) 118 119def get_protos(bytes protobuf_path, list include_paths): 120 cdef vector[string] c_include_paths = include_paths 121 cdef vector[pair[string, string]] files 122 cdef vector[cProtocError] errors 123 # NOTE: Abbreviated name used to avoid shadowing of the module name. 124 cdef vector[cProtocWarning] wrnings 125 rc = protoc_get_protos(protobuf_path, &c_include_paths, &files, &errors, &wrnings) 126 _handle_errors(rc, &errors, &wrnings, protobuf_path) 127 return files 128 129def get_services(bytes protobuf_path, list include_paths): 130 cdef vector[string] c_include_paths = include_paths 131 cdef vector[pair[string, string]] files 132 cdef vector[cProtocError] errors 133 # NOTE: Abbreviated name used to avoid shadowing of the module name. 134 cdef vector[cProtocWarning] wrnings 135 version = grpc_version.VERSION.encode() 136 rc = protoc_get_services(protobuf_path, version, &c_include_paths, &files, &errors, &wrnings) 137 _handle_errors(rc, &errors, &wrnings, protobuf_path) 138 return files 139 140