Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/google-sheets/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python项目使用协议缓冲区,部署问题_Python_Installation_Protocol Buffers_Setuptools_Software Distribution - Fatal编程技术网

Python项目使用协议缓冲区,部署问题

Python项目使用协议缓冲区,部署问题,python,installation,protocol-buffers,setuptools,software-distribution,Python,Installation,Protocol Buffers,Setuptools,Software Distribution,我有一个Python项目,它使用setuptools进行部署,我主要关注项目结构。该项目使用谷歌协议缓冲区来定义网络消息格式。我的主要问题是如何让setup.py在安装过程中调用protoc编译器,将定义构建到_pb2.py文件中 在本文中,建议将生成的_pb2.py文件与项目一起分发。虽然这可能适用于非常类似的平台,但我发现有几种情况下这不起作用。例如,当我在使用Anaconda Python的Mac上开发并将生成的_pb2.py和项目的其余部分复制到运行Raspbian的Raspberry

我有一个Python项目,它使用setuptools进行部署,我主要关注项目结构。该项目使用谷歌协议缓冲区来定义网络消息格式。我的主要问题是如何让setup.py在安装过程中调用protoc编译器,将定义构建到_pb2.py文件中

在本文中,建议将生成的_pb2.py文件与项目一起分发。虽然这可能适用于非常类似的平台,但我发现有几种情况下这不起作用。例如,当我在使用Anaconda Python的Mac上开发并将生成的_pb2.py和项目的其余部分复制到运行Raspbian的Raspberry Pi时,总是会有来自_pb2.py模块的导入错误。但是,如果我在Pi上新编译.proto文件,项目将按预期工作。因此,分发编译后的文件似乎不是一种选择

在这里寻找工作和最佳实践解决方案。可以假设protoc编译器安装在目标平台上

编辑:

因为人们会问失败的原因。在Mac上,protobuf版本是2.6.1。Pi上是2.4.1。显然,生成的protoc编译器输出所使用的内部API已经更改。输出基本上是:

  File "[...]network_manager.py", line 8, in <module>
      import InstrumentControl.transports.serial_bridge_protocol_pb2 as protocol
  File "[...]serial_bridge_protocol_pb2.py", line 9, in <module>
      from google.protobuf import symbol_database as _symbol_database
  ImportError: cannot import name symbol_database
文件“[…]network_manager.py”,第8行,在
导入InstrumentControl.transports.serial_bridge_协议_pb2作为协议
文件“[…]串行_桥_协议_pb2.py”,第9行,在
从google.protobuf导入symbol_数据库作为_symbol_数据库
ImportError:无法导入名称符号\u数据库

好的,我解决了这个问题,不需要用户在我的开发机器以外的其他平台上安装特定的旧版本或编译proto文件。它的灵感来自

首先,需要找到protoc,这可以使用

# Find the Protocol Compiler.
if 'PROTOC' in os.environ and os.path.exists(os.environ['PROTOC']):
  protoc = os.environ['PROTOC']
else:
  protoc = find_executable("protoc")
此函数将编译一个.proto文件并将_pb2.py放在同一位置。但是,行为可以任意改变

def generate_proto(source):
  """Invokes the Protocol Compiler to generate a _pb2.py from the given
  .proto file.  Does nothing if the output already exists and is newer than
  the input."""

  output = source.replace(".proto", "_pb2.py")

  if (not os.path.exists(output) or
      (os.path.exists(source) and
       os.path.getmtime(source) > os.path.getmtime(output))):
    print "Generating %s..." % output

    if not os.path.exists(source):
      sys.stderr.write("Can't find required file: %s\n" % source)
      sys.exit(-1)

    if protoc == None:
      sys.stderr.write(
          "Protocol buffers compiler 'protoc' not installed or not found.\n"
          )
      sys.exit(-1)

    protoc_command = [ protoc, "-I.", "--python_out=.", source ]
    if subprocess.call(protoc_command) != 0:
      sys.exit(-1)
接下来,派生类_build_py和_clean来添加构建和清理协议缓冲区

# List of all .proto files
proto_src = ['file1.proto', 'path/to/file2.proto']

class build_py(_build_py):
  def run(self):
    for f in proto_src:
        generate_proto(f)
    _build_py.run(self)

class clean(_clean):
  def run(self):
    # Delete generated files in the code tree.
    for (dirpath, dirnames, filenames) in os.walk("."):
      for filename in filenames:
        filepath = os.path.join(dirpath, filename)
        if filepath.endswith("_pb2.py"):
          os.remove(filepath)
    # _clean is an old-style class, so super() doesn't work.
    _clean.run(self)
最后是参数

cmdclass = { 'clean': clean, 'build_py': build_py }   

需要添加到设置调用中,所有操作都应该正常。仍然需要检查可能的怪癖,但到目前为止,它在Mac和Pi上工作得完美无缺。

另一个解决方案是将protobuf库与应用程序捆绑在一起,而不是在目标机器上使用已安装的版本。这样,您就知道生成的代码没有版本不匹配。

我刚刚启动了protobuf setuptools软件包,以使用此代码中最合理的部分。它仍然需要改进,所以欢迎任何反馈


查看:

我也有类似的问题,并且总是在PI上编译。问题源于不同的protobuf版本。那么-您在各自的机器上有哪些版本,您不能将它们升级到相同的版本吗?我真的希望避免这种情况。我可以(可能)在我控制的机器上做到这一点,但感觉这不是正确的方式。当把软件分发给其他人时,它可能会失败。让他们在可以使用当前版本(通过重新编译)的情况下安装特定版本的协议缓冲区是不对的。您是否研究过-是什么导致导入错误?我会选择打包pb2.py文件的策略并研究导入错误问题。对于用户来说,总是有最低要求需要满足的。所以,要么你要求他们安装某些软件,要么你把它捆绑在你的应用程序中。您可以选择某个版本的协议缓冲区,并将整个堆栈包含在产品中。只要确保在导入时首先获取它。@Gill Bates:我已经更新了我的问题,以显示到底是什么错了。很好!我希望我能看一看,并很快将其与我们的资源整合。@jan将乐于帮助和改进。