docstr: Downloads images from the web-app and stores them in output_dir.
  
  Args:
      output_dir:
          Where to store the downloaded images.
      tag_name:
          Name of the tag which should be downloaded.
      max_workers:
          Maximum number of workers downloading images in parallel.
      verbose:
          Whether or not to show the progress bar.
  
  Raises:
      ValueError:
          If the specified tag does not exist on the dataset.
      RuntimeError:
          If the connection to the server failed.
  
  Examples:
      >>> client = ApiWorkflowClient(token="MY_AWESOME_TOKEN")
      >>>
      >>> # Already created some Lightly Worker runs with this dataset
      >>> client.set_dataset_id_by_name("my-dataset")
      >>> client.download_dataset("/tmp/data")
      Downloading 3 images (with 3 workers):
      100%|██████████████████████████████████| 3/3 [00:01<00:00,  1.99imgs/s]
docstr_tok: ["Downloads","images","from","the","web-app","and","stores","them","in","output_dir",".","Args",":","output_dir",":","Where","to","store","the","downloaded","images",".","tag_name",":","Name","of","the","tag","which","should","be","downloaded",".","max_workers",":","Maximum","number","of","workers","downloading","images","in","parallel",".","verbose",":","Whether","or","not","to","show","the","progress","bar",".","Raises",":","ValueError",":","If","the","specified","tag","does","not","exist","on","the","dataset",".","RuntimeError",":","If","the","connection","to","the","server","failed",".","Examples",":",">",">",">","client","=","ApiWorkflowClient","(","token=","''","MY_AWESOME_TOKEN","''",")",">",">",">",">",">",">","#","Already","created","some","Lightly","Worker","runs","with","this","dataset",">",">",">","client.set_dataset_id_by_name","(","``","my-dataset","''",")",">",">",">","client.download_dataset","(","``","\/tmp\/data","''",")","Downloading","3","images","(","with","3","workers",")",":","100","%","|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588|","3\/3","[","00:01","<","00:00",",","1.99imgs\/s","]"]
code: def download_dataset(
      self,
      output_dir: str,
      tag_name: str = "initial-tag",
      max_workers: int = 8,
      verbose: bool = True,
  ) -> None:
      """Downloads images from the web-app and stores them in output_dir.
  
      Args:
          output_dir:
              Where to store the downloaded images.
          tag_name:
              Name of the tag which should be downloaded.
          max_workers:
              Maximum number of workers downloading images in parallel.
          verbose:
              Whether or not to show the progress bar.
  
      Raises:
          ValueError:
              If the specified tag does not exist on the dataset.
          RuntimeError:
              If the connection to the server failed.
  
      Examples:
          >>> client = ApiWorkflowClient(token="MY_AWESOME_TOKEN")
          >>>
          >>> # Already created some Lightly Worker runs with this dataset
          >>> client.set_dataset_id_by_name("my-dataset")
          >>> client.download_dataset("/tmp/data")
          Downloading 3 images (with 3 workers):
          100%|██████████████████████████████████| 3/3 [00:01<00:00,  1.99imgs/s]
      """
  
      # check if images are available
      dataset = self._datasets_api.get_dataset_by_id(self.dataset_id)
      if dataset.img_type != ImageType.FULL:
          # only thumbnails or metadata available
          raise ValueError(
              f"Dataset with id {self.dataset_id} has no downloadable images!"
          )
  
      # check if tag exists
      available_tags = self.get_all_tags()
      try:
          tag = next(
              tag for tag in available_tags if tag.name == tag_name
          )
      except StopIteration:
          raise ValueError(
              f"Dataset with id {self.dataset_id} has no tag {tag_name}!"
          )
  
      # get sample ids
      sample_ids = self._mappings_api.get_sample_mappings_by_dataset_id(
          self.dataset_id, field="_id"
      )
  
      indices = BitMask.from_hex(tag.bit_mask_data).to_indices()
      sample_ids = [sample_ids[i] for i in indices]
  
      filenames_on_server = self.get_filenames()
      filenames = [filenames_on_server[i] for i in indices]
  
      downloadables = zip(sample_ids, filenames)
  
      # handle the case where len(sample_ids) < max_workers
      max_workers = min(len(sample_ids), max_workers)
      max_workers = max(max_workers, 1)
  
      if verbose:
          print(
              f"Downloading {bcolors.OKGREEN}{len(sample_ids)}{bcolors.ENDC} images (with {bcolors.OKGREEN}{max_workers}{bcolors.ENDC} workers):",
              flush=True,
          )
          pbar = tqdm.tqdm(unit="imgs", total=len(sample_ids))
          tqdm_lock = tqdm.tqdm.get_lock()
  
      # define lambda function for concurrent download
      def lambda_(i):
          sample_id, filename = i
          # try to download image
          try:
              read_url = (
                  self._samples_api.get_sample_image_read_url_by_id(
                      dataset_id=self.dataset_id,
                      sample_id=sample_id,
                      type="full",
                  )
              )
              img = _get_image_from_read_url(read_url)
              _make_dir_and_save_image(output_dir, filename, img)
              success = True
          except Exception as e:  # pylint: disable=broad-except
              warnings.warn(
                  f"Downloading of image {filename} failed with error {e}"
              )
              success = False
  
          # update the progress bar
          if verbose:
              tqdm_lock.acquire()
              pbar.update(1)
              tqdm_lock.release()
          # return whether the download was successful
          return success
  
      with ThreadPoolExecutor(max_workers=max_workers) as executor:
          results = list(
              executor.map(lambda_, downloadables, chunksize=1)
          )
  
      if not all(results):
          msg = "Warning: Unsuccessful download! "
          msg += "Failed at image: {}".format(results.index(False))
          warnings.warn(msg)
  
imports: import io
  import os
  import urllib.request
  import warnings
  from concurrent.futures.thread import ThreadPoolExecutor
  from typing import Dict, List, Optional
  from urllib.request import Request
  import tqdm
  from PIL import Image
  from lightly.api import download, utils
  from lightly.api.bitmask import BitMask
  from lightly.openapi_generated.swagger_client.models import DatasetEmbeddingData, ImageType
  from lightly.utils.hipify import bcolors
label_desc: Use image node_id 1 for calling the _DownloadDatasetMixin obj's underlying member method code with example usage: obj.download_dataset(output_dir, tag_name, max_workers, verbose) and returns: success