def _IsFieldPathPrimitiveLike(fieldpath, protobuf): """Whether fieldpath is an actual primitive, or honorary primitive. We allow this latter, for our doc writers, so they don't have to fiddle + maybe get wrong, adding :value to the end of so much. Args: fieldpath: path to field. protobuf: protobuf in which to find field. Returns: whether the field at fieldpath is a primitive (true leaf) or, an honorary primitive. """ toks = path_utils.SplitAbstract(path_utils.AsAbstract(fieldpath)) fname, rest = path_utils.FirstRest(toks) fd = protobuf.DESCRIPTOR.fields_by_name.get(fname, None) if fd is None: return False while bool(rest) and fd.type == fd.TYPE_MESSAGE: fname, rest = path_utils.FirstRest(rest) fd = fd.message_type.fields_by_name.get(fname, None) if fd is None: # path contains something not in the protobuf return False # Ended of path return (not rest) and ( # .. is primitive fd.type != fd.TYPE_MESSAGE or # .. or honorary primitive path_converters.IsHonoraryPrimitive(fd.message_type.name))
def FieldpathNature(fieldpath, protobuf=None): """Returns information about the nature of a given field. Args: fieldpath: path of the field of interest protobuf: container of the field. Returns: tuple of: (whether <fieldpath> is contained in the protobuf, is true-or-honorary primitive, is strictly honorary primitive) """ if protobuf is None: protobuf = StructuralDbroot() toks = path_utils.SplitAbstract(path_utils.AsAbstract(fieldpath)) fname, rest = path_utils.FirstRest(toks) fd = protobuf.DESCRIPTOR.fields_by_name.get(fname, None) if fd is None: return (False, None, None) while bool(rest) and fd.type == fd.TYPE_MESSAGE: fname, rest = path_utils.FirstRest(rest) fd = fd.message_type.fields_by_name.get(fname, None) if fd is None: # path contains something not in the protobuf return (False, None, None) # 'poked through the bottom' of the protobuf if rest: return (False, None, None) is_true_primitive = fd.type != fd.TYPE_MESSAGE is_primitive_like = is_true_primitive or ( path_converters.IsHonoraryPrimitive(fd.message_type.name)) return (True, is_primitive_like, not is_true_primitive)
def _IsFieldPathPrimitive(fieldpath, protobuf): """Whether the fieldpath is a (true) leaf in protobuf. whether protobuf structurally contains the path and, that it ends at a primitive (ie rejects subtree paths). Args: fieldpath: path of the field within the protobuf protobuf: container of the protobuf Returns: whether the fieldpath ends at a true leaf ie, value field. """ toks = path_utils.SplitAbstract(path_utils.AsAbstract(fieldpath)) fname, rest = path_utils.FirstRest(toks) fd = protobuf.DESCRIPTOR.fields_by_name.get(fname, None) if fd is None: return False while bool(rest) and fd.type == fd.TYPE_MESSAGE: fname, rest = path_utils.FirstRest(rest) fd = fd.message_type.fields_by_name.get(fname, None) if fd is None: # path contains something not in the protobuf return False # Both ended on a primitive. return (not rest) and (fd.type != fd.TYPE_MESSAGE)
def _GeneralSetAbstract(parts, value, store, log): """Set a value in store, where the top level of store is not repeated. It complements _SetAbstractThroughRepeated. Args: parts: already-broken-up path, of where to put the value. value: value to write into the store. store: the multi-level dict to write into. log: logger object """ assert isinstance(store, dict) key, rest = path_utils.FirstRest(parts) # not concrete assert not key.isdigit() if not rest: store[key] = value else: substore = store.get(key, {}) if not substore: store[key] = substore if isinstance(substore, dict): if substore and substore.keys()[0].isdigit(): # Handle repeated elements. _SetAbstractThroughRepeated(rest, value, substore, log) else: # Get the next element from path to check if it is index of repeated # element. next_key, unused_rest = path_utils.FirstRest(rest) if next_key and next_key == "[]": # Handle repeated elements. It is the case when there is no items of # repeated element, and first field is coming to set. _SetAbstractThroughRepeated(rest, value, substore, log) else: # Handle generic elements. _GeneralSetAbstract(rest, value, substore, log) else: # It breaks an invariant of the protobuf => sparse tree, to replace # a primitive value with a subtree. Eg, trying to write # 'a.b' = 2 to {'a': 1}. 'b' cannot be a sibling of 2. That would be # the error we're trying to do here. log.error( "Programmer or data error; cannot write a subtree (%s) over" " a primitive value (%s); that\'s an invariant of protobufs =>" " sparse trees. Value ignored, but no further damage done. " "%s" % (str(key), str(store), repr(traceback.extract_stack())))
def EmptyConcretizeFieldPath(fieldpath, protobuf=None): """Adds empty concreteness markings to an abstract fieldpath. Takes an abstract path (no indices or '[]') and puts '[]' markers at repeated parts, newstyle (ie a.b.[]). We do this for reading from the template, masking file. Args: fieldpath: path of the field within the protobuf protobuf: container of the protobuf Returns: fieldpath, with empty concrete markings. """ assert path_utils.IsAbstract(fieldpath) if protobuf is None: protobuf = StructuralDbroot() toks = path_utils.SplitAbstract(fieldpath) empty_concrete_toks = [] def AddElement(fname, fd): empty_concrete_toks.append(fname) if fd.label == fd.LABEL_REPEATED: empty_concrete_toks.append("[]") def GetNext(toks, fd): fname, rest = path_utils.FirstRest(toks) fd = fd.message_type.fields_by_name.get(fname, None) if fd is None: assert False, "bad path: %s, at: %s" % (fieldpath, fname) return fname, rest, fd fname, rest = path_utils.FirstRest(toks) fd = protobuf.DESCRIPTOR.fields_by_name.get(fname, None) if fd is None: assert False, "bad path: %s, at: %s" % (fieldpath, fname) AddElement(fname, fd) while bool(rest) and fd.type == fd.TYPE_MESSAGE: fname, rest, fd = GetNext(rest, fd) AddElement(fname, fd) assert (not rest) and (fd.type != fd.TYPE_MESSAGE), ( "path %s incomplete or something" % fieldpath) return ".".join(empty_concrete_toks)
def GetNext(toks, fd): fname, rest = path_utils.FirstRest(toks) fd = fd.message_type.fields_by_name.get(fname, None) if fd is None: assert False, "bad path: %s, at: %s" % (fieldpath, fname) return fname, rest, fd