Skip to content

Commit

Permalink
fix: numerous small performance tweaks (#85)
Browse files Browse the repository at this point in the history
  • Loading branch information
software-dov committed Jul 30, 2020
1 parent b2b0ca3 commit 7b5faf2
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 30 deletions.
6 changes: 2 additions & 4 deletions proto/_file_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,11 +158,9 @@ def ready(self, new_class):
# manifest has been populated.
module = inspect.getmodule(new_class)
manifest = self._get_remaining_manifest(new_class)
if not all([hasattr(module, i) for i in manifest]):
return False

# Okay, we are ready.
return True
# We are ready if all members have been populated.
return all(hasattr(module, i) for i in manifest)

@property
def unresolved_fields(self):
Expand Down
26 changes: 12 additions & 14 deletions proto/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
class Field:
"""A representation of a type of field in protocol buffers."""

# Fields are NOT repeated nor maps.
# The RepeatedField overrides this values.
repeated = False

def __init__(
self,
proto_type,
Expand All @@ -35,7 +39,7 @@ def __init__(
):
# This class is not intended to stand entirely alone;
# data is augmented by the metaclass for Message.
self.mcls_data = {}
self.mcls_data = None
self.parent = None

# If the proto type sent is an object or a string, it is really
Expand All @@ -59,11 +63,6 @@ def __init__(
self.optional = optional
self.oneof = oneof

# Fields are neither repeated nor maps.
# The RepeatedField and MapField subclasses override these values
# in their initializers.
self.repeated = False

# Once the descriptor is accessed the first time, cache it.
# This is important because in rare cases the message or enum
# types are written later.
Expand All @@ -72,8 +71,8 @@ def __init__(
@property
def descriptor(self):
"""Return the descriptor for the field."""
proto_type = self.proto_type
if not self._descriptor:
proto_type = self.proto_type
# Resolve the message type, if any, to a string.
type_name = None
if isinstance(self.message, str):
Expand All @@ -83,10 +82,11 @@ def descriptor(self):
)
type_name = self.message
elif self.message:
if hasattr(self.message, "DESCRIPTOR"):
type_name = self.message.DESCRIPTOR.full_name
else:
type_name = self.message.meta.full_name
type_name = (
self.message.DESCRIPTOR.full_name
if hasattr(self.message, "DESCRIPTOR")
else self.message.meta.full_name
)
elif self.enum:
# Nos decipiat.
#
Expand Down Expand Up @@ -146,9 +146,7 @@ def pb_type(self):
class RepeatedField(Field):
"""A representation of a repeated field in protocol buffers."""

def __init__(self, proto_type, *, number: int, message=None, enum=None):
super().__init__(proto_type, number=number, message=message, enum=enum)
self.repeated = True
repeated = True


class MapField(Field):
Expand Down
15 changes: 8 additions & 7 deletions proto/marshal/marshal.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ def to_proto(self, proto_type, value, *, strict: bool = False):

# Convert lists and tuples recursively.
if isinstance(value, (list, tuple)):
return type(value)([self.to_proto(proto_type, i) for i in value],)
return type(value)(self.to_proto(proto_type, i) for i in value)

# Convert dictionaries recursively when the proto type is a map.
# This is slightly more complicated than converting a list or tuple
Expand All @@ -196,9 +196,8 @@ def to_proto(self, proto_type, value, *, strict: bool = False):
proto_type.DESCRIPTOR.has_options
and proto_type.DESCRIPTOR.GetOptions().map_entry
):
return {
k: self.to_proto(type(proto_type().value), v) for k, v in value.items()
}
recursive_type = type(proto_type().value)
return {k: self.to_proto(recursive_type, v) for k, v in value.items()}

# Convert ordinary values.
rule = self._rules.get(proto_type, self._noop)
Expand Down Expand Up @@ -235,9 +234,11 @@ def __new__(cls, *, name: str):
marshals with the same ``name`` argument will provide the
same marshal each time.
"""
if name not in cls._instances:
cls._instances[name] = super().__new__(cls)
return cls._instances[name]
klass = cls._instances.get(name)
if klass is None:
klass = cls._instances[name] = super().__new__(cls)

return klass

def __init__(self, *, name: str):
"""Instantiate a marshal.
Expand Down
14 changes: 9 additions & 5 deletions proto/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ def __new__(mcls, name, bases, attrs):
# shorthand for a nested message and a repeated field of that message.
# Decompose each map into its constituent form.
# https://developers.google.com/protocol-buffers/docs/proto3#maps
for key, field in copy.copy(attrs).items():
map_fields = {}
for key, field in attrs.items():
if not isinstance(field, MapField):
continue

Expand Down Expand Up @@ -92,13 +93,16 @@ def __new__(mcls, name, bases, attrs):
entry_attrs["value"] = Field(
field.proto_type, number=2, enum=field.enum, message=field.message,
)
attrs[msg_name] = MessageMeta(msg_name, (Message,), entry_attrs)
map_fields[msg_name] = MessageMeta(msg_name, (Message,), entry_attrs)

# Create the repeated field for the entry message.
attrs[key] = RepeatedField(
ProtoType.MESSAGE, number=field.number, message=attrs[msg_name],
map_fields[key] = RepeatedField(
ProtoType.MESSAGE, number=field.number, message=map_fields[msg_name],
)

# Add the new entries to the attrs
attrs.update(map_fields)

# Okay, now we deal with all the rest of the fields.
# Iterate over all the attributes and separate the fields into
# their own sequence.
Expand Down Expand Up @@ -525,7 +529,7 @@ def __setattr__(self, key, value):
For well-known protocol buffer types which are marshalled, either
the protocol buffer object or the Python equivalent is accepted.
"""
if key.startswith("_"):
if key[0] == "_":
return super().__setattr__(key, value)
marshal = self._meta.marshal
pb_type = self._meta.fields[key].pb_type
Expand Down

0 comments on commit 7b5faf2

Please sign in to comment.