예제 #1
0
 def __deepcopy__(self, memo):
   # This avoids recursive ProjectionSpec transforms that deepcopy chokes on.
   return copy.copy(self)
예제 #2
0
  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