def placeholder_to_cel()

in tfx/orchestration/kubeflow/v2/compiler_utils.py [0:0]


def placeholder_to_cel(
    expression: placeholder_pb2.PlaceholderExpression) -> str:
  """Encodes a Predicate into a CEL string expression.

  The CEL specification is at:
  https://github.com/google/cel-spec/blob/master/doc/langdef.md

  Args:
    expression: A PlaceholderExpression proto descrbing a Predicate.

  Returns:
    A CEL expression in string format.
  """
  if expression.HasField('value'):
    value_field_name = expression.value.WhichOneof('value')
    if value_field_name == 'int_value':
      # In KFP IR, all values are defined as google.protobuf.Value,
      # which does not differentiate between int and float. CEL's treats
      # comparison between different types as an error. Hence we need to convert
      # ints to floats for comparison in CEL.
      return f'{float(expression.value.int_value)}'
    if value_field_name == 'double_value':
      return f'{expression.value.double_value}'
    if value_field_name == 'string_value':
      return f'\'{expression.value.string_value}\''
    raise NotImplementedError(
        'Only supports predicate with primitive type values.')

  if expression.HasField('placeholder'):
    placeholder_pb = expression.placeholder
    # Predicates are always built from ChannelWrappedPlaceholder, which means
    # a component can only write a predicate about its inputs. It doesn't make
    # sense for a component to say "run only if my output is something."
    if placeholder_pb.type != placeholder_pb2.Placeholder.INPUT_ARTIFACT:
      raise NotImplementedError(
          'Only supports accessing input artifact through placeholders on KFPv2.'
          f'Got {placeholder_pb.type}.')
    if not placeholder_pb.key:
      raise ValueError(
          'Only supports accessing placeholders with a key on KFPv2.')
    # Note that because CEL automatically performs dynamic value conversion,
    # we don't need type info for the oneof fields in google.protobuf.Value.
    return f"inputs.artifacts['{placeholder_pb.key}'].artifacts"

  if expression.HasField('operator'):
    operator_name = expression.operator.WhichOneof('operator_type')
    operator_pb = getattr(expression.operator, operator_name)

    if operator_name == 'index_op':
      sub_expression_str = placeholder_to_cel(operator_pb.expression)
      return f'{sub_expression_str}[{operator_pb.index}]'

    if operator_name == 'artifact_property_op':
      sub_expression_str = placeholder_to_cel(operator_pb.expression)
      # CEL's dynamic value conversion applies to here as well.
      return f"{sub_expression_str}.metadata['{operator_pb.key}']"

    if operator_name == 'artifact_uri_op':
      sub_expression_str = placeholder_to_cel(operator_pb.expression)
      if operator_pb.split:
        raise NotImplementedError(
            'Accessing artifact\'s split uri is unsupported.')
      return f'{sub_expression_str}.uri'

    if operator_name == 'concat_op':
      expression_str = ' + '.join(
          placeholder_to_cel(e) for e in operator_pb.expressions)
      return f'({expression_str})'

    if operator_name == 'compare_op':
      lhs_str = placeholder_to_cel(operator_pb.lhs)
      rhs_str = placeholder_to_cel(operator_pb.rhs)
      if operator_pb.op == placeholder_pb2.ComparisonOperator.Operation.EQUAL:
        op_str = '=='
      elif operator_pb.op == placeholder_pb2.ComparisonOperator.Operation.LESS_THAN:
        op_str = '<'
      elif operator_pb.op == placeholder_pb2.ComparisonOperator.Operation.GREATER_THAN:
        op_str = '>'
      else:
        return f'Unknown Comparison Operation {operator_pb.op}'
      return f'({lhs_str} {op_str} {rhs_str})'

    if operator_name == 'unary_logical_op':
      expression_str = placeholder_to_cel(operator_pb.expression)
      if operator_pb.op == placeholder_pb2.UnaryLogicalOperator.Operation.NOT:
        op_str = '!'
      else:
        return f'Unknown Unary Logical Operation {operator_pb.op}'
      return f'{op_str}({expression_str})'

    if operator_name == 'binary_logical_op':
      lhs_str = placeholder_to_cel(operator_pb.lhs)
      rhs_str = placeholder_to_cel(operator_pb.rhs)
      if operator_pb.op == placeholder_pb2.BinaryLogicalOperator.Operation.AND:
        op_str = '&&'
      elif operator_pb.op == placeholder_pb2.BinaryLogicalOperator.Operation.OR:
        op_str = '||'
      else:
        return f'Unknown Binary Logical Operation {operator_pb.op}'
      return f'({lhs_str} {op_str} {rhs_str})'

    raise ValueError(f'Got unsupported placeholder operator {operator_name}.')

  raise ValueError('Unknown placeholder expression.')