code: def test_gitattributes(path=None):
      gr = GitRepo(path, create=True)
      # starts without any attributes file
      ok_(not op.exists(op.join(gr.path, ".gitattributes")))
      eq_(gr.get_gitattributes(".")["."], {})
      # bool is a tag or unsets, anything else is key/value
      gr.set_gitattributes(
          [("*", {"tag": True}), ("*", {"sec.key": "val"})]
      )
      ok_(op.exists(op.join(gr.path, ".gitattributes")))
      eq_(
          gr.get_gitattributes(".")["."],
          {"tag": True, "sec.key": "val"},
      )
      # unset by amending the record, but does not remove notion of the
      # tag entirely
      gr.set_gitattributes([("*", {"tag": False})])
      eq_(
          gr.get_gitattributes(".")["."],
          {"tag": False, "sec.key": "val"},
      )
      # attributes file is not added or committed, we can ignore such
      # attributes
      eq_(gr.get_gitattributes(".", index_only=True)["."], {})
  
      # we can send absolute path patterns and write to any file, and
      # the patterns will be translated relative to the target file
      gr.set_gitattributes(
          [
              (
                  op.join(gr.path, "relative", "ikethemike/**"),
                  {"bang": True},
              )
          ],
          attrfile=op.join("relative", ".gitattributes"),
      )
      # directory and file get created
      ok_(op.exists(op.join(gr.path, "relative", ".gitattributes")))
      eq_(
          gr.get_gitattributes(
              op.join(gr.path, "relative", "ikethemike", "probe")
          ),
          # always comes out relative to the repo root, even if abs goes in
          {
              op.join("relative", "ikethemike", "probe"): {
                  "tag": False,
                  "sec.key": "val",
                  "bang": True,
              }
          },
      )
      if get_encoding_info()["default"] != "ascii" and not on_windows:
          # do not perform this on obscure systems without anything like UTF
          # it is not relevant whether a path actually exists, and paths
          # with spaces and other funky stuff are just fine
          funky = "{} {}".format(
              get_most_obscure_supported_name(),
              get_most_obscure_supported_name(),
          )
          gr.set_gitattributes([(funky, {"this": "that"})])
          eq_(
              gr.get_gitattributes(funky)[funky],
              {
                  "this": "that",
                  "tag": False,
                  "sec.key": "val",
              },
          )
  
      # mode='w' should replace the entire file:
      gr.set_gitattributes([("**", {"some": "nonsense"})], mode="w")
      eq_(gr.get_gitattributes(".")["."], {"some": "nonsense"})
      # mode='a' appends additional key/value
      gr.set_gitattributes([("*", {"king": "kong"})], mode="a")
      eq_(
          gr.get_gitattributes(".")["."],
          {"some": "nonsense", "king": "kong"},
      )
      # handle files without trailing newline
      with open(op.join(gr.path, ".gitattributes"), "r+") as f:
          s = f.read()
          f.seek(0)
          f.write(s.rstrip())
          f.truncate()
      gr.set_gitattributes([("*", {"ding": "dong"})], mode="a")
      eq_(
          gr.get_gitattributes(".")["."],
          {"some": "nonsense", "king": "kong", "ding": "dong"},
      )
  
imports: import logging
  import os
  import os.path
  import sys
  import pytest
  from datalad import get_encoding_info
  from datalad.cmd import StdOutCapture, StdOutErrCapture, WitlessRunner
  from datalad.support.exceptions import CommandError, FileNotInRepositoryError, InvalidGitRepositoryError, NoSuchPathError, PathKnownToRepositoryError
  from datalad.support.external_versions import external_versions
  from datalad.support.gitrepo import GitRepo, _normalize_path, normalize_paths, to_options
  from datalad.support.sshconnector import get_connection_hash
  from datalad.tests.utils_pytest import DEFAULT_BRANCH, DEFAULT_REMOTE, SkipTest, assert_cwd_unchanged, assert_equal, assert_false, assert_in, assert_in_results, assert_is_instance, assert_not_equal, assert_not_in, assert_raises, assert_repo_status, assert_true, create_tree, eq_, get_most_obscure_supported_name, integration, neq_, ok_, skip_if_no_network, skip_if_on_windows, skip_nomultiplex_ssh, slow, swallow_logs, with_tempfile, with_tree, xfail_buggy_annex_info
  from datalad.utils import Path, chpwd, getpwd, on_windows, rmtree
label_desc: Use image node_id 39 for calling a global function with example usage: test_gitattributes(path) without return types