123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159 |
- # Copyright 2020 The 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 sys
- import types
- from typing import Tuple, Union
- _REQUIRED_SYMBOLS = ("_protos", "_services", "_protos_and_services")
- _MINIMUM_VERSION = (3, 5, 0)
- _UNINSTALLED_TEMPLATE = "Install the grpcio-tools package (1.32.0+) to use the {} function."
- _VERSION_ERROR_TEMPLATE = "The {} function is only on available on Python 3.X interpreters."
- def _has_runtime_proto_symbols(mod: types.ModuleType) -> bool:
- return all(hasattr(mod, sym) for sym in _REQUIRED_SYMBOLS)
- def _is_grpc_tools_importable() -> bool:
- try:
- import grpc_tools # pylint: disable=unused-import # pytype: disable=import-error
- return True
- except ImportError as e:
- # NOTE: It's possible that we're encountering a transitive ImportError, so
- # we check for that and re-raise if so.
- if "grpc_tools" not in e.args[0]:
- raise
- return False
- def _call_with_lazy_import(
- fn_name: str, protobuf_path: str
- ) -> Union[types.ModuleType, Tuple[types.ModuleType, types.ModuleType]]:
- """Calls one of the three functions, lazily importing grpc_tools.
- Args:
- fn_name: The name of the function to import from grpc_tools.protoc.
- protobuf_path: The path to import.
- Returns:
- The appropriate module object.
- """
- if sys.version_info < _MINIMUM_VERSION:
- raise NotImplementedError(_VERSION_ERROR_TEMPLATE.format(fn_name))
- else:
- if not _is_grpc_tools_importable():
- raise NotImplementedError(_UNINSTALLED_TEMPLATE.format(fn_name))
- import grpc_tools.protoc # pytype: disable=import-error
- if _has_runtime_proto_symbols(grpc_tools.protoc):
- fn = getattr(grpc_tools.protoc, '_' + fn_name)
- return fn(protobuf_path)
- else:
- raise NotImplementedError(_UNINSTALLED_TEMPLATE.format(fn_name))
- def protos(protobuf_path): # pylint: disable=unused-argument
- """Returns a module generated by the indicated .proto file.
- THIS IS AN EXPERIMENTAL API.
- Use this function to retrieve classes corresponding to message
- definitions in the .proto file.
- To inspect the contents of the returned module, use the dir function.
- For example:
- ```
- protos = grpc.protos("foo.proto")
- print(dir(protos))
- ```
- The returned module object corresponds to the _pb2.py file generated
- by protoc. The path is expected to be relative to an entry on sys.path
- and all transitive dependencies of the file should also be resolveable
- from an entry on sys.path.
- To completely disable the machinery behind this function, set the
- GRPC_PYTHON_DISABLE_DYNAMIC_STUBS environment variable to "true".
- Args:
- protobuf_path: The path to the .proto file on the filesystem. This path
- must be resolveable from an entry on sys.path and so must all of its
- transitive dependencies.
- Returns:
- A module object corresponding to the message code for the indicated
- .proto file. Equivalent to a generated _pb2.py file.
- """
- return _call_with_lazy_import("protos", protobuf_path)
- def services(protobuf_path): # pylint: disable=unused-argument
- """Returns a module generated by the indicated .proto file.
- THIS IS AN EXPERIMENTAL API.
- Use this function to retrieve classes and functions corresponding to
- service definitions in the .proto file, including both stub and servicer
- definitions.
- To inspect the contents of the returned module, use the dir function.
- For example:
- ```
- services = grpc.services("foo.proto")
- print(dir(services))
- ```
- The returned module object corresponds to the _pb2_grpc.py file generated
- by protoc. The path is expected to be relative to an entry on sys.path
- and all transitive dependencies of the file should also be resolveable
- from an entry on sys.path.
- To completely disable the machinery behind this function, set the
- GRPC_PYTHON_DISABLE_DYNAMIC_STUBS environment variable to "true".
- Args:
- protobuf_path: The path to the .proto file on the filesystem. This path
- must be resolveable from an entry on sys.path and so must all of its
- transitive dependencies.
- Returns:
- A module object corresponding to the stub/service code for the indicated
- .proto file. Equivalent to a generated _pb2_grpc.py file.
- """
- return _call_with_lazy_import("services", protobuf_path)
- def protos_and_services(protobuf_path): # pylint: disable=unused-argument
- """Returns a 2-tuple of modules corresponding to protos and services.
- THIS IS AN EXPERIMENTAL API.
- The return value of this function is equivalent to a call to protos and a
- call to services.
- To completely disable the machinery behind this function, set the
- GRPC_PYTHON_DISABLE_DYNAMIC_STUBS environment variable to "true".
- Args:
- protobuf_path: The path to the .proto file on the filesystem. This path
- must be resolveable from an entry on sys.path and so must all of its
- transitive dependencies.
- Returns:
- A 2-tuple of module objects corresponding to (protos(path), services(path)).
- """
- return _call_with_lazy_import("protos_and_services", protobuf_path)
|