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

Shorter optional fields

Open MicaelJarniac opened this issue 2 years ago • 0 comments

Optional fields generate very long and repetitive code.

The idea is to use shorter and simpler code, and internally consider it as a field having optional=True, group=f"_{field_name}".

Related to #459.

Proto file

syntax = "proto3";

message Foo {
    optional uint32 bar = 1;
};

Currently generated code

from dataclasses import dataclass

import betterproto

@dataclass(eq=False, repr=False)
class Foo(betterproto.Message):
    bar: Optional[int] = betterproto.uint32_field(
        1, optional=True, group="_bar"
    )

Idea A

Read the type-hint of the field, and if it's a union of a type with None, consider it an optional field.

This might be a bad idea if unions of a type + None are used for something other than optional fields.

An example implementation of detecting optional fields can be found here: cattrs/converters.py.

from dataclasses import dataclass
from typing import Union, Optional

import betterproto

@dataclass(eq=False, repr=False)
class Foo(betterproto.Message):
    bar: Optional[int] = betterproto.uint32_field(1)

Idea B

Use a custom type-hint that indicates a field is optional, and is correctly understood by type-checkers as Optional.

from dataclasses import dataclass

import betterproto

@dataclass(eq=False, repr=False)
class Foo(betterproto.Message):
    bar: betterproto.OptionalField[int] = betterproto.uint32_field(1)

It could possibly be implemented something like this: Annotated

from typing import Optional, TypeVar
from typing_extensions import Annotated

T = TypeVar("T")

optional_metadata = object()  # or another sentinel

OptionalField = Annotated[Optional[T], optional_metadata]

Idea C

Automatically add group=f"_{field_name}" if optional=True and no group specified.

from dataclasses import dataclass

import betterproto


@dataclass(eq=False, repr=False)
class Foo(betterproto.Message):
    bar: Optional[int] = betterproto.uint32_field(1, optional=True)

MicaelJarniac avatar Jun 02 '23 03:06 MicaelJarniac