code: def test_procedure_discovery(path=None, super_path=None):
      with chpwd(path):
          # ^ Change directory so that we don't fail with an
          # InvalidGitRepositoryError if the test is executed from a git
          # worktree.
          ps = run_procedure(discover=True, result_renderer="disabled")
          # there are a few procedures coming with datalad, needs to find them
          assert_true(len(ps) > 2)
          # we get essential properties
          _check_procedure_properties(ps)
  
      # set up dataset with registered procedure (c&p from test_basics):
      ds = Dataset(path).create(force=True)
      # extra check: must not pick up cfg_yoda.sh in top directory
      ds.run_procedure("cfg_yoda")
  
      # path to a procedure which is not under any "standard" location but
      # present in the dataset
      code_dir_procedure_path = op.join(
          ds.path, "code", "datalad_test_proc.py"
      )
      top_dir_procedure_path = op.join(ds.path, "cfg_yoda.sh")
  
      # run discovery on the dataset:
      ps = ds.run_procedure(discover=True, result_renderer="disabled")
      # it should not be found magically by default
      assert_not_in_results(ps, path=code_dir_procedure_path)
      assert_not_in_results(ps, path=top_dir_procedure_path)
  
      with patch_config(
          {
              "datalad.locations.extra-procedures": op.join(
                  ds.path, "code"
              )
          }
      ):
          # run discovery on the dataset:
          ps = ds.run_procedure(
              discover=True, result_renderer="disabled"
          )
          # still needs to find procedures coming with datalad
          assert_true(len(ps) > 3)
          # and procedure under the path we specified
          assert_result_count(ps, 1, path=code_dir_procedure_path)
          assert_not_in_results(ps, path=top_dir_procedure_path)
  
      # multiple extra locations
      with patch_config(
          {
              "datalad.locations.extra-procedures": [
                  op.join(ds.path, "code"),
                  ds.path,
              ]
          }
      ):
          # run discovery on the dataset:
          ps = ds.run_procedure(
              discover=True, result_renderer="disabled"
          )
          # still needs to find procedures coming with datalad
          assert_true(len(ps) > 4)
          # and procedure under the path we specified
          assert_result_count(ps, 1, path=code_dir_procedure_path)
          assert_result_count(ps, 1, path=top_dir_procedure_path)
  
      # configure dataset to look for procedures in its code folder
      ds.config.add(
          "datalad.locations.dataset-procedures", "code", scope="branch"
      )
      ds.save(op.join(".datalad", "config"))
  
      # run discovery on the dataset:
      ps = ds.run_procedure(discover=True, result_renderer="disabled")
  
      # still needs to find procedures coming with datalad
      assert_true(len(ps) > 2)
      # we get three essential properties
      _check_procedure_properties(ps)
      # dataset's procedure needs to be in the results
      # and only a single one
      assert_result_count(ps, 1, path=code_dir_procedure_path)
      # a subdir shouldn't be considered a procedure just because it's "executable"
      assert_not_in_results(
          ps, path=op.join(ds.path, "code", "testdir")
      )
  
      # make it a subdataset and try again:
      # first we need to save the beast to make install work
      ds.save()
      super = Dataset(super_path).create()
      super.install("sub", source=ds.path)
  
      ps = super.run_procedure(
          discover=True, result_renderer="disabled"
      )
      # still needs to find procedures coming with datalad
      assert_true(len(ps) > 2)
      _check_procedure_properties(ps)
      # dataset's procedure needs to be in the results
      assert_in_results(
          ps,
          path=op.join(
              super.path, "sub", "code", "datalad_test_proc.py"
          ),
      )
  
      if not ds.repo.is_managed_branch():  # no symlinks
          import os
  
          # create a procedure which is a broken symlink, but recognizable as a
          # python script:
          os.symlink(
              op.join(super.path, "sub", "not_existent"),
              op.join(super.path, "sub", "code", "broken_link_proc.py"),
          )
          # broken symlink at procedure location, but we can't tell, whether it is
          # an actual procedure without any guess on how to execute it:
          os.symlink(
              op.join(super.path, "sub", "not_existent"),
              op.join(super.path, "sub", "code", "unknwon_broken_link"),
          )
  
          ps = super.run_procedure(
              discover=True, result_renderer="disabled"
          )
          # still needs to find procedures coming with datalad and the dataset
          # procedure registered before
          assert_true(len(ps) > 3)
          assert_in_results(
              ps,
              path=op.join(
                  super.path, "sub", "code", "broken_link_proc.py"
              ),
              state="absent",
          )
          assert_in_results(
              ps,
              path=op.join(
                  super.path, "sub", "code", "unknwon_broken_link"
              ),
              state="absent",
          )
  
imports: import json
  import os.path
  import sys
  from unittest.mock import patch
  from datalad.api import run_procedure
  from datalad.cmd import KillOutput, WitlessRunner
  from datalad.distribution.dataset import Dataset
  from datalad.support.exceptions import CommandError, InsufficientArgumentsError
  from datalad.tests.utils_pytest import OBSCURE_FILENAME, assert_false, assert_in_results, assert_not_in_results, assert_raises, assert_repo_status, assert_result_count, assert_true, eq_, known_failure_windows, ok_file_has_content, patch_config, with_tempfile, with_tree, xfail_buggy_annex_info
  from datalad.utils import chpwd, quote_cmdlinearg, swallow_outputs
label_desc: Use image node_id 3 for calling a global function with example usage: test_procedure_discovery(path, super_path) without return types