예제 #1
0
  def Print(self, resources, single=False, intermediate=False):
    """Prints resources using printer.AddRecord() and printer.Finish().

    Args:
      resources: A singleton or list of JSON-serializable Python objects.
      single: If True then resources is a single item and not a list.
        For example, use this to print a single object as JSON.
      intermediate: This is an intermediate call, do not call Finish().

    Raises:
      ProjectionRequiredError: If the projection is empty and the format
        requires a non-empty projection.
    """
    if 'disable' in self.attributes:
      # Disable formatted output and do not consume the resources.
      self._empty = False
      return
    if self._non_empty_projection_required and (
        not self.column_attributes or not self.column_attributes.Columns()):
      raise ProjectionRequiredError(
          'Format [{0}] requires a non-empty projection.'.format(self._name))
    # Resources may be a generator and since generators can raise exceptions, we
    # have to call Finish() in the finally block to make sure that the resources
    # we've been able to pull out of the generator are printed before control is
    # given to the exception-handling code.
    try:
      if resources:
        if single or not resource_property.IsListLike(resources):
          self.AddRecord(resources, delimit=intermediate)
        else:
          for resource in resources:
            self.AddRecord(resource)
    finally:
      if not intermediate:
        self.Finish()
예제 #2
0
def TransformFilter(r, expression):
  """Selects elements of r that match the filter expression.

  Args:
    r: A JSON-serializable object.
    expression: The filter expression to apply to r.

  Returns:
    The elements of r that match the filter expression.

  Example:
    x.filter("key:val") selects elements of r that have 'key' fields containing
    'val'.
  """

  # import loop
  from googlecloudsdk.core.resource import resource_filter  # pylint: disable=g-import-not-at-top

  if not r:
    return r
  select = resource_filter.Compile(expression).Evaluate
  if not resource_property.IsListLike(r):
    return r if select(r) else ''
  transformed = []
  for item in r:
    if select(item):
      transformed.append(item)
  return transformed
예제 #3
0
 def Run(self, args):
     if args.json_file:
         with open(args.json_file, 'r') as f:
             resources = json.load(f)
     else:
         resources = json.load(sys.stdin)
     # TODO(gsfowler): Drop this if when the --aggregate global flag lands.
     if args.aggregate:
         key = resource_lex.Lexer(args.aggregate).Key()
         resources = Aggregator(resources, key)
     # TODO(gsfowler): Return resources here when the --filter global flag lands.
     if not args.format:
         args.format = 'json'
     if not args.filter:
         return resources
     select = resource_filter.Compile(args.filter).Evaluate
     filtered_resources = []
     if resource_property.IsListLike(resources):
         for resource in resources:
             if select(resource):
                 filtered_resources.append(resource)
     elif select(resources):
         # treat non-iterable resources as a list of length 1
         filtered_resources.append(resources)
     return filtered_resources
예제 #4
0
    def _AddSortByTap(self):
        """Sorts the resources using the --sort-by keys."""
        if not resource_property.IsListLike(self._resources):
            return
        sort_keys = self._GetSortKeys()
        if not sort_keys:
            return
        self._args.sort_by = None
        # This loop partitions the keys into groups having the same reverse value.
        # The groups are then applied in reverse order to maintain the original
        # precedence.
        #
        # This is not a pure tap since, by necessity, it consumes self._resources
        # to sort and converts it to a list.
        groups = [
        ]  # [(group_keys, group_reverse)] LIFO to preserve precedence
        group_keys = []  # keys for current group
        group_reverse = False
        for key, reverse in sort_keys:
            if not group_keys:
                group_reverse = reverse
            elif group_reverse != reverse:
                groups.insert(0, (group_keys, group_reverse))
                group_keys = []
                group_reverse = reverse
            group_keys.append(key)
        if group_keys:
            groups.insert(0, (group_keys, group_reverse))

        # Finally sort the resources by groups having the same reverse value.
        for keys, reverse in groups:
            self._SortResources(keys, reverse)
 def Evaluate(self, obj):
     """Apply the list of transforms to obj and return the transformed value."""
     for transform in self._transforms:
         if transform.map_transform and resource_property.IsListLike(obj):
             # A transform mapped on a list - transform each list item.
             # map_transform > 1 for nested lists. For example:
             #   abc[].def[].ghi[].map(3)
             # iterates over the items in ghi[] for all abc[] and def[].
             items = obj
             for _ in range(transform.map_transform - 1):
                 nested = []
                 try:
                     # Stop if items is not a list.
                     for item in items:
                         nested.extend(item)
                 except TypeError:
                     break
                 items = nested
             obj = []
             for item in items:
                 obj.append(
                     transform.func(item, *transform.args,
                                    **transform.kwargs))
         elif obj or not transform.map_transform:
             obj = transform.func(obj, *transform.args, **transform.kwargs)
     return obj
