code: def _datasets_since_(
      dataset, since, paths, recursive, recursion_limit
  ):
      """Generator"""
      # rely on diff() reporting sequentially across datasets
      cur_ds = None
      ds_res = None
      for res in diff_dataset(
          dataset=dataset,
          fr=since,
          # we never touch unsaved content
          to="HEAD",
          constant_refs=False,
          path=paths,
          # we need to know what is around locally to be able
          # to report something that should have been pushed
          # but could not, because we don't have a copy.
          # however, getting this info here is needlessly
          # expensive, we will do it at the latest possible stage
          # in _push_data()
          annex=None,
          recursive=recursive,
          recursion_limit=recursion_limit,
          # TODO?: expose order as an option for diff and push
          # since in some cases breadth-first would be sufficient
          # and result in "taking action faster"
          reporting_order="bottom-up",
      ):
          if res.get("action", None) != "diff":
              # we don't care right now
              continue
          if res.get("status", None) != "ok":
              # we cannot handle this situation, report it in panic
              raise RuntimeError(
                  "Cannot handle non-OK diff result: {}".format(res)
              )
          parentds = res.get("parentds", None)
          if not parentds:
              raise RuntimeError(
                  "Cannot handle diff result without a parent dataset "
                  "property: {}".format(res)
              )
          if res.get("type", None) == "dataset":
              # a subdataset record in another dataset
              # this could be here, because
              # - this dataset was explicitly requested by path
              #   -> should get a dedicated dataset record -- even without recursion
              # - a path within an existing subdataset was given
              # - a path within an non-existing subdataset was given
              #   locally or not)
              #   -> it should be ignored, but should not cause the branch in the
              #   superdataset not to be pushed, if this was the only change
              p = Path(res["path"])
              # was given as an explicit path argument
              if any(
                  arg == p for arg in paths
              ) and not GitRepo.is_valid_repo(res["path"]):
                  raise ValueError(
                      "Cannot publish subdataset, not present: {}".format(
                          res["path"]
                      )
                  )
  
          if parentds != cur_ds:
              if ds_res:
                  # we switch to another dataset, yield this one so outside
                  # code can start processing immediately
                  yield (cur_ds, ds_res)
              # clean start
              ds_res = []
              cur_ds = parentds
          ds_res.append(
              {
                  k: v
                  for k, v in res.items()
                  if k
                  in (
                      # let's keep 'state' in for now, it would make it possible
                      # to implement a "sync"-type push downstream that actually
                      # pulls 'deleted' files
                      "state",
                      # 'file' to copy-to, and subdataset records to possibly
                      # act on
                      "type",
                      # essential
                      "path",
                  )
              }
          )
  
      # if we have something left to report, do it
      # importantly do not test for ds_res, even if we had only seen subdataset
      # records to be changes, we would still want to push the git branches
      if cur_ds:
          yield (cur_ds, ds_res)
  
imports: from itertools import chain
  import logging
  import re
  from datalad.interface.base import Interface, build_doc, eval_results
  from datalad.interface.common_opts import jobs_opt, recursion_limit, recursion_flag
  from datalad.interface.utils import render_action_summary
  from datalad.interface.results import annexjson2result
  from datalad.log import log_progress
  from datalad.support.annexrepo import AnnexRepo
  from datalad.support.gitrepo import GitRepo
  from datalad.support.param import Parameter
  from datalad.support.constraints import EnsureStr, EnsureNone, EnsureChoice
  from datalad.support.exceptions import CommandError
  from datalad.utils import Path, ensure_list, todo_interface_for_extensions
  from datalad.distribution.dataset import Dataset, EnsureDataset, datasetmethod, require_dataset, resolve_path
  from datalad.core.local.diff import diff_dataset
label_desc: Use image node_id 1 for calling a global function with example usage: _datasets_since_(dataset, since, paths, recursive, recursion_limit) without return types