Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
1
Help us understand the problem. What is going on with this article?
@hoto17296

Python で protobuf スキーマを直接読み込む

Jupyter から自作の gRPC サーバにリクエストを投げたいが、そのためには protobuf スキーマを protoc でコンパイルして生成された Python コードを import しなければならない。

例えばこんな感じで。

$ pip install grpcio grpcio-tools
$ python -m grpc_tools.protoc -I./ --python_out=. --grpc_python_out=. foo.proto
    → foo_pb2.py と foo_pb2_grpc.py が生成される
import grpc
import foo_pb2
import foo_pb2_grpc

普通の Jupyter サーバでの作業なら一度コンパイルしたものを使いまわせばいいが、Google Colab で作業をしていると時間が経つとランタイムがリセットされて消えてしまって毎回コンパイルし直す必要があり面倒臭い。

これを自動化できないかと考えた。

実装

grpc-tools が必要なので pip install grpcio-tools などしてインストールしておく。

import sys, os
from tempfile import TemporaryDirectory
from io import IOBase
from importlib.machinery import SourceFileLoader
from grpc_tools import _protoc_compiler

def load_proto(proto, name='tmp'):
    with TemporaryDirectory(dir='.') as dname:
        fname = name + '.proto'
        fpath = os.path.join(dname, fname)
        with open(fpath, 'w') as f:
            if isinstance(proto, IOBase):
                f.write(proto.read())
            else:
                f.write(proto)

        args = [
            '--proto_path=' + dname,
            '--python_out=.',
            '--grpc_python_out=.',
            fpath,
        ]
        res = _protoc_compiler.run_main([arg.encode() for arg in args])

        pb2 = SourceFileLoader(name + '_pb2', os.path.join(dname, name + '_pb2.py')).load_module()
        pb2_grpc = SourceFileLoader(name + '_pb2_grpc', os.path.join(dname, name + '_pb2_grpc.py')).load_module()

    return pb2, pb2_grpc

一時ディレクトリを作成して、そこに proto ファイルを置いてコンパイルして、生成された Python コードを import して返す load_proto という関数を作った。

使う

ファイルを読み込む場合

with open('foo.proto') as f:
    foo_pb2, foo_pb2_grpc = load_proto(f)

文字列を読み込む場合

proto = """
    syntax = "proto3";

    package foo;

    service Foo {
        ...
    }
    """
foo_pb2, foo_pb2_grpc = load_proto(proto)

proto ファイルを明示的にコンパイルしなくても Python で扱えるようになった。

注意点

これ普通に動くけど、あまりやってはいけないことをやっている気がするので真似する際は注意して欲しい。

1
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
hoto17296
ソフトウェアエンジニアです
churadata
沖縄で データ分析 / 機械学習 / Deep Learning をやっている会社です

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
1
Help us understand the problem. What is going on with this article?