Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

Official method to determine if betterproto.Message or betterproto.primitive was set

未关闭
#659 2 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

评估

难度
5/5
预计耗时
一周以上
新手友好度
35/100
Issue 类型
功能
描述清晰度
基本清楚
活跃度
停滞
技术栈
python
领域
api

调研方向

从 test.py 示例以及其中展示的 Message.parse、_serialized_on_wire、FieldMetadata 和 _get_field_default 入口点开始。复现默认值 primitive 和未知字节的情况,然后将受支持的行为与所要求的 parsed-versus-unset 区分进行比较。对于消息和 primitive 字段,覆盖所选择的 public behavior 即表示完成。

由索引模型根据 Issue 内容生成。

描述

enhancement
Summary

The _serialized_on_wire attribute is 99% of the functionality I require.
Because it is a dunder attribute I can't rely on the attribute in future updates.

What is the feature request for?

The core library

The Problem

A method for determining if a betterproto field was set from parsed data in the protobuf bytes vs default value.
Fields in protobuf messages are optional by default.
It is important to detect if a field was set vs the default value.
For example, in Pydantic, optional values are None when unset.

This is done for the user by checking _serialized_on_wire.
I would like a supported function or non-dunder attribute exposing the _serialized_on_wire value.

Additionally, _serialized_on_wire is not enough when dealing with primitive types.
Currently, primitives types are check against the default value to determine their "_serialized_on_wire" status.
This causes primitive types that HAVE been set but match the default value to be indistinguishable from default set primitives.

Below is my testing code and function that works for my use case.
Other use cases will run into the primitive set issue.

# example.proto

syntax = "proto3";
option optimize_for = LITE_RUNTIME;

package example;

message NoPrimitives {
    PrimitivesOne one = 1;
    PrimitivesTwo two = 2;
}

message PrimitivesOne {
    uint64 value1 = 1;
    uint64 value2 = 2;
}

message PrimitivesTwo {
    string value1 = 1;
    string value2 = 2;
}
# test.py

import dataclasses
import betterproto
from proto_example import NoPrimitives, PrimitivesOne

data = b"foo"
no_primitives = NoPrimitives().parse(data)

# appends unparsed data at the end
# Is there a supported way to remove unpased bytes?
# I would have expected unparsable bytes to be dropped when converting back.
print(f"original: {data}")
print(f"reconstructed: {bytes(no_primitives)}")

# will return true because bytes exist, even if no bytes are "valid/parsed" in the protobuf structure
print(f"serialized: {no_primitives._serialized_on_wire}")


# a workable solution in my use case, but will not handle other possible cases
def serialized_on_wire(better_proto: betterproto.Message):
    """return true if proto message was serialized on wire"""

    for field in dataclasses.fields(better_proto):
        meta = betterproto.FieldMetadata.get(field)
        v = getattr(better_proto, field.name)

        if isinstance(v, betterproto.Message):
            if v._serialized_on_wire:
                return True
        elif v != better_proto._get_field_default(field, meta):
            return True

    return False


# How to detect serialized_on_wire for messages with primitive types only? (int, string, ect...)

# Assuming primitive types are changed from defaults, desired behavoir.
data = b"foo"
no_primitives = NoPrimitives().parse(data)
no_primitives.one = 1
print(f"serialized original: {no_primitives._serialized_on_wire}")
print(f"serialized new: {serialized_on_wire(no_primitives)}")

# If primitive types correlate with default values, undesired behavoir.
primitives_one = PrimitivesOne().parse(b"")
print(f"serialized before manual set: {primitives_one._serialized_on_wire}")

# setting values that correlate with default values
# will set serialized on wire to true
primitives_one.value1 = 0
primitives_one.value2 = 0

# can detect items have been set but not which ones, to_dict will still return empty
print(f"serialized after manual set: {primitives_one._serialized_on_wire}")
print(f"serialized new: {serialized_on_wire(primitives_one)}")

# Valid values have been set but because they correlate with default values nothing is retured.
# I would like a way to detect if a value if the default value AND parsed over serial or set through python.
# Even if bytes have been given to parse but invalid/unparsed
print(f"empty dictionary: {primitives_one.to_dict() == {}}")  # returns true
The Ideal Solution

Optional fields can be None when unset. (pydantics solution)
If default value returns are desired, there is already a flag for that.

For betterproto.Messages:
A method to return False if all primitive/non-primitive fields are unset.

For primitives:
Some other method for determining unset values beyond checking if the value is equal to the default value.

The Current Solution

99% solution for determining if an attribute if unset:
Check against the dunder attribute _serialized_on_wire directly and checking if primitives are equal to their default values.

Unable to determine if primitives are set but still equal to default value.

主要语言
Python
星标
1.8k
派生
235
PR 合并指标
30 天内没有已合并 PR

环境准备

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

danielgtaylor/python-betterproto 的其他 Issue

查看 danielgtaylor/python-betterproto 的全部 Issue

相似的 Issue

更多 Python Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。