Logo

dev-resources.site

for different kinds of informations.

OCaml, Python and protobuf

Published at
10/17/2023
Categories
100daystooffload
protobuf
ocaml
python
Author
stefanalfbo
Author
11 person written this
stefanalfbo
open
OCaml, Python and protobuf

Time to explore protobuf with code! I'll start by trying to share a message between an OCaml and a Python application.

Beginning first with making a directory structure for the project.

mkdir simple-protobuf-example && cd $_

# Create a directory for the python project
mkdir -p src/python
touch src/python/main.py

# Create a directory for the proto files
mkdir src/proto

# Create a OCaml project
dune init proj ocaml ./src

# Install the OCaml protobuf compiler
opam install ocaml-protoc

# Open the IDE
code .
Enter fullscreen mode Exit fullscreen mode

To start, we'll install the open source protobuf compiler, ocaml-protoc. We'll use this for the OCaml project, which is where we'll start. The project tree structure will look like this.

Project tree

Create a new file in named, Example.proto, in the directory, src/proto, that looks like this.

message Person {
    string name = 1;
    int32 age = 2;
    repeated string hobbies = 3;
}
Enter fullscreen mode Exit fullscreen mode

Use this command from the root of the project structure to generate OCaml types along with serialization functions for the binary encodings.

simple-protobuf-example ocaml-protoc -binary -ml_out ./src/ocaml/bin/ ./src/proto/Example.proto 
Enter fullscreen mode Exit fullscreen mode

The generated files should now be in the bin directory of the OCaml project.

Generated files

The Example_types.{ml|mli} file has the type definition along with a constructor function to conveniently create values of that type.

type person = {
  name : string;
  age : int32;
  hobbies : string list;
}

let rec default_person 
  ?name:((name:string) = "")
  ?age:((age:int32) = 0l)
  ?hobbies:((hobbies:string list) = [])
  () : person  = {
  name;
  age;
  hobbies;
}
Enter fullscreen mode Exit fullscreen mode

Here we can see how the Example.proto file was compiled/transpiled to OCaml code. The Example_pb.{ml|mli} file has the code for the binary encodings (because of the -binary command line switch earlier).

To use this code we'll need to update the main.ml file.

open Example_types
open Example_pb

let () =
  (* Create a person *)
  let person = { name = "Tony Stark"; age = 42l; hobbies = ["AI"; "Jarvis"] } in

  (* Encode the person *)
  let encoder = Pbrt.Encoder.create () in
  encode_person person encoder;
  let bytes = Pbrt.Encoder.to_bytes encoder in

  (* Write the bytes to a file *)
  let oc = open_out "person.bin" in
  output_bytes oc bytes;
  close_out oc

Enter fullscreen mode Exit fullscreen mode

This code is serializing a person record to a file called, person.bin.

There is also a need to update the dune file (in the bin directory) so it includes the pbrt library.

(executable
 (public_name ocaml)
 (name main)
 (libraries ocaml pbrt))
Enter fullscreen mode Exit fullscreen mode

To run the program we are executing following command in the ocaml directory.

dune build
dune exec ocaml
Enter fullscreen mode Exit fullscreen mode

This should produce a person.bin file which is in a binary format.

person.bin content

Now we are done with the first part, to produce a binary message of a serialized person in OCaml. Next step is to de-serialize the person.bin file in Python.

To work with protobuf in Python will need to start to make sure that we have installed the official protobuf compiler. If you haven’t installed the compiler, download the package and follow the instructions in the README.

# Check the current version, I'm using libprotoc 24.4
protoc --version

# Go to the python project directory
cd src/python

# Copy the person.bin file to the python directory for convenience
cp ../ocaml/person.bin .

# Create a virtual environment for the project
pyenv virtualenv 3.9.0 protobuf 
pyenv activate protobuf

# Install needed python packages
python -m pip install protobuf
python -m pip freeze > requirements.txt

# Generate the classes you’ll need to read Person
protoc --python_out=./ --proto_path=../proto/ Example.proto
Enter fullscreen mode Exit fullscreen mode

The last command should have generated a file called, Example_pb2.py.

Generated python file

Finally we need to read the file and de-serialize the content with the help of the generated protobuf code. Update the main.py file with this code.

import Example_pb2

def main():
    # Read the binary file
    with open("person.bin", "rb") as f:
        # Deserialize the content using protobuf
        person = Example_pb2.Person()
        person.ParseFromString(f.read())

    # Access the deserialized data
    print(person.name)
    print(person.age)
    print(person.hobbies)

if __name__ == "__main__":
    main()
Enter fullscreen mode Exit fullscreen mode

Lets run and see if it works.

Run the program

It's working! Hurray!

protobuf Article's
30 articles in total
Favicon
Protocol Buffers as a Serialization Format
Favicon
Part 2: Defining the Authentication gRPC Interface
Favicon
Compile Protocol Buffers & gRPC to Typescript with Yarn
Favicon
Use RBAC to protect your gRPC service right on proto definition
Favicon
Gamechanger Protobuf
Favicon
Gamechanger Protobuf
Favicon
RPC Action EP2: Using Protobuf and Creating a Custom Plugin
Favicon
FauxRPC
Favicon
Why should we use Protobuf in Web API as data transfer protocol.
Favicon
JSON vs FlatBuffers vs Protocol Buffers
Favicon
gRPC - Unimplemented Error 12
Favicon
A protoc compiler plugin that generates useful extension code for Kotlin/JVM
Favicon
Reducing flyxc data usage
Favicon
Koinos, Smart Contracts, WASM & Protobuf
Favicon
This Week I Learnt: gRPC & Protobuf
Favicon
Building a gRPC Server with NestJS and Buf: A Comprehensive Showcase
Favicon
Exploring Alternatives: Are There Better Options Than JSON?
Favicon
Creating the Local First Stack
Favicon
Roll your own auth with Rust and Protobuf
Favicon
OCaml, Python and protobuf
Favicon
Introduction to Protocol Buffers
Favicon
Using Protobuf with TypeScript
Favicon
[Typia] I made Protocol Buffer library of TypeScript, easiest in the world
Favicon
Protoc Plugins with Go
Favicon
Using Azure Web PubSub with Protobuf subprotocol in .NET
Favicon
A secret weapon to improve the efficiency of golang development, a community backend service was developed in one day
Favicon
Linting Proto Files With Buf
Favicon
What is gRPC
Favicon
fast framework for binary serialization and deserialization in Java, and has the fewest serialization bytes
Favicon
Protobuf vs Avro for Kafka, what to choose?

Featured ones: