class_docstr: TaskDataStore is obtained through FlowDataStore.get_datastore_for_task and
  is used to store three things:
      - Task artifacts (using save_artifacts and load_artifacts) which will
        ultimately be stored using ContentAddressedStore's save_blobs and
        load_blobs. This is basically the content indexed portion of the
        storage (identical objects are stored only once).
      - Metadata information (using save_metadata and load_metadata) which
        stores JSON encoded metadata about a task in a non-content indexed
        way in a hierarchical manner (ie: the files are stored
        in a path indicated by the pathspec (run_id/step_name/task_id)).
        This portion of the store can be viewed as name indexed (storing
        two metadata items with the same name will overwrite the previous item
        so the condition of equality is the name as
        opposed to the content).
      - Logs which are a special sort of task metadata but are handled
        differently (they are not JSON-encodable dictionaries).
class_docstr_tok: ["TaskDataStore","is","obtained","through","FlowDataStore.get_datastore_for_task","and","is","used","to","store","three","things",":","-","Task","artifacts","(","using","save_artifacts","and","load_artifacts",")","which","will","ultimately","be","stored","using","ContentAddressedStore","'s","save_blobs","and","load_blobs",".","This","is","basically","the","content","indexed","portion","of","the","storage","(","identical","objects","are","stored","only","once",")",".","-","Metadata","information","(","using","save_metadata","and","load_metadata",")","which","stores","JSON","encoded","metadata","about","a","task","in","a","non-content","indexed","way","in","a","hierarchical","manner","(","ie",":","the","files","are","stored","in","a","path","indicated","by","the","pathspec","(","run_id\/step_name\/task_id",")",")",".","This","portion","of","the","store","can","be","viewed","as","name","indexed","(","storing","two","metadata","items","with","the","same","name","will","overwrite","the","previous","item","so","the","condition","of","equality","is","the","name","as","opposed","to","the","content",")",".","-","Logs","which","are","a","special","sort","of","task","metadata","but","are","handled","differently","(","they","are","not","JSON-encodable","dictionaries",")","."]
docstr: Saves Metaflow Artifacts (Python objects) to the datastore and stores
  any relevant metadata needed to retrieve them.
  
  Typically, objects are pickled but the datastore may perform any
  operation that it deems necessary. You should only access artifacts
  using load_artifacts
  
  This method requires mode 'w'.
  
  Parameters
  ----------
  artifacts : Iterator[(string, object)]
      Iterator over the human-readable name of the object to save
      and the object itself
  force_v4 : boolean or Dict[string -> boolean]
      Indicates whether the artifact should be pickled using the v4
      version of pickle. If a single boolean, applies to all artifacts.
      If a dictionary, applies to the object named only. Defaults to False
      if not present or not specified
  len_hint: integer
      Estimated number of items in artifacts_iter
docstr_tok: ["Saves","Metaflow","Artifacts","(","Python","objects",")","to","the","datastore","and","stores","any","relevant","metadata","needed","to","retrieve","them",".","Typically",",","objects","are","pickled","but","the","datastore","may","perform","any","operation","that","it","deems","necessary",".","You","should","only","access","artifacts","using","load_artifacts","This","method","requires","mode","'","w","'",".","Parameters","--","--","--","--","--","artifacts",":","Iterator","[","(","string",",","object",")","]","Iterator","over","the","human-readable","name","of","the","object","to","save","and","the","object","itself","force_v4",":","boolean","or","Dict","[","string","-",">","boolean","]","Indicates","whether","the","artifact","should","be","pickled","using","the","v4","version","of","pickle",".","If","a","single","boolean",",","applies","to","all","artifacts",".","If","a","dictionary",",","applies","to","the","object","named","only",".","Defaults","to","False","if","not","present","or","not","specified","len_hint",":","integer","Estimated","number","of","items","in","artifacts_iter"]
code: def save_artifacts(self, artifacts_iter, force_v4=False, len_hint=0):
      """
      Saves Metaflow Artifacts (Python objects) to the datastore and stores
      any relevant metadata needed to retrieve them.
  
      Typically, objects are pickled but the datastore may perform any
      operation that it deems necessary. You should only access artifacts
      using load_artifacts
  
      This method requires mode 'w'.
  
      Parameters
      ----------
      artifacts : Iterator[(string, object)]
          Iterator over the human-readable name of the object to save
          and the object itself
      force_v4 : boolean or Dict[string -> boolean]
          Indicates whether the artifact should be pickled using the v4
          version of pickle. If a single boolean, applies to all artifacts.
          If a dictionary, applies to the object named only. Defaults to False
          if not present or not specified
      len_hint: integer
          Estimated number of items in artifacts_iter
      """
      artifact_names = []
  
      def pickle_iter():
          for name, obj in artifacts_iter:
              do_v4 = (
                  force_v4 and force_v4
                  if isinstance(force_v4, bool)
                  else force_v4.get(name, False)
              )
              if do_v4:
                  encode_type = "gzip+pickle-v4"
                  if encode_type not in self._encodings:
                      raise DataException(
                          "Artifact *%s* requires a serialization encoding that "
                          "requires Python 3.4 or newer." % name
                      )
                  try:
                      blob = pickle.dumps(obj, protocol=4)
                  except TypeError as e:
                      raise UnpicklableArtifactException(name)
              else:
                  try:
                      blob = pickle.dumps(obj, protocol=2)
                      encode_type = "gzip+pickle-v2"
                  except (SystemError, OverflowError):
                      encode_type = "gzip+pickle-v4"
                      if encode_type not in self._encodings:
                          raise DataException(
                              "Artifact *%s* is very large (over 2GB). "
                              "You need to use Python 3.4 or newer if you want to "
                              "serialize large objects." % name
                          )
                      try:
                          blob = pickle.dumps(obj, protocol=4)
                      except TypeError as e:
                          raise UnpicklableArtifactException(name)
                  except TypeError as e:
                      raise UnpicklableArtifactException(name)
  
              self._info[name] = {
                  "size": len(blob),
                  "type": str(type(obj)),
                  "encoding": encode_type,
              }
  
              artifact_names.append(name)
              yield blob
  
      # Use the content-addressed store to store all artifacts
      save_result = self._ca_store.save_blobs(
          pickle_iter(), len_hint=len_hint
      )
      for name, result in zip(artifact_names, save_result):
          self._objects[name] = result.key
  
imports: from collections import defaultdict
  import json
  import pickle
  import sys
  import time
  from functools import wraps
  from io import BufferedIOBase, FileIO, RawIOBase
  from types import MethodType, FunctionType
  from ..None import metaflow_config
  from ..exception import MetaflowInternalError
  from ..metadata import DataArtifact, MetaDatum
  from ..parameters import Parameter
  from ..util import Path, is_stringish, to_fileobj
  from .exceptions import DataException, UnpicklableArtifactException
label_desc: Use image node_id 15 for calling the TaskDataStore obj's underlying member method code with example usage: obj.save_artifacts(artifacts_iter, force_v4, len_hint) without return types