code: def build(self) -> Optional[Artifact]:
      _logger.info("Attempting to build job artifact")
      if not os.path.exists(
          os.path.join(self._settings.files_dir, REQUIREMENTS_FNAME)
      ):
          wandb.termwarn(
              "No requirements.txt found, not creating job artifact. See https://docs.wandb.ai/guides/launch/create-job"
          )
          return None
      metadata = self._handle_metadata_file()
      if metadata is None:
          wandb.termwarn(
              f"Ensure read and write access to run files dir: {self._settings.files_dir}, control this via the WANDB_DIR env var. See https://docs.wandb.ai/guides/track/environment-variables"
          )
          return None
  
      runtime: Optional[str] = metadata.get("python")
      # can't build a job without a python version
      if runtime is None:
          wandb.termwarn(
              "No python version found in metadata, not creating job artifact. See https://docs.wandb.ai/guides/launch/create-job"
          )
          return None
  
      input_types = TypeRegistry.type_of(self._config).to_json()
      output_types = TypeRegistry.type_of(self._summary).to_json()
  
      name: Optional[str] = None
      source_info: Optional[JobSourceDict] = None
  
      if self._partial_source is not None:
          # construct source from downloaded partial job metadata
          name = self._partial_source["job_name"]
          source_info = self._partial_source["job_source_info"]
          # add input/output types now that we are actually running a run
          source_info.update(
              {"input_types": input_types, "output_types": output_types}
          )
          # set source_type to determine whether to add diff file to artifact
          source_type = source_info.get("source_type")
      else:
          # configure job from environment
          source_type = self._get_source_type(metadata)
          if not source_type:
              # if source_type is None, then we don't have enough information to build a job
              # if the user intended to create a job, warn.
              if (
                  self._settings.job_name
                  or self._settings.job_source
                  or self._source_type
              ):
                  wandb.termwarn(
                      "No source type found, not creating job artifact"
                  )
              return None
  
          program_relpath = self._get_program_relpath(
              source_type, metadata
          )
          if source_type != "image" and not program_relpath:
              wandb.termwarn(
                  "No program path found, not creating job artifact. See https://docs.wandb.ai/guides/launch/create-job"
              )
              return None
  
          source: Union[
              Optional[GitSourceDict],
              Optional[ArtifactSourceDict],
              Optional[ImageSourceDict],
          ] = None
  
          # make source dict
          if source_type == "repo":
              assert program_relpath
              source, name = self._build_repo_job_source(
                  program_relpath, metadata
              )
          elif source_type == "artifact":
              assert program_relpath
              source, name = self._build_artifact_job_source(
                  program_relpath, metadata
              )
          elif (
              source_type == "image"
              and self._has_image_job_ingredients(metadata)
          ):
              source, name = self._build_image_job_source(metadata)
          else:
              source = None
  
          if source is None:
              if source_type:
                  wandb.termwarn(
                      f"Source type is set to '{source_type}' but some required information is missing "
                      "from the environment. A job will not be created from this run. See "
                      "https://docs.wandb.ai/guides/launch/create-job"
                  )
              return None
  
          source_info = {
              "_version": "v0",
              "source_type": source_type,
              "source": source,
              "input_types": input_types,
              "output_types": output_types,
              "runtime": runtime,
          }
  
      assert source_info is not None
      assert name is not None
      if metadata.get("_partial"):
          assert (
              not self._partial_source
          ), "partial job has partial output"
          source_info.update({"_partial": metadata["_partial"]})
  
      artifact = JobArtifact(name)
  
      _logger.info("adding wandb-job metadata file")
      with artifact.new_file("wandb-job.json") as f:
          f.write(json.dumps(source_info, indent=4))
  
      artifact.add_file(
          os.path.join(self._settings.files_dir, REQUIREMENTS_FNAME),
          name=FROZEN_REQUIREMENTS_FNAME,
      )
  
      if source_type == "repo":
          # add diff
          if os.path.exists(
              os.path.join(self._settings.files_dir, DIFF_FNAME)
          ):
              artifact.add_file(
                  os.path.join(self._settings.files_dir, DIFF_FNAME),
                  name=DIFF_FNAME,
              )
  
      return artifact
  
imports: import json
  import logging
  import os
  import re
  import sys
  from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Union
  import wandb
  from wandb.sdk.artifacts.artifact import Artifact
  from wandb.sdk.data_types._dtypes import TypeRegistry
  from wandb.sdk.lib.filenames import DIFF_FNAME, METADATA_FNAME, REQUIREMENTS_FNAME
  from wandb.util import make_artifact_name_safe
  from .settings_static import SettingsStatic
label_desc: Use image node_id 14 for calling the JobBuilder obj's underlying member method code with example usage: obj.build() and returns: artifact, None, None, None, None, None, None