Skip to content

Test failures in Python 3.14 due to changes in metadata handling (2.0.0b7) #679

Description

@sarahec

Summary

Error: cls._betterproto_meta no longer exists @ betterproto/init.py:909

Reproduction Steps

While building release 2.0.0b7 for nixpkgs

Expected Results

It should build and test cleanly.

Actual Results

____________ test_message_can_instantiated[namespace_builtin_types] ____________

cls = <class 'tests.output_betterproto.namespace_builtin_types.Test'>

    @classproperty
    def _betterproto(cls: type[Self]) -> ProtoClassMetadata:  # type: ignore
        """
        Lazy initialize metadata for each protobuf class.
        It may be initialized multiple times in a multi-threaded environment,
        but that won't affect the correctness.
        """
        try:
>           return cls._betterproto_meta
                   ^^^^^^^^^^^^^^^^^^^^^
E           AttributeError: type object 'Test' has no attribute '_betterproto_meta'. Did you mean: '_betterproto'?

/nix/store/i3pvlk97zcrmgmcmrjzx1qfgkd8jhkw2-python3.14-betterproto-2.0.0b7/lib/python3.14/site-packages/betterproto/__init__.py:909: AttributeError

During handling of the above exception, another exception occurred:

test_data = TestData(plugin_module=<module 'tests.output_betterproto.namespace_builtin_types' from '/nix/var/nix/builds/nix-build-...-for-map",\n  "bool": "value-for-bool"\n}', test_name='namespace_builtin_types', file_name='namespace_builtin_types')])

    @pytest.mark.parametrize("test_data", test_cases.messages, indirect=True)
    def test_message_can_instantiated(test_data: TestData) -> None:
        plugin_module, *_ = test_data
>       plugin_module.Test()

tests/test_inputs.py:165:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
<string>:18: in __init__
    ???
/nix/store/i3pvlk97zcrmgmcmrjzx1qfgkd8jhkw2-python3.14-betterproto-2.0.0b7/lib/python3.14/site-packages/betterproto/__init__.py:755: in __post_init__
    for field_name, meta in self._betterproto.meta_by_field_name.items():
                            ^^^^^^^^^^^^^^^^^
/nix/store/i3pvlk97zcrmgmcmrjzx1qfgkd8jhkw2-python3.14-betterproto-2.0.0b7/lib/python3.14/site-packages/betterproto/__init__.py:846: in __getattribute__
    value = super().__getattribute__(name)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/nix/store/i3pvlk97zcrmgmcmrjzx1qfgkd8jhkw2-python3.14-betterproto-2.0.0b7/lib/python3.14/site-packages/betterproto/utils.py:56: in __get__
    return self.__func__(type)
           ^^^^^^^^^^^^^^^^^^^
/nix/store/i3pvlk97zcrmgmcmrjzx1qfgkd8jhkw2-python3.14-betterproto-2.0.0b7/lib/python3.14/site-packages/betterproto/__init__.py:911: in _betterproto
    cls._betterproto_meta = meta = ProtoClassMetadata(cls)
                                   ^^^^^^^^^^^^^^^^^^^^^^^
/nix/store/i3pvlk97zcrmgmcmrjzx1qfgkd8jhkw2-python3.14-betterproto-2.0.0b7/lib/python3.14/site-packages/betterproto/__init__.py:691: in __init__
    self.default_gen = self._get_default_gen(cls, fields)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/nix/store/i3pvlk97zcrmgmcmrjzx1qfgkd8jhkw2-python3.14-betterproto-2.0.0b7/lib/python3.14/site-packages/betterproto/__init__.py:698: in _get_default_gen
    return {field.name: cls._get_field_default_gen(field) for field in fields}
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

cls = <class 'tests.output_betterproto.namespace_builtin_types.Test'>
field = Field(name='int',type=Field(name='str',type=<class 'str'>,default=<object object at 0x10428ecd0>,default_factory=<data...oto_type='string', map_types=None, group=None, wraps=None, optional=False)}),kw_only=
False,doc=None,_field_type=_FIELD)

    @classmethod
    def _get_field_default_gen(cls, field: dataclasses.Field) -> Any:
        t = cls._type_hint(field.name)

        is_310_union = isinstance(t, _types_UnionType)
        if hasattr(t, "__origin__") or is_310_union:
            if is_310_union or t.__origin__ is Union:
                # This is an optional field (either wrapped, or using proto3
                # field presence). For setting the default we really don't care
                # what kind of field it is.
                return type(None)
            if t.__origin__ is list:
                # This is some kind of list (repeated) field.
                return list
            if t.__origin__ is dict:
                # This is some kind of map (dict in Python).
                return dict
            return t
>       if issubclass(t, Enum):
           ^^^^^^^^^^^^^^^^^^^
E       TypeError: issubclass() arg 1 must be a class

/nix/store/i3pvlk97zcrmgmcmrjzx1qfgkd8jhkw2-python3.14-betterproto-2.0.0b7/lib/python3.14/site-packages/betterproto/__init__.py:1191: TypeError.
.
.
=========================== short test summary info ============================
FAILED tests/test_inputs.py::test_message_can_instantiated[namespace_builtin_types] - TypeError: issubclass() arg 1 must be a class
FAILED tests/test_inputs.py::test_message_equality[namespace_builtin_types] - TypeError: issubclass() arg 1 must be a class
FAILED tests/test_inputs.py::test_message_json[namespace_builtin_types] - TypeError: issubclass() arg 1 must be a class

### System Information

Python 3.14.2


### Checklist

- [x] I have searched the issues for duplicates.
- [x] I have shown the entire traceback, if possible.
- [x] I have verified this issue occurs on the latest prelease of betterproto which can be installed using `pip install -U --pre betterproto`, if possible.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions