class_docstr: StorageManager is helper interface for downloading & uploading files to supported remote storage
  Support remote servers: http(s)/S3/GS/Azure/File-System-Folder
  Cache is enabled by default for all downloaded remote urls/files
docstr: Download remote folder recursively to the local machine, maintaining the sub folder structure
  from the remote storage.
  
  .. note::
  
      If we have a remote file `s3://bucket/sub/file.ext` then
      `StorageManager.download_folder('s3://bucket/', '~/folder/')`
      will create `~/folder/sub/file.ext`
  
  :param str remote_url: Source remote storage location, tree structure of `remote_url` will
      be created under the target local_folder. Supports S3/GS/Azure and shared filesystem.
      Example: 's3://bucket/data/'
  :param str local_folder: Local target folder to create the full tree from remote_url.
      If None, use the cache folder. (Default: use cache folder)
  :param match_wildcard: If specified only download files matching the `match_wildcard`
      Example: `*.json`
  :param bool overwrite: If False, and target files exist do not download.
      If True, always download the remote files. Default False.
  :param bool skip_zero_size_check: If True, no error will be raised for files with zero bytes size.
  :param bool silence_errors: If True, silence errors that might pop up when trying to download
      files stored remotely. Default False
  
  :return: Target local folder
docstr_tok: ["Download","remote","folder","recursively","to","the","local","machine",",","maintaining","the","sub","folder","structure","from","the","remote","storage",".","..","note",":",":","If","we","have","a","remote","file","`","s3",":","\/\/bucket\/sub\/file.ext","`","then","`","StorageManager.download_folder","(","'s3",":","\/\/bucket\/","'",",","'~\/folder\/","'",")","`","will","create","`","~\/folder\/sub\/file.ext","`",":","param","str","remote_url",":","Source","remote","storage","location",",","tree","structure","of","`","remote_url","`","will","be","created","under","the","target","local_folder",".","Supports","S3\/GS\/Azure","and","shared","filesystem",".","Example",":","'s3",":","\/\/bucket\/data\/'",":","param","str","local_folder",":","Local","target","folder","to","create","the","full","tree","from","remote_url",".","If","None",",","use","the","cache","folder",".","(","Default",":","use","cache","folder",")",":","param","match_wildcard",":","If","specified","only","download","files","matching","the","`","match_wildcard","`","Example",":","`","*",".json","`",":","param","bool","overwrite",":","If","False",",","and","target","files","exist","do","not","download",".","If","True",",","always","download","the","remote","files",".","Default","False",".",":","param","bool","skip_zero_size_check",":","If","True",",","no","error","will","be","raised","for","files","with","zero","bytes","size",".",":","param","bool","silence_errors",":","If","True",",","silence","errors","that","might","pop","up","when","trying","to","download","files","stored","remotely",".","Default","False",":","return",":","Target","local","folder"]
code: def download_folder(
      cls,
      remote_url,
      local_folder=None,
      match_wildcard=None,
      overwrite=False,
      skip_zero_size_check=False,
      silence_errors=False,
  ):
      # type: (str, Optional[str], Optional[str], bool, bool, bool) -> Optional[str]
      """
      Download remote folder recursively to the local machine, maintaining the sub folder structure
      from the remote storage.
  
      .. note::
  
          If we have a remote file `s3://bucket/sub/file.ext` then
          `StorageManager.download_folder('s3://bucket/', '~/folder/')`
          will create `~/folder/sub/file.ext`
  
      :param str remote_url: Source remote storage location, tree structure of `remote_url` will
          be created under the target local_folder. Supports S3/GS/Azure and shared filesystem.
          Example: 's3://bucket/data/'
      :param str local_folder: Local target folder to create the full tree from remote_url.
          If None, use the cache folder. (Default: use cache folder)
      :param match_wildcard: If specified only download files matching the `match_wildcard`
          Example: `*.json`
      :param bool overwrite: If False, and target files exist do not download.
          If True, always download the remote files. Default False.
      :param bool skip_zero_size_check: If True, no error will be raised for files with zero bytes size.
      :param bool silence_errors: If True, silence errors that might pop up when trying to download
          files stored remotely. Default False
  
      :return: Target local folder
      """
  
      base_logger = LoggerRoot.get_base_logger()
  
      if local_folder:
          try:
              Path(local_folder).mkdir(parents=True, exist_ok=True)
          except OSError as ex:
              base_logger.error(
                  "Failed creating local folder '{}': {}".format(
                      local_folder, ex
                  )
              )
              return
      else:
          local_folder = (
              CacheManager.get_cache_manager().get_cache_folder()
          )
  
      helper = StorageHelper.get(remote_url)
      results = []
  
      with ThreadPool() as pool:
          for path in helper.list(prefix=remote_url):
              remote_path = (
                  str(Path(helper.base_url) / Path(path))
                  if helper.get_driver_direct_access(helper.base_url)
                  else "{}/{}".format(
                      helper.base_url.rstrip("/"), path.lstrip("/")
                  )
              )
              if match_wildcard and not fnmatch.fnmatch(
                  remote_path, match_wildcard
              ):
                  continue
              results.append(
                  pool.apply_async(
                      cls.download_file,
                      args=(remote_path, local_folder),
                      kwds={
                          "overwrite": overwrite,
                          "skip_zero_size_check": skip_zero_size_check,
                          "silence_errors": silence_errors,
                      },
                  )
              )
          for res in results:
              res.wait()
      if not results and not silence_errors:
          LoggerRoot.get_base_logger().warning(
              "Did not download any files matching {}".format(
                  remote_url
              )
          )
      return local_folder
  
imports: import fnmatch
  import shutil
  import tarfile
  from multiprocessing.pool import ThreadPool
  from random import random
  from time import time
  from typing import List, Optional, Union
  from zipfile import ZipFile
  from pathlib2 import Path
  from .cache import CacheManager
  from .callbacks import ProgressReport
  from .helper import StorageHelper
  from .util import encode_string_to_filename, safe_extract, create_zip_directories
  from ..debugging.log import LoggerRoot
  from ..config import deferred_config
label_desc: Use image node_id 10 for calling the StorageManager obj's underlying member method code with example usage: obj.download_folder(cls, remote_url, local_folder, match_wildcard, overwrite, skip_zero_size_check, silence_errors) and returns: local_folder