docs: def plant_kbos(filename, psf, kbos, shifts, prefix):
      """
      Add KBOs to an image
      :param filename: name of the image to add KBOs to
      :param psf: the Point Spread Function in IRAF/DAOPHOT format to be used by ADDSTAR
      :param kbos: list of KBOs to add, has format as returned by KBOGenerator
      :param shifts: dictionary with shifts to transfer to coordinates to reference frame.
      :param prefix: an estimate FWHM of the image, used to determine trailing.
      :return: None
      """
  
      iraf.set(uparm="./")
      iraf.digiphot()
      iraf.apphot()
      iraf.daophot(_doprint=0)
      iraf.images()
  
      if shifts['nmag'] < 4:
          logging.warning("Mag shift based on fewer than 4 common stars.")
          fd = open("plant.WARNING", 'a')
          fd.write("Mag shift based on fewer than 4 common stars.")
          fd.close()
  
      if shifts['emag'] > 0.05:
          logging.warning("Mag shift has large uncertainty.")
          fd = open("plant.WARNING", 'a')
          fd.write("Mag shift hsa large uncertainty.")
          fd.close()
  
      addstar = tempfile.NamedTemporaryFile(suffix=".add")
  
      # transform KBO locations to this frame using the shifts provided.
      w = get_wcs(shifts)
  
      header = fits.open(filename)[0].header
  
      # set the rate of motion in units of pixels/hour instead of ''/hour
      scale = header['PIXSCAL1']
      rate = kbos['sky_rate']/scale
  
      # compute the location of the KBOs in the current frame.
  
      # offset magnitudes from the reference frame to the current one.
      mag = kbos['mag'] - shifts['dmag']
      angle = radians(kbos['angle'])
  
      # Move the x/y locations to account for the sky motion of the source.
      x = kbos['x'] - rate*24.0*shifts['dmjd']*cos(angle)
      y = kbos['y'] - rate*24.0*shifts['dmjd']*sin(angle)
      x, y = w.wcs_world2pix(x, y, 1)
  
      # Each source will be added as a series of PSFs so that a new PSF is added for each pixel the source moves.
      itime = float(header['EXPTIME'])/3600.0
      npsf = fabs(rint(rate * itime)) + 1
      mag += 2.5*log10(npsf)
      dt_per_psf = itime/npsf
  
      # Build an addstar file to be used in the planting of source.
      idx = 0
      for record in transpose([x, y, mag, npsf, dt_per_psf, rate, angle]):
          x = record[0]
          y = record[1]
          mag = record[2]
          npsf = record[3]
          dt = record[4]
          rate = record[5]
          angle = record[6]
          for i in range(int(npsf)):
              idx += 1
              x += dt*rate*math.cos(angle)
              y += dt*rate*math.sin(angle)
              addstar.write("{} {} {} {}\n".format(x, y, mag, idx))
  
      addstar.flush()
      fk_image = prefix+filename
      try:
          os.unlink(fk_image)
      except OSError as err:
          if err.errno == errno.ENOENT:
              pass
          else:
              raise
  
      # add the sources to the image.
      iraf.daophot.addstar(filename, addstar.name, psf, fk_image,
                           simple=True, verify=False, verbose=False)
      # convert the image to short integers.
      iraf.images.chpix(fk_image, fk_image, 'ushort')