code: def _artifacts_not_kept_by_property_value_groups(
      artifacts: Sequence[metadata_store_pb2.Artifact],
      keep_property_value_groups: garbage_collection_policy_pb2.GarbageCollectionPolicy.KeepPropertyValueGroups,
  ) -> Sequence[metadata_store_pb2.Artifact]:
      """Returns artifacts that are not kept by KeepPropertyValueGroups."""
      artifact_groups = [artifacts]
      for grouping in keep_property_value_groups.groupings:
          next_artifact_groups = []
          all_property_value_type = type(None)
          for artifact_group in artifact_groups:
              artifacts_by_property_value = collections.defaultdict(
                  list
              )
              for artifact in artifact_group:
                  property_value = _get_property_value(
                      artifact, grouping.property_name
                  )
                  if property_value is not None:
                      if all_property_value_type != type(
                          None
                      ) and all_property_value_type != type(
                          property_value
                      ):
                          raise ValueError(
                              "Properties from the same group should have a homogenous type "
                              f"except NoneType. Expected {all_property_value_type}, but "
                              f"passed {type(property_value)}"
                          )
                      all_property_value_type = type(property_value)
                  artifacts_by_property_value[property_value].append(
                      artifact
                  )
  
              if grouping.keep_num <= 0:
                  next_artifact_groups.extend(
                      artifacts_by_property_value.values()
                  )
              else:
                  sorted_property_values = sorted(
                      x
                      for x in artifacts_by_property_value.keys()
                      if x is not None
                  )
                  if (
                      grouping.keep_order
                      == _KeepOrder.KEEP_ORDER_UNSPECIFIED
                      or grouping.keep_order
                      == _KeepOrder.KEEP_ORDER_LARGEST
                  ):
                      property_values_to_keep = sorted_property_values[
                          -grouping.keep_num :
                      ]
                  elif (
                      grouping.keep_order
                      == _KeepOrder.KEEP_ORDER_SMALLEST
                  ):
                      property_values_to_keep = sorted_property_values[
                          : grouping.keep_num
                      ]
                  else:
                      message = (
                          f"Unknown keep_order in grouping: {grouping}"
                      )
                      logging.error(message)
                      raise ValueError(message)
                  for property_value_to_keep in property_values_to_keep:
                      next_artifact_groups.append(
                          artifacts_by_property_value[
                              property_value_to_keep
                          ]
                      )
                  if (
                      None in artifacts_by_property_value
                      and len(property_values_to_keep)
                      < grouping.keep_num
                  ):
                      # TODO(b/251069580): Currently, it gives the lowest priority to retain
                      # for the None-property-value group. Should compare with the default
                      # value policy.
                      next_artifact_groups.append(
                          artifacts_by_property_value[None]
                      )
          artifact_groups = next_artifact_groups
      artifacts_ids_to_keep = []
      for artifact_group in artifact_groups:
          for artifact in artifact_group:
              artifacts_ids_to_keep.append(artifact.id)
      return [a for a in artifacts if a.id not in artifacts_ids_to_keep]
  
imports: import collections
  import itertools
  from typing import Mapping, Optional, Sequence
  from absl import logging
  from tfx import types
  from tfx.dsl.io import fileio
  from tfx.orchestration import data_types_utils
  from tfx.orchestration import metadata
  from tfx.orchestration import node_proto_view
  from tfx.orchestration.experimental.core import task
  from tfx.orchestration.portable.mlmd import event_lib
  from tfx.orchestration.portable.mlmd import execution_lib
  from tfx.orchestration.portable.mlmd import store_ext
  from tfx.proto.orchestration import garbage_collection_policy_pb2
  from tfx.orchestration.experimental.core import garbage_collection_extensions
  from ml_metadata.proto import metadata_store_pb2
label_desc: Use image node_id 7 for calling a global function with example usage: _artifacts_not_kept_by_property_value_groups(artifacts, keep_property_value_groups) and returns: unknown