class_docstr: This exists independent of AzureBlobStorage as a wrapper around SDK clients.
  It carries around parameters needed to construct Azure SDK clients on demand.
  
  _AzureRootClient objects will be passed from main to worker threads or processes. They
  must be picklable. We delay constructing Azure SDK objects because they are not picklable.
  
  For example, azure.core.TokenCredential objects are not picklable. Therefore, we pass around an
  AccessToken (token) instead, and construct TokenCredential on demand in the target thread (or process).
  Note that we do this to amortize credential retrieval cost across threads (or processes). Depending on
  the credential methods available to DefaultAzureCredential, credential retrieval can be expensive.
  E.g. Azure CLI based credential may take 500-1000ms.
  
  _AzureRootClient  also carries around with it blob methods that operate relative to
  datastore_root.
class_docstr_tok: ["This","exists","independent","of","AzureBlobStorage","as","a","wrapper","around","SDK","clients",".","It","carries","around","parameters","needed","to","construct","Azure","SDK","clients","on","demand",".","_AzureRootClient","objects","will","be","passed","from","main","to","worker","threads","or","processes",".","They","must","be","picklable",".","We","delay","constructing","Azure","SDK","objects","because","they","are","not","picklable",".","For","example",",","azure.core.TokenCredential","objects","are","not","picklable",".","Therefore",",","we","pass","around","an","AccessToken","(","token",")","instead",",","and","construct","TokenCredential","on","demand","in","the","target","thread","(","or","process",")",".","Note","that","we","do","this","to","amortize","credential","retrieval","cost","across","threads","(","or","processes",")",".","Depending","on","the","credential","methods","available","to","DefaultAzureCredential",",","credential","retrieval","can","be","expensive",".","E.g",".","Azure","CLI","based","credential","may","take","500-1000ms",".","_AzureRootClient","also","carries","around","with","it","blob","methods","that","operate","relative","to","datastore_root","."]
code: def get_datastore_root(self):
      return self._datastore_root
  
imports: import json
  import os
  import shutil
  import uuid
  import time
  from concurrent.futures import as_completed
  from tempfile import mkdtemp
  from metaflow.datastore.datastore_storage import DataStoreStorage, CloseAfterUse
  from metaflow.exception import MetaflowInternalError
  from metaflow.metaflow_config import DATASTORE_SYSROOT_AZURE, ARTIFACT_LOCALROOT, AZURE_STORAGE_WORKLOAD_TYPE
  from metaflow.plugins.azure.azure_utils import check_azure_deps, process_exception, handle_exceptions, create_static_token_credential, parse_azure_full_path
  from metaflow.plugins.azure.blob_service_client_factory import get_azure_blob_service_client
  from metaflow.plugins.storage_executor import StorageExecutor, handle_executor_exceptions
label_desc: Use image node_id 2 for calling the _AzureRootClient obj's underlying member method code with example usage: obj.get_datastore_root() and returns: self