code: def test_read_ctf(tmp_path):
      """Test CTF reader."""
      temp_dir = str(tmp_path)
      out_fname = op.join(temp_dir, "test_py_raw.fif")
  
      # Create a dummy .eeg file so we can test our reading/application of it
      os.mkdir(op.join(temp_dir, "randpos"))
      ctf_eeg_fname = op.join(temp_dir, "randpos", ctf_fname_catch)
      shutil.copytree(op.join(ctf_dir, ctf_fname_catch), ctf_eeg_fname)
      with pytest.warns(
          RuntimeWarning, match="RMSP .* changed to a MISC ch"
      ):
          raw = _test_raw_reader(read_raw_ctf, directory=ctf_eeg_fname)
      picks = pick_types(raw.info, meg=False, eeg=True)
      pos = np.random.RandomState(42).randn(len(picks), 3)
      fake_eeg_fname = op.join(ctf_eeg_fname, "catch-alp-good-f.eeg")
      # Create a bad file
      with open(fake_eeg_fname, "wb") as fid:
          fid.write("foo\n".encode("ascii"))
      pytest.raises(RuntimeError, read_raw_ctf, ctf_eeg_fname)
      # Create a good file
      with open(fake_eeg_fname, "wb") as fid:
          for ii, ch_num in enumerate(picks):
              args = (
                  str(ch_num + 1),
                  raw.ch_names[ch_num],
              ) + tuple(
                  "%0.5f" % x for x in 100 * pos[ii]
              )  # convert to cm
              fid.write(("\t".join(args) + "\n").encode("ascii"))
      pos_read_old = np.array(
          [raw.info["chs"][p]["loc"][:3] for p in picks]
      )
      with pytest.warns(
          RuntimeWarning, match="RMSP .* changed to a MISC ch"
      ):
          raw = read_raw_ctf(ctf_eeg_fname)  # read modified data
      pos_read = np.array(
          [raw.info["chs"][p]["loc"][:3] for p in picks]
      )
      assert_allclose(
          apply_trans(raw.info["ctf_head_t"], pos),
          pos_read,
          rtol=1e-5,
          atol=1e-5,
      )
      assert (pos_read == pos_read_old).mean() < 0.1
      shutil.copy(
          op.join(ctf_dir, "catch-alp-good-f.ds_randpos_raw.fif"),
          op.join(temp_dir, "randpos", "catch-alp-good-f.ds_raw.fif"),
      )
  
      # Create a version with no hc, starting out *with* EEG pos (error)
      os.mkdir(op.join(temp_dir, "nohc"))
      ctf_no_hc_fname = op.join(temp_dir, "no_hc", ctf_fname_catch)
      shutil.copytree(ctf_eeg_fname, ctf_no_hc_fname)
      remove_base = op.join(
          ctf_no_hc_fname, op.basename(ctf_fname_catch[:-3])
      )
      os.remove(remove_base + ".hc")
      with pytest.warns(RuntimeWarning, match="MISC channel"):
          pytest.raises(RuntimeError, read_raw_ctf, ctf_no_hc_fname)
      os.remove(remove_base + ".eeg")
      shutil.copy(
          op.join(ctf_dir, "catch-alp-good-f.ds_nohc_raw.fif"),
          op.join(temp_dir, "no_hc", "catch-alp-good-f.ds_raw.fif"),
      )
  
      # All our files
      use_fnames = [op.join(ctf_dir, c) for c in ctf_fnames]
      for fname in use_fnames:
          raw_c = read_raw_fif(fname + "_raw.fif", preload=True)
          # sometimes matches "MISC channel"
          with _record_warnings():
              raw = read_raw_ctf(fname)
  
          # check info match
          assert_array_equal(raw.ch_names, raw_c.ch_names)
          assert_allclose(raw.times, raw_c.times)
          assert_allclose(raw._cals, raw_c._cals)
          assert (
              raw.info["meas_id"]["version"]
              == raw_c.info["meas_id"]["version"] + 1
          )
          for t in ("dev_head_t", "dev_ctf_t", "ctf_head_t"):
              assert_allclose(
                  raw.info[t]["trans"],
                  raw_c.info[t]["trans"],
                  rtol=1e-4,
                  atol=1e-7,
              )
          # XXX 2019/11/29 : MNC-C FIF conversion files don't have meas_date set.
          # Consider adding meas_date to below checks once this is addressed in
          # MNE-C
          for key in (
              "acq_pars",
              "acq_stim",
              "bads",
              "ch_names",
              "custom_ref_applied",
              "description",
              "events",
              "experimenter",
              "highpass",
              "line_freq",
              "lowpass",
              "nchan",
              "proj_id",
              "proj_name",
              "projs",
              "sfreq",
              "subject_info",
          ):
              assert raw.info[key] == raw_c.info[key], key
          if op.basename(fname) not in single_trials:
              # We don't force buffer size to be smaller like MNE-C
              assert raw.buffer_size_sec == raw_c.buffer_size_sec
          assert len(raw.info["comps"]) == len(raw_c.info["comps"])
          for c1, c2 in zip(raw.info["comps"], raw_c.info["comps"]):
              for key in ("colcals", "rowcals"):
                  assert_allclose(c1[key], c2[key])
              assert c1["save_calibrated"] == c2["save_calibrated"]
              for key in ("row_names", "col_names", "nrow", "ncol"):
                  assert_array_equal(c1["data"][key], c2["data"][key])
              assert_allclose(
                  c1["data"]["data"],
                  c2["data"]["data"],
                  atol=1e-7,
                  rtol=1e-5,
              )
          assert_allclose(
              raw.info["hpi_results"][0]["coord_trans"]["trans"],
              raw_c.info["hpi_results"][0]["coord_trans"]["trans"],
              rtol=1e-5,
              atol=1e-7,
          )
          assert len(raw.info["chs"]) == len(raw_c.info["chs"])
          for ii, (c1, c2) in enumerate(
              zip(raw.info["chs"], raw_c.info["chs"])
          ):
              for key in (
                  "kind",
                  "scanno",
                  "unit",
                  "ch_name",
                  "unit_mul",
                  "range",
                  "coord_frame",
                  "coil_type",
                  "logno",
              ):
                  if (
                      c1["ch_name"] == "RMSP"
                      and "catch-alp-good-f" in fname
                      and key
                      in (
                          "kind",
                          "unit",
                          "coord_frame",
                          "coil_type",
                          "logno",
                      )
                  ):
                      continue  # XXX see below...
                  if (
                      key == "coil_type"
                      and c1[key] == FIFF.FIFFV_COIL_EEG
                  ):
                      # XXX MNE-C bug that this is not set
                      assert c2[key] == FIFF.FIFFV_COIL_NONE
                      continue
                  assert c1[key] == c2[key], key
              for key in ("cal",):
                  assert_allclose(
                      c1[key],
                      c2[key],
                      atol=1e-6,
                      rtol=1e-4,
                      err_msg='raw.info["chs"][%d][%s]' % (ii, key),
                  )
              # XXX 2016/02/24: fixed bug with normal computation that used
              # to exist, once mne-C tools are updated we should update our FIF
              # conversion files, then the slices can go away (and the check
              # can be combined with that for "cal")
              for key in ("loc",):
                  if (
                      c1["ch_name"] == "RMSP"
                      and "catch-alp-good-f" in fname
                  ):
                      continue
                  if (c2[key][:3] == 0.0).all():
                      check = [np.nan] * 3
                  else:
                      check = c2[key][:3]
                  assert_allclose(
                      c1[key][:3],
                      check,
                      atol=1e-6,
                      rtol=1e-4,
                      err_msg='raw.info["chs"][%d][%s]' % (ii, key),
                  )
                  if (c2[key][3:] == 0.0).all():
                      check = [np.nan] * 3
                  else:
                      check = c2[key][9:12]
                  assert_allclose(
                      c1[key][9:12],
                      check,
                      atol=1e-6,
                      rtol=1e-4,
                      err_msg='raw.info["chs"][%d][%s]' % (ii, key),
                  )
  
          # Make sure all digitization points are in the MNE head coord frame
          for p in raw.info["dig"]:
              assert (
                  p["coord_frame"] == FIFF.FIFFV_COORD_HEAD
              ), "dig points must be in FIFF.FIFFV_COORD_HEAD"
  
          if fname.endswith(
              "catch-alp-good-f.ds"
          ):  # omit points from .pos file
              with raw.info._unlock():
                  raw.info["dig"] = raw.info["dig"][:-10]
  
          # XXX: Next test would fail because c-tools assign the fiducials from
          # CTF data as HPI. Should eventually clarify/unify with Matti.
          # assert_dig_allclose(raw.info, raw_c.info)
  
          # check data match
          raw_c.save(out_fname, overwrite=True, buffer_size_sec=1.0)
          raw_read = read_raw_fif(out_fname)
  
          # so let's check tricky cases based on sample boundaries
          rng = np.random.RandomState(0)
          pick_ch = rng.permutation(np.arange(len(raw.ch_names)))[:10]
          bnd = int(round(raw.info["sfreq"] * raw.buffer_size_sec))
          assert bnd == raw._raw_extras[0]["block_size"]
          assert bnd == block_sizes[op.basename(fname)]
          slices = (
              slice(0, bnd),
              slice(bnd - 1, bnd),
              slice(3, bnd),
              slice(3, 300),
              slice(None),
          )
          if len(raw.times) >= 2 * bnd:  # at least two complete blocks
              slices = slices + (
                  slice(bnd, 2 * bnd),
                  slice(bnd, bnd + 1),
                  slice(0, bnd + 100),
              )
          for sl_time in slices:
              assert_allclose(
                  raw[pick_ch, sl_time][0], raw_c[pick_ch, sl_time][0]
              )
              assert_allclose(
                  raw_read[pick_ch, sl_time][0],
                  raw_c[pick_ch, sl_time][0],
              )
          # all data / preload
          raw.load_data()
          assert_allclose(raw[:][0], raw_c[:][0], atol=1e-15)
          # test bad segment annotations
          if "testdata_ctf_short.ds" in fname:
              assert "bad" in raw.annotations.description[0]
              assert_allclose(raw.annotations.onset, [2.15])
              assert_allclose(raw.annotations.duration, [0.0225])
  
      with pytest.raises(TypeError, match="path-like"):
          read_raw_ctf(1)
      with pytest.raises(FileNotFoundError, match="does not exist"):
          read_raw_ctf(ctf_fname_continuous + "foo.ds")
      # test ignoring of system clock
      read_raw_ctf(op.join(ctf_dir, ctf_fname_continuous), "ignore")
      with pytest.raises(ValueError, match="system_clock"):
          read_raw_ctf(op.join(ctf_dir, ctf_fname_continuous), "foo")
  
imports: import copy
  import os
  import shutil
  from datetime import datetime, timezone
  from os import path
  import numpy
  import pytest
  from numpy import array_equal
  from numpy.testing import assert_allclose, assert_array_equal
  import mne
  import mne.io.ctf.info
  from mne import create_info, events_from_annotations, make_forward_solution, pick_types, read_annotations
  from mne._fiff.compensator import get_current_comp
  from mne._fiff.constants import FIFF
  from mne._fiff.pick import _picks_to_idx
  from mne.datasets import brainstorm, spm_face, testing
  from mne.io import RawArray, read_raw_ctf, read_raw_fif
  from mne.io.ctf.constants import CTF
  from mne.io.ctf.info import _convert_time
  from mne.io.tests.test_raw import _test_raw_reader
  from mne.tests.test_annotations import _assert_annotations_equal
  from mne.transforms import apply_trans
  from mne.utils import _clean_names, _record_warnings, _stamp_to_dt, catch_logging
label_desc: Use image node_id 1 for calling a global function with example usage: test_read_ctf(tmp_path) without return types