docs: def upload_microscope_files(self, plate_name, acquisition_name,
                                  path, parallel=1, retry=5,
                                  convert=None, delete_after_upload=False,
                                  _deprecated_directory_option=False):
          '''
          Uploads microscope files contained in `path`.
          If `path` is a directory, upload all files contained in it.
  
          Parameters
          ----------
          plate_name: str
              name of the parent plate
          acquisition_name: str
              name of the parent acquisition
          path: str
              path to a directory on disk where the files that should be uploaded
              are located
          parallel: int
              number of parallel processes to use for upload
          retry: int
              number of times to retry failed uploads
          convert: str
              Format to convert images to during the upload process.
              Given as a string specifying the new file extension (e.g.,
              ``png`` or ``jpg``).  If ``None`` or the empty string,
              no conversion takes place and files are uploaded as-is.
          delete_after_upload: bool
              Delete source files after successful upload.
  
          Returns
          -------
          List[str]
              names of registered files
  
          See also
          --------
          :func:`tmserver.api.acquisition.add_microscope_file`
          :class:`tmlib.models.file.MicroscopeImageFile`
          :class:`tmlib.models.file.MicroscopeMetadataFile`
          '''
          if _deprecated_directory_option:
              logger.warn(
                  "The `--directory` option is now superfluous."
                  " You can remove it from the command line.")
          # TODO: consider using os.walk() to screen subdirectories recursively
          logger.info(
              'upload microscope files for experiment "%s", plate "%s" '
              'and acquisition "%s"',
              self.experiment_name, plate_name, acquisition_name
          )
          if convert:
              # FIXME: This checks that `convert` can handle the
              # *destination* image format, but it could be lacking
              # support for the *source* image format... But the source
              # images are many and, in principle, they could be of many
              # different formats...
              if not check_imagemagick_supported_format(convert):
                  logger.fatal(
                      "Aborting: conversion requested"
                      " but ImageMagick's `convert` not available.")
                  return -1
              logger.info("files will be converted to %s format", convert)
          acquisition_id = self._get_acquisition_id(plate_name, acquisition_name)
  
          path = os.path.expandvars(os.path.expanduser(path))
          if os.path.isdir(path):
              filenames = [
                  f for f in os.listdir(path)
                  if (not f.startswith('.')
                      and not os.path.isdir(os.path.join(path, f)))
              ]
              paths = [
                  os.path.join(path, name) for name in filenames
              ]
          else:
              filenames = [ os.path.basename(path) ]
              paths = [ path ]
          if convert:
              filenames_to_register = []
              for filename in filenames:
                  # note: `ext` starts with a dot!
                  name, ext = os.path.splitext(filename)
                  if ext in SUPPORTED_IMAGE_FORMATS:
                      filenames_to_register.append(replace_ext(filename, convert))
                  else:
                      # no image, no change
                      filenames_to_register.append(filename)
          else:
              filenames_to_register = filenames
          registered_filenames = self._register_files_for_upload(
              acquisition_id, filenames_to_register
          )
          logger.info('registered %d files', len(registered_filenames))
  
          if convert:
              # make temporary directory and schedule its deletion
              convert_dir = tempfile.mkdtemp(prefix='tm_client', suffix='.d')
              atexit.register(shutil.rmtree, convert_dir, ignore_errors=True)
          else:
              convert_dir = None  # unused, but still have to provide it
  
          upload_url = self._build_api_url(
              '/experiments/{experiment_id}/acquisitions/{acquisition_id}/microscope-file'
              .format(experiment_id=self._experiment_id, acquisition_id=acquisition_id)
          )
          total = len(paths)
          retry += 1  # make usage here consistent with CLI usage
          while retry > 0:
              work = [
                  # function,         *args ...
                  (self._upload_file, upload_url, path, convert,
                                      delete_after_upload, convert_dir)
                  for path in paths
              ]
              outcome = self._parallelize(work, parallel)
              # report on failures
              paths = [path for (ok, path) in outcome if not ok]
              failed = len(paths)
              successful = total - failed
              logger.info('file uploads: %d successful, %d failed', successful, failed)
              # try again?
              if failed == 0:
                  break
              else:
                  retry -= 1
                  total = failed
                  logger.info('trying again to upload failed files ...')
  
          return registered_filenames