Rebuild nanopb_pb2.py and print version numbers on import failure (#733, #742)
When python-protobuf and protoc versions do not match, the most common
error message is "AttributeError: module 'google.protobuf.descriptor' has no attribute '_internal_create_key'".
Attempt to provide more helpful info in this situation.
diff --git a/generator/proto/__init__.py b/generator/proto/__init__.py
index 29153d4..e2e8000 100644
--- a/generator/proto/__init__.py
+++ b/generator/proto/__init__.py
@@ -6,31 +6,45 @@
import pkg_resources
-from ._utils import has_grpcio_protoc, invoke_protoc
+from ._utils import has_grpcio_protoc, invoke_protoc, print_versions
dirname = os.path.dirname(__file__)
protosrc = os.path.join(dirname, "nanopb.proto")
protodst = os.path.join(dirname, "nanopb_pb2.py")
+rebuild = False
if os.path.isfile(protosrc):
src_date = os.path.getmtime(protosrc)
if not os.path.isfile(protodst) or os.path.getmtime(protodst) < src_date:
+ rebuild = True
- cmd = [
- "protoc",
- "--python_out={}".format(dirname),
- protosrc,
- "-I={}".format(dirname),
- ]
+if not rebuild:
+ try:
+ from . import nanopb_pb2
+ except AttributeError as e:
+ rebuild = True
+ sys.stderr.write("Failed to import nanopb_pb2.py: " + str(e) + "\n"
+ "Will automatically attempt to rebuild this.\n"
+ "Verify that python-protobuf and protoc versions match.\n")
+ print_versions()
- if has_grpcio_protoc():
- # grpcio-tools has an extra CLI argument
- # from grpc.tools.protoc __main__ invocation.
- _builtin_proto_include = pkg_resources.resource_filename('grpc_tools', '_proto')
+if rebuild:
+ cmd = [
+ "protoc",
+ "--python_out={}".format(dirname),
+ protosrc,
+ "-I={}".format(dirname),
+ ]
- cmd.append("-I={}".format(_builtin_proto_include))
- try:
- invoke_protoc(argv=cmd)
- except:
- sys.stderr.write("Failed to build nanopb_pb2.py: " + ' '.join(cmd) + "\n")
- raise
+ if has_grpcio_protoc():
+ # grpcio-tools has an extra CLI argument
+ # from grpc.tools.protoc __main__ invocation.
+ _builtin_proto_include = pkg_resources.resource_filename('grpc_tools', '_proto')
+
+ cmd.append("-I={}".format(_builtin_proto_include))
+ try:
+ invoke_protoc(argv=cmd)
+ except:
+ sys.stderr.write("Failed to build nanopb_pb2.py: " + ' '.join(cmd) + "\n")
+ raise
+
diff --git a/generator/proto/_utils.py b/generator/proto/_utils.py
index 7076e9d..bd49537 100644
--- a/generator/proto/_utils.py
+++ b/generator/proto/_utils.py
@@ -1,3 +1,4 @@
+import sys
import subprocess
import os.path
@@ -41,3 +42,25 @@
return protoc.main(argv)
else:
return subprocess.call(argv)
+
+def print_versions():
+ try:
+ if has_grpcio_protoc():
+ import grpc_tools.protoc
+ sys.stderr.write("Using grpcio-tools protoc from " + grpc_tools.protoc.__file__ + "\n")
+ else:
+ sys.stderr.write("Using protoc from system path\n")
+
+ invoke_protoc(['protoc', '--version'])
+ except Exception as e:
+ sys.stderr.write("Failed to determine protoc version: " + str(e) + "\n")
+
+ try:
+ import google.protobuf
+ sys.stderr.write("Using python-protobuf from " + google.protobuf.__file__ + "\n")
+ sys.stderr.write("Python-protobuf version: " + google.protobuf.__version__ + "\n")
+ except Exception as e:
+ sys.stderr.write("Failed to determine python-protobuf version: " + str(e) + "\n")
+
+if __name__ == '__main__':
+ print_versions()