def count_aggs(self, module: abc.Mapping, obj_count: int = 0, grp_count: int = 0) -> tuple((int, int)): """Returns the count of OBJECT and GROUP aggregations that are contained within the *module* as a two-tuple in that order. """ # This currently just counts the values in the passed # in module, it does not 'recurse' if those aggregations also # may contain aggregations. for k, v in module.items(): if isinstance(v, abc.Mapping): if isinstance(v, self.grpcls): grp_count += 1 elif isinstance(v, self.objcls): obj_count += 1 else: # We treat other dict-like Python objects as # PVL Objects for the purposes of this count, # because that is how they will be encoded. obj_count += 1 return obj_count, grp_count
def serialize_mapping(self, obj: abc.Mapping): """ Mappings are just copied into another mapping. While copying, all the values are recursively serialized. """ return {k: self.serialize(v) for k, v in obj.items()}
def is_PDSgroup(self, group: abc.Mapping) -> bool: """Returns true if the dict-like *group* qualifies as a PDS Group, false otherwise. PDS applies the following restrictions to GROUPS: 1. The GROUP structure may only be used in a data product label which also contains one or more data OBJECT definitions. 2. The GROUP statement must contain only attribute assignment statements, include pointers, or related information pointers (i.e., no data location pointers). If there are multiple values, a single statement must be used with either sequence or set syntax; no attribute assignment statement or pointer may be repeated. 3. GROUP statements may not be nested. 4. GROUP statements may not contain OBJECT definitions. 5. Only PSDD elements may appear within a GROUP statement. *PSDD is not defined anywhere in the PDS document, so don't know how to test for it.* 6. The keyword contents associated with a specific GROUP identifier must be identical across all labels of a single data set (with the exception of the “PARAMETERS” GROUP, as explained). Use of the GROUP structure must be coordinated with the responsible PDS discipline Node. Items 1 & 6 and the final sentence above, can't really be tested by examining a single group, but must be dealt with in a larger context. The ODLEncoder.encode_module() handles #1, at least. You're on your own for the other two issues. Item 5: *PSDD* is not defined anywhere in the ODL PDS document, so don't know how to test for it. """ (obj_count, grp_count) = self.count_aggs(group) # Items 3 and 4: if obj_count != 0 or grp_count != 0: return False # Item 2, no data location pointers: for k, v in group.items(): if k.startswith("^"): if isinstance(v, int): return False else: for quant in self.quantities: if isinstance(v, quant.cls) and isinstance( getattr(v, quant.value_prop), int): return False # Item 2, no repeated keys: keys = list(group.keys()) if len(keys) != len(set(keys)): return False return True
def __init__(self, data: abc.Mapping): super(ReadOnlyDict, self).__init__() self._data = dict() for k, v in data.items(): if isinstance(v, list): self._data.__setitem__(k, ReadOnlyList(v)) elif isinstance(v, dict): self._data.__setitem__(k, ReadOnlyDict(v)) else: self._data.__setitem__(k, v)
def encode_module(self, module: abc.Mapping, level: int = 0) -> str: """Returns a ``str`` formatted as a PVL module based on the dict-like *module* object according to the rules of this encoder, with an indentation level of *level*. """ lines = list() # To align things on the equals sign, just need to normalize # the non-aggregation key length: non_agg_key_lengths = list() for k, v in module.items(): if not isinstance(v, abc.Mapping): non_agg_key_lengths.append(len(k)) longest_key_len = max(non_agg_key_lengths, default=0) for k, v in module.items(): if isinstance(v, abc.Mapping): lines.append(self.encode_aggregation_block(k, v, level)) else: lines.append( self.encode_assignment(k, v, level, longest_key_len)) return self.newline.join(lines)