def Transform(self, func_name, active=0): """Parses one or more transform calls and returns a _Transform call object. The initial '(' has already been consumed by the caller. Args: func_name: The name of the first transform function. active: The transform active level, None for always active. Returns: The _Transform object containing the ordered list of transform calls. """ here = self.GetPosition() calls = _Transform() map_transform = 0 while True: transform = self._ParseTransform(func_name, active=active, map_transform=map_transform) if transform.func == resource_transform.TransformAlways: active = None # Always active. func_name = None elif transform.func == resource_transform.TransformMap: map_transform = int(transform.args[0]) if transform.args else 1 func_name = None elif transform.func == resource_transform.TransformIf: if len(transform.args) != 1: raise resource_exceptions.ExpressionSyntaxError( 'Conditional filter expression expected [{0}].'.format( self.Annotate(here))) calls.SetConditional(transform.args[0]) elif transform.func == resource_transform.TransformSynthesize: transform.func = self._ParseSynthesize(transform.args) transform.args = [] transform.kwargs = {} calls.Add(transform) else: # always() applies to all transforms for key. # map() applies to the next transform. map_transform = 0 calls.Add(transform) if not self.IsCharacter('.', eoi_ok=True): break call = self.Key() here = self.GetPosition() if not self.IsCharacter('('): raise resource_exceptions.ExpressionSyntaxError( 'Transform function expected [{0}].'.format( self.Annotate(here))) if len(call) != 1: raise resource_exceptions.UnknownTransformError( 'Unknown transform function {0} [{1}].'.format( '.'.join(call), self.Annotate(here))) func_name = call.pop() return calls
def _ParseTransform(self, func_name, active=0, map_transform=None): """Parses a transform function call. The initial '(' has already been consumed by the caller. Args: func_name: The transform function name. active: The transform active level or None if always active. map_transform: Apply the transform to each resource list item this many times. Returns: A _TransformCall object. The caller appends these to a list that is used to apply the transform functions. Raises: ExpressionSyntaxError: The expression has a syntax error. """ here = self.GetPosition() func = self._defaults.symbols.get(func_name) if not func: raise resource_exceptions.UnknownTransformError( 'Unknown transform function {0} [{1}].'.format( func_name, self.Annotate(here))) args = [] kwargs = {} doc = getattr(func, '__doc__', None) if doc and resource_projection_spec.PROJECTION_ARG_DOC in doc: # The second transform arg is the caller projection. args.append(self._defaults) if getattr(func, '__defaults__', None): # Separate the args from the kwargs. for arg in self.Args(): name, sep, val = arg.partition('=') if sep: kwargs[name] = val else: args.append(arg) else: # No kwargs. args += self.Args() return _TransformCall(func_name, func, active=active, map_transform=map_transform, args=args, kwargs=kwargs)