Proyecto Python usando búferes de protocolo, problemas de implementación

Tengo un proyecto de Python que usa setuptools para la implementación y la mayoría de las veces seguí esta guía con respecto a la estructura del proyecto. El proyecto utiliza Google Protocol Buffers para definir un formato de mensaje de red. Mi principal problema es cómo hacer que setup.py llame al compoctor protoc durante la instalación para comstackr las definiciones en un archivo _pb2.py.

En esta pregunta, se dio el consejo de distribuir los archivos _pb2.py resultantes junto con el proyecto. Si bien esto podría funcionar para plataformas muy similares, he encontrado varios casos en los que esto no funciona. Por ejemplo, cuando me desarrollo en una Mac que usa Anaconda Python y copio el _pb2.py resultante junto con el rest del proyecto a una Raspberry Pi que ejecuta Raspbian, siempre hay errores de importación provenientes de los módulos _pb2.py. Sin embargo, si compilo los archivos .proto recientemente en el Pi, el proyecto funciona como se esperaba. Por lo tanto, la distribución de los archivos comstackdos no parece ser una opción.

Tipo de búsqueda de soluciones de trabajo y mejores prácticas aquí. Se puede suponer que el compoctor de protoc está instalado en la plataforma de destino.

Editar:

Ya que la gente pregunta por las razones del fracaso. En la Mac, la versión protobuf es 2.6.1. y en el Pi es 2.4.1. Aparentemente, la API interna utilizada por la salida generada del comstackdor protoc ha cambiado. La salida es básicamente:

    File "[...]network_manager.py", line 8, in  import InstrumentControl.transports.serial_bridge_protocol_pb2 as protocol File "[...]serial_bridge_protocol_pb2.py", line 9, in  from google.protobuf import symbol_database as _symbol_database ImportError: cannot import name symbol_database 

    Ok, resolví el problema sin requerir que el usuario instale una versión anterior específica o compile los archivos de proto en otra plataforma que no sea mi máquina dev. Está inspirado en este script setup.py del propio protobuf .

    En primer lugar, se necesita encontrar protoc, esto se puede hacer usando

     # 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") 

    Esta función comstackrá un archivo .proto y pondrá el _pb2.py en el mismo lugar. Sin embargo, el comportamiento puede ser cambiado arbitrariamente.

     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) 

    A continuación, las clases _build_py y _clean se derivan para agregar la creación y limpieza de los búferes de protocolo.

     # 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) 

    Y por último, el parámetro.

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

    debe agregarse a la llamada de configuración y todo debería funcionar. Todavía tengo que buscar posibles caprichos, pero hasta ahora funciona perfectamente en la Mac y en la Pi.

    Otra solución es agrupar la biblioteca protobuf con su aplicación, en lugar de usar la versión instalada en la máquina de destino. De esta manera usted sabe que no hay discrepancia de versión con su código generado.

    Acabo de comenzar con el paquete protobuf-setuptools para usar la parte más sana de este código. Todavía necesita mejoras, por lo que cualquier comentario es bienvenido!

    Echa un vistazo a: https://pypi.python.org/pypi/protobuf-setuptools