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

Fix to_(py)?dict bool fields

Open alirezasafi opened this issue 1 year ago • 10 comments

Fixes #490

alirezasafi avatar May 27 '23 06:05 alirezasafi

Hi, thank you for the PR, would you be able to run poe fmt and add a regression test for this code change?

Gobot1234 avatar May 27 '23 09:05 Gobot1234

I'm very hesitant to make a change of behaviour like this just for bool fields. Does the proposed change apply to all fields which are set and include them even if bool(value) returns False?

Gobot1234 avatar May 27 '23 10:05 Gobot1234

yes its applied to all of them and include bool field even if the value is False. here is the sample code:

from dataclasses import dataclass

import betterproto


@dataclass
class Greeting(betterproto.Message):
    """Greeting represents a message you can tell a user."""

    int_field: int = betterproto.int32_field(1)
    bool_field: bool = betterproto.bool_field(2)


if __name__ == "__main__":
    greeting = Greeting(
        bool_field=False,
    )
    print("default value is disabled (bool_field=False): ", greeting.to_pydict(include_default_values=False))
    print("default value is enabled (bool_field=False): ", greeting.to_pydict(include_default_values=True))
    greeting = Greeting()
    print("default value is disabled (unset bool_field): ", greeting.to_pydict(include_default_values=False))
    print("default value is enabled (unset bool_field): ", greeting.to_pydict(include_default_values=True))

output:

default value is disabled (bool_field=False):  {'boolField': False}
default value is enabled (bool_field=False):  {'intField': 0, 'boolField': False}
default value is disabled (unset bool_field):  {}
default value is enabled (unset bool_field):  {'intField': 0, 'boolField': False}

alirezasafi avatar May 27 '23 11:05 alirezasafi

Sorry if I wasn't clear, I meant what's the output for things that implement bool that aren't int subclasses. ie what does

from dataclasses import dataclass

import betterproto

@dataclass
class Msg(bettterproto.Message):
    bar: bool = betterproto.bool_field(1)

@dataclass
class Greeting(betterproto.Message):
    """Greeting represents a message you can tell a user."""

    msg_field: Msg = betterproto.message_field(1)
    str_field: str = betterproto.string_field(2)


if __name__ == "__main__":
    greeting = Greeting(
        Msg(), ""
    )
    print(greeting.to_pydict())

print?

Gobot1234 avatar May 27 '23 11:05 Gobot1234

from dataclasses import dataclass

import betterproto

@dataclass
class Msg(bettterproto.Message):
    bar: bool = betterproto.bool_field(1)

@dataclass
class Greeting(betterproto.Message):
    """Greeting represents a message you can tell a user."""

    msg_field: Msg = betterproto.message_field(1)
    str_field: str = betterproto.string_field(2)


if __name__ == "__main__":
    greeting = Greeting(
        Msg(), ""
    )
    print(greeting.to_pydict())

only strField is in the output:

{'strField': ''}

alirezasafi avatar May 27 '23 11:05 alirezasafi

Interesting, I would expect an empty dict for the msg field cause it's set

Gobot1234 avatar May 27 '23 11:05 Gobot1234

bool_field

why? i think the output is correct. because the bool field bar didn't set and default value disabled.

alirezasafi avatar May 27 '23 11:05 alirezasafi

I'd expect the output to be the output you've shown if the Greeting(str_field="") but according to proto spec setting the value of msg_field still means it should show up in the wire format so I think the output should be {'msgField': Msg(), 'strField': ''} for the first input I gave in https://github.com/danielgtaylor/python-betterproto/pull/494#issuecomment-1565356331

Gobot1234 avatar May 27 '23 11:05 Gobot1234

Please could you add some unit tests for this feature please

Gobot1234 avatar May 29 '23 18:05 Gobot1234

I'd expect the output to be the output you've shown if the Greeting(str_field="") but according to proto spec setting the value of msg_field still means it should show up in the wire format so I think the output should be {'msgField': Msg(), 'strField': ''} for the first input I gave in #494 (comment)

I agree, if a message is placed into a field, I would consider it set and expect there to be an empty dict there, if the message itself has no fields set.

cetanu avatar Oct 16 '23 02:10 cetanu