code: def _unit(mode, extra_arg_string="", coverage=False):
      """Run unit tests using a particular mode"""
      if isinstance(extra_arg_string, str):
          if len(extra_arg_string):
              extra_args = extra_arg_string.split(" ")
          else:
              extra_args = ()
      else:
          extra_args = extra_arg_string
      del extra_arg_string
      assert isinstance(extra_args, (list, tuple))
      assert all(isinstance(e, str) for e in extra_args)
  
      import_dir = _get_import_dir()[0]
      cwd = op.abspath(op.join(import_dir, ".."))
      extra_args = list(extra_args)
      try:
          import pytest  # noqa, analysis:ignore
      except ImportError:
          raise VispySkipSuite(
              "Skipping unit tests, pytest not installed"
          )
  
      if mode == "nobackend":
          msg = "Running tests with no backend"
          extra_args += ["-m", "not vispy_app_test"]
      else:
          # check to make sure we actually have the backend of interest
          stdout, stderr, invalid = run_subprocess(
              [
                  sys.executable,
                  "-c",
                  'import vispy.app; vispy.app.use_app("%s"); exit(0)'
                  % mode,
              ],
              return_code=True,
          )
          if invalid:
              stdout = stdout + "\n" + stderr
              stdout = "\n".join("    " + x for x in stdout.split("\n"))
              raise VispySkipSuite(
                  "\n%s\n%s\n%s"
                  % (
                      _line_sep,
                      "Skipping backend %s, not "
                      "installed or working properly:\n%s"
                      % (mode, stdout),
                      _line_sep,
                  )
              )
          msg = "Running tests with %s backend" % mode
          extra_args += ["-m", "vispy_app_test"]
      if coverage:
          # Don't actually print the coverage because it's way too long
          extra_args += ["--cov", "vispy", "--cov-report="]
      if not any(e.startswith("-r") for e in extra_args):
          extra_args.append("-ra")
      # make a call to "python" so that it inherits whatever the system
      # thinks is "python" (e.g., virtualenvs)
      extra_args += [import_dir]  # positional argument
      cmd = [sys.executable, "-m", "pytest"] + extra_args
      env = deepcopy(os.environ)
  
      # We want to set this for all app backends plus "nobackend" to
      # help ensure that app tests are appropriately decorated
      env.update(
          dict(_VISPY_TESTING_APP=mode, VISPY_IGNORE_OLD_VERSION="true")
      )
      env_str = "_VISPY_TESTING_APP=%s " % mode
      if len(msg) > 0:
          cmd_string = " ".join(cmd)
          msg = "%s\n%s:\n%s%s" % (
              _line_sep,
              "msg",
              env_str,
              cmd_string,
          )
          print(msg)
      sys.stdout.flush()
      return_code = run_subprocess(
          cmd,
          return_code=True,
          cwd=cwd,
          env=env,
          stdout=None,
          stderr=None,
      )[2]
      if return_code:
          raise RuntimeError("unit failure (%s)" % return_code)
      if coverage:
          # Running a py.test with coverage will wipe out any files that
          # exist as .coverage or .coverage.*. It should work to pass
          # COVERAGE_FILE env var when doing run_subprocess above, but
          # it does not. Therefore we instead use our own naming scheme,
          # and in Travis when we combine them, use COVERAGE_FILE with the
          # `coverage combine` command.
          out_name = op.join(cwd, ".vispy-coverage.%s" % mode)
          if op.isfile(out_name):
              os.remove(out_name)
          os.rename(op.join(cwd, ".coverage"), out_name)
  
imports: from __future__ import print_function
  import sys
  import os
  import warnings
  from os import path
  from copy import deepcopy
  from functools import partial
  from ..util import use_log_level, run_subprocess
  from ..util.ptime import time
  from ._testing import has_application, nottest, IS_CI, IS_TRAVIS_CI
label_desc: Use image node_id 2 for calling a global function with example usage: _unit(mode, extra_arg_string, coverage) without return types