class_docstr: Run an arbitrary shell command and record its impact on a dataset.
  
  It is recommended to craft the command such that it can run in the root
  directory of the dataset that the command will be recorded in. However,
  as long as the command is executed somewhere underneath the dataset root,
  the exact location will be recorded relative to the dataset root.
  
  If the executed command did not alter the dataset in any way, no record of
  the command execution is made.
  
  If the given command errors, a `CommandError` exception with the same exit
  code will be raised, and no modifications will be saved. A command
  execution will not be attempted, by default, when an error occurred during
  input or output preparation. This default ``stop`` behavior can be
  overridden via [CMD: --on-failure ... CMD][PY: `on_failure=...` PY].
  
  In the presence of subdatasets, the full dataset hierarchy will be checked
  for unsaved changes prior command execution, and changes in any dataset
  will be saved after execution. Any modification of subdatasets is also
  saved in their respective superdatasets to capture a comprehensive record
  of the entire dataset hierarchy state. The associated provenance record is
  duplicated in each modified (sub)dataset, although only being fully
  interpretable and re-executable in the actual top-level superdataset. For
  this reason the provenance record contains the dataset ID of that
  superdataset.
  
  *Command format*
  
  || REFLOW >>
  A few placeholders are supported in the command via Python format
  specification. "{pwd}" will be replaced with the full path of the current
  working directory. "{dspath}" will be replaced with the full path of the
  dataset that run is invoked on. "{tmpdir}" will be replaced with the full
  path of a temporary directory. "{inputs}" and "{outputs}" represent the
  values specified by [CMD: --input and --output CMD][PY: `inputs` and
  `outputs` PY]. If multiple values are specified, the values will be joined
  by a space. The order of the values will match that order from the command
  line, with any globs expanded in alphabetical order (like bash). Individual
  values can be accessed with an integer index (e.g., "{inputs[0]}").
  << REFLOW ||
  
  || REFLOW >>
  Note that the representation of the inputs or outputs in the formatted
  command string depends on whether the command is given as a list of
  arguments or as a string[CMD:  (quotes surrounding the command) CMD]. The
  concatenated list of inputs or outputs will be surrounded by quotes when
  the command is given as a list but not when it is given as a string. This
  means that the string form is required if you need to pass each input as a
  separate argument to a preceding script (i.e., write the command as
  "./script {inputs}", quotes included). The string form should also be used
  if the input or output paths contain spaces or other characters that need
  to be escaped.
  << REFLOW ||
  
  To escape a brace character, double it (i.e., "{{" or "}}").
  
  Custom placeholders can be added as configuration variables under
  "datalad.run.substitutions".  As an example:
  
    Add a placeholder "name" with the value "joe"::
  
      % datalad configuration --scope branch set datalad.run.substitutions.name=joe
      % datalad save -m "Configure name placeholder" .datalad/config
  
    Access the new placeholder in a command::
  
      % datalad run "echo my name is {name} >me"