예제 #6
0
    def _ProjectTransform(self, obj, transforms):
        """Applies transforms to obj.

    Args:
      obj: The object to transform.
      transforms: The list of resource_projection_parser._Transform objects.

    Returns:
      The transformed object.
    """
        if not self._transforms_enabled:
            if self._transforms_enabled is not None:
                return obj
            if transforms[0].active not in (None, self._projection.active):
                return obj
        for transform in transforms:
            if transform.map_transform and resource_property.IsListLike(obj):
                # A transform mapped on a list - transform each list item.
                items = obj
                obj = []
                for item in items:
                    obj.append(
                        transform.func(item, *transform.args,
                                       **transform.kwargs))
            elif obj or not transform.map_transform:
                obj = transform.func(obj, *transform.args, **transform.kwargs)
        return obj
예제 #7
0
def Print(resources, print_format, out=None, defaults=None, single=False):
    """Prints the given resources.

  Args:
    resources: A singleton or list of JSON-serializable Python objects.
    print_format: The _FORMATTER name with optional projection expression.
    out: Output stream, log.out if None.
    defaults: Optional resource_projection_spec.ProjectionSpec defaults.
    single: If True then resources is a single item and not a list.
      For example, use this to print a single object as JSON.

  Raises:
    ProjectionRequiredError: If a format requires a projection and one is not
      provided.
  """
    printer = Printer(print_format, out=out, defaults=defaults)
    if printer.ByColumns() and not printer.column_attributes.Columns():
        raise ProjectionRequiredError(
            'Format [{0}] requires a non-empty projection.'.format(
                printer.column_attributes.Name()))

    # Resources may be a generator and since generators can raise exceptions, we
    # have to call Finish() in the finally block to make sure that the resources
    # we've been able to pull out of the generator are printed before control is
    # given to the exception-handling code.
    try:
        if resources:
            if single or not resource_property.IsListLike(resources):
                printer.AddRecord(resources, delimit=False)
            else:
                for resource in resources:
                    printer.AddRecord(resource)
    finally:
        printer.Finish()
예제 #8
0
    def Display(self):
        """The default display method."""

        if not log.IsUserOutputEnabled():
            log.info('Display disabled.')
            # NOTICE: Do not consume resources here. Some commands use this case to
            # access the results of Run() via the return value of Execute(). However,
            # to satisfy callers who are only interetsted in silent side effects,
            # generators/iterators must be converted to a list here.
            if resource_property.IsListLike(self._resources):
                return list(self._resources)
            return self._resources

        # Initialize the printer.
        self._InitPrinter()

        # Add a URI cache update tap if needed.
        self._AddUriCacheTap()

        # Add a resource page tap if needed.
        self._AddPageTap()

        # Add a resource flatten tap if needed.
        self._AddFlattenTap()

        # Add a sort tap if needed.
        self._AddSortByTap()

        # Add a resource filter tap if needed.
        self._AddFilterTap()

        # Add a resource limit tap if needed.
        self._AddLimitTap()

        # Add the URI replace tap if needed.
        self._AddUriReplaceTap()

        resources_were_displayed = True
        if self._printer:
            # Most command output will end up here.
            log.info('Display format: "%s"', self._format)
            self._printer.Print(self._resources)
            resources_were_displayed = self._printer.ResourcesWerePrinted()
        elif hasattr(self._command, 'Display'):
            # This will eventually be rare.
            log.info('Explicit Display.')
            self._command.Display(self._args, self._resources)

        # Resource display is done.
        log.out.flush()

        # If the default format was used then display the epilog.
        if not self._args.IsSpecified('format'):
            self._command.Epilog(resources_were_displayed)

        return self._resources
예제 #9
0
 def Evaluate(self, obj):
   """Apply the list of transforms to obj and return the transformed value."""
   for transform in self._transforms:
     if transform.map_transform and resource_property.IsListLike(obj):
       # A transform mapped on a list - transform each list item.
       items = obj
       obj = []
       for item in items:
         obj.append(transform.func(item, *transform.args, **transform.kwargs))
     elif obj or not transform.map_transform:
       if transform.restriction:
         obj = transform.func(*transform.args, **transform.kwargs)
       else:
         obj = transform.func(obj, *transform.args, **transform.kwargs)
   return obj
예제 #10
0
def _PrintResources(resources, printer, single=False):
    """Prints resources using printer.AddRecord() and printer.Finish().

  Args:
    resources: A singleton or list of JSON-serializable Python objects.
    printer: An instantiated printer.
    single: If True then resources is a single item and not a list.
      For example, use this to print a single object as JSON.
  """
    # Resources may be a generator and since generators can raise exceptions, we
    # have to call Finish() in the finally block to make sure that the resources
    # we've been able to pull out of the generator are printed before control is
    # given to the exception-handling code.
    try:
        if resources:
            if single or not resource_property.IsListLike(resources):
                printer.AddRecord(resources, delimit=False)
            else:
                for resource in resources:
                    printer.AddRecord(resource)
    finally:
        printer.Finish()