hit9 / bitproto

The bit level data interchange format for serializing data structures (long term maintenance).
https://bitproto.readthedocs.io/
BSD 3-Clause "New" or "Revised" License
127 stars 16 forks source link

Invalid enum field name on imported proto on python generation #52

Closed hit9 closed 1 year ago

hit9 commented 1 year ago

Test on bitproto v1.1.0:

// b.bitproto
proto b;

enum X : uint1 {
    OK = 0;
}
// a.bitproto
proto a

import "b.bitproto"

message A {
    b.X x = 1;
}

Generates for python:


# b_bp.py

# Code generated by bitproto. DO NOT EDIT.

import json
from dataclasses import dataclass, field
from typing import ClassVar, Dict, List, Union
from enum import IntEnum, unique

from bitprotolib import bp

@unique
class X(IntEnum): # 1bit
    OK = 0

# Aliases for backwards compatibility
OK: X = X.OK

_X_VALUE_TO_NAME_MAP: Dict[X, str] = {
    X.OK: "OK",
}

def bp_processor_X() -> bp.Processor:
    return bp.EnumProcessor(bp.Uint(1))

# a_bp.py

import json
from dataclasses import dataclass, field
from typing import ClassVar, Dict, List, Union
from enum import IntEnum, unique

from bitprotolib import bp

import b_bp as b

@dataclass
class A(bp.MessageBase):
    # Number of bytes to serialize class A
    BYTES_LENGTH: ClassVar[int] = 1

    x: Union[int, b.X] = b.X.b.OK          # !!!!!!!!!!!!! ERROR here
    # This field is a proxy to hold integer value of enum field 'x'
    _enum_field_proxy__x: int = field(init=False, repr=False) # 1bit

    def __post_init__(self):
        # initialize handling of enum field 'x' as `enum.IntEnum`
        if not isinstance(getattr(A, "x", False), property):
            self._enum_field_proxy__x = self.x
            A.x = property(A._get_x, A._set_x)  # type: ignore

    @staticmethod
    def dict_factory(kv_pairs):
        return {k: v for k, v in kv_pairs if not k.startswith('_enum_field_proxy__')}

    def _get_x(self) -> b.X:
        """property getter for enum proxy field"""
        return b.X(self._enum_field_proxy__x)

    def _set_x(self, val):
        """property setter for enum proxy field"""
        self._enum_field_proxy__x = val

    def bp_processor(self) -> bp.Processor:
        field_processors: List[bp.Processor] = [
            bp.MessageFieldProcessor(1, b.bp_processor_X()),
        ]
        return bp.MessageProcessor(False, 1, field_processors)

    def bp_set_byte(self, di: bp.DataIndexer, lshift: int, b: bp.byte) -> None:
        if di.field_number == 1:
            self.x |= (b.X(b) << lshift)
        return

    def bp_get_byte(self, di: bp.DataIndexer, rshift: int) -> bp.byte:
        if di.field_number == 1:
            return (self.x >> rshift) & 255
        return bp.byte(0)  # Won't reached

    def bp_get_accessor(self, di: bp.DataIndexer) -> bp.Accessor:
        return bp.NilAccessor() # Won't reached

    def encode(self) -> bytearray:
        """
        Encode this object to bytearray.
        """
        s = bytearray(self.BYTES_LENGTH)
        ctx = bp.ProcessContext(True, s)
        self.bp_processor().process(ctx, bp.NIL_DATA_INDEXER, self)
        return ctx.s

    def decode(self, s: bytearray) -> None:
        """
        Decode given bytearray s to this object.
        :param s: A bytearray with length at least `BYTES_LENGTH`.
        """
        assert len(s) >= self.BYTES_LENGTH, bp.NotEnoughBytes()
        ctx = bp.ProcessContext(False, s)
        self.bp_processor().process(ctx, bp.NIL_DATA_INDEXER, self)

    def bp_process_int(self, di: bp.DataIndexer) -> None:
        return
hit9 commented 1 year ago

Fixed in #53