class_docstr_tok: ["Run","an","arbitrary","shell","command","and","record","its","impact","on","a","dataset",".","It","is","recommended","to","craft","the","command","such","that","it","can","run","in","the","root","directory","of","the","dataset","that","the","command","will","be","recorded","in",".","However",",","as","long","as","the","command","is","executed","somewhere","underneath","the","dataset","root",",","the","exact","location","will","be","recorded","relative","to","the","dataset","root",".","If","the","executed","command","did","not","alter","the","dataset","in","any","way",",","no","record","of","the","command","execution","is","made",".","If","the","given","command","errors",",","a","`","CommandError","`","exception","with","the","same","exit","code","will","be","raised",",","and","no","modifications","will","be","saved",".","A","command","execution","will","not","be","attempted",",","by","default",",","when","an","error","occurred","during","input","or","output","preparation",".","This","default","``","stop","``","behavior","can","be","overridden","via","[","CMD",":","--","on-failure","...","CMD","]","[","PY",":","`","on_failure=","...","`","PY","]",".","In","the","presence","of","subdatasets",",","the","full","dataset","hierarchy","will","be","checked","for","unsaved","changes","prior","command","execution",",","and","changes","in","any","dataset","will","be","saved","after","execution",".","Any","modification","of","subdatasets","is","also","saved","in","their","respective","superdatasets","to","capture","a","comprehensive","record","of","the","entire","dataset","hierarchy","state",".","The","associated","provenance","record","is","duplicated","in","each","modified","(","sub",")","dataset",",","although","only","being","fully","interpretable","and","re-executable","in","the","actual","top-level","superdataset",".","For","this","reason","the","provenance","record","contains","the","dataset","ID","of","that","superdataset",".","*","Command","format","*","||","REFLOW",">",">","A","few","placeholders","are","supported","in","the","command","via","Python","format","specification",".","``","{","pwd","}","''","will","be","replaced","with","the","full","path","of","the","current","working","directory",".","``","{","dspath","}","''","will","be","replaced","with","the","full","path","of","the","dataset","that","run","is","invoked","on",".","``","{","tmpdir","}","''","will","be","replaced","with","the","full","path","of","a","temporary","directory",".","``","{","inputs","}","''","and","``","{","outputs","}","''","represent","the","values","specified","by","[","CMD",":","--","input","and","--","output","CMD","]","[","PY",":","`","inputs","`","and","`","outputs","`","PY","]",".","If","multiple","values","are","specified",",","the","values","will","be","joined","by","a","space",".","The","order","of","the","values","will","match","that","order","from","the","command","line",",","with","any","globs","expanded","in","alphabetical","order","(","like","bash",")",".","Individual","values","can","be","accessed","with","an","integer","index","(","e.g.",",","``","{","inputs","[","0","]","}","''",")",".","<","<","REFLOW","||","||","REFLOW",">",">","Note","that","the","representation","of","the","inputs","or","outputs","in","the","formatted","command","string","depends","on","whether","the","command","is","given","as","a","list","of","arguments","or","as","a","string","[","CMD",":","(","quotes","surrounding","the","command",")","CMD","]",".","The","concatenated","list","of","inputs","or","outputs","will","be","surrounded","by","quotes","when","the","command","is","given","as","a","list","but","not","when","it","is","given","as","a","string",".","This","means","that","the","string","form","is","required","if","you","need","to","pass","each","input","as","a","separate","argument","to","a","preceding","script","(","i.e.",",","write","the","command","as","''",".\/script","{","inputs","}","''",",","quotes","included",")",".","The","string","form","should","also","be","used","if","the","input","or","output","paths","contain","spaces","or","other","characters","that","need","to","be","escaped",".","<","<","REFLOW","||","To","escape","a","brace","character",",","double","it","(","i.e.",",","``","{","{","``","or","``","}","}","''",")",".","Custom","placeholders","can","be","added","as","configuration","variables","under","''","datalad.run.substitutions","''",".","As","an","example",":","Add","a","placeholder","``","name","''","with","the","value","``","joe","''",":",":","%","datalad","configuration","--","scope","branch","set","datalad.run.substitutions.name=joe","%","datalad","save","-m","``","Configure","name","placeholder","''",".datalad\/config","Access","the","new","placeholder","in","a","command",":",":","%","datalad","run","``","echo","my","name","is","{","name","}",">","me","''"]
code: def custom_result_renderer(res, **kwargs):
      dry_run = kwargs.get("dry_run")
      if dry_run and "dry_run_info" in res:
          if dry_run == "basic":
              _display_basic(res)
          elif dry_run == "command":
              ui.message(res["dry_run_info"]["cmd_expanded"])
          else:
              raise ValueError(f"Unknown dry-run mode: {dry_run!r}")
      else:
          if (
              kwargs.get("on_failure") == "stop"
              and res.get("action") == "run"
              and res.get("status") == "error"
          ):
              msg_path = res.get("msg_path")
              if msg_path:
                  ds_path = res["path"]
                  if datalad.get_apimode() == "python":
                      help = (
                          f"\"Dataset('{ds_path}').save(path='.', "
                          "recursive=True, message_file='%s')\""
                      )
                  else:
                      help = "'datalad save -d . -r -F %s'"
                  lgr.info(
                      "The command had a non-zero exit code. "
                      "If this is expected, you can save the changes with "
                      f"{help}",
                      # shorten to the relative path for a more concise
                      # message
                      Path(msg_path).relative_to(ds_path),
                  )
          generic_result_renderer(res)
  
imports: import json
  import logging
  import os
  import os.path
  import warnings
  from argparse import REMAINDER
  from pathlib import Path
  from tempfile import mkdtemp
  import datalad
  import datalad.support.ansi_colors
  from datalad.config import anything2bool
  from datalad.core.local.save import Save
  from datalad.core.local.status import Status
  from datalad.distribution.dataset import Dataset, EnsureDataset, datasetmethod, require_dataset
  from datalad.distribution.get import Get
  from datalad.distribution.install import Install
  from datalad.interface.base import Interface, build_doc, eval_results
  from datalad.interface.common_opts import jobs_opt, save_message_opt
  from datalad.interface.results import get_status_dict
  from datalad.interface.utils import generic_result_renderer
  from datalad.local.unlock import Unlock
  from datalad.support.constraints import EnsureBool, EnsureChoice, EnsureNone
  from datalad.support.exceptions import CapturedException, CommandError
  from datalad.support.globbedpaths import GlobbedPaths
  from datalad.support.json_py import dump2stream
  from datalad.support.param import Parameter
  from datalad.ui import ui
  from datalad.utils import SequenceFormatter, chpwd, ensure_list, ensure_unicode, get_dataset_root, getpwd, join_cmdline, quote_cmdlinearg
label_desc: Use image node_id 2 for calling the Run obj's underlying member method code with example usage: obj.custom_result_renderer(res) without return types