code: def test_rerun(path=None, nodspath=None):
      ds = Dataset(path).create()
      sub = ds.create("sub")
      probe_path = op.join(sub.path, "sequence")
      # run inside the dataset
      with chpwd(path), swallow_outputs():
          ds.run(f"echo x$({cat_command} sub/sequence) > sub/sequence")
      # command ran once, all clean
      assert_repo_status(ds.path)
      eq_("x\n", open(probe_path).read())
      # now, for a rerun we can be anywhere, PWD and all are recorded
      # moreover, rerun must figure out which bits to unlock, even in
      # subdatasets
      with chpwd(nodspath), swallow_outputs():
          ds.rerun()
      assert_repo_status(ds.path)
      # ran twice now
      eq_("xx\n", open(probe_path).read())
  
      # Rerunning from a subdataset skips the command.
      _, sub_info = get_run_info(ds, last_commit_msg(sub.repo))
      eq_(ds.id, sub_info["dsid"])
      assert_result_count(
          sub.rerun(return_type="list", on_failure="ignore"),
          1,
          status="impossible",
          action="run",
          rerun_action="skip",
      )
      eq_("xx\n", open(probe_path).read())
  
      # Rerun fails with a dirty repo.
      dirt = op.join(path, "dirt")
      with open(dirt, "w") as fh:
          fh.write("")
      assert_status("impossible", ds.rerun(on_failure="ignore"))
      remove(dirt)
      assert_repo_status(ds.path)
  
      # Make a non-run commit.
      with open(op.join(path, "nonrun-file"), "w") as f:
          f.write("foo")
      ds.save("nonrun-file")
      # Now rerun the buried command.
      ds.rerun(revision=DEFAULT_BRANCH + "~", message="rerun buried")
      eq_("xxx\n", open(probe_path).read())
      # Also check that the messasge override worked.
      eq_(
          last_commit_msg(ds.repo).splitlines()[0],
          "[DATALAD RUNCMD] rerun buried",
      )
      # Or a range of commits, skipping non-run commits.
      ds.rerun(since=DEFAULT_BRANCH + "~3")
      eq_("xxxxx\n", open(probe_path).read())
      # Or --since= to run all reachable commits.
      ds.rerun(since="")
      eq_("xxxxxxxxxx\n", open(probe_path).read())
  
      # We can get back a report of what would happen rather than actually
      # rerunning anything.
      report = ds.rerun(since="", report=True, return_type="list")
      # The "diff" section of the report doesn't include the unchanged files that
      # would come in "-f json diff" output.
      for entry in report:
          if entry["rerun_action"] == "run":
              # None of the run commits touch .datalad/config or any other config
              # file.
              assert_false(
                  any(
                      r["path"].endswith("config")
                      for r in entry["diff"]
                  )
              )
  
      # Nothing changed.
      eq_("xxxxxxxxxx\n", open(probe_path).read())
      assert_result_count(report, 1, rerun_action="skip-or-pick")
      report[-1]["commit"] == ds.repo.get_hexsha()
  
      # If a file is dropped, we remove it instead of unlocking it.
      ds.drop(probe_path, reckless="kill")
      with swallow_outputs():
          ds.rerun()
  
      eq_("x\n", open(probe_path).read())
  
imports: import logging
  import os.path
  import sys
  from io import StringIO
  from os import remove
  import pytest
  from unittest.mock import patch
  from datalad.api import install, run
  from datalad.core.local.run import run_command
  from datalad.core.local.tests.test_run import last_commit_msg
  from datalad.distribution.dataset import Dataset
  from datalad.local.rerun import diff_revision, get_run_info, new_or_modified
  from datalad.support.exceptions import CommandError, IncompleteResultsError
  from datalad.support.gitrepo import GitRepo
  from datalad.tests.utils_pytest import DEFAULT_BRANCH, DEFAULT_REMOTE, SkipTest, assert_dict_equal, assert_false, assert_in, assert_in_results, assert_not_in, assert_not_in_results, assert_raises, assert_repo_status, assert_result_count, assert_status, create_tree, eq_, known_failure_windows, neq_, ok_, ok_exists, ok_file_has_content, ok_file_under_git, skip_if_adjusted_branch, slow, swallow_logs, swallow_outputs, with_tempfile, with_tree
  from datalad.utils import Path, chpwd, on_windows
label_desc: Use image node_id 1 for calling a global function with example usage: test_rerun(path, nodspath) without return types