python-betterproto icon indicating copy to clipboard operation
python-betterproto copied to clipboard

Importing well known types

Open Luminaar opened this issue 4 years ago • 11 comments

Hello,

I'm not sure how to work with well known types.

Having a proto file like this:

syntax = "proto3";      
      
package simple;      
      
import "google/protobuf/empty.proto";      
      
service SimpleSender {      
    rpc Send(SendParams) returns (google.protobuf.Empty) {}      
}      
      
message SendParams {      
    string body = 1;      
}

I get output like this:

# Generated by the protocol buffer compiler.  DO NOT EDIT!      
# sources: Simple.proto      
# plugin: python-betterproto      
from dataclasses import dataclass      
      
import betterproto      
import grpclib          
      
from .google import protobuf      
      
      
@dataclass      
class SendParams(betterproto.Message):      
    body: str = betterproto.string_field(1)      
      
      
class SimpleSenderStub(betterproto.ServiceStub):      
    async def send(self, *, body: str = "") -> protobuf.Empty:      
        request = SendParams()      
        request.body = body         
      
        return await self._unary_unary(      
            "/simple.SimpleSender/Send", request, protobuf.Empty,      
        )

There is ofcourse no google package. I tried to generate code from proto files included in grpc_tools but I'm not able to get any python code.

What is the best way to work with well known types?

Luminaar avatar Jan 06 '20 15:01 Luminaar

It looks like the google.protobuf.Emtpy type is not currently supported. Someone will need to implement it in python-betterproto.

As a workaround you can define your own empty message until this is done.

danielgtaylor avatar Jan 10 '20 00:01 danielgtaylor

Howdy people!

The same issue happens when I tried to use Struct.

from unbabelevents.chat_api import *
---------------------------------------------------------------------------
ModuleNotFoundError                       Traceback (most recent call last)
<ipython-input-2-4950c13b1c3b> in <module>
----> 1 from unbabelevents.chat_api import *
~/chat_api.py in <module>
      9
     10 from . import commons
---> 11 from .google import protobuf
     12
     13

ModuleNotFoundError: No module named 'unbabelevents.google'

The proto file has the following message

syntax = "proto3";

import "google/protobuf/struct.proto";

message Nugget {
    repeated google.protobuf.Struct alerts = 1;
}

And the generated python class is


import betterproto

from . import commons
from .google import protobuf


@dataclass
class Nugget(betterproto.Message):
    qe_alerts: List[protobuf.Struct] = betterproto.message_field(1)

JoaoVasques avatar Jan 27 '20 16:01 JoaoVasques

It looks like the google.protobuf.Emtpy type is not currently supported. Someone will need to implement it in python-betterproto.

There is a google.protobuf.empty_pb2.Empty

devova avatar Feb 26 '20 09:02 devova

@devova yes but there are no generated dataclasses.

I made this module as a bandaid.


#  proto_types.py
from dataclasses import dataclass
import betterproto
from google.protobuf import struct_pb2



@dataclass
class Struct(betterproto.Message):
    def parse(self: betterproto.T, data: bytes) -> betterproto.T:
        decoded = struct_pb2.Struct.FromString(data)
        self.__dict__.update({item: value for item, value in decoded.items()})
        return self

    def __repr__(self):
        return repr(self.__dict__)


@dataclass
class Empty(betterproto.Message):
    def parse(self: betterproto.T, data: bytes) -> betterproto.T:
        return self

And then a post-generating find and replace.

with open(file_path, 'r') as f:
    lines = f.readlines()
with open(file_path, 'w') as f:
    for line in lines:
        line = line.replace("from .google import protobuf", "from wherever_proto_types_exists import proto_types")
        line = line.replace('protobuf.Empty', 'proto_types.Empty')
        line = line.replace('protobuf.Struct', 'proto_types.Struct')
        f.write(line)

where file_path is the path to the generated grpc python module

adisunw avatar Feb 27 '20 16:02 adisunw

Fixed by #78?

kalvdans avatar Jul 26 '20 12:07 kalvdans

Not Struct, unfortunately. If Struct is the only WKT used in your protobuf (as it is for me), you'll still have this dangling/invalid import. @adisunw 's patch fix at least unblocks the build, which is great.

Even easier than the find-replace that @adisunw provides above, if you just put that file in google/protobuf.py relative to the imported files you're in business.

kalzoo avatar Feb 11 '21 00:02 kalzoo

Is this what is needed? (along with the other types) https://github.com/danielgtaylor/python-betterproto/blob/master/src/betterproto/lib/google/protobuf/init.py#L1100

cetanu avatar Mar 16 '21 11:03 cetanu

I am also impacted by this issue.

lizelive avatar Feb 03 '22 06:02 lizelive

Is this still an issue? I am using wkt timestamp and it works for me with 2.0.0b5.

zwn avatar Sep 15 '22 08:09 zwn

Seems like it's still an issue. The lack of support for Empty, Value and FieldMask prevents me from using this (really nice!) library :(

krugi avatar Feb 15 '23 21:02 krugi

wait, seems like all of them are already here 🤔 https://github.com/danielgtaylor/python-betterproto/blob/13d656587cd4f1211b12a0fc5d9dbaf04b2bca9d/src/betterproto/lib/google/protobuf/init.py#L1362

Any idea why there's no files under from .google import protobuf? (generating using buf.build, if it matters)

krugi avatar Feb 15 '23 21:02 krugi