docs: def get_job_input_filenames(job_input_file):
      """Extract list of files, returns a set of directories to create, and
      a set of files, with sources and destinations. The paths created are
      relative to the input directory.
  
      Note: we go through file names inside arrays, and create a
      separate subdirectory for each. This avoids clobbering files when
      duplicate filenames appear in an array.
      """
      def get_input_hash():
          with open(job_input_file) as fh:
              job_input = json.load(fh)
              return job_input
      job_input = get_input_hash()
  
      files = collections.defaultdict(list)  # dictionary, with empty lists as default elements
      dirs = []  # directories to create under <idir>
  
      # Local function for adding a file to the list of files to be created
      # for example:
      #    iname == "seq1"
      #    subdir == "015"
      #    value == { "$dnanexus_link": {
      #       "project": "project-BKJfY1j0b06Z4y8PX8bQ094f",
      #       "id": "file-BKQGkgQ0b06xG5560GGQ001B"
      #    }
      # will create a record describing that the file should
      # be downloaded into seq1/015/<filename>
      def add_file(iname, subdir, value):
          if not dxpy.is_dxlink(value):
              return
          handler = dxpy.get_handler(value)
          if not isinstance(handler, dxpy.DXFile):
              return
          filename = make_unix_filename(handler.name)
          trg_dir = iname
          if subdir is not None:
              trg_dir = os.path.join(trg_dir, subdir)
          files[iname].append({'trg_fname': os.path.join(trg_dir, filename),
                               'handler': handler,
                               'src_file_id': handler.id})
          dirs.append(trg_dir)
  
      # An array of inputs, for a single key. A directory
      # will be created per array entry. For example, if the input key is
      # FOO, and the inputs are {A, B, C}.vcf then, the directory structure
      # will be:
      #   <idir>/FOO/00/A.vcf
      #   <idir>/FOO/01/B.vcf
      #   <idir>/FOO/02/C.vcf
      def add_file_array(input_name, links):
          num_files = len(links)
          if num_files == 0:
              return
          num_digits = len(str(num_files - 1))
          dirs.append(input_name)
          for i, link in enumerate(links):
              subdir = str(i).zfill(num_digits)
              add_file(input_name, subdir, link)
  
      for input_name, value in list(job_input.items()):
          if isinstance(value, list):
              # This is a file array
              add_file_array(input_name, value)
          else:
              add_file(input_name, None, value)
  
      ## create a dictionary of the all non-file elements
      rest_hash = {key: val for key, val in list(job_input.items()) if key not in files}
      return dirs, files, rest_hash