Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
field_mask.py313 linesDownload Raw Back to internal
1# Protocol Buffers - Google's data interchange format2# Copyright 2008 Google Inc.  All rights reserved.3#4# Use of this source code is governed by a BSD-style5# license that can be found in the LICENSE file or at6# https://developers.google.com/open-source/licenses/bsd7 8"""Contains FieldMask class."""9 10from google.protobuf.descriptor import FieldDescriptor11 12 13class FieldMask(object):14  """Class for FieldMask message type."""15 16  __slots__ = ()17 18  def ToJsonString(self):19    """Converts FieldMask to string according to proto3 JSON spec."""20    camelcase_paths = []21    for path in self.paths:22      camelcase_paths.append(_SnakeCaseToCamelCase(path))23    return ','.join(camelcase_paths)24 25  def FromJsonString(self, value):26    """Converts string to FieldMask according to proto3 JSON spec."""27    if not isinstance(value, str):28      raise ValueError('FieldMask JSON value not a string: {!r}'.format(value))29    self.Clear()30    if value:31      for path in value.split(','):32        self.paths.append(_CamelCaseToSnakeCase(path))33 34  def IsValidForDescriptor(self, message_descriptor):35    """Checks whether the FieldMask is valid for Message Descriptor."""36    for path in self.paths:37      if not _IsValidPath(message_descriptor, path):38        return False39    return True40 41  def AllFieldsFromDescriptor(self, message_descriptor):42    """Gets all direct fields of Message Descriptor to FieldMask."""43    self.Clear()44    for field in message_descriptor.fields:45      self.paths.append(field.name)46 47  def CanonicalFormFromMask(self, mask):48    """Converts a FieldMask to the canonical form.49 50    Removes paths that are covered by another path. For example,51    "foo.bar" is covered by "foo" and will be removed if "foo"52    is also in the FieldMask. Then sorts all paths in alphabetical order.53 54    Args:55      mask: The original FieldMask to be converted.56    """57    tree = _FieldMaskTree(mask)58    tree.ToFieldMask(self)59 60  def Union(self, mask1, mask2):61    """Merges mask1 and mask2 into this FieldMask."""62    _CheckFieldMaskMessage(mask1)63    _CheckFieldMaskMessage(mask2)64    tree = _FieldMaskTree(mask1)65    tree.MergeFromFieldMask(mask2)66    tree.ToFieldMask(self)67 68  def Intersect(self, mask1, mask2):69    """Intersects mask1 and mask2 into this FieldMask."""70    _CheckFieldMaskMessage(mask1)71    _CheckFieldMaskMessage(mask2)72    tree = _FieldMaskTree(mask1)73    intersection = _FieldMaskTree()74    for path in mask2.paths:75      tree.IntersectPath(path, intersection)76    intersection.ToFieldMask(self)77 78  def MergeMessage(79      self, source, destination,80      replace_message_field=False, replace_repeated_field=False):81    """Merges fields specified in FieldMask from source to destination.82 83    Args:84      source: Source message.85      destination: The destination message to be merged into.86      replace_message_field: Replace message field if True. Merge message87          field if False.88      replace_repeated_field: Replace repeated field if True. Append89          elements of repeated field if False.90    """91    tree = _FieldMaskTree(self)92    tree.MergeMessage(93        source, destination, replace_message_field, replace_repeated_field)94 95 96def _IsValidPath(message_descriptor, path):97  """Checks whether the path is valid for Message Descriptor."""98  parts = path.split('.')99  last = parts.pop()100  for name in parts:101    field = message_descriptor.fields_by_name.get(name)102    if (field is None or103        field.is_repeated or104        field.type != FieldDescriptor.TYPE_MESSAGE):105      return False106    message_descriptor = field.message_type107  return last in message_descriptor.fields_by_name108 109 110def _CheckFieldMaskMessage(message):111  """Raises ValueError if message is not a FieldMask."""112  message_descriptor = message.DESCRIPTOR113  if (message_descriptor.name != 'FieldMask' or114      message_descriptor.file.name != 'google/protobuf/field_mask.proto'):115    raise ValueError('Message {0} is not a FieldMask.'.format(116        message_descriptor.full_name))117 118 119def _SnakeCaseToCamelCase(path_name):120  """Converts a path name from snake_case to camelCase."""121  result = []122  after_underscore = False123  for c in path_name:124    if c.isupper():125      raise ValueError(126          'Fail to print FieldMask to Json string: Path name '127          '{0} must not contain uppercase letters.'.format(path_name))128    if after_underscore:129      if c.islower():130        result.append(c.upper())131        after_underscore = False132      else:133        raise ValueError(134            'Fail to print FieldMask to Json string: The '135            'character after a "_" must be a lowercase letter '136            'in path name {0}.'.format(path_name))137    elif c == '_':138      after_underscore = True139    else:140      result += c141 142  if after_underscore:143    raise ValueError('Fail to print FieldMask to Json string: Trailing "_" '144                     'in path name {0}.'.format(path_name))145  return ''.join(result)146 147 148def _CamelCaseToSnakeCase(path_name):149  """Converts a field name from camelCase to snake_case."""150  result = []151  for c in path_name:152    if c == '_':153      raise ValueError('Fail to parse FieldMask: Path name '154                       '{0} must not contain "_"s.'.format(path_name))155    if c.isupper():156      result += '_'157      result += c.lower()158    else:159      result += c160  return ''.join(result)161 162 163class _FieldMaskTree(object):164  """Represents a FieldMask in a tree structure.165 166  For example, given a FieldMask "foo.bar,foo.baz,bar.baz",167  the FieldMaskTree will be:168      [_root] -+- foo -+- bar169            |       |170            |       +- baz171            |172            +- bar --- baz173  In the tree, each leaf node represents a field path.174  """175 176  __slots__ = ('_root',)177 178  def __init__(self, field_mask=None):179    """Initializes the tree by FieldMask."""180    self._root = {}181    if field_mask:182      self.MergeFromFieldMask(field_mask)183 184  def MergeFromFieldMask(self, field_mask):185    """Merges a FieldMask to the tree."""186    for path in field_mask.paths:187      self.AddPath(path)188 189  def AddPath(self, path):190    """Adds a field path into the tree.191 192    If the field path to add is a sub-path of an existing field path193    in the tree (i.e., a leaf node), it means the tree already matches194    the given path so nothing will be added to the tree. If the path195    matches an existing non-leaf node in the tree, that non-leaf node196    will be turned into a leaf node with all its children removed because197    the path matches all the node's children. Otherwise, a new path will198    be added.199 200    Args:201      path: The field path to add.202    """203    node = self._root204    for name in path.split('.'):205      if name not in node:206        node[name] = {}207      elif not node[name]:208        # Pre-existing empty node implies we already have this entire tree.209        return210      node = node[name]211    # Remove any sub-trees we might have had.212    node.clear()213 214  def ToFieldMask(self, field_mask):215    """Converts the tree to a FieldMask."""216    field_mask.Clear()217    _AddFieldPaths(self._root, '', field_mask)218 219  def IntersectPath(self, path, intersection):220    """Calculates the intersection part of a field path with this tree.221 222    Args:223      path: The field path to calculates.224      intersection: The out tree to record the intersection part.225    """226    node = self._root227    for name in path.split('.'):228      if name not in node:229        return230      elif not node[name]:231        intersection.AddPath(path)232        return233      node = node[name]234    intersection.AddLeafNodes(path, node)235 236  def AddLeafNodes(self, prefix, node):237    """Adds leaf nodes begin with prefix to this tree."""238    if not node:239      self.AddPath(prefix)240    for name in node:241      child_path = prefix + '.' + name242      self.AddLeafNodes(child_path, node[name])243 244  def MergeMessage(245      self, source, destination,246      replace_message, replace_repeated):247    """Merge all fields specified by this tree from source to destination."""248    _MergeMessage(249        self._root, source, destination, replace_message, replace_repeated)250 251 252def _StrConvert(value):253  """Converts value to str if it is not."""254  # This file is imported by c extension and some methods like ClearField255  # requires string for the field name. py2/py3 has different text256  # type and may use unicode.257  if not isinstance(value, str):258    return value.encode('utf-8')259  return value260 261 262def _MergeMessage(263    node, source, destination, replace_message, replace_repeated):264  """Merge all fields specified by a sub-tree from source to destination."""265  source_descriptor = source.DESCRIPTOR266  for name in node:267    child = node[name]268    field = source_descriptor.fields_by_name[name]269    if field is None:270      raise ValueError('Error: Can\'t find field {0} in message {1}.'.format(271          name, source_descriptor.full_name))272    if child:273      # Sub-paths are only allowed for singular message fields.274      if (field.is_repeated or275          field.cpp_type != FieldDescriptor.CPPTYPE_MESSAGE):276        raise ValueError('Error: Field {0} in message {1} is not a singular '277                         'message field and cannot have sub-fields.'.format(278                             name, source_descriptor.full_name))279      if source.HasField(name):280        _MergeMessage(281            child, getattr(source, name), getattr(destination, name),282            replace_message, replace_repeated)283      continue284    if field.is_repeated:285      if replace_repeated:286        destination.ClearField(_StrConvert(name))287      repeated_source = getattr(source, name)288      repeated_destination = getattr(destination, name)289      repeated_destination.MergeFrom(repeated_source)290    else:291      if field.cpp_type == FieldDescriptor.CPPTYPE_MESSAGE:292        if replace_message:293          destination.ClearField(_StrConvert(name))294        if source.HasField(name):295          getattr(destination, name).MergeFrom(getattr(source, name))296      elif not field.has_presence or source.HasField(name):297        setattr(destination, name, getattr(source, name))298      else:299        destination.ClearField(_StrConvert(name))300 301 302def _AddFieldPaths(node, prefix, field_mask):303  """Adds the field paths descended from node to field_mask."""304  if not node and prefix:305    field_mask.paths.append(prefix)306    return307  for name in sorted(node):308    if prefix:309      child_path = prefix + '.' + name310    else:311      child_path = name312    _AddFieldPaths(node[name], child_path, field_mask)313 
codekingpro/portable-devtools · Team Ai