Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

to_dict or to_pydict miss integer and boolean fields #490

Open
alirezasafi opened this issue May 14, 2023 · 3 comments · May be fixed by #494
Open

to_dict or to_pydict miss integer and boolean fields #490

alirezasafi opened this issue May 14, 2023 · 3 comments · May be fixed by #494
Labels
bug? Bug or feature?

Comments

@alirezasafi
Copy link

alirezasafi commented May 14, 2023

when i use to_dict or to_pydict function to serialize message, False and 0 values are not work for boolean and integer fields.
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(
        int_field=0,
        bool_field=False
    )
    print(greeting.to_pytdict())
    greeting.int_field = 1
    greeting.bool_field = True
    print(greeting.to_pydict())

and output is:

{}
{'intField': 1, 'boolField': True}

python version: 3.8
betterproto version: 2.0.0b5

@alirezasafi
Copy link
Author

we could change to_pydict to this:

    def to_pydict(
        self, casing: Casing = Casing.CAMEL, include_default_values: bool = False
    ) -> Dict[str, Any]:
        """
        Returns a python dict representation of this object.

        Parameters
        -----------
        casing: :class:`Casing`
            The casing to use for key values. Default is :attr:`Casing.CAMEL` for
            compatibility purposes.
        include_default_values: :class:`bool`
            If ``True`` will include the default values of fields. Default is ``False``.
            E.g. an ``int32`` field will be included with a value of ``0`` if this is
            set to ``True``, otherwise this would be ignored.

        Returns
        --------
        Dict[:class:`str`, Any]
            The python dict representation of this object.
        """
        output: Dict[str, Any] = {}
        defaults = self._betterproto.default_gen
        for field_name, meta in self._betterproto.meta_by_field_name.items():
            field_is_repeated = defaults[field_name] is list
            if self.__raw_get(field_name) is PLACEHOLDER and \
                not include_default_values:
                continue
            value = getattr(self, field_name)
            cased_name = casing(field_name).rstrip("_")  # type: ignore
            if meta.proto_type == TYPE_MESSAGE:
                if isinstance(value, datetime):
                    if (
                        value != DATETIME_ZERO
                        or include_default_values
                        or self._include_default_value_for_oneof(
                            field_name=field_name, meta=meta
                        )
                    ):
                        output[cased_name] = value
                elif isinstance(value, timedelta):
                    if (
                        value != timedelta(0)
                        or include_default_values
                        or self._include_default_value_for_oneof(
                            field_name=field_name, meta=meta
                        )
                    ):
                        output[cased_name] = value
                elif meta.wraps:
                    if value is not None or include_default_values:
                        output[cased_name] = value
                elif field_is_repeated:
                    # Convert each item.
                    value = [i.to_pydict(casing, include_default_values) for i in value]
                    if value or include_default_values:
                        output[cased_name] = value
                elif (
                    value._serialized_on_wire
                    or include_default_values
                    or self._include_default_value_for_oneof(
                        field_name=field_name, meta=meta
                    )
                ):
                    output[cased_name] = value.to_pydict(casing, include_default_values)
            elif meta.proto_type == TYPE_MAP:
                for k in value:
                    if hasattr(value[k], "to_pydict"):
                        value[k] = value[k].to_pydict(casing, include_default_values)

                if value or include_default_values:
                    output[cased_name] = value
            else
                output[cased_name] = value
        return output

@alirezasafi alirezasafi linked a pull request May 27, 2023 that will close this issue
@Gobot1234
Copy link
Collaborator

Coming back to this issue, why can't you use include_default_values=True?

@Gobot1234 Gobot1234 added bug? Bug or feature? wait Waiting for author labels May 27, 2023
@alirezasafi
Copy link
Author

because i don't wanna set default value for all the unset fields.

@Gobot1234 Gobot1234 removed the wait Waiting for author label May 27, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug? Bug or feature?
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants