Various micro-optimizations (#139)

This commit is contained in:
James 2020-08-30 16:23:57 +01:00 committed by GitHub
parent 16d554db75
commit ca16b6ed34
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -4,7 +4,7 @@ import inspect
import json import json
import struct import struct
import sys import sys
import warnings import typing
from abc import ABC from abc import ABC
from base64 import b64decode, b64encode from base64 import b64decode, b64encode
from datetime import datetime, timedelta, timezone from datetime import datetime, timedelta, timezone
@ -22,8 +22,6 @@ from typing import (
get_type_hints, get_type_hints,
) )
import typing
from ._types import T from ._types import T
from .casing import camel_case, safe_snake_case, snake_case from .casing import camel_case, safe_snake_case, snake_case
from .grpc.grpclib_client import ServiceStub from .grpc.grpclib_client import ServiceStub
@ -126,11 +124,7 @@ class Casing(enum.Enum):
SNAKE = snake_case SNAKE = snake_case
class _PLACEHOLDER: PLACEHOLDER: Any = object()
pass
PLACEHOLDER: Any = _PLACEHOLDER()
@dataclasses.dataclass(frozen=True) @dataclasses.dataclass(frozen=True)
@ -261,7 +255,7 @@ class Enum(enum.IntEnum):
def from_string(cls, name: str) -> int: def from_string(cls, name: str) -> int:
"""Return the value which corresponds to the string name.""" """Return the value which corresponds to the string name."""
try: try:
return cls.__members__[name] return cls._member_map_[name]
except KeyError as e: except KeyError as e:
raise ValueError(f"Unknown value {name} for enum {cls.__name__}") from e raise ValueError(f"Unknown value {name} for enum {cls.__name__}") from e
@ -349,7 +343,7 @@ def _serialize_single(
"""Serializes a single field and value.""" """Serializes a single field and value."""
value = _preprocess_single(proto_type, wraps, value) value = _preprocess_single(proto_type, wraps, value)
output = b"" output = bytearray()
if proto_type in WIRE_VARINT_TYPES: if proto_type in WIRE_VARINT_TYPES:
key = encode_varint(field_number << 3) key = encode_varint(field_number << 3)
output += key + value output += key + value
@ -366,10 +360,10 @@ def _serialize_single(
else: else:
raise NotImplementedError(proto_type) raise NotImplementedError(proto_type)
return output return bytes(output)
def decode_varint(buffer: bytes, pos: int, signed: bool = False) -> Tuple[int, int]: def decode_varint(buffer: bytes, pos: int) -> Tuple[int, int]:
""" """
Decode a single varint value from a byte buffer. Returns the value and the Decode a single varint value from a byte buffer. Returns the value and the
new position in the buffer. new position in the buffer.
@ -513,7 +507,7 @@ class Message(ABC):
all_sentinel = True all_sentinel = True
# Set current field of each group after `__init__` has already been run. # Set current field of each group after `__init__` has already been run.
group_current: Dict[str, str] = {} group_current: Dict[str, Optional[str]] = {}
for field_name, meta in self._betterproto.meta_by_field_name.items(): for field_name, meta in self._betterproto.meta_by_field_name.items():
if meta.group: if meta.group:
@ -571,7 +565,7 @@ class Message(ABC):
""" """
Get the binary encoded Protobuf representation of this instance. Get the binary encoded Protobuf representation of this instance.
""" """
output = b"" output = bytearray()
for field_name, meta in self._betterproto.meta_by_field_name.items(): for field_name, meta in self._betterproto.meta_by_field_name.items():
value = getattr(self, field_name) value = getattr(self, field_name)
@ -609,7 +603,7 @@ class Message(ABC):
# Packed lists look like a length-delimited field. First, # Packed lists look like a length-delimited field. First,
# preprocess/encode each value into a buffer and then # preprocess/encode each value into a buffer and then
# treat it like a field of raw bytes. # treat it like a field of raw bytes.
buf = b"" buf = bytearray()
for item in value: for item in value:
buf += _preprocess_single(meta.proto_type, "", item) buf += _preprocess_single(meta.proto_type, "", item)
output += _serialize_single(meta.number, TYPE_BYTES, buf) output += _serialize_single(meta.number, TYPE_BYTES, buf)
@ -644,7 +638,8 @@ class Message(ABC):
wraps=meta.wraps or "", wraps=meta.wraps or "",
) )
return output + self._unknown_fields output += self._unknown_fields
return bytes(output)
# For compatibility with other libraries # For compatibility with other libraries
SerializeToString = __bytes__ SerializeToString = __bytes__
@ -754,14 +749,14 @@ class Message(ABC):
""" """
# Got some data over the wire # Got some data over the wire
self._serialized_on_wire = True self._serialized_on_wire = True
proto_meta = self._betterproto
for parsed in parse_fields(data): for parsed in parse_fields(data):
field_name = self._betterproto.field_name_by_number.get(parsed.number) field_name = proto_meta.field_name_by_number.get(parsed.number)
if not field_name: if not field_name:
self._unknown_fields += parsed.raw self._unknown_fields += parsed.raw
continue continue
meta = self._betterproto.meta_by_field_name[field_name] meta = proto_meta.meta_by_field_name[field_name]
value: Any value: Any
if parsed.wire_type == WIRE_LEN_DELIM and meta.proto_type in PACKED_TYPES: if parsed.wire_type == WIRE_LEN_DELIM and meta.proto_type in PACKED_TYPES:
@ -907,7 +902,6 @@ class Message(ABC):
returns the instance itself and is therefore assignable and chainable. returns the instance itself and is therefore assignable and chainable.
""" """
self._serialized_on_wire = True self._serialized_on_wire = True
fields_by_name = {f.name: f for f in dataclasses.fields(self)}
for key in value: for key in value:
field_name = safe_snake_case(key) field_name = safe_snake_case(key)
meta = self._betterproto.meta_by_field_name.get(field_name) meta = self._betterproto.meta_by_field_name.get(field_name)