diff --git a/src/betterproto/__init__.py b/src/betterproto/__init__.py index 0dcf1e5..dab33f1 100644 --- a/src/betterproto/__init__.py +++ b/src/betterproto/__init__.py @@ -1319,7 +1319,12 @@ class Message(ABC): :class:`bool` `True` if field has been set, otherwise `False`. """ - return self.__raw_get(name) is not PLACEHOLDER + default = ( + PLACEHOLDER + if not self._betterproto.meta_by_field_name[name].optional + else None + ) + return self.__raw_get(name) is not default def serialized_on_wire(message: Message) -> bool: diff --git a/tests/test_features.py b/tests/test_features.py index 39fa5c2..ffbab47 100644 --- a/tests/test_features.py +++ b/tests/test_features.py @@ -517,3 +517,15 @@ def test_copyability(): assert spam == deepcopied assert spam is not deepcopied assert spam.baz is not deepcopied.baz + + +def test_is_set(): + @dataclass + class Spam(betterproto.Message): + foo: bool = betterproto.bool_field(1) + bar: Optional[int] = betterproto.int32_field(2, optional=True) + + assert not Spam().is_set("foo") + assert not Spam().is_set("bar") + assert Spam(foo=True).is_set("foo") + assert Spam(foo=True, bar=0).is_set("bar")