def __deepcopy__(self, memo): # This avoids recursive ProjectionSpec transforms that deepcopy chokes on. return copy.copy(self)
def _AddKey(self, key, attribute_add): """Propagates default attribute values and adds key to the projection. Args: key: The parsed key to add. attribute_add: Parsed _Attribute to add. """ projection = self._root # Add or update the inner nodes. for name in key[:-1]: tree = projection.tree if name in tree: attribute = tree[name].attribute if attribute.flag != self._projection.PROJECT: attribute.flag = self._projection.INNER else: tree[name] = self._Tree(self._Attribute(self._projection.INNER)) projection = tree[name] # Add or update the terminal node. tree = projection.tree # self.key == [] => . or a function on the entire object. name = key[-1] if key else '' name_in_tree = name in tree if name_in_tree: # Already added. if (not self.__key_attributes_only and any([col for col in self._projection.Columns() if col.key == key])): # A duplicate column. A projection can only have one attribute object # per key. The first <key, attribute> pair added to the current set of # columns remains in the projection. Projection columns may have # duplicate keys (e.g., table columns with the same key but different # transforms). The attribute copy, with attribute_add merged in, is # added to the projection columns but not the projection tree. attribute = copy.copy(tree[name].attribute) else: attribute = tree[name].attribute attribute.hidden = False elif isinstance(name, (int, long)) and None in tree: # New projection for explicit name using slice defaults. tree[name] = copy.deepcopy(tree[None]) attribute = tree[name].attribute else: # New projection. attribute = attribute_add if self.__key_attributes_only and attribute.order: attribute.hidden = True if key or attribute.transform: tree[name] = self._Tree(attribute) # Propagate non-default values from attribute_add to attribute. if attribute_add.order is not None: attribute.order = attribute_add.order if attribute_add.label is not None: attribute.label = attribute_add.label elif attribute.label is None: attribute.label = self._AngrySnakeCase(key) if attribute_add.align != resource_projection_spec.ALIGN_DEFAULT: attribute.align = attribute_add.align if attribute_add.optional is not None: attribute.optional = attribute_add.optional elif attribute.optional is None: attribute.optional = False if attribute_add.reverse is not None: attribute.reverse = attribute_add.reverse elif attribute.reverse is None: attribute.reverse = False if attribute_add.transform: attribute.transform = attribute_add.transform if attribute_add.subformat: attribute.subformat = attribute_add.subformat self._projection.AddAlias(attribute.label, key) if not self.__key_attributes_only or attribute.hidden: # This key is in the projection. attribute.flag = self._projection.PROJECT self._projection.AddKey(key, attribute) elif not name_in_tree: # This is a new attributes only key. attribute.flag = self._projection.DEFAULT
def _AddKey(self, key, attribute_add): """Propagates default attribute values and adds key to the projection. Args: key: The parsed key to add. attribute_add: Parsed _Attribute to add. """ projection = self._root # Add or update the inner nodes. for name in key[:-1]: tree = projection.tree if name in tree: attribute = tree[name].attribute if attribute.flag != self._projection.PROJECT: attribute.flag = self._projection.INNER else: tree[name] = self._Tree(self._Attribute( self._projection.INNER)) projection = tree[name] # Add or update the terminal node. tree = projection.tree # self.key == [] => . or a function on the entire object. name = key[-1] if key else '' name_in_tree = name in tree if name_in_tree: # Already added. if (not self.__key_attributes_only and any( [col for col in self._projection.Columns() if col.key == key])): # A duplicate column. A projection can only have one attribute object # per key. The first <key, attribute> pair added to the current set of # columns remains in the projection. Projection columns may have # duplicate keys (e.g., table columns with the same key but different # transforms). The attribute copy, with attribute_add merged in, is # added to the projection columns but not the projection tree. attribute = copy.copy(tree[name].attribute) else: attribute = tree[name].attribute attribute.hidden = False elif isinstance(name, (int, long)) and None in tree: # New projection for explicit name using slice defaults. tree[name] = copy.deepcopy(tree[None]) attribute = tree[name].attribute else: # New projection. attribute = attribute_add if self.__key_attributes_only and attribute.order: attribute.hidden = True if key or attribute.transform: tree[name] = self._Tree(attribute) # Propagate non-default values from attribute_add to attribute. if attribute_add.order is not None: attribute.order = attribute_add.order if attribute_add.label is not None: attribute.label = attribute_add.label elif attribute.label is None: attribute.label = self._AngrySnakeCase(key) if attribute_add.align != resource_projection_spec.ALIGN_DEFAULT: attribute.align = attribute_add.align if attribute_add.optional is not None: attribute.optional = attribute_add.optional elif attribute.optional is None: attribute.optional = False if attribute_add.reverse is not None: attribute.reverse = attribute_add.reverse elif attribute.reverse is None: attribute.reverse = False if attribute_add.transform: attribute.transform = attribute_add.transform if attribute_add.subformat: attribute.subformat = attribute_add.subformat self._projection.AddAlias(attribute.label, key) if not self.__key_attributes_only or attribute.hidden: # This key is in the projection. attribute.flag = self._projection.PROJECT self._projection.AddKey(key, attribute) elif not name_in_tree: # This is a new attributes only key. attribute.flag = self._projection.DEFAULT