class_docstr: Plan to create jobs after a processing step has finished.
  
  Args:
      job_info (JobInfo): The job info.
      processing_graph (ProcessingGraph): The processing graph.
class_docstr_tok: ["Plan","to","create","jobs","after","a","processing","step","has","finished",".","Args",":","job_info","(","JobInfo",")",":","The","job","info",".","processing_graph","(","ProcessingGraph",")",":","The","processing","graph","."]
code: def update(
      self,
      next_processing_step: ProcessingStep,
      config: Optional[str],
      split: Optional[str],
  ) -> None:
      # ignore unrelated jobs
      config_mask = (
          self.pending_jobs_df["config"].isnull()
          if config is None
          else self.pending_jobs_df["config"] == config
      )
      split_mask = (
          self.pending_jobs_df["split"].isnull()
          if split is None
          else self.pending_jobs_df["split"] == split
      )
  
      unrelated_jobs_mask = (
          self.pending_jobs_df["type"] == next_processing_step.job_type
      ) & (
          (self.pending_jobs_df["dataset"] != self.dataset)
          | (~config_mask)
          | (~split_mask)
      )
      self.pending_jobs_df = self.pending_jobs_df[~unrelated_jobs_mask]
  
      jobs_mask = (
          (
              self.pending_jobs_df["type"]
              == next_processing_step.job_type
          )
          & (self.pending_jobs_df["dataset"] == self.dataset)
          & (config_mask)
          & (split_mask)
      )
      ok_jobs_mask = jobs_mask & (
          self.pending_jobs_df["revision"] == self.revision
      )
      if ok_jobs_mask.any():
          # remove the first ok job for the list, and keep the others to delete them later
          self.pending_jobs_df.drop(ok_jobs_mask.idxmax(), inplace=True)
      else:
          # no pending job for the current processing step
          difficulty = next_processing_step.difficulty
          if (
              self.num_bytes is not None
              and self.num_bytes
              >= self.processing_graph.min_bytes_for_bonus_difficulty
          ):
              difficulty += (
                  next_processing_step.bonus_difficulty_if_dataset_is_big
              )
          # increase difficulty according to number of failed runs
          difficulty = min(
              DEFAULT_DIFFICULTY_MAX,
              difficulty
              + self.failed_runs * DIFFICULTY_BONUS_BY_FAILED_RUNS,
          )
          self.job_infos_to_create.append(
              {
                  "job_id": "not used",  # TODO: remove this field
                  "type": next_processing_step.job_type,
                  "params": {
                      "dataset": self.dataset,
                      "config": config,
                      "split": split,
                      "revision": self.revision,
                  },
                  "priority": self.priority,
                  "difficulty": difficulty,
              }
          )
  
imports: import logging
  from abc import ABC, abstractmethod
  from dataclasses import dataclass, field
  from http import HTTPStatus
  from typing import Optional, Union
  import pandas
  from libcommon.constants import CONFIG_INFO_KINDS, CONFIG_SPLIT_NAMES_KINDS, DATASET_CONFIG_NAMES_KINDS, DEFAULT_DIFFICULTY_MAX, DIFFICULTY_BONUS_BY_FAILED_RUNS
  from libcommon.processing_graph import ProcessingGraph, ProcessingStep, ProcessingStepDoesNotExist, processing_graph
  from libcommon.prometheus import StepProfiler
  from libcommon.queue import Queue
  from libcommon.simple_cache import CacheEntryDoesNotExistError, delete_dataset_responses, fetch_names, get_best_response, get_cache_entries_df, get_response_metadata, upsert_response_params
  from libcommon.state import ArtifactState, DatasetState, FirstStepsDatasetState
  from libcommon.storage_client import StorageClient
  from libcommon.utils import JobInfo, JobResult, Priority
label_desc: Use image node_id 2 for calling the AfterJobPlan obj's underlying member method code with example usage: obj.update(next_processing_step, config, split) without return types