code: def test_preserve_attrs(src=None, dest=None):
      create_tree(src, {"src": {"foo": {"bar": "This is test text."}}})
      os.utime(opj(src, "src", "foo", "bar"), (1234567890, 1234567890))
      _RunnerAdapter().put(
          opj(src, "src"), dest, recursive=True, preserve_attrs=True
      )
      s = os.stat(opj(dest, "src", "foo", "bar"))
      assert s.st_atime == 1234567890
      assert s.st_mtime == 1234567890
      with open(opj(dest, "src", "foo", "bar")) as fp:
          assert fp.read() == "This is test text."
  
imports: import logging
  import os
  import stat
  import sys
  from os import chmod
  from os.path import basename, exists
  from os.path import join
  import pytest
  from datalad.api import create_sibling, install, push
  from datalad.cmd import StdOutErrCapture
  from datalad.cmd import WitlessRunner
  from datalad.distribution.create_sibling import _RunnerAdapter
  from datalad.support.annexrepo import AnnexRepo
  from datalad.support.exceptions import CommandError, InsufficientArgumentsError
  from datalad.support.gitrepo import GitRepo
  from datalad.support.network import urlquote
  from datalad.tests.utils_testdatasets import _mk_submodule_annex
  from datalad.tests.utils_pytest import DEFAULT_BRANCH, DEFAULT_REMOTE, SkipTest, assert_dict_equal, assert_false, assert_in, assert_in_results, assert_no_errors_logged, assert_not_equal, assert_not_in, assert_raises, assert_repo_status, assert_result_count, assert_status, create_tree, eq_, get_mtimes_and_digests, get_ssh_port, known_failure_windows, ok_, ok_endswith, ok_file_has_content, ok_file_under_git, skip_if_on_windows, skip_if_root, skip_ssh, slow, swallow_logs, with_tempfile, with_testsui
  from datalad.utils import Path, _path_, chpwd, on_windows
  from ..dataset import Dataset
label_desc: Use image node_id 20 for calling a global function with example usage: test_preserve_attrs(src, dest) without return types