Suggestion: give user an option not to change field name of the message.
Every prevailing project has its own name-style, forcing users to rename every name may be not a good idea.
To communicate with Java/C++/JavaScript, mixedCase (also known as Lower CamelCase) is accepted by every other language,
and it is much shorter than PEP8 suggested-style: private_multicast_addr .
In my case, the InitConfig is passed by an JSON-object from web client, changing the name back and forth is useless and boring.
message InitConfig{
string sendFileDir=1;
string publicMulitcastAddr=2;
uint32 linkID =3;
string privateMulticastAddr=4;
uint32 CIR=5;
repeated string channels=6;
repeated string waitingFiles=7;
}
the generated python file by betterproto:
@dataclass(eq=False, repr=False)
class InitConfig(betterproto.Message):
send_file_dir: str = betterproto.string_field(1)
public_mulitcast_addr: str = betterproto.string_field(2)
link_id: int = betterproto.uint32_field(3)
private_multicast_addr: str = betterproto.string_field(4)
cir: int = betterproto.uint32_field(5)
channels: List[str] = betterproto.string_field(6)
waiting_files: List[str] = betterproto.string_field(7)
JS(brower)<--JSON--> Python(web server) <--GRPC--> C++(file stransfer backend)
{
"sendFileDir": "/home/lccy/sendfile",
"publicMulitcastAddr": "223.0.1.1",
"linkID": 1,
"privateMulticastAddr": "234.0.1.1",
"CIR": 22333,
"channels": [
"\u7b2c\u4e00\u9891\u9053",
"\u7b2c\u4e8c\u9891\u9053"
],
"waitingFiles": [
"\u7b2c\u4e00\u9891\u9053/11.txt",
"\u7b2c\u4e8c\u9891\u9053/22.txt"
]
}
If you are serialising as JSON you can pass a betterproto.Casing to make sure that the field names are in camelCase
Question 1: betterproto.Casing.CAMEL seems not enough:
message ReplyX{
bool aBigCDEndOne=1;//
}
import betterproto
from uftplink import ReplyX
a = ReplyX(a_big_cd_end_one=True)
b =a.to_dict(casing=betterproto.Casing.CAMEL )
expect = {'aBigCDEndOne':True}
assert b== expect #not equal
question 2: from JSON to ReplyX message?
question2.1: easy way from JSON to Nested-Type message?
message _FileInfo{
string name=1;
uint64 size=2;
}
message _SendFileStatus{
string name=1;
uint64 size=2;
uint64 sended =3;
}
message LinkFileStatus{
repeated _FileInfo waitingFiles=1;
_SendFileStatus currentFile=2;
}
a = {
"currentFile":{"name":"c/11.txt", "size":532323,"sended":3322,},
"waitingFiles":[
{"name":"c/12.txt",
"size":32325,
}
,{"name":"c/22.txt",
"size":32335,
}
],
}
LinkFileStatus( **a ) #not work
a changed generated Python file:
@dataclass(eq=False, repr=False)
class FileInfo(betterproto.Message):
name: str = betterproto.string_field(1)
size: int = betterproto.uint64_field(2)
@dataclass(eq=False, repr=False)
class SendFileStatus(betterproto.Message):
name: str = betterproto.string_field(1)
size: int = betterproto.uint64_field(2)
sended: int = betterproto.uint64_field(3)
@dataclass(eq=False, repr=False)
class LinkFileStatus(betterproto.Message):
waitingFiles: List[FileInfo] = betterproto.message_field(1)
currentFile: SendFileStatus = betterproto.message_field(2)
a simple JSON-> betterproto.Message
from betterproto import Message
def set_attrs(value_type:Message, value):
'''
oneof is not considered
'''
if value_type == Empty:
return Empty()
result = value_type()
for field_name, field_type in result.__annotations__.items():
if hasattr(field_type,'_name'):
list_field_type = field_type.__args__[0]
if field_type._name=='List': #repeated/python typing.List
if issubclass(list_field_type, Message):
list_value = [set_attrs(list_field_type, v) for v in value.get(field_name)]
setattr(result, field_name, list_value )
else:
setattr(result, field_name, value.get(field_name))
elif field_type._name =='Optional':
if issubclass(list_field_type, Message):
if field_value:= value.get(field_name):
setattr(result, field_name, set_attrs(list_field_type,field_value) )
elif issubclass(field_type, Message): #Nested Message
setattr(result, field_name, set_attrs(field_type, value.get(field_name)) )
else:
setattr(result, field_name, value.get(field_name))
return result
b = set_attrs(LinkFileStatus, a)
bytes(b